diff --git a/code/datums/category.dm b/code/datums/category.dm new file mode 100644 index 0000000000..01cbc21386 --- /dev/null +++ b/code/datums/category.dm @@ -0,0 +1,75 @@ +/********************** +* Category Collection * +**********************/ +/datum/category_collection + var/category_group_type // The type of categories to initialize + var/list/datum/category_group/categories // The list of initialized categories + +/datum/category_collection/New() + ..() + categories = new() + for(var/category_type in typesof(category_group_type)) + var/datum/category_group/category = category_type + if(initial(category.name)) + category = new category(src) + categories += category + categories = dd_sortedObjectList(categories) + +/datum/category_collection/Destroy() + for(var/category in categories) + qdel(category) + categories.Cut() + return ..() + +/****************** +* Category Groups * +******************/ +/datum/category_group + var/name = "" + var/category_item_type // The type of items to initialize + var/list/datum/category_item/items // The list of initialized items + var/datum/category_collection/collection // The collection this group belongs to + +/datum/category_group/New(var/datum/category_collection/cc) + ..() + collection = cc + items = new() + + for(var/item_type in typesof(category_item_type)) + var/datum/category_item/item = item_type + if(initial(item.name)) + item = new item(src) + items += item + + // For whatever reason dd_insertObjectList(items, item) doesn't insert in the correct order + // If you change this, confirm that character setup doesn't become completely unordered. + items = dd_sortedObjectList(items) + +/datum/category_group/Destroy() + for(var/item in items) + qdel(item) + items.Cut() + collection = null + return ..() + +datum/category_group/dd_SortValue() + return name + + +/***************** +* Category Items * +*****************/ +/datum/category_item + var/name = "" + var/list/datum/category_group/category // The group this item belongs to + +/datum/category_item/New(var/datum/category_group/cg) + ..() + category = cg + +/datum/category_item/Destroy() + category = null + return ..() + +datum/category_item/dd_SortValue() + return name diff --git a/code/modules/client/preference_setup/antagonism/01_basic.dm b/code/modules/client/preference_setup/antagonism/01_basic.dm new file mode 100644 index 0000000000..eefc531da1 --- /dev/null +++ b/code/modules/client/preference_setup/antagonism/01_basic.dm @@ -0,0 +1,38 @@ +var/global/list/uplink_locations = list("PDA", "Headset", "None") + +/datum/category_item/player_setup_item/antagonism/basic + 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 + +/datum/category_item/player_setup_item/antagonism/basic/save_character(var/savefile/S) + S["uplinklocation"] << pref.uplinklocation + S["exploit_record"] << pref.exploit_record + +/datum/category_item/player_setup_item/antagonism/basic/sanitize_character() + pref.uplinklocation = sanitize_inlist(pref.uplinklocation, uplink_locations, initial(pref.uplinklocation)) + +/datum/category_item/player_setup_item/antagonism/basic/content(var/mob/user) + . +="Uplink Type : [pref.uplinklocation]" + . +="
" + . +="Exploitable information:
" + if(jobban_isbanned(user, "Records")) + . += "You are banned from using character records.
" + else + . +="[TextPreview(pref.exploit_record,40)]
" + +/datum/category_item/player_setup_item/antagonism/basic/OnTopic(var/href,var/list/href_list, var/mob/user) + if (href_list["antagtask"]) + pref.uplinklocation = next_in_list(pref.uplinklocation, uplink_locations) + return TOPIC_REFRESH + + if(href_list["exploitable_record"]) + var/exploitmsg = sanitize(input(user,"Set exploitable information about you here.","Exploitable Information", html_decode(pref.exploit_record)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(!isnull(exploitmsg) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) + pref.exploit_record = exploitmsg + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/antagonism/02_candidacy.dm b/code/modules/client/preference_setup/antagonism/02_candidacy.dm new file mode 100644 index 0000000000..82d44027af --- /dev/null +++ b/code/modules/client/preference_setup/antagonism/02_candidacy.dm @@ -0,0 +1,54 @@ +var/global/list/special_roles = list( //keep synced with the defines BE_* in setup.dm --rastaf +//some autodetection here. +// TODO: Update to new antagonist system. + "traitor" = IS_MODE_COMPILED("traitor"), // 0 + "operative" = IS_MODE_COMPILED("nuclear"), // 1 + "changeling" = IS_MODE_COMPILED("changeling"), // 2 + "wizard" = IS_MODE_COMPILED("wizard"), // 3 + "malf AI" = IS_MODE_COMPILED("malfunction"), // 4 + "revolutionary" = IS_MODE_COMPILED("revolution"), // 5 + "alien candidate" = 1, //always show // 6 + "positronic brain" = 1, // 7 + "cultist" = IS_MODE_COMPILED("cult"), // 8 + "infested monkey" = IS_MODE_COMPILED("monkey"), // 9 + "ninja" = "true", // 10 + "raider" = IS_MODE_COMPILED("heist"), // 11 + "diona" = 1, // 12 + "loyalist" = IS_MODE_COMPILED("revolution"), // 13 + "pAI candidate" = 1, // -- TLE // 14 +) + +/datum/category_item/player_setup_item/antagonism/candidacy + 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/save_character(var/savefile/S) + S["be_special"] << pref.be_special + +/datum/category_item/player_setup_item/antagonism/candidacy/sanitize_character() + pref.be_special = sanitize_integer(pref.be_special, 0, 65535, initial(pref.be_special)) + +/datum/category_item/player_setup_item/antagonism/candidacy/content(var/mob/user) + if(jobban_isbanned(user, "Syndicate")) + . += "You are banned from antagonist roles." + pref.be_special = 0 + else + var/n = 0 + for (var/i in special_roles) + if(special_roles[i]) //if mode is available on the server + if(jobban_isbanned(user, i) || (i == "positronic brain" && jobban_isbanned(user, "AI") && jobban_isbanned(user, "Cyborg")) || (i == "pAI candidate" && jobban_isbanned(user, "pAI"))) + . += "Be [i]: \[BANNED]
" + else + . += "Be [i]: [pref.be_special&(1<
" + n++ + +/datum/category_item/player_setup_item/antagonism/candidacy/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["be_special"]) + var/num = text2num(href_list["be_special"]) + pref.be_special ^= (1<> pref.real_name + S["name_is_always_random"] >> pref.be_random_name + S["gender"] >> pref.gender + S["age"] >> pref.age + S["spawnpoint"] >> pref.spawnpoint + S["OOC_Notes"] >> pref.metadata + +/datum/category_item/player_setup_item/general/basic/save_character(var/savefile/S) + S["real_name"] << pref.real_name + S["name_is_always_random"] << pref.be_random_name + S["gender"] << pref.gender + S["age"] << pref.age + S["spawnpoint"] << pref.spawnpoint + S["OOC_Notes"] << pref.metadata + +/datum/category_item/player_setup_item/general/basic/sanitize_character() + pref.real_name = sanitizeName(pref.real_name) + if(!pref.real_name) + pref.real_name = random_name(pref.gender, pref.species) + pref.spawnpoint = sanitize_inlist(pref.spawnpoint, spawntypes, initial(pref.spawnpoint)) + pref.be_random_name = sanitize_integer(pref.be_random_name, 0, 1, initial(pref.be_random_name)) + pref.age = sanitize_integer(pref.age, AGE_MIN, AGE_MAX, initial(pref.age)) + +/datum/category_item/player_setup_item/general/basic/content() + . = "Name: " + . += "[pref.real_name]
" + . += "(Random Name) " + . += "(Always Random Name: [pref.be_random_name ? "Yes" : "No"])" + . += "
" + . += "Gender: [pref.gender == MALE ? "Male" : "Female"]
" + . += "Age: [pref.age]
" + . += "Spawn Point: [pref.spawnpoint]
" + if(config.allow_Metadata) + . += "OOC Notes: Edit
" + +/datum/category_item/player_setup_item/general/basic/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["rename"]) + var/raw_name = input(user, "Choose your character's name:", "Character Name") as text|null + if (!isnull(raw_name) && CanUseTopic(user)) + var/new_name = sanitizeName(raw_name) + if(new_name) + pref.real_name = new_name + return TOPIC_REFRESH + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + return TOPIC_NOACTION + + else if(href_list["random_name"]) + pref.real_name = random_name(pref.gender, pref.species) + return TOPIC_REFRESH + + else if(href_list["always_random_name"]) + pref.be_random_name = !pref.be_random_name + return TOPIC_REFRESH + + else if(href_list["gender"]) + if(pref.gender == MALE) + pref.gender = FEMALE + else + pref.gender = MALE + return TOPIC_REFRESH + + else if(href_list["age"]) + var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference", pref.age) as num|null + if(new_age && CanUseTopic(user)) + pref.age = max(min(round(text2num(new_age)), AGE_MAX), AGE_MIN) + return TOPIC_REFRESH + + else if(href_list["spawnpoint"]) + var/list/spawnkeys = list() + for(var/S in spawntypes) + spawnkeys += S + var/choice = input(user, "Where would you like to spawn when late-joining?") as null|anything in spawnkeys + if(!choice || !spawntypes[choice] || !CanUseTopic(user)) return TOPIC_NOACTION + pref.spawnpoint = choice + return TOPIC_REFRESH + + + else if(href_list["metadata"]) + var/new_metadata = sanitize(input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , pref.metadata)) as message|null + if(new_metadata && CanUseTopic(user)) + pref.metadata = sanitize(new_metadata) + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm new file mode 100644 index 0000000000..7e9a803766 --- /dev/null +++ b/code/modules/client/preference_setup/general/02_language.dm @@ -0,0 +1,93 @@ +/datum/category_item/player_setup_item/general/language + name = "Language" + sort_order = 2 + +/datum/category_item/player_setup_item/general/language/load_character(var/savefile/S) + S["language"] >> pref.alternate_languages + S["language_prefixes"] >> pref.language_prefixes + +/datum/category_item/player_setup_item/general/language/save_character(var/savefile/S) + S["language"] << pref.alternate_languages + S["language_prefixes"] << pref.language_prefixes + +/datum/category_item/player_setup_item/general/language/sanitize_character() + if(!islist(pref.alternate_languages)) pref.alternate_languages = list() + if(isnull(pref.language_prefixes) || !pref.language_prefixes.len) + pref.language_prefixes = config.language_prefixes.Copy() + +/datum/category_item/player_setup_item/general/language/content() + . += "Languages
" + var/datum/species/S = all_species[pref.species] + if(S.language) + . += "- [S.language]
" + if(S.default_language && S.default_language != S.language) + . += "- [S.default_language]
" + if(S.num_alternate_languages) + if(pref.alternate_languages.len) + for(var/i = 1 to pref.alternate_languages.len) + var/lang = pref.alternate_languages[i] + . += "- [lang] - remove
" + + if(pref.alternate_languages.len < S.num_alternate_languages) + . += "- add ([S.num_alternate_languages - pref.alternate_languages.len] remaining)
" + else + . += "- [pref.species] cannot choose secondary languages.
" + + . += "Language Keys
" + . += " [english_list(pref.language_prefixes, and_text = " ", comma_text = " ")] Change Reset
" + +/datum/category_item/player_setup_item/general/language/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["remove_language"]) + var/index = text2num(href_list["remove_language"]) + pref.alternate_languages.Cut(index, index+1) + return TOPIC_REFRESH + else if(href_list["add_language"]) + var/datum/species/S = all_species[pref.species] + if(pref.alternate_languages.len >= S.num_alternate_languages) + alert(user, "You have already selected the maximum number of alternate languages for this species!") + else + var/list/available_languages = S.secondary_langs.Copy() + for(var/L in all_languages) + var/datum/language/lang = all_languages[L] + if(!(lang.flags & RESTRICTED) && (!config.usealienwhitelist || is_alien_whitelisted(user, L) || !(lang.flags & WHITELISTED))) + available_languages |= L + + // make sure we don't let them waste slots on the default languages + available_languages -= S.language + available_languages -= S.default_language + available_languages -= pref.alternate_languages + + if(!available_languages.len) + alert(user, "There are no additional languages available to select.") + else + var/new_lang = input(user, "Select an additional language", "Character Generation", null) as null|anything in available_languages + if(new_lang) + pref.alternate_languages |= new_lang + return TOPIC_REFRESH + + else if(href_list["change_prefix"]) + var/char + var/keys[0] + do + char = input("Enter a single special character.\nYou may re-select the same characters.\nThe following characters are already in use by radio: ; : .\nThe following characters are already in use by special say commands: ! * ^", "Enter Character - [3 - keys.len] remaining") as null|text + if(char) + if(length(char) > 1) + alert(user, "Only single characters allowed.", "Error", "Ok") + else if(char in list(";", ":", ".")) + alert(user, "Radio character. Rejected.", "Error", "Ok") + else if(char in list("!","*", "^")) + alert(user, "Say character. Rejected.", "Error", "Ok") + else if(contains_az09(char)) + alert(user, "Non-special character. Rejected.", "Error", "Ok") + else + keys.Add(char) + while(char && keys.len < 3) + + if(keys.len == 3) + pref.language_prefixes = keys + return TOPIC_REFRESH + else if(href_list["reset_prefix"]) + pref.language_prefixes = config.language_prefixes.Copy() + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm new file mode 100644 index 0000000000..07530881fe --- /dev/null +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -0,0 +1,498 @@ +var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-") + +/datum/category_item/player_setup_item/general/body + 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["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["facial_style_name"] >> pref.f_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 + +/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["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["facial_style_name"] << pref.f_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 + +/datum/category_item/player_setup_item/general/body/sanitize_character(var/savefile/S) + if(!pref.species || !(pref.species in playable_species)) + pref.species = "Human" + pref.r_hair = sanitize_integer(pref.r_hair, 0, 255, initial(pref.r_hair)) + pref.g_hair = sanitize_integer(pref.g_hair, 0, 255, initial(pref.g_hair)) + pref.b_hair = sanitize_integer(pref.b_hair, 0, 255, initial(pref.b_hair)) + pref.r_facial = sanitize_integer(pref.r_facial, 0, 255, initial(pref.r_facial)) + pref.g_facial = sanitize_integer(pref.g_facial, 0, 255, initial(pref.g_facial)) + pref.b_facial = sanitize_integer(pref.b_facial, 0, 255, initial(pref.b_facial)) + pref.s_tone = sanitize_integer(pref.s_tone, -185, 34, initial(pref.s_tone)) + pref.r_skin = sanitize_integer(pref.r_skin, 0, 255, initial(pref.r_skin)) + pref.g_skin = sanitize_integer(pref.g_skin, 0, 255, initial(pref.g_skin)) + pref.b_skin = sanitize_integer(pref.b_skin, 0, 255, initial(pref.b_skin)) + pref.h_style = sanitize_inlist(pref.h_style, hair_styles_list, initial(pref.h_style)) + pref.f_style = sanitize_inlist(pref.f_style, facial_hair_styles_list, initial(pref.f_style)) + pref.r_eyes = sanitize_integer(pref.r_eyes, 0, 255, initial(pref.r_eyes)) + pref.g_eyes = sanitize_integer(pref.g_eyes, 0, 255, initial(pref.g_eyes)) + pref.b_eyes = sanitize_integer(pref.b_eyes, 0, 255, initial(pref.b_eyes)) + pref.b_type = sanitize_text(pref.b_type, initial(pref.b_type)) + + pref.disabilities = sanitize_integer(pref.disabilities, 0, 65535, initial(pref.disabilities)) + if(!pref.organ_data) pref.organ_data = list() + if(!pref.rlimb_data) pref.rlimb_data = list() + +/datum/category_item/player_setup_item/general/body/content(var/mob/user) + pref.update_preview_icon() + if(pref.preview_icon_front && pref.preview_icon_side) + user << browse_rsc(pref.preview_icon_front, "previewicon.png") + user << browse_rsc(pref.preview_icon_side, "previewicon2.png") + + var/mob_species = all_species[pref.species] + . += "
Body " + . += "(®)" + . += "
" + . += "Species: [pref.species]
" + . += "Blood Type: [pref.b_type]
" + if(has_flag(mob_species, HAS_SKIN_TONE)) + . += "Skin Tone: [-pref.s_tone + 35]/220
" + . += "Needs Glasses: [pref.disabilities & NEARSIGHTED ? "Yes" : "No"]
" + . += "Limbs: Adjust
" + . += "Internal Organs: Adjust
" + + //display limbs below + var/ind = 0 + for(var/name in pref.organ_data) + var/status = pref.organ_data[name] + var/organ_name = null + switch(name) + if("l_arm") + organ_name = "left arm" + if("r_arm") + organ_name = "right arm" + if("l_leg") + organ_name = "left leg" + if("r_leg") + organ_name = "right leg" + if("l_foot") + organ_name = "left foot" + if("r_foot") + organ_name = "right foot" + if("l_hand") + organ_name = "left hand" + if("r_hand") + organ_name = "right hand" + if("heart") + organ_name = "heart" + if("eyes") + organ_name = "eyes" + + if(status == "cyborg") + ++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]] + else + R = basic_robolimb + . += "\t[R.company] [organ_name] prothesis" + else if(status == "amputated") + ++ind + if(ind > 1) + . += ", " + . += "\tAmputated [organ_name]" + else if(status == "mechanical") + ++ind + if(ind > 1) + . += ", " + . += "\tMechanical [organ_name]" + else if(status == "assisted") + ++ind + if(ind > 1) + . += ", " + switch(organ_name) + if("heart") + . += "\tPacemaker-assisted [organ_name]" + if("voicebox") //on adding voiceboxes for speaking skrell/similar replacements + . += "\tSurgically altered [organ_name]" + if("eyes") + . += "\tRetinal overlayed [organ_name]" + else + . += "\tMechanically assisted [organ_name]" + if(!ind) + . += "\[...\]

" + else + . += "

" + + . += "
Preview
" + . += "
" + + . += "Hair
" + if(has_flag(mob_species, HAS_HAIR_COLOR)) + . += "Change Color
__
" + . += " Style: [pref.h_style]
" + + . += "
Facial
" + if(has_flag(mob_species, HAS_HAIR_COLOR)) + . += "Change Color
__
" + . += " Style: [pref.f_style]
" + + if(has_flag(mob_species, HAS_EYE_COLOR)) + . += "
Eyes
" + . += "Change Color
__

" + + if(has_flag(mob_species, HAS_SKIN_COLOR)) + . += "
Body Color
" + . += "Change Color
__

" + +/datum/category_item/player_setup_item/general/body/proc/has_flag(var/datum/species/mob_species, var/flag) + return mob_species && (mob_species.appearance_flags & flag) + +/datum/category_item/player_setup_item/general/body/OnTopic(var/href,var/list/href_list, var/mob/user) + var/mob_species = all_species[pref.species] + + if(href_list["random"]) + pref.randomize_appearance_for() + return TOPIC_REFRESH + + else if(href_list["blood_type"]) + var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in valid_bloodtypes + if(new_b_type && CanUseTopic(user)) + pref.b_type = new_b_type + return TOPIC_REFRESH + + else if(href_list["show_species"]) + // Actual whitelist checks are handled elsewhere, this is just for accessing the preview window. + var/choice = input("Which species would you like to look at?") as null|anything in playable_species + if(!choice) return + pref.species_preview = choice + SetSpecies(preference_mob()) + pref.alternate_languages.Cut() // Reset their alternate languages. Todo: attempt to just fix it instead? + return TOPIC_HANDLED + + else if(href_list["set_species"]) + user << browse(null, "window=species") + if(!pref.species_preview || !(pref.species_preview in all_species)) + return TOPIC_NOACTION + + var/prev_species = pref.species + pref.species = href_list["set_species"] + if(prev_species != pref.species) + //grab one of the valid hair styles for the newly chosen species + var/list/valid_hairstyles = list() + for(var/hairstyle in hair_styles_list) + var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + if(pref.gender == MALE && S.gender == FEMALE) + continue + if(pref.gender == FEMALE && S.gender == MALE) + continue + if(!(pref.species in S.species_allowed)) + continue + valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] + + if(valid_hairstyles.len) + pref.h_style = pick(valid_hairstyles) + else + //this shouldn't happen + pref.h_style = hair_styles_list["Bald"] + + //grab one of the valid facial hair styles for the newly chosen species + var/list/valid_facialhairstyles = list() + for(var/facialhairstyle in facial_hair_styles_list) + var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] + if(pref.gender == MALE && S.gender == FEMALE) + continue + if(pref.gender == FEMALE && S.gender == MALE) + continue + if(!(pref.species in S.species_allowed)) + continue + + valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] + + if(valid_facialhairstyles.len) + pref.f_style = pick(valid_facialhairstyles) + else + //this shouldn't happen + pref.f_style = facial_hair_styles_list["Shaved"] + + //reset hair colour and skin colour + pref.r_hair = 0//hex2num(copytext(new_hair, 2, 4)) + pref.g_hair = 0//hex2num(copytext(new_hair, 4, 6)) + pref.b_hair = 0//hex2num(copytext(new_hair, 6, 8)) + pref.s_tone = 0 + + return TOPIC_REFRESH + + else if(href_list["hair_color"]) + if(!has_flag(mob_species, HAS_HAIR_COLOR)) + return TOPIC_NOACTION + var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference", rgb(pref.r_hair, pref.g_hair, pref.b_hair)) as color|null + if(new_hair && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) + pref.r_hair = hex2num(copytext(new_hair, 2, 4)) + pref.g_hair = hex2num(copytext(new_hair, 4, 6)) + pref.b_hair = hex2num(copytext(new_hair, 6, 8)) + return TOPIC_REFRESH + + else if(href_list["hair_style"]) + var/list/valid_hairstyles = list() + for(var/hairstyle in hair_styles_list) + var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + if(!(pref.species in S.species_allowed)) + continue + + valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] + + var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference", pref.h_style) as null|anything in valid_hairstyles + if(new_h_style && CanUseTopic(user)) + pref.h_style = new_h_style + return TOPIC_REFRESH + + else if(href_list["facial_color"]) + if(!has_flag(mob_species, HAS_HAIR_COLOR)) + return TOPIC_NOACTION + var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(pref.r_facial, pref.g_facial, pref.b_facial)) as color|null + if(new_facial && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) + pref.r_facial = hex2num(copytext(new_facial, 2, 4)) + pref.g_facial = hex2num(copytext(new_facial, 4, 6)) + pref.b_facial = hex2num(copytext(new_facial, 6, 8)) + return TOPIC_REFRESH + + else if(href_list["eye_color"]) + if(!has_flag(mob_species, HAS_EYE_COLOR)) + return TOPIC_NOACTION + var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(pref.r_eyes, pref.g_eyes, pref.b_eyes)) as color|null + if(new_eyes && has_flag(mob_species, HAS_EYE_COLOR) && CanUseTopic(user)) + pref.r_eyes = hex2num(copytext(new_eyes, 2, 4)) + pref.g_eyes = hex2num(copytext(new_eyes, 4, 6)) + pref.b_eyes = hex2num(copytext(new_eyes, 6, 8)) + return TOPIC_REFRESH + + else if(href_list["skin_tone"]) + if(!has_flag(mob_species, HAS_SKIN_TONE)) + return TOPIC_NOACTION + var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference", pref.s_tone) as num|null + if(new_s_tone && has_flag(mob_species, HAS_SKIN_TONE) && CanUseTopic(user)) + pref.s_tone = 35 - max(min( round(new_s_tone), 220),1) + return TOPIC_REFRESH + + else if(href_list["skin_color"]) + if(!has_flag(mob_species, HAS_SKIN_COLOR)) + return TOPIC_NOACTION + var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(pref.r_skin, pref.g_skin, pref.b_skin)) as color|null + if(new_skin && has_flag(mob_species, HAS_SKIN_COLOR) && CanUseTopic(user)) + pref.r_skin = hex2num(copytext(new_skin, 2, 4)) + pref.g_skin = hex2num(copytext(new_skin, 4, 6)) + pref.b_skin = hex2num(copytext(new_skin, 6, 8)) + return TOPIC_REFRESH + + else if(href_list["facial_style"]) + var/list/valid_facialhairstyles = list() + for(var/facialhairstyle in facial_hair_styles_list) + var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] + if(pref.gender == MALE && S.gender == FEMALE) + continue + if(pref.gender == FEMALE && S.gender == MALE) + continue + if(!(pref.species in S.species_allowed)) + continue + + valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] + + var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference", pref.f_style) as null|anything in valid_facialhairstyles + if(new_f_style && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) + pref.f_style = new_f_style + return TOPIC_REFRESH + + else if(href_list["limbs"]) + var/limb_name = input(user, "Which limb do you want to change?") as null|anything in list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand") + if(!limb_name && !CanUseTopic(user)) return TOPIC_NOACTION + + var/limb = null + var/second_limb = null // if you try to change the arm, the hand should also change + var/third_limb = null // if you try to unchange the hand, the arm should also change + switch(limb_name) + if("Left Leg") + limb = "l_leg" + second_limb = "l_foot" + if("Right Leg") + limb = "r_leg" + second_limb = "r_foot" + if("Left Arm") + limb = "l_arm" + second_limb = "l_hand" + if("Right Arm") + limb = "r_arm" + second_limb = "r_hand" + if("Left Foot") + limb = "l_foot" + third_limb = "l_leg" + if("Right Foot") + limb = "r_foot" + third_limb = "r_leg" + if("Left Hand") + limb = "l_hand" + third_limb = "l_arm" + if("Right Hand") + limb = "r_hand" + third_limb = "r_arm" + + var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in list("Normal","Amputated","Prothesis") + if(!new_state && !CanUseTopic(user)) return TOPIC_NOACTION + + switch(new_state) + if("Normal") + pref.organ_data[limb] = null + pref.rlimb_data[limb] = null + if(third_limb) + pref.organ_data[third_limb] = null + pref.rlimb_data[third_limb] = null + if("Amputated") + pref.organ_data[limb] = "amputated" + pref.rlimb_data[limb] = null + if(second_limb) + pref.organ_data[second_limb] = "amputated" + pref.rlimb_data[second_limb] = null + + if("Prothesis") + var/tmp_species = pref.species ? pref.species : "Human" + var/list/usable_manufacturers = list() + for(var/company in chargen_robolimbs) + var/datum/robolimb/M = chargen_robolimbs[company] + if(tmp_species in M.species_cannot_use) + continue + usable_manufacturers[company] = M + if(!usable_manufacturers.len) + return + var/choice = input(user, "Which manufacturer do you wish to use for this limb?") as null|anything in usable_manufacturers + if(!choice) + return + pref.rlimb_data[limb] = choice + pref.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 + return TOPIC_REFRESH + + else if(href_list["organs"]) + var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes") + if(!organ_name) return + + var/organ = null + switch(organ_name) + if("Heart") + organ = "heart" + if("Eyes") + organ = "eyes" + + var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in list("Normal","Assisted","Mechanical") + if(!new_state) return + + switch(new_state) + if("Normal") + pref.organ_data[organ] = null + if("Assisted") + pref.organ_data[organ] = "assisted" + if("Mechanical") + pref.organ_data[organ] = "mechanical" + return TOPIC_REFRESH + + else if(href_list["disabilities"]) + var/disability_flag = text2num(href_list["disabilities"]) + pref.disabilities ^= disability_flag + return TOPIC_REFRESH + + return ..() + +/datum/category_item/player_setup_item/general/body/proc/SetSpecies(mob/user) + if(!pref.species_preview || !(pref.species_preview in all_species)) + pref.species_preview = "Human" + var/datum/species/current_species = all_species[pref.species_preview] + var/dat = "" + dat += "

[current_species.name] \[change\]


" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "
[current_species.blurb]" + if("preview" in icon_states(current_species.icobase)) + usr << browse_rsc(icon(current_species.icobase,"preview"), "species_preview_[current_species.name].png") + dat += "

" + dat += "Language: [current_species.language]
" + dat += "" + if(current_species.spawn_flags & CAN_JOIN) + dat += "
Often present on human stations." + if(current_species.spawn_flags & IS_WHITELISTED) + dat += "
Whitelist restricted." + if(current_species.flags & NO_BLOOD) + dat += "
Does not have blood." + if(current_species.flags & NO_BREATHE) + dat += "
Does not breathe." + if(current_species.flags & NO_SCAN) + dat += "
Does not have DNA." + if(current_species.flags & NO_PAIN) + dat += "
Does not feel pain." + if(current_species.flags & NO_SLIP) + dat += "
Has excellent traction." + if(current_species.flags & NO_POISON) + dat += "
Immune to most poisons." + if(current_species.appearance_flags & HAS_SKIN_TONE) + dat += "
Has a variety of skin tones." + if(current_species.appearance_flags & HAS_SKIN_COLOR) + dat += "
Has a variety of skin colours." + if(current_species.appearance_flags & HAS_EYE_COLOR) + dat += "
Has a variety of eye colours." + if(current_species.flags & IS_PLANT) + dat += "
Has a plantlike physiology." + dat += "

" + + var/restricted = 0 + if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it! + if(!(current_species.spawn_flags & CAN_JOIN)) + restricted = 2 + else if((current_species.spawn_flags & IS_WHITELISTED) && !is_alien_whitelisted(preference_mob(),current_species)) + restricted = 1 + + if(restricted) + if(restricted == 1) + dat += "You cannot play as this species.
If you wish to be whitelisted, you can make an application post on the forums.

" + else if(restricted == 2) + dat += "You cannot play as this species.
This species is not available for play as a station race..

" + if(!restricted || check_rights(R_ADMIN, 0)) + dat += "\[select\]" + dat += "
" + + user << browse(dat, "window=species;size=700x400") diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm new file mode 100644 index 0000000000..bf933932b8 --- /dev/null +++ b/code/modules/client/preference_setup/general/04_equipment.dm @@ -0,0 +1,129 @@ +/datum/category_item/player_setup_item/general/equipment + name = "Equipment" + sort_order = 4 + +/datum/category_item/player_setup_item/general/equipment/load_character(var/savefile/S) + S["underwear"] >> pref.underwear + S["undershirt"] >> pref.undershirt + S["backbag"] >> pref.backbag + S["gear"] >> pref.gear + +/datum/category_item/player_setup_item/general/equipment/save_character(var/savefile/S) + S["underwear"] << pref.underwear + S["undershirt"] << pref.undershirt + S["backbag"] << pref.backbag + S["gear"] << pref.gear + +/datum/category_item/player_setup_item/general/equipment/sanitize_character() + pref.backbag = sanitize_integer(pref.backbag, 1, backbaglist.len, initial(pref.backbag)) + + if(!islist(pref.gear)) pref.gear = list() + + var/undies = get_undies() + if(!get_key_by_value(undies, pref.underwear)) + pref.underwear = undies[1] + if(!get_key_by_value(undershirt_t, pref.undershirt)) + pref.undershirt = undershirt_t[1] + + var/total_cost = 0 + for(var/gear_name in pref.gear) + if(!gear_datums[gear_name]) + pref.gear -= gear_name + else if(!(gear_name in valid_gear_choices())) + pref.gear -= gear_name + else + var/datum/gear/G = gear_datums[gear_name] + if(total_cost + G.cost > MAX_GEAR_COST) + pref.gear -= gear_name + else + total_cost += G.cost + +/datum/category_item/player_setup_item/general/equipment/content() + . += "Equipment Loadout:
" + . += "Underwear: [get_key_by_value(get_undies(),pref.underwear)]
" + . += "Undershirt: [get_key_by_value(undershirt_t,pref.undershirt)]
" + . += "Backpack Type: [backbaglist[pref.backbag]]
" + + . += "
Custom Loadout:
" + var/total_cost = 0 + + if(pref.gear && pref.gear.len) + for(var/i = 1; i <= pref.gear.len; i++) + var/datum/gear/G = gear_datums[pref.gear[i]] + if(G) + total_cost += G.cost + . += "[pref.gear[i]] ([G.cost] points) Remove
" + + . += "Used: [total_cost] points." + else + . += "None." + + if(total_cost < MAX_GEAR_COST) + . += " Add" + if(pref.gear && pref.gear.len) + . += " Clear" + . += "
" + +/datum/category_item/player_setup_item/general/equipment/proc/get_undies() + return pref.gender == MALE ? underwear_m : underwear_f + +/datum/category_item/player_setup_item/general/equipment/proc/valid_gear_choices(var/max_cost) + var/list/valid_gear_choices = list() + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + if(G.whitelisted && !is_alien_whitelisted(preference_mob(), G.whitelisted)) + continue + if(max_cost && G.cost > max_cost) + continue + valid_gear_choices += gear_name + return valid_gear_choices + +/datum/category_item/player_setup_item/general/equipment/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["change_underwear"]) + var/underwear_options = get_undies() + var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference", get_key_by_value(get_undies(),pref.underwear)) as null|anything in underwear_options + if(!isnull(new_underwear) && CanUseTopic(user)) + pref.underwear = underwear_options[new_underwear] + return TOPIC_REFRESH + + else if(href_list["change_undershirt"]) + var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference", get_key_by_value(undershirt_t,pref.undershirt)) as null|anything in undershirt_t + if(!isnull(new_undershirt) && CanUseTopic(user)) + pref.undershirt = undershirt_t[new_undershirt] + return TOPIC_REFRESH + + else if(href_list["change_backpack"]) + var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference", backbaglist[pref.backbag]) as null|anything in backbaglist + if(!isnull(new_backbag) && CanUseTopic(user)) + pref.backbag = backbaglist.Find(new_backbag) + return TOPIC_REFRESH + + else if(href_list["add_loadout"]) + var/total_cost = 0 + for(var/gear_name in pref.gear) + if(gear_datums[gear_name]) + var/datum/gear/G = gear_datums[gear_name] + total_cost += G.cost + + var/choice = input(user, "Select gear to add:", "Character Preference") as null|anything in valid_gear_choices(MAX_GEAR_COST - total_cost) + if(choice && gear_datums[choice] && CanUseTopic(user)) + var/datum/gear/C = gear_datums[choice] + total_cost += C.cost + if(C && total_cost <= MAX_GEAR_COST) + pref.gear += choice + user << "Added \the '[choice]' for [C.cost] points ([MAX_GEAR_COST - total_cost] points remaining)." + else + user << "Adding \the '[choice]' will exceed the maximum loadout cost of [MAX_GEAR_COST] points." + return TOPIC_REFRESH + + else if(href_list["remove_loadout"]) + var/i_remove = text2num(href_list["remove_loadout"]) + if(i_remove < 1 || i_remove > pref.gear.len) return TOPIC_NOACTION + pref.gear.Cut(i_remove, i_remove + 1) + return TOPIC_REFRESH + + else if(href_list["clear_loadout"]) + pref.gear.Cut() + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/general/05_background.dm b/code/modules/client/preference_setup/general/05_background.dm new file mode 100644 index 0000000000..5708d3c757 --- /dev/null +++ b/code/modules/client/preference_setup/general/05_background.dm @@ -0,0 +1,125 @@ +/datum/category_item/player_setup_item/general/background + name = "Background" + sort_order = 5 + +/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["citizenship"] >> pref.citizenship + S["faction"] >> pref.faction + S["religion"] >> pref.religion + S["nanotrasen_relation"] >> pref.nanotrasen_relation + +/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["citizenship"] << pref.citizenship + S["faction"] << pref.faction + S["religion"] << pref.religion + S["nanotrasen_relation"] << pref.nanotrasen_relation + +/datum/category_item/player_setup_item/general/background/sanitize_character() + if(!pref.home_system) pref.home_system = "Unset" + if(!pref.citizenship) pref.citizenship = "None" + if(!pref.faction) pref.faction = "None" + if(!pref.religion) pref.religion = "None" + + pref.nanotrasen_relation = sanitize_inlist(pref.nanotrasen_relation, COMPANY_ALIGNMENTS, initial(pref.nanotrasen_relation)) + +/datum/category_item/player_setup_item/general/background/content(var/mob/user) + . += "Background Information
" + . += "[company_name] Relation: [pref.nanotrasen_relation]
" + . += "Home System: [pref.home_system]
" + . += "Citizenship: [pref.citizenship]
" + . += "Faction: [pref.faction]
" + . += "Religion: [pref.religion]
" + + . += "
Records:
" + if(jobban_isbanned(user, "Records")) + . += "You are banned from using character records.
" + else + . += "Medical Records:
" + . += "[TextPreview(pref.med_record,40)]

" + . += "Employment Records:
" + . += "[TextPreview(pref.gen_record,40)]

" + . += "Security Records:
" + . += "[TextPreview(pref.sec_record,40)]
" + +/datum/category_item/player_setup_item/general/background/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["nt_relation"]) + var/new_relation = input(user, "Choose your relation to NT. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", "Character Preference", pref.nanotrasen_relation) as null|anything in COMPANY_ALIGNMENTS + if(new_relation && CanUseTopic(user)) + pref.nanotrasen_relation = new_relation + return TOPIC_REFRESH + + else if(href_list["home_system"]) + var/choice = input(user, "Please choose a home system.", "Character Preference", pref.home_system) as null|anything in home_system_choices + list("Unset","Other") + if(!choice || !CanUseTopic(user)) + return TOPIC_NOACTION + if(choice == "Other") + var/raw_choice = sanitize(input(user, "Please enter a home system.", "Character Preference") as text|null, MAX_NAME_LEN) + if(raw_choice && CanUseTopic(user)) + pref.home_system = raw_choice + else + pref.home_system = choice + return TOPIC_REFRESH + + else if(href_list["citizenship"]) + var/choice = input(user, "Please choose your current citizenship.", "Character Preference", pref.citizenship) as null|anything in citizenship_choices + list("None","Other") + if(!choice || !CanUseTopic(user)) + return TOPIC_NOACTION + if(choice == "Other") + var/raw_choice = sanitize(input(user, "Please enter your current citizenship.", "Character Preference") as text|null, MAX_NAME_LEN) + if(raw_choice && CanUseTopic(user)) + pref.citizenship = raw_choice + else + pref.citizenship = choice + return TOPIC_REFRESH + + else if(href_list["faction"]) + var/choice = input(user, "Please choose a faction to work for.", "Character Preference", pref.faction) as null|anything in faction_choices + list("None","Other") + if(!choice || !CanUseTopic(user)) + return TOPIC_NOACTION + if(choice == "Other") + var/raw_choice = sanitize(input(user, "Please enter a faction.", "Character Preference") as text|null, MAX_NAME_LEN) + if(raw_choice) + pref.faction = raw_choice + else + pref.faction = choice + return TOPIC_REFRESH + + else if(href_list["religion"]) + var/choice = input(user, "Please choose a religion.", "Character Preference", pref.religion) as null|anything in religion_choices + list("None","Other") + if(!choice || !CanUseTopic(user)) + return TOPIC_NOACTION + if(choice == "Other") + var/raw_choice = sanitize(input(user, "Please enter a religon.", "Character Preference") as text|null, MAX_NAME_LEN) + if(raw_choice) + pref.religion = sanitize(raw_choice) + else + pref.religion = choice + return TOPIC_REFRESH + + else if(href_list["set_medical_records"]) + var/new_medical = sanitize(input(user,"Enter medical information here.","Character Preference", html_decode(pref.med_record)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(!isnull(new_medical) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) + pref.med_record = new_medical + return TOPIC_REFRESH + + else if(href_list["set_general_records"]) + var/new_general = sanitize(input(user,"Enter employment information here.","Character Preference", html_decode(pref.gen_record)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(!isnull(new_general) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) + pref.gen_record = new_general + return TOPIC_REFRESH + + else if(href_list["set_security_records"]) + var/sec_medical = sanitize(input(user,"Enter security information here.","Character Preference", html_decode(pref.sec_record)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(!isnull(sec_medical) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) + pref.sec_record = sec_medical + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/general/06_flavor.dm b/code/modules/client/preference_setup/general/06_flavor.dm new file mode 100644 index 0000000000..3c2d93073b --- /dev/null +++ b/code/modules/client/preference_setup/general/06_flavor.dm @@ -0,0 +1,127 @@ +/datum/category_item/player_setup_item/general/flavor + 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"] + + //Flavour text for robots. + S["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] + +/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["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] + +/datum/category_item/player_setup_item/general/flavor/sanitize_character() + return + +/datum/category_item/player_setup_item/general/flavor/content(var/mob/user) + . += "Flavor:
" + . += "Set Flavor Text
" + . += "Set Robot Flavor Text
" + +/datum/category_item/player_setup_item/general/flavor/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["flavor_text"]) + switch(href_list["flavor_text"]) + if("open") + else if("general") + var/msg = sanitize(input(usr,"Give a general description of your character. This will be shown regardless of clothing, and may include OOC notes and preferences.","Flavor Text",html_decode(pref.flavor_texts[href_list["task"]])) as message, extra = 0) + if(CanUseTopic(user)) + pref.flavor_texts[href_list["flavor_text"]] = msg + else + var/msg = sanitize(input(usr,"Set the flavor text for your [href_list["flavor_text"]].","Flavor Text",html_decode(pref.flavor_texts[href_list["flavor_text"]])) as message, extra = 0) + if(CanUseTopic(user)) + pref.flavor_texts[href_list["flavor_text"]] = msg + SetFlavorText(user) + return TOPIC_HANDLED + + else if(href_list["flavour_text_robot"]) + switch(href_list["flavour_text_robot"]) + if("open") + else if("Default") + var/msg = sanitize(input(usr,"Set the default flavour text for your robot. It will be used for any module without individual setting.","Flavour Text",html_decode(pref.flavour_texts_robot["Default"])) as message, extra = 0) + if(CanUseTopic(user)) + pref.flavour_texts_robot[href_list["flavour_text_robot"]] = msg + else + var/msg = sanitize(input(usr,"Set the flavour text for your robot with [href_list["flavour_text_robot"]] module. If you leave this empty, default flavour text will be used for this module.","Flavour Text",html_decode(pref.flavour_texts_robot[href_list["flavour_text_robot"]])) as message, extra = 0) + if(CanUseTopic(user)) + pref.flavour_texts_robot[href_list["flavour_text_robot"]] = msg + SetFlavourTextRobot(user) + return TOPIC_HANDLED + + return ..() + +/datum/category_item/player_setup_item/general/flavor/proc/SetFlavorText(mob/user) + var/HTML = "" + HTML += "
" + HTML += "Set Flavour Text
" + HTML += "
" + HTML += "General: " + HTML += TextPreview(pref.flavor_texts["general"]) + HTML += "
" + HTML += "Head: " + HTML += TextPreview(pref.flavor_texts["head"]) + HTML += "
" + HTML += "Face: " + HTML += TextPreview(pref.flavor_texts["face"]) + HTML += "
" + HTML += "Eyes: " + HTML += TextPreview(pref.flavor_texts["eyes"]) + HTML += "
" + HTML += "Body: " + HTML += TextPreview(pref.flavor_texts["torso"]) + HTML += "
" + HTML += "Arms: " + HTML += TextPreview(pref.flavor_texts["arms"]) + HTML += "
" + HTML += "Hands: " + HTML += TextPreview(pref.flavor_texts["hands"]) + HTML += "
" + HTML += "Legs: " + HTML += TextPreview(pref.flavor_texts["legs"]) + HTML += "
" + HTML += "Feet: " + HTML += TextPreview(pref.flavor_texts["feet"]) + HTML += "
" + HTML += "
" + HTML += "" + user << browse(HTML, "window=flavor_text;size=430x300") + return + +/datum/category_item/player_setup_item/general/flavor/proc/SetFlavourTextRobot(mob/user) + var/HTML = "" + HTML += "
" + HTML += "Set Robot Flavour Text
" + HTML += "
" + HTML += "Default: " + HTML += TextPreview(pref.flavour_texts_robot["Default"]) + HTML += "
" + for(var/module in robot_module_types) + HTML += "[module]: " + HTML += TextPreview(pref.flavour_texts_robot[module]) + HTML += "
" + HTML += "
" + HTML += "" + user << browse(HTML, "window=flavour_text_robot;size=430x300") + return diff --git a/code/modules/client/preference_setup/global/01_ui.dm b/code/modules/client/preference_setup/global/01_ui.dm new file mode 100644 index 0000000000..09289c1068 --- /dev/null +++ b/code/modules/client/preference_setup/global/01_ui.dm @@ -0,0 +1,73 @@ +/datum/category_item/player_setup_item/player_global/ui + 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 + +/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 + +/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)) + pref.UI_style_color = sanitize_hexcolor(pref.UI_style_color, initial(pref.UI_style_color)) + pref.UI_style_alpha = sanitize_integer(pref.UI_style_alpha, 0, 255, initial(pref.UI_style_alpha)) + pref.ooccolor = sanitize_hexcolor(pref.ooccolor, initial(pref.ooccolor)) + +/datum/category_item/player_setup_item/player_global/ui/content(var/mob/user) + . = "UI Style: [pref.UI_style]
" + . += "Custom UI (recommended for White UI):
" + . += "-Color: [pref.UI_style_color] 
__
 reset
" + . += "-Alpha(transparency): [pref.UI_style_alpha] reset
" + if(can_select_ooc_color(user)) + . += "OOC Color: " + if(pref.ooccolor == initial(pref.ooccolor)) + . += "Using Default
" + else + . += "[pref.ooccolor]
__
 reset
" + +/datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["select_style"]) + var/UI_style_new = input(user, "Choose UI style.", "Character Preference", pref.UI_style) as null|anything in all_ui_styles + if(!UI_style_new || !CanUseTopic(user)) return TOPIC_NOACTION + pref.UI_style = UI_style_new + return TOPIC_REFRESH + + else if(href_list["select_color"]) + var/UI_style_color_new = input(user, "Choose UI color, dark colors are not recommended!", "Global Preference", pref.UI_style_color) as color|null + if(isnull(UI_style_color_new) || !CanUseTopic(user)) return TOPIC_NOACTION + pref.UI_style_color = UI_style_color_new + return TOPIC_REFRESH + + else if(href_list["select_alpha"]) + var/UI_style_alpha_new = input(user, "Select UI alpha (transparency) level, between 50 and 255.", "Global Preference", pref.UI_style_alpha) as num|null + if(isnull(UI_style_alpha_new) || (UI_style_alpha_new < 50 || UI_style_alpha_new > 255) || !CanUseTopic(user)) return TOPIC_NOACTION + pref.UI_style_alpha = UI_style_alpha_new + return TOPIC_REFRESH + + else if(href_list["select_ooc_color"]) + var/new_ooccolor = input(user, "Choose OOC color:", "Global Preference") as color|null + if(new_ooccolor && can_select_ooc_color(user) && CanUseTopic(user)) + pref.ooccolor = new_ooccolor + return TOPIC_REFRESH + + else if(href_list["reset"]) + switch(href_list["reset"]) + if("ui") + pref.UI_style_color = initial(pref.UI_style_color) + if("alpha") + pref.UI_style_alpha = initial(pref.UI_style_alpha) + if("ooc") + pref.ooccolor = initial(pref.ooccolor) + return TOPIC_REFRESH + + return ..() + +/datum/category_item/player_setup_item/player_global/ui/proc/can_select_ooc_color(var/mob/user) + return config.allow_admin_ooccolor && check_rights(R_ADMIN, 0, user) diff --git a/code/modules/client/preference_setup/global/02_settings.dm b/code/modules/client/preference_setup/global/02_settings.dm new file mode 100644 index 0000000000..7b61a86cb4 --- /dev/null +++ b/code/modules/client/preference_setup/global/02_settings.dm @@ -0,0 +1,38 @@ +/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["default_slot"] >> pref.default_slot + S["toggles"] >> pref.toggles + +/datum/category_item/player_setup_item/player_global/settings/save_preferences(var/savefile/S) + S["lastchangelog"] << pref.lastchangelog + S["default_slot"] << pref.default_slot + S["toggles"] << pref.toggles + +/datum/category_item/player_setup_item/player_global/settings/sanitize_preferences() + pref.lastchangelog = sanitize_text(pref.lastchangelog, initial(pref.lastchangelog)) + pref.default_slot = sanitize_integer(pref.default_slot, 1, config.character_slots, initial(pref.default_slot)) + pref.toggles = sanitize_integer(pref.toggles, 0, 65535, initial(pref.toggles)) + +/datum/category_item/player_setup_item/player_global/settings/content(var/mob/user) + . += "Play admin midis: [(pref.toggles & SOUND_MIDI) ? "Yes" : "No"]
" + . += "Play lobby music: [(pref.toggles & SOUND_LOBBY) ? "Yes" : "No"]
" + . += "Ghost ears: [(pref.toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]
" + . += "Ghost sight: [(pref.toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"]
" + . += "Ghost radio: [(pref.toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"]
" + +/datum/category_item/player_setup_item/player_global/settings/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["toggle"]) + var/toggle_flag = text2num(href_list["toggle"]) + pref.toggles ^= toggle_flag + if(toggle_flag == SOUND_LOBBY && isnewplayer(user)) + if(pref.toggles & SOUND_LOBBY) + user << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1) + else + user << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/global/03_pai.dm b/code/modules/client/preference_setup/global/03_pai.dm new file mode 100644 index 0000000000..7944c7b6e7 --- /dev/null +++ b/code/modules/client/preference_setup/global/03_pai.dm @@ -0,0 +1,54 @@ +/datum/category_item/player_setup_item/player_global/pai + name = "pAI" + sort_order = 3 + + var/datum/paiCandidate/candidate + +/datum/category_item/player_setup_item/player_global/pai/load_preferences(var/savefile/S) + if(!candidate) + candidate = new() + + if(!preference_mob()) + return + + candidate.savefile_load(preference_mob()) + +/datum/category_item/player_setup_item/player_global/pai/save_preferences(var/savefile/S) + if(!candidate) + return + + if(!preference_mob()) + return + + candidate.savefile_save(preference_mob()) + +/datum/category_item/player_setup_item/player_global/pai/content(var/mob/user) + . += "pAI:
" + . += "Name: [candidate.name ? candidate.name : "None Set"]
" + . += "Description: [candidate.description ? TextPreview(candidate.description, 40) : "None Set"]
" + . += "Role: [candidate.role ? TextPreview(candidate.role, 40) : "None Set"]
" + . += "OOC Comments: [candidate.comments ? TextPreview(candidate.comments, 40) : "None Set"]
" + +/datum/category_item/player_setup_item/player_global/pai/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["option"]) + var/t + switch(href_list["option"]) + if("name") + t = sanitizeName(input(user, "Enter a name for your pAI", "Global Preference", candidate.name) as text|null, MAX_NAME_LEN, 1) + if(t && CanUseTopic(user)) + candidate.name = t + if("desc") + t = input(user, "Enter a description for your pAI", "Global Preference", html_decode(candidate.description)) as message|null + if(!isnull(t) && CanUseTopic(user)) + candidate.description = sanitize(t) + if("role") + t = input(user, "Enter a role for your pAI", "Global Preference", html_decode(candidate.role)) as text|null + if(!isnull(t) && CanUseTopic(user)) + candidate.role = sanitize(t) + if("ooc") + t = input(user, "Enter any OOC comments", "Global Preference", html_decode(candidate.comments)) as message + if(!isnull(t) && CanUseTopic(user)) + candidate.comments = sanitize(t) + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm new file mode 100644 index 0000000000..561ffb3ec4 --- /dev/null +++ b/code/modules/client/preference_setup/occupation/occupation.dm @@ -0,0 +1,291 @@ +//used for pref.alternate_option +#define GET_RANDOM_JOB 0 +#define BE_ASSISTANT 1 +#define RETURN_TO_LOBBY 2 + +/datum/category_item/player_setup_item/occupation + 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 + S["player_alt_titles"] >> pref.player_alt_titles + +/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 + S["player_alt_titles"] << pref.player_alt_titles + +/datum/category_item/player_setup_item/occupation/sanitize_character() + pref.alternate_option = sanitize_integer(pref.alternate_option, 0, 2, initial(pref.alternate_option)) + pref.job_civilian_high = sanitize_integer(pref.job_civilian_high, 0, 65535, initial(pref.job_civilian_high)) + pref.job_civilian_med = sanitize_integer(pref.job_civilian_med, 0, 65535, initial(pref.job_civilian_med)) + pref.job_civilian_low = sanitize_integer(pref.job_civilian_low, 0, 65535, initial(pref.job_civilian_low)) + pref.job_medsci_high = sanitize_integer(pref.job_medsci_high, 0, 65535, initial(pref.job_medsci_high)) + pref.job_medsci_med = sanitize_integer(pref.job_medsci_med, 0, 65535, initial(pref.job_medsci_med)) + pref.job_medsci_low = sanitize_integer(pref.job_medsci_low, 0, 65535, initial(pref.job_medsci_low)) + pref.job_engsec_high = sanitize_integer(pref.job_engsec_high, 0, 65535, initial(pref.job_engsec_high)) + pref.job_engsec_med = sanitize_integer(pref.job_engsec_med, 0, 65535, initial(pref.job_engsec_med)) + pref.job_engsec_low = sanitize_integer(pref.job_engsec_low, 0, 65535, initial(pref.job_engsec_low)) + if(!pref.player_alt_titles) pref.player_alt_titles = new() + + if(!job_master) + return + + for(var/datum/job/job in job_master.occupations) + var/alt_title = pref.player_alt_titles[job.title] + if(alt_title && !(alt_title in job.alt_titles)) + pref.player_alt_titles -= job.title + +/datum/category_item/player_setup_item/occupation/content(mob/user, limit = 16, list/splitJobs = list("Chief Medical Officer")) + if(!job_master) + return + + . += "
" + . += "Choose occupation chances
Unavailable occupations are crossed out.
" + . += "
" // Table within a table for alignment, also allows you to easily add more colomns. + . += "" + var/index = -1 + + //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. + var/datum/job/lastJob + if (!job_master) return + for(var/datum/job/job in job_master.occupations) + + index += 1 + if((index >= limit) || (job.title in splitJobs)) + if((index < limit) && (lastJob != null)) + //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with + //the last job's selection color. Creating a rather nice effect. + for(var/i = 0, i < (limit - index), i += 1) + . += "" + . += "
  
" + index = 0 + + . += "" + continue + if(!job.player_old_enough(user.client)) + var/available_in_days = job.available_in_days(user.client) + . += "[rank]" + continue + if((pref.job_civilian_low & ASSISTANT) && (rank != "Assistant")) + . += "[rank]" + continue + if((rank in command_positions) || (rank == "AI"))//Bold head jobs + . += "[rank]" + else + . += "[rank]" + + . += "" + . += "" + continue + + if(pref.GetJobDepartment(job, 1) & job.flag) + . += " \[High]" + else if(pref.GetJobDepartment(job, 2) & job.flag) + . += " \[Medium]" + else if(pref.GetJobDepartment(job, 3) & job.flag) + . += " \[Low]" + else + . += " \[NEVER]" + if(job.alt_titles) + . += "" + . += "" + + . += "
" + var/rank = job.title + lastJob = job + if(jobban_isbanned(user, rank)) + . += "[rank] \[BANNED]
\[IN [(available_in_days)] DAYS]
" + + . += "" + + if(rank == "Assistant")//Assistant is special + if(pref.job_civilian_low & ASSISTANT) + . += " \[Yes]" + else + . += " \[No]" + if(job.alt_titles) //Blatantly cloned from a few lines down. + . += "
 \[[pref.GetPlayerAltTitle(job)]\]
 \[[pref.GetPlayerAltTitle(job)]\]
" + + . += "
" + + switch(pref.alternate_option) + if(GET_RANDOM_JOB) + . += "

Get random job if preferences unavailable

" + if(BE_ASSISTANT) + . += "

Be assistant if preference unavailable

" + if(RETURN_TO_LOBBY) + . += "

Return to lobby if preference unavailable

" + + . += "
\[Reset\]
" + . += "
" + +/datum/category_item/player_setup_item/occupation/OnTopic(href, href_list, user) + if(href_list["reset_jobs"]) + ResetJobs() + return TOPIC_REFRESH + + else if(href_list["job_alternative"]) + if(pref.alternate_option == GET_RANDOM_JOB || pref.alternate_option == BE_ASSISTANT) + pref.alternate_option += 1 + else if(pref.alternate_option == RETURN_TO_LOBBY) + pref.alternate_option = 0 + return TOPIC_REFRESH + + else if(href_list["select_alt_title"]) + var/datum/job/job = locate(href_list["select_alt_title"]) + if (job) + var/choices = list(job.title) + job.alt_titles + var/choice = input("Choose an title for [job.title].", "Choose Title", pref.GetPlayerAltTitle(job)) as anything in choices|null + if(choice && CanUseTopic(user)) + SetPlayerAltTitle(job, choice) + return TOPIC_REFRESH + + else if(href_list["set_job"]) + if(SetJob(user, href_list["set_job"])) return TOPIC_REFRESH + + return ..() + +/datum/category_item/player_setup_item/occupation/proc/SetPlayerAltTitle(datum/job/job, new_title) + // remove existing entry + pref.player_alt_titles -= job.title + // add one if it's not default + if(job.title != new_title) + pref.player_alt_titles[job.title] = new_title + +/datum/category_item/player_setup_item/occupation/proc/SetJob(mob/user, role) + var/datum/job/job = job_master.GetJob(role) + if(!job) + return 0 + + if(role == "Assistant") + if(pref.job_civilian_low & job.flag) + pref.job_civilian_low &= ~job.flag + else + pref.job_civilian_low |= job.flag + return 1 + + if(pref.GetJobDepartment(job, 1) & job.flag) + SetJobDepartment(job, 1) + else if(pref.GetJobDepartment(job, 2) & job.flag) + SetJobDepartment(job, 2) + else if(pref.GetJobDepartment(job, 3) & job.flag) + SetJobDepartment(job, 3) + else//job = Never + SetJobDepartment(job, 4) + + return 1 + +/datum/category_item/player_setup_item/occupation/proc/SetJobDepartment(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(level) + if(1)//Only one of these should ever be active at once so clear them all here + pref.job_civilian_high = 0 + pref.job_medsci_high = 0 + pref.job_engsec_high = 0 + return 1 + if(2)//Set current highs to med, then reset them + pref.job_civilian_med |= pref.job_civilian_high + pref.job_medsci_med |= pref.job_medsci_high + pref.job_engsec_med |= pref.job_engsec_high + pref.job_civilian_high = 0 + pref.job_medsci_high = 0 + pref.job_engsec_high = 0 + + switch(job.department_flag) + if(CIVILIAN) + switch(level) + if(2) + pref.job_civilian_high = job.flag + pref.job_civilian_med &= ~job.flag + if(3) + pref.job_civilian_med |= job.flag + pref.job_civilian_low &= ~job.flag + else + pref.job_civilian_low |= job.flag + if(MEDSCI) + switch(level) + if(2) + pref.job_medsci_high = job.flag + pref.job_medsci_med &= ~job.flag + if(3) + pref.job_medsci_med |= job.flag + pref.job_medsci_low &= ~job.flag + else + pref.job_medsci_low |= job.flag + if(ENGSEC) + switch(level) + if(2) + pref.job_engsec_high = job.flag + pref.job_engsec_med &= ~job.flag + if(3) + pref.job_engsec_med |= job.flag + pref.job_engsec_low &= ~job.flag + else + pref.job_engsec_low |= job.flag + return 1 + +/datum/category_item/player_setup_item/occupation/proc/ResetJobs() + pref.job_civilian_high = 0 + pref.job_civilian_med = 0 + pref.job_civilian_low = 0 + + pref.job_medsci_high = 0 + pref.job_medsci_med = 0 + pref.job_medsci_low = 0 + + pref.job_engsec_high = 0 + pref.job_engsec_med = 0 + pref.job_engsec_low = 0 + + pref.player_alt_titles.Cut() + +/datum/preferences/proc/GetPlayerAltTitle(datum/job/job) + return (job.title in player_alt_titles) ? player_alt_titles[job.title] : job.title + +/datum/preferences/proc/GetJobDepartment(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(job.department_flag) + if(CIVILIAN) + switch(level) + if(1) + return job_civilian_high + if(2) + return job_civilian_med + if(3) + return job_civilian_low + if(MEDSCI) + switch(level) + if(1) + return job_medsci_high + if(2) + return job_medsci_med + if(3) + return job_medsci_low + if(ENGSEC) + switch(level) + if(1) + return job_engsec_high + if(2) + return job_engsec_med + if(3) + return job_engsec_low + return 0 diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm new file mode 100644 index 0000000000..9cb4f943f8 --- /dev/null +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -0,0 +1,209 @@ +// These are not flags, binary operations not intended +#define TOPIC_NOACTION 0 +#define TOPIC_HANDLED 1 +#define TOPIC_REFRESH 2 + +/datum/category_group/player_setup_category/general_preferences + name = "General" + sort_order = 1 + category_item_type = /datum/category_item/player_setup_item/general + +/datum/category_group/player_setup_category/skill_preferences + name = "Skills" + sort_order = 2 + category_item_type = /datum/category_item/player_setup_item/skills + +/datum/category_group/player_setup_category/occupation_preferences + name = "Occupation" + sort_order = 3 + category_item_type = /datum/category_item/player_setup_item/occupation + +/datum/category_group/player_setup_category/appearance_preferences + name = "Antagonism" + sort_order = 4 + category_item_type = /datum/category_item/player_setup_item/antagonism + +/datum/category_group/player_setup_category/global_preferences + name = "Global" + sort_order = 5 + category_item_type = /datum/category_item/player_setup_item/player_global + +/**************************** +* Category Collection Setup * +****************************/ +/datum/category_collection/player_setup_collection + category_group_type = /datum/category_group/player_setup_category + var/datum/preferences/preferences + var/datum/category_group/player_setup_category/selected_category = null + +/datum/category_collection/player_setup_collection/New(var/datum/preferences/preferences) + src.preferences = preferences + ..() + selected_category = categories[1] + +/datum/category_collection/player_setup_collection/Destroy() + preferences = null + selected_category = null + return ..() + +/datum/category_collection/player_setup_collection/proc/load_character(var/savefile/S) + for(var/datum/category_group/player_setup_category/PS in categories) + PS.load_character(S) + +/datum/category_collection/player_setup_collection/proc/save_character(var/savefile/S) + for(var/datum/category_group/player_setup_category/PS in categories) + PS.save_character(S) + +/datum/category_collection/player_setup_collection/proc/load_preferences(var/savefile/S) + for(var/datum/category_group/player_setup_category/PS in categories) + PS.load_preferences(S) + +/datum/category_collection/player_setup_collection/proc/save_preferences(var/savefile/S) + for(var/datum/category_group/player_setup_category/PS in categories) + PS.save_preferences(S) + +/datum/category_collection/player_setup_collection/proc/header() + var/dat = "" + for(var/datum/category_group/player_setup_category/PS in categories) + if(PS == selected_category) + dat += "[PS.name] " // TODO: Check how to properly mark a href/button selected in a classic browser window + else + dat += "[PS.name] " + return dat + +/datum/category_collection/player_setup_collection/proc/content(var/mob/user) + if(selected_category) + return selected_category.content(user) + +/datum/category_collection/player_setup_collection/Topic(var/href,var/list/href_list) + if(..()) + return 1 + var/mob/user = usr + if(!user.client) + return 1 + + if(href_list["category"]) + var/category = locate(href_list["category"]) + if(category && category in categories) + selected_category = category + . = 1 + + if(.) + user.client.prefs.ShowChoices(user) + +/************************** +* Category Category Setup * +**************************/ +/datum/category_group/player_setup_category + var/sort_order = 0 + +/datum/category_group/player_setup_category/dd_SortValue() + return sort_order + +/datum/category_group/player_setup_category/proc/load_character(var/savefile/S) + for(var/datum/category_item/player_setup_item/PI in items) + PI.load_character(S) + PI.sanitize_character() + +/datum/category_group/player_setup_category/proc/save_character(var/savefile/S) + for(var/datum/category_item/player_setup_item/PI in items) + PI.sanitize_character() + PI.save_character(S) + +/datum/category_group/player_setup_category/proc/load_preferences(var/savefile/S) + for(var/datum/category_item/player_setup_item/PI in items) + PI.load_preferences(S) + PI.sanitize_preferences() + +/datum/category_group/player_setup_category/proc/save_preferences(var/savefile/S) + for(var/datum/category_item/player_setup_item/PI in items) + PI.sanitize_preferences() + PI.save_preferences(S) + +/datum/category_group/player_setup_category/proc/content(var/mob/user) + . = "
" + var/current = 0 + var/halfway = items.len / 2 + for(var/datum/category_item/player_setup_item/PI in items) + if(halfway && current++ >= halfway) + halfway = 0 + . += "" + . += "[PI.content(user)]
" + . += "
" + +/datum/category_group/player_setup_category/occupation_preferences/content(var/mob/user) + for(var/datum/category_item/player_setup_item/PI in items) + . += "[PI.content(user)]
" + +/********************** +* Category Item Setup * +**********************/ +/datum/category_item/player_setup_item + var/sort_order = 0 + var/datum/preferences/pref + +/datum/category_item/player_setup_item/New() + ..() + var/datum/category_collection/player_setup_collection/psc = category.collection + pref = psc.preferences + +/datum/category_item/player_setup_item/Destroy() + pref = null + return ..() + +/datum/category_item/player_setup_item/dd_SortValue() + return sort_order + +/* +* Called when the item is asked to load per character settings +*/ +/datum/category_item/player_setup_item/proc/load_character(var/savefile/S) + return + +/* +* Called when the item is asked to save per character settings +*/ +/datum/category_item/player_setup_item/proc/save_character(var/savefile/S) + return + +/* +* Called when the item is asked to load user/global settings +*/ +/datum/category_item/player_setup_item/proc/load_preferences(var/savefile/S) + return + +/* +* Called when the item is asked to save user/global settings +*/ +/datum/category_item/player_setup_item/proc/save_preferences(var/savefile/S) + return + +/datum/category_item/player_setup_item/proc/content() + return + +/datum/category_item/player_setup_item/proc/sanitize_character() + return + +/datum/category_item/player_setup_item/proc/sanitize_preferences() + return + +/datum/category_item/player_setup_item/Topic(var/href,var/list/href_list) + if(..()) + return 1 + var/mob/user = usr + if(!user.client) + return 1 + + . = OnTopic(href, href_list, user) + if(. == TOPIC_REFRESH) + user.client.prefs.ShowChoices(user) + +/datum/category_item/player_setup_item/CanUseTopic(var/mob/user) + return 1 + +/datum/category_item/player_setup_item/proc/OnTopic(var/href,var/list/href_list, var/mob/user) + return TOPIC_NOACTION + +/datum/category_item/player_setup_item/proc/preference_mob() + if(pref && pref.client && pref.client.mob) + return pref.client.mob diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm new file mode 100644 index 0000000000..1f60cd3bb7 --- /dev/null +++ b/code/modules/client/preference_setup/skills/skills.dm @@ -0,0 +1,77 @@ +/datum/category_item/player_setup_item/skills + 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/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/sanitize_character() + if(SKILLS == null) setup_skills() + if(!pref.skills) pref.skills = list() + if(!pref.skills.len) pref.ZeroSkills() + if(pref.used_skillpoints < 0) pref.used_skillpoints = 0 + +/datum/category_item/player_setup_item/skills/content() + . += "Select your Skills
" + . += "Current skill level: [pref.GetSkillClass(pref.used_skillpoints)] ([pref.used_skillpoints])
" + . += "Use preconfigured skillset
" + . += "" + for(var/V in SKILLS) + . += "" + for(var/datum/skill/S in SKILLS[V]) + var/level = pref.skills[S.ID] + . += "" + . += "" + . += "" + // secondary skills don't have an amateur level + if(S.secondary) + . += "" + else + . += "" + . += "" + . += "" + . += "" + . += "
[V]" + . += "
[S.name]\[Untrained\]\[Amateur\]\[Trained\]\[Professional\]
" + +/datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) + if(href_list["skillinfo"]) + var/datum/skill/S = locate(href_list["skillinfo"]) + var/HTML = "[S.name]
[S.desc]" + user << browse(HTML, "window=\ref[user]skillinfo") + return TOPIC_HANDLED + + else if(href_list["setskill"]) + var/datum/skill/S = locate(href_list["setskill"]) + var/value = text2num(href_list["newvalue"]) + pref.skills[S.ID] = value + pref.CalculateSkillPoints() + return TOPIC_REFRESH + + else if(href_list["preconfigured"]) + var/selected = input(user, "Select a skillset", "Skillset") as null|anything in SKILL_PRE + if(!selected && !CanUseTopic(user)) return + + pref.ZeroSkills(1) + for(var/V in SKILL_PRE[selected]) + if(V == "field") + pref.skill_specialization = SKILL_PRE[selected]["field"] + continue + pref.skills[V] = SKILL_PRE[selected][V] + pref.CalculateSkillPoints() + + return TOPIC_REFRESH + + else if(href_list["setspecialization"]) + pref.skill_specialization = href_list["setspecialization"] + pref.CalculateSkillPoints() + return TOPIC_REFRESH + + return ..() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index c6a91faf86..61bf6939ff 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -2,31 +2,6 @@ var/list/preferences_datums = list() -var/global/list/special_roles = list( //keep synced with the defines BE_* in setup.dm --rastaf -//some autodetection here. -// TODO: Update to new antagonist system. - "traitor" = IS_MODE_COMPILED("traitor"), // 0 - "operative" = IS_MODE_COMPILED("nuclear"), // 1 - "changeling" = IS_MODE_COMPILED("changeling"), // 2 - "wizard" = IS_MODE_COMPILED("wizard"), // 3 - "malf AI" = IS_MODE_COMPILED("malfunction"), // 4 - "revolutionary" = IS_MODE_COMPILED("revolution"), // 5 - "alien candidate" = 1, //always show // 6 - "positronic brain" = 1, // 7 - "cultist" = IS_MODE_COMPILED("cult"), // 8 - "infested monkey" = IS_MODE_COMPILED("monkey"), // 9 - "ninja" = "true", // 10 - "raider" = IS_MODE_COMPILED("heist"), // 11 - "diona" = 1, // 12 - "loyalist" = IS_MODE_COMPILED("revolution"), // 13 - "pAI candidate" = 1, // -- TLE // 14 -) - -//used for alternate_option -#define GET_RANDOM_JOB 0 -#define BE_ASSISTANT 1 -#define RETURN_TO_LOBBY 2 - datum/preferences //doohickeys for savefiles var/path @@ -57,7 +32,6 @@ datum/preferences var/b_type = "A+" //blood type (not-chooseable) var/underwear //underwear type var/undershirt //undershirt type - var/socks //socks type var/backbag = 2 //backpack type var/h_style = "Bald" //Hair type var/r_hair = 0 //Hair color @@ -130,14 +104,22 @@ datum/preferences var/uplinklocation = "PDA" - // OOC Metadata: + // OOC Metadata: var/metadata = "" - var/slot_name = "" var/client/client = null + var/datum/category_collection/player_setup_collection/player_setup + /datum/preferences/New(client/C) + player_setup = new(src) + + gender = pick(MALE, FEMALE) + real_name = random_name(gender,species) b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") + + gear = list() + if(istype(C)) client = C if(!IsGuestKey(C.key)) @@ -145,10 +127,6 @@ datum/preferences if(load_preferences()) if(load_character()) return - gender = pick(MALE, FEMALE) - real_name = random_name(gender,species) - - gear = list() /datum/preferences/proc/ZeroSkills(var/forced = 0) for(var/V in SKILLS) for(var/datum/skill/S in SKILLS[V]) @@ -202,705 +180,26 @@ datum/preferences if(24 to 1000) return "God" -/datum/preferences/proc/SetSkills(mob/user) - if(SKILLS == null) - setup_skills() - - if(skills.len == 0) - ZeroSkills() - - - var/HTML = "" - HTML += "Select your Skills
" - HTML += "Current skill level: [GetSkillClass(used_skillpoints)] ([used_skillpoints])
" - HTML += "Use preconfigured skillset
" - HTML += "" - for(var/V in SKILLS) - HTML += "" - for(var/datum/skill/S in SKILLS[V]) - var/level = skills[S.ID] - HTML += "" - HTML += "" - HTML += "" - // secondary skills don't have an amateur level - if(S.secondary) - HTML += "" - else - HTML += "" - HTML += "" - HTML += "" - HTML += "" - HTML += "
[V]" - HTML += "
[S.name]\[Untrained\]\[Amateur\]\[Trained\]\[Professional\]
" - HTML += "\[Done\]" - - user << browse(null, "window=preferences") - user << browse(HTML, "window=show_skills;size=600x800") - return - /datum/preferences/proc/ShowChoices(mob/user) if(!user || !user.client) return - update_preview_icon() - if(preview_icon_front && preview_icon_side) - user << browse_rsc(preview_icon_front, "previewicon.png") - user << browse_rsc(preview_icon_side, "previewicon2.png") var/dat = "
" if(path) - dat += "
" - dat += "Slot [slot_name] - " + dat += "Slot - " dat += "Load slot - " dat += "Save slot - " dat += "Reload slot" - dat += "
" else dat += "Please create an account to save your preferences." - dat += "

" - - dat += "Name: " - dat += "[real_name]
" - dat += "(Random Name) " - dat += "(Always Random Name: [be_random_name ? "Yes" : "No"])" dat += "
" + dat += player_setup.header() + dat += "

" + dat += player_setup.content(user) - dat += "Gender: [gender == MALE ? "Male" : "Female"]
" - dat += "Age: [age]
" - dat += "Spawn Point: [spawnpoint]" - - dat += "
" - dat += "UI Style: [UI_style]
" - dat += "Custom UI(recommended for White UI):
" - dat += "-Color: [UI_style_color]
__

" - dat += "-Alpha(transparency): [UI_style_alpha]
" - dat += "Play admin midis: [(toggles & SOUND_MIDI) ? "Yes" : "No"]
" - dat += "Play lobby music: [(toggles & SOUND_LOBBY) ? "Yes" : "No"]
" - dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]
" - dat += "Ghost sight: [(toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"]
" - dat += "Ghost radio: [(toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"]
" - - if(config.allow_Metadata) - dat += "OOC Notes: Edit
" - - dat += "
Custom Loadout: " - var/total_cost = 0 - - if(!islist(gear)) gear = list() - - if(gear && gear.len) - dat += "
" - for(var/i = 1; i <= gear.len; i++) - var/datum/gear/G = gear_datums[gear[i]] - if(G) - total_cost += G.cost - dat += "[gear[i]] ([G.cost] points) \[remove\]
" - - dat += "Used: [total_cost] points." - else - dat += "none." - - if(total_cost < MAX_GEAR_COST) - dat += " \[add\]" - if(gear && gear.len) - dat += " \[clear\]" - - dat += "

Occupation Choices
" - dat += "\tSet Preferences
" - - dat += "
Body " - dat += "(®)" - dat += "
" - dat += "Species: [species]
" - - dat += "Blood Type: [b_type]
" - dat += "Skin Tone: [-s_tone + 35]/220
" - //dat += "Skin pattern: Adjust
" - dat += "Needs Glasses: [disabilities == 0 ? "No" : "Yes"]
" - dat += "Limbs: Adjust
" - dat += "Internal Organs: Adjust
" - - //display limbs below - var/ind = 0 - for(var/name in organ_data) - //world << "[ind] \ [organ_data.len]" - var/status = organ_data[name] - var/organ_name = null - switch(name) - if("l_arm") - organ_name = "left arm" - if("r_arm") - organ_name = "right arm" - if("l_leg") - organ_name = "left leg" - if("r_leg") - organ_name = "right leg" - if("l_foot") - organ_name = "left foot" - if("r_foot") - organ_name = "right foot" - if("l_hand") - organ_name = "left hand" - if("r_hand") - organ_name = "right hand" - if("heart") - organ_name = "heart" - if("eyes") - organ_name = "eyes" - - if(status == "cyborg") - ++ind - if(ind > 1) - dat += ", " - var/datum/robolimb/R - if(rlimb_data[name] && all_robolimbs[rlimb_data[name]]) - R = all_robolimbs[rlimb_data[name]] - else - R = basic_robolimb - dat += "\t[R.company] [organ_name] prothesis" - else if(status == "amputated") - ++ind - if(ind > 1) - dat += ", " - dat += "\tAmputated [organ_name]" - else if(status == "mechanical") - ++ind - if(ind > 1) - dat += ", " - dat += "\tMechanical [organ_name]" - else if(status == "assisted") - ++ind - if(ind > 1) - dat += ", " - switch(organ_name) - if("heart") - dat += "\tPacemaker-assisted [organ_name]" - if("voicebox") //on adding voiceboxes for speaking skrell/similar replacements - dat += "\tSurgically altered [organ_name]" - if("eyes") - dat += "\tRetinal overlayed [organ_name]" - else - dat += "\tMechanically assisted [organ_name]" - if(!ind) - dat += "\[...\]

" - else - dat += "

" - - - dat += "Languages
" - var/datum/species/S = all_species[species] - if(S.language) - dat += "- [S.language]
" - if(S.default_language && S.default_language != S.language) - dat += "- [S.default_language]
" - if(S.num_alternate_languages) - if(alternate_languages.len) - for(var/i = 1 to alternate_languages.len) - var/lang = alternate_languages[i] - dat += "- [lang] - remove
" - - if(alternate_languages.len < S.num_alternate_languages) - dat += "- add ([S.num_alternate_languages - alternate_languages.len] remaining)
" - else - dat += "- [species] cannot choose secondary languages.
" - - dat += "Language Keys
" - dat += " [english_list(language_prefixes, and_text = " ", comma_text = " ")] Change Reset
" - - dat += "

" - var/list/undies = gender == MALE ? underwear_m : underwear_f - - dat += "Underwear: [get_key_by_value(undies,underwear)]
" - - dat += "Undershirt: [get_key_by_value(undershirt_t,undershirt)]
" - - dat += "Socks: [get_key_by_value(socks_t,socks)]
" - - dat += "Backpack Type:
[backbaglist[backbag]]
" - - dat += "[company_name] Relation:
[nanotrasen_relation]
" - - dat += "
Preview
" - - dat += "
" - - if(jobban_isbanned(user, "Records")) - dat += "You are banned from using character records.
" - else - dat += "Character Records
" - - dat += "Set Antag Options
" - - dat += "\tSet Skills ([GetSkillClass(used_skillpoints)] [used_skillpoints > 0 ? "[used_skillpoints]" : "0"])
" - - dat += "Set Flavor Text
" - dat += "Set Robot Flavour Text
" - - dat += "pAI Configuration
" - dat += "
" - - dat += "
Hair
" - dat += "Change Color
__
" - dat += " Style: [h_style]
" - - dat += "
Facial
" - dat += "Change Color
__
" - dat += " Style: [f_style]
" - - dat += "
Eyes
" - dat += "Change Color
__

" - - dat += "
Body Color
" - dat += "Change Color
__
" - - dat += "

Background Information
" - dat += "Home system: [home_system]
" - dat += "Citizenship: [citizenship]
" - dat += "Faction: [faction]
" - dat += "Religion: [religion]
" - - dat += "

" - - if(jobban_isbanned(user, "Syndicate")) - dat += "You are banned from antagonist roles." - src.be_special = 0 - else - var/n = 0 - for (var/i in special_roles) - if(special_roles[i]) //if mode is available on the server - if(jobban_isbanned(user, i) || (i == "positronic brain" && jobban_isbanned(user, "AI") && jobban_isbanned(user, "Cyborg")) || (i == "pAI candidate" && jobban_isbanned(user, "pAI"))) - dat += "Be [i]: \[BANNED]
" - else - dat += "Be [i]: [src.be_special&(1<
" - n++ - dat += "

" - - if(!IsGuestKey(user.key)) - dat += "Undo - " - dat += "Save Setup - " - - dat += "Reset Setup" - dat += "
" - - user << browse(dat, "window=preferences;size=560x736") - -/datum/preferences/proc/SetChoices(mob/user, limit = 16, list/splitJobs = list("Chief Medical Officer"), width = 550, height = 660) - if(!job_master) - return - - //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice. - //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice. - //width - Screen' width. Defaults to 550 to make it look nice. - //height - Screen's height. Defaults to 500 to make it look nice. - - - var/HTML = "" - HTML += "
" - HTML += "Choose occupation chances
Unavailable occupations are crossed out.

" - HTML += "
\[Done\]

" // Easier to press up here. - HTML += "
" // Table within a table for alignment, also allows you to easily add more colomns. - HTML += "" - var/index = -1 - - //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. - var/datum/job/lastJob - if (!job_master) return - for(var/datum/job/job in job_master.occupations) - - index += 1 - if((index >= limit) || (job.title in splitJobs)) - if((index < limit) && (lastJob != null)) - //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with - //the last job's selection color. Creating a rather nice effect. - for(var/i = 0, i < (limit - index), i += 1) - HTML += "" - HTML += "
  
" - index = 0 - - HTML += "" - continue - if(!job.player_old_enough(user.client)) - var/available_in_days = job.available_in_days(user.client) - HTML += "[rank]" - continue - if((job_civilian_low & ASSISTANT) && (rank != "Assistant")) - HTML += "[rank]" - continue - if((rank in command_positions) || (rank == "AI"))//Bold head jobs - HTML += "[rank]" - else - HTML += "[rank]" - - HTML += "" - HTML += "" - continue - - if(GetJobDepartment(job, 1) & job.flag) - HTML += " \[High]" - else if(GetJobDepartment(job, 2) & job.flag) - HTML += " \[Medium]" - else if(GetJobDepartment(job, 3) & job.flag) - HTML += " \[Low]" - else - HTML += " \[NEVER]" - if(job.alt_titles) - HTML += "" - HTML += "" - - HTML += "
" - var/rank = job.title - lastJob = job - if(jobban_isbanned(user, rank)) - HTML += "[rank] \[BANNED]
\[IN [(available_in_days)] DAYS]
" - - HTML += "" - - if(rank == "Assistant")//Assistant is special - if(job_civilian_low & ASSISTANT) - HTML += " \[Yes]" - else - HTML += " \[No]" - if(job.alt_titles) //Blatantly cloned from a few lines down. - HTML += "
 \[[GetPlayerAltTitle(job)]\]
 \[[GetPlayerAltTitle(job)]\]
" - - HTML += "
" - - switch(alternate_option) - if(GET_RANDOM_JOB) - HTML += "

Get random job if preferences unavailable

" - if(BE_ASSISTANT) - HTML += "

Be assistant if preference unavailable

" - if(RETURN_TO_LOBBY) - HTML += "

Return to lobby if preference unavailable

" - - HTML += "
\[Reset\]
" - HTML += "
" - - user << browse(null, "window=preferences") - user << browse(HTML, "window=mob_occupation;size=[width]x[height]") - return - -/datum/preferences/proc/SetDisabilities(mob/user) - var/HTML = "" - HTML += "
" - HTML += "Choose disabilities
" - - HTML += "Need Glasses? [disabilities & (1<<0) ? "Yes" : "No"]
" - HTML += "Seizures? [disabilities & (1<<1) ? "Yes" : "No"]
" - HTML += "Coughing? [disabilities & (1<<2) ? "Yes" : "No"]
" - HTML += "Tourettes/Twitching? [disabilities & (1<<3) ? "Yes" : "No"]
" - HTML += "Nervousness? [disabilities & (1<<4) ? "Yes" : "No"]
" - HTML += "Deafness? [disabilities & (1<<5) ? "Yes" : "No"]
" - - HTML += "
" - HTML += "\[Done\]" - HTML += "
" - - user << browse(null, "window=preferences") - user << browse(HTML, "window=disabil;size=350x300") - return - -/datum/preferences/proc/SetRecords(mob/user) - var/HTML = "" - HTML += "
" - HTML += "Set Character Records
" - - HTML += "Medical Records
" - - HTML += TextPreview(med_record,40) - - HTML += "

Employment Records
" - - HTML += TextPreview(gen_record,40) - - HTML += "

Security Records
" - - HTML += TextPreview(sec_record,40) - - HTML += "
" - HTML += "\[Done\]" - HTML += "
" - - user << browse(null, "window=preferences") - user << browse(HTML, "window=records;size=350x300") - return - -/datum/preferences/proc/SetSpecies(mob/user) - if(!species_preview || !(species_preview in all_species)) - species_preview = "Human" - var/datum/species/current_species = all_species[species_preview] - var/dat = "" - dat += "

[current_species.name] \[change\]


" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
[current_species.blurb]" - if("preview" in icon_states(current_species.icobase)) - usr << browse_rsc(icon(current_species.icobase,"preview"), "species_preview_[current_species.name].png") - dat += "

" - dat += "Language: [current_species.language]
" - dat += "" - if(current_species.spawn_flags & CAN_JOIN) - dat += "
Often present on human stations." - if(current_species.spawn_flags & IS_WHITELISTED) - dat += "
Whitelist restricted." - if(current_species.flags & NO_BLOOD) - dat += "
Does not have blood." - if(current_species.flags & NO_BREATHE) - dat += "
Does not breathe." - if(current_species.flags & NO_SCAN) - dat += "
Does not have DNA." - if(current_species.flags & NO_PAIN) - dat += "
Does not feel pain." - if(current_species.flags & NO_SLIP) - dat += "
Has excellent traction." - if(current_species.flags & NO_POISON) - dat += "
Immune to most poisons." - if(current_species.appearance_flags & HAS_SKIN_TONE) - dat += "
Has a variety of skin tones." - if(current_species.appearance_flags & HAS_SKIN_COLOR) - dat += "
Has a variety of skin colours." - if(current_species.appearance_flags & HAS_EYE_COLOR) - dat += "
Has a variety of eye colours." - if(current_species.flags & IS_PLANT) - dat += "
Has a plantlike physiology." - dat += "

" - - var/restricted = 0 - if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it! - if(!(current_species.spawn_flags & CAN_JOIN)) - restricted = 2 - else if((current_species.spawn_flags & IS_WHITELISTED) && !is_alien_whitelisted(user,current_species)) - restricted = 1 - - if(restricted) - if(restricted == 1) - dat += "You cannot play as this species.
If you wish to be whitelisted, you can make an application post on the forums.

" - else if(restricted == 2) - dat += "You cannot play as this species.
This species is not available for play as a station race..

" - if(!restricted || check_rights(R_ADMIN, 0)) - dat += "\[select\]" - dat += "
" - - user << browse(null, "window=preferences") - user << browse(dat, "window=species;size=700x400") - -/datum/preferences/proc/SetAntagoptions(mob/user) - if(uplinklocation == "" || !uplinklocation) - uplinklocation = "PDA" - var/HTML = "" - HTML += "
" - HTML += "Antagonist Options
" - HTML += "
" - HTML +="Uplink Type : [uplinklocation]" - HTML +="
" - HTML +="Exploitable information about you : " - HTML += "
" - if(jobban_isbanned(user, "Records")) - HTML += "You are banned from using character records.
" - else - HTML +="[TextPreview(exploit_record,40)]" - HTML +="
" - HTML +="
" - HTML +="\[Done\]" - - HTML += "
" - - user << browse(null, "window=preferences") - user << browse(HTML, "window=antagoptions") - return - -/datum/preferences/proc/SetFlavorText(mob/user) - var/HTML = "" - HTML += "
" - HTML += "Set Flavour Text
" - HTML += "
" - HTML += "General: " - HTML += TextPreview(flavor_texts["general"]) - HTML += "
" - HTML += "Head: " - HTML += TextPreview(flavor_texts["head"]) - HTML += "
" - HTML += "Face: " - HTML += TextPreview(flavor_texts["face"]) - HTML += "
" - HTML += "Eyes: " - HTML += TextPreview(flavor_texts["eyes"]) - HTML += "
" - HTML += "Body: " - HTML += TextPreview(flavor_texts["torso"]) - HTML += "
" - HTML += "Arms: " - HTML += TextPreview(flavor_texts["arms"]) - HTML += "
" - HTML += "Hands: " - HTML += TextPreview(flavor_texts["hands"]) - HTML += "
" - HTML += "Legs: " - HTML += TextPreview(flavor_texts["legs"]) - HTML += "
" - HTML += "Feet: " - HTML += TextPreview(flavor_texts["feet"]) - HTML += "
" - HTML += "
" - HTML +="\[Done\]" - HTML += "" - user << browse(null, "window=preferences") - user << browse(HTML, "window=flavor_text;size=430x300") - return - -/datum/preferences/proc/SetFlavourTextRobot(mob/user) - var/HTML = "" - HTML += "
" - HTML += "Set Robot Flavour Text
" - HTML += "
" - HTML += "Default: " - HTML += TextPreview(flavour_texts_robot["Default"]) - HTML += "
" - for(var/module in robot_module_types) - HTML += "[module]: " - HTML += TextPreview(flavour_texts_robot[module]) - HTML += "
" - HTML += "
" - HTML +="\[Done\]" - HTML += "" - user << browse(null, "window=preferences") - user << browse(HTML, "window=flavour_text_robot;size=430x300") - return - -/datum/preferences/proc/GetPlayerAltTitle(datum/job/job) - return player_alt_titles.Find(job.title) > 0 \ - ? player_alt_titles[job.title] \ - : job.title - -/datum/preferences/proc/SetPlayerAltTitle(datum/job/job, new_title) - // remove existing entry - if(player_alt_titles.Find(job.title)) - player_alt_titles -= job.title - // add one if it's not default - if(job.title != new_title) - player_alt_titles[job.title] = new_title - -/datum/preferences/proc/SetJob(mob/user, role) - var/datum/job/job = job_master.GetJob(role) - if(!job) - user << browse(null, "window=mob_occupation") - ShowChoices(user) - return - - if(role == "Assistant") - if(job_civilian_low & job.flag) - job_civilian_low &= ~job.flag - else - job_civilian_low |= job.flag - SetChoices(user) - return 1 - - if(GetJobDepartment(job, 1) & job.flag) - SetJobDepartment(job, 1) - else if(GetJobDepartment(job, 2) & job.flag) - SetJobDepartment(job, 2) - else if(GetJobDepartment(job, 3) & job.flag) - SetJobDepartment(job, 3) - else//job = Never - SetJobDepartment(job, 4) - - SetChoices(user) - return 1 - -/datum/preferences/proc/ResetJobs() - job_civilian_high = 0 - job_civilian_med = 0 - job_civilian_low = 0 - - job_medsci_high = 0 - job_medsci_med = 0 - job_medsci_low = 0 - - job_engsec_high = 0 - job_engsec_med = 0 - job_engsec_low = 0 - - -/datum/preferences/proc/GetJobDepartment(var/datum/job/job, var/level) - if(!job || !level) return 0 - switch(job.department_flag) - if(CIVILIAN) - switch(level) - if(1) - return job_civilian_high - if(2) - return job_civilian_med - if(3) - return job_civilian_low - if(MEDSCI) - switch(level) - if(1) - return job_medsci_high - if(2) - return job_medsci_med - if(3) - return job_medsci_low - if(ENGSEC) - switch(level) - if(1) - return job_engsec_high - if(2) - return job_engsec_med - if(3) - return job_engsec_low - return 0 - -/datum/preferences/proc/SetJobDepartment(var/datum/job/job, var/level) - if(!job || !level) return 0 - switch(level) - if(1)//Only one of these should ever be active at once so clear them all here - job_civilian_high = 0 - job_medsci_high = 0 - job_engsec_high = 0 - return 1 - if(2)//Set current highs to med, then reset them - job_civilian_med |= job_civilian_high - job_medsci_med |= job_medsci_high - job_engsec_med |= job_engsec_high - job_civilian_high = 0 - job_medsci_high = 0 - job_engsec_high = 0 - - switch(job.department_flag) - if(CIVILIAN) - switch(level) - if(2) - job_civilian_high = job.flag - job_civilian_med &= ~job.flag - if(3) - job_civilian_med |= job.flag - job_civilian_low &= ~job.flag - else - job_civilian_low |= job.flag - if(MEDSCI) - switch(level) - if(2) - job_medsci_high = job.flag - job_medsci_med &= ~job.flag - if(3) - job_medsci_med |= job.flag - job_medsci_low &= ~job.flag - else - job_medsci_low |= job.flag - if(ENGSEC) - switch(level) - if(2) - job_engsec_high = job.flag - job_engsec_med &= ~job.flag - if(3) - job_engsec_med |= job.flag - job_engsec_low &= ~job.flag - else - job_engsec_low |= job.flag - return 1 + dat += "" + user << browse(dat, "window=preferences;size=625x736") /datum/preferences/proc/process_link(mob/user, list/href_list) if(!user) return @@ -913,778 +212,24 @@ datum/preferences else user << "The forum URL is not set in the server configuration." return - - if(href_list["preference"] == "job") - switch(href_list["task"]) - if("close") - user << browse(null, "window=mob_occupation") - ShowChoices(user) - if("reset") - ResetJobs() - SetChoices(user) - if("random") - if(alternate_option == GET_RANDOM_JOB || alternate_option == BE_ASSISTANT) - alternate_option += 1 - else if(alternate_option == RETURN_TO_LOBBY) - alternate_option = 0 - else - return 0 - SetChoices(user) - if ("alt_title") - var/datum/job/job = locate(href_list["job"]) - if (job) - var/choices = list(job.title) + job.alt_titles - var/choice = input("Pick a title for [job.title].", "Character Generation", GetPlayerAltTitle(job)) as anything in choices | null - if(choice) - SetPlayerAltTitle(job, choice) - SetChoices(user) - if("input") - SetJob(user, href_list["text"]) - else - SetChoices(user) - return 1 - else if(href_list["preference"] == "skills") - if(href_list["cancel"]) - user << browse(null, "window=show_skills") - ShowChoices(user) - else if(href_list["skillinfo"]) - var/datum/skill/S = locate(href_list["skillinfo"]) - var/HTML = "[S.name]
[S.desc]" - user << browse(HTML, "window=\ref[user]skillinfo") - else if(href_list["setskill"]) - var/datum/skill/S = locate(href_list["setskill"]) - var/value = text2num(href_list["newvalue"]) - skills[S.ID] = value - CalculateSkillPoints() - SetSkills(user) - else if(href_list["preconfigured"]) - var/selected = input(user, "Select a skillset", "Skillset") as null|anything in SKILL_PRE - if(!selected) return - - ZeroSkills(1) - for(var/V in SKILL_PRE[selected]) - if(V == "field") - skill_specialization = SKILL_PRE[selected]["field"] - continue - skills[V] = SKILL_PRE[selected][V] - CalculateSkillPoints() - - SetSkills(user) - else if(href_list["setspecialization"]) - skill_specialization = href_list["setspecialization"] - CalculateSkillPoints() - SetSkills(user) - else - SetSkills(user) - return 1 - - else if (href_list["preference"] == "loadout") - - if(href_list["task"] == "input") - - var/list/valid_gear_choices = list() - - for(var/gear_name in gear_datums) - var/datum/gear/G = gear_datums[gear_name] - if(G.whitelisted && !is_alien_whitelisted(user, G.whitelisted)) - continue - valid_gear_choices += gear_name - - var/choice = input(user, "Select gear to add: ") as null|anything in valid_gear_choices - - if(choice && gear_datums[choice]) - - var/total_cost = 0 - - if(isnull(gear) || !islist(gear)) gear = list() - - if(gear && gear.len) - for(var/gear_name in gear) - if(gear_datums[gear_name]) - var/datum/gear/G = gear_datums[gear_name] - total_cost += G.cost - - var/datum/gear/C = gear_datums[choice] - total_cost += C.cost - if(C && total_cost <= MAX_GEAR_COST) - gear += choice - user << "Added \the '[choice]' for [C.cost] points ([MAX_GEAR_COST - total_cost] points remaining)." - else - user << "Adding \the '[choice]' will exceed the maximum loadout cost of [MAX_GEAR_COST] points." - - else if(href_list["task"] == "remove") - var/i_remove = text2num(href_list["gear"]) - if(i_remove < 1 || i_remove > gear.len) return - gear.Cut(i_remove, i_remove + 1) - - else if(href_list["task"] == "clear") - gear.Cut() - - else if(href_list["preference"] == "flavor_text") - switch(href_list["task"]) - if("open") - SetFlavorText(user) - return - if("done") - user << browse(null, "window=flavor_text") - ShowChoices(user) - return - if("general") - var/msg = sanitize(input(usr,"Give a general description of your character. This will be shown regardless of clothing, and may include OOC notes and preferences.","Flavor Text",html_decode(flavor_texts[href_list["task"]])) as message, extra = 0) - flavor_texts[href_list["task"]] = msg - else - var/msg = sanitize(input(usr,"Set the flavor text for your [href_list["task"]].","Flavor Text",html_decode(flavor_texts[href_list["task"]])) as message, extra = 0) - flavor_texts[href_list["task"]] = msg - SetFlavorText(user) - return - - else if(href_list["preference"] == "flavour_text_robot") - switch(href_list["task"]) - if("open") - SetFlavourTextRobot(user) - return - if("done") - user << browse(null, "window=flavour_text_robot") - ShowChoices(user) - return - if("Default") - var/msg = sanitize(input(usr,"Set the default flavour text for your robot. It will be used for any module without individual setting.","Flavour Text",html_decode(flavour_texts_robot["Default"])) as message, extra = 0) - flavour_texts_robot[href_list["task"]] = msg - else - var/msg = sanitize(input(usr,"Set the flavour text for your robot with [href_list["task"]] module. If you leave this empty, default flavour text will be used for this module.","Flavour Text",html_decode(flavour_texts_robot[href_list["task"]])) as message, extra = 0) - flavour_texts_robot[href_list["task"]] = msg - SetFlavourTextRobot(user) - return - - else if(href_list["preference"] == "pAI") - paiController.recruitWindow(user, 0) - return 1 - - else if(href_list["preference"] == "records") - if(text2num(href_list["record"]) >= 1) - SetRecords(user) - return - else - user << browse(null, "window=records") - if(href_list["task"] == "med_record") - var/medmsg = sanitize(input(usr,"Set your medical notes here.","Medical Records",html_decode(med_record)) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) - if(medmsg != null) - med_record = medmsg - SetRecords(user) - - if(href_list["task"] == "sec_record") - var/secmsg = sanitize(input(usr,"Set your security notes here.","Security Records",html_decode(sec_record)) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) - if(secmsg != null) - sec_record = secmsg - SetRecords(user) - if(href_list["task"] == "gen_record") - var/genmsg = sanitize(input(usr,"Set your employment notes here.","Employment Records",html_decode(gen_record)) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) - if(genmsg != null) - gen_record = genmsg - SetRecords(user) - - if(href_list["task"] == "exploitable_record") - var/exploitmsg = sanitize(input(usr,"Set exploitable information about you here.","Exploitable Information",html_decode(exploit_record)) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) - if(exploitmsg != null) - exploit_record = exploitmsg - SetAntagoptions(user) - - else if (href_list["preference"] == "antagoptions") - if(text2num(href_list["active"]) == 0) - SetAntagoptions(user) - return - if (href_list["antagtask"] == "uplinktype") - if (uplinklocation == "PDA") - uplinklocation = "Headset" - else if(uplinklocation == "Headset") - uplinklocation = "None" - else - uplinklocation = "PDA" - SetAntagoptions(user) - if (href_list["antagtask"] == "done") - user << browse(null, "window=antagoptions") - ShowChoices(user) - return 1 - - else if (href_list["preference"] == "loadout") - - if(href_list["task"] == "input") - - var/list/valid_gear_choices = list() - - for(var/gear_name in gear_datums) - var/datum/gear/G = gear_datums[gear_name] - if(G.whitelisted && !is_alien_whitelisted(user, G.whitelisted)) - continue - valid_gear_choices += gear_name - - var/choice = input(user, "Select gear to add: ") as null|anything in valid_gear_choices - - if(choice && gear_datums[choice]) - - var/total_cost = 0 - - if(isnull(gear) || !islist(gear)) gear = list() - - if(gear && gear.len) - for(var/gear_name in gear) - if(gear_datums[gear_name]) - var/datum/gear/G = gear_datums[gear_name] - total_cost += G.cost - - var/datum/gear/C = gear_datums[choice] - total_cost += C.cost - if(C && total_cost <= MAX_GEAR_COST) - gear += choice - user << "\blue Added [choice] for [C.cost] points ([MAX_GEAR_COST - total_cost] points remaining)." - else - user << "\red That item will exceed the maximum loadout cost of [MAX_GEAR_COST] points." - - else if(href_list["task"] == "remove") - - if(isnull(gear) || !islist(gear)) - gear = list() - if(!gear.len) - return - - var/choice = input(user, "Select gear to remove: ") as null|anything in gear - if(!choice) - return - - for(var/gear_name in gear) - if(gear_name == choice) - gear -= gear_name - break - else if(href_list["preference"] == "language") - if(href_list["remove"]) - var/index = text2num(href_list["remove"]) - alternate_languages.Cut(index, index+1) - if(href_list["add"]) - var/datum/species/S = all_species[species] - if(alternate_languages.len >= S.num_alternate_languages) - alert(user, "You have already selected the maximum number of alternate languages for this species!") - else - var/list/available_languages = S.secondary_langs.Copy() - for(var/L in all_languages) - var/datum/language/lang = all_languages[L] - if(!(lang.flags & RESTRICTED) && (!config.usealienwhitelist || is_alien_whitelisted(user, L) || !(lang.flags & WHITELISTED))) - available_languages |= L - - // make sure we don't let them waste slots on the default languages - available_languages -= S.language - available_languages -= S.default_language - available_languages -= alternate_languages - - if(!available_languages.len) - alert(user, "There are no additional languages available to select.") - else - var/new_lang = input("Select an additional language", "Character Generation", null) as null|anything in available_languages - if(new_lang) - alternate_languages |= new_lang - - else if(href_list["preference"] == "language_prefix") - if(href_list["add"]) - var/char - var/keys[0] - do - char = input("Enter a single special character.\nYou may re-select the same characters.\nThe following characters are already in use by radio: ; : .\nThe following characters are already in use by special say commands: ! * ^", "Enter Character - [3 - keys.len] remaining") as null|text - if(char) - if(length(char) > 1) - alert("Only single characters allowed.", "Error", "Ok") - else if(char in list(";", ":", ".")) - alert("Radio character. Rejected.", "Error", "Ok") - else if(char in list("!","*", "^")) - alert("Say character. Rejected.", "Error", "Ok") - else if(contains_az09(char)) - alert("Non-special character. Rejected.", "Error", "Ok") - else - keys.Add(char) - while(char && keys.len < 3) - - if(keys.len == 3) - language_prefixes = keys - else if(href_list["reset"]) - language_prefixes = config.language_prefixes.Copy() - - switch(href_list["task"]) - if("change") - if(href_list["preference"] == "species") - // Actual whitelist checks are handled elsewhere, this is just for accessing the preview window. - var/choice = input("Which species would you like to look at?") as null|anything in playable_species - if(!choice) return - species_preview = choice - SetSpecies(user) - alternate_languages = list() // Reset their alternate languages. Todo: attempt to just fix it instead? - - if("random") - switch(href_list["preference"]) - if("name") - real_name = random_name(gender,species) - if("age") - age = rand(AGE_MIN, AGE_MAX) - if("hair") - r_hair = rand(0,255) - g_hair = rand(0,255) - b_hair = rand(0,255) - if("h_style") - h_style = random_hair_style(gender, species) - if("facial") - r_facial = rand(0,255) - g_facial = rand(0,255) - b_facial = rand(0,255) - if("f_style") - f_style = random_facial_hair_style(gender, species) - if("underwear") - var/r = pick(underwear_m) - underwear = underwear_m[r] - ShowChoices(user) - if("undershirt") - var/r = pick(undershirt_t) - undershirt = undershirt_t[r] - ShowChoices(user) - if("socks") - var/r = pick(socks_t) - socks = socks_t[r] - ShowChoices(user) - if("eyes") - r_eyes = rand(0,255) - g_eyes = rand(0,255) - b_eyes = rand(0,255) - if("s_tone") - s_tone = random_skin_tone() - if("s_color") - r_skin = rand(0,255) - g_skin = rand(0,255) - b_skin = rand(0,255) - if("bag") - backbag = rand(1,4) - /*if("skin_style") - h_style = random_skin_style(gender)*/ - if("all") - randomize_appearance_for() //no params needed - if("input") - switch(href_list["preference"]) - if("name") - var/raw_name = input(user, "Choose your character's name:", "Character Preference") as text|null - if (!isnull(raw_name)) // Check to ensure that the user entered text (rather than cancel.) - var/new_name = sanitizeName(raw_name) - if(new_name) - real_name = new_name - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." - - if("age") - var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null - if(new_age) - age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) - - if("species") - user << browse(null, "window=species") - var/prev_species = species - species = href_list["newspecies"] - if(prev_species != species) - //grab one of the valid hair styles for the newly chosen species - var/list/valid_hairstyles = list() - for(var/hairstyle in hair_styles_list) - var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - - if(valid_hairstyles.len) - h_style = pick(valid_hairstyles) - else - //this shouldn't happen - h_style = hair_styles_list["Bald"] - - //grab one of the valid facial hair styles for the newly chosen species - var/list/valid_facialhairstyles = list() - for(var/facialhairstyle in facial_hair_styles_list) - var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - - valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - - if(valid_facialhairstyles.len) - f_style = pick(valid_facialhairstyles) - else - //this shouldn't happen - f_style = facial_hair_styles_list["Shaved"] - - //reset hair colour and skin colour - r_hair = 0//hex2num(copytext(new_hair, 2, 4)) - g_hair = 0//hex2num(copytext(new_hair, 4, 6)) - b_hair = 0//hex2num(copytext(new_hair, 6, 8)) - - s_tone = 0 - - if("metadata") - var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null - if(new_metadata) - metadata = sanitize(new_metadata) - - if("b_type") - var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in list( "A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-" ) - if(new_b_type) - b_type = new_b_type - - if("hair") - var/datum/species/S = all_species[species] - if(S && (S.appearance_flags & HAS_HAIR_COLOR)) - var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference", rgb(r_hair, g_hair, b_hair)) as color|null - if(new_hair) - r_hair = hex2num(copytext(new_hair, 2, 4)) - g_hair = hex2num(copytext(new_hair, 4, 6)) - b_hair = hex2num(copytext(new_hair, 6, 8)) - - if("h_style") - var/list/valid_hairstyles = list() - for(var/hairstyle in hair_styles_list) - var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if( !(species in S.species_allowed)) - continue - - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - - var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles - if(new_h_style) - h_style = new_h_style - - if("facial") - var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(r_facial, g_facial, b_facial)) as color|null - if(new_facial) - r_facial = hex2num(copytext(new_facial, 2, 4)) - g_facial = hex2num(copytext(new_facial, 4, 6)) - b_facial = hex2num(copytext(new_facial, 6, 8)) - - if("f_style") - var/list/valid_facialhairstyles = list() - for(var/facialhairstyle in facial_hair_styles_list) - var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - - valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - - var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in valid_facialhairstyles - if(new_f_style) - f_style = new_f_style - - if("underwear") - var/list/underwear_options - if(gender == MALE) - underwear_options = underwear_m - else - underwear_options = underwear_f - - var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_options - if(new_underwear) - underwear = underwear_options[new_underwear] - ShowChoices(user) - - if("undershirt") - var/list/undershirt_options - undershirt_options = undershirt_t - - var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_options - if (new_undershirt) - undershirt = undershirt_options[new_undershirt] - ShowChoices(user) - - if("socks") - var/list/socks_options - socks_options = socks_t - - var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in socks_options - if (new_socks) - socks = socks_options[new_socks] - ShowChoices(user) - - if("eyes") - var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(r_eyes, g_eyes, b_eyes)) as color|null - if(new_eyes) - r_eyes = hex2num(copytext(new_eyes, 2, 4)) - g_eyes = hex2num(copytext(new_eyes, 4, 6)) - b_eyes = hex2num(copytext(new_eyes, 6, 8)) - - if("s_tone") - if(species != "Human") - return - var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference") as num|null - if(new_s_tone) - s_tone = 35 - max(min( round(new_s_tone), 220),1) - - if("skin") - var/datum/species/S = all_species[species] - if(S && (S.appearance_flags & HAS_SKIN_COLOR)) - var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(r_skin, g_skin, b_skin)) as color|null - if(new_skin) - r_skin = hex2num(copytext(new_skin, 2, 4)) - g_skin = hex2num(copytext(new_skin, 4, 6)) - b_skin = hex2num(copytext(new_skin, 6, 8)) - - if("ooccolor") - var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference") as color|null - if(new_ooccolor) - ooccolor = new_ooccolor - - if("bag") - var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in backbaglist - if(new_backbag) - backbag = backbaglist.Find(new_backbag) - - if("nt_relation") - var/new_relation = input(user, "Choose your relation to NT. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", "Character Preference") as null|anything in COMPANY_ALIGNMENTS - if(new_relation) - nanotrasen_relation = new_relation - - if("disabilities") - if(text2num(href_list["disabilities"]) >= -1) - if(text2num(href_list["disabilities"]) >= 0) - disabilities ^= (1<= 50)) return - UI_style_alpha = UI_style_alpha_new - - if("be_special") - var/num = text2num(href_list["num"]) - be_special ^= (1< 4 || backbag < 1) backbag = 1 //Same as above character.backbag = backbag diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 3c16144e83..66709917e0 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -47,26 +47,7 @@ save_character() return 0 - //general preferences - S["ooccolor"] >> ooccolor - S["lastchangelog"] >> lastchangelog - S["UI_style"] >> UI_style - S["be_special"] >> be_special - S["default_slot"] >> default_slot - S["toggles"] >> toggles - S["UI_style_color"] >> UI_style_color - S["UI_style_alpha"] >> UI_style_alpha - - //Sanitize - ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) - lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) - UI_style = sanitize_inlist(UI_style, all_ui_styles, initial(UI_style)) - be_special = sanitize_integer(be_special, 0, 65535, initial(be_special)) - default_slot = sanitize_integer(default_slot, 1, config.character_slots, initial(default_slot)) - toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) - UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color)) - UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha)) - + player_setup.load_preferences(S) return 1 /datum/preferences/proc/save_preferences() @@ -76,15 +57,7 @@ S.cd = "/" S["version"] << savefile_version - - //general preferences - S["ooccolor"] << ooccolor - S["lastchangelog"] << lastchangelog - S["UI_style"] << UI_style - S["be_special"] << be_special - S["default_slot"] << default_slot - S["toggles"] << toggles - + player_setup.save_preferences(S) return 1 /datum/preferences/proc/load_character(slot) @@ -100,184 +73,7 @@ S["default_slot"] << slot S.cd = "/character[slot]" - //Character - S["OOC_Notes"] >> metadata - S["real_name"] >> real_name - S["name_is_always_random"] >> be_random_name - S["gender"] >> gender - S["age"] >> age - S["species"] >> species - S["spawnpoint"] >> spawnpoint - - S["language"] >> alternate_languages - S["language_prefixes"] >> language_prefixes - if(isnull(alternate_languages)) - alternate_languages = list() - if(isnull(language_prefixes) || !language_prefixes.len) - language_prefixes = config.language_prefixes.Copy() - if(!islist(alternate_languages)) - if(client) - // Warn them that we (probably) just broke their languages - client << "Your current character slot's languages list has been updated from an old version, and may not be what you expect." - - if(alternate_languages in all_languages) - alternate_languages = list(alternate_languages) - else - alternate_languages = list() - - // try to give them their species language - var/datum/species/SP = all_species[species] - if(SP) - alternate_languages |= SP.language - alternate_languages |= SP.default_language - - // remove the Galcom that most races have as default_language - alternate_languages -= "Galactic Common" - - //colors to be consolidated into hex strings (requires some work with dna code) - S["hair_red"] >> r_hair - S["hair_green"] >> g_hair - S["hair_blue"] >> b_hair - S["facial_red"] >> r_facial - S["facial_green"] >> g_facial - S["facial_blue"] >> b_facial - S["skin_tone"] >> s_tone - S["skin_red"] >> r_skin - S["skin_green"] >> g_skin - S["skin_blue"] >> b_skin - S["hair_style_name"] >> h_style - S["facial_style_name"] >> f_style - S["eyes_red"] >> r_eyes - S["eyes_green"] >> g_eyes - S["eyes_blue"] >> b_eyes - S["underwear"] >> underwear - S["undershirt"] >> undershirt - S["socks"] >> socks - S["backbag"] >> backbag - S["b_type"] >> b_type - - //Jobs - S["alternate_option"] >> alternate_option - S["job_civilian_high"] >> job_civilian_high - S["job_civilian_med"] >> job_civilian_med - S["job_civilian_low"] >> job_civilian_low - S["job_medsci_high"] >> job_medsci_high - S["job_medsci_med"] >> job_medsci_med - S["job_medsci_low"] >> job_medsci_low - S["job_engsec_high"] >> job_engsec_high - S["job_engsec_med"] >> job_engsec_med - S["job_engsec_low"] >> job_engsec_low - - //Flavour Text - S["flavor_texts_general"] >> flavor_texts["general"] - S["flavor_texts_head"] >> flavor_texts["head"] - S["flavor_texts_face"] >> flavor_texts["face"] - S["flavor_texts_eyes"] >> flavor_texts["eyes"] - S["flavor_texts_torso"] >> flavor_texts["torso"] - S["flavor_texts_arms"] >> flavor_texts["arms"] - S["flavor_texts_hands"] >> flavor_texts["hands"] - S["flavor_texts_legs"] >> flavor_texts["legs"] - S["flavor_texts_feet"] >> flavor_texts["feet"] - - //Flavour text for robots. - S["flavour_texts_robot_Default"] >> flavour_texts_robot["Default"] - for(var/module in robot_module_types) - S["flavour_texts_robot_[module]"] >> flavour_texts_robot[module] - - //Miscellaneous - S["med_record"] >> med_record - S["sec_record"] >> sec_record - S["gen_record"] >> gen_record - S["be_special"] >> be_special - S["disabilities"] >> disabilities - S["player_alt_titles"] >> player_alt_titles - S["used_skillpoints"] >> used_skillpoints - S["skills"] >> skills - S["skill_specialization"] >> skill_specialization - S["organ_data"] >> organ_data - S["rlimb_data"] >> rlimb_data - S["gear"] >> gear - S["home_system"] >> home_system - S["citizenship"] >> citizenship - S["faction"] >> faction - S["religion"] >> religion - - S["nanotrasen_relation"] >> nanotrasen_relation - //S["skin_style"] >> skin_style - - S["uplinklocation"] >> uplinklocation - S["exploit_record"] >> exploit_record - - S["UI_style_color"] << UI_style_color - S["UI_style_alpha"] << UI_style_alpha - - //Sanitize - metadata = sanitize_text(metadata, initial(metadata)) - real_name = sanitizeName(real_name) - - if(isnull(species) || !(species in playable_species)) - species = "Human" - - if(isnum(underwear)) - var/list/undies = gender == MALE ? underwear_m : underwear_f - underwear = undies[undies[underwear]] - - if(isnum(undershirt)) - undershirt = undershirt_t[undershirt_t[undershirt]] - - if(isnum(socks)) - socks = socks_t[socks_t[socks]] - - if(isnull(alternate_languages)) alternate_languages = list() - if(isnull(spawnpoint)) spawnpoint = "Arrivals Shuttle" - if(isnull(nanotrasen_relation)) nanotrasen_relation = initial(nanotrasen_relation) - if(!real_name) real_name = random_name(gender) - be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) - gender = sanitize_gender(gender) - age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age)) - r_hair = sanitize_integer(r_hair, 0, 255, initial(r_hair)) - g_hair = sanitize_integer(g_hair, 0, 255, initial(g_hair)) - b_hair = sanitize_integer(b_hair, 0, 255, initial(b_hair)) - r_facial = sanitize_integer(r_facial, 0, 255, initial(r_facial)) - g_facial = sanitize_integer(g_facial, 0, 255, initial(g_facial)) - b_facial = sanitize_integer(b_facial, 0, 255, initial(b_facial)) - s_tone = sanitize_integer(s_tone, -185, 34, initial(s_tone)) - r_skin = sanitize_integer(r_skin, 0, 255, initial(r_skin)) - g_skin = sanitize_integer(g_skin, 0, 255, initial(g_skin)) - b_skin = sanitize_integer(b_skin, 0, 255, initial(b_skin)) - h_style = sanitize_inlist(h_style, hair_styles_list, initial(h_style)) - f_style = sanitize_inlist(f_style, facial_hair_styles_list, initial(f_style)) - r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes)) - g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes)) - b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes)) - backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag)) - b_type = sanitize_text(b_type, initial(b_type)) - - alternate_option = sanitize_integer(alternate_option, 0, 2, initial(alternate_option)) - job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high)) - job_civilian_med = sanitize_integer(job_civilian_med, 0, 65535, initial(job_civilian_med)) - job_civilian_low = sanitize_integer(job_civilian_low, 0, 65535, initial(job_civilian_low)) - job_medsci_high = sanitize_integer(job_medsci_high, 0, 65535, initial(job_medsci_high)) - job_medsci_med = sanitize_integer(job_medsci_med, 0, 65535, initial(job_medsci_med)) - job_medsci_low = sanitize_integer(job_medsci_low, 0, 65535, initial(job_medsci_low)) - job_engsec_high = sanitize_integer(job_engsec_high, 0, 65535, initial(job_engsec_high)) - job_engsec_med = sanitize_integer(job_engsec_med, 0, 65535, initial(job_engsec_med)) - job_engsec_low = sanitize_integer(job_engsec_low, 0, 65535, initial(job_engsec_low)) - - if(!skills) skills = list() - if(!used_skillpoints) used_skillpoints= 0 - if(isnull(disabilities)) disabilities = 0 - if(!player_alt_titles) player_alt_titles = new() - if(!organ_data) src.organ_data = list() - if(!rlimb_data) src.rlimb_data = list() - if(!gear) src.gear = list() - //if(!skin_style) skin_style = "Default" - - if(!home_system) home_system = "Unset" - if(!citizenship) citizenship = "None" - if(!faction) faction = "None" - if(!religion) religion = "None" - + player_setup.load_character(S) return 1 /datum/preferences/proc/save_character() @@ -286,92 +82,7 @@ if(!S) return 0 S.cd = "/character[default_slot]" - //Character - S["OOC_Notes"] << metadata - S["real_name"] << real_name - S["name_is_always_random"] << be_random_name - S["gender"] << gender - S["age"] << age - S["species"] << species - S["language"] << alternate_languages - S["language_prefixes"] << language_prefixes - S["hair_red"] << r_hair - S["hair_green"] << g_hair - S["hair_blue"] << b_hair - S["facial_red"] << r_facial - S["facial_green"] << g_facial - S["facial_blue"] << b_facial - S["skin_tone"] << s_tone - S["skin_red"] << r_skin - S["skin_green"] << g_skin - S["skin_blue"] << b_skin - S["hair_style_name"] << h_style - S["facial_style_name"] << f_style - S["eyes_red"] << r_eyes - S["eyes_green"] << g_eyes - S["eyes_blue"] << b_eyes - S["underwear"] << underwear - S["undershirt"] << undershirt - S["socks"] << socks - S["backbag"] << backbag - S["b_type"] << b_type - S["spawnpoint"] << spawnpoint - - //Jobs - S["alternate_option"] << alternate_option - S["job_civilian_high"] << job_civilian_high - S["job_civilian_med"] << job_civilian_med - S["job_civilian_low"] << job_civilian_low - S["job_medsci_high"] << job_medsci_high - S["job_medsci_med"] << job_medsci_med - S["job_medsci_low"] << job_medsci_low - S["job_engsec_high"] << job_engsec_high - S["job_engsec_med"] << job_engsec_med - S["job_engsec_low"] << job_engsec_low - - //Flavour Text - S["flavor_texts_general"] << flavor_texts["general"] - S["flavor_texts_head"] << flavor_texts["head"] - S["flavor_texts_face"] << flavor_texts["face"] - S["flavor_texts_eyes"] << flavor_texts["eyes"] - S["flavor_texts_torso"] << flavor_texts["torso"] - S["flavor_texts_arms"] << flavor_texts["arms"] - S["flavor_texts_hands"] << flavor_texts["hands"] - S["flavor_texts_legs"] << flavor_texts["legs"] - S["flavor_texts_feet"] << flavor_texts["feet"] - - //Flavour text for robots. - S["flavour_texts_robot_Default"] << flavour_texts_robot["Default"] - for(var/module in robot_module_types) - S["flavour_texts_robot_[module]"] << flavour_texts_robot[module] - - //Miscellaneous - S["med_record"] << med_record - S["sec_record"] << sec_record - S["gen_record"] << gen_record - S["player_alt_titles"] << player_alt_titles - S["be_special"] << be_special - S["disabilities"] << disabilities - S["used_skillpoints"] << used_skillpoints - S["skills"] << skills - S["skill_specialization"] << skill_specialization - S["organ_data"] << organ_data - S["rlimb_data"] << rlimb_data - S["gear"] << gear - S["home_system"] << home_system - S["citizenship"] << citizenship - S["faction"] << faction - S["religion"] << religion - - S["nanotrasen_relation"] << nanotrasen_relation - //S["skin_style"] << skin_style - - S["uplinklocation"] << uplinklocation - S["exploit_record"] << exploit_record - - S["UI_style_color"] << UI_style_color - S["UI_style_alpha"] << UI_style_alpha - + player_setup.save_character(S) return 1 diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 34546662c3..6b8bc2c4d3 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -1,11 +1,7 @@ datum/preferences //The mob should have a gender you want before running this proc. Will run fine without H proc/randomize_appearance_for(var/mob/living/carbon/human/H) - if(H) - if(H.gender == MALE) - gender = MALE - else - gender = FEMALE + gender = pick(MALE, FEMALE) s_tone = random_skin_tone() h_style = random_hair_style(gender, species) f_style = random_facial_hair_style(gender, species) diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index 995105a2bc..87bfc76176 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -33,7 +33,7 @@ return 1 if(href_list["skin_tone"]) if(can_change_skin_tone()) - var/new_s_tone = input(usr, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", owner.s_tone) as num|null + var/new_s_tone = input(usr, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", -owner.s_tone + 35) as num|null if(isnum(new_s_tone) && can_still_topic(state)) new_s_tone = 35 - max(min( round(new_s_tone), 220),1) return owner.change_skin_tone(new_s_tone)