[MIRROR] Revert "Revert "/tg/ preference datums part 1: take two"" (#8929)

Co-authored-by: Heroman3003 <31296024+Heroman3003@users.noreply.github.com>
Co-authored-by: Kashargul <KashL@t-online.de>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2
2024-09-14 03:30:15 -07:00
committed by GitHub
parent a8318eb241
commit 2986497a43
204 changed files with 5174 additions and 2371 deletions

View File

@@ -225,12 +225,15 @@
//preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum)
prefs = preferences_datums[ckey]
if(!prefs)
if(prefs)
prefs.client = src
prefs.load_savefile() // just to make sure we have the latest data
prefs.apply_all_client_preferences()
else
prefs = new /datum/preferences(src)
preferences_datums[ckey] = prefs
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
prefs.client = src // Only relevant if we reloaded it from the global list, otherwise prefs/New sets it
hook_vr("client_new",list(src)) //VOREStation Code. For now this only loads vore prefs, so better put before mob.Login() call but after normal prefs are loaded.
@@ -302,7 +305,7 @@
alert = TRUE
if(alert)
for(var/client/X in GLOB.admins)
if(X.is_preference_enabled(/datum/client_preference/holder/play_adminhelp_ping))
if(X.prefs?.read_preference(/datum/preference/toggle/holder/play_adminhelp_ping))
X << 'sound/voice/bcriminal.ogg' //ChompEDIT - back to beepsky
window_flash(X)
//VOREStation Edit end.
@@ -522,6 +525,12 @@
if(prefs)
prefs.ShowChoices(usr)
/client/verb/game_options()
set name = "Game Options"
set category = "Preferences"
if(prefs)
prefs.tgui_interact(usr)
/client/proc/findJoinDate()
var/list/http = world.Export("http://byond.com/members/[ckey]?format=text")
if(!http)

View File

@@ -4,17 +4,17 @@ var/global/list/uplink_locations = list("PDA", "Headset", "None")
name = "Basic"
sort_order = 1
/datum/category_item/player_setup_item/antagonism/basic/load_character(var/savefile/S)
S["uplinklocation"] >> pref.uplinklocation
S["exploit_record"] >> pref.exploit_record
S["antag_faction"] >> pref.antag_faction
S["antag_vis"] >> pref.antag_vis
/datum/category_item/player_setup_item/antagonism/basic/load_character(list/save_data)
pref.uplinklocation = save_data["uplinklocation"]
pref.exploit_record = save_data["exploit_record"]
pref.antag_faction = save_data["antag_faction"]
pref.antag_vis = save_data["antag_vis"]
/datum/category_item/player_setup_item/antagonism/basic/save_character(var/savefile/S)
S["uplinklocation"] << pref.uplinklocation
S["exploit_record"] << pref.exploit_record
S["antag_faction"] << pref.antag_faction
S["antag_vis"] << pref.antag_vis
/datum/category_item/player_setup_item/antagonism/basic/save_character(list/save_data)
save_data["uplinklocation"] = pref.uplinklocation
save_data["exploit_record"] = pref.exploit_record
save_data["antag_faction"] = pref.antag_faction
save_data["antag_vis"] = pref.antag_vis
/datum/category_item/player_setup_item/antagonism/basic/sanitize_character()
pref.uplinklocation = sanitize_inlist(pref.uplinklocation, uplink_locations, initial(pref.uplinklocation))

View File

@@ -32,11 +32,11 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set
name = "Candidacy"
sort_order = 2
/datum/category_item/player_setup_item/antagonism/candidacy/load_character(var/savefile/S)
S["be_special"] >> pref.be_special
/datum/category_item/player_setup_item/antagonism/candidacy/load_character(list/save_data)
pref.be_special = save_data["be_special"]
/datum/category_item/player_setup_item/antagonism/candidacy/save_character(var/savefile/S)
S["be_special"] << pref.be_special
/datum/category_item/player_setup_item/antagonism/candidacy/save_character(list/save_data)
save_data["be_special"] = pref.be_special
/datum/category_item/player_setup_item/antagonism/candidacy/sanitize_character()
pref.be_special = sanitize_integer(pref.be_special, 0, 16777215, initial(pref.be_special)) //VOREStation Edit - 24 bits of support

View File

@@ -10,47 +10,47 @@
name = "Basic"
sort_order = 1
/datum/category_item/player_setup_item/general/basic/load_character(var/savefile/S)
S["real_name"] >> pref.real_name
S["nickname"] >> pref.nickname
S["name_is_always_random"] >> pref.be_random_name
S["gender"] >> pref.biological_gender
S["id_gender"] >> pref.identifying_gender
S["age"] >> pref.age
S["bday_month"] >> pref.bday_month
S["bday_day"] >> pref.bday_day
S["last_bday_note"] >> pref.last_birthday_notification
S["bday_announce"] >> pref.bday_announce
S["spawnpoint"] >> pref.spawnpoint
S["OOC_Notes"] >> pref.metadata
S["OOC_Notes_Likes"] >> pref.metadata_likes
S["OOC_Notes_Disikes"] >> pref.metadata_dislikes
//CHOMPEdit Start
S["OOC_Notes_Maybes"] >> pref.metadata_maybes
S["OOC_Notes_Favs"] >> pref.metadata_favs
S["OOC_Notes_System"] >> pref.matadata_ooc_style
//CHOMPEdit End
/datum/category_item/player_setup_item/general/basic/load_character(list/save_data)
pref.real_name = save_data["real_name"]
pref.nickname = save_data["nickname"]
pref.be_random_name = save_data["name_is_always_random"]
pref.biological_gender = save_data["gender"]
pref.identifying_gender = save_data["id_gender"]
pref.age = save_data["age"]
pref.bday_month = save_data["bday_month"]
pref.bday_day = save_data["bday_day"]
pref.last_birthday_notification = save_data["last_bday_note"]
pref.bday_announce = save_data["bday_announce"]
pref.spawnpoint = save_data["spawnpoint"]
pref.metadata = save_data["OOC_Notes"]
pref.metadata_likes = save_data["OOC_Notes_Likes"]
pref.metadata_dislikes = save_data["OOC_Notes_Disikes"]
//CHOMPAdd Start
pref.metadata_maybes = save_data["OOC_Notes_Maybes"]
pref.metadata_favs = save_data["OOC_Notes_Favs"]
pref.matadata_ooc_style = save_data["OOC_Notes_System"]
//CHOMPAdd End
/datum/category_item/player_setup_item/general/basic/save_character(var/savefile/S)
S["real_name"] << pref.real_name
S["nickname"] << pref.nickname
S["name_is_always_random"] << pref.be_random_name
S["gender"] << pref.biological_gender
S["id_gender"] << pref.identifying_gender
S["age"] << pref.age
S["bday_month"] << pref.bday_month
S["bday_day"] << pref.bday_day
S["last_bday_note"] << pref.last_birthday_notification
S["bday_announce"] << pref.bday_announce
S["spawnpoint"] << pref.spawnpoint
S["OOC_Notes"] << pref.metadata
S["OOC_Notes_Likes"] << pref.metadata_likes
S["OOC_Notes_Disikes"] << pref.metadata_dislikes
//CHOMPEdit Start
S["OOC_Notes_Favs"] << pref.metadata_favs
S["OOC_Notes_Maybes"] << pref.metadata_maybes
S["OOC_Notes_System"] << pref.matadata_ooc_style
//CHOMPEdit End
/datum/category_item/player_setup_item/general/basic/save_character(list/save_data)
save_data["real_name"] = pref.real_name
save_data["nickname"] = pref.nickname
save_data["name_is_always_random"] = pref.be_random_name
save_data["gender"] = pref.biological_gender
save_data["id_gender"] = pref.identifying_gender
save_data["age"] = pref.age
save_data["bday_month"] = pref.bday_month
save_data["bday_day"] = pref.bday_day
save_data["last_bday_note"] = pref.last_birthday_notification
save_data["bday_announce"] = pref.bday_announce
save_data["spawnpoint"] = pref.spawnpoint
save_data["OOC_Notes"] = pref.metadata
save_data["OOC_Notes_Likes"] = pref.metadata_likes
save_data["OOC_Notes_Disikes"] = pref.metadata_dislikes
//CHOMPAdd Start
save_data["OOC_Notes_Maybes"] = pref.metadata_maybes
save_data["OOC_Notes_Favs"] = pref.metadata_favs
save_data["OOC_Notes_System"] = pref.matadata_ooc_style
//CHOMPAdd End
/datum/category_item/player_setup_item/general/basic/sanitize_character()
pref.age = sanitize_integer(pref.age, get_min_age(), get_max_age(), initial(pref.age))

View File

@@ -7,28 +7,20 @@
sort_order = 2
var/static/list/forbidden_prefixes = list(";", ":", ".", "!", "*", "^", "-")
/datum/category_item/player_setup_item/general/language/load_character(var/savefile/S)
S["language"] >> pref.alternate_languages
S["extra_languages"] >> pref.extra_languages
if(islist(pref.alternate_languages)) // Because aparently it may not be?
testing("LANGSANI: Loaded from [pref.client]'s character [pref.real_name || "-name not yet loaded-"] savefile: [english_list(pref.alternate_languages || list())]")
S["language_prefixes"] >> pref.language_prefixes
//CHOMPEdit Begin
S["species"] >> pref.species
//CHOMPEdit End
//VORE Edit Begin
S["preflang"] >> pref.preferred_language
//VORE Edit End
S["language_custom_keys"] >> pref.language_custom_keys
/datum/category_item/player_setup_item/general/language/load_character(list/save_data)
pref.alternate_languages = save_data["language"]
pref.extra_languages = save_data["extra_languages"]
pref.language_prefixes = save_data["language_prefixes"]
pref.species = save_data["species"] //CHOMPAdd
pref.preferred_language = save_data["preflang"]
pref.language_custom_keys = save_data["language_custom_keys"]
/datum/category_item/player_setup_item/general/language/save_character(var/savefile/S)
S["language"] << pref.alternate_languages
S["extra_languages"] << pref.extra_languages
if(islist(pref.alternate_languages)) // Because aparently it may not be?
testing("LANGSANI: Loaded from [pref.client]'s character [pref.real_name || "-name not yet loaded-"] savefile: [english_list(pref.alternate_languages || list())]")
S["language_prefixes"] << pref.language_prefixes
S["language_custom_keys"] << pref.language_custom_keys
S["preflang"] << pref.preferred_language // VOREStation Edit
/datum/category_item/player_setup_item/general/language/save_character(list/save_data)
save_data["language"] = pref.alternate_languages
save_data["extra_languages"] = pref.extra_languages
save_data["language_prefixes"] = pref.language_prefixes
save_data["language_custom_keys"] = pref.language_custom_keys
save_data["preflang"] = pref.preferred_language
/datum/category_item/player_setup_item/general/language/sanitize_character()
if(!islist(pref.alternate_languages)) pref.alternate_languages = list()

View File

@@ -90,152 +90,151 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
name = "Body"
sort_order = 3
/datum/category_item/player_setup_item/general/body/load_character(var/savefile/S)
S["species"] >> pref.species
S["hair_red"] >> pref.r_hair
S["hair_green"] >> pref.g_hair
S["hair_blue"] >> pref.b_hair
S["grad_red"] >> pref.r_grad
S["grad_green"] >> pref.g_grad
S["grad_blue"] >> pref.b_grad
S["facial_red"] >> pref.r_facial
S["grad_red"] >> pref.r_grad
S["grad_green"] >> pref.g_grad
S["grad_blue"] >> pref.b_grad
S["facial_green"] >> pref.g_facial
S["facial_blue"] >> pref.b_facial
S["skin_tone"] >> pref.s_tone
S["skin_red"] >> pref.r_skin
S["skin_green"] >> pref.g_skin
S["skin_blue"] >> pref.b_skin
S["hair_style_name"] >> pref.h_style
S["grad_style_name"] >> pref.grad_style
S["facial_style_name"] >> pref.f_style
S["grad_style_name"] >> pref.grad_style
S["eyes_red"] >> pref.r_eyes
S["eyes_green"] >> pref.g_eyes
S["eyes_blue"] >> pref.b_eyes
S["b_type"] >> pref.b_type
S["disabilities"] >> pref.disabilities
S["organ_data"] >> pref.organ_data
S["rlimb_data"] >> pref.rlimb_data
S["body_markings"] >> pref.body_markings
S["synth_color"] >> pref.synth_color
S["synth_red"] >> pref.r_synth
S["synth_green"] >> pref.g_synth
S["synth_blue"] >> pref.b_synth
S["synth_markings"] >> pref.synth_markings
S["bgstate"] >> pref.bgstate
S["body_descriptors"] >> pref.body_descriptors
S["Wingdings"] >> pref.wingdings //YWadd start
S["colorblind_mono"] >> pref.colorblind_mono
S["colorblind_vulp"] >> pref.colorblind_vulp
S["colorblind_taj"] >> pref.colorblind_taj
S["haemophilia"] >> pref.haemophilia //YWadd end
S["ear_style"] >> pref.ear_style
S["r_ears"] >> pref.r_ears
S["g_ears"] >> pref.g_ears
S["b_ears"] >> pref.b_ears
S["r_ears2"] >> pref.r_ears2
S["g_ears2"] >> pref.g_ears2
S["b_ears2"] >> pref.b_ears2
S["r_ears3"] >> pref.r_ears3
S["g_ears3"] >> pref.g_ears3
S["b_ears3"] >> pref.b_ears3
S["tail_style"] >> pref.tail_style
S["r_tail"] >> pref.r_tail
S["g_tail"] >> pref.g_tail
S["b_tail"] >> pref.b_tail
S["r_tail2"] >> pref.r_tail2
S["g_tail2"] >> pref.g_tail2
S["b_tail2"] >> pref.b_tail2
S["r_tail3"] >> pref.r_tail3
S["g_tail3"] >> pref.g_tail3
S["b_tail3"] >> pref.b_tail3
S["wing_style"] >> pref.wing_style
S["r_wing"] >> pref.r_wing
S["g_wing"] >> pref.g_wing
S["b_wing"] >> pref.b_wing
S["r_wing2"] >> pref.r_wing2
S["g_wing2"] >> pref.g_wing2
S["b_wing2"] >> pref.b_wing2
S["r_wing3"] >> pref.r_wing3
S["g_wing3"] >> pref.g_wing3
S["b_wing3"] >> pref.b_wing3
S["digitigrade"] >> pref.digitigrade
/datum/category_item/player_setup_item/general/body/load_character(list/save_data)
pref.species = save_data["species"]
pref.r_hair = save_data["hair_red"]
pref.g_hair = save_data["hair_green"]
pref.b_hair = save_data["hair_blue"]
pref.r_facial = save_data["facial_red"]
pref.r_grad = save_data["grad_red"]
pref.g_grad = save_data["grad_green"]
pref.b_grad = save_data["grad_blue"]
pref.g_facial = save_data["facial_green"]
pref.b_facial = save_data["facial_blue"]
pref.s_tone = save_data["skin_tone"]
pref.r_skin = save_data["skin_red"]
pref.g_skin = save_data["skin_green"]
pref.b_skin = save_data["skin_blue"]
pref.h_style = save_data["hair_style_name"]
pref.f_style = save_data["facial_style_name"]
pref.grad_style = save_data["grad_style_name"]
pref.r_eyes = save_data["eyes_red"]
pref.g_eyes = save_data["eyes_green"]
pref.b_eyes = save_data["eyes_blue"]
pref.b_type = save_data["b_type"]
pref.disabilities = save_data["disabilities"]
pref.organ_data = save_data["organ_data"]
pref.rlimb_data = save_data["rlimb_data"]
pref.body_markings = save_data["body_markings"]
pref.synth_color = save_data["synth_color"]
pref.r_synth = save_data["synth_red"]
pref.g_synth = save_data["synth_green"]
pref.b_synth = save_data["synth_blue"]
pref.synth_markings = save_data["synth_markings"]
pref.bgstate = save_data["bgstate"]
pref.body_descriptors = save_data["body_descriptors"]
//YWadd start
pref.wingdings = save_data["Wingdings"]
pref.colorblind_mono = save_data["colorblind_mono"]
pref.colorblind_vulp = save_data["colorblind_vulp"]
pref.colorblind_taj = save_data["colorblind_taj"]
pref.haemophilia = save_data["haemophilia"]
//YWadd end
pref.ear_style = save_data["ear_style"]
pref.r_ears = save_data["r_ears"]
pref.g_ears = save_data["g_ears"]
pref.b_ears = save_data["b_ears"]
pref.r_ears2 = save_data["r_ears2"]
pref.g_ears2 = save_data["g_ears2"]
pref.b_ears2 = save_data["b_ears2"]
pref.r_ears3 = save_data["r_ears3"]
pref.g_ears3 = save_data["g_ears3"]
pref.b_ears3 = save_data["b_ears3"]
pref.tail_style = save_data["tail_style"]
pref.r_tail = save_data["r_tail"]
pref.g_tail = save_data["g_tail"]
pref.b_tail = save_data["b_tail"]
pref.r_tail2 = save_data["r_tail2"]
pref.g_tail2 = save_data["g_tail2"]
pref.b_tail2 = save_data["b_tail2"]
pref.r_tail3 = save_data["r_tail3"]
pref.g_tail3 = save_data["g_tail3"]
pref.b_tail3 = save_data["b_tail3"]
pref.wing_style = save_data["wing_style"]
pref.r_wing = save_data["r_wing"]
pref.g_wing = save_data["g_wing"]
pref.b_wing = save_data["b_wing"]
pref.r_wing2 = save_data["r_wing2"]
pref.g_wing2 = save_data["g_wing2"]
pref.b_wing2 = save_data["b_wing2"]
pref.r_wing3 = save_data["r_wing3"]
pref.g_wing3 = save_data["g_wing3"]
pref.b_wing3 = save_data["b_wing3"]
pref.digitigrade = save_data["digitigrade"]
/datum/category_item/player_setup_item/general/body/save_character(var/savefile/S)
S["species"] << pref.species
S["hair_red"] << pref.r_hair
S["hair_green"] << pref.g_hair
S["hair_blue"] << pref.b_hair
S["grad_red"] << pref.r_grad
S["grad_green"] << pref.g_grad
S["grad_blue"] << pref.b_grad
S["facial_red"] << pref.r_facial
S["facial_green"] << pref.g_facial
S["facial_blue"] << pref.b_facial
S["skin_tone"] << pref.s_tone
S["skin_red"] << pref.r_skin
S["skin_green"] << pref.g_skin
S["skin_blue"] << pref.b_skin
S["hair_style_name"] << pref.h_style
S["grad_style_name"] << pref.grad_style
S["facial_style_name"] << pref.f_style
S["grad_style_name"] << pref.grad_style
S["eyes_red"] << pref.r_eyes
S["eyes_green"] << pref.g_eyes
S["eyes_blue"] << pref.b_eyes
S["b_type"] << pref.b_type
S["disabilities"] << pref.disabilities
S["organ_data"] << pref.organ_data
S["rlimb_data"] << pref.rlimb_data
S["body_markings"] << pref.body_markings
S["synth_color"] << pref.synth_color
S["synth_red"] << pref.r_synth
S["synth_green"] << pref.g_synth
S["synth_blue"] << pref.b_synth
S["synth_markings"] << pref.synth_markings
S["bgstate"] << pref.bgstate
S["body_descriptors"] << pref.body_descriptors
S["Wingdings"] << pref.wingdings //YWadd start
S["colorblind_mono"] << pref.colorblind_mono
S["colorblind_vulp"] << pref.colorblind_vulp
S["colorblind_taj"] << pref.colorblind_taj
S["haemophilia"] << pref.haemophilia //YWadd end
S["ear_style"] << pref.ear_style
S["r_ears"] << pref.r_ears
S["g_ears"] << pref.g_ears
S["b_ears"] << pref.b_ears
S["r_ears2"] << pref.r_ears2
S["g_ears2"] << pref.g_ears2
S["b_ears2"] << pref.b_ears2
S["r_ears3"] << pref.r_ears3
S["g_ears3"] << pref.g_ears3
S["b_ears3"] << pref.b_ears3
S["tail_style"] << pref.tail_style
S["r_tail"] << pref.r_tail
S["g_tail"] << pref.g_tail
S["b_tail"] << pref.b_tail
S["r_tail2"] << pref.r_tail2
S["g_tail2"] << pref.g_tail2
S["b_tail2"] << pref.b_tail2
S["r_tail3"] << pref.r_tail3
S["g_tail3"] << pref.g_tail3
S["b_tail3"] << pref.b_tail3
S["wing_style"] << pref.wing_style
S["r_wing"] << pref.r_wing
S["g_wing"] << pref.g_wing
S["b_wing"] << pref.b_wing
S["r_wing2"] << pref.r_wing2
S["g_wing2"] << pref.g_wing2
S["b_wing2"] << pref.b_wing2
S["r_wing3"] << pref.r_wing3
S["g_wing3"] << pref.g_wing3
S["b_wing3"] << pref.b_wing3
S["digitigrade"] << pref.digitigrade
/datum/category_item/player_setup_item/general/body/save_character(list/save_data)
save_data["species"] = pref.species
save_data["hair_red"] = pref.r_hair
save_data["hair_green"] = pref.g_hair
save_data["hair_blue"] = pref.b_hair
save_data["grad_red"] = pref.r_grad
save_data["grad_green"] = pref.g_grad
save_data["grad_blue"] = pref.b_grad
save_data["facial_red"] = pref.r_facial
save_data["facial_green"] = pref.g_facial
save_data["facial_blue"] = pref.b_facial
save_data["skin_tone"] = pref.s_tone
save_data["skin_red"] = pref.r_skin
save_data["skin_green"] = pref.g_skin
save_data["skin_blue"] = pref.b_skin
save_data["hair_style_name"] = pref.h_style
save_data["facial_style_name"] = pref.f_style
save_data["grad_style_name"] = pref.grad_style
save_data["eyes_red"] = pref.r_eyes
save_data["eyes_green"] = pref.g_eyes
save_data["eyes_blue"] = pref.b_eyes
save_data["b_type"] = pref.b_type
save_data["disabilities"] = pref.disabilities
save_data["organ_data"] = pref.organ_data
save_data["rlimb_data"] = pref.rlimb_data
save_data["body_markings"] = pref.body_markings
save_data["synth_color"] = pref.synth_color
save_data["synth_red"] = pref.r_synth
save_data["synth_green"] = pref.g_synth
save_data["synth_blue"] = pref.b_synth
save_data["synth_markings"] = pref.synth_markings
save_data["bgstate"] = pref.bgstate
save_data["body_descriptors"] = pref.body_descriptors
//YWadd start
save_data["Wingdings"] = pref.wingdings
save_data["colorblind_mono"] = pref.colorblind_mono
save_data["colorblind_vulp"] = pref.colorblind_vulp
save_data["colorblind_taj"] = pref.colorblind_taj
save_data["haemophilia"] = pref.haemophilia
//YWadd end
save_data["ear_style"] = pref.ear_style
save_data["r_ears"] = pref.r_ears
save_data["g_ears"] = pref.g_ears
save_data["b_ears"] = pref.b_ears
save_data["r_ears2"] = pref.r_ears2
save_data["g_ears2"] = pref.g_ears2
save_data["b_ears2"] = pref.b_ears2
save_data["r_ears3"] = pref.r_ears3
save_data["g_ears3"] = pref.g_ears3
save_data["b_ears3"] = pref.b_ears3
save_data["tail_style"] = pref.tail_style
save_data["r_tail"] = pref.r_tail
save_data["g_tail"] = pref.g_tail
save_data["b_tail"] = pref.b_tail
save_data["r_tail2"] = pref.r_tail2
save_data["g_tail2"] = pref.g_tail2
save_data["b_tail2"] = pref.b_tail2
save_data["r_tail3"] = pref.r_tail3
save_data["g_tail3"] = pref.g_tail3
save_data["b_tail3"] = pref.b_tail3
save_data["wing_style"] = pref.wing_style
save_data["r_wing"] = pref.r_wing
save_data["g_wing"] = pref.g_wing
save_data["b_wing"] = pref.b_wing
save_data["r_wing2"] = pref.r_wing2
save_data["g_wing2"] = pref.g_wing2
save_data["b_wing2"] = pref.b_wing2
save_data["r_wing3"] = pref.r_wing3
save_data["g_wing3"] = pref.g_wing3
save_data["b_wing3"] = pref.b_wing3
save_data["digitigrade"] = pref.digitigrade
/datum/category_item/player_setup_item/general/body/sanitize_character(var/savefile/S)
/datum/category_item/player_setup_item/general/body/sanitize_character()
if(!pref.species || !(pref.species in GLOB.playable_species))
pref.species = SPECIES_HUMAN
pref.r_hair = sanitize_integer(pref.r_hair, 0, 255, initial(pref.r_hair))
@@ -539,11 +538,17 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
++ind
if(ind > 1)
. += ", "
var/datum/robolimb/R
if(pref.rlimb_data[name] && all_robolimbs[pref.rlimb_data[name]])
R = all_robolimbs[pref.rlimb_data[name]]
var/datum/robolimb/R = basic_robolimb
var/key = pref.rlimb_data[name]
if(!istext(key))
log_debug("Bad rlimb_data for [key_name(pref.client)], [name] was set to [key]")
to_chat(usr, span_warning("Error loading robot limb data for `[name]`, clearing pref."))
pref.rlimb_data -= name
else
R = basic_robolimb
R = LAZYACCESS(all_robolimbs, key)
if(!istype(R))
R = basic_robolimb
. += "\t[R.company] [organ_name] prosthesis"
else if(status == "amputated")
++ind

View File

@@ -6,23 +6,23 @@
name = "Clothing"
sort_order = 4
/datum/category_item/player_setup_item/general/equipment/load_character(var/savefile/S)
S["all_underwear"] >> pref.all_underwear
S["all_underwear_metadata"] >> pref.all_underwear_metadata
S["backbag"] >> pref.backbag
S["pdachoice"] >> pref.pdachoice
S["communicator_visibility"] >> pref.communicator_visibility
S["ttone"] >> pref.ringtone // CHOMPEdit - We use ttone in the pref so that it doesnt get reset
//S["shoe_hater"] >> pref.shoe_hater //RS ADD //CHOMPRemove, remove RS No shoes
/datum/category_item/player_setup_item/general/equipment/load_character(list/save_data)
pref.all_underwear = save_data["all_underwear"]
pref.all_underwear_metadata = save_data["all_underwear_metadata"]
pref.backbag = save_data["backbag"]
pref.pdachoice = save_data["pdachoice"]
pref.communicator_visibility = save_data["communicator_visibility"]
pref.ringtone = save_data["ttone"] // CHOMPEdit - We use ttone in the pref so that it doesnt get reset
//pref.shoe_hater = save_data["shoe_hater"] //CHOMPRemove, remove RS No shoes
/datum/category_item/player_setup_item/general/equipment/save_character(var/savefile/S)
S["all_underwear"] << pref.all_underwear
S["all_underwear_metadata"] << pref.all_underwear_metadata
S["backbag"] << pref.backbag
S["pdachoice"] << pref.pdachoice
S["communicator_visibility"] << pref.communicator_visibility
S["ttone"] << pref.ringtone // CHOMPEdit - We use ttone in the pref so that it doesnt get reset
//S["shoe_hater"] << pref.shoe_hater //RS ADD //CHOMPRemove, remove RS No shoes
/datum/category_item/player_setup_item/general/equipment/save_character(list/save_data)
save_data["all_underwear"] = pref.all_underwear
save_data["all_underwear_metadata"] = pref.all_underwear_metadata
save_data["backbag"] = pref.backbag
save_data["pdachoice"] = pref.pdachoice
save_data["communicator_visibility"] = pref.communicator_visibility
save_data["ttone"] = pref.ringtone // CHOMPEdit - We use ttone in the pref so that it doesnt get reset
//save_data["shoe_hater"] = pref.shoe_hater //CHOMPRemove, remove RS No shoes
var/global/list/valid_ringtones = list(
"beep",

View File

@@ -1,28 +1,27 @@
/datum/category_item/player_setup_item/general/background
name = "Background"
sort_order = 5
/datum/category_item/player_setup_item/general/background/load_character(list/save_data)
pref.med_record = save_data["med_record"]
pref.sec_record = save_data["sec_record"]
pref.gen_record = save_data["gen_record"]
pref.home_system = save_data["home_system"]
pref.birthplace = save_data["birthplace"]
pref.citizenship = save_data["citizenship"]
pref.faction = save_data["faction"]
pref.religion = save_data["religion"]
pref.economic_status = save_data["economic_status"]
/datum/category_item/player_setup_item/general/background/load_character(var/savefile/S)
S["med_record"] >> pref.med_record
S["sec_record"] >> pref.sec_record
S["gen_record"] >> pref.gen_record
S["home_system"] >> pref.home_system
S["birthplace"] >> pref.birthplace
S["citizenship"] >> pref.citizenship
S["faction"] >> pref.faction
S["religion"] >> pref.religion
S["economic_status"] >> pref.economic_status
/datum/category_item/player_setup_item/general/background/save_character(var/savefile/S)
S["med_record"] << pref.med_record
S["sec_record"] << pref.sec_record
S["gen_record"] << pref.gen_record
S["home_system"] << pref.home_system
S["birthplace"] << pref.birthplace
S["citizenship"] << pref.citizenship
S["faction"] << pref.faction
S["religion"] << pref.religion
S["economic_status"] << pref.economic_status
/datum/category_item/player_setup_item/general/background/save_character(list/save_data)
save_data["med_record"] = pref.med_record
save_data["sec_record"] = pref.sec_record
save_data["gen_record"] = pref.gen_record
save_data["home_system"] = pref.home_system
save_data["birthplace"] = pref.birthplace
save_data["citizenship"] = pref.citizenship
save_data["faction"] = pref.faction
save_data["religion"] = pref.religion
save_data["economic_status"] = pref.economic_status
/datum/category_item/player_setup_item/general/background/sanitize_character()
if(!pref.home_system) pref.home_system = "Unset"

View File

@@ -2,37 +2,37 @@
name = "Flavor"
sort_order = 6
/datum/category_item/player_setup_item/general/flavor/load_character(var/savefile/S)
S["flavor_texts_general"] >> pref.flavor_texts["general"]
S["flavor_texts_head"] >> pref.flavor_texts["head"]
S["flavor_texts_face"] >> pref.flavor_texts["face"]
S["flavor_texts_eyes"] >> pref.flavor_texts["eyes"]
S["flavor_texts_torso"] >> pref.flavor_texts["torso"]
S["flavor_texts_arms"] >> pref.flavor_texts["arms"]
S["flavor_texts_hands"] >> pref.flavor_texts["hands"]
S["flavor_texts_legs"] >> pref.flavor_texts["legs"]
S["flavor_texts_feet"] >> pref.flavor_texts["feet"]
S["custom_link"] >> pref.custom_link
/datum/category_item/player_setup_item/general/flavor/load_character(list/save_data)
pref.flavor_texts["general"] = save_data["flavor_texts_general"]
pref.flavor_texts["head"] = save_data["flavor_texts_head"]
pref.flavor_texts["face"] = save_data["flavor_texts_face"]
pref.flavor_texts["eyes"] = save_data["flavor_texts_eyes"]
pref.flavor_texts["torso"] = save_data["flavor_texts_torso"]
pref.flavor_texts["arms"] = save_data["flavor_texts_arms"]
pref.flavor_texts["hands"] = save_data["flavor_texts_hands"]
pref.flavor_texts["legs"] = save_data["flavor_texts_legs"]
pref.flavor_texts["feet"] = save_data["flavor_texts_feet"]
pref.custom_link = save_data["custom_link"]
//Flavour text for robots.
S["flavour_texts_robot_Default"] >> pref.flavour_texts_robot["Default"]
pref.flavour_texts_robot["Default"] = save_data["flavour_texts_robot_Default"]
for(var/module in robot_module_types)
S["flavour_texts_robot_[module]"] >> pref.flavour_texts_robot[module]
pref.flavour_texts_robot[module] = save_data["flavour_texts_robot_[module]"]
/datum/category_item/player_setup_item/general/flavor/save_character(var/savefile/S)
S["flavor_texts_general"] << pref.flavor_texts["general"]
S["flavor_texts_head"] << pref.flavor_texts["head"]
S["flavor_texts_face"] << pref.flavor_texts["face"]
S["flavor_texts_eyes"] << pref.flavor_texts["eyes"]
S["flavor_texts_torso"] << pref.flavor_texts["torso"]
S["flavor_texts_arms"] << pref.flavor_texts["arms"]
S["flavor_texts_hands"] << pref.flavor_texts["hands"]
S["flavor_texts_legs"] << pref.flavor_texts["legs"]
S["flavor_texts_feet"] << pref.flavor_texts["feet"]
S["custom_link"] << pref.custom_link
/datum/category_item/player_setup_item/general/flavor/save_character(list/save_data)
save_data["flavor_texts_general"] = pref.flavor_texts["general"]
save_data["flavor_texts_head"] = pref.flavor_texts["head"]
save_data["flavor_texts_face"] = pref.flavor_texts["face"]
save_data["flavor_texts_eyes"] = pref.flavor_texts["eyes"]
save_data["flavor_texts_torso"] = pref.flavor_texts["torso"]
save_data["flavor_texts_arms"] = pref.flavor_texts["arms"]
save_data["flavor_texts_hands"] = pref.flavor_texts["hands"]
save_data["flavor_texts_legs"] = pref.flavor_texts["legs"]
save_data["flavor_texts_feet"] = pref.flavor_texts["feet"]
save_data["custom_link"] = pref.custom_link
S["flavour_texts_robot_Default"] << pref.flavour_texts_robot["Default"]
save_data["flavour_texts_robot_Default"] = pref.flavour_texts_robot["Default"]
for(var/module in robot_module_types)
S["flavour_texts_robot_[module]"] << pref.flavour_texts_robot[module]
save_data["flavour_texts_robot_[module]"] = pref.flavour_texts_robot[module]
/datum/category_item/player_setup_item/general/flavor/sanitize_character()
return

View File

@@ -2,41 +2,41 @@
name = "UI"
sort_order = 1
/datum/category_item/player_setup_item/player_global/ui/load_preferences(var/savefile/S)
S["UI_style"] >> pref.UI_style
S["UI_style_color"] >> pref.UI_style_color
S["UI_style_alpha"] >> pref.UI_style_alpha
S["ooccolor"] >> pref.ooccolor
S["tooltipstyle"] >> pref.tooltipstyle
S["client_fps"] >> pref.client_fps
S["ambience_freq"] >> pref.ambience_freq
S["ambience_chance"] >> pref.ambience_chance
S["tgui_fancy"] >> pref.tgui_fancy
S["tgui_lock"] >> pref.tgui_lock
S["tgui_input_mode"] >> pref.tgui_input_mode
S["tgui_large_buttons"] >> pref.tgui_large_buttons
S["tgui_swapped_buttons"] >> pref.tgui_swapped_buttons
S["obfuscate_key"] >> pref.obfuscate_key
S["obfuscate_job"] >> pref.obfuscate_job
S["chat_timestamp"] >> pref.chat_timestamp
/datum/category_item/player_setup_item/player_global/ui/load_preferences(datum/json_savefile/savefile)
pref.UI_style = savefile.get_entry("UI_style")
pref.UI_style_color = savefile.get_entry("UI_style_color")
pref.UI_style_alpha = savefile.get_entry("UI_style_alpha")
pref.ooccolor = savefile.get_entry("ooccolor")
pref.tooltipstyle = savefile.get_entry("tooltipstyle")
pref.client_fps = savefile.get_entry("client_fps")
pref.ambience_freq = savefile.get_entry("ambience_freq")
pref.ambience_chance = savefile.get_entry("ambience_chance")
pref.tgui_fancy = savefile.get_entry("tgui_fancy")
pref.tgui_lock = savefile.get_entry("tgui_lock")
pref.tgui_input_mode = savefile.get_entry("tgui_input_mode")
pref.tgui_large_buttons = savefile.get_entry("tgui_large_buttons")
pref.tgui_swapped_buttons = savefile.get_entry("tgui_swapped_buttons")
pref.obfuscate_key = savefile.get_entry("obfuscate_key")
pref.obfuscate_job = savefile.get_entry("obfuscate_job")
pref.chat_timestamp = savefile.get_entry("chat_timestamp")
/datum/category_item/player_setup_item/player_global/ui/save_preferences(var/savefile/S)
S["UI_style"] << pref.UI_style
S["UI_style_color"] << pref.UI_style_color
S["UI_style_alpha"] << pref.UI_style_alpha
S["ooccolor"] << pref.ooccolor
S["tooltipstyle"] << pref.tooltipstyle
S["client_fps"] << pref.client_fps
S["ambience_freq"] << pref.ambience_freq
S["ambience_chance"] << pref.ambience_chance
S["tgui_fancy"] << pref.tgui_fancy
S["tgui_lock"] << pref.tgui_lock
S["tgui_input_mode"] << pref.tgui_input_mode
S["tgui_large_buttons"] << pref.tgui_large_buttons
S["tgui_swapped_buttons"] << pref.tgui_swapped_buttons
S["obfuscate_key"] << pref.obfuscate_key
S["obfuscate_job"] << pref.obfuscate_job
S["chat_timestamp"] << pref.chat_timestamp
/datum/category_item/player_setup_item/player_global/ui/save_preferences(datum/json_savefile/savefile)
savefile.set_entry("UI_style", pref.UI_style)
savefile.set_entry("UI_style_color", pref.UI_style_color)
savefile.set_entry("UI_style_alpha", pref.UI_style_alpha)
savefile.set_entry("ooccolor", pref.ooccolor)
savefile.set_entry("tooltipstyle", pref.tooltipstyle)
savefile.set_entry("client_fps", pref.client_fps)
savefile.set_entry("ambience_freq", pref.ambience_freq)
savefile.set_entry("ambience_chance", pref.ambience_chance)
savefile.set_entry("tgui_fancy", pref.tgui_fancy)
savefile.set_entry("tgui_lock", pref.tgui_lock)
savefile.set_entry("tgui_input_mode", pref.tgui_input_mode)
savefile.set_entry("tgui_large_buttons", pref.tgui_large_buttons)
savefile.set_entry("tgui_swapped_buttons", pref.tgui_swapped_buttons)
savefile.set_entry("obfuscate_key", pref.obfuscate_key)
savefile.set_entry("obfuscate_job", pref.obfuscate_job)
savefile.set_entry("chat_timestamp", pref.chat_timestamp)
/datum/category_item/player_setup_item/player_global/ui/sanitize_preferences()
pref.UI_style = sanitize_inlist(pref.UI_style, all_ui_styles, initial(pref.UI_style))

View File

@@ -1,141 +1,20 @@
/datum/preferences
var/preferences_enabled = null
var/preferences_disabled = null
/datum/category_item/player_setup_item/player_global/settings
name = "Settings"
sort_order = 2
/datum/category_item/player_setup_item/player_global/settings/load_preferences(var/savefile/S)
S["lastchangelog"] >> pref.lastchangelog
S["lastnews"] >> pref.lastnews
S["lastlorenews"] >> pref.lastlorenews
S["default_slot"] >> pref.default_slot
S["preferences"] >> pref.preferences_enabled
S["preferences_disabled"] >> pref.preferences_disabled
/datum/category_item/player_setup_item/player_global/settings/load_preferences(datum/json_savefile/savefile)
pref.lastchangelog = savefile.get_entry("lastchangelog")
pref.lastnews = savefile.get_entry("lastnews")
pref.lastlorenews = savefile.get_entry("lastlorenews")
pref.default_slot = savefile.get_entry("default_slot")
/datum/category_item/player_setup_item/player_global/settings/save_preferences(var/savefile/S)
S["lastchangelog"] << pref.lastchangelog
S["lastnews"] << pref.lastnews
S["lastlorenews"] << pref.lastlorenews
S["default_slot"] << pref.default_slot
S["preferences"] << pref.preferences_enabled
S["preferences_disabled"] << pref.preferences_disabled
/datum/category_item/player_setup_item/player_global/settings/save_preferences(datum/json_savefile/savefile)
savefile.set_entry("lastchangelog", pref.lastchangelog)
savefile.set_entry("lastnews", pref.lastnews)
savefile.set_entry("lastlorenews", pref.lastlorenews)
savefile.set_entry("default_slot", pref.default_slot)
/datum/category_item/player_setup_item/player_global/settings/sanitize_preferences()
// Ensure our preferences are lists.
if(!istype(pref.preferences_enabled, /list))
pref.preferences_enabled = list()
if(!istype(pref.preferences_disabled, /list))
pref.preferences_disabled = list()
// Arrange preferences that have never been enabled/disabled.
var/list/client_preference_keys = list()
for(var/datum/client_preference/client_pref as anything in get_client_preferences())
client_preference_keys += client_pref.key
if((client_pref.key in pref.preferences_enabled) || (client_pref.key in pref.preferences_disabled))
continue
if(client_pref.enabled_by_default)
pref.preferences_enabled += client_pref.key
else
pref.preferences_disabled += client_pref.key
// Clean out preferences that no longer exist.
for(var/key in pref.preferences_enabled)
if(!(key in client_preference_keys))
pref.preferences_enabled -= key
for(var/key in pref.preferences_disabled)
if(!(key in client_preference_keys))
pref.preferences_disabled -= key
pref.lastchangelog = sanitize_text(pref.lastchangelog, initial(pref.lastchangelog))
pref.lastnews = sanitize_text(pref.lastnews, initial(pref.lastnews))
pref.default_slot = sanitize_integer(pref.default_slot, 1, CONFIG_GET(number/character_slots), initial(pref.default_slot)) // CHOMPEdit
/datum/category_item/player_setup_item/player_global/settings/content(var/mob/user)
. = list()
. += "<b>Preferences</b><br>"
. += "<table>"
var/mob/pref_mob = preference_mob()
for(var/datum/client_preference/client_pref as anything in get_client_preferences())
if(!client_pref.may_toggle(pref_mob))
continue
. += "<tr><td>[client_pref.description]: </td>"
if(pref_mob.is_preference_enabled(client_pref.key))
. += "<td><span class='linkOn'><b>[client_pref.enabled_description]</b></span></td> <td><a href='?src=\ref[src];toggle_off=[client_pref.key]'>[client_pref.disabled_description]</a></td>"
else
. += "<td><a href='?src=\ref[src];toggle_on=[client_pref.key]'>[client_pref.enabled_description]</a></td> <td><span class='linkOn'><b>[client_pref.disabled_description]</b></span></td>"
. += "</tr>"
. += "</table>"
return jointext(., "")
/datum/category_item/player_setup_item/player_global/settings/OnTopic(var/href,var/list/href_list, var/mob/user)
var/mob/pref_mob = preference_mob()
if(href_list["toggle_on"])
. = pref_mob.set_preference(href_list["toggle_on"], TRUE)
else if(href_list["toggle_off"])
. = pref_mob.set_preference(href_list["toggle_off"], FALSE)
if(.)
return TOPIC_REFRESH
return ..()
/**
* This can take either a single preference datum or a list of preferences, and will return true if *all* preferences in the arguments are enabled.
*/
/client/proc/is_preference_enabled(var/preference)
if(!islist(preference))
preference = list(preference)
for(var/p in preference)
var/datum/client_preference/cp = get_client_preference(p)
if(!prefs || !cp || !istype(cp, /datum/client_preference) || !(cp.key in prefs.preferences_enabled))
return FALSE
return TRUE
/client/proc/set_preference(var/preference, var/set_preference)
var/datum/client_preference/cp = get_client_preference(preference)
if(!cp)
return FALSE
preference = cp.key
if(set_preference && !(preference in prefs.preferences_enabled))
return toggle_preference(cp)
else if(!set_preference && (preference in prefs.preferences_enabled))
return toggle_preference(cp)
/client/proc/toggle_preference(var/preference, var/set_preference)
var/datum/client_preference/cp = get_client_preference(preference)
if(!cp)
return FALSE
preference = cp.key
var/enabled
if(preference in prefs.preferences_disabled)
prefs.preferences_enabled |= preference
prefs.preferences_disabled -= preference
enabled = TRUE
. = TRUE
else if(preference in prefs.preferences_enabled)
prefs.preferences_enabled -= preference
prefs.preferences_disabled |= preference
enabled = FALSE
. = TRUE
if(.)
cp.toggled(mob, enabled)
/mob/proc/is_preference_enabled(var/preference)
if(!client)
return FALSE
return client.is_preference_enabled(preference)
/mob/proc/set_preference(var/preference, var/set_preference)
if(!client)
return FALSE
if(!client.prefs)
log_debug("Client prefs found to be null for mob [src] and client [ckey], this should be investigated.")
return FALSE
return client.set_preference(preference, set_preference)

View File

@@ -4,7 +4,7 @@
var/datum/paiCandidate/candidate
/datum/category_item/player_setup_item/player_global/pai/load_preferences(var/savefile/S)
/datum/category_item/player_setup_item/player_global/pai/load_preferences(datum/json_savefile/savefile)
if(!candidate)
candidate = new()
var/preference_mob = preference_mob()
@@ -18,7 +18,7 @@
candidate.savefile_load(preference_mob)
/datum/category_item/player_setup_item/player_global/pai/save_preferences(var/savefile/S)
/datum/category_item/player_setup_item/player_global/pai/save_preferences(datum/json_savefile/savefile)
if(!candidate)
return

View File

@@ -2,12 +2,12 @@
name = "OOC"
sort_order = 4
/datum/category_item/player_setup_item/player_global/ooc/load_preferences(var/savefile/S)
S["ignored_players"] >> pref.ignored_players
/datum/category_item/player_setup_item/player_global/ooc/load_preferences(datum/json_savefile/savefile)
pref.ignored_players = savefile.get_entry("ignored_players")
/datum/category_item/player_setup_item/player_global/ooc/save_preferences(var/savefile/S)
S["ignored_players"] << pref.ignored_players
/datum/category_item/player_setup_item/player_global/ooc/save_preferences(datum/json_savefile/savefile)
savefile.set_entry("ignored_players", pref.ignored_players)
/*
/datum/category_item/player_setup_item/player_global/ooc/sanitize_preferences()
@@ -39,4 +39,4 @@
return TOPIC_REFRESH
return ..()
*/
*/

View File

@@ -1,503 +0,0 @@
var/list/_client_preferences
var/list/_client_preferences_by_key
var/list/_client_preferences_by_type
/proc/get_client_preferences()
if(!_client_preferences)
_client_preferences = list()
for(var/datum/client_preference/client_type as anything in subtypesof(/datum/client_preference))
if(initial(client_type.description))
_client_preferences += new client_type()
return _client_preferences
/proc/get_client_preference(var/datum/client_preference/preference)
if(istype(preference))
return preference
if(ispath(preference))
return get_client_preference_by_type(preference)
return get_client_preference_by_key(preference)
/proc/get_client_preference_by_key(var/preference)
if(!_client_preferences_by_key)
_client_preferences_by_key = list()
for(var/datum/client_preference/client_pref as anything in get_client_preferences())
_client_preferences_by_key[client_pref.key] = client_pref
return _client_preferences_by_key[preference]
/proc/get_client_preference_by_type(var/preference)
if(!_client_preferences_by_type)
_client_preferences_by_type = list()
for(var/datum/client_preference/client_pref as anything in get_client_preferences())
_client_preferences_by_type[client_pref.type] = client_pref
return _client_preferences_by_type[preference]
/datum/client_preference
var/description
var/key
var/enabled_by_default = TRUE
var/enabled_description = "Yes"
var/disabled_description = "No"
/datum/client_preference/proc/may_toggle(var/mob/preference_mob)
return TRUE
/datum/client_preference/proc/toggled(var/mob/preference_mob, var/enabled)
return
/*********************
* Player Preferences *
*********************/
/datum/client_preference/play_admin_midis
description ="Play admin midis"
key = "SOUND_MIDI"
/datum/client_preference/play_lobby_music
description ="Play lobby music"
key = "SOUND_LOBBY"
/datum/client_preference/play_lobby_music/toggled(var/mob/preference_mob, var/enabled)
if(!preference_mob.client || !preference_mob.client.media)
return
if(enabled)
preference_mob.client.playtitlemusic()
else
preference_mob.client.media.stop_music()
/datum/client_preference/play_ambiance
description ="Play ambience"
key = "SOUND_AMBIENCE"
/datum/client_preference/play_ambiance/toggled(var/mob/preference_mob, var/enabled)
if(!enabled)
preference_mob << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1)
preference_mob << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2)
//VOREStation Add - Need to put it here because it should be ordered riiiight here.
/datum/client_preference/play_jukebox
description ="Play jukebox music"
key = "SOUND_JUKEBOX"
/datum/client_preference/play_jukebox/toggled(var/mob/preference_mob, var/enabled)
if(!enabled)
preference_mob.stop_all_music()
else
preference_mob.update_music()
/datum/client_preference/eating_noises
description = "Eating Noises"
key = "EATING_NOISES"
enabled_description = "Noisy"
disabled_description = "Silent"
/datum/client_preference/digestion_noises
description = "Digestion Noises"
key = "DIGEST_NOISES"
enabled_description = "Noisy"
disabled_description = "Silent"
/datum/client_preference/belch_noises // Belching noises - pref toggle for 'em
description = "Burping"
key = "BELCH_NOISES"
enabled_description = "Noisy"
disabled_description = "Silent"
enabled_by_default = FALSE //CHOMPedit
/datum/client_preference/emote_noises
description = "Emote Noises" //MERP
key = "EMOTE_NOISES"
enabled_description = "Noisy"
disabled_description = "Silent"
/datum/client_preference/whisubtle_vis
description = "Whi/Subtles Ghost Visible"
key = "WHISUBTLE_VIS"
enabled_description = "Visible"
disabled_description = "Hidden"
enabled_by_default = FALSE
/datum/client_preference/ghost_see_whisubtle
description = "See subtles/whispers as ghost"
key = "GHOST_SEE_WHISUBTLE"
enabled_description = "Visible"
disabled_description = "Hidden"
enabled_by_default = TRUE
//VOREStation Add End
/datum/client_preference/weather_sounds
description ="Weather sounds"
key = "SOUND_WEATHER"
enabled_description = "Audible"
disabled_description = "Silent"
/datum/client_preference/supermatter_hum
description ="Supermatter hum"
key = "SOUND_SUPERMATTER"
enabled_description = "Audible"
disabled_description = "Silent"
/datum/client_preference/ghost_ears
description ="Ghost ears"
key = "CHAT_GHOSTEARS"
enabled_description = "All Speech"
disabled_description = "Nearby"
/datum/client_preference/ghost_sight
description ="Ghost sight"
key = "CHAT_GHOSTSIGHT"
enabled_description = "All Emotes"
disabled_description = "Nearby"
/datum/client_preference/ghost_radio
description ="Ghost radio"
key = "CHAT_GHOSTRADIO"
enabled_description = "All Chatter"
disabled_description = "Nearby"
/datum/client_preference/chat_tags
description ="Chat tags"
key = "CHAT_SHOWICONS"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/air_pump_noise
description ="Air Pump Ambient Noise"
key = "SOUND_AIRPUMP"
enabled_description = "Audible"
disabled_description = "Silent"
/datum/client_preference/looping_alarms // CHOMPStation Add: Looping Alarms
description ="Looping Alarm Sounds"
key = "SOUND_ALARMLOOP"
enabled_description = "Audible"
disabled_description = "Silent"
/datum/client_preference/fridge_hum // CHOMPStation Add: Misc Sounds
description ="Fridge Humming"
key = "SOUND_FRIDGEHUM"
enabled_description = "Audible"
disabled_description = "Silent"
/datum/client_preference/old_door_sounds
description ="Old Door Sounds"
key = "SOUND_OLDDOORS"
enabled_description = "Old"
disabled_description = "New"
enabled_by_default = FALSE
/datum/client_preference/department_door_sounds
description ="Department-Specific Door Sounds"
key = "SOUND_DEPARTMENTDOORS"
enabled_description = "Enabled"
disabled_description = "Disabled"
/datum/client_preference/pickup_sounds
description = "Picked Up Item Sounds"
key = "SOUND_PICKED"
enabled_description = "Enabled"
disabled_description = "Disabled"
/datum/client_preference/drop_sounds
description = "Dropped Item Sounds"
key = "SOUND_DROPPED"
enabled_description = "Enabled"
disabled_description = "Disabled"
/datum/client_preference/mob_tooltips
description ="Mob tooltips"
key = "MOB_TOOLTIPS"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/inv_tooltips
description ="Inventory tooltips"
key = "INV_TOOLTIPS"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/attack_icons
description ="Attack icons"
key = "ATTACK_ICONS"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/precision_placement
description ="Precision Placement"
key = "PRECISE_PLACEMENT"
enabled_description = "Active"
disabled_description = "Inactive"
/datum/client_preference/hotkeys_default
description ="Hotkeys Default"
key = "HUD_HOTKEYS"
enabled_description = "Enabled"
disabled_description = "Disabled"
enabled_by_default = TRUE // Backwards compatibility //CHOMP Edit: It's 2020, use your WASD keys by default. Flipped to True.
/datum/client_preference/show_typing_indicator
description ="Typing indicator"
key = "SHOW_TYPING"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/show_typing_indicator/toggled(var/mob/preference_mob, var/enabled)
if(!enabled)
preference_mob.client?.stop_thinking()
/datum/client_preference/show_typing_indicator_subtle
description ="Typing indicator (subtle)"
key = "SHOW_TYPING_SUBTLE"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/show_ooc
description ="OOC chat"
key = "CHAT_OOC"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/show_looc
description ="LOOC chat"
key = "CHAT_LOOC"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/show_dsay
description ="Dead chat"
key = "CHAT_DEAD"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/check_mention
description ="Emphasize Name Mention"
key = "CHAT_MENTION"
enabled_description = "Emphasize"
disabled_description = "Normal"
/datum/client_preference/show_progress_bar
description ="Progress Bar"
key = "SHOW_PROGRESS"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/safefiring
description = "Gun Firing Intent Requirement"
key = "SAFE_FIRING"
enabled_description = "Safe"
disabled_description = "Dangerous"
/datum/client_preference/browser_style
description = "Fake NanoUI Browser Style"
key = "BROWSER_STYLED"
enabled_description = "Fancy"
disabled_description = "Plain"
/datum/client_preference/ambient_occlusion
description = "Fake Ambient Occlusion"
key = "AMBIENT_OCCLUSION_PREF"
enabled_by_default = FALSE
enabled_description = "On"
disabled_description = "Off"
/datum/client_preference/ambient_occlusion/toggled(var/mob/preference_mob, var/enabled)
. = ..()
if(preference_mob && preference_mob.plane_holder)
var/datum/plane_holder/PH = preference_mob.plane_holder
PH.set_ao(VIS_OBJS, enabled)
PH.set_ao(VIS_MOBS, enabled)
/datum/client_preference/instrument_toggle
description ="Hear In-game Instruments"
key = "SOUND_INSTRUMENT"
/datum/client_preference/vchat_enable
description = "Enable/Disable TGChat"
key = "VCHAT_ENABLE"
enabled_description = "Enabled"
disabled_description = "Disabled"
/datum/client_preference/status_indicators
description = "Status Indicators"
key = "SHOW_STATUS"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/radio_sounds
description = "Radio Sounds"
key = "RADIO_SOUNDS"
enabled_description = "On"
disabled_description = "Off"
/datum/client_preference/say_sounds
description = "Say Sounds"
key = "SAY_SOUNDS"
enabled_description = "On"
disabled_description = "Off"
/datum/client_preference/emote_sounds
description = "Me Sounds"
key = "EMOTE_SOUNDS"
enabled_description = "On"
disabled_description = "Off"
/datum/client_preference/whisper_sounds
description = "Whisper Sounds"
key = "WHISPER_SOUNDS"
enabled_description = "On"
disabled_description = "Off"
/datum/client_preference/subtle_sounds
description = "Subtle Sounds"
key = "SUBTLE_SOUNDS"
enabled_description = "On"
disabled_description = "Off"
/datum/client_preference/vore_health_bars
description = "Vore Health Bars"
key = "VORE_HEALTH_BARS"
enabled_description = "Enabled"
disabled_description = "Disabled"
/datum/client_preference/runechat_mob
description = "Runechat (Mobs)"
key = "RUNECHAT_MOB"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/runechat_obj
description = "Runechat (Objs)"
key = "RUNECHAT_OBJ"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/runechat_border
description = "Runechat Message Border"
key = "RUNECHAT_BORDER"
enabled_description = "Show"
disabled_description = "Hide"
enabled_by_default = TRUE
/datum/client_preference/runechat_long_messages
description = "Runechat Message Length"
key = "RUNECHAT_LONG"
enabled_description = "Long"
disabled_description = "Short"
enabled_by_default = FALSE
/datum/client_preference/status_indicators/toggled(mob/preference_mob, enabled)
. = ..()
if(preference_mob && preference_mob.plane_holder)
var/datum/plane_holder/PH = preference_mob.plane_holder
PH.set_vis(VIS_STATUS, enabled)
/datum/client_preference/show_lore_news
description = "Lore News Popup"
key = "NEWS_POPUP"
enabled_by_default = TRUE
enabled_description = "Popup New On Login"
disabled_description = "Do Nothing"
/datum/client_preference/play_mentorhelp_ping
description = "Mentorhelps"
key = "SOUND_MENTORHELP"
enabled_description = "Hear"
disabled_description = "Silent"
/datum/client_preference/player_tips
description = "Receive Tips Periodically"
key = "RECEIVE_TIPS"
enabled_description = "Enabled"
disabled_description = "Disabled"
/datum/client_preference/pain_frequency
description = "Pain Messages Cooldown"
key = "PAIN_FREQUENCY"
enabled_by_default = FALSE
enabled_description = "Extended"
disabled_description = "Default"
// CHOMPAdd
/datum/client_preference/sleep_music
description = "Sleeping Music"
key = "SLEEP_MUSIC"
enabled_description = "Audible"
disabled_description = "Silent"
// CHOMPAdd End
/datum/client_preference/auto_afk
description = "Automatic AFK Status"
key = "AUTO_AFK"
enabled_by_default = TRUE
enabled_description = "Automatic"
disabled_description = "Manual Only"
/datum/client_preference/tgui_say
description = "TGUI Say: Use TGUI For Say Input"
key = "TGUI_SAY"
enabled_by_default = TRUE
enabled_description = "Yes"
disabled_description = "No"
/datum/client_preference/tgui_say_light
description = "TGUI Say: Use Light Mode"
key = "TGUI_SAY_LIGHT_MODE"
enabled_by_default = FALSE
enabled_description = "Yes"
disabled_description = "No"
/********************
* Staff Preferences *
********************/
/datum/client_preference/admin/may_toggle(var/mob/preference_mob)
return check_rights(R_ADMIN|R_EVENT, 0, preference_mob)
/datum/client_preference/mod/may_toggle(var/mob/preference_mob)
return check_rights(R_MOD|R_ADMIN, 0, preference_mob)
/datum/client_preference/debug/may_toggle(var/mob/preference_mob)
return check_rights(R_DEBUG|R_ADMIN, 0, preference_mob)
/datum/client_preference/mod/show_attack_logs
description = "Attack Log Messages"
key = "CHAT_ATTACKLOGS"
enabled_description = "Show"
disabled_description = "Hide"
enabled_by_default = FALSE
/datum/client_preference/debug/show_debug_logs
description = "Debug Log Messages"
key = "CHAT_DEBUGLOGS"
enabled_description = "Show"
disabled_description = "Hide"
enabled_by_default = FALSE
/datum/client_preference/admin/show_chat_prayers
description = "Chat Prayers"
key = "CHAT_PRAYER"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/holder/may_toggle(var/mob/preference_mob)
return preference_mob && preference_mob.client && preference_mob.client.holder
/datum/client_preference/holder/play_adminhelp_ping
description = "Adminhelps"
key = "SOUND_ADMINHELP"
enabled_description = "Hear"
disabled_description = "Silent"
/datum/client_preference/holder/hear_radio
description = "Radio chatter"
key = "CHAT_RADIO"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/holder/show_rlooc
description ="Remote LOOC chat"
key = "CHAT_RLOOC"
enabled_description = "Show"
disabled_description = "Hide"
/datum/client_preference/holder/show_staff_dsay
description ="Staff Deadchat"
key = "CHAT_ADSAY"
enabled_description = "Show"
disabled_description = "Hide"

View File

@@ -45,19 +45,19 @@ var/list/gear_datums = list()
sort_order = 1
var/current_tab = "General"
/datum/category_item/player_setup_item/loadout/load_character(var/savefile/S)
from_file(S["gear_list"], pref.gear_list)
from_file(S["gear_slot"], pref.gear_slot)
/datum/category_item/player_setup_item/loadout/load_character(list/save_data)
pref.gear_list = save_data["gear_list"]
pref.gear_slot = save_data["gear_slot"]
if(pref.gear_list!=null && pref.gear_slot!=null)
pref.gear = pref.gear_list["[pref.gear_slot]"]
else
from_file(S["gear"], pref.gear)
pref.gear = save_data["gear"]
pref.gear_slot = 1
/datum/category_item/player_setup_item/loadout/save_character(var/savefile/S)
/datum/category_item/player_setup_item/loadout/save_character(list/save_data)
pref.gear_list["[pref.gear_slot]"] = pref.gear
to_file(S["gear_list"], pref.gear_list)
to_file(S["gear_slot"], pref.gear_slot)
save_data["gear_list"] = pref.gear_list
save_data["gear_slot"] = pref.gear_slot
/datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost)
. = list()

View File

@@ -2,51 +2,51 @@
name = "Occupation"
sort_order = 1
/datum/category_item/player_setup_item/occupation/load_character(var/savefile/S)
S["alternate_option"] >> pref.alternate_option
S["job_civilian_high"] >> pref.job_civilian_high
S["job_civilian_med"] >> pref.job_civilian_med
S["job_civilian_low"] >> pref.job_civilian_low
S["job_medsci_high"] >> pref.job_medsci_high
S["job_medsci_med"] >> pref.job_medsci_med
S["job_medsci_low"] >> pref.job_medsci_low
S["job_engsec_high"] >> pref.job_engsec_high
S["job_engsec_med"] >> pref.job_engsec_med
S["job_engsec_low"] >> pref.job_engsec_low
/datum/category_item/player_setup_item/occupation/load_character(list/save_data)
pref.alternate_option = save_data["alternate_option"]
pref.job_civilian_high = save_data["job_civilian_high"]
pref.job_civilian_med = save_data["job_civilian_med"]
pref.job_civilian_low = save_data["job_civilian_low"]
pref.job_medsci_high = save_data["job_medsci_high"]
pref.job_medsci_med = save_data["job_medsci_med"]
pref.job_medsci_low = save_data["job_medsci_low"]
pref.job_engsec_high = save_data["job_engsec_high"]
pref.job_engsec_med = save_data["job_engsec_med"]
pref.job_engsec_low = save_data["job_engsec_low"]
//VOREStation Add
S["job_talon_low"] >> pref.job_talon_low
S["job_talon_med"] >> pref.job_talon_med
S["job_talon_high"] >> pref.job_talon_high
pref.job_talon_low = save_data["job_talon_low"]
pref.job_talon_med = save_data["job_talon_med"]
pref.job_talon_high = save_data["job_talon_high"]
//VOREStation Add End
S["player_alt_titles"] >> pref.player_alt_titles
pref.player_alt_titles = save_data["player_alt_titles"]
//CHOMPStation Add
S["job_other_low"] >> pref.job_other_low
S["job_other_med"] >> pref.job_other_med
S["job_other_high"] >> pref.job_other_high
pref.job_other_low = save_data["job_other_low"]
pref.job_other_med = save_data["job_other_med"]
pref.job_other_high = save_data["job_other_high"]
//CHOMPStation Add End
/datum/category_item/player_setup_item/occupation/save_character(var/savefile/S)
S["alternate_option"] << pref.alternate_option
S["job_civilian_high"] << pref.job_civilian_high
S["job_civilian_med"] << pref.job_civilian_med
S["job_civilian_low"] << pref.job_civilian_low
S["job_medsci_high"] << pref.job_medsci_high
S["job_medsci_med"] << pref.job_medsci_med
S["job_medsci_low"] << pref.job_medsci_low
S["job_engsec_high"] << pref.job_engsec_high
S["job_engsec_med"] << pref.job_engsec_med
S["job_engsec_low"] << pref.job_engsec_low
/datum/category_item/player_setup_item/occupation/save_character(list/save_data)
save_data["alternate_option"] = pref.alternate_option
save_data["job_civilian_high"] = pref.job_civilian_high
save_data["job_civilian_med"] = pref.job_civilian_med
save_data["job_civilian_low"] = pref.job_civilian_low
save_data["job_medsci_high"] = pref.job_medsci_high
save_data["job_medsci_med"] = pref.job_medsci_med
save_data["job_medsci_low"] = pref.job_medsci_low
save_data["job_engsec_high"] = pref.job_engsec_high
save_data["job_engsec_med"] = pref.job_engsec_med
save_data["job_engsec_low"] = pref.job_engsec_low
//VOREStation Add
S["job_talon_low"] << pref.job_talon_low
S["job_talon_med"] << pref.job_talon_med
S["job_talon_high"] << pref.job_talon_high
save_data["job_talon_low"] = pref.job_talon_low
save_data["job_talon_med"] = pref.job_talon_med
save_data["job_talon_high"] = pref.job_talon_high
//VOREStation Add End
S["player_alt_titles"] << pref.player_alt_titles
save_data["player_alt_titles"] = pref.player_alt_titles
//CHOMPStation Add
S["job_other_low"] << pref.job_other_low
S["job_other_med"] << pref.job_other_med
S["job_other_high"] << pref.job_other_high
//CHOMPStation Add End
save_data["job_other_low"] = pref.job_other_low
save_data["job_other_med"] = pref.job_other_med
save_data["job_other_high"] = pref.job_other_high
//CHOMPStation Add Endarkens/revert-16279-revert-16253-reprefs
/datum/category_item/player_setup_item/occupation/sanitize_character()
pref.alternate_option = sanitize_integer(pref.alternate_option, 0, 2, initial(pref.alternate_option))

View File

@@ -59,21 +59,21 @@
for(var/datum/category_group/player_setup_category/PS in categories)
PS.sanitize_setup()
/datum/category_collection/player_setup_collection/proc/load_character(var/savefile/S)
/datum/category_collection/player_setup_collection/proc/load_character(list/save_data)
for(var/datum/category_group/player_setup_category/PS in categories)
PS.load_character(S)
PS.load_character(save_data)
/datum/category_collection/player_setup_collection/proc/save_character(var/savefile/S)
/datum/category_collection/player_setup_collection/proc/save_character(list/save_data)
for(var/datum/category_group/player_setup_category/PS in categories)
PS.save_character(S)
PS.save_character(save_data)
/datum/category_collection/player_setup_collection/proc/load_preferences(var/savefile/S)
/datum/category_collection/player_setup_collection/proc/load_preferences(datum/json_savefile/savefile)
for(var/datum/category_group/player_setup_category/PS in categories)
PS.load_preferences(S)
PS.load_preferences(savefile)
/datum/category_collection/player_setup_collection/proc/save_preferences(var/savefile/S)
/datum/category_collection/player_setup_collection/proc/save_preferences(datum/json_savefile/savefile)
for(var/datum/category_group/player_setup_category/PS in categories)
PS.save_preferences(S)
PS.save_preferences(savefile)
/datum/category_collection/player_setup_collection/proc/copy_to_mob(var/mob/living/carbon/human/C)
for(var/datum/category_group/player_setup_category/PS in categories)
@@ -86,6 +86,7 @@
dat += "[PS.name] " // TODO: Check how to properly mark a href/button selected in a classic browser window
else
dat += "<a href='?src=\ref[src];category=\ref[PS]'>[PS.name]</a> "
dat += "<a href='?src=\ref[src];game_prefs=1'>Game Options</a>"
return dat
/datum/category_collection/player_setup_collection/proc/content(var/mob/user)
@@ -105,6 +106,9 @@
selected_category = category
. = 1
else if(href_list["game_prefs"])
user.client.prefs.tgui_interact(user)
if(.)
user.client.prefs.ShowChoices(user)
@@ -123,29 +127,29 @@
for(var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_character()
/datum/category_group/player_setup_category/proc/load_character(var/savefile/S)
/datum/category_group/player_setup_category/proc/load_character(list/save_data)
// Load all data, then sanitize it.
// Need due to, for example, the 01_basic module relying on species having been loaded to sanitize correctly but that isn't loaded until module 03_body.
for(var/datum/category_item/player_setup_item/PI in items)
PI.load_character(S)
PI.load_character(save_data)
/datum/category_group/player_setup_category/proc/save_character(var/savefile/S)
/datum/category_group/player_setup_category/proc/save_character(list/save_data)
// Sanitize all data, then save it
for(var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_character()
for(var/datum/category_item/player_setup_item/PI in items)
PI.save_character(S)
PI.save_character(save_data)
/datum/category_group/player_setup_category/proc/load_preferences(var/savefile/S)
/datum/category_group/player_setup_category/proc/load_preferences(datum/json_savefile/savefile)
for(var/datum/category_item/player_setup_item/PI in items)
PI.load_preferences(S)
PI.load_preferences(savefile)
/datum/category_group/player_setup_category/proc/save_preferences(var/savefile/S)
/datum/category_group/player_setup_category/proc/save_preferences(datum/json_savefile/savefile)
for(var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_preferences()
for(var/datum/category_item/player_setup_item/PI in items)
PI.save_preferences(S)
PI.save_preferences(savefile)
/datum/category_group/player_setup_category/proc/copy_to_mob(var/mob/living/carbon/human/C)
for(var/datum/category_item/player_setup_item/PI in items)
@@ -188,25 +192,25 @@
/*
* Called when the item is asked to load per character settings
*/
/datum/category_item/player_setup_item/proc/load_character(var/savefile/S)
/datum/category_item/player_setup_item/proc/load_character(list/save_data)
return
/*
* Called when the item is asked to save per character settings
*/
/datum/category_item/player_setup_item/proc/save_character(var/savefile/S)
/datum/category_item/player_setup_item/proc/save_character(list/save_data)
return
/*
* Called when the item is asked to load user/global settings
*/
/datum/category_item/player_setup_item/proc/load_preferences(var/savefile/S)
/datum/category_item/player_setup_item/proc/load_preferences(datum/json_savefile/savefile)
return
/*
* Called when the item is asked to save user/global settings
*/
/datum/category_item/player_setup_item/proc/save_preferences(var/savefile/S)
/datum/category_item/player_setup_item/proc/save_preferences(datum/json_savefile/savefile)
return
/*

View File

@@ -2,15 +2,15 @@
name = "Skills"
sort_order = 1
/datum/category_item/player_setup_item/skills/load_character(var/savefile/S)
S["skills"] >> pref.skills
S["used_skillpoints"] >> pref.used_skillpoints
S["skill_specialization"] >> pref.skill_specialization
/datum/category_item/player_setup_item/skills/load_character(list/save_data)
pref.skills = save_data["skills"]
pref.used_skillpoints = save_data["used_skillpoints"]
pref.skill_specialization = save_data["skill_specialization"]
/datum/category_item/player_setup_item/skills/save_character(var/savefile/S)
S["skills"] << pref.skills
S["used_skillpoints"] << pref.used_skillpoints
S["skill_specialization"] << pref.skill_specialization
/datum/category_item/player_setup_item/skills/save_character(list/save_data)
save_data["skills"] = pref.skills
save_data["used_skillpoints"] = pref.used_skillpoints
save_data["skill_specialization"] = pref.skill_specialization
/datum/category_item/player_setup_item/skills/sanitize_character()
if(SKILLS == null) setup_skills()

View File

@@ -35,11 +35,11 @@ var/list/trait_categories = list() // The categories available for the trait men
sort_order = 1
var/current_tab = "Physical"
/datum/category_item/player_setup_item/traits/load_character(var/savefile/S)
S["traits"] >> pref.traits
/datum/category_item/player_setup_item/traits/load_character(list/save_data)
pref.traits = save_data["traits"]
/datum/category_item/player_setup_item/traits/save_character(var/savefile/S)
S["traits"] << pref.traits
/datum/category_item/player_setup_item/traits/save_character(list/save_data)
save_data["traits"] = pref.traits
/datum/category_item/player_setup_item/traits/content()

View File

@@ -7,11 +7,11 @@
name = "General Volume"
sort_order = 1
/datum/category_item/player_setup_item/volume_sliders/volume/load_preferences(var/savefile/S)
S["volume_channels"] >> pref.volume_channels
/datum/category_item/player_setup_item/volume_sliders/volume/load_preferences(datum/json_savefile/savefile)
pref.volume_channels = savefile.get_entry("volume_channels")
/datum/category_item/player_setup_item/volume_sliders/volume/save_preferences(var/savefile/S)
S["volume_channels"] << pref.volume_channels
/datum/category_item/player_setup_item/volume_sliders/volume/save_preferences(datum/json_savefile/savefile)
savefile.set_entry("volume_channels", pref.volume_channels)
/datum/category_item/player_setup_item/volume_sliders/volume/sanitize_preferences()
if(isnull(pref.volume_channels))

View File

@@ -6,13 +6,13 @@
name = "Media"
sort_order = 2
/datum/category_item/player_setup_item/volume_sliders/media/load_preferences(var/savefile/S)
S["media_volume"] >> pref.media_volume
S["media_player"] >> pref.media_player
/datum/category_item/player_setup_item/volume_sliders/media/load_preferences(datum/json_savefile/savefile)
pref.media_volume = savefile.get_entry("media_volume")
pref.media_player = savefile.get_entry("media_player")
/datum/category_item/player_setup_item/volume_sliders/media/save_preferences(var/savefile/S)
S["media_volume"] << pref.media_volume
S["media_player"] << pref.media_player
/datum/category_item/player_setup_item/volume_sliders/media/save_preferences(datum/json_savefile/savefile)
savefile.set_entry("media_volume", pref.media_volume)
savefile.set_entry("media_player", pref.media_player)
/datum/category_item/player_setup_item/volume_sliders/media/sanitize_preferences()
pref.media_volume = isnum(pref.media_volume) ? CLAMP(pref.media_volume, 0, 1) : initial(pref.media_volume)

View File

@@ -24,32 +24,35 @@
name = "Size"
sort_order = 2
/datum/category_item/player_setup_item/vore/size/load_character(var/savefile/S)
S["size_multiplier"] >> pref.size_multiplier
S["weight_vr"] >> pref.weight_vr
S["weight_gain"] >> pref.weight_gain
S["weight_loss"] >> pref.weight_loss
S["fuzzy"] >> pref.fuzzy
S["offset_override"] >> pref.offset_override
S["voice_freq"] >> pref.voice_freq
S["voice_sound"] >> pref.voice_sound
S["custom_speech_bubble"] >> pref.custom_speech_bubble
S["custom_footstep"] >> pref.custom_footstep // CHOMPEdit
S["species_sound"] >> pref.species_sound // CHOMPEdit
/datum/category_item/player_setup_item/vore/size/save_character(var/savefile/S)
S["size_multiplier"] << pref.size_multiplier
S["weight_vr"] << pref.weight_vr
S["weight_gain"] << pref.weight_gain
S["weight_loss"] << pref.weight_loss
S["fuzzy"] << pref.fuzzy
S["offset_override"] << pref.offset_override
S["voice_freq"] << pref.voice_freq
S["voice_sound"] << pref.voice_sound
S["custom_speech_bubble"] << pref.custom_speech_bubble
S["custom_footstep"] << pref.custom_footstep // CHOMPEdit
S["species_sound"] << pref.species_sound // CHOMPEdit
/datum/category_item/player_setup_item/vore/size/load_character(list/save_data)
pref.size_multiplier = save_data["size_multiplier"]
pref.weight_vr = save_data["weight_vr"]
pref.weight_gain = save_data["weight_gain"]
pref.weight_loss = save_data["weight_loss"]
pref.fuzzy = save_data["fuzzy"]
pref.offset_override = save_data["offset_override"]
pref.voice_freq = save_data["voice_freq"]
pref.voice_sound = save_data["voice_sound"]
pref.custom_speech_bubble = save_data["custom_speech_bubble"]
//CHOMPAdd Start
pref.custom_footstep = save_data["custom_footstep"]
pref.species_sound = save_data["species_sound"]
//CHOMPAdd End
/datum/category_item/player_setup_item/vore/size/save_character(list/save_data)
save_data["size_multiplier"] = pref.size_multiplier
save_data["weight_vr"] = pref.weight_vr
save_data["weight_gain"] = pref.weight_gain
save_data["weight_loss"] = pref.weight_loss
save_data["fuzzy"] = pref.fuzzy
save_data["offset_override"] = pref.offset_override
save_data["voice_freq"] = pref.voice_freq
save_data["voice_sound"] = pref.voice_sound
save_data["custom_speech_bubble"] = pref.custom_speech_bubble
//CHOMPAdd Start
save_data["custom_footstep"] = pref.custom_footstep
save_data["species_sound"] = pref.species_sound
//CHOMPAdd End
/datum/category_item/player_setup_item/vore/size/sanitize_character()
pref.weight_vr = sanitize_integer(pref.weight_vr, WEIGHT_MIN, WEIGHT_MAX, initial(pref.weight_vr))

View File

@@ -14,13 +14,13 @@
name = "Egg appearance."
sort_order = 3
/datum/category_item/player_setup_item/vore/egg/load_character(var/savefile/S)
S["vore_egg_type"] >> pref.vore_egg_type
S["autohiss"] >> pref.autohiss // VOREStation Add
/datum/category_item/player_setup_item/vore/egg/load_character(list/save_data)
pref.vore_egg_type = save_data["vore_egg_type"]
pref.autohiss = save_data["autohiss"]
/datum/category_item/player_setup_item/vore/egg/save_character(var/savefile/S)
S["vore_egg_type"] << pref.vore_egg_type
S["autohiss"] << pref.autohiss // VOREStation Add
/datum/category_item/player_setup_item/vore/egg/save_character(list/save_data)
save_data["vore_egg_type"] = pref.vore_egg_type
save_data["autohiss"] = pref.autohiss
/datum/category_item/player_setup_item/vore/egg/sanitize_character()
pref.vore_egg_type = sanitize_inlist(pref.vore_egg_type, global_vore_egg_types, initial(pref.vore_egg_type))

View File

@@ -9,16 +9,15 @@
name = "Resleeving"
sort_order = 4
/datum/category_item/player_setup_item/vore/resleeve/load_character(var/savefile/S)
S["resleeve_lock"] >> pref.resleeve_lock
S["resleeve_scan"] >> pref.resleeve_scan
S["mind_scan"] >> pref.mind_scan
/datum/category_item/player_setup_item/vore/resleeve/load_character(list/save_data)
pref.resleeve_lock = save_data["resleeve_lock"]
pref.resleeve_scan = save_data["resleeve_scan"]
pref.mind_scan = save_data["mind_scan"]
/datum/category_item/player_setup_item/vore/resleeve/save_character(var/savefile/S)
S["resleeve_lock"] << pref.resleeve_lock
S["resleeve_scan"] << pref.resleeve_scan
S["mind_scan"] << pref.mind_scan
/datum/category_item/player_setup_item/vore/resleeve/save_character(list/save_data)
save_data["resleeve_lock"] = pref.resleeve_lock
save_data["resleeve_scan"] = pref.resleeve_scan
save_data["mind_scan"] = pref.mind_scan
/datum/category_item/player_setup_item/vore/resleeve/sanitize_character()
pref.resleeve_lock = sanitize_integer(pref.resleeve_lock, 0, 1, initial(pref.resleeve_lock))

View File

@@ -7,12 +7,12 @@
name = "Persistence"
sort_order = 5
/datum/category_item/player_setup_item/vore/persistence/load_character(var/savefile/S)
S["persistence_settings"] >> pref.persistence_settings
/datum/category_item/player_setup_item/vore/persistence/load_character(list/save_data)
pref.persistence_settings = save_data["persistence_settings"]
sanitize_character() // Don't let new characters start off with nulls
/datum/category_item/player_setup_item/vore/persistence/save_character(var/savefile/S)
S["persistence_settings"] << pref.persistence_settings
/datum/category_item/player_setup_item/vore/persistence/save_character(list/save_data)
save_data["persistence_settings"] = pref.persistence_settings
/datum/category_item/player_setup_item/vore/persistence/sanitize_character()
pref.persistence_settings = sanitize_integer(pref.persistence_settings, 0, (1<<(PERSIST_COUNT+1)-1), initial(pref.persistence_settings))

View File

@@ -8,13 +8,13 @@
name = "VS Events"
sort_order = 6
/datum/category_item/player_setup_item/vore/vantag/load_character(var/savefile/S)
S["vantag_volunteer"] >> pref.vantag_volunteer
S["vantag_preference"] >> pref.vantag_preference
/datum/category_item/player_setup_item/vore/vantag/load_character(list/save_data)
pref.vantag_volunteer = save_data["vantag_volunteer"]
pref.vantag_preference = save_data["vantag_preference"]
/datum/category_item/player_setup_item/vore/vantag/save_character(var/savefile/S)
S["vantag_volunteer"] << pref.vantag_volunteer
S["vantag_preference"] << pref.vantag_preference
/datum/category_item/player_setup_item/vore/vantag/save_character(list/save_data)
save_data["vantag_volunteer"] = pref.vantag_volunteer
save_data["vantag_preference"] = pref.vantag_preference
/datum/category_item/player_setup_item/vore/vantag/sanitize_character()
pref.vantag_volunteer = sanitize_integer(pref.vantag_volunteer, 0, 1, initial(pref.vantag_volunteer))

View File

@@ -113,47 +113,47 @@ var/global/list/valid_bloodreagents = list("default","iron","copper","phoron","s
name = "Traits"
sort_order = 7
/datum/category_item/player_setup_item/vore/traits/load_character(var/savefile/S)
S["custom_species"] >> pref.custom_species
S["custom_base"] >> pref.custom_base
S["pos_traits"] >> pref.pos_traits
S["neu_traits"] >> pref.neu_traits
S["neg_traits"] >> pref.neg_traits
S["blood_color"] >> pref.blood_color
S["blood_reagents"] >> pref.blood_reagents
/datum/category_item/player_setup_item/vore/traits/load_character(list/save_data)
pref.custom_species = save_data["custom_species"]
pref.custom_base = save_data["custom_base"]
pref.pos_traits = text2path_list(save_data["pos_traits"])
pref.neu_traits = text2path_list(save_data["neu_traits"])
pref.neg_traits = text2path_list(save_data["neg_traits"])
pref.blood_color = save_data["blood_color"]
pref.blood_reagents = save_data["blood_reagents"]
S["traits_cheating"] >> pref.traits_cheating
S["max_traits"] >> pref.max_traits
S["trait_points"] >> pref.starting_trait_points
pref.traits_cheating = save_data["traits_cheating"]
pref.max_traits = save_data["max_traits"]
pref.starting_trait_points = save_data["trait_points"]
S["custom_say"] >> pref.custom_say
S["custom_whisper"] >> pref.custom_whisper
S["custom_ask"] >> pref.custom_ask
S["custom_exclaim"] >> pref.custom_exclaim
pref.custom_say = save_data["custom_say"]
pref.custom_whisper = save_data["custom_whisper"]
pref.custom_ask = save_data["custom_ask"]
pref.custom_exclaim = save_data["custom_exclaim"]
S["custom_heat"] >> pref.custom_heat
S["custom_cold"] >> pref.custom_cold
pref.custom_heat = save_data["custom_heat"]
pref.custom_cold = save_data["custom_cold"]
/datum/category_item/player_setup_item/vore/traits/save_character(var/savefile/S)
S["custom_species"] << pref.custom_species
S["custom_base"] << pref.custom_base
S["pos_traits"] << pref.pos_traits
S["neu_traits"] << pref.neu_traits
S["neg_traits"] << pref.neg_traits
S["blood_color"] << pref.blood_color
S["blood_reagents"] << pref.blood_reagents
/datum/category_item/player_setup_item/vore/traits/save_character(list/save_data)
save_data["custom_species"] = pref.custom_species
save_data["custom_base"] = pref.custom_base
save_data["pos_traits"] = pref.pos_traits
save_data["neu_traits"] = pref.neu_traits
save_data["neg_traits"] = pref.neg_traits
save_data["blood_color"] = pref.blood_color
save_data["blood_reagents"] = pref.blood_reagents
S["traits_cheating"] << pref.traits_cheating
S["max_traits"] << pref.max_traits
S["trait_points"] << pref.starting_trait_points
save_data["traits_cheating"] = pref.traits_cheating
save_data["max_traits"] = pref.max_traits
save_data["trait_points"] = pref.starting_trait_points
S["custom_say"] << pref.custom_say
S["custom_whisper"] << pref.custom_whisper
S["custom_ask"] << pref.custom_ask
S["custom_exclaim"] << pref.custom_exclaim
save_data["custom_say"] = pref.custom_say
save_data["custom_whisper"] = pref.custom_whisper
save_data["custom_ask"] = pref.custom_ask
save_data["custom_exclaim"] = pref.custom_exclaim
S["custom_heat"] << pref.custom_heat
S["custom_cold"] << pref.custom_cold
save_data["custom_heat"] = pref.custom_heat
save_data["custom_cold"] = pref.custom_cold
/datum/category_item/player_setup_item/vore/traits/sanitize_character()
if(!pref.pos_traits) pref.pos_traits = list()
@@ -192,13 +192,16 @@ var/global/list/valid_bloodreagents = list("default","iron","copper","phoron","s
//Neutral traits
for(var/datum/trait/path as anything in pref.neu_traits)
if(!(path in neutral_traits))
to_world_log("removing [path] for not being in neutral_traits")
pref.neu_traits -= path
continue
if(!(pref.species == SPECIES_CUSTOM) && !(path in everyone_traits_neutral))
to_world_log("removing [path] for not being a custom species")
pref.neu_traits -= path
continue
var/take_flags = initial(path.can_take)
if((pref.dirty_synth && !(take_flags & SYNTHETICS)) || (pref.gross_meatbag && !(take_flags & ORGANICS)))
to_world_log("removing [path] for being a dirty synth")
pref.neu_traits -= path
//Negative traits
for(var/datum/trait/path as anything in pref.neg_traits)

View File

@@ -5,19 +5,34 @@
var/list/nif_savedata
// Definition of the stuff for NIFs
// Magic bullshit, they're stored separately from everything else
/datum/category_item/player_setup_item/vore/nif
name = "NIF Data"
sort_order = 8
/datum/category_item/player_setup_item/vore/nif/load_character(var/savefile/S)
S["nif_path"] >> pref.nif_path
S["nif_durability"] >> pref.nif_durability
S["nif_savedata"] >> pref.nif_savedata
/proc/nif_savefile_path(ckey)
if(!ckey)
return
return "data/player_saves/[copytext(ckey,1,2)]/[ckey]/nif.json"
/datum/category_item/player_setup_item/vore/nif/save_character(var/savefile/S)
S["nif_path"] << pref.nif_path
S["nif_durability"] << pref.nif_durability
S["nif_savedata"] << pref.nif_savedata
/datum/category_item/player_setup_item/vore/nif/load_character()
var/datum/json_savefile/savefile = new /datum/json_savefile(nif_savefile_path(pref.client_ckey))
var/list/save_data_file = savefile.get_entry("character[pref.default_slot]", list())
pref.nif_path = save_data_file["nif_path"]
pref.nif_durability = save_data_file["nif_durability"]
pref.nif_savedata = save_data_file["nif_savedata"]
/datum/category_item/player_setup_item/vore/nif/save_character()
var/datum/json_savefile/savefile = new /datum/json_savefile(nif_savefile_path(pref.client_ckey))
var/list/save_data_file = savefile.get_entry("character[pref.default_slot]", list())
save_data_file["nif_path"] = pref.nif_path
save_data_file["nif_durability"] = pref.nif_durability
save_data_file["nif_savedata"] = pref.nif_savedata
savefile.set_entry("character[pref.default_slot]", save_data_file)
savefile.save()
/datum/category_item/player_setup_item/vore/nif/sanitize_character()
if(pref.nif_path && !ispath(pref.nif_path)) //We have at least a text string that should be a path.
@@ -38,23 +53,8 @@
/datum/category_item/player_setup_item/vore/nif/copy_to_mob(var/mob/living/carbon/human/character)
//If you had a NIF...
if((character.type == /mob/living/carbon/human) && ispath(pref.nif_path) && pref.nif_durability)
new pref.nif_path(character,pref.nif_durability,pref.nif_savedata)
/*
//And now here's the trick. We wipe these so that if they die, they lose the NIF.
//Backup implants will start saving this again periodically, and so will cryo'ing out.
pref.nif_path = null
pref.nif_durability = null
pref.nif_savedata = null
*/
//No we do not, that's lame and admins have to re-NIF them later.
//If they leave round after they get their NIF extracted, it will save as 'gone' anyway
//The NIF will save automatically every time durability changes too now.
var/savefile/S = new /savefile(pref.path)
if(!S) WARNING ("Couldn't load NIF save savefile? [pref.real_name]")
S.cd = "/character[pref.default_slot]"
save_character(S)
if(istype(character) && ispath(pref.nif_path) && pref.nif_durability)
new pref.nif_path(character, pref.nif_durability, pref.nif_savedata)
/datum/category_item/player_setup_item/vore/nif/content(var/mob/user)
. += "<b>NIF:</b> [ispath(pref.nif_path) ? "Present" : "None"]"

View File

@@ -2,31 +2,35 @@
name = "Misc Settings"
sort_order = 9
/datum/category_item/player_setup_item/vore/misc/load_character(var/savefile/S)
S["show_in_directory"] >> pref.show_in_directory
S["directory_tag"] >> pref.directory_tag
S["directory_gendertag"] >> pref.directory_gendertag // CHOMPStation Edit: Character Directory Update
S["directory_sexualitytag"] >> pref.directory_sexualitytag // CHOMPStation Edit: Character Directory Update
S["directory_erptag"] >> pref.directory_erptag
S["directory_ad"] >> pref.directory_ad
S["sensorpref"] >> pref.sensorpref
S["capture_crystal"] >> pref.capture_crystal
S["auto_backup_implant"] >> pref.auto_backup_implant
S["borg_petting"] >> pref.borg_petting
S["stomach_vision"] >> pref.stomach_vision
/datum/category_item/player_setup_item/vore/misc/load_character(list/save_data)
pref.show_in_directory = save_data["show_in_directory"]
pref.directory_tag = save_data["directory_tag"]
//CHOMPAdd Start
pref.directory_gendertag = save_data["directory_gendertag"]
pref.directory_sexualitytag = save_data["directory_sexualitytag"]
//CHOMPAdd End
pref.directory_erptag = save_data["directory_erptag"]
pref.directory_ad = save_data["directory_ad"]
pref.sensorpref = save_data["sensorpref"]
pref.capture_crystal = save_data["capture_crystal"]
pref.auto_backup_implant = save_data["auto_backup_implant"]
pref.borg_petting = save_data["borg_petting"]
pref.stomach_vision = save_data["stomach_vision"]
/datum/category_item/player_setup_item/vore/misc/save_character(var/savefile/S)
S["show_in_directory"] << pref.show_in_directory
S["directory_tag"] << pref.directory_tag
S["directory_gendertag"] << pref.directory_gendertag // CHOMPStation Edit: Character Directory Update
S["directory_sexualitytag"] << pref.directory_sexualitytag // CHOMPStation Edit: Character Directory Update
S["directory_erptag"] << pref.directory_erptag
S["directory_ad"] << pref.directory_ad
S["sensorpref"] << pref.sensorpref
S["capture_crystal"] << pref.capture_crystal
S["auto_backup_implant"] << pref.auto_backup_implant
S["borg_petting"] << pref.borg_petting
S["stomach_vision"] << pref.stomach_vision
/datum/category_item/player_setup_item/vore/misc/save_character(list/save_data)
save_data["show_in_directory"] = pref.show_in_directory
save_data["directory_tag"] = pref.directory_tag
//CHOMPAdd Start
save_data["directory_gendertag"] = pref.directory_gendertag
save_data["directory_sexualitytag"] = pref.directory_sexualitytag
//CHOMPAdd End
save_data["directory_erptag"] = pref.directory_erptag
save_data["directory_ad"] = pref.directory_ad
save_data["sensorpref"] = pref.sensorpref
save_data["capture_crystal"] = pref.capture_crystal
save_data["auto_backup_implant"] = pref.auto_backup_implant
save_data["borg_petting"] = pref.borg_petting
save_data["stomach_vision"] = pref.stomach_vision
/datum/category_item/player_setup_item/vore/misc/copy_to_mob(var/mob/living/carbon/human/character)
if(pref.sensorpref > 5 || pref.sensorpref < 1)

View File

@@ -1,10 +1,12 @@
var/list/preferences_datums = list()
/datum/preferences
//doohickeys for savefiles
/// The path to the general savefile for this datum
var/path
var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used
var/savefile_version = 0
/// 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
@@ -176,29 +178,55 @@ var/list/preferences_datums = 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
gear = list()
gear_list = list()
gear_slot = 1
if(istype(C))
client = C
client_ckey = C.ckey
if(!IsGuestKey(C.key))
load_path(C.ckey)
if(load_preferences())
load_character()
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/ZeroSkills(var/forced = 0)
for(var/V in SKILLS) for(var/datum/skill/S in SKILLS[V])
@@ -357,8 +385,8 @@ var/list/preferences_datums = list()
return 1
if(href_list["save"])
save_preferences()
save_character()
save_preferences()
else if(href_list["reload"])
load_preferences()
load_character()
@@ -373,7 +401,7 @@ var/list/preferences_datums = list()
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
load_character(SAVE_RESET)
reset_slot()
sanitize_preferences()
else if(href_list["copy"])
if(!IsGuestKey(usr.key))
@@ -402,6 +430,12 @@ var/list/preferences_datums = list()
// 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()
@@ -420,26 +454,23 @@ var/list/preferences_datums = list()
if(selecting_slots)
to_chat(user, "<span class='warning'>You already have a slot selection dialog open!</span>")
return
var/savefile/S = new /savefile(path)
if(!S)
error("Somehow missing savefile path?! [path]")
if(!savefile)
return
var/name
var/nickname //vorestation edit - This set appends nicknames to the save slot
var/default
var/list/charlist = list()
var/default //VOREStation edit
for(var/i = 1, i <= CONFIG_GET(number/character_slots), i++) // CHOMPEdit
S.cd = "/character[i]"
S["real_name"] >> name
S["nickname"] >> nickname //vorestation edit
for(var/i in 1 to CONFIG_GET(number/character_slots)) //CHOMPEdit
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) //VOREStation edit
if(i == default_slot)
default = "[name][nickname ? " ([nickname])" : ""]"
charlist["[name][nickname ? " ([nickname])" : ""]"] = i
@@ -454,33 +485,34 @@ var/list/preferences_datums = list()
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 class='warning'>You already have a slot selection dialog open!</span>")
return
var/savefile/S = new /savefile(path)
if(!S)
error("Somehow missing savefile path?! [path]")
if(!savefile)
return
var/name
var/nickname //vorestation edit - This set appends nicknames to the save slot
var/list/charlist = list()
for(var/i = 1, i <= CONFIG_GET(number/character_slots), i++) // CHOMPEdit
S.cd = "/character[i]"
S["real_name"] >> name
S["nickname"] >> nickname //vorestation edit
for(var/i in 1 to CONFIG_GET(number/character_slots)) //CHOMPEdit
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\]"
if(i == default_slot)
else if(i == default_slot)
name = "►[i] - [name]"
else
name = "[i] - [name]"
charlist["[name][nickname ? " ([nickname])" : ""]"] = i
selecting_slots = TRUE
@@ -494,10 +526,10 @@ var/list/preferences_datums = list()
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], [name][nickname ? " ([nickname])" : ""]'s savedata?", "Confirm Override", list("No", "Yes")) == "Yes")
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_preferences()
save_character()
save_preferences()
attempt_vr(user.client?.prefs_vr,"load_vore","")
ShowChoices(user)

View File

@@ -0,0 +1,456 @@
# Preferences (by Mothblocks)
This does not contain all the information on specific values--you can find those as doc-comments in relevant paths, such as `/datum/preference`. Rather, this gives you an overview for creating *most* preferences, and getting your foot in the door to create more advanced ones.
## Anatomy of a preference (A.K.A. how do I make one?)
Most preferences consist of two parts:
1. A `/datum/preference` type.
2. A tgui representation in a TypeScript file.
Every `/datum/preference` requires these three values be set:
1. `category` - See [Categories](#Categories).
2. `savefile_key` - The value which will be saved in the savefile. This will also be the identifier for tgui.
3. `savefile_identifier` - Whether or not this is a character specific preference (`PREFERENCE_CHARACTER`) or one that affects the player (`PREFERENCE_PLAYER`). As an example: hair color is `PREFERENCE_CHARACTER` while your UI settings are `PREFERENCE_PLAYER`, since they do not change between characters.
For the tgui representation, most preferences will create a `.tsx` file in `tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/`. If your preference is a character preference, make a new file in `character_preferences`. Otherwise, put it in `game_preferences`. The filename does not matter, and this file can hold multiple relevant preferences if you would like.
From here, you will want to write code resembling:
```ts
import { Feature } from "../base";
export const savefile_key_here: Feature<T> = {
name: "Preference Name Here",
component: Component,
// Necessary for game preferences, unused for others
category: "CATEGORY",
// Optional, shown as a tooltip
description: "This preference will blow your mind!",
}
```
`T` and `Component` depend on the type of preference you're making. Here are all common examples...
## Numeric preferences
Examples include age and FPS.
A numeric preference derives from `/datum/preference/numeric`.
```dm
/datum/preference/numeric/legs
category = PREFERENCE_CATEGORY_NON_CONTEXTUAL
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "legs"
minimum = 1
maximum = 8
```
You can optionally provide a `step` field. This value is 1 by default, meaning only integers are accepted.
Your `.tsx` file would look like:
```ts
import { Feature, FeatureNumberInput } from "../base";
export const legs: Feature<number> = {
name: "Legs",
component: FeatureNumberInput,
}
```
## Toggle preferences
Examples include enabling tooltips.
```dm
/datum/preference/toggle/enable_breathing
category = PREFERENCE_CATEGORY_NON_CONTEXTUAL
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "enable_breathing"
// Optional, TRUE by default
default_value = FALSE
```
Your `.tsx` file would look like:
```ts
import { CheckboxInput, FeatureToggle } from "../base";
export const enable_breathing: FeatureToggle = {
name: "Enable breathing",
component: CheckboxInput,
}
```
## Choiced preferences
A choiced preference is one where the only options are in a distinct few amount of choices. Examples include skin tone, shirt, and UI style.
To create one, derive from `/datum/preference/choiced`.
```dm
/datum/preference/choiced/favorite_drink
category = PREFERENCE_CATEGORY_NON_CONTEXTUAL
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "favorite_drink"
```
Now we need to tell the game what the choices are. We do this by overriding `init_possible_values()`. This will return a list of possible options.
```dm
/datum/preference/choiced/favorite_drink/init_possible_values()
return list(
"Milk",
"Cola",
"Water",
)
```
Your `.tsx` file would then look like:
```tsx
import { FeatureChoiced, FeatureDropdownInput } from "../base";
export const favorite_drink: FeatureChoiced = {
name: "Favorite drink",
component: FeatureDropdownInput,
};
```
This will create a dropdown input for your preference.
### Choiced preferences - Icons
Choiced preferences can generate icons. This is how the clothing/species preferences work, for instance. However, if we just want a basic dropdown input with icons, it would look like this:
```dm
/datum/preference/choiced/favorite_drink
category = PREFERENCE_CATEGORY_NON_CONTEXTUAL
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "favorite_drink"
should_generate_icons = TRUE // NEW! This is necessary.
/datum/preference/choiced/favorite_drink/init_possible_values()
return list("Milk", "Cola", "Water")
// New! This proc will get called for every value.
/datum/preference/choiced/favorite_drink/icon_for(value)
switch (value)
if ("Milk")
return icon('drinks.dmi', "milk")
if ("Cola")
return icon('drinks.dmi', "cola")
if ("Water")
return icon('drinks.dmi', "water")
```
Then, change your `.tsx` file to look like:
```tsx
import { FeatureChoiced, FeatureIconnedDropdownInput } from "../base";
export const favorite_drink: FeatureChoiced = {
name: "Favorite drink",
component: FeatureIconnedDropdownInput,
};
```
### Choiced preferences - Display names
Sometimes the values you want to save in code aren't the same as the ones you want to display. You can specify display names to change this.
The only thing you will add is "compiled data".
```dm
/datum/preference/choiced/favorite_drink/compile_constant_data()
var/list/data = ..()
// An assoc list of values to display names
data[CHOICED_PREFERENCE_DISPLAY_NAMES] = list(
"Milk" = "Delicious Milk",
"Cola" = "Crisp Cola",
"Water" = "Plain Ol' Water",
)
return data
```
Your `.tsx` file does not change. The UI will figure it out for you!
## Color preferences
These refer to colors, such as your OOC color. When read, these values will be given as 6 hex digits, *without* the pound sign.
```dm
/datum/preference/color/eyeliner_color
category = PREFERENCE_CATEGORY_NON_CONTEXTUAL
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "eyeliner_color"
```
Your `.tsx` file would look like:
```ts
import { FeatureColorInput, Feature } from "../base";
export const eyeliner_color: Feature<string> = {
name: "Eyeliner color",
component: FeatureColorInput,
};
```
## Name preferences
These refer to an alternative name. Examples include AI names and backup human names.
These exist in `code/modules/client/preferences/names.dm`.
These do not need a `.ts` file, and will be created in the UI automatically.
```dm
/datum/preference/name/doctor
savefile_key = "doctor_name"
// The name on the UI
explanation = "Doctor name"
// This groups together with anything else with the same group
group = "medicine"
// Optional, if specified the UI will show this name actively
// when the player is a medical doctor.
relevant_job = /datum/job/medical_doctor
```
## Making your preference do stuff
There are a handful of procs preferences can use to act on their own:
```dm
/// Apply this preference onto the given client.
/// Called when the savefile_identifier == PREFERENCE_PLAYER.
/datum/preference/proc/apply_to_client(client/client, value)
/// Fired when the preference is updated.
/// Calls apply_to_client by default, but can be overridden.
/datum/preference/proc/apply_to_client_updated(client/client, value)
/// Apply this preference onto the given human.
/// Must be overriden by subtypes.
/// Called when the savefile_identifier == PREFERENCE_CHARACTER.
/datum/preference/proc/apply_to_human(mob/living/carbon/human/target, value)
```
For example, `/datum/preference/numeric/age` contains:
```dm
/datum/preference/numeric/age/apply_to_human(mob/living/carbon/human/target, value)
target.age = value
```
If your preference is `PREFERENCE_CHARACTER`, it MUST override `apply_to_human`, even if just to immediately `return`.
You can also read preferences directly with `prefs.read_preference(/datum/preference/type/here)`, which will return the stored value.
## Categories
Every preference needs to be in a `category`. These can be found in `code/__DEFINES/preferences.dm`.
```dm
/// These will be shown in the character sidebar, but at the bottom.
#define PREFERENCE_CATEGORY_FEATURES "features"
/// Any preferences that will show to the sides of the character in the setup menu.
#define PREFERENCE_CATEGORY_CLOTHING "clothing"
/// Preferences that will be put into the 3rd list, and are not contextual.
#define PREFERENCE_CATEGORY_NON_CONTEXTUAL "non_contextual"
/// Will be put under the game preferences window.
#define PREFERENCE_CATEGORY_GAME_PREFERENCES "game_preferences"
/// These will show in the list to the right of the character preview.
#define PREFERENCE_CATEGORY_SECONDARY_FEATURES "secondary_features"
/// These are preferences that are supplementary for main features,
/// such as hair color being affixed to hair.
#define PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES "supplemental_features"
```
![Preference categories for the main page](https://raw.githubusercontent.com/tgstation/documentation-assets/main/preferences/preference_categories.png)
> SECONDARY_FEATURES or NON_CONTEXTUAL?
Secondary features tend to be species specific. Non contextual features shouldn't change much from character to character.
## Default values and randomization
There are three procs to be aware of in regards to this topic:
- `create_default_value()`. This is used when a value deserializes improperly or when a new character is created.
- `create_informed_default_value(datum/preferences/preferences)` - Used for more complicated default values, like how names require the gender. Will call `create_default_value()` by default.
- `create_random_value(datum/preferences/preferences)` - Explicitly used for random values, such as when a character is being randomized.
`create_default_value()` in most preferences will create a random value. If this is a problem (like how default characters should always be human), you can override `create_default_value()`. By default (without overriding `create_random_value`), random values are just default values.
## Advanced - Server data
As previewed in [the display names implementation](#Choiced-preferences---Display-names), there exists a `compile_constant_data()` proc you can override.
Compiled data is used wherever the server needs to give the client some value it can't figure out on its own. Skin tones use this to tell the client what colors they represent, for example.
Compiled data is sent to the `serverData` field in the `FeatureValueProps`.
## Advanced - Creating your own tgui component
If you have good knowledge with tgui (especially TypeScript), you'll be able to create your own component to represent preferences.
The `component` field in a feature accepts __any__ component that accepts `FeatureValueProps<TReceiving, TSending = TReceiving, TServerData = undefined>`.
This will give you the fields:
```ts
act: typeof sendAct,
featureId: string,
handleSetValue: (newValue: TSending) => void,
serverData: TServerData | undefined,
shrink?: boolean,
value: TReceiving,
```
`act` is the same as the one you get from `useBackend`.
`featureId` is the savefile_key of the feature.
`handleSetValue` is a function that, when called, will tell the server the new value, as well as changing the value immediately locally.
`serverData` is the [server data](#Advanced---Server-data), if it has been fetched yet (and exists).
`shrink` is whether or not the UI should appear smaller. This is only used for supplementary features.
`value` is the current value, could be predicted (meaning that the value was changed locally, but has not yet reached the server).
For a basic example of how this can look, observe `CheckboxInput`:
```tsx
export const CheckboxInput = (
props: FeatureValueProps<BooleanLike, boolean>
) => {
return (<Button.Checkbox
checked={!!props.value}
onClick={() => {
props.handleSetValue(!props.value);
}}
/>);
};
```
## Advanced - Middleware
A `/datum/preference_middleware` is a way to inject your own data at specific points, as well as hijack actions.
Middleware can hijack actions by specifying `action_delegations`:
```dm
/datum/preference_middleware/congratulations
action_delegations = list(
"congratulate_me" = PROC_REF(congratulate_me),
)
/datum/preference_middleware/congratulations/proc/congratulate_me(list/params, mob/user)
to_chat(user, span_notice("Wow, you did a great job learning about middleware!"))
return TRUE
```
Middleware can inject its own data at several points, such as providing new UI assets, compiled data (used by middleware such as quirks to tell the client what quirks exist), etc. Look at `code/modules/client/preferences/middleware/_middleware.dm` for full information.
---
## Antagonists
In order to make an antagonist selectable, you must do a few things:
1. Your antagonist needs an icon.
2. Your antagonist must be in a Dynamic ruleset. The ruleset must specify the antagonist as its `antag_flag`.
3. Your antagonist needs a file in `tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/filename.ts`. This file name MUST be the `antag_flag` of your ruleset, with nothing but letters remaining (e.g. "Nuclear Operative" -> `nuclearoperative`).
4. Add it to `special_roles`.
## Creating icons
If you are satisfied with your icon just being a dude with some clothes, then you can specify `preview_outfit` in your `/datum/antagonist`.
Space Ninja, for example, looks like:
```dm
/datum/antagonist/ninja
preview_outift = /datum/outfit/ninja
```
However, if you want to get creative, you can override `/get_preview_icon()`. This proc should return an icon of size `ANTAGONIST_PREVIEW_ICON_SIZE`x`ANTAGONIST_PREVIEW_ICON_SIZE`.
There are some helper procs you can use as well. `render_preview_outfit(outfit_type)` will take an outfit and give you an icon of someone wearing those clothes. `finish_preview_outfit` will, given an icon, resize it appropriately and zoom in on the head. Note that this will look bad on anything that isn't a human, so if you have a non-human antagonist (such as sentient disease), just run `icon.Scale(ANTAGONIST_PREVIEW_ICON_SIZE, ANTAGONIST_PREVIEW_ICON_SIZE)`.
For inspiration, here is changeling's:
```dm
/datum/antagonist/changeling/get_preview_icon()
var/icon/final_icon = render_preview_outfit(/datum/outfit/changeling)
var/icon/split_icon = render_preview_outfit(/datum/outfit/job/engineer)
final_icon.Shift(WEST, world.icon_size / 2)
final_icon.Shift(EAST, world.icon_size / 2)
split_icon.Shift(EAST, world.icon_size / 2)
split_icon.Shift(WEST, world.icon_size / 2)
final_icon.Blend(split_icon, ICON_OVERLAY)
return finish_preview_icon(final_icon)
```
...which creates:
![Changeling icon](https://raw.githubusercontent.com/tgstation/documentation-assets/main/preferences/changeling.png)
## Creating the tgui representation
In the `.ts` file you created earlier, you must now give the information of your antagonist. For reference, this is the changeling's:
```ts
import { Antagonist, Category } from "../base";
import { multiline } from "common/string";
const Changeling: Antagonist = {
key: "changeling", // This must be the same as your filename
name: "Changeling",
description: [
multiline`
A highly intelligent alien predator that is capable of altering their
shape to flawlessly resemble a human.
`,
multiline`
Transform yourself or others into different identities, and buy from an
arsenal of biological weaponry with the DNA you collect.
`,
],
category: Category.Roundstart, // Category.Roundstart, Category.Midround, or Category.Latejoin
};
export default Changeling;
```
## Readying the Dynamic ruleset
You already need to create a Dynamic ruleset, so in order to get your antagonist recognized, you just need to specify `antag_flag`. This must be unique per ruleset.
Two other values to note are `antag_flag_override` and `antag_preference`.
`antag_flag_override` exists for cases where you want the banned antagonist to be separate from `antag_flag`. As an example: roundstart, midround, and latejoin traitors have separate `antag_flag`, but all have `antag_flag_override = ROLE_TRAITOR`. This is because admins want to ban a player from Traitor altogether, not specific rulesets.
If `antag_preference` is set, it will refer to that preference instead of `antag_flag`. This is used for clown operatives, which we want to be on the same preference as standard nuke ops, but must specify a unique `antag_flag` for.
## Updating special_roles
In `code/__DEFINES/role_preferences.dm` (the same place you'll need to make your ROLE_\* defined), simply add your antagonist to the `special_roles` assoc list. The key is your ROLE, the value is the number of days since your first game in order to play as that antagonist.

View File

@@ -0,0 +1,546 @@
// Priorities must be in order!
/// The default priority level
#define PREFERENCE_PRIORITY_DEFAULT 1
/// The priority at which species runs, needed for external organs to apply properly.
#define PREFERENCE_PRIORITY_SPECIES 2
/**
* Some preferences get applied directly to bodyparts (anything head_flags related right now).
* These must apply after species, as species gaining might replace the bodyparts of the human.
*/
#define PREFERENCE_PRIORITY_BODYPARTS 3
/// The priority at which gender is determined, needed for proper randomization.
#define PREFERENCE_PRIORITY_GENDER 4
/// The priority at which body type is decided, applied after gender so we can
/// support the "use gender" option.
#define PREFERENCE_PRIORITY_BODY_TYPE 5
/// Used for preferences that rely on body setup being finalized.
#define PREFERENCE_PRORITY_LATE_BODY_TYPE 6
/// Equpping items based on preferences.
/// Should happen after species and body type to make sure it looks right.
/// Mostly redundant, but a safety net for saving/loading.
#define PREFERENCE_PRIORITY_LOADOUT 7
/// The priority at which names are decided, needed for proper randomization.
#define PREFERENCE_PRIORITY_NAMES 8
/// Preferences that aren't names, but change the name changes set by PREFERENCE_PRIORITY_NAMES.
#define PREFERENCE_PRIORITY_NAME_MODIFICATIONS 9
/// The maximum preference priority, keep this updated, but don't use it for `priority`.
#define MAX_PREFERENCE_PRIORITY PREFERENCE_PRIORITY_NAME_MODIFICATIONS
/// For choiced preferences, this key will be used to set display names in constant data.
#define CHOICED_PREFERENCE_DISPLAY_NAMES "display_names"
/// For main feature preferences, this key refers to a feature considered supplemental.
/// For instance, hair color being supplemental to hair.
#define SUPPLEMENTAL_FEATURE_KEY "supplemental_feature"
/// An assoc list list of types to instantiated `/datum/preference` instances
GLOBAL_LIST_INIT(preference_entries, init_preference_entries())
/// An assoc list of preference entries by their `savefile_key`
GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
/proc/init_preference_entries()
var/list/output = list()
for(var/datum/preference/preference_type as anything in subtypesof(/datum/preference))
if(is_abstract(preference_type))
continue
output[preference_type] = new preference_type
return output
/proc/init_preference_entries_by_key()
var/list/output = list()
for(var/datum/preference/preference_type as anything in subtypesof(/datum/preference))
if(is_abstract(preference_type))
continue
output[initial(preference_type.savefile_key)] = GLOB.preference_entries[preference_type]
return output
/// Returns a flat list of preferences in order of their priority
/proc/get_preferences_in_priority_order()
var/list/preferences[MAX_PREFERENCE_PRIORITY]
for(var/preference_type in GLOB.preference_entries)
var/datum/preference/preference = GLOB.preference_entries[preference_type]
LAZYADD(preferences[preference.priority], preference)
var/list/flattened = list()
for(var/index in 1 to MAX_PREFERENCE_PRIORITY)
// Don't add nulls to the list if there's no preferences in a given priority level
if(LAZYLEN(preferences[index]))
flattened += preferences[index]
return flattened
/// Represents an individual preference.
/datum/preference
/// The key inside the savefile to use.
/// This is also sent to the UI.
/// Once you pick this, don't change it.
var/savefile_key
/// The category of preference, for use by the PreferencesMenu.
/// This isn't used for anything other than as a key for UI data.
/// It is up to the PreferencesMenu UI itself to interpret it.
var/category = "misc"
/// Do not instantiate if type matches this.
abstract_type = /datum/preference
/// What savefile should this preference be read from?
/// Valid values are PREFERENCE_CHARACTER and PREFERENCE_PLAYER.
/// See the documentation in [code/__DEFINES/preferences.dm].
var/savefile_identifier
/// The priority of when to apply this preference.
/// Used for when you need to rely on another preference.
var/priority = PREFERENCE_PRIORITY_DEFAULT
/// If set, will be available to randomize, but only if the preference
/// is for PREFERENCE_CHARACTER.
var/can_randomize = TRUE
/// If randomizable (PREFERENCE_CHARACTER and can_randomize), whether
/// or not to enable randomization by default.
/// This doesn't mean it'll always be random, but rather if a player
/// DOES have random body on, will this already be randomized?
var/randomize_by_default = TRUE
/// If the selected species has this in its /datum/species/mutant_bodyparts,
/// will show the feature as selectable.
var/relevant_mutant_bodypart = null
/// If the selected species has this in its /datum/species/body_markings,
/// will show the feature as selectable.
var/relevant_body_markings = null
/// If the selected species has this in its /datum/species/inherent_traits,
/// will show the feature as selectable.
var/relevant_inherent_trait = null
/// If the selected species has this in its /datum/species/var/external_organs,
/// will show the feature as selectable.
var/relevant_external_organ = null
/// If the selected species has this head_flag by default,
/// will show the feature as selectable.
var/relevant_head_flag = null
/// Called on the saved input when retrieving.
/// Also called by the value sent from the user through UI. Do not trust it.
/// Input is the value inside the savefile, output is to tell other code
/// what the value is.
/// This is useful either for more optimal data saving or for migrating
/// older data.
/// Must be overridden by subtypes.
/// Can return null if no value was found.
/datum/preference/proc/pref_deserialize(input, datum/preferences/preferences)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(FALSE)
CRASH("`pref_deserialize()` was not implemented on [type]!")
/// Called on the input while saving.
/// Input is the current value, output is what to save in the savefile.
/datum/preference/proc/pref_serialize(input)
SHOULD_NOT_SLEEP(TRUE)
return input
/// Produce a default, potentially random value for when no value for this
/// preference is found in the savefile.
/// Either this or create_informed_default_value must be overriden by subtypes.
/datum/preference/proc/create_default_value()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(FALSE)
CRASH("`create_default_value()` was not implemented on [type]!")
/// Produce a default, potentially random value for when no value for this
/// preference is found in the savefile.
/// Unlike create_default_value(), will provide the preferences object if you
/// need to use it.
/// If not overriden, will call create_default_value() instead.
/datum/preference/proc/create_informed_default_value(datum/preferences/preferences)
return create_default_value()
/// Produce a random value for the purposes of character randomization.
/// Will just create a default value by default.
/datum/preference/proc/create_random_value(datum/preferences/preferences)
return create_informed_default_value(preferences)
/// Returns whether or not a preference can be randomized.
/datum/preference/proc/is_randomizable()
SHOULD_NOT_OVERRIDE(TRUE)
return savefile_identifier == PREFERENCE_CHARACTER && can_randomize
/// Given a savefile, return either the saved data or an acceptable default.
/// This will write to the savefile if a value was not found with the new value.
/datum/preference/proc/read(list/save_data, datum/preferences/preferences)
SHOULD_NOT_OVERRIDE(TRUE)
var/value
if(!isnull(save_data))
value = save_data[savefile_key]
if(isnull(value))
return null
else
return pref_deserialize(value, preferences)
/// Given a savefile, writes the inputted value.
/// Returns TRUE for a successful application.
/// Return FALSE if it is invalid.
/datum/preference/proc/write(list/save_data, value)
SHOULD_NOT_OVERRIDE(TRUE)
if(!is_valid(value))
return FALSE
if(!isnull(save_data))
save_data[savefile_key] = pref_serialize(value)
return TRUE
/// Apply this preference onto the given client.
/// Called when the savefile_identifier == PREFERENCE_PLAYER.
/datum/preference/proc/apply_to_client(client/client, value)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(FALSE)
return
/// Fired when the preference is updated.
/// Calls apply_to_client by default, but can be overridden.
/datum/preference/proc/apply_to_client_updated(client/client, value)
SHOULD_NOT_SLEEP(TRUE)
apply_to_client(client, value)
/// Apply this preference onto the given human.
/// Must be overriden by subtypes.
/// Called when the savefile_identifier == PREFERENCE_CHARACTER.
/datum/preference/proc/apply_to_human(mob/living/carbon/human/target, value)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(FALSE)
CRASH("`apply_to_human()` was not implemented for [type]!")
/// Returns which savefile to use for a given savefile identifier
/datum/preferences/proc/get_save_data_for_savefile_identifier(savefile_identifier)
RETURN_TYPE(/list)
if(!client)
return null
if(!savefile)
CRASH("Attempted to get the savedata for [savefile_identifier] of [client] without a savefile. This should have been handled by load_preferences()")
// Both of these will cache savefiles, but only for a tick.
// This is because storing a savefile will lock it, causing later issues down the line.
// Do not change them to addtimer, since the timer SS might not be running at this time.
switch (savefile_identifier)
if(PREFERENCE_CHARACTER)
return savefile.get_entry("character[default_slot]")
if(PREFERENCE_PLAYER)
return savefile.get_entry()
else
CRASH("Unknown savefile identifier [savefile_identifier]")
/// Read a /datum/preference type and return its value.
/// This will write to the savefile if a value was not found with the new value.
/datum/preferences/proc/read_preference(preference_type)
var/datum/preference/preference_entry = GLOB.preference_entries[preference_type]
if(isnull(preference_entry))
var/extra_info = ""
// Current initializing subsystem is important to know because it might be a problem with
// things running pre-assets-initialization.
// if(!isnull(Master.current_initializing_subsystem))
// extra_info = "Info was attempted to be retrieved while [Master.current_initializing_subsystem] was initializing."
// else if(!MC_RUNNING())
// extra_info = "Info was attempted to be retrieved before the MC started, but not while it was actively initializing a subsystem"
CRASH("Preference type `[preference_type]` is invalid! [extra_info]")
if(preference_type in value_cache)
return value_cache[preference_type]
var/value = preference_entry.read(get_save_data_for_savefile_identifier(preference_entry.savefile_identifier), src)
if(isnull(value))
value = preference_entry.create_informed_default_value(src)
if(write_preference(preference_entry, value))
return value
else
CRASH("Couldn't write the default value for [preference_type] (received [value])")
value_cache[preference_type] = value
return value
/// Read a /datum/preference type and return its value.
/mob/proc/read_preference(preference_type)
return client?.prefs?.read_preference(preference_type)
/// Set a /datum/preference entry.
/// Returns TRUE for a successful preference application.
/// Returns FALSE if it is invalid.
/datum/preferences/proc/write_preference(datum/preference/preference, preference_value)
var/save_data = get_save_data_for_savefile_identifier(preference.savefile_identifier)
var/new_value = preference.pref_deserialize(preference_value, src)
var/success = preference.write(save_data, new_value)
if(success)
value_cache[preference.type] = new_value
return success
/// Will perform an update on the preference, but not write to the savefile.
/// This will, for instance, update the character preference view.
/// Performs sanity checks.
/datum/preferences/proc/update_preference(datum/preference/preference, preference_value)
if(!preference.is_accessible(src))
return FALSE
var/new_value = preference.pref_deserialize(preference_value, src)
var/success = preference.write(null, new_value)
if(!success)
return FALSE
recently_updated_keys |= preference.type
value_cache[preference.type] = new_value
if(preference.savefile_identifier == PREFERENCE_PLAYER)
preference.apply_to_client_updated(client, read_preference(preference.type))
else
update_preview_icon()
return TRUE
/// Checks that a given value is valid.
/// Must be overriden by subtypes.
/// Any type can be passed through.
/datum/preference/proc/is_valid(value)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(FALSE)
CRASH("`is_valid()` was not implemented for [type]!")
/// Returns data to be sent to users in the menu
/datum/preference/proc/compile_ui_data(mob/user, value)
SHOULD_NOT_SLEEP(TRUE)
return pref_serialize(value)
/// Returns data compiled into the preferences JSON asset
/datum/preference/proc/compile_constant_data()
SHOULD_NOT_SLEEP(TRUE)
return null
/// Returns whether or not this preference is accessible.
/// If FALSE, will not show in the UI and will not be editable (by update_preference).
/datum/preference/proc/is_accessible(datum/preferences/preferences)
SHOULD_CALL_PARENT(TRUE)
SHOULD_NOT_SLEEP(TRUE)
// if(
// !isnull(relevant_mutant_bodypart)
// || !isnull(relevant_inherent_trait)
// || !isnull(relevant_external_organ)
// || !isnull(relevant_head_flag)
// || !isnull(relevant_body_markings)
// )
// var/species_type = preferences.read_preference(/datum/preference/choiced/species)
// var/datum/species/species = GLOB.species_prototypes[species_type]
// if(!(savefile_key in species.get_features()))
// return FALSE
if(!should_show_on_page(preferences.current_window))
return FALSE
return TRUE
/// Returns whether or not, given the PREFERENCE_TAB_*, this preference should
/// appear.
/datum/preference/proc/should_show_on_page(preference_tab)
var/is_on_character_page = preference_tab == PREFERENCE_TAB_CHARACTER_PREFERENCES
var/is_character_preference = savefile_identifier == PREFERENCE_CHARACTER
return is_on_character_page == is_character_preference
/// A preference that is a choice of one option among a fixed set.
/// Used for preferences such as clothing.
/datum/preference/choiced
/// If this is TRUE, an icon will be generated for every value.
/// If you implement this, you must implement `icon_for(value)` for every possible value.
var/should_generate_icons = FALSE
var/list/cached_values
/// If the preference is a main feature (PREFERENCE_CATEGORY_FEATURES or PREFERENCE_CATEGORY_CLOTHING)
/// this is the name of the feature that will be presented.
var/main_feature_name
abstract_type = /datum/preference/choiced
/// Returns a list of every possible value.
/// The first time this is called, will run `init_values()`.
/// Return value can be in the form of:
/// - A flat list of raw values, such as list(MALE, FEMALE, PLURAL).
/// - An assoc list of raw values to atoms/icons.
/datum/preference/choiced/proc/get_choices()
// Override `init_values()` instead.
SHOULD_NOT_OVERRIDE(TRUE)
if(isnull(cached_values))
cached_values = init_possible_values()
ASSERT(cached_values.len)
return cached_values
/// Returns a list of every possible value, serialized.
/datum/preference/choiced/proc/get_choices_serialized()
// Override `init_values()` instead.
SHOULD_NOT_OVERRIDE(TRUE)
var/list/serialized_choices = list()
for(var/choice in get_choices())
serialized_choices += pref_serialize(choice)
return serialized_choices
/// Returns a list of every possible value.
/// This must be overriden by `/datum/preference/choiced` subtypes.
/// If `should_generate_icons` is TRUE, then you will also need to implement `icon_for(value)`
/// for every possible value.
/datum/preference/choiced/proc/init_possible_values()
CRASH("`init_possible_values()` was not implemented for [type]!")
/// When `should_generate_icons` is TRUE, this proc is called for every value.
/// It can return either an icon or a typepath to an atom to create.
/datum/preference/choiced/proc/icon_for(value)
SHOULD_CALL_PARENT(FALSE)
SHOULD_NOT_SLEEP(TRUE)
CRASH("`icon_for()` was not implemented for [type], even though should_generate_icons = TRUE!")
/datum/preference/choiced/is_valid(value)
return value in get_choices()
/datum/preference/choiced/pref_deserialize(input, datum/preferences/preferences)
return sanitize_inlist(input, get_choices(), create_default_value())
/datum/preference/choiced/create_default_value()
return pick(get_choices())
/datum/preference/choiced/compile_constant_data()
var/list/data = list()
var/list/choices = list()
for(var/choice in get_choices())
choices += choice
data["choices"] = choices
if(should_generate_icons)
var/list/icons = list()
// for(var/choice in choices) // TODO: Pref spritesheet asset
// icons[choice] = get_spritesheet_key(choice)
data["icons"] = icons
if(!isnull(main_feature_name))
data["name"] = main_feature_name
return data
/// A preference that represents an RGB color of something.
/// Will give the value as 6 hex digits, without a hash.
/datum/preference/color
abstract_type = /datum/preference/color
/datum/preference/color/pref_deserialize(input, datum/preferences/preferences)
return sanitize_hexcolor(input)
/datum/preference/color/create_default_value()
return random_color()
/datum/preference/color/pref_serialize(input)
return sanitize_hexcolor(input)
/datum/preference/color/is_valid(value)
return findtext(value, GLOB.is_color)
/// A numeric preference with a minimum and maximum value
/datum/preference/numeric
/// The minimum value
var/minimum
/// The maximum value
var/maximum
/// The step of the number, such as 1 for integers or 0.5 for half-steps.
var/step = 1
abstract_type = /datum/preference/numeric
/datum/preference/numeric/pref_deserialize(input, datum/preferences/preferences)
if(istext(input)) // Sometimes TGUI will return a string instead of a number, so we take that into account.
input = text2num(input) // Worst case, it's null, it'll just use create_default_value()
return sanitize_float(input, minimum, maximum, step, create_default_value())
/datum/preference/numeric/pref_serialize(input)
return sanitize_float(input, minimum, maximum, step, create_default_value())
/datum/preference/numeric/create_default_value()
return rand(minimum, maximum)
/datum/preference/numeric/is_valid(value)
return isnum(value) && value >= round(minimum, step) && value <= round(maximum, step)
/datum/preference/numeric/compile_constant_data()
return list(
"minimum" = minimum,
"maximum" = maximum,
"step" = step,
)
/// A preference whose value is always TRUE or FALSE
/datum/preference/toggle
abstract_type = /datum/preference/toggle
/// The default value of the toggle, if create_default_value is not specified
var/default_value = TRUE
/datum/preference/toggle/create_default_value()
return default_value
/datum/preference/toggle/pref_deserialize(input, datum/preferences/preferences)
return !!input
/datum/preference/toggle/is_valid(value)
return value == TRUE || value == FALSE
/// A string-based preference accepting arbitrary string values entered by the user, with a maximum length.
/datum/preference/text
abstract_type = /datum/preference/text
/// What is the maximum length of the value allowed in this field?
var/maximum_value_length = 256
/// Should we strip HTML the input or simply restrict it to the maximum_value_length?
var/should_strip_html = TRUE
/datum/preference/text/pref_deserialize(input, datum/preferences/preferences)
return should_strip_html ? STRIP_HTML_SIMPLE(input, maximum_value_length) : copytext(input, 1, maximum_value_length)
/datum/preference/text/create_default_value()
return ""
/datum/preference/text/is_valid(value)
return istext(value) && length(value) < maximum_value_length
/datum/preference/text/compile_constant_data()
return list("maximum_length" = maximum_value_length)

View File

@@ -0,0 +1,52 @@
/// Preference middleware is code that helps to decentralize complicated preference features.
/datum/preference_middleware
/// The preferences datum
var/datum/preferences/preferences
/// The key that will be used for get_constant_data().
/// If null, will use the typepath minus /datum/preference_middleware.
var/key = null
/// Map of ui_act actions -> proc paths to call.
/// Signature is `(list/params, mob/user) -> TRUE/FALSE.
/// Return output is the same as ui_act--TRUE if it should update, FALSE if it should not
var/list/action_delegations = list()
/datum/preference_middleware/New(datum/preferences)
src.preferences = preferences
if (isnull(key))
// + 2 coming from the off-by-one of copytext, and then another from the slash
key = copytext("[type]", length("[parent_type]") + 2)
/datum/preference_middleware/Destroy()
preferences = null
return ..()
/// Append all of these into ui_data
/datum/preference_middleware/proc/get_ui_data(mob/user)
return list()
/// Append all of these into ui_static_data
/datum/preference_middleware/proc/get_ui_static_data(mob/user)
return list()
/// Append all of these into ui_assets
/datum/preference_middleware/proc/get_ui_assets()
return list()
/// Append all of these into /datum/asset/json/preferences.
/datum/preference_middleware/proc/get_constant_data()
return null
/// Merge this into the result of compile_character_preferences.
/datum/preference_middleware/proc/get_character_preferences(mob/user)
return null
/// Called every set_preference, returns TRUE if this handled it.
/datum/preference_middleware/proc/pre_set_preference(mob/user, preference, value)
return FALSE
/// Called when a character is changed.
/datum/preference_middleware/proc/on_new_character(mob/user)
return

View File

@@ -0,0 +1,12 @@
/// Transforms the bay style `"preferences": ["SOUND_MIDI", ...]` to `"SOUND_MIDI": 1` and `"preferences_disabled": [...]` to `0`.
/datum/preferences/proc/migration_13_preferences(datum/json_savefile/S)
var/list/preferences_enabled = S.get_entry("preferences")
for(var/key in preferences_enabled)
S.set_entry("[key]", TRUE)
var/list/preferences_disabled = S.get_entry("preferences_disabled")
for(var/key in preferences_disabled)
S.set_entry("[key]", FALSE)
// Force a reload of the value cache
apply_all_client_preferences()

View File

@@ -0,0 +1,17 @@
/// Moves nif stuff to it's own file
/datum/preferences/proc/migration_14_nifs(datum/json_savefile/S)
var/datum/json_savefile/new_savefile = new /datum/json_savefile(nif_savefile_path(client_ckey))
for(var/slot in 1 to CONFIG_GET(number/character_slots)) //CHOMPEdit
var/list/prefs = S.get_entry("character[slot]", null)
if(!islist(prefs))
continue
var/list/new_data = list()
new_data["nif_path"] = prefs["nif_path"]
new_data["nif_durability"] = prefs["nif_durability"]
new_data["nif_savedata"] = prefs["nif_savedata"]
new_savefile.set_entry("character[slot]", new_data)
new_savefile.save()

View File

@@ -0,0 +1,28 @@
// Contains all of the variables and such to make tg prefs work
/datum/preferences
/// The savefile relating to character preferences, PREFERENCE_CHARACTER
var/list/character_data
/// A list of keys that have been updated since the last save.
var/list/recently_updated_keys = list()
/// A cache of preference entries to values.
/// Used to avoid expensive READ_FILE every time a preference is retrieved.
var/value_cache = list()
/// If set to TRUE, will update character_profiles on the next ui_data tick.
var/tainted_character_profiles = FALSE
var/current_window = PREFERENCE_TAB_GAME_PREFERENCES
/// A list of instantiated middleware
var/list/datum/preference_middleware/middleware = list()
/// Applies all PREFERENCE_PLAYER preferences
/datum/preferences/proc/apply_all_client_preferences()
for(var/datum/preference/preference as anything in get_preferences_in_priority_order())
if(preference.savefile_identifier != PREFERENCE_PLAYER)
continue
value_cache -= preference.type
preference.apply_to_client(client, read_preference(preference.type))

View File

@@ -0,0 +1,73 @@
/datum/preference/toggle/show_attack_logs
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_ATTACKLOGS"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_attack_logs/is_accessible(datum/preferences/preferences)
. = ..()
if(!.)
return
return check_rights(R_MOD|R_ADMIN, FALSE, preferences.client)
/datum/preference/toggle/show_debug_logs
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_DEBUGLOGS"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_debug_logs/is_accessible(datum/preferences/preferences)
. = ..()
if(!.)
return
return check_rights(R_DEBUG|R_ADMIN, FALSE, preferences.client)
/datum/preference/toggle/show_chat_prayers
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_PRAYER"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_chat_prayers/is_accessible(datum/preferences/preferences)
. = ..()
if(!.)
return
return check_rights(R_EVENT|R_ADMIN, FALSE, preferences.client)
// General holder prefs
/datum/preference/toggle/holder
abstract_type = /datum/preference/toggle/holder
/datum/preference/toggle/holder/is_accessible(datum/preferences/preferences)
. = ..(preferences)
if(!.)
return
return preferences.client.holder
/datum/preference/toggle/holder/play_adminhelp_ping
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_ADMINHELP"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/holder/hear_radio
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_RADIO"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/holder/show_rlooc
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_RLOOC"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/holder/show_staff_dsay
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_ADSAY"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER

View File

@@ -0,0 +1,69 @@
/datum/preference/toggle/chat_tags
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_SHOWICONS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_typing_indicator
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SHOW_TYPING"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_typing_indicator/apply_to_client(client/client, value)
if(!value)
client.stop_thinking()
/datum/preference/toggle/show_typing_indicator_subtle
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SHOW_TYPING_SUBTLE"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_ooc
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_OOC"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_looc
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_LOOC"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_dsay
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_DEAD"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/check_mention
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_MENTION"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/vore_health_bars
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "VORE_HEALTH_BARS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_lore_news
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "NEWS_POPUP"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/player_tips
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "RECEIVE_TIPS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/pain_frequency
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "PAIN_FREQUENCY"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER

View File

@@ -0,0 +1,29 @@
/datum/preference/toggle/whisubtle_vis
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "WHISUBTLE_VIS"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/ghost_see_whisubtle
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "GHOST_SEE_WHISUBTLE"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/ghost_ears
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_GHOSTEARS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/ghost_sight
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_GHOSTSIGHT"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/ghost_radio
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "CHAT_GHOSTRADIO"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER

View File

@@ -0,0 +1,71 @@
/// Whether or not to toggle ambient occlusion, the shadows around people
/datum/preference/toggle/ambient_occlusion
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "AMBIENT_OCCLUSION_PREF"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/ambient_occlusion/apply_to_client(client/client, value)
var/datum/plane_holder/PH = client?.mob?.plane_holder
if(PH)
PH.set_ao(VIS_OBJS, value)
PH.set_ao(VIS_MOBS, value)
/datum/preference/toggle/mob_tooltips
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "MOB_TOOLTIPS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/inv_tooltips
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "INV_TOOLTIPS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/attack_icons
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "ATTACK_ICONS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/precision_placement
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "PRECISE_PLACEMENT"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/hotkeys_default
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "HUD_HOTKEYS"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/show_progress_bar
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SHOW_PROGRESS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/safefiring
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SAFE_FIRING"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/status_indicators
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SHOW_STATUS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/status_indicators/apply_to_client(client/client, value)
var/datum/plane_holder/PH = client?.mob?.plane_holder
if(PH)
PH.set_vis(VIS_STATUS, value)
/datum/preference/toggle/auto_afk
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "AUTO_AFK"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER

View File

@@ -0,0 +1,23 @@
/datum/preference/toggle/runechat_mob
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "RUNECHAT_MOB"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/runechat_obj
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "RUNECHAT_OBJ"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/runechat_border
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "RUNECHAT_BORDER"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/runechat_long_messages
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "RUNECHAT_LONG"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER

View File

@@ -0,0 +1,149 @@
/datum/preference/toggle/play_admin_midis
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_MIDI"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/play_lobby_music
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_LOBBY"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/play_lobby_music/apply_to_client(client/client, value)
if(value)
client?.playtitlemusic()
else
client?.media?.stop_music()
/datum/preference/toggle/play_ambience
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_AMBIENCE"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/play_ambience/apply_to_client(client/client, value)
if(!value)
client << sound(null, repeat = 0, wait = 0, volume = 0, channel = CHANNEL_AMBIENCE_FORCED)
client << sound(null, repeat = 0, wait = 0, volume = 0, channel = CHANNEL_AMBIENCE)
/datum/preference/toggle/play_jukebox
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_JUKEBOX"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/play_jukebox/apply_to_client(client/client, value)
if(value)
client?.mob?.update_music()
else
client?.mob?.stop_all_music()
/datum/preference/toggle/instrument_toggle
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_INSTRUMENT"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/emote_noises
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "EMOTE_NOISES"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/radio_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "RADIO_SOUNDS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/say_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SAY_SOUNDS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/emote_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "EMOTE_SOUNDS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/whisper_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "WHISPER_SOUNDS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/subtle_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SUBTLE_SOUNDS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/air_pump_noise
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_AIRPUMP"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/old_door_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_OLDDOORS"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/department_door_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_DEPARTMENTDOORS"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/pickup_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_PICKED"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/drop_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_DROPPED"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/weather_sounds
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_WEATHER"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/supermatter_hum
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_SUPERMATTER"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/play_mentorhelp_ping
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "SOUND_MENTORHELP"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
// Vorey sounds
/datum/preference/toggle/belch_noises // Belching noises - pref toggle for 'em
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "BELCH_NOISES"
default_value = FALSE //CHOMPEdit
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/eating_noises
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "EATING_NOISES"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/digestion_noises
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "DIGEST_NOISES"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER

View File

@@ -0,0 +1,37 @@
/datum/preference/toggle/browser_style
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "BROWSER_STYLED"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/vchat_enable
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "VCHAT_ENABLE"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/vchat_enable/apply_to_client(client/client, value)
var/before = client.tgui_panel.oldchat
if(value)
client.tgui_panel.oldchat = FALSE
else
client.tgui_panel.oldchat = TRUE
// If something actually changed, reload chat
if(before != client.tgui_panel.oldchat)
client.nuke_chat()
/datum/preference/toggle/tgui_say
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "TGUI_SAY"
default_value = TRUE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/tgui_say_light
category = PREFERENCE_CATEGORY_GAME_PREFERENCES
savefile_key = "TGUI_SAY_LIGHT_MODE"
default_value = FALSE
savefile_identifier = PREFERENCE_PLAYER
/datum/preference/toggle/tgui_say_light/apply_to_client(client/client, value)
client.tgui_say?.load()

View File

@@ -1,67 +0,0 @@
/client/verb/toggle_looping_alarms()
set name = "Looping Alarms"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles alarm sound loops."
var/pref_path = /datum/client_preference/looping_alarms
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear alarm sounds looping.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TAlarmLoops") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_sleep_music()
set name = "Toggle Sleeping Music"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "When enabled, you will hear cozy music played during surgery, cryo, and sleeper pod usage."
var/pref_path = /datum/client_preference/sleep_music
toggle_preference(pref_path)
to_chat(src, "You are [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hearing sleeping music while in cryo/surgery/sleeper.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb", "TSleepMusic")
/* // Up-ported to Virgo, disabling here
/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]"]
*/

View File

@@ -1,121 +1,267 @@
#define SAVEFILE_VERSION_MIN 8
#define SAVEFILE_VERSION_MAX 11
#define SAVEFILE_VERSION_MAX 14
//handles converting savefiles to new formats
//MAKE SURE YOU KEEP THIS UP TO DATE!
//If the sanity checks are capable of handling any issues. Only increase SAVEFILE_VERSION_MAX,
//this will mean that savefile_version will still be over SAVEFILE_VERSION_MIN, meaning
//this savefile update doesn't run everytime we load from the savefile.
//This is mainly for format changes, such as the bitflags in toggles changing order or something.
//if a file can't be updated, return 0 to delete it and start again
//if a file was updated, return 1
/datum/preferences/proc/savefile_update()
if(savefile_version < 8) //lazily delete everything + additional files so they can be saved in the new format
for(var/ckey in preferences_datums)
var/datum/preferences/D = preferences_datums[ckey]
if(D == src)
var/delpath = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/"
if(delpath && fexists(delpath))
fdel(delpath)
break
return 0
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
This proc checks if the current directory of the savefile S needs updating
It is to be used by the load_character and load_preferences procs.
(S.cd == "/" is preferences, S.cd == "/character[integer]" is a character slot, etc)
if(savefile_version == SAVEFILE_VERSION_MAX) //update successful.
save_preferences()
save_character()
return 1
return 0
if the current directory's version is below SAVEFILE_VERSION_MIN it will simply wipe everything in that directory
(if we're at root "/" then it'll just wipe the entire savefile, for instance.)
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey) return
if its version is below SAVEFILE_VERSION_MAX but above the minimum, it will load data but later call the
respective update_preferences() or update_character() proc.
Those procs allow coders to specify format changes so users do not lose their setups and have to redo them again.
Failing all that, the standard sanity checks are performed. They simply check the data is suitable, reverting to
initial() values if necessary.
*/
/datum/preferences/proc/save_data_needs_update(list/save_data)
if(!save_data) // empty list, either savefile isnt loaded or its a new char
return -1
if(!save_data["version"]) // special case: if there is no version key, such as in character slots before v12
return -3
if(save_data["version"] < SAVEFILE_VERSION_MIN)
return -2
if(save_data["version"] < SAVEFILE_VERSION_MAX)
return save_data["version"]
return -1
//should these procs get fairly long
//just increase SAVEFILE_VERSION_MIN so it's not as far behind
//SAVEFILE_VERSION_MAX and then delete any obsolete if clauses
//from these procs.
//This only really meant to avoid annoying frequent players
//if your savefile is 3 months out of date, then 'tough shit'.
/datum/preferences/proc/update_preferences(current_version, datum/json_savefile/S)
// Migration from BYOND savefiles to JSON: Important milemark.
// if(current_version < 11)
// Migration for client preferences
if(current_version < 13)
log_debug("[client_ckey] preferences migrating from [current_version] to v13....")
to_chat(client, span_danger("Migrating savefile from version [current_version] to v13..."))
migration_13_preferences(S)
log_debug("[client_ckey] preferences successfully migrated from [current_version] to v13.")
to_chat(client, span_danger("v13 savefile migration complete."))
// Migration for nifs
if(current_version < 14)
log_debug("[client_ckey] preferences migrating from [current_version] to v14....")
to_chat(client, span_danger("Migrating savefile from version [current_version] to v14..."))
migration_14_nifs(S)
log_debug("[client_ckey] preferences successfully migrated from [current_version] to v14.")
to_chat(client, span_danger("v14 savefile migration complete."))
/datum/preferences/proc/update_character(current_version, list/save_data)
// Migration from BYOND savefiles to JSON: Important milemark.
if(current_version == -3)
// Add a version field inside each character
save_data["version"] = SAVEFILE_VERSION_MAX
/// Migrates from byond savefile to json savefile
/datum/preferences/proc/try_savefile_type_migration()
log_debug("[client_ckey] preferences migrating from savefile to JSON...")
to_chat(client, span_danger("Savefile migration to JSON in progress..."))
load_path(client.ckey, "preferences.sav") // old save file
var/old_path = path
load_path(client.ckey)
if(!fexists(old_path))
return
var/datum/json_savefile/json_savefile = new(path)
json_savefile.import_byond_savefile(new /savefile(old_path))
json_savefile.save()
log_debug("[client_ckey] preferences successfully migrated from savefile to JSON.")
to_chat(client, span_danger("Savefile migration to JSON is complete."))
return TRUE
/datum/preferences/proc/load_path(ckey, filename = "preferences.json")
if(!ckey || !load_and_save)
return
path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/[filename]"
savefile_version = SAVEFILE_VERSION_MAX
/datum/preferences/proc/load_savefile()
if(load_and_save && !path)
CRASH("Attempted to load savefile without first loading a path!")
savefile = new /datum/json_savefile(load_and_save ? path : null)
/datum/preferences/proc/load_preferences()
if(!path) return 0
if(!fexists(path)) return 0
var/savefile/S = new /savefile(path)
if(!S) return 0
S.cd = "/"
if(!savefile)
stack_trace("Attempted to load the preferences of [client] without a savefile; did you forget to call load_savefile?")
load_savefile()
if(!savefile)
stack_trace("Failed to load the savefile for [client] after manually calling load_savefile; something is very wrong.")
return FALSE
S["version"] >> savefile_version
//Conversion
if(!savefile_version || !isnum(savefile_version) || savefile_version < SAVEFILE_VERSION_MIN || savefile_version > SAVEFILE_VERSION_MAX)
if(!savefile_update()) //handles updates
savefile_version = SAVEFILE_VERSION_MAX
save_preferences()
save_character()
return 0
var/needs_update = save_data_needs_update(savefile.get_entry())
if(load_and_save && (needs_update <= -2)) //fatal, can't load any data
var/bacpath = "[path].updatebac" //todo: if the savefile version is higher then the server, check the backup, and give the player a prompt to load the backup
if(fexists(bacpath))
fdel(bacpath) //only keep 1 version of backup
fcopy(savefile.path, bacpath) //byond helpfully lets you use a savefile for the first arg.
return FALSE
player_setup.load_preferences(S)
return 1
apply_all_client_preferences()
//try to fix any outdated data if necessary
if(needs_update >= 0)
var/bacpath = "[path].updatebac" //todo: if the savefile version is higher then the server, check the backup, and give the player a prompt to load the backup
if(fexists(bacpath))
fdel(bacpath) //only keep 1 version of backup
fcopy(savefile.path, bacpath) //byond helpfully lets you use a savefile for the first arg.
update_preferences(needs_update, savefile) //needs_update = savefile_version if we need an update (positive integer)
// Load general prefs after applying migrations
player_setup.load_preferences(savefile)
//save the updated version
var/old_default_slot = default_slot
// var/old_max_save_slots = max_save_slots
for(var/slot in savefile.get_entry()) //but first, update all current character slots.
if (copytext(slot, 1, 10) != "character")
continue
var/slotnum = text2num(copytext(slot, 10))
if (!slotnum)
continue
// max_save_slots = max(max_save_slots, slotnum) //so we can still update byond member slots after they lose memeber status
default_slot = slotnum
if(load_character())
save_character()
default_slot = old_default_slot
// max_save_slots = old_max_save_slots
save_preferences()
else
// Load general prefs
player_setup.load_preferences(savefile)
return TRUE
/datum/preferences/proc/save_preferences()
if(!path) return 0
var/savefile/S = new /savefile(path)
if(!S) return 0
S.cd = "/"
if(!savefile)
CRASH("Attempted to save the preferences of [client] without a savefile. This should have been handled by load_preferences()")
savefile.set_entry("version", SAVEFILE_VERSION_MAX) //updates (or failing that the sanity checks) will ensure data is not invalid at load. Assume up-to-date
S["version"] << savefile_version
player_setup.save_preferences(S)
return 1
player_setup.save_preferences(savefile)
for(var/preference_type in GLOB.preference_entries)
var/datum/preference/preference = GLOB.preference_entries[preference_type]
if(preference.savefile_identifier != PREFERENCE_PLAYER)
continue
if(!(preference.type in recently_updated_keys))
continue
recently_updated_keys -= preference.type
if(preference_type in value_cache)
write_preference(preference, preference.pref_serialize(value_cache[preference_type]))
savefile.save()
return TRUE
/datum/preferences/proc/reset_slot()
var/bacpath = "[path].resetbac"
if(fexists(bacpath))
fdel(bacpath) //only keep 1 version of backup
fcopy(savefile.path, bacpath) //byond helpfully lets you use a savefile for the first arg.
savefile.remove_entry("character[default_slot]")
default_slot = 1
clear_character_previews()
// Load slot 1 character
load_character()
// And save them immediately, in case we load an empty slot
save_character()
save_preferences()
return TRUE
/datum/preferences/proc/load_character(slot)
if(!path) return 0
if(!fexists(path)) return 0
var/savefile/S = new /savefile(path)
if(!S) return 0
S.cd = "/"
if(!slot) slot = default_slot
if(slot != SAVE_RESET) // SAVE_RESET will reset the slot as though it does not exist, but keep the current slot for saving purposes.
slot = sanitize_integer(slot, 1, CONFIG_GET(number/character_slots), initial(default_slot)) // CHOMPEdit
if(slot != default_slot)
default_slot = slot
S["default_slot"] << slot
else
S["default_slot"] << default_slot
SHOULD_NOT_SLEEP(TRUE)
if(!slot)
slot = default_slot
if(slot != SAVE_RESET)
S.cd = "/character[slot]"
player_setup.load_character(S)
else
player_setup.load_character(S)
S.cd = "/character[default_slot]"
player_setup.save_character(S)
slot = sanitize_integer(slot, 1, CONFIG_GET(number/character_slots), initial(default_slot)) // CHOMPEdit
if(slot != default_slot)
default_slot = slot
savefile.set_entry("default_slot", slot)
clear_character_previews() // VOREStation Edit
return 1
var/list/save_data = savefile.get_entry("character[slot]") // This is allowed to be null and will give a -1 in needs_update
var/needs_update = save_data_needs_update(save_data)
if(needs_update == -2) //fatal, can't load any data
return FALSE
// Read everything into cache (pre-migrations, as migrations should have access to deserialized data)
// Uses priority order as some values may rely on others for creating default values
for(var/datum/preference/preference as anything in get_preferences_in_priority_order())
if(preference.savefile_identifier != PREFERENCE_CHARACTER)
continue
value_cache -= preference.type
read_preference(preference.type)
// It has to be a list or load_character freaks out
if(!save_data)
player_setup.load_character(list())
else
player_setup.load_character(save_data)
//try to fix any outdated data if necessary
//preference updating will handle saving the updated data for us.
if(needs_update >= 0 || needs_update == -3)
update_character(needs_update, save_data) //needs_update == savefile_version if we need an update (positive integer
clear_character_previews()
return TRUE
/datum/preferences/proc/save_character()
if(!path) return 0
var/savefile/S = new /savefile(path)
if(!S) return 0
S.cd = "/character[default_slot]"
SHOULD_NOT_SLEEP(TRUE)
if(!savefile)
return FALSE
player_setup.save_character(S)
return 1
var/tree_key = "character[default_slot]"
if(!(tree_key in savefile.get_entry()))
savefile.set_entry(tree_key, list())
var/save_data = savefile.get_entry(tree_key)
save_data["version"] = SAVEFILE_VERSION_MAX //load_character will sanitize any bad data, so assume up-to-date.
player_setup.save_character(save_data)
return TRUE
/datum/preferences/proc/overwrite_character(slot)
if(!path) return 0
if(!fexists(path)) return 0
var/savefile/S = new /savefile(path)
if(!S) return 0
if(!slot) slot = default_slot
if(slot != SAVE_RESET)
slot = sanitize_integer(slot, 1, CONFIG_GET(number/character_slots), initial(default_slot)) // CHOMPEdit
if(slot != default_slot)
default_slot = slot
nif_path = nif_durability = nif_savedata = null //VOREStation Add - Don't copy NIF
S["default_slot"] << slot
if(!savefile)
return FALSE
if(!slot)
slot = default_slot
else
S["default_slot"] << default_slot
// This basically just changes default_slot without loading the correct data, so the next save call will overwrite
// the slot
slot = sanitize_integer(slot, 1, CONFIG_GET(number/character_slots), initial(default_slot)) // CHOMPEdit
if(slot != default_slot)
default_slot = slot
nif_path = nif_durability = nif_savedata = null //VOREStation Add - Don't copy NIF
savefile.set_entry("default_slot", slot)
return 1
return TRUE
/datum/preferences/proc/sanitize_preferences()
player_setup.sanitize_setup()
return 1
return TRUE
#undef SAVEFILE_VERSION_MAX
#undef SAVEFILE_VERSION_MIN

View File

@@ -0,0 +1,138 @@
/datum/preferences/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, custom_state)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "PreferencesMenu", "Preferences")
ui.set_autoupdate(FALSE)
ui.open()
/datum/preferences/tgui_state(mob/user)
return GLOB.tgui_always_state
/datum/preferences/tgui_status(mob/user, datum/tgui_state/state)
return user.client == client ? STATUS_INTERACTIVE : STATUS_CLOSE
/datum/preferences/ui_assets(mob/user)
var/list/assets = list(
// get_asset_datum(/datum/asset/spritesheet/preferences),
get_asset_datum(/datum/asset/json/preferences),
)
for (var/datum/preference_middleware/preference_middleware as anything in middleware)
assets += preference_middleware.get_ui_assets()
return assets
/datum/preferences/tgui_data(mob/user)
var/list/data = list()
if(tainted_character_profiles)
data["character_profiles"] = create_character_profiles()
tainted_character_profiles = FALSE
data["character_preferences"] = compile_character_preferences(user)
data["active_slot"] = default_slot
for(var/datum/preference_middleware/preference_middleware as anything in middleware)
data += preference_middleware.get_ui_data(user)
return data
/datum/preferences/tgui_static_data(mob/user)
var/list/data = list()
data["character_profiles"] = create_character_profiles()
// data["character_preview_view"] = character_preview_view.assigned_map
// data["overflow_role"] = SSjob.GetJobType(SSjob.overflow_role).title
data["window"] = current_window
for(var/datum/preference_middleware/preference_middleware as anything in middleware)
data += preference_middleware.get_ui_static_data(user)
return data
/datum/preferences/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("set_preference")
var/requested_preference_key = params["preference"]
var/value = params["value"]
for(var/datum/preference_middleware/preference_middleware as anything in middleware)
if(preference_middleware.pre_set_preference(usr, requested_preference_key, value))
return TRUE
var/datum/preference/requested_preference = GLOB.preference_entries_by_key[requested_preference_key]
if(isnull(requested_preference))
return FALSE
// SAFETY: `update_preference` performs validation checks
if(!update_preference(requested_preference, value))
return FALSE
// if(istype(requested_preference, /datum/preference/name)) // TODO: do this
// tainted_character_profiles = TRUE
return TRUE
for(var/datum/preference_middleware/preference_middleware as anything in middleware)
var/delegation = preference_middleware.action_delegations[action]
if(!isnull(delegation))
return call(preference_middleware, delegation)(params, usr)
return FALSE
/datum/preferences/tgui_close(mob/user)
save_character()
save_preferences()
/datum/preferences/proc/create_character_profiles()
var/list/profiles = list()
for(var/index in 1 to CONFIG_GET(number/character_slots)) //CHOMPEdit
// TODO: It won't be updated in the savefile yet, so just read the name directly
// if(index == default_slot)
// profiles += read_preference(/datum/preference/name/real_name)
// continue
var/tree_key = "character[index]"
var/save_data = savefile.get_entry(tree_key)
var/name = save_data?["real_name"]
if(isnull(name))
profiles += null
continue
profiles += name
return profiles
/datum/preferences/proc/compile_character_preferences(mob/user)
var/list/preferences = list()
for(var/datum/preference/preference as anything in get_preferences_in_priority_order())
if(!preference.is_accessible(src))
continue
var/value = read_preference(preference.type)
var/data = preference.compile_ui_data(user, value)
LAZYINITLIST(preferences[preference.category])
preferences[preference.category][preference.savefile_key] = data
for(var/datum/preference_middleware/preference_middleware as anything in middleware)
var/list/append_character_preferences = preference_middleware.get_character_preferences(user)
if(isnull(append_character_preferences))
continue
for(var/category in append_character_preferences)
if(category in preferences)
preferences[category] += append_character_preferences[category]
else
preferences[category] = append_character_preferences[category]
return preferences

View File

@@ -1,229 +1,3 @@
//Toggles for preferences, normal clients
/client/verb/toggle_ghost_ears()
set name = "Toggle Ghost Ears"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "Toggles between seeing all mob speech and only nearby mob speech as an observer."
var/pref_path = /datum/client_preference/ghost_ears
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear all mob speech as a ghost.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TGEars") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_ghost_vision()
set name = "Toggle Ghost Sight"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "Toggles between seeing all mob emotes and only nearby mob emotes as an observer."
var/pref_path = /datum/client_preference/ghost_sight
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] see all emotes as a ghost.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TGVision") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_ghost_radio()
set name = "Toggle Ghost Radio"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "Toggles between seeing all radio chat and only nearby radio chatter as an observer."
var/pref_path = /datum/client_preference/ghost_radio
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear all radios as a ghost.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TGRadio") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_deadchat()
set name = "Toggle Deadchat"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "Toggles visibility of dead chat."
var/pref_path = /datum/client_preference/show_dsay
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear dead chat as a ghost.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TDeadChat") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_ooc()
set name = "Toggle OOC"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "Toggles visibility of global out of character chat."
var/pref_path = /datum/client_preference/show_ooc
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(/datum/client_preference/show_ooc)) ? "now" : "no longer"] hear global out of character chat.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_looc()
set name = "Toggle LOOC"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "Toggles visibility of local out of character chat."
var/pref_path = /datum/client_preference/show_looc
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear local out of character chat.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_precision_placement()
set name = "Toggle Precision Placement"
set category = "Preferences.Game" //CHOMPEdit
set desc = "Toggles whether objects placed on table will be on cursor position or centered."
var/pref_path = /datum/client_preference/precision_placement
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] place items where your cursor is on the table.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TPIP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_typing()
set name = "Toggle Typing Indicator"
set category = "Preferences.Game" //CHOMPEdit
set desc = "Toggles you having the speech bubble typing indicator."
var/pref_path = /datum/client_preference/show_typing_indicator
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] have the speech indicator.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TTIND") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_ahelp_sound()
set name = "Toggle Admin Help Sound"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear a noise broadcasted when you get an admin message."
var/pref_path = /datum/client_preference/holder/play_adminhelp_ping
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] receive noise from admin messages.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TAHelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_lobby_music()
set name = "Toggle Lobby Music"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear the music in the lobby."
var/pref_path = /datum/client_preference/play_lobby_music
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear music in the lobby.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TLobMusic") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_admin_midis()
set name = "Toggle Admin Music"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear music played by admins."
var/pref_path = /datum/client_preference/play_admin_midis
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear music from admins.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TAMidis") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_ambience()
set name = "Toggle Ambience"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear local ambience."
var/pref_path = /datum/client_preference/play_ambiance
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear ambient noise.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TAmbience") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_weather_sounds()
set name = "Toggle Weather Sounds"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear weather sounds while on a planet."
var/pref_path = /datum/client_preference/weather_sounds
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear weather sounds.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TWeatherSounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_supermatter_hum()
set name = "Toggle SM Hum" // Avoiding using the full 'Supermatter' name to not conflict with the Setup-Supermatter adminverb.
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear supermatter hums."
var/pref_path = /datum/client_preference/supermatter_hum
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear a hum from the supermatter.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TSupermatterHum") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_jukebox()
set name = "Toggle Jukebox"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear jukebox music."
var/pref_path = /datum/client_preference/play_jukebox
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear jukebox music.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TJukebox") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_be_special(role in be_special_flags)
set name = "Toggle Special Role Candidacy"
set category = "Preferences.Character" //CHOMPEdit
@@ -239,146 +13,6 @@
feedback_add_details("admin_verb","TBeSpecial") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_air_pump_hum()
set name = "Toggle Air Vent Noise"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear air vent humming."
var/pref_path = /datum/client_preference/air_pump_noise
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear air vents hum, start, and stop.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TAirPumpNoise")
/client/verb/toggle_old_door_sounds()
set name = "Toggle Door: Old Sounds"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles door sounds between old and new."
var/pref_path = /datum/client_preference/old_door_sounds
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear the legacy door sounds.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TOldDoorSounds")
/client/verb/toggle_department_door_sounds()
set name = "Toggle Door: Department Sounds"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles hearing of department-specific door sounds."
var/pref_path = /datum/client_preference/department_door_sounds
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear per-department door sounds.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TDepartmentDoorSounds")
/client/verb/toggle_pickup_sounds()
set name = "Toggle Item: Picked up Sounds"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear sounds when items are picked up."
var/pref_path = /datum/client_preference/pickup_sounds
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear sounds when items are picked up.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb", "TPickupSounds")
/client/verb/toggle_drop_sounds()
set name = "Toggle Item: Dropped Sounds"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear sounds when items are dropped or thrown."
var/pref_path = /datum/client_preference/drop_sounds
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear sounds when items are dropped or thrown.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb", "TDropSounds")
/client/verb/toggle_safe_firing()
set name = "Toggle Gun Firing Intent Requirement"
set category = "Preferences.Game" //CHOMPEdit
set desc = "Toggles between safe and dangerous firing. Safe requires a non-help intent to fire, dangerous can be fired on help intent."
var/pref_path = /datum/client_preference/safefiring
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src,"You will now use [(is_preference_enabled(/datum/client_preference/safefiring)) ? "safe" : "dangerous"] firearms firing.")
feedback_add_details("admin_verb","TFiringMode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_mob_tooltips()
set name = "Toggle Mob Tooltips"
set category = "Preferences.Game" //CHOMPEdit
set desc = "Toggles displaying name/species over mobs when they are moused over."
var/pref_path = /datum/client_preference/mob_tooltips
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src,"You will now [(is_preference_enabled(/datum/client_preference/mob_tooltips)) ? "see" : "not see"] mob tooltips.")
feedback_add_details("admin_verb","TMobTooltips") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_inv_tooltips()
set name = "Toggle Item Tooltips"
set category = "Preferences.Game" //CHOMPEdit
set desc = "Toggles displaying name/desc over items when they are moused over (only applies in inventory)."
var/pref_path = /datum/client_preference/inv_tooltips
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src,"You will now [(is_preference_enabled(/datum/client_preference/inv_tooltips)) ? "see" : "not see"] inventory tooltips.")
feedback_add_details("admin_verb","TInvTooltips") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_hear_instruments()
set name = "Toggle Hear/Ignore Instruments"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles the ability to hear instruments playing."
var/pref_path = /datum/client_preference/instrument_toggle
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/instrument_toggle)) ? "hear" : "not hear"] instruments being played.")
feedback_add_details("admin_verb","THInstm") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_vchat()
set name = "Toggle TGChat"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "Toggles TGChat. Reloading TGChat and/or reconnecting required to affect changes."
var/pref_path = /datum/client_preference/vchat_enable
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "You have toggled TGChat [is_preference_enabled(pref_path) ? "on" : "off"]. \
You will have to reload TGChat and/or reconnect to the server for these changes to take place. \
TGChat message persistence is not guaranteed if you change this again before the start of the next round.")
/client/verb/toggle_chat_timestamps()
set name = "Toggle Chat Timestamps"
set category = "Preferences.Chat" //CHOMPEdit
@@ -389,101 +23,6 @@
to_chat(src, span_notice("You have toggled chat timestamps: [prefs.chat_timestamp ? "ON" : "OFF"]."))
/client/verb/toggle_status_indicators()
set name = "Toggle Status Indicators"
set category = "Preferences.Game" //CHOMPEdit
set desc = "Toggles seeing status indicators over peoples' heads."
var/pref_path = /datum/client_preference/status_indicators
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/status_indicators)) ? "see" : "not see"] status indicators.")
feedback_add_details("admin_verb","TStatusIndicators")
/client/verb/toggle_radio_sounds()
set name = "Toggle Radio Sounds"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggle hearing a sound when somebody speaks over your headset."
var/pref_path = /datum/client_preference/radio_sounds
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/radio_sounds)) ? "hear" : "not hear"] radio sounds.")
feedback_add_details("admin_verb","TRadioSounds")
/client/verb/toggle_say_sounds()
set name = "Toggle Voice Sounds" //CHOMPEdit - changed name to one that doesn't interfere with say autofill
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggle hearing a sound when somebody speaks or emotes."
var/pref_path = /datum/client_preference/say_sounds
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/say_sounds)) ? "hear" : "not hear"] say sounds.")
feedback_add_details("admin_verb","TSaySounds")
/*
CHOMPRemove. Bundled voice sounds into emote/whisper/subtle. Going this extra length to babyproof prefs wasn't necessary and got in the way of quick whisper/say autofill.
/client/verb/toggle_emote_sounds()
set name = "Sound-Toggle-Me"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggle hearing a sound when somebody speaks using me ."
var/pref_path = /datum/client_preference/emote_sounds
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/emote_sounds)) ? "hear" : "not hear"] me sounds.")
feedback_add_details("admin_verb","TMeSounds")
/client/verb/toggle_whisper_sounds()
set name = "Sound-Toggle-Whisper"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggle hearing a sound when somebody speaks using whisper."
var/pref_path = /datum/client_preference/whisper_sounds
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/whisper_sounds)) ? "hear" : "not hear"] whisper sounds.")
feedback_add_details("admin_verb","TWhisperSounds")
/client/verb/toggle_subtle_sounds()
set name = "Sound-Toggle-Subtle"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggle hearing a sound when somebody uses subtle."
var/pref_path = /datum/client_preference/subtle_sounds
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/subtle_sounds)) ? "hear" : "not hear"] subtle sounds.")
feedback_add_details("admin_verb","TSubtleSounds")
*/
/client/verb/toggle_vore_health_bars()
set name = "Toggle Vore Health Bars"
set category = "Preferences.Vore" //CHOMPEdit
set desc = "Toggle the display of vore related health bars"
var/pref_path = /datum/client_preference/vore_health_bars
toggle_preference(pref_path)
SScharacter_setup.queue_preferences_save(prefs)
to_chat(src, "Vore related health bars - [(is_preference_enabled(/datum/client_preference/vore_health_bars)) ? "Enabled" : "Disabled"]")
feedback_add_details("admin_verb","TVoreHealthBars")
// Not attached to a pref datum because those are strict binary toggles
/client/verb/toggle_examine_mode()
set name = "Toggle Examine Mode"
@@ -518,65 +57,3 @@ CHOMPRemove. Bundled voice sounds into emote/whisper/subtle. Going this extra le
to_chat(src, "<span class='filter_system'>Multilingual parsing will enforce the a language delimiter after the delimiter-key combination (,0,galcom -2 still galcom). The extra delimiter will be consumed by the pattern-matching.</span>")
if(MULTILINGUAL_OFF)
to_chat(src, "<span class='filter_system'>Multilingual parsing is now disabled. Entire messages will be in the language specified at the start of the message.</span>")
//Toggles for Staff
//Developers
/client/proc/toggle_debug_logs()
set name = "Toggle Debug Logs"
set category = "Preferences.Admin" //CHOMPEdit
set desc = "Toggles seeing debug logs."
var/pref_path = /datum/client_preference/debug/show_debug_logs
if(check_rights(R_ADMIN|R_DEBUG))
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] receive debug logs.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TADebugLogs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//Mods
/client/proc/toggle_attack_logs()
set name = "Toggle Attack Logs"
set category = "Preferences.Admin" //CHOMPEdit
set desc = "Toggles seeing attack logs."
var/pref_path = /datum/client_preference/mod/show_attack_logs
if(check_rights(R_ADMIN|R_MOD))
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] receive attack logs.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TAAttackLogs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//General
/client/proc/toggle_admin_global_looc()
set name = "Toggle Admin Global LOOC Visibility"
set category = "Preferences.Admin" //CHOMPEdit
set desc = "Toggles seeing LOOC messages outside your actual LOOC range."
var/pref_path = /datum/client_preference/holder/show_rlooc
if(holder)
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear global LOOC.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TAGlobalLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/toggle_admin_deadchat()
set name = "Toggle Admin Living Deadchat"
set category = "Preferences.Admin" //CHOMPEdit
set desc = "Toggles seeing deadchat while not observing."
var/pref_path = /datum/client_preference/holder/show_staff_dsay
if(holder)
toggle_preference(pref_path)
to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear deadchat while not observing.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TADeadchat") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

View File

@@ -18,97 +18,6 @@
var/job_talon_low = 0
//Why weren't these in game toggles already?
/client/verb/toggle_eating_noises()
set name = "Toggle Eating Noises"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles hearing Vore Eating noises."
var/pref_path = /datum/client_preference/eating_noises
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear eating related vore noises.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TEatNoise") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_digestion_noises()
set name = "Toggle Digestion Noises"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles hearing Vore Digestion noises."
var/pref_path = /datum/client_preference/digestion_noises
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear digestion related vore noises.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TDigestNoise") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_belch_noises()
set name = "Toggle Audible Belching"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles hearing audible belches."
var/pref_path = /datum/client_preference/belch_noises
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear belching.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TBelchNoise")
/client/verb/toggle_emote_noises()
set name = "Toggle Emote Noises"
set category = "Preferences.Sounds" //CHOMPEdit
set desc = "Toggles hearing emote noises."
var/pref_path = /datum/client_preference/emote_noises
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear emote-related noises.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TEmoteNoise") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_ghost_quiets()
set name = "Toggle Ghost Privacy"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "Toggles ghosts being able to see your subtles/whispers."
var/pref_path = /datum/client_preference/whisubtle_vis
toggle_preference(pref_path)
to_chat(src, "Ghosts will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear subtles/whispers made by you.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TWhisubtleVis") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_ghost_privacyvision()
set name = "Toggle Ghost Private Eyes/ears"
set category = "Preferences.Admin" //CHOMPEdit
set desc = "Toggles your ability to see subtles/whispers. Overrides admin status. Respects Ghost Privacy"
var/pref_path = /datum/client_preference/ghost_see_whisubtle
toggle_preference(pref_path)
to_chat(src, "As a ghost, you will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear subtles/whispers made by players.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TGhostSeeWhisSubtle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_capture_crystal()
set name = "Toggle Catchable"
set category = "Preferences.Character" //CHOMPEdit
@@ -127,55 +36,3 @@
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TCaptureCrystal") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_mentorhelp_ping()
set name = "Toggle Mentorhelp Ping"
set category = "Preferences.Admin" //CHOMPEdit
set desc = "Toggles the mentorhelp ping"
var/pref_path = /datum/client_preference/play_mentorhelp_ping
toggle_preference(pref_path)
to_chat(src, "Mentorhelp pings are now [ is_preference_enabled(pref_path) ? "enabled" : "disabled"]")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb", "TSoundMentorhelps")
/client/verb/toggle_player_tips()
set name = "Toggle Receiving Player Tips"
set category = "Preferences.Chat" //CHOMPEdit
set desc = "When toggled on, you receive tips periodically on roleplay and gameplay."
var/pref_path = /datum/client_preference/player_tips
toggle_preference(pref_path)
to_chat(src, "You are [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] periodically receiving advice on gameplay and roleplay.")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb", "TReceivePlayerTips")
/client/verb/toggle_pain_frequency()
set name = "Toggle Pain Frequency"
set category = "Preferences.Game" //CHOMPEdit
set desc = "When toggled on, increases the cooldown of pain messages sent to chat for minor injuries"
var/pref_path = /datum/client_preference/pain_frequency
toggle_preference(pref_path)
to_chat(src, "The cooldown between pain messages for minor (under 20/5 injury. Multi-limb injuries are still faster) is now [ (is_preference_enabled(pref_path)) ? "extended" : "default"].")
/client/verb/toggle_automatic_afk()
set name = "Toggle Automatic AFK"
set category = "Preferences.Game" //CHOMPEdit
set desc = "When enabled, causes you to be automatically marked as AFK if you are idle for too long."
var/pref_path = /datum/client_preference/auto_afk
toggle_preference(pref_path)
to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "not"] be automatically marked as AFK if you are idle for ten minutes or more.")

View File

@@ -15,7 +15,7 @@
msg = sanitize(msg)
if(!msg) return
if(!is_preference_enabled(/datum/client_preference/show_ooc))
if(!prefs?.read_preference(/datum/preference/toggle/show_ooc))
to_chat(src, "<span class='warning'>You have OOC muted.</span>")
return
@@ -66,7 +66,7 @@
msg = GLOB.is_valid_url.Replace(msg,"<span class='linkify'>$1</span>")
for(var/client/target in GLOB.clients)
if(target.is_preference_enabled(/datum/client_preference/show_ooc))
if(target.prefs?.read_preference(/datum/preference/toggle/show_ooc))
if(target.is_key_ignored(key)) // If we're ignored by this person, then do nothing.
continue
var/display_name = src.key
@@ -101,7 +101,7 @@
if(!msg)
return
if(!is_preference_enabled(/datum/client_preference/show_looc))
if(!prefs?.read_preference(/datum/preference/toggle/show_looc))
to_chat(src, "<span class='danger'>You have LOOC muted.</span>")
return
@@ -159,7 +159,7 @@
// Everyone in normal viewing range of the LOOC
for(var/mob/viewer in m_viewers)
if(viewer.client && viewer.client.is_preference_enabled(/datum/client_preference/show_looc))
if(viewer.client && viewer.client.prefs?.read_preference(/datum/preference/toggle/show_looc))
receivers |= viewer.client
else if(istype(viewer,/mob/observer/eye)) // For AI eyes and the like
var/mob/observer/eye/E = viewer
@@ -168,7 +168,7 @@
// Admins with RLOOC displayed who weren't already in
for(var/client/admin in GLOB.admins)
if(!(admin in receivers) && admin.is_preference_enabled(/datum/client_preference/holder/show_rlooc))
if(!(admin in receivers) && admin.prefs?.read_preference(/datum/preference/toggle/holder/show_rlooc))
if(check_rights(R_ADMIN|R_SERVER, FALSE, admin)) //Stop rLOOC showing for retired staff //CHOMPEdit, admins should see LOOC
r_receivers |= admin

View File

@@ -7,7 +7,7 @@
src << output('html/typing_indicator.html', "commandbar_spy")
/client/proc/handle_commandbar_typing(href_list)
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator))
if(!prefs?.read_preference(/datum/preference/toggle/show_typing_indicator))
return
if(length(href_list["verb"]) < 1 || !(lowertext(href_list["verb"]) in IC_VERBS) || text2num(href_list["argument_length"]) < 1)
@@ -31,10 +31,10 @@
/** Sets the mob as "thinking" - with indicator and the TRAIT_THINKING_IN_CHARACTER trait */
/client/proc/start_thinking(channel)
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator))
if(!prefs?.read_preference(/datum/preference/toggle/show_typing_indicator))
return FALSE
if(channel == "Whis" || channel == "Subtle" || channel == "whisper" || channel == "subtle")
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator_subtle))
if(!prefs?.read_preference(/datum/preference/toggle/show_typing_indicator_subtle))
return FALSE
ADD_TRAIT(mob, TRAIT_THINKING_IN_CHARACTER, CURRENTLY_TYPING_TRAIT)
mob.create_thinking_indicator()
@@ -50,10 +50,10 @@
/client/proc/start_typing(channel)
var/mob/client_mob = mob
client_mob.remove_thinking_indicator()
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator) || !HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER))
if(!prefs?.read_preference(/datum/preference/toggle/show_typing_indicator) || !HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER))
return FALSE
if(channel == "Whis" || channel == "Subtle" || channel == "whisper" || channel == "subtle")
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator_subtle))
if(!prefs?.read_preference(/datum/preference/toggle/show_typing_indicator_subtle))
return FALSE
client_mob.create_typing_indicator()
addtimer(CALLBACK(src, PROC_REF(stop_typing), channel), 5 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_STOPPABLE)
@@ -67,10 +67,10 @@
return FALSE
var/mob/client_mob = mob
client_mob.remove_typing_indicator()
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator) || !HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER))
if(!prefs?.read_preference(/datum/preference/toggle/show_typing_indicator) || !HAS_TRAIT(client_mob, TRAIT_THINKING_IN_CHARACTER))
return FALSE
if(channel == "Whis" || channel == "Subtle" || channel == "whisper" || channel == "subtle")
if(!is_preference_enabled(/datum/client_preference/show_typing_indicator_subtle))
if(!prefs?.read_preference(/datum/preference/toggle/show_typing_indicator_subtle))
return FALSE
client_mob.create_thinking_indicator()