diff --git a/code/datums/components/species/xenochimera.dm b/code/datums/components/species/xenochimera.dm index ef6c12b232..64ae15433a 100644 --- a/code/datums/components/species/xenochimera.dm +++ b/code/datums/components/species/xenochimera.dm @@ -394,10 +394,11 @@ var/from_slot = "" from_slot = "You'll hatch using your current appearance" if(reload_slot == "From Slot" && client) - if(client.prefs.species == SPECIES_PROTEAN) // Exploit protection + if(client.prefs.read_preference(/datum/preference/choiced/species) == SPECIES_PROTEAN) // Exploit protection to_chat(src,span_warning("You cannot copy nanoform prosthetic limbs from this species. Please try another character.")) return - var/slot_is_synth = ((O_BRAIN in client.prefs.organ_data) && client.prefs.organ_data[O_BRAIN]) + var/list/organ_data = client.prefs.read_preference(/datum/preference/organ_data) + var/slot_is_synth = (organ_data && (O_BRAIN in organ_data) && organ_data[O_BRAIN]) if(slot_is_synth && !isSynthetic()) // Prevents some pretty weird situations to_chat(src,span_warning("Cannot apply character appearance. [slot_is_synth ? "The slot's character is synthetic." : "The slot's character is organic."] Slot must match the current body's synthetic state. Please try another character.")) return diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm index d09a357dcb..c0129a2c11 100644 --- a/code/game/antagonist/station/changeling.dm +++ b/code/game/antagonist/station/changeling.dm @@ -82,10 +82,11 @@ return 1 else if(isnewplayer(player.current)) if(player.current.client && player.current.client.prefs) - var/datum/species/S = GLOB.all_species[player.current.client.prefs.species] + var/datum/species/S = GLOB.all_species[player.current.client.prefs.read_preference(/datum/preference/choiced/species)] if(S && (S.flags & (NO_SLEEVE|NO_DNA))) return 0 - if(player.current.client.prefs.organ_data[BP_TORSO] == "cyborg") // Full synthetic. // TODO, this to issynthetic()? + var/list/organ_data = player.current.client.prefs.read_preference(/datum/preference/organ_data) + if(organ_data && organ_data[BP_TORSO] == "cyborg") // Full synthetic. // TODO, this to issynthetic()? return 0 return 1 return 0 diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index db670d19b1..e5baaf6913 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -50,7 +50,7 @@ GLOBAL_DATUM(job_master, /datum/controller/occupations) var/datum/job/job = GetJob(rank) if(!job) return 0 - if((job.minimum_character_age || job.min_age_by_species) && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.species, player.client.prefs.organ_data[O_BRAIN]))) + if((job.minimum_character_age || job.min_age_by_species) && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) return 0 if(jobban_isbanned(player, rank)) return 0 @@ -100,7 +100,7 @@ GLOBAL_DATUM(job_master, /datum/controller/occupations) if(!job.player_old_enough(player.client)) Debug("FOC player not old enough, Player: [player]") continue - if(job.minimum_character_age && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.species, player.client.prefs.organ_data[O_BRAIN]))) + if(job.minimum_character_age && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) Debug("FOC character not old enough, Player: [player]") continue //VOREStation Code Start @@ -125,7 +125,7 @@ GLOBAL_DATUM(job_master, /datum/controller/occupations) if(!job) continue - if((job.minimum_character_age || job.min_age_by_species) && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.species, player.client.prefs.organ_data[O_BRAIN]))) + if((job.minimum_character_age || job.min_age_by_species) && (player.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(player.client.prefs.read_preference(/datum/preference/choiced/species), player.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) continue if(istype(job, GetJob(JOB_ALT_VISITOR))) // We don't want to give him assistant, that's boring! //VOREStation Edit - Visitor not Assistant @@ -183,10 +183,10 @@ GLOBAL_DATUM(job_master, /datum/controller/occupations) if(!V.client) continue var/age = V.read_preference(/datum/preference/numeric/human/age) - if(age < job.get_min_age(V.client.prefs.species, V.client.prefs.organ_data[O_BRAIN])) // Nope. + if(age < job.get_min_age(V.client.prefs.read_preference(/datum/preference/choiced/species), V.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN])) // Nope. continue - var/idealage = job.get_ideal_age(V.client.prefs.species, V.client.prefs.organ_data[O_BRAIN]) + var/idealage = job.get_ideal_age(V.client.prefs.read_preference(/datum/preference/choiced/species), V.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]) var/agediff = abs(idealage - age) // Compute the absolute difference in age from target switch(agediff) /// If the math sucks, it's because I almost failed algebra in high school. if(20 to INFINITY) diff --git a/code/game/machinery/virtual_reality/vr_procs.dm b/code/game/machinery/virtual_reality/vr_procs.dm index 9a79a4039c..501aa5cfcd 100644 --- a/code/game/machinery/virtual_reality/vr_procs.dm +++ b/code/game/machinery/virtual_reality/vr_procs.dm @@ -62,7 +62,7 @@ if(!landmark) return - var/mob/living/carbon/human/avatar = new(get_turf(landmark), client.prefs.species) + var/mob/living/carbon/human/avatar = new(get_turf(landmark), client.prefs.read_preference(/datum/preference/choiced/species)) if(!avatar) to_chat(src, "Something went wrong and spawning failed.") return diff --git a/code/game/objects/structures/ghost_pods/event_vr.dm b/code/game/objects/structures/ghost_pods/event_vr.dm index b09369826e..637afa1892 100644 --- a/code/game/objects/structures/ghost_pods/event_vr.dm +++ b/code/game/objects/structures/ghost_pods/event_vr.dm @@ -133,7 +133,7 @@ return //No whitelist - if(!is_alien_whitelisted(user.client, GLOB.all_species[user.client.prefs.species])) + if(!is_alien_whitelisted(user.client, GLOB.all_species[user.client.prefs.read_preference(/datum/preference/choiced/species)])) to_chat(user, span_warning("You cannot use this spawnpoint to spawn as a species you are not whitelisted for!")) return @@ -211,7 +211,7 @@ return //No whitelist - if(!is_alien_whitelisted(user.client, GLOB.all_species[user.client.prefs.species])) + if(!is_alien_whitelisted(user.client, GLOB.all_species[user.client.prefs.read_preference(/datum/preference/choiced/species)])) to_chat(user, span_warning("You cannot use this spawnpoint to spawn as a species you are not whitelisted for!")) return diff --git a/code/game/objects/structures/ghost_pods/unified_ghost_hole.dm b/code/game/objects/structures/ghost_pods/unified_ghost_hole.dm index 8e160fcffc..17024555cd 100644 --- a/code/game/objects/structures/ghost_pods/unified_ghost_hole.dm +++ b/code/game/objects/structures/ghost_pods/unified_ghost_hole.dm @@ -39,7 +39,7 @@ if("Morph") create_morph(user) if("Lurker") - if(!is_alien_whitelisted(user.client, GLOB.all_species[user.client.prefs.species])) + if(!is_alien_whitelisted(user.client, GLOB.all_species[user.client.prefs.read_preference(/datum/preference/choiced/species)])) to_chat(user, span_warning("You cannot use this spawnpoint to spawn as a species you are not whitelisted for!")) return create_lurker(user) diff --git a/code/game/sound.dm b/code/game/sound.dm index 5e5bf9643c..7951a6726c 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -416,9 +416,10 @@ GLOBAL_LIST_INIT(species_sound_map, list( */ /proc/select_default_species_sound(var/datum/preferences/pref) // Called in character setup. This is similar to check_gendered_sounds, except here we pull from the prefs. // First, we determine if we're custom-choosing a body or if we're a base game species. - var/datum/species/valid = GLOB.all_species[pref.species] + var/pref_species = pref.read_preference(/datum/preference/choiced/species) + var/datum/species/valid = GLOB.all_species[pref_species] if(valid.selects_bodytype == (SELECTS_BODYTYPE_CUSTOM || SELECTS_BODYTYPE_SHAPESHIFTER)) // Custom species or xenochimera handling here - valid = coalesce(GLOB.all_species[pref.custom_base], GLOB.all_species[pref.species]) + valid = coalesce(GLOB.all_species[pref.custom_base], GLOB.all_species[pref_species]) // Now we start getting our sounds. var/id_gender = pref.read_preference(/datum/preference/choiced/gender/identifying) if(valid.gender_specific_species_sounds) // Do we have gender-specific sounds? diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm index b5ff2f03d7..491ca9030a 100644 --- a/code/modules/client/preference_setup/general/01_basic.dm +++ b/code/modules/client/preference_setup/general/01_basic.dm @@ -31,11 +31,12 @@ var/char_real_name = pref.read_preference(/datum/preference/name/real_name) var/char_bio_gender = pref.read_preference(/datum/preference/choiced/gender/biological) var/char_id_gender = pref.read_preference(/datum/preference/choiced/gender/identifying) + var/pref_species = pref.read_preference(/datum/preference/choiced/species) // Re-sanitize name on join. // Fixes being able to swap from FBP to organic before round join to be organic with numbers in name. - char_real_name = sanitize_name(char_real_name, pref.species, is_FBP()) + char_real_name = sanitize_name(char_real_name, pref_species, is_FBP()) if(!char_real_name) - char_real_name = random_name(char_id_gender, pref.species) + char_real_name = random_name(char_id_gender, pref_species) if(CONFIG_GET(flag/humans_need_surnames)) var/firstspace = findtext(char_real_name, " ") var/name_length = length(char_real_name) @@ -91,10 +92,12 @@ var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(pref.client_ckey) if(mannequin) species = mannequin.species - else if(pref.species) - species = GLOB.all_species[pref.species] else - species = GLOB.all_species[SPECIES_HUMAN] + var/pref_species = pref.read_preference(/datum/preference/choiced/species) + if(pref_species) + species = GLOB.all_species[pref_species] + else + species = GLOB.all_species[SPECIES_HUMAN] var/list/species_stats = list( "total_health" = species.total_health, @@ -193,9 +196,10 @@ switch(action) if("rename") var/current_name = pref.read_preference(/datum/preference/name/real_name) + var/pref_species = pref.read_preference(/datum/preference/choiced/species) var/raw_name = tgui_input_text(user, "Choose your character's name:", "Character Name", current_name, encode = FALSE) if(!isnull(raw_name)) - var/new_name = sanitize_name(raw_name, pref.species, is_FBP()) + var/new_name = sanitize_name(raw_name, pref_species, is_FBP()) if(new_name) pref.update_preference_by_type(/datum/preference/name/real_name, new_name) return TOPIC_REFRESH @@ -204,7 +208,7 @@ return TOPIC_NOACTION if("random_name") - pref.update_preference_by_type(/datum/preference/name/real_name, random_name(pref.read_preference(/datum/preference/choiced/gender/identifying), pref.species)) + pref.update_preference_by_type(/datum/preference/name/real_name, random_name(pref.read_preference(/datum/preference/choiced/gender/identifying), pref.read_preference(/datum/preference/choiced/species))) return TOPIC_REFRESH if("always_random_name") @@ -213,9 +217,10 @@ if("nickname") var/current_nickname = pref.read_preference(/datum/preference/name/nickname) + var/pref_species = pref.read_preference(/datum/preference/choiced/species) var/raw_nickname = tgui_input_text(user, "Choose your character's nickname:", "Character Nickname", current_nickname, encode = FALSE) if(!isnull(raw_nickname)) - var/new_nickname = sanitize_name(raw_nickname, pref.species, is_FBP()) + var/new_nickname = sanitize_name(raw_nickname, pref_species, is_FBP()) if(new_nickname) pref.update_preference_by_type(/datum/preference/name/nickname, new_nickname) return TOPIC_REFRESH @@ -376,12 +381,14 @@ /datum/category_item/player_setup_item/general/basic/proc/get_genders() var/datum/species/S - if(pref.species) - S = GLOB.all_species[pref.species] + var/pref_species = pref.read_preference(/datum/preference/choiced/species) + if(pref_species) + S = GLOB.all_species[pref_species] else S = GLOB.all_species[SPECIES_HUMAN] var/list/possible_genders = S.genders - if(!pref.organ_data || pref.organ_data[BP_TORSO] != "cyborg") + var/list/organ_data = pref.read_preference(/datum/preference/organ_data) + if(!organ_data || organ_data[BP_TORSO] != "cyborg") return possible_genders possible_genders = possible_genders.Copy() possible_genders |= NEUTER diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm index d3a898266a..45dafdf5b5 100644 --- a/code/modules/client/preference_setup/general/02_language.dm +++ b/code/modules/client/preference_setup/general/02_language.dm @@ -12,7 +12,6 @@ pref.alternate_languages = check_list_copy(save_data["language"]) pref.extra_languages = save_data["extra_languages"] pref.language_prefixes = save_data["language_prefixes"] - pref.species = save_data["species"] pref.preferred_language = save_data["preflang"] pref.language_custom_keys = check_list_copy(save_data["language_custom_keys"]) pref.runechat_color = save_data["runechat_color"] @@ -32,10 +31,11 @@ if(!islist(pref.alternate_languages)) testing("LANGSANI: Sanitizing languages on [pref.client]'s character [char_name] because their character has no languages list") pref.alternate_languages = list() - if(pref.species) - var/datum/species/S = GLOB.all_species[pref.species] + var/pref_species = pref.read_preference(/datum/preference/choiced/species) + if(pref_species) + var/datum/species/S = GLOB.all_species[pref_species] if(!istype(S)) - testing("LANGSANI: Failed sani on [pref.client]'s character [char_name] because their species ([pref.species]) isn't in the global list") + testing("LANGSANI: Failed sani on [pref.client]'s character [char_name] because their species ([pref_species]) isn't in the global list") return if(pref.alternate_languages.len > (S.num_alternate_languages + pref.extra_languages)) @@ -62,7 +62,7 @@ pref.language_prefixes -= prefix if(isnull(pref.language_custom_keys)) pref.language_custom_keys = list() - var/datum/species/S = GLOB.all_species[pref.species] + var/datum/species/S = GLOB.all_species[pref.read_preference(/datum/preference/choiced/species)] for(var/key in pref.language_custom_keys) if(!pref.language_custom_keys[key]) pref.language_custom_keys.Remove(key) @@ -76,7 +76,7 @@ var/list/languages_list = list() - var/datum/species/S = GLOB.all_species[pref.species] + var/datum/species/S = GLOB.all_species[pref.read_preference(/datum/preference/choiced/species)] if(S.language) UNTYPED_LIST_ADD(languages_list, list( "name" = S.language, @@ -108,7 +108,7 @@ return var/mob/user = ui.user - var/datum/species/S = GLOB.all_species[pref.species] + var/datum/species/S = GLOB.all_species[pref.read_preference(/datum/preference/choiced/species)] switch(action) if("remove_language") diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 2e063513a1..e70c1d38b3 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -50,6 +50,7 @@ /datum/preferences/proc/get_available_styles(var/style_list) . = list("Normal" = null) + var/pref_species = read_preference(/datum/preference/choiced/species) for(var/path in style_list) var/datum/sprite_accessory/instance = style_list[path] if(!istype(instance)) @@ -58,7 +59,7 @@ continue if(instance.ckeys_allowed && (!client || !(client.ckey in instance.ckeys_allowed))) continue - if(instance.species_allowed && (!species || !(species in instance.species_allowed)) && (!client || !check_rights_for(client, R_ADMIN | R_EVENT | R_FUN)) && (!custom_base || !(custom_base in instance.species_allowed))) + if(instance.species_allowed && (!pref_species || !(pref_species in instance.species_allowed)) && (!client || !check_rights_for(client, R_ADMIN | R_EVENT | R_FUN)) && (!custom_base || !(custom_base in instance.species_allowed))) continue if(!instance.can_be_selected && (!client || !check_rights_for(client, R_HOLDER))) continue @@ -79,14 +80,11 @@ sort_order = 3 /datum/category_item/player_setup_item/general/body/load_character(list/save_data) - pref.species = save_data["species"] pref.s_tone = save_data["skin_tone"] 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.b_type = save_data["b_type"] - pref.organ_data = check_list_copy(save_data["organ_data"]) - pref.rlimb_data = check_list_copy(save_data["rlimb_data"]) pref.body_markings = check_list_copy(save_data["body_markings"]) for(var/i in pref.body_markings) pref.body_markings[i] = check_list_copy(pref.body_markings[i]) @@ -103,14 +101,11 @@ pref.digitigrade = save_data["digitigrade"] /datum/category_item/player_setup_item/general/body/save_character(list/save_data) - save_data["species"] = pref.species save_data["skin_tone"] = pref.s_tone 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["b_type"] = pref.b_type - save_data["organ_data"] = check_list_copy(pref.organ_data) - save_data["rlimb_data"] = check_list_copy(pref.rlimb_data) var/list/body_markings = check_list_copy(pref.body_markings) for(var/i in pref.body_markings) body_markings[i] = check_list_copy(body_markings[i]) @@ -128,28 +123,18 @@ save_data["digitigrade"] = pref.digitigrade /datum/category_item/player_setup_item/general/body/sanitize_character() - if(!pref.species || !(pref.species in GLOB.playable_species)) - pref.species = SPECIES_HUMAN pref.s_tone = sanitize_integer(pref.s_tone, -185, 34, initial(pref.s_tone)) pref.h_style = sanitize_inlist(pref.h_style, GLOB.hair_styles_list, initial(pref.h_style)) pref.f_style = sanitize_inlist(pref.f_style, GLOB.facial_hair_styles_list, initial(pref.f_style)) pref.grad_style = sanitize_inlist(pref.grad_style, GLOB.hair_gradients, initial(pref.grad_style)) pref.b_type = sanitize_text(pref.b_type, initial(pref.b_type)) - if(!pref.organ_data) pref.organ_data = list() - if(!pref.rlimb_data || !islist(pref.rlimb_data)) pref.rlimb_data = list() if(!pref.body_markings) pref.body_markings = list() else pref.body_markings &= GLOB.body_marking_styles_list for (var/M in pref.body_markings) if (!islist(pref.body_markings[M])) var/col = istext(pref.body_markings[M]) ? pref.body_markings[M] : "#000000" pref.body_markings[M] = pref.mass_edit_marking_list(M,color=col) - for(var/limb in pref.rlimb_data) - var/key = pref.rlimb_data[limb] - if(!istext(key)) - pref.rlimb_data -= limb - if(!LAZYACCESS(GLOB.all_robolimbs, key)) - pref.rlimb_data -= limb if(!pref.bgstate || !(pref.bgstate in pref.bgstate_options)) pref.bgstate = "000" @@ -198,7 +183,9 @@ character.set_gender(pref.read_preference(/datum/preference/choiced/gender/biological)) - character.synthetic = pref.species == "Protean" ? GLOB.all_robolimbs["protean"] : null //Clear the existing var. (unless protean, then switch it to the normal protean limb) + character.synthetic = pref.read_preference(/datum/preference/choiced/species) == "Protean" ? GLOB.all_robolimbs["protean"] : null //Clear the existing var. (unless protean, then switch it to the normal protean limb) + var/list/pref_organ_data = pref.read_preference(/datum/preference/organ_data) + var/list/pref_rlimb_data = pref.read_preference(/datum/preference/rlimb_data) var/list/organs_to_edit = list() for (var/name in list(BP_TORSO, BP_HEAD, BP_GROIN, BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) var/obj/item/organ/external/O = character.organs_by_name[name] @@ -209,19 +196,19 @@ else organs_to_edit.Insert(x+(O.robotic == ORGAN_NANOFORM ? 1 : 0), name) for(var/name in organs_to_edit) - var/status = pref.organ_data[name] + var/status = pref_organ_data[name] var/obj/item/organ/external/O = character.organs_by_name[name] if(O) if(status == "amputated") O.remove_rejuv() else if(status == "cyborg") - if(pref.rlimb_data[name]) - O.robotize(pref.rlimb_data[name]) + if(pref_rlimb_data[name]) + O.robotize(pref_rlimb_data[name]) else O.robotize() for(var/name in list(O_HEART,O_EYES,O_VOICE,O_LUNGS,O_LIVER,O_KIDNEYS,O_SPLEEN,O_STOMACH,O_INTESTINE,O_BRAIN)) - var/status = pref.organ_data[name] + var/status = pref_organ_data[name] if(!status) continue var/obj/item/organ/I = character.internal_organs_by_name[name] @@ -256,31 +243,26 @@ return mob_species && (mob_species.appearance_flags & flag) /datum/category_item/player_setup_item/general/body/proc/reset_limbs() - for(var/organ in pref.organ_data) - pref.organ_data[organ] = null - while(null in pref.organ_data) - pref.organ_data -= null - - for(var/organ in pref.rlimb_data) - pref.rlimb_data[organ] = null - while(null in pref.rlimb_data) - pref.rlimb_data -= null + // Reset organ and robolimb data + pref.write_preference(GLOB.preference_entries[/datum/preference/organ_data], list()) + pref.write_preference(GLOB.preference_entries[/datum/preference/rlimb_data], list()) // Sanitize the name so that there aren't any numbers sticking around. // Is this still necessary with TG conversation? + var/pref_species = pref.read_preference(/datum/preference/choiced/species) var/current_name = pref.read_preference(/datum/preference/name/real_name) - current_name = sanitize_name(current_name, pref.species) + current_name = sanitize_name(current_name, pref_species) if(!current_name) - current_name = random_name(pref.read_preference(/datum/preference/choiced/gender/identifying), pref.species) + current_name = random_name(pref.read_preference(/datum/preference/choiced/gender/identifying), pref_species) pref.update_preference_by_type(/datum/preference/name/real_name, current_name) /datum/category_item/player_setup_item/general/body/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) var/list/data = ..() - data["species"] = pref.species - data["organ_data"] = pref.organ_data - data["rlimb_data"] = pref.rlimb_data + data["species"] = pref.read_preference(/datum/preference/choiced/species) + data["organ_data"] = pref.read_preference(/datum/preference/organ_data) + data["rlimb_data"] = pref.read_preference(/datum/preference/rlimb_data) data["s_tone"] = -pref.s_tone + 35 data["eyes_color"] = pref.read_preference(/datum/preference/color/human/eyes_color) @@ -495,7 +477,7 @@ if(.) return - var/datum/species/mob_species = GLOB.all_species[pref.species] + var/datum/species/mob_species = GLOB.all_species[pref.read_preference(/datum/preference/choiced/species)] var/mob/user = ui.user switch(action) @@ -753,9 +735,9 @@ if(((!(setting_species.spawn_flags & SPECIES_CAN_JOIN)) || (!is_alien_whitelisted(user.client,setting_species))) && !check_rights(R_ADMIN|R_EVENT, 0) && !(setting_species.spawn_flags & SPECIES_WHITELIST_SELECTABLE)) return TOPIC_NOACTION - var/prev_species = pref.species - pref.species = params["species"] - if(prev_species != pref.species) + var/prev_species = pref.read_preference(/datum/preference/choiced/species) + pref.update_preference_by_type(/datum/preference/choiced/species, params["species"]) + if(prev_species != pref.read_preference(/datum/preference/choiced/species)) if(!(pref.read_preference(/datum/preference/choiced/gender/biological) in mob_species.genders)) pref.set_biological_gender(mob_species.genders[1]) pref.custom_species = null @@ -879,27 +861,35 @@ switch(new_state) if("Normal") - pref.organ_data[limb] = null - pref.rlimb_data[limb] = null + var/list/organ_data = pref.read_preference(/datum/preference/organ_data) + var/list/rlimb_data = pref.read_preference(/datum/preference/rlimb_data) + organ_data[limb] = null + rlimb_data[limb] = null if(limb == BP_TORSO) // depends on standardization for(var/other_limb in BP_ALL - BP_TORSO) - pref.organ_data[other_limb] = null - pref.rlimb_data[other_limb] = null + organ_data[other_limb] = null + rlimb_data[other_limb] = null for(var/internal in O_STANDARD) - pref.organ_data[internal] = null - pref.rlimb_data[internal] = null + organ_data[internal] = null + rlimb_data[internal] = null if(third_limb) - pref.organ_data[third_limb] = null - pref.rlimb_data[third_limb] = null + organ_data[third_limb] = null + rlimb_data[third_limb] = null + pref.write_preference(GLOB.preference_entries[/datum/preference/organ_data], organ_data) + pref.write_preference(GLOB.preference_entries[/datum/preference/rlimb_data], rlimb_data) if("Amputated") if(limb == BP_TORSO) // depends on standardization return - pref.organ_data[limb] = "amputated" - pref.rlimb_data[limb] = null + var/list/organ_data = pref.read_preference(/datum/preference/organ_data) + var/list/rlimb_data = pref.read_preference(/datum/preference/rlimb_data) + organ_data[limb] = "amputated" + rlimb_data[limb] = null if(second_limb) - pref.organ_data[second_limb] = "amputated" - pref.rlimb_data[second_limb] = null + organ_data[second_limb] = "amputated" + rlimb_data[second_limb] = null + pref.write_preference(GLOB.preference_entries[/datum/preference/organ_data], organ_data) + pref.write_preference(GLOB.preference_entries[/datum/preference/rlimb_data], rlimb_data) if("Prosthesis") var/list/usable_manufacturers = list() @@ -907,7 +897,7 @@ var/datum/robolimb/M = GLOB.chargen_robolimbs[company] if(!(limb in M.parts)) continue - if(pref.species in M.species_cannot_use) + if(pref.read_preference(/datum/preference/choiced/species) in M.species_cannot_use) continue if(M.whitelisted_to && !(user.ckey in M.whitelisted_to)) continue @@ -918,25 +908,29 @@ if(!choice) return - pref.rlimb_data[limb] = choice - pref.organ_data[limb] = "cyborg" + var/list/organ_data = pref.read_preference(/datum/preference/organ_data) + var/list/rlimb_data = pref.read_preference(/datum/preference/rlimb_data) + rlimb_data[limb] = choice + organ_data[limb] = "cyborg" if(second_limb) - pref.rlimb_data[second_limb] = choice - pref.organ_data[second_limb] = "cyborg" - if(third_limb && pref.organ_data[third_limb] == "amputated") - pref.organ_data[third_limb] = null + rlimb_data[second_limb] = choice + organ_data[second_limb] = "cyborg" + if(third_limb && organ_data[third_limb] == "amputated") + organ_data[third_limb] = null if(limb == BP_TORSO) for(var/other_limb in BP_ALL - BP_TORSO) - if(pref.organ_data[other_limb]) + if(organ_data[other_limb]) continue - pref.organ_data[other_limb] = "cyborg" - pref.rlimb_data[other_limb] = choice - if(!pref.organ_data[O_BRAIN]) - pref.organ_data[O_BRAIN] = FBP_ASSISTED + organ_data[other_limb] = "cyborg" + rlimb_data[other_limb] = choice + if(!organ_data[O_BRAIN]) + organ_data[O_BRAIN] = FBP_ASSISTED for(var/internal_organ in list(O_HEART,O_EYES)) - pref.organ_data[internal_organ] = FBP_MECHANICAL + organ_data[internal_organ] = FBP_MECHANICAL + pref.write_preference(GLOB.preference_entries[/datum/preference/organ_data], organ_data) + pref.write_preference(GLOB.preference_entries[/datum/preference/rlimb_data], rlimb_data) return TOPIC_REFRESH_UPDATE_PREVIEW @@ -945,7 +939,8 @@ if(!(zone in O_STANDARD)) return - if(zone == O_BRAIN && pref.organ_data[BP_HEAD] != "cyborg") + var/list/organ_data = pref.read_preference(/datum/preference/organ_data) + if(zone == O_BRAIN && organ_data[BP_HEAD] != "cyborg") to_chat(user, span_warning("You may only select a cybernetic or synthetic brain if you have a full prosthetic body.")) return @@ -971,17 +966,18 @@ switch(new_state) if("Normal") - pref.organ_data[zone] = null + organ_data[zone] = null if("Assisted") - pref.organ_data[zone] = FBP_ASSISTED + organ_data[zone] = FBP_ASSISTED if("Cybernetic") - pref.organ_data[zone] = FBP_ASSISTED + organ_data[zone] = FBP_ASSISTED if("Mechanical") - pref.organ_data[zone] = FBP_MECHANICAL + organ_data[zone] = FBP_MECHANICAL if("Drone") - pref.organ_data[zone] = FBP_DIGITAL + organ_data[zone] = FBP_DIGITAL if("Positronic") - pref.organ_data[zone] = FBP_MECHANICAL + organ_data[zone] = FBP_MECHANICAL + pref.write_preference(GLOB.preference_entries[/datum/preference/organ_data], organ_data) return TOPIC_REFRESH_UPDATE_PREVIEW diff --git a/code/modules/client/preference_setup/general/12_traits.dm b/code/modules/client/preference_setup/general/12_traits.dm index b7e952a170..6db74d4310 100644 --- a/code/modules/client/preference_setup/general/12_traits.dm +++ b/code/modules/client/preference_setup/general/12_traits.dm @@ -18,7 +18,7 @@ /datum/preferences/proc/get_custom_bases_for_species(var/new_species) if (!new_species) - new_species = species + new_species = read_preference(/datum/preference/choiced/species) var/list/choices var/datum/species/spec = GLOB.all_species[new_species] if (spec.selects_bodytype == SELECTS_BODYTYPE_SHAPESHIFTER) @@ -108,14 +108,15 @@ pref.blood_reagents = sanitize_text(pref.blood_reagents, initial(pref.blood_reagents)) if(!pref.traits_cheating) - var/datum/species/S = GLOB.all_species[pref.species] + var/datum/species/S = GLOB.all_species[pref.read_preference(/datum/preference/choiced/species)] if(S) pref.starting_trait_points = S.trait_points else pref.starting_trait_points = 0 pref.max_traits = MAX_SPECIES_TRAITS - if(pref.organ_data[O_BRAIN]) //Checking if we have a synth on our hands, boys. + var/list/organ_data = pref.read_preference(/datum/preference/organ_data) + if(organ_data && organ_data[O_BRAIN]) //Checking if we have a synth on our hands, boys. pref.dirty_synth = 1 pref.gross_meatbag = 0 else @@ -123,11 +124,12 @@ pref.dirty_synth = 0 // Clean up positive traits + var/pref_species = pref.read_preference(/datum/preference/choiced/species) for(var/datum/trait/path as anything in pref.pos_traits) if(!(path in GLOB.positive_traits)) pref.pos_traits -= path continue - if(!(pref.species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_positive)) + if(!(pref_species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_positive)) pref.pos_traits -= path continue var/take_flags = initial(path.can_take) @@ -139,7 +141,7 @@ log_world("removing [path] for not being in neutral_traits") pref.neu_traits -= path continue - if(!(pref.species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_neutral)) + if(!(pref_species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_neutral)) log_world("removing [path] for not being a custom species") pref.neu_traits -= path continue @@ -152,14 +154,14 @@ if(!(path in GLOB.negative_traits)) pref.neg_traits -= path continue - if(!(pref.species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_negative)) + if(!(pref_species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_negative)) pref.neg_traits -= path continue var/take_flags = initial(path.can_take) if((pref.dirty_synth && !(take_flags & SYNTHETICS)) || (pref.gross_meatbag && !(take_flags & ORGANICS))) pref.neg_traits -= path - var/datum/species/selected_species = GLOB.all_species[pref.species] + var/datum/species/selected_species = GLOB.all_species[pref_species] if(selected_species.selects_bodytype) if (!(pref.custom_base in pref.get_custom_bases_for_species())) pref.custom_base = selected_species.default_custom_base @@ -193,7 +195,7 @@ new_S.species_sounds = species_sounds_to_copy // Now we send our sounds over to the mob - if(pref.species == SPECIES_CUSTOM) + if(pref.read_preference(/datum/preference/choiced/species) == SPECIES_CUSTOM) //Statistics for this would be nice var/english_traits = english_list(new_S.traits, and_text = ";", comma_text = ";") log_game("TRAITS [pref.client_ckey]/([character]) with: [english_traits]") //Terrible 'fake' key_name()... but they aren't in the same entity yet @@ -201,7 +203,7 @@ /datum/category_item/player_setup_item/general/traits/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) var/list/data = ..() - var/datum/species/selected_species = GLOB.all_species[pref.species] + var/datum/species/selected_species = GLOB.all_species[pref.read_preference(/datum/preference/choiced/species)] data["selects_bodytype"] = selected_species.selects_bodytype data["custom_base"] = pref.custom_base data["blood_color"] = pref.blood_color @@ -252,7 +254,7 @@ pref.blood_color = sanitize_hexcolor(color_choice, default="#A10808") return TOPIC_REFRESH if("blood_reset") - var/datum/species/spec = GLOB.all_species[pref.species] + var/datum/species/spec = GLOB.all_species[pref.read_preference(/datum/preference/choiced/species)] var/new_blood = spec.blood_color ? spec.blood_color : "#A10808" var/choice = tgui_alert(user, "Reset blood color to species default ([new_blood])?","Reset Blood Color",list("Reset","Cancel")) if(choice == "Reset") @@ -295,23 +297,24 @@ var/mode = text2num(params["add_trait"]) var/list/picklist var/list/mylist + var/pref_species_for_traits = pref.read_preference(/datum/preference/choiced/species) switch(mode) if(POSITIVE_MODE) - if(pref.species == SPECIES_CUSTOM) + if(pref_species_for_traits == SPECIES_CUSTOM) picklist = GLOB.positive_traits.Copy() - pref.pos_traits mylist = pref.pos_traits else picklist = GLOB.everyone_traits_positive.Copy() - pref.pos_traits mylist = pref.pos_traits if(NEUTRAL_MODE) - if(pref.species == SPECIES_CUSTOM) + if(pref_species_for_traits == SPECIES_CUSTOM) picklist = GLOB.neutral_traits.Copy() - pref.neu_traits mylist = pref.neu_traits else picklist = GLOB.everyone_traits_neutral.Copy() - pref.neu_traits mylist = pref.neu_traits if(NEGATIVE_MODE) - if(pref.species == SPECIES_CUSTOM) + if(pref_species_for_traits == SPECIES_CUSTOM) picklist = GLOB.negative_traits.Copy() - pref.neg_traits mylist = pref.neg_traits else @@ -375,11 +378,11 @@ tgui_alert_async(user, "The trait you've selected can only be taken by synthetic characters!", "Error") return TOPIC_REFRESH - if(pref.species in instance.banned_species) + if(pref_species_for_traits in instance.banned_species) tgui_alert_async(user, "The trait you've selected cannot be taken by the species you've chosen!", "Error") return TOPIC_REFRESH - if( LAZYLEN(instance.allowed_species) && !(pref.species in instance.allowed_species)) + if( LAZYLEN(instance.allowed_species) && !(pref_species_for_traits in instance.allowed_species)) tgui_alert_async(user, "The trait you've selected cannot be taken by the species you've chosen!", "Error") return TOPIC_REFRESH diff --git a/code/modules/client/preference_setup/general/13_nif.dm b/code/modules/client/preference_setup/general/13_nif.dm index 91f59dfbc1..d4ed4d4442 100644 --- a/code/modules/client/preference_setup/general/13_nif.dm +++ b/code/modules/client/preference_setup/general/13_nif.dm @@ -42,7 +42,7 @@ pref.nif_path = null //Kill! WARNING("Loaded a NIF but it was an invalid path, [char_name]") - if (ispath(pref.nif_path, /obj/item/nif/protean) && pref.species != SPECIES_PROTEAN) //no free nifs + if (ispath(pref.nif_path, /obj/item/nif/protean) && pref.read_preference(/datum/preference/choiced/species) != SPECIES_PROTEAN) //no free nifs pref.nif_path = null if(ispath(pref.nif_path) && isnull(pref.nif_durability)) //How'd you lose this? diff --git a/code/modules/client/preference_setup/loadout/02_loadout.dm b/code/modules/client/preference_setup/loadout/02_loadout.dm index f6b151bda0..b9d86167e5 100644 --- a/code/modules/client/preference_setup/loadout/02_loadout.dm +++ b/code/modules/client/preference_setup/loadout/02_loadout.dm @@ -66,7 +66,7 @@ GLOBAL_LIST_EMPTY_TYPED(gear_datums, /datum/gear) /datum/category_item/player_setup_item/loadout/loadout/proc/is_valid_gear(datum/gear/G, max_cost) if(G.whitelisted && CONFIG_GET(flag/loadout_whitelist) != LOADOUT_WHITELIST_OFF && pref.client) - if(CONFIG_GET(flag/loadout_whitelist) == LOADOUT_WHITELIST_STRICT && (G.whitelisted != pref.species && G.whitelisted != pref.custom_base)) + if(CONFIG_GET(flag/loadout_whitelist) == LOADOUT_WHITELIST_STRICT && (G.whitelisted != pref.read_preference(/datum/preference/choiced/species) && G.whitelisted != pref.custom_base)) return FALSE if(CONFIG_GET(flag/loadout_whitelist) == LOADOUT_WHITELIST_LAX && !is_alien_whitelisted(pref.client, GLOB.all_species[G.whitelisted])) return FALSE diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm index fd1da110d3..aa3013dcb2 100644 --- a/code/modules/client/preference_setup/occupation/occupation.dm +++ b/code/modules/client/preference_setup/occupation/occupation.dm @@ -98,14 +98,14 @@ "denylist_whitelist" = !is_job_whitelisted(user, job.title), // tigercat2000 - these shouldn't exist >:( "denylist_character_age" = FALSE, - "min_age" = job.get_min_age(pref.species, pref.organ_data[O_BRAIN]), + "min_age" = job.get_min_age(pref.read_preference(/datum/preference/choiced/species), pref.read_preference(/datum/preference/organ_data)?[O_BRAIN]), "special_color" = "", "selected" = 0, "selected_title" = "", "alt_titles" = list(), ) - if((job.minimum_character_age || job.min_age_by_species) && user.client && (user.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(user.client.prefs.species, user.client.prefs.organ_data[O_BRAIN]))) + if((job.minimum_character_age || job.min_age_by_species) && user.client && (user.read_preference(/datum/preference/numeric/human/age) < job.get_min_age(user.client.prefs.read_preference(/datum/preference/choiced/species), user.client.prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]))) job_data["denylist_character_age"] = TRUE if((pref.job_civilian_low & ASSISTANT) && job.type != /datum/job/assistant) diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm index 8839988f65..a59d10949a 100644 --- a/code/modules/client/preference_setup/preference_setup.dm +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -233,7 +233,8 @@ // Checks in a really hacky way if a character's preferences say they are an FBP or not. /datum/category_item/player_setup_item/proc/is_FBP() - if(pref.organ_data && pref.organ_data[BP_TORSO] != "cyborg") + var/list/organ_data = pref.read_preference(/datum/preference/organ_data) + if(organ_data && organ_data[BP_TORSO] != "cyborg") return 0 return 1 @@ -241,8 +242,9 @@ /datum/category_item/player_setup_item/proc/get_FBP_type() if(!is_FBP()) return 0 // Not a robot. - if(O_BRAIN in pref.organ_data) - switch(pref.organ_data[O_BRAIN]) + var/list/organ_data = pref.read_preference(/datum/preference/organ_data) + if(organ_data && (O_BRAIN in organ_data)) + switch(organ_data[O_BRAIN]) if(FBP_ASSISTED) return PREF_FBP_CYBORG if(FBP_MECHANICAL) @@ -252,7 +254,8 @@ return 0 //Something went wrong! /datum/category_item/player_setup_item/proc/get_min_age() - var/datum/species/S = GLOB.all_species[pref.species ? pref.species : "Human"] + var/pref_species = pref.read_preference(/datum/preference/choiced/species) || "Human" + var/datum/species/S = GLOB.all_species[pref_species] if(!is_FBP()) return S.min_age // If they're not a robot, we can just use the species var. var/FBP_type = get_FBP_type() @@ -266,7 +269,8 @@ return S.min_age // welp /datum/category_item/player_setup_item/proc/get_max_age() - var/datum/species/S = GLOB.all_species[pref.species ? pref.species : "Human"] + var/pref_species = pref.read_preference(/datum/preference/choiced/species) || "Human" + var/datum/species/S = GLOB.all_species[pref_species] if(!is_FBP()) return S.max_age // If they're not a robot, we can just use the species var. var/FBP_type = get_FBP_type() diff --git a/code/modules/client/preference_setup/preference_setup_vr.dm b/code/modules/client/preference_setup/preference_setup_vr.dm index 2379875910..cd92790e68 100644 --- a/code/modules/client/preference_setup/preference_setup_vr.dm +++ b/code/modules/client/preference_setup/preference_setup_vr.dm @@ -1,7 +1,8 @@ //Minimum limit is 18 /datum/category_item/player_setup_item/get_min_age() var/min_age = 18 - var/datum/species/S = GLOB.all_species[pref.species ? pref.species : "Human"] + var/pref_species = pref.read_preference(/datum/preference/choiced/species) || "Human" + var/datum/species/S = GLOB.all_species[pref_species] if(!is_FBP() && S.min_age > 18) min_age = S.min_age return min_age diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 45f31866ed..77771b5ccc 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -30,7 +30,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/grad_style = "none" //Gradient style var/f_style = "Shaved" //Face hair type var/s_tone = -75 //Skin tone - var/species = SPECIES_HUMAN //Species datum to use. var/species_preview //Used for the species selection window. var/list/alternate_languages = list() //Secondary language(s) var/list/language_prefixes = list() //Language prefix keys @@ -86,8 +85,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) // maps each organ to either null(intact), "cyborg" or "amputated" // will probably not be able to do this for head and torso ;) - var/list/organ_data = list() - var/list/rlimb_data = list() var/list/player_alt_titles = new() // the default name of a job like JOB_MEDICAL_DOCTOR var/list/body_markings = list() // "name" = "#rgbcolor" //VOREStation Edit: "name" = list(BP_HEAD = list("on" = , "color" = "#rgbcolor"), BP_TORSO = ...) @@ -158,7 +155,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) // Didn't load a character, so let's randomize set_biological_gender(pick(MALE, FEMALE)) - update_preference_by_type(/datum/preference/name/real_name, random_name(read_preference(/datum/preference/choiced/gender/identifying), species)) + update_preference_by_type(/datum/preference/name/real_name, random_name(read_preference(/datum/preference/choiced/gender/identifying), read_preference(/datum/preference/choiced/species))) b_type = RANDOM_BLOOD_TYPE if(client) @@ -297,10 +294,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) player_setup.sanitize_setup() // This needs to happen before anything else becuase it sets some variables. - character.set_species(species) + character.set_species(read_preference(/datum/preference/choiced/species)) // Special Case: This references variables owned by two different datums, so do it here. if(read_preference(/datum/preference/toggle/human/name_is_always_random)) - update_preference_by_type(/datum/preference/name/real_name, random_name(read_preference(/datum/preference/choiced/gender/identifying), species)) + update_preference_by_type(/datum/preference/name/real_name, random_name(read_preference(/datum/preference/choiced/gender/identifying), read_preference(/datum/preference/choiced/species))) // Ask the preferences datums to apply their own settings to the new mob player_setup.copy_to_mob(character) @@ -514,6 +511,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) // Destroy/cyborgize organs and limbs. if (convert_to_prosthetics) //should only really be run for proteans + var/list/pref_organ_data = read_preference(/datum/preference/organ_data) + var/list/pref_rlimb_data = read_preference(/datum/preference/rlimb_data) var/list/organs_to_edit = list() for (var/name in list(BP_TORSO, BP_HEAD, BP_GROIN, BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)) var/obj/item/organ/external/O = character.organs_by_name[name] @@ -524,16 +523,16 @@ GLOBAL_LIST_EMPTY(preferences_datums) else organs_to_edit.Insert(x+(O.robotic == ORGAN_NANOFORM ? 1 : 0), name) for(var/name in organs_to_edit) - var/status = organ_data[name] + var/status = pref_organ_data[name] var/obj/item/organ/external/O = character.organs_by_name[name] if(O) if(status == "amputated") continue else if(status == "cyborg") - O.robotize(rlimb_data[name]) + O.robotize(pref_rlimb_data[name]) else var/bodytype - var/datum/species/selected_species = GLOB.all_species[species] + var/datum/species/selected_species = GLOB.all_species[read_preference(/datum/preference/choiced/species)] if(selected_species.selects_bodytype && custom_base) //Everyone technically has custom_base set to HUMAN, but only some species actually select it. bodytype = custom_base else @@ -620,7 +619,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.species?.blood_color = blood_color - var/datum/species/selected_species = GLOB.all_species[species] + var/datum/species/selected_species = GLOB.all_species[read_preference(/datum/preference/choiced/species)] var/bodytype_selected if(selected_species.selects_bodytype && custom_base) bodytype_selected = custom_base diff --git a/code/modules/client/preferences/types/character/gender.dm b/code/modules/client/preferences/types/character/gender.dm index 42d2657335..aefb026c30 100644 --- a/code/modules/client/preferences/types/character/gender.dm +++ b/code/modules/client/preferences/types/character/gender.dm @@ -11,15 +11,17 @@ /// FBP check /datum/preference/choiced/gender/proc/is_fbp(datum/preferences/preferences) - if(!preferences?.organ_data) + var/list/organ_data = preferences?.read_preference(/datum/preference/organ_data) + if(!organ_data) return FALSE - return preferences.organ_data[BP_TORSO] == "cyborg" + return organ_data[BP_TORSO] == "cyborg" /// Get the list of valid bio genders for the species /datum/preference/choiced/gender/proc/get_valid_biological_genders(datum/preferences/preferences) var/datum/species/S - if(preferences?.species) - S = GLOB.all_species[preferences.species] + var/species_name = preferences?.read_preference(/datum/preference/choiced/species) + if(species_name) + S = GLOB.all_species[species_name] if(!S) S = GLOB.all_species[SPECIES_HUMAN] var/list/possible_genders = S.genders diff --git a/code/modules/client/preferences/types/character/names.dm b/code/modules/client/preferences/types/character/names.dm index 5093917849..b3faeb49ed 100644 --- a/code/modules/client/preferences/types/character/names.dm +++ b/code/modules/client/preferences/types/character/names.dm @@ -11,9 +11,10 @@ /// Check if the character is a Full Body Prosthetic (allows numbers in name) /datum/preference/name/proc/is_fbp(datum/preferences/preferences) - if(!preferences?.organ_data) + var/list/organ_data = preferences?.read_preference(/datum/preference/organ_data) + if(!organ_data) return FALSE - return preferences.organ_data[BP_TORSO] == "cyborg" + return organ_data[BP_TORSO] == "cyborg" /datum/preference/name/is_valid(value) if(!istext(value)) @@ -26,8 +27,8 @@ if(!istext(input)) return create_default_value() var/species = default_species - if(preferences?.species) - species = preferences.species + if(preferences) + species = preferences.read_preference(/datum/preference/choiced/species) var/allow_numbers = is_fbp(preferences) var/sanitized = sanitize_name(input, species, allow_numbers) if(!sanitized) @@ -63,7 +64,7 @@ /datum/preference/name/real_name/create_informed_default_value(datum/preferences/preferences) var/gender = preferences?.read_preference(/datum/preference/choiced/gender/identifying) || MALE - var/species = preferences?.species || SPECIES_HUMAN + var/species = preferences?.read_preference(/datum/preference/choiced/species) || SPECIES_HUMAN return random_name(gender, species) /datum/preference/name/real_name/create_random_value(datum/preferences/preferences, datum/species/current_species) diff --git a/code/modules/client/preferences/types/character/organ_data.dm b/code/modules/client/preferences/types/character/organ_data.dm new file mode 100644 index 0000000000..7654bb10e9 --- /dev/null +++ b/code/modules/client/preferences/types/character/organ_data.dm @@ -0,0 +1,38 @@ +// Organ data preference for character creation +// Stores an assoc list mapping organ tags to their prosthetic/modified status. +// Values can be: null (normal), "cyborg", "amputated", FBP_ASSISTED, FBP_MECHANICAL, or FBP_DIGITAL. + +/datum/preference/organ_data + savefile_key = "organ_data" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + can_randomize = FALSE + +/datum/preference/organ_data/create_default_value() + return list() + +/datum/preference/organ_data/pref_deserialize(input, datum/preferences/preferences) + if(!islist(input)) + return list() + // Return the list directly (same reference) so in-place mutations update the cache. + return input + +/datum/preference/organ_data/pref_serialize(input) + if(!islist(input)) + return list() + return check_list_copy(input) + +/datum/preference/organ_data/is_valid(value) + return islist(value) + +/datum/preference/organ_data/apply_to_human(mob/living/carbon/human/target, value) + return // Organ application is handled by copy_to_mob in 03_body.dm + +/datum/preference/organ_data/apply_to_living(mob/living/target, value) + return + +/datum/preference/organ_data/apply_to_silicon(mob/living/silicon/target, value) + return + +/datum/preference/organ_data/apply_to_animal(mob/living/simple_mob/target, value) + return diff --git a/code/modules/client/preferences/types/character/rlimb_data.dm b/code/modules/client/preferences/types/character/rlimb_data.dm new file mode 100644 index 0000000000..9713c31eda --- /dev/null +++ b/code/modules/client/preferences/types/character/rlimb_data.dm @@ -0,0 +1,42 @@ +// Robolimb data preference for character creation +// Stores an assoc list mapping organ tags to robolimb manufacturer model names. +// Values are strings corresponding to keys in GLOB.all_robolimbs. + +/datum/preference/rlimb_data + savefile_key = "rlimb_data" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + can_randomize = FALSE + +/datum/preference/rlimb_data/create_default_value() + return list() + +/datum/preference/rlimb_data/pref_deserialize(input, datum/preferences/preferences) + if(!islist(input)) + return list() + // Sanitize: remove entries with invalid robolimb keys + for(var/limb in input) + var/key = input[limb] + if(!istext(key) || !LAZYACCESS(GLOB.all_robolimbs, key)) + input -= limb + return input + +/datum/preference/rlimb_data/pref_serialize(input) + if(!islist(input)) + return list() + return check_list_copy(input) + +/datum/preference/rlimb_data/is_valid(value) + return islist(value) + +/datum/preference/rlimb_data/apply_to_human(mob/living/carbon/human/target, value) + return // Robolimb application is handled by copy_to_mob in 03_body.dm + +/datum/preference/rlimb_data/apply_to_living(mob/living/target, value) + return + +/datum/preference/rlimb_data/apply_to_silicon(mob/living/silicon/target, value) + return + +/datum/preference/rlimb_data/apply_to_animal(mob/living/simple_mob/target, value) + return diff --git a/code/modules/client/preferences/types/character/species.dm b/code/modules/client/preferences/types/character/species.dm new file mode 100644 index 0000000000..b640e0258d --- /dev/null +++ b/code/modules/client/preferences/types/character/species.dm @@ -0,0 +1,38 @@ +// Species preference for character creation +// Handles the player's selected species, validated against GLOB.playable_species. + +/datum/preference/choiced/species + savefile_key = "species" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + can_randomize = FALSE + priority = PREFERENCE_PRIORITY_SPECIES + +/datum/preference/choiced/species/init_possible_values() + // GLOB.playable_species is populated at world init and contains all joinable species names. + return GLOB.playable_species + +/datum/preference/choiced/species/create_default_value() + return SPECIES_HUMAN + +/datum/preference/choiced/species/pref_deserialize(input, datum/preferences/preferences) + if(!input || !istext(input) || !(input in GLOB.playable_species)) + return SPECIES_HUMAN + return input + +/datum/preference/choiced/species/is_valid(value) + if(!istext(value)) + return FALSE + return value in GLOB.playable_species + +/datum/preference/choiced/species/apply_to_human(mob/living/carbon/human/target, value) + return // Species application is handled by copy_to via character.set_species() + +/datum/preference/choiced/species/apply_to_living(mob/living/target, value) + return + +/datum/preference/choiced/species/apply_to_silicon(mob/living/silicon/target, value) + return + +/datum/preference/choiced/species/apply_to_animal(mob/living/simple_mob/target, value) + return diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index f22d25ee15..a1c3eddd25 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -381,8 +381,9 @@ var/use_species_name var/datum/species/chosen_species - if(client.prefs.species) - chosen_species = GLOB.all_species[client.prefs.species] + var/pref_species = client.prefs.read_preference(/datum/preference/choiced/species) + if(pref_species) + chosen_species = GLOB.all_species[pref_species] use_species_name = chosen_species.get_station_variant() //Only used by pariahs atm. if(chosen_species && use_species_name) @@ -464,8 +465,9 @@ /mob/new_player/get_species() var/datum/species/chosen_species - if(client.prefs.species) - chosen_species = GLOB.all_species[client.prefs.species] + var/pref_species = client.prefs.read_preference(/datum/preference/choiced/species) + if(pref_species) + chosen_species = GLOB.all_species[pref_species] if(!chosen_species) return SPECIES_HUMAN diff --git a/code/modules/mob/new_player/new_player_vr.dm b/code/modules/mob/new_player/new_player_vr.dm index 594a108a70..55dc2a7a3d 100644 --- a/code/modules/mob/new_player/new_player_vr.dm +++ b/code/modules/mob/new_player/new_player_vr.dm @@ -27,12 +27,12 @@ to_chat(src,span_warning("You have not set your scale yet. Do this on the VORE tab in character setup.")) //Can they play? - if(!is_alien_whitelisted(src.client,GLOB.all_species[client?.prefs?.species]) && !check_rights(R_ADMIN, 0)) + if(!is_alien_whitelisted(src.client,GLOB.all_species[client?.prefs?.read_preference(/datum/preference/choiced/species)]) && !check_rights(R_ADMIN, 0)) pass = FALSE to_chat(src,span_warning("You are not allowed to spawn in as this species.")) //Custom species checks - if (client?.prefs?.species == "Custom Species") + if (client?.prefs?.read_preference(/datum/preference/choiced/species) == SPECIES_CUSTOM) //Didn't name it if(!client?.prefs?.custom_species) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index c79f477bfe..a7888bb798 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -276,11 +276,12 @@ /datum/preferences/proc/get_valid_hairstyles(mob/user) var/list/valid_hairstyles = list() + var/pref_species = read_preference(/datum/preference/choiced/species) for(var/hairstyle in GLOB.hair_styles_list) var/datum/sprite_accessory/S = GLOB.hair_styles_list[hairstyle] if(S.name == DEVELOPER_WARNING_NAME) continue - if(!(species in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) + if(!(pref_species in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) continue if(!S.can_be_selected && (!client || !check_rights_for(client, R_HOLDER))) continue @@ -293,6 +294,7 @@ /datum/preferences/proc/get_valid_facialhairstyles() var/list/valid_facialhairstyles = list() var/bio_gender = read_preference(/datum/preference/choiced/gender/biological) + var/pref_species = read_preference(/datum/preference/choiced/species) for(var/facialhairstyle in GLOB.facial_hair_styles_list) var/datum/sprite_accessory/S = GLOB.facial_hair_styles_list[facialhairstyle] if(S.name == DEVELOPER_WARNING_NAME) @@ -301,7 +303,7 @@ continue if(bio_gender == FEMALE && S.gender == MALE) continue - if(!(species in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) + if(!(pref_species in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) continue if(!S.can_be_selected && (!client || !check_rights_for(client, R_HOLDER))) continue diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index d87bdd1d7c..805edc122d 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -332,7 +332,8 @@ if(owner) handle_organ_mod_special() if(!ignore_prosthetic_prefs && owner && owner.client && owner.client.prefs && owner.client.prefs.read_preference(/datum/preference/name/real_name) == owner.real_name) - var/status = owner.client.prefs.organ_data[organ_tag] + var/list/organ_data = owner.client.prefs.read_preference(/datum/preference/organ_data) + var/status = organ_data?[organ_tag] if(status == FBP_ASSISTED) mechassist() else if(status == FBP_MECHANICAL) diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index ff2b698500..ca33066b5b 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -666,11 +666,13 @@ This function completely restores a damaged organ to perfect condition. if(owner && !ignore_prosthetic_prefs) if(owner.client && owner.client.prefs && owner.client.prefs.read_preference(/datum/preference/name/real_name) == owner.real_name) - var/status = owner.client.prefs.organ_data[organ_tag] + var/list/organ_data = owner.client.prefs.read_preference(/datum/preference/organ_data) + var/status = organ_data?[organ_tag] if(status == "amputated") remove_rejuv() else if(status == "cyborg") - var/robodata = owner.client.prefs.rlimb_data[organ_tag] + var/list/rlimb_data = owner.client.prefs.read_preference(/datum/preference/rlimb_data) + var/robodata = rlimb_data?[organ_tag] if(robodata) robotize(robodata) else diff --git a/code/modules/resleeving/autoresleever.dm b/code/modules/resleeving/autoresleever.dm index f67f121133..f9c2c23084 100644 --- a/code/modules/resleeving/autoresleever.dm +++ b/code/modules/resleeving/autoresleever.dm @@ -85,14 +85,15 @@ GLOBAL_LIST_EMPTY(active_autoresleevers) var/client/ghost_client = ghost.client - if(!is_alien_whitelisted(ghost.client, GLOB.all_species[ghost_client?.prefs?.species]) && !check_rights(R_ADMIN, 0)) // Prevents a ghost ghosting in on a slot and spawning via a resleever with race they're not whitelisted for, getting around normal join restrictions. + if(!is_alien_whitelisted(ghost.client, GLOB.all_species[ghost_client?.prefs?.read_preference(/datum/preference/choiced/species)]) && !check_rights(R_ADMIN, 0)) // Prevents a ghost ghosting in on a slot and spawning via a resleever with race they're not whitelisted for, getting around normal join restrictions. to_chat(ghost, span_warning("You are not whitelisted to spawn as this species!")) return /* // Comments out NO_SLEEVE restriction, as per headmin/maintainer request. var/datum/species/chosen_species - if(ghost.client.prefs.species) // In case we somehow don't have a species set here. - chosen_species = GLOB.all_species[ghost_client.prefs.species] + var/pref_species = ghost.client.prefs.read_preference(/datum/preference/choiced/species) + if(pref_species) // In case we somehow don't have a species set here. + chosen_species = GLOB.all_species[pref_species] if(chosen_species.flags & NO_SLEEVE) // Sanity. Prevents species like Xenochimera, Proteans, etc from rejoining the round via resleeve, as they should have their own methods of doing so already, as agreed to when you whitelist as them. to_chat(ghost, span_warning("This species cannot be resleeved!")) diff --git a/code/modules/tgui/modules/late_choices.dm b/code/modules/tgui/modules/late_choices.dm index 20de36e48f..a3d2c8194a 100644 --- a/code/modules/tgui/modules/late_choices.dm +++ b/code/modules/tgui/modules/late_choices.dm @@ -49,7 +49,7 @@ if(!job.minimum_character_age && !job.min_age_by_species) return TRUE - var/min_age = job.get_min_age(prefs.species, prefs.organ_data[O_BRAIN]) + var/min_age = job.get_min_age(prefs.read_preference(/datum/preference/choiced/species), prefs.read_preference(/datum/preference/organ_data)?[O_BRAIN]) if(prefs.read_preference(/datum/preference/numeric/human/age) >= min_age) return TRUE return FALSE @@ -125,13 +125,14 @@ to_chat(new_user, span_danger("The station is currently exploding. Joining would go poorly.")) return - var/datum/species/S = GLOB.all_species[new_user.client.prefs.species] + var/pref_species = new_user.client.prefs.read_preference(/datum/preference/choiced/species) + var/datum/species/S = GLOB.all_species[pref_species] if(!is_alien_whitelisted(new_user.client, S)) - tgui_alert(new_user, "You are currently not whitelisted to play [new_user.client.prefs.species].") + tgui_alert(new_user, "You are currently not whitelisted to play [pref_species].") return 0 if(!(S.spawn_flags & SPECIES_CAN_JOIN)) - tgui_alert_async(new_user,"Your current species, [new_user.client.prefs.species], is not available for play on the station.") + tgui_alert_async(new_user,"Your current species, [pref_species], is not available for play on the station.") return 0 new_user.AttemptLateSpawn(job) diff --git a/code/modules/vore/eating/inbelly_spawn.dm b/code/modules/vore/eating/inbelly_spawn.dm index 4e5151e424..ce8af1c702 100644 --- a/code/modules/vore/eating/inbelly_spawn.dm +++ b/code/modules/vore/eating/inbelly_spawn.dm @@ -55,7 +55,7 @@ if(confirmation_prey == "Yes" && potential_prey && src && belly_choice) //Now we finally spawn them in! - if(!is_alien_whitelisted(potential_prey, GLOB.all_species[potential_prey.prefs.species])) + if(!is_alien_whitelisted(potential_prey, GLOB.all_species[potential_prey.prefs.read_preference(/datum/preference/choiced/species)])) to_chat(potential_prey, span_notice("You are not whitelisted to play as currently selected character.")) to_chat(src, span_notice("Prey accepted the confirmation, but something went wrong with spawning their character.")) return diff --git a/code/modules/vore/persist/persist_vr.dm b/code/modules/vore/persist/persist_vr.dm index 7914955ca6..eefed33acc 100644 --- a/code/modules/vore/persist/persist_vr.dm +++ b/code/modules/vore/persist/persist_vr.dm @@ -163,35 +163,39 @@ // This basically needs to be the reverse of /datum/category_item/player_setup_item/general/body/copy_to_mob() ~Leshana /proc/apply_organs_to_prefs(var/mob/living/carbon/human/character, var/datum/preferences/prefs) if(!istype(character) || !character.species) return + var/list/organ_data = prefs.read_preference(/datum/preference/organ_data) || list() + var/list/rlimb_data = prefs.read_preference(/datum/preference/rlimb_data) || list() // Checkify the limbs! for(var/name in character.species.has_limbs) - var/obj/item/organ/external/O = character.organs_by_name[name] - if(!O) + var/obj/item/organ/external/external_organ = character.organs_by_name[name] + if(!external_organ) if(name in GLOB.storable_amputated_organs) - prefs.organ_data[name] = "amputated" + organ_data[name] = "amputated" else - prefs.rlimb_data.Remove(name) // Missing limb and not in the global list means default model - else if(O.robotic >= ORGAN_ROBOT) - prefs.organ_data[name] = "cyborg" - if(O.model) - prefs.rlimb_data[name] = O.model + rlimb_data.Remove(name) // Missing limb and not in the global list means default model + else if(external_organ.robotic >= ORGAN_ROBOT) + organ_data[name] = "cyborg" + if(external_organ.model) + rlimb_data[name] = external_organ.model else - prefs.rlimb_data.Remove(name) // Missing rlimb_data entry means default model + rlimb_data.Remove(name) // Missing rlimb_data entry means default model else - prefs.organ_data.Remove(name) // Misisng organ_data entry means normal + organ_data.Remove(name) // Misisng organ_data entry means normal // Internal organs also for(var/name in character.species.has_organ) - var/obj/item/organ/I = character.internal_organs_by_name[name] - if(I) - if(istype(I, /obj/item/organ/internal/mmi_holder/robot)) - prefs.organ_data[name] = FBP_DIGITAL // Need a better way to detect this special type - else if(I.robotic == ORGAN_ASSISTED) - prefs.organ_data[name] = FBP_ASSISTED - else if(I.robotic >= ORGAN_ROBOT) - prefs.organ_data[name] = FBP_MECHANICAL + var/obj/item/organ/internal_organ = character.internal_organs_by_name[name] + if(internal_organ) + if(istype(internal_organ, /obj/item/organ/internal/mmi_holder/robot)) + organ_data[name] = FBP_DIGITAL // Need a better way to detect this special type + else if(internal_organ.robotic == ORGAN_ASSISTED) + organ_data[name] = FBP_ASSISTED + else if(internal_organ.robotic >= ORGAN_ROBOT) + organ_data[name] = FBP_MECHANICAL else - prefs.organ_data.Remove(name) // Missing organ_data entry means normal + organ_data.Remove(name) // Missing organ_data entry means normal + prefs.write_preference(GLOB.preference_entries[/datum/preference/organ_data], organ_data) + prefs.write_preference(GLOB.preference_entries[/datum/preference/rlimb_data], rlimb_data) // Saves mob's current body markings state to prefs. // This basically needs to be the reverse of /datum/category_item/player_setup_item/general/body/copy_to_mob() ~Leshana diff --git a/vorestation.dme b/vorestation.dme index d6ca415e47..8fccd75aa0 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2478,6 +2478,9 @@ #include "code\modules\client\preferences\migrations\19_paifile.dm" #include "code\modules\client\preferences\types\character\gender.dm" #include "code\modules\client\preferences\types\character\names.dm" +#include "code\modules\client\preferences\types\character\organ_data.dm" +#include "code\modules\client\preferences\types\character\rlimb_data.dm" +#include "code\modules\client\preferences\types\character\species.dm" #include "code\modules\client\preferences\types\character\antagonism\01_basic.dm" #include "code\modules\client\preferences\types\character\general\01_basic.dm" #include "code\modules\client\preferences\types\character\general\03_body.dm"