Character Setup Rework (#17576)

* Character Setup Rework

Little tweaks

Species selection done~

Merk randomize body button

Body color and eye color

Merk more replaced code

Convert robolimbs to tgui

Add a warning if flavor text/ooc notes are too short

Custom preview icons for species selector!

A sidequest that only took 8
hours. Also add digitigrade and blood type.

Remove unused body_descriptor system completely

Finish the general tab~

Reorganization to prepare for loadout page creation

* Start of work on the loadout screen

* Only send the data that's actually selected

* Get rid of these ugly ../../../..

* Retype this to avoid conflicts

* Holy shit why did this work this way

* Finish loadout screen

* Add copy loadout function

* Finish occupation page

* Move Special Roles into general tab

* Fix path conflict

* Move size prefs to general tab

* Convert jukebox and volume settings to datum/preference

* Fix a little mergery fuckery in loadout

* Migrate jukebox to new range

* Fix TabbedMenu tabs

* Fix wordwrap for loadout screen

* Kill the vore tab, just traits left to convert

* Convert custom messages

* Convert custom species name

* Convert blood color and reagents

* Move icobase to tgui

* Finished

* This can fuck off too

* Fix a few bugs

* Update index.tsx

* initial for emote sound mode switch

* Make show_roles actually work, hide fluff items

* Fix not being able to select species

* Add emote_sound_mode to body tab

* Fix runtime when no active gear list is present

* Add a save notification to character setup

* Switch to floating

* Add more search bars

* Whoops forgot to add this

---------

Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
ShadowLarkens
2025-05-24 18:20:51 -07:00
committed by GitHub
parent 44d1ce470e
commit 31e8e009db
106 changed files with 8770 additions and 4739 deletions
@@ -1,7 +1,14 @@
#define AUTOHISS_OFF 0
#define AUTOHISS_BASIC 1
#define AUTOHISS_FULL 2
/datum/preferences
var/biological_gender = MALE
var/identifying_gender = MALE
var/vore_egg_type = "Egg" //The egg type they have.
var/autohiss = "Full" // VOREStation Add: Whether we have Autohiss on. I'm hijacking the egg panel bc this one has a shitton of unused space.
/datum/preferences/proc/set_biological_gender(var/gender)
biological_gender = gender
identifying_gender = gender
@@ -11,16 +18,20 @@
sort_order = 1
/datum/category_item/player_setup_item/general/basic/load_character(list/save_data)
pref.real_name = save_data["real_name"]
pref.nickname = save_data["nickname"]
pref.biological_gender = save_data["gender"]
pref.identifying_gender = save_data["id_gender"]
pref.real_name = save_data["real_name"]
pref.nickname = save_data["nickname"]
pref.biological_gender = save_data["gender"]
pref.identifying_gender = save_data["id_gender"]
pref.vore_egg_type = save_data["vore_egg_type"]
pref.autohiss = save_data["autohiss"]
/datum/category_item/player_setup_item/general/basic/save_character(list/save_data)
save_data["real_name"] = pref.real_name
save_data["nickname"] = pref.nickname
save_data["gender"] = pref.biological_gender
save_data["id_gender"] = pref.identifying_gender
save_data["vore_egg_type"] = pref.vore_egg_type
save_data["autohiss"] = pref.autohiss
/datum/category_item/player_setup_item/general/basic/sanitize_character()
pref.biological_gender = sanitize_inlist(pref.biological_gender, get_genders(), pick(get_genders()))
@@ -29,6 +40,8 @@
if(!pref.real_name)
pref.real_name = random_name(pref.identifying_gender, pref.species)
pref.nickname = sanitize_name(pref.nickname)
pref.vore_egg_type = sanitize_inlist(pref.vore_egg_type, GLOB.global_vore_egg_types, initial(pref.vore_egg_type))
pref.autohiss = sanitize_inlist(pref.autohiss, list("None", "Basic", "Full"), initial(pref.autohiss))
// Moved from /datum/preferences/proc/copy_to()
/datum/category_item/player_setup_item/general/basic/copy_to_mob(var/mob/living/carbon/human/character)
@@ -50,174 +63,232 @@
character.gender = pref.biological_gender
character.identifying_gender = pref.identifying_gender
/datum/category_item/player_setup_item/general/basic/content()
. = list()
. += span_bold("Name:") + " "
. += "<a href='byond://?src=\ref[src];rename=1'><b>[pref.real_name]</b></a><br>"
. += "<a href='byond://?src=\ref[src];random_name=1'>Randomize Name</A><br>"
. += "<a href='byond://?src=\ref[src];always_random_name=1'>Always Random Name: [pref.read_preference(/datum/preference/toggle/human/name_is_always_random) ? "Yes" : "No"]</a><br>"
. += span_bold("Nickname:") + " "
. += "<a href='byond://?src=\ref[src];nickname=1'><b>[pref.nickname]</b></a>"
. += "(<a href='byond://?src=\ref[src];reset_nickname=1'>Clear</A>)"
. += "<br>"
. += span_bold("Biological Sex:") + " <a href='byond://?src=\ref[src];bio_gender=1'><b>[gender2text(pref.biological_gender)]</b></a><br>"
. += span_bold("Pronouns:") + " <a href='byond://?src=\ref[src];id_gender=1'><b>[genders_to_pronoun_set[pref.identifying_gender]]</b></a><br>"
. += span_bold("Age:") + " <a href='byond://?src=\ref[src];age=1'>[pref.read_preference(/datum/preference/numeric/human/age)]</a> <b>Birthday:</b> <a href='byond://?src=\ref[src];bday_month=1'>[pref.read_preference(/datum/preference/numeric/human/bday_month)]</a><b>/</b><a href='byond://?src=\ref[src];bday_day=1'>[pref.read_preference(/datum/preference/numeric/human/bday_day)]</a> - <b>Announce?:</b> <a href='byond://?src=\ref[src];bday_announce=1'>[pref.read_preference(/datum/preference/toggle/human/bday_announce) ? "Yes" : "Disabled"]</a><br>"
. += span_bold("Spawn Point:") + " <a href='byond://?src=\ref[src];spawnpoint=1'>[pref.read_preference(/datum/preference/choiced/living/spawnpoint)]</a><br>"
if(CONFIG_GET(flag/allow_metadata))
. += span_bold("OOC Notes: <a href='byond://?src=\ref[src];edit_ooc_notes=1'>Edit</a><a href='byond://?src=\ref[src];edit_ooc_note_favs=1'>Favs</a><a href='byond://?src=\ref[src];edit_ooc_note_likes=1'>Likes</a><a href='byond://?src=\ref[src];edit_ooc_note_maybes=1'>Maybes</a><a href='byond://?src=\ref[src];edit_ooc_note_dislikes=1'>Dislikes</a>") + "<br>"
. += "Detailed field or short list system? <a href='byond://?src=\ref[src];edit_ooc_note_style=1'>[pref.read_preference(/datum/preference/toggle/living/ooc_notes_style) ? "Lists" : "Fields"]</a><br><br>"
. = jointext(.,null)
character.vore_egg_type = pref.vore_egg_type
// VOREStation Add
if(pref.client) // Safety, just in case so we don't runtime.
if(!pref.autohiss)
pref.client.autohiss_mode = AUTOHISS_FULL
else
switch(pref.autohiss)
if("Full")
pref.client.autohiss_mode = AUTOHISS_FULL
if("Basic")
pref.client.autohiss_mode = AUTOHISS_BASIC
if("Off")
pref.client.autohiss_mode = AUTOHISS_OFF
/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 = tgui_input_text(user, "Choose your character's name:", "Character Name")
if (!isnull(raw_name) && CanUseTopic(user))
var/new_name = sanitize_name(raw_name, pref.species, is_FBP())
if(new_name)
pref.real_name = new_name
return TOPIC_REFRESH
else
to_chat(user, span_warning("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
/datum/category_item/player_setup_item/general/basic/tgui_data(mob/user)
var/list/data = ..()
else if(href_list["random_name"])
pref.real_name = random_name(pref.identifying_gender, pref.species)
return TOPIC_REFRESH
data["real_name"] = pref.real_name
data["be_random_name"] = pref.read_preference(/datum/preference/toggle/human/name_is_always_random)
data["nickname"] = pref.nickname
data["biological_sex"] = gender2text(pref.biological_gender)
data["identifying_gender"] = gender2text(pref.identifying_gender)
data["age"] = pref.read_preference(/datum/preference/numeric/human/age)
data["bday_month"] = pref.read_preference(/datum/preference/numeric/human/bday_month)
data["bday_day"] = pref.read_preference(/datum/preference/numeric/human/bday_day)
data["bday_announce"] = pref.read_preference(/datum/preference/toggle/human/bday_announce)
data["spawnpoint"] = pref.read_preference(/datum/preference/choiced/living/spawnpoint)
data["ooc_notes_length"] = LAZYLEN(pref.read_preference(/datum/preference/text/living/ooc_notes))
data["vore_egg_type"] = pref.vore_egg_type
data["autohiss"] = pref.autohiss
data["emote_sound_mode"] = pref.read_preference(/datum/preference/choiced/living/emote_sound_mode)
else if(href_list["always_random_name"])
pref.update_preference_by_type(/datum/preference/toggle/human/name_is_always_random, !pref.read_preference(/datum/preference/toggle/human/name_is_always_random))
return TOPIC_REFRESH
return data
else if(href_list["nickname"])
var/raw_nickname = tgui_input_text(user, "Choose your character's nickname:", "Character Nickname", pref.nickname)
if (!isnull(raw_nickname) && CanUseTopic(user))
var/new_nickname = sanitize_name(raw_nickname, pref.species, is_FBP())
if(new_nickname)
pref.nickname = new_nickname
return TOPIC_REFRESH
else
to_chat(user, span_warning("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
/datum/category_item/player_setup_item/general/basic/tgui_static_data(mob/user)
var/list/data = ..()
else if(href_list["reset_nickname"])
var/nick_choice = tgui_alert(user, "Wipe your Nickname? This will completely remove any chosen nickname(s).","Wipe Nickname",list("Yes","No"))
if(nick_choice == "Yes")
pref.nickname = null
return TOPIC_REFRESH
data["allow_metadata"] = CONFIG_GET(flag/allow_metadata)
else if(href_list["bio_gender"])
var/new_gender = tgui_input_list(user, "Choose your character's biological sex:", "Character Preference", get_genders(), pref.biological_gender)
if(new_gender && CanUseTopic(user))
pref.set_biological_gender(new_gender)
return TOPIC_REFRESH_UPDATE_PREVIEW
return data
else if(href_list["id_gender"])
var/new_gender = tgui_input_list(user, "Choose your character's pronouns:", "Character Preference", pronoun_set_to_genders, genders_to_pronoun_set[pref.identifying_gender])
if(new_gender && CanUseTopic(user))
pref.identifying_gender = pronoun_set_to_genders[new_gender]
return TOPIC_REFRESH
/datum/category_item/player_setup_item/general/basic/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
else if(href_list["age"])
var/min_age = get_min_age()
var/max_age = get_max_age()
var/new_age = tgui_input_number(user, "Choose your character's age:\n([min_age]-[max_age])", "Character Preference", pref.read_preference(/datum/preference/numeric/human/age), max_age, min_age)
if(new_age && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/numeric/human/age, max(min(round(text2num(new_age)), max_age), min_age))
var/mob/user = ui.user
switch(action)
if("rename")
var/raw_name = tgui_input_text(user, "Choose your character's name:", "Character Name", pref.real_name)
if(!isnull(raw_name))
var/new_name = sanitize_name(raw_name, pref.species, is_FBP())
if(new_name)
pref.real_name = new_name
return TOPIC_REFRESH
else
to_chat(user, span_warning("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
if("random_name")
pref.real_name = random_name(pref.identifying_gender, pref.species)
return TOPIC_REFRESH
else if(href_list["bday_month"])
var/new_month = tgui_input_number(user, "Choose your character's birth month (number)", "Birthday Month", pref.read_preference(/datum/preference/numeric/human/bday_month), 12, 0)
if(new_month && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/numeric/human/bday_month, new_month)
else if((tgui_alert(user, "Would you like to clear the birthday entry?","Clear?",list("No","Yes")) == "Yes") && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/numeric/human/bday_month, 0)
pref.update_preference_by_type(/datum/preference/numeric/human/bday_day, 0)
return TOPIC_REFRESH
if("always_random_name")
pref.update_preference_by_type(/datum/preference/toggle/human/name_is_always_random, !pref.read_preference(/datum/preference/toggle/human/name_is_always_random))
return TOPIC_REFRESH
else if(href_list["bday_day"])
if(!pref.read_preference(/datum/preference/numeric/human/bday_month))
tgui_alert(user,"You must set a birth month before you can set a day.", "Error", list("Okay"))
return
var/max_days
switch(pref.read_preference(/datum/preference/numeric/human/bday_month))
if(1)
max_days = 31
if(2)
max_days = 29
if(3)
max_days = 31
if(4)
max_days = 30
if(5)
max_days = 31
if(6)
max_days = 30
if(7)
max_days = 31
if(8)
max_days = 31
if(9)
max_days = 30
if(10)
max_days = 31
if(11)
max_days = 30
if(12)
max_days = 31
if("nickname")
var/raw_nickname = tgui_input_text(user, "Choose your character's nickname:", "Character Nickname", pref.nickname)
if(!isnull(raw_nickname))
var/new_nickname = sanitize_name(raw_nickname, pref.species, is_FBP())
if(new_nickname)
pref.nickname = new_nickname
return TOPIC_REFRESH
else
to_chat(user, span_warning("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
var/new_day = tgui_input_number(user, "Choose your character's birth day (number, 1-[max_days])", "Birthday Day", pref.read_preference(/datum/preference/numeric/human/bday_day), max_days, 0)
if(new_day && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/numeric/human/bday_day, new_day)
else if((tgui_alert(user, "Would you like to clear the birthday entry?","Clear?",list("No","Yes")) == "Yes") && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/numeric/human/bday_month, 0)
pref.update_preference_by_type(/datum/preference/numeric/human/bday_day, 0)
return TOPIC_REFRESH
if("reset_nickname")
var/nick_choice = tgui_alert(user, "Wipe your Nickname? This will completely remove any chosen nickname(s).","Wipe Nickname",list("Yes","No"))
if(nick_choice == "Yes")
pref.nickname = null
return TOPIC_REFRESH
else if(href_list["bday_announce"])
pref.update_preference_by_type(/datum/preference/toggle/human/bday_announce, !pref.read_preference(/datum/preference/toggle/human/bday_announce))
return TOPIC_REFRESH
if("bio_gender")
var/new_gender = lowertext(params["gender"])
if(new_gender in get_genders())
pref.set_biological_gender(new_gender)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["spawnpoint"])
var/list/spawnkeys = list()
for(var/spawntype in spawntypes)
spawnkeys += spawntype
var/choice = tgui_input_list(user, "Where would you like to spawn when late-joining?", "Late-Join Choice", spawnkeys)
if(!choice || !spawntypes[choice] || !CanUseTopic(user)) return TOPIC_NOACTION
pref.update_preference_by_type(/datum/preference/choiced/living/spawnpoint, choice)
return TOPIC_REFRESH
if("id_gender")
var/new_gender = lowertext(params["gender"])
if(new_gender in all_genders_define_list)
pref.identifying_gender = new_gender
return TOPIC_REFRESH
if("age")
var/min_age = get_min_age()
var/max_age = get_max_age()
var/new_age = tgui_input_number(user, "Choose your character's age:\n([min_age]-[max_age])", "Character Preference", pref.read_preference(/datum/preference/numeric/human/age), max_age, min_age)
if(new_age)
pref.update_preference_by_type(/datum/preference/numeric/human/age, max(min(round(text2num(new_age)), max_age), min_age))
return TOPIC_REFRESH
if("bday_month")
var/new_month = tgui_input_number(user, "Choose your character's birth month (number)", "Birthday Month", pref.read_preference(/datum/preference/numeric/human/bday_month), 12, 0)
if(new_month)
pref.update_preference_by_type(/datum/preference/numeric/human/bday_month, new_month)
else if((tgui_alert(user, "Would you like to clear the birthday entry?","Clear?",list("No","Yes")) == "Yes"))
pref.update_preference_by_type(/datum/preference/numeric/human/bday_month, 0)
pref.update_preference_by_type(/datum/preference/numeric/human/bday_day, 0)
if("bday_day")
if(!pref.read_preference(/datum/preference/numeric/human/bday_month))
tgui_alert(user,"You must set a birth month before you can set a day.", "Error", list("Okay"))
return
var/max_days
switch(pref.read_preference(/datum/preference/numeric/human/bday_month))
if(1)
max_days = 31
if(2)
max_days = 29
if(3)
max_days = 31
if(4)
max_days = 30
if(5)
max_days = 31
if(6)
max_days = 30
if(7)
max_days = 31
if(8)
max_days = 31
if(9)
max_days = 30
if(10)
max_days = 31
if(11)
max_days = 30
if(12)
max_days = 31
var/new_day = tgui_input_number(user, "Choose your character's birth day (number, 1-[max_days])", "Birthday Day", pref.read_preference(/datum/preference/numeric/human/bday_day), max_days, 0)
if(new_day)
pref.update_preference_by_type(/datum/preference/numeric/human/bday_day, new_day)
else if((tgui_alert(user, "Would you like to clear the birthday entry?","Clear?",list("No","Yes")) == "Yes"))
pref.update_preference_by_type(/datum/preference/numeric/human/bday_month, 0)
pref.update_preference_by_type(/datum/preference/numeric/human/bday_day, 0)
return TOPIC_REFRESH
if("bday_announce")
pref.update_preference_by_type(/datum/preference/toggle/human/bday_announce, !pref.read_preference(/datum/preference/toggle/human/bday_announce))
return TOPIC_REFRESH
if("spawnpoint")
var/list/spawnkeys = list()
for(var/spawntype in spawntypes)
spawnkeys += spawntype
var/choice = tgui_input_list(user, "Where would you like to spawn when late-joining?", "Late-Join Choice", spawnkeys)
if(!choice || !spawntypes[choice])
return TOPIC_NOACTION
pref.update_preference_by_type(/datum/preference/choiced/living/spawnpoint, choice)
return TOPIC_REFRESH
if("edit_ooc_notes")
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see, such as Roleplay-preferences. This will not be saved permanently unless you click save in the Character Setup panel!", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata)
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes, new_metadata)
if("edit_ooc_note_favs")
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see relating to your FAVOURITE roleplay preferences. This will not be saved permanently unless you click save in the Character Setup panel! Type \"!clear\" to empty.", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes_favs)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata)
if(new_metadata == "!clear")
new_metadata = ""
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes_favs, new_metadata)
if("edit_ooc_note_likes")
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see relating to your LIKED roleplay preferences. This will not be saved permanently unless you click save in the Character Setup panel! Type \"!clear\" to empty.", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes_likes)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata)
if(new_metadata == "!clear")
new_metadata = ""
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes_likes, new_metadata)
if("edit_ooc_note_maybes")
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see relating to your MAYBE roleplay preferences. This will not be saved permanently unless you click save in the Character Setup panel! Type \"!clear\" to empty.", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes_maybes)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata && CanUseTopic(user))
if(new_metadata == "!clear")
new_metadata = ""
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes_maybes, new_metadata)
if("edit_ooc_note_dislikes")
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see relating to your DISLIKED roleplay preferences. This will not be saved permanently unless you click save in the Character Setup panel! Type \"!clear\" to empty.", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes_dislikes)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata)
if(new_metadata == "!clear")
new_metadata = ""
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes_dislikes, new_metadata)
if("edit_ooc_note_style")
pref.update_preference_by_type(/datum/preference/toggle/living/ooc_notes_style, !pref.read_preference(/datum/preference/toggle/living/ooc_notes_style))
return TOPIC_REFRESH
if("vore_egg_type")
var/list/vore_egg_types = GLOB.global_vore_egg_types
var/selection = tgui_input_list(user, "Choose your character's egg type:", "Character Preference", vore_egg_types, pref.vore_egg_type)
if(selection)
pref.vore_egg_type = selection
return TOPIC_REFRESH
if("autohiss")
var/list/autohiss_selection = list("Full", "Basic", "Off")
var/selection = tgui_input_list(user, "Choose your default autohiss setting:", "Character Preference", autohiss_selection, pref.autohiss)
if(selection)
pref.autohiss = selection
else if(!selection)
pref.autohiss = "Full"
return TOPIC_REFRESH
if("emote_sound_mode")
var/datum/preference/choiced/living/emote_sound_mode = GLOB.preference_entries_by_key["emote_sound_mode"]
var/selection = tgui_input_list(user, "Choose your emote sound mode", "Emote Sound Mode", emote_sound_mode.get_choices())
if(selection)
pref.update_preference(emote_sound_mode, selection)
return TOPIC_REFRESH
else if(href_list["edit_ooc_notes"])
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see, such as Roleplay-preferences. This will not be saved permanently unless you click save in the Character Setup panel!", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes, new_metadata)
else if(href_list["edit_ooc_note_likes"])
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see relating to your LIKED roleplay preferences. This will not be saved permanently unless you click save in the Character Setup panel! Type \"!clear\" to empty.", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes_likes)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata && CanUseTopic(user))
if(new_metadata == "!clear")
new_metadata = ""
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes_likes, new_metadata)
else if(href_list["edit_ooc_note_dislikes"])
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see relating to your DISLIKED roleplay preferences. This will not be saved permanently unless you click save in the Character Setup panel! Type \"!clear\" to empty.", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes_dislikes)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata && CanUseTopic(user))
if(new_metadata == "!clear")
new_metadata = ""
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes_dislikes, new_metadata)
else if(href_list["edit_ooc_note_favs"])
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see relating to your FAVOURITE roleplay preferences. This will not be saved permanently unless you click save in the Character Setup panel! Type \"!clear\" to empty.", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes_favs)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata && CanUseTopic(user))
if(new_metadata == "!clear")
new_metadata = ""
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes_favs, new_metadata)
else if(href_list["edit_ooc_note_maybes"])
var/new_metadata = strip_html_simple(tgui_input_text(user, "Enter any information you'd like others to see relating to your MAYBE roleplay preferences. This will not be saved permanently unless you click save in the Character Setup panel! Type \"!clear\" to empty.", "Game Preference" , html_decode(pref.read_preference(/datum/preference/text/living/ooc_notes_maybes)), multiline = TRUE, prevent_enter = TRUE))
if(new_metadata && CanUseTopic(user))
if(new_metadata == "!clear")
new_metadata = ""
pref.update_preference_by_type(/datum/preference/text/living/ooc_notes_maybes, new_metadata)
else if(href_list["edit_ooc_note_style"])
pref.update_preference_by_type(/datum/preference/toggle/living/ooc_notes_style, !pref.read_preference(/datum/preference/toggle/living/ooc_notes_style))
return TOPIC_REFRESH
return ..()
/datum/category_item/player_setup_item/general/basic/proc/get_genders()
@@ -232,3 +303,7 @@
possible_genders = possible_genders.Copy()
possible_genders |= NEUTER
return possible_genders
#undef AUTOHISS_OFF
#undef AUTOHISS_BASIC
#undef AUTOHISS_FULL
@@ -68,42 +68,59 @@
pref.runechat_color = sanitize_hexcolor(pref.runechat_color, COLOR_BLACK)
/datum/category_item/player_setup_item/general/language/content()
. += span_bold("Languages") + "<br>"
/datum/category_item/player_setup_item/general/language/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
var/list/languages_list = list()
var/datum/species/S = GLOB.all_species[pref.species]
if(pref.alternate_languages.len > (S.num_alternate_languages + pref.extra_languages))
testing("LANGSANI: Truncated [pref.client]'s character [pref.real_name || "-name not yet loaded-"] language list because it was too long (len: [pref.alternate_languages.len], allowed: [S.num_alternate_languages])")
pref.alternate_languages.len = (S.num_alternate_languages + pref.extra_languages) // Truncate to allowed length
if(S.language)
. += "- [S.language] - <a href='byond://?src=\ref[src];set_custom_key=[S.language]'>Set Custom Key</a><br>"
UNTYPED_LIST_ADD(languages_list, list(
"name" = S.language,
"removable" = FALSE
))
if(S.default_language && S.default_language != S.language)
. += "- [S.default_language] - <a href='byond://?src=\ref[src];set_custom_key=[S.default_language]'>Set Custom Key</a><br>"
if(S.num_alternate_languages + pref.extra_languages)
if(pref.alternate_languages.len)
for(var/i = 1 to pref.alternate_languages.len)
var/lang = pref.alternate_languages[i]
. += "- [lang] - <a href='byond://?src=\ref[src];remove_language=[i]'>remove</a> - <a href='byond://?src=\ref[src];set_custom_key=[lang]'>Set Custom Key</a><br>"
UNTYPED_LIST_ADD(languages_list, list(
"name" = S.default_language,
"removable" = FALSE
))
for(var/lang in pref.alternate_languages)
UNTYPED_LIST_ADD(languages_list, list(
"name" = lang,
"removable" = TRUE
))
if(pref.alternate_languages.len < (S.num_alternate_languages + pref.extra_languages))
. += "- <a href='byond://?src=\ref[src];add_language=1'>add</a> ([(S.num_alternate_languages + pref.extra_languages) - pref.alternate_languages.len] remaining)<br>"
else
. += "- [pref.species] cannot choose secondary languages.<br>"
data["languages"] = languages_list
. += span_bold("Language Keys") + "<br>"
. += " [jointext(pref.language_prefixes, " ")] <a href='byond://?src=\ref[src];change_prefix=1'>Change</a> <a href='byond://?src=\ref[src];reset_prefix=1'>Reset</a><br>"
. += span_bold("Preferred Language") + " <a href='byond://?src=\ref[src];pref_lang=1'>[pref.preferred_language]</a><br>" // VOREStation Add
. += span_bold("Runechat Color") + " <a href='byond://?src=\ref[src];pref_runechat_color=1'>Change Runechat Color</a> [color_square(hex = pref.runechat_color)]"
data["languages_can_add"] = LAZYLEN(pref.alternate_languages) < (S.num_alternate_languages + pref.extra_languages)
data["language_keys"] = pref.language_prefixes
data["preferred_language"] = pref.preferred_language
data["runechat_color"] = pref.runechat_color
return data
/datum/category_item/player_setup_item/general/language/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
var/mob/user = ui.user
var/datum/species/S = GLOB.all_species[pref.species]
switch(action)
if("remove_language")
var/lang_to_remove = params["lang"]
var/index = pref.alternate_languages.Find(lang_to_remove)
if(!index)
return TOPIC_REFRESH
pref.alternate_languages.Cut(index, index+1)
return TOPIC_REFRESH
if("add_language")
if(pref.alternate_languages.len >= (S.num_alternate_languages + pref.extra_languages))
tgui_alert_async(user, "You have already selected the maximum number of alternate languages for this species!")
return TOPIC_REFRESH
/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 = GLOB.all_species[pref.species]
if(pref.alternate_languages.len >= (S.num_alternate_languages + pref.extra_languages))
tgui_alert_async(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 GLOB.all_languages)
var/datum/language/lang = GLOB.all_languages[L]
@@ -117,74 +134,73 @@
if(!available_languages.len)
tgui_alert_async(user, "There are no additional languages available to select.")
else
var/new_lang = tgui_input_list(user, "Select an additional language", "Character Generation", available_languages)
if(new_lang && pref.alternate_languages.len < (S.num_alternate_languages + pref.extra_languages))
var/datum/language/chosen_lang = GLOB.all_languages[new_lang]
if(istype(chosen_lang))
var/choice = tgui_alert(user, "[chosen_lang.desc]",chosen_lang.name, list("Take","Cancel"))
if(choice != "Cancel" && pref.alternate_languages.len < (S.num_alternate_languages + pref.extra_languages))
pref.alternate_languages |= new_lang
return TOPIC_REFRESH
return TOPIC_REFRESH
else if(href_list["change_prefix"])
var/char
var/keys[0]
do
char = tgui_input_text(user, "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")
if(char)
if(length(char) > 1)
tgui_alert_async(user, "Only single characters allowed.", "Error")
else if(char in list(";", ":", "."))
tgui_alert_async(user, "Radio character. Rejected.", "Error")
else if(char in list("!","*","^","-"))
tgui_alert_async(user, "Say character. Rejected.", "Error")
else if(contains_az09(char))
tgui_alert_async(user, "Non-special character. Rejected.", "Error")
else
keys.Add(char)
while(char && keys.len < 3)
var/new_lang = tgui_input_list(user, "Select an additional language", "Character Generation", available_languages)
if(new_lang && pref.alternate_languages.len < (S.num_alternate_languages + pref.extra_languages))
var/datum/language/chosen_lang = GLOB.all_languages[new_lang]
if(istype(chosen_lang))
var/choice = tgui_alert(user, "[chosen_lang.desc]",chosen_lang.name, list("Take","Cancel"))
if(choice != "Cancel" && pref.alternate_languages.len < (S.num_alternate_languages + pref.extra_languages))
pref.alternate_languages |= new_lang
return TOPIC_REFRESH
if(keys.len == 3)
pref.language_prefixes = keys
return TOPIC_REFRESH
else if(href_list["reset_prefix"])
var/list/prefixes = CONFIG_GET(str_list/language_prefixes)
pref.language_prefixes = prefixes.Copy()
return TOPIC_REFRESH
if("change_prefix")
var/char
var/keys[0]
do
char = tgui_input_text(user, "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")
if(char)
if(length(char) > 1)
tgui_alert_async(user, "Only single characters allowed.", "Error")
else if(char in list(";", ":", "."))
tgui_alert_async(user, "Radio character. Rejected.", "Error")
else if(char in list("!","*","^","-"))
tgui_alert_async(user, "Say character. Rejected.", "Error")
else if(contains_az09(char))
tgui_alert_async(user, "Non-special character. Rejected.", "Error")
else
keys.Add(char)
while(char && keys.len < 3)
else if(href_list["set_custom_key"])
var/lang = href_list["set_custom_key"]
if(!(lang in GLOB.all_languages))
if(keys.len == 3)
pref.language_prefixes = keys
return TOPIC_REFRESH
if("reset_prefix")
var/list/prefixes = CONFIG_GET(str_list/language_prefixes)
pref.language_prefixes = prefixes.Copy()
return TOPIC_REFRESH
var/oldkey = ""
for(var/key in pref.language_custom_keys)
if(pref.language_custom_keys[key] == lang)
oldkey = key
break
if("set_custom_key")
var/lang = params["lang"]
if(!(lang in GLOB.all_languages))
return TOPIC_REFRESH
var/char = tgui_input_text(user, "Input a language key for [lang]. Input a single space to reset.", "Language Custom Key", oldkey)
if(length(char) != 1)
return TOPIC_REFRESH
else if(char == " ")
var/oldkey = ""
for(var/key in pref.language_custom_keys)
if(pref.language_custom_keys[key] == lang)
pref.language_custom_keys -= key
oldkey = key
break
else if(contains_az09(char))
if(!(char in pref.language_custom_keys))
pref.language_custom_keys += char
pref.language_custom_keys[char] = lang
else
tgui_alert_async(user, "Improper language key. Rejected.", "Error")
return TOPIC_REFRESH
var/char = tgui_input_text(user, "Input a language key for [lang]. Input a single space to reset.", "Language Custom Key", oldkey)
if(length(char) != 1)
return TOPIC_REFRESH
else if(char == " ")
for(var/key in pref.language_custom_keys)
if(pref.language_custom_keys[key] == lang)
pref.language_custom_keys -= key
break
else if(contains_az09(char))
if(!(char in pref.language_custom_keys))
pref.language_custom_keys += char
pref.language_custom_keys[char] = lang
else
tgui_alert_async(user, "Improper language key. Rejected.", "Error")
// VOREStation Add: Preferred Language
else if(href_list["pref_lang"])
if(pref.species) // Safety to prevent a null runtime here
var/datum/species/S = GLOB.all_species[pref.species]
return TOPIC_REFRESH
if("pref_lang")
var/list/lang_opts = list(S.language) + pref.alternate_languages + LANGUAGE_GALCOM
var/selection = tgui_input_list(user, "Choose your preferred spoken language:", "Preferred Spoken Language", lang_opts, pref.preferred_language)
if(!selection) // Set our preferred to default, just in case.
@@ -196,19 +212,15 @@
else // Did they set anything else?
tgui_alert_async(user, "You will now speak [pref.preferred_language] if you do not specify a language when speaking.", "Preferred Language Set")
return TOPIC_REFRESH
// VOREStation Add End
else if(href_list["pref_runechat_color"])
var/new_runechat_color = tgui_color_picker(user, "Choose your character's runechat colour (#000000 for random):", "Character Preference", pref.runechat_color)
if(new_runechat_color && CanUseTopic(user))
pref.runechat_color = new_runechat_color
// whenever we change this, we update our mob
var/mob/pref_mob = preference_mob()
if(pref_mob)
pref_mob.chat_color = new_runechat_color
pref_mob.chat_color_darkened = new_runechat_color
pref_mob.chat_color_name = pref_mob.name
return TOPIC_REFRESH
return ..()
if("pref_runechat_color")
var/new_runechat_color = tgui_color_picker(user, "Choose your character's runechat colour (#000000 for random):", "Character Preference", pref.runechat_color)
if(new_runechat_color)
pref.runechat_color = new_runechat_color
// whenever we change this, we update our mob
var/mob/pref_mob = preference_mob()
if(pref_mob)
pref_mob.chat_color = new_runechat_color
pref_mob.chat_color_darkened = new_runechat_color
pref_mob.chat_color_name = pref_mob.name
return TOPIC_REFRESH
File diff suppressed because it is too large Load Diff
@@ -1,225 +0,0 @@
/datum/preferences
var/list/all_underwear
var/list/all_underwear_metadata
/datum/category_item/player_setup_item/general/equipment
name = "Clothing"
sort_order = 4
/datum/category_item/player_setup_item/general/equipment/load_character(list/save_data)
pref.all_underwear = check_list_copy(save_data["all_underwear"])
pref.all_underwear_metadata = check_list_copy(save_data["all_underwear_metadata"])
for(var/i in pref.all_underwear_metadata)
pref.all_underwear_metadata[i] = path2text_list(pref.all_underwear_metadata[i])
pref.headset = save_data["headset"]
pref.backbag = save_data["backbag"]
pref.pdachoice = save_data["pdachoice"]
pref.communicator_visibility = save_data["communicator_visibility"]
pref.ringtone = save_data["ringtone"]
pref.shoe_hater = save_data["shoe_hater"]
pref.no_jacket = save_data["no_jacket"]
/datum/category_item/player_setup_item/general/equipment/save_character(list/save_data)
save_data["all_underwear"] = pref.all_underwear
var/list/underwear = list()
for(var/i in pref.all_underwear_metadata)
underwear[i] = check_list_copy(pref.all_underwear_metadata[i])
save_data["all_underwear_metadata"] = underwear
save_data["headset"] = pref.headset
save_data["backbag"] = pref.backbag
save_data["pdachoice"] = pref.pdachoice
save_data["communicator_visibility"] = pref.communicator_visibility
save_data["ringtone"] = pref.ringtone
save_data["shoe_hater"] = pref.shoe_hater
save_data["no_jacket"] = pref.no_jacket
var/global/list/valid_ringtones = list(
"beep",
"boom",
"slip",
"honk",
"SKREE",
"xeno",
"spark",
"rad",
"servo",
"buh-boop",
"trombone",
"whistle",
"chirp",
"slurp",
"pwing",
"clack",
"bzzt",
"chimes",
"prbt",
"bark",
"bork",
"roark",
"chitter",
"squish"
)
// Moved from /datum/preferences/proc/copy_to()
/datum/category_item/player_setup_item/general/equipment/copy_to_mob(var/mob/living/carbon/human/character)
character.all_underwear.Cut()
character.all_underwear_metadata.Cut()
for(var/underwear_category_name in pref.all_underwear)
var/datum/category_group/underwear/underwear_category = global_underwear.categories_by_name[underwear_category_name]
if(underwear_category)
var/underwear_item_name = pref.all_underwear[underwear_category_name]
character.all_underwear[underwear_category_name] = underwear_category.items_by_name[underwear_item_name]
if(pref.all_underwear_metadata[underwear_category_name])
character.all_underwear_metadata[underwear_category_name] = pref.all_underwear_metadata[underwear_category_name]
else
pref.all_underwear -= underwear_category_name
// TODO - Looks like this is duplicating the work of sanitize_character() if so, remove
if(pref.headset > GLOB.headsetlist.len || pref.headset < 1)
pref.headset = 1 //Same as above
character.headset = pref.headset
if(pref.backbag > backbaglist.len || pref.backbag < 1)
pref.backbag = 2 //Same as above
character.backbag = pref.backbag
if(pref.pdachoice > 8 || pref.pdachoice < 1)
pref.pdachoice = 1
character.pdachoice = pref.pdachoice
/datum/category_item/player_setup_item/general/equipment/sanitize_character()
if(!islist(pref.gear)) pref.gear = list()
if(!istype(pref.all_underwear))
pref.all_underwear = list()
for(var/datum/category_group/underwear/WRC in global_underwear.categories)
for(var/datum/category_item/underwear/WRI in WRC.items)
if(WRI.is_default(pref.identifying_gender ? pref.identifying_gender : MALE))
pref.all_underwear[WRC.name] = WRI.name
break
if(!istype(pref.all_underwear_metadata))
pref.all_underwear_metadata = list()
for(var/underwear_category in pref.all_underwear)
var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[underwear_category]
if(!UWC)
pref.all_underwear -= underwear_category
else
var/datum/category_item/underwear/UWI = UWC.items_by_name[pref.all_underwear[underwear_category]]
if(!UWI)
pref.all_underwear -= underwear_category
for(var/underwear_metadata in pref.all_underwear_metadata)
if(!(underwear_metadata in pref.all_underwear))
pref.all_underwear_metadata -= underwear_metadata
pref.headset = sanitize_integer(pref.headset, 1, GLOB.headsetlist.len, initial(pref.headset))
pref.backbag = sanitize_integer(pref.backbag, 1, backbaglist.len, initial(pref.backbag))
pref.pdachoice = sanitize_integer(pref.pdachoice, 1, pdachoicelist.len, initial(pref.pdachoice))
pref.ringtone = sanitize(pref.ringtone, 20)
/datum/category_item/player_setup_item/general/equipment/content()
. = list()
. += span_bold("Equipment:") + "<br>"
for(var/datum/category_group/underwear/UWC in global_underwear.categories)
var/item_name = pref.all_underwear[UWC.name] ? pref.all_underwear[UWC.name] : "None"
. += "[UWC.name]: <a href='byond://?src=\ref[src];change_underwear=[UWC.name]'><b>[item_name]</b></a>"
var/datum/category_item/underwear/UWI = UWC.items_by_name[item_name]
if(UWI)
for(var/datum/gear_tweak/gt in UWI.tweaks)
. += " <a href='byond://?src=\ref[src];underwear=[UWC.name];tweak=\ref[gt]'>[gt.get_contents(get_metadata(UWC.name, gt))]</a>"
. += "<br>"
. += "Headset Type: <a href='byond://?src=\ref[src];change_headset=1'><b>[GLOB.headsetlist[pref.headset]]</b></a><br>"
. += "Backpack Type: <a href='byond://?src=\ref[src];change_backpack=1'><b>[backbaglist[pref.backbag]]</b></a><br>"
. += "PDA Type: <a href='byond://?src=\ref[src];change_pda=1'><b>[pdachoicelist[pref.pdachoice]]</b></a><br>"
. += "Communicator Visibility: <a href='byond://?src=\ref[src];toggle_comm_visibility=1'><b>[(pref.communicator_visibility) ? "Yes" : "No"]</b></a><br>"
. += "Ringtone (leave blank for job default): <a href='byond://?src=\ref[src];set_ringtone=1'><b>[pref.ringtone]</b></a><br>"
. += "Spawn With Shoes:<a href='byond://?src=\ref[src];toggle_shoes=1'><b>[(pref.shoe_hater) ? "No" : "Yes"]</b></a><br>"
. += "Spawn With Jacket:<a href='byond://?src=\ref[src];toggle_jacket=1'><b>[(pref.no_jacket) ? "No" : "Yes"]</b></a><br>"
return jointext(.,null)
/datum/category_item/player_setup_item/general/equipment/proc/get_metadata(var/underwear_category, var/datum/gear_tweak/gt)
var/metadata = pref.all_underwear_metadata[underwear_category]
if(!metadata)
metadata = list()
pref.all_underwear_metadata[underwear_category] = metadata
var/tweak_data = metadata["[gt]"]
if(!tweak_data)
tweak_data = gt.get_default()
metadata["[gt]"] = tweak_data
return tweak_data
/datum/category_item/player_setup_item/general/equipment/proc/set_metadata(var/underwear_category, var/datum/gear_tweak/gt, var/new_metadata)
var/list/metadata = pref.all_underwear_metadata[underwear_category]
metadata["[gt]"] = new_metadata
/datum/category_item/player_setup_item/general/equipment/OnTopic(var/href,var/list/href_list, var/mob/user)
if(href_list["change_headset"])
var/new_headset = tgui_input_list(user, "Choose your character's style of headset:", "Character Preference", GLOB.headsetlist, GLOB.headsetlist[pref.headset])
if(!isnull(new_headset) && CanUseTopic(user))
pref.headset = GLOB.headsetlist.Find(new_headset)
return TOPIC_REFRESH_UPDATE_PREVIEW
if(href_list["change_backpack"])
var/new_backbag = tgui_input_list(user, "Choose your character's style of bag:", "Character Preference", backbaglist, backbaglist[pref.backbag])
if(!isnull(new_backbag) && CanUseTopic(user))
pref.backbag = backbaglist.Find(new_backbag)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["change_pda"])
var/new_pdachoice = tgui_input_list(user, "Choose your character's style of PDA:", "Character Preference", pdachoicelist, pdachoicelist[pref.pdachoice])
if(!isnull(new_pdachoice) && CanUseTopic(user))
pref.pdachoice = pdachoicelist.Find(new_pdachoice)
return TOPIC_REFRESH
else if(href_list["change_underwear"])
var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[href_list["change_underwear"]]
if(!UWC)
return
var/datum/category_item/underwear/selected_underwear = tgui_input_list(user, "Choose underwear:", "Character Preference", UWC.items, pref.all_underwear[UWC.name])
if(selected_underwear && CanUseTopic(user))
pref.all_underwear[UWC.name] = selected_underwear.name
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["underwear"] && href_list["tweak"])
var/underwear = href_list["underwear"]
if(!(underwear in pref.all_underwear))
return TOPIC_NOACTION
var/datum/gear_tweak/gt = locate(href_list["tweak"])
if(!gt)
return TOPIC_NOACTION
var/new_metadata = gt.get_metadata(user, get_metadata(underwear, gt))
if(new_metadata)
set_metadata(underwear, gt, new_metadata)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["toggle_comm_visibility"])
if(CanUseTopic(user))
pref.communicator_visibility = !pref.communicator_visibility
return TOPIC_REFRESH
else if(href_list["set_ringtone"])
var/choice = tgui_input_list(user, "Please select a ringtone. All of these choices come with an associated preset sound. Alternately, select \"Other\" to specify manually.", "Character Preference", valid_ringtones + "Other", pref.ringtone)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = sanitize(tgui_input_text(user, "Please enter a custom ringtone. If this doesn't match any of the other listed choices, your PDA will use the default (\"beep\") sound.", "Character Preference", null, 20), 20)
if(raw_choice && CanUseTopic(user))
pref.ringtone = raw_choice
else
pref.ringtone = choice
return TOPIC_REFRESH
else if(href_list["toggle_shoes"])
if(CanUseTopic(user))
pref.shoe_hater = !pref.shoe_hater
return TOPIC_REFRESH
else if(href_list["toggle_jacket"])
if(CanUseTopic(user))
pref.no_jacket = !pref.no_jacket
return TOPIC_REFRESH
return ..()
@@ -43,130 +43,133 @@
character.personal_faction = pref.faction
character.religion = pref.religion
/datum/category_item/player_setup_item/general/background/content(var/mob/user)
. += span_bold("Background Information") + "<br>"
. += "Economic Status: <a href='byond://?src=\ref[src];econ_status=1'>[pref.economic_status]</a><br/>"
. += "Home: <a href='byond://?src=\ref[src];home_system=1'>[pref.home_system]</a><br/>"
. += "Birthplace: <a href='byond://?src=\ref[src];birthplace=1'>[pref.birthplace]</a><br/>"
. += "Citizenship: <a href='byond://?src=\ref[src];citizenship=1'>[pref.citizenship]</a><br/>"
. += "Faction: <a href='byond://?src=\ref[src];faction=1'>[pref.faction]</a><br/>"
. += "Religion: <a href='byond://?src=\ref[src];religion=1'>[pref.religion]</a><br/>"
/datum/category_item/player_setup_item/general/background/tgui_data(mob/user)
var/list/data = ..()
data["economic_status"] = pref.economic_status
data["home_system"] = pref.home_system
data["birthplace"] = pref.birthplace
data["citizenship"] = pref.citizenship
data["faction"] = pref.faction
data["religion"] = pref.religion
data["ooc_note_style"] = pref.read_preference(/datum/preference/toggle/living/ooc_notes_style)
. += "<br/><b>Records</b>:<br/>"
if(jobban_isbanned(user, "Records"))
. += span_danger("You are banned from using character records.") + "<br>"
data["records_banned"] = TRUE
else
. += "Medical Records:<br>"
. += "<a href='byond://?src=\ref[src];set_medical_records=1'>[TextPreview(pref.med_record,40)]</a><br>"
. += " (<a href='byond://?src=\ref[src];reset_medrecord=1'>Reset</A>)<br><br>"
. += "Employment Records:<br>"
. += "<a href='byond://?src=\ref[src];set_general_records=1'>[TextPreview(pref.gen_record,40)]</a><br>"
. += "(<a href='byond://?src=\ref[src];reset_emprecord=1'>Reset</A>)<br><br>"
. += "Security Records:<br>"
. += "<a href='byond://?src=\ref[src];set_security_records=1'>[TextPreview(pref.sec_record,40)]</a><br>"
. += "(<a href='byond://?src=\ref[src];reset_secrecord=1'>Reset</A>)"
data["records_banned"] = FALSE
/datum/category_item/player_setup_item/general/background/OnTopic(var/href,var/list/href_list, var/mob/user)
if(href_list["econ_status"])
var/new_class = tgui_input_list(user, "Choose your economic status. This will affect the amount of money you will start with.", "Character Preference", ECONOMIC_CLASS, pref.economic_status)
if(new_class && CanUseTopic(user))
pref.economic_status = new_class
data["med_record"] = TextPreview(pref.med_record,40)
data["gen_record"] = TextPreview(pref.gen_record,40)
data["sec_record"] = TextPreview(pref.sec_record,40)
return data
/datum/category_item/player_setup_item/general/background/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
var/mob/user = ui.user
switch(action)
if("econ_status")
var/new_class = tgui_input_list(user, "Choose your economic status. This will affect the amount of money you will start with.", "Character Preference", ECONOMIC_CLASS, pref.economic_status)
if(new_class)
pref.economic_status = new_class
return TOPIC_REFRESH
if("home_system")
var/choice = tgui_input_list(user, "Please choose your home planet and/or system. This should be your current primary residence. Select \"Other\" to specify manually.", "Character Preference", home_system_choices + list("Unset","Other"), pref.home_system)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter a home system.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice)
pref.home_system = raw_choice
else
pref.home_system = choice
return TOPIC_REFRESH
else if(href_list["home_system"])
var/choice = tgui_input_list(user, "Please choose your home planet and/or system. This should be your current primary residence. Select \"Other\" to specify manually.", "Character Preference", home_system_choices + list("Unset","Other"), pref.home_system)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter a home system.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice && CanUseTopic(user))
pref.home_system = raw_choice
else
pref.home_system = choice
return TOPIC_REFRESH
if("birthplace")
var/choice = tgui_input_list(user, "Please choose the planet and/or system or other appropriate location that you were born/created. Select \"Other\" to specify manually.", "Character Preference", home_system_choices + list("Unset","Other"), pref.birthplace)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter a birthplace.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice)
pref.birthplace = raw_choice
else
pref.birthplace = choice
return TOPIC_REFRESH
else if(href_list["birthplace"])
var/choice = tgui_input_list(user, "Please choose the planet and/or system or other appropriate location that you were born/created. Select \"Other\" to specify manually.", "Character Preference", home_system_choices + list("Unset","Other"), pref.birthplace)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter a birthplace.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice && CanUseTopic(user))
pref.birthplace = raw_choice
else
pref.birthplace = choice
return TOPIC_REFRESH
if("citizenship")
var/choice = tgui_input_list(user, "Please select the faction or political entity with which you currently hold citizenship. Select \"Other\" to specify manually.", "Character Preference", citizenship_choices + list("None","Other"), pref.citizenship)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter your current citizenship.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice)
pref.citizenship = raw_choice
else
pref.citizenship = choice
return TOPIC_REFRESH
else if(href_list["citizenship"])
var/choice = tgui_input_list(user, "Please select the faction or political entity with which you currently hold citizenship. Select \"Other\" to specify manually.", "Character Preference", citizenship_choices + list("None","Other"), pref.citizenship)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter your current citizenship.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice && CanUseTopic(user))
pref.citizenship = raw_choice
else
pref.citizenship = choice
return TOPIC_REFRESH
if("faction")
var/choice = tgui_input_list(user, "Please choose the faction you primarily work for, if you are not under the direct employ of NanoTrasen. Select \"Other\" to specify manually.", "Character Preference", faction_choices + list("None","Other"), pref.faction)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter a faction.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice)
pref.faction = raw_choice
else
pref.faction = choice
return TOPIC_REFRESH
else if(href_list["faction"])
var/choice = tgui_input_list(user, "Please choose the faction you primarily work for, if you are not under the direct employ of NanoTrasen. Select \"Other\" to specify manually.", "Character Preference", faction_choices + list("None","Other"), pref.faction)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter a faction.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice)
pref.faction = raw_choice
else
pref.faction = choice
return TOPIC_REFRESH
if("religion")
var/choice = tgui_input_list(user, "Please choose a religion. Select \"Other\" to specify manually.", "Character Preference", religion_choices + list("None","Other"), pref.religion)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter a religon.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice)
pref.religion = sanitize(raw_choice)
else
pref.religion = choice
return TOPIC_REFRESH
else if(href_list["religion"])
var/choice = tgui_input_list(user, "Please choose a religion. Select \"Other\" to specify manually.", "Character Preference", religion_choices + list("None","Other"), pref.religion)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = strip_html_simple(tgui_input_text(user, "Please enter a religon.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice)
pref.religion = sanitize(raw_choice)
else
pref.religion = choice
return TOPIC_REFRESH
if("set_medical_records")
var/new_medical = strip_html_simple(tgui_input_text(user,"Enter medical information here.","Character Preference", html_decode(pref.med_record), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH)
if(new_medical && !jobban_isbanned(user, JOB_RECORDS))
pref.med_record = new_medical
return TOPIC_REFRESH
else if(href_list["set_medical_records"])
var/new_medical = strip_html_simple(tgui_input_text(user,"Enter medical information here.","Character Preference", html_decode(pref.med_record), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH)
if(new_medical && !jobban_isbanned(user, JOB_RECORDS) && CanUseTopic(user))
pref.med_record = new_medical
return TOPIC_REFRESH
if("set_general_records")
var/new_general = strip_html_simple(tgui_input_text(user,"Enter employment information here.","Character Preference", html_decode(pref.gen_record), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH)
if(new_general && !jobban_isbanned(user, JOB_RECORDS))
pref.gen_record = new_general
return TOPIC_REFRESH
else if(href_list["set_general_records"])
var/new_general = strip_html_simple(tgui_input_text(user,"Enter employment information here.","Character Preference", html_decode(pref.gen_record), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH)
if(new_general && !jobban_isbanned(user, JOB_RECORDS) && CanUseTopic(user))
pref.gen_record = new_general
return TOPIC_REFRESH
if("set_security_records")
var/sec_medical = strip_html_simple(tgui_input_text(user,"Enter security information here.","Character Preference", html_decode(pref.sec_record), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH)
if(sec_medical && !jobban_isbanned(user, JOB_RECORDS))
pref.sec_record = sec_medical
return TOPIC_REFRESH
else if(href_list["set_security_records"])
var/sec_medical = strip_html_simple(tgui_input_text(user,"Enter security information here.","Character Preference", html_decode(pref.sec_record), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH)
if(sec_medical && !jobban_isbanned(user, JOB_RECORDS) && CanUseTopic(user))
pref.sec_record = sec_medical
return TOPIC_REFRESH
if("reset_medrecord")
var/resetmed_choice = tgui_alert(user, "Wipe your Medical Records? This cannot be reverted if you have not saved your character recently! You may wish to make a backup first.","Reset Records",list("Yes","No"))
if(resetmed_choice == "Yes")
pref.med_record = null
return TOPIC_REFRESH
else if(href_list["reset_medrecord"])
var/resetmed_choice = tgui_alert(user, "Wipe your Medical Records? This cannot be reverted if you have not saved your character recently! You may wish to make a backup first.","Reset Records",list("Yes","No"))
if(resetmed_choice == "Yes")
pref.med_record = null
return TOPIC_REFRESH
if("reset_emprecord")
var/resetemp_choice = tgui_alert(user, "Wipe your Employment Records? This cannot be reverted if you have not saved your character recently! You may wish to make a backup first.","Reset Records",list("Yes","No"))
if(resetemp_choice == "Yes")
pref.gen_record = null
return TOPIC_REFRESH
else if(href_list["reset_emprecord"])
var/resetemp_choice = tgui_alert(user, "Wipe your Employment Records? This cannot be reverted if you have not saved your character recently! You may wish to make a backup first.","Reset Records",list("Yes","No"))
if(resetemp_choice == "Yes")
pref.gen_record = null
return TOPIC_REFRESH
else if(href_list["reset_secrecord"])
var/resetsec_choice = tgui_alert(user, "Wipe your Security Records? This cannot be reverted if you have not saved your character recently! You may wish to make a backup first.","Reset Records",list("Yes","No"))
if(resetsec_choice == "Yes")
pref.sec_record = null
return TOPIC_REFRESH
return ..()
if("reset_secrecord")
var/resetsec_choice = tgui_alert(user, "Wipe your Security Records? This cannot be reverted if you have not saved your character recently! You may wish to make a backup first.","Reset Records",list("Yes","No"))
if(resetsec_choice == "Yes")
pref.sec_record = null
return TOPIC_REFRESH
@@ -50,12 +50,37 @@
character.flavor_texts["feet"] = pref.flavor_texts["feet"]
character.custom_link = pref.custom_link
/datum/category_item/player_setup_item/general/flavor/content(var/mob/user)
. += span_bold("Flavor:") + "<br>"
. += "<a href='byond://?src=\ref[src];flavor_text=open'>Set Flavor Text</a><br/>"
. += "<a href='byond://?src=\ref[src];flavour_text_robot=open'>Set Robot Flavor Text</a><br/>"
. += "<a href='byond://?src=\ref[src];custom_link=1'>Set Custom Link</a><br/>"
/datum/category_item/player_setup_item/general/flavor/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
data["flavor_text_length"] = LAZYLEN(pref.flavor_texts["general"])
return data
/datum/category_item/player_setup_item/general/flavor/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
var/mob/user = ui.user
switch(action)
if("flavor_text")
SetFlavorText(user)
return TOPIC_HANDLED
if("flavour_text_robot")
SetFlavourTextRobot(user)
return TOPIC_HANDLED
if("custom_link")
var/new_link = strip_html_simple(tgui_input_text(user, "Enter a link to add on to your examine text! This should be a related image link/gallery, or things like your F-list. This is not the place for memes.", "Custom Link" , html_decode(pref.custom_link), max_length = 100, encode = TRUE, prevent_enter = TRUE))
if(new_link)
if(length(new_link) > 100)
to_chat(user, span_warning("Your entry is too long, it must be 100 characters or less."))
return
pref.custom_link = new_link
log_admin("[user]/[user.ckey] set their custom link to [pref.custom_link]")
// README: This must stay for SetFlavorText to work!
/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"])
@@ -75,7 +100,6 @@
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")
@@ -0,0 +1,128 @@
/datum/category_item/player_setup_item/general/basic_antagonism
name = "Basic"
sort_order = 7
var/datum/paiCandidate/candidate
/datum/category_item/player_setup_item/general/basic_antagonism/load_character(list/save_data)
pref.exploit_record = save_data["exploit_record"]
pref.antag_faction = save_data["antag_faction"]
pref.antag_vis = save_data["antag_vis"]
/datum/category_item/player_setup_item/general/basic_antagonism/save_character(list/save_data)
save_data["exploit_record"] = pref.exploit_record
save_data["antag_faction"] = pref.antag_faction
save_data["antag_vis"] = pref.antag_vis
/datum/category_item/player_setup_item/general/basic_antagonism/load_preferences(datum/json_savefile/savefile)
if(!candidate)
candidate = new()
var/preference_mob = preference_mob()
if(!preference_mob)// No preference mob - this happens when we're called from client/New() before it calls ..() (via datum/preferences/New())
spawn()
preference_mob = preference_mob()
if(!preference_mob)
return
candidate.savefile_load(preference_mob)
return
candidate.savefile_load(preference_mob)
/datum/category_item/player_setup_item/general/basic_antagonism/save_preferences(datum/json_savefile/savefile)
if(!candidate)
return
if(!preference_mob())
return
candidate.savefile_save(preference_mob())
/datum/category_item/player_setup_item/general/basic_antagonism/sanitize_character()
if(!pref.antag_faction) pref.antag_faction = "None"
if(!pref.antag_vis) pref.antag_vis = "Hidden"
// Moved from /datum/preferences/proc/copy_to()
/datum/category_item/player_setup_item/general/basic_antagonism/copy_to_mob(var/mob/living/carbon/human/character)
character.exploit_record = pref.exploit_record
character.antag_faction = pref.antag_faction
character.antag_vis = pref.antag_vis
/datum/category_item/player_setup_item/general/basic_antagonism/tgui_data(mob/user)
var/list/data = ..()
data["antag_faction"] = pref.antag_faction
data["antag_vis"] = pref.antag_vis
data["uplink_type"] = pref.read_preference(/datum/preference/choiced/uplinklocation)
data["record_banned"] = jobban_isbanned(user, "Records")
if(!jobban_isbanned(user, "Records"))
data["exploitable_record"] = TextPreview(pref.exploit_record, 40)
if(!candidate)
CRASH("[user] pAI prefs have a null candidate var.")
data["pai_name"] = candidate.name ? candidate.name : "None Set"
data["pai_desc"] = candidate.description ? TextPreview(candidate.description, 40) : "None Set"
data["pai_role"] = candidate.role ? TextPreview(candidate.role, 40) : "None Set"
data["pai_comments"] = candidate.comments ? TextPreview(candidate.comments, 40) : "None Set"
return data
/datum/category_item/player_setup_item/general/basic_antagonism/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
var/mob/user = ui.user
switch(action)
if("uplinklocation")
var/new_uplinklocation = tgui_input_list(user, "Choose your uplink location:", "Character Preference", GLOB.uplink_locations, pref.read_preference(/datum/preference/choiced/uplinklocation))
if(new_uplinklocation && CanUseTopic(user))
pref.update_preference_by_type(/datum/preference/choiced/uplinklocation, new_uplinklocation)
return TOPIC_REFRESH
if("exploitable_record")
var/exploitmsg = sanitize(tgui_input_text(user,"Set exploitable information about you here.","Exploitable Information", html_decode(pref.exploit_record), MAX_RECORD_LENGTH, TRUE, prevent_enter = TRUE), MAX_RECORD_LENGTH, extra = 0)
if(!isnull(exploitmsg) && !jobban_isbanned(user, "Records") && CanUseTopic(user))
pref.exploit_record = exploitmsg
return TOPIC_REFRESH
if("antagfaction")
var/choice = tgui_input_list(user, "Please choose an antagonistic faction to work for.", "Character Preference", antag_faction_choices + list("None","Other"), pref.antag_faction)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
if(choice == "Other")
var/raw_choice = sanitize(tgui_input_text(user, "Please enter a faction.", "Character Preference", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(raw_choice)
pref.antag_faction = raw_choice
else
pref.antag_faction = choice
return TOPIC_REFRESH
if("antagvis")
var/choice = tgui_input_list(user, "Please choose an antagonistic visibility level.", "Character Preference", antag_visiblity_choices, pref.antag_vis)
if(!choice || !CanUseTopic(user))
return TOPIC_NOACTION
else
pref.antag_vis = choice
return TOPIC_REFRESH
if("option")
var/t
switch(params["option"])
if("name")
t = sanitizeName(tgui_input_text(user, "Enter a name for your pAI", "Global Preference", candidate.name, MAX_NAME_LEN), MAX_NAME_LEN, 1)
if(t && CanUseTopic(user))
candidate.name = t
if("desc")
t = tgui_input_text(user, "Enter a description for your pAI", "Global Preference", html_decode(candidate.description), multiline = TRUE, prevent_enter = TRUE)
if(!isnull(t) && CanUseTopic(user))
candidate.description = sanitize(t)
if("role")
t = tgui_input_text(user, "Enter a role for your pAI", "Global Preference", html_decode(candidate.role))
if(!isnull(t) && CanUseTopic(user))
candidate.role = sanitize(t)
if("ooc")
t = tgui_input_text(user, "Enter any OOC comments", "Global Preference", html_decode(candidate.comments), multiline = TRUE, prevent_enter = TRUE)
if(!isnull(t) && CanUseTopic(user))
candidate.comments = sanitize(t)
return TOPIC_REFRESH
@@ -0,0 +1,81 @@
var/global/list/special_roles = list( //keep synced with the defines BE_* in setup.dm --rastaf
//some autodetection here.
// Change these to 0 if the equivalent mode is disabled for whatever reason!
"traitor" = 0, // 0
"operative" = 0, // 1
"changeling" = 0, // 2
"wizard" = 0, // 3
"malf AI" = 0, // 4
"revolutionary" = 0, // 5
"alien candidate" = 0, // 6
"positronic brain" = 1, // 7
"cultist" = 0, // 8
"renegade" = 0, // 9
"ninja" = 0, // 10
"raider" = 0, // 11
"diona" = 0, // 12
"mutineer" = 0, // 13
"loyalist" = 0, // 14
"pAI candidate" = 1, // 15
//VOREStation Add
"lost drone" = 1, // 16
"maint pred" = 1, // 17
"maint lurker" = 1, // 18
"morph" = 1, // 19
"corgi" = 1, // 20
"cursed sword" = 1, // 21
"Ship Survivor" = 1, // 22
//VOREStation Add End
)
/datum/category_item/player_setup_item/general/candidacy
name = "Candidacy"
sort_order = 8
/datum/category_item/player_setup_item/general/candidacy/load_character(list/save_data)
pref.be_special = save_data["be_special"]
/datum/category_item/player_setup_item/general/candidacy/save_character(list/save_data)
save_data["be_special"] = pref.be_special
/datum/category_item/player_setup_item/general/candidacy/sanitize_character()
pref.be_special = sanitize_integer(pref.be_special, 0, 16777215, initial(pref.be_special)) //VOREStation Edit - 24 bits of support
/datum/category_item/player_setup_item/general/candidacy/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("be_special")
var/num = text2num(params["be_special"])
pref.be_special ^= (1<<num)
return TOPIC_REFRESH
/datum/category_item/player_setup_item/general/candidacy/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
data["syndicate_ban"] = FALSE
if(jobban_isbanned(user, JOB_SYNDICATE))
data["syndicate_ban"] = TRUE
return
var/list/special_data = list()
var/n = 0
for(var/i in special_roles)
if(special_roles[i])
var/banned = FALSE
if(jobban_isbanned(user, i) || (i == "positronic brain" && jobban_isbanned(user, JOB_AI) && jobban_isbanned(user, JOB_CYBORG)) || (i == "pAI candidate" && jobban_isbanned(user, JOB_PAI)))
banned = TRUE
UNTYPED_LIST_ADD(special_data, list(
"idx" = n,
"name" = "Be [i]",
"selected" = pref.be_special & (1<<n),
"banned" = banned
))
n++
data["special_roles"] = special_data
return data
@@ -0,0 +1,305 @@
// Body weight limits on a character.
#define WEIGHT_CHANGE_MIN 0
#define WEIGHT_CHANGE_MAX 100
// Define a place to save in character setup
/datum/preferences
var/size_multiplier = RESIZE_NORMAL
// Body weight stuff.
var/weight_vr = 137 // bodyweight of character (pounds, because I'm not doing the math again -Spades)
var/weight_gain = 100 // Weight gain rate.
var/weight_loss = 50 // Weight loss rate.
var/fuzzy = 0 // Preference toggle for sharp/fuzzy icon. Default sharp.
var/offset_override = FALSE
var/voice_freq = 42500
var/voice_sound = "beep-boop"
var/custom_speech_bubble = "default"
var/custom_footstep = "Default"
var/species_sound = "Unset"
// Definition of the stuff for Sizing
/datum/category_item/player_setup_item/general/size
name = "Size"
sort_order = 9
/datum/category_item/player_setup_item/general/size/load_character(list/save_data)
pref.size_multiplier = save_data["size_multiplier"]
pref.weight_vr = save_data["weight_vr"]
pref.weight_gain = save_data["weight_gain"]
pref.weight_loss = save_data["weight_loss"]
pref.fuzzy = save_data["fuzzy"]
pref.offset_override = save_data["offset_override"]
pref.voice_freq = save_data["voice_freq"]
pref.voice_sound = save_data["voice_sound"]
pref.custom_speech_bubble = save_data["custom_speech_bubble"]
pref.custom_footstep = save_data["custom_footstep"]
pref.species_sound = save_data["species_sound"]
/datum/category_item/player_setup_item/general/size/save_character(list/save_data)
save_data["size_multiplier"] = pref.size_multiplier
save_data["weight_vr"] = pref.weight_vr
save_data["weight_gain"] = pref.weight_gain
save_data["weight_loss"] = pref.weight_loss
save_data["fuzzy"] = pref.fuzzy
save_data["offset_override"] = pref.offset_override
save_data["voice_freq"] = pref.voice_freq
save_data["voice_sound"] = pref.voice_sound
save_data["custom_speech_bubble"] = pref.custom_speech_bubble
save_data["custom_footstep"] = pref.custom_footstep
save_data["species_sound"] = pref.species_sound
/datum/category_item/player_setup_item/general/size/sanitize_character()
pref.weight_vr = sanitize_integer(pref.weight_vr, WEIGHT_MIN, WEIGHT_MAX, initial(pref.weight_vr))
pref.weight_gain = sanitize_integer(pref.weight_gain, WEIGHT_CHANGE_MIN, WEIGHT_CHANGE_MAX, initial(pref.weight_gain))
pref.weight_loss = sanitize_integer(pref.weight_loss, WEIGHT_CHANGE_MIN, WEIGHT_CHANGE_MAX, initial(pref.weight_loss))
pref.fuzzy = sanitize_integer(pref.fuzzy, 0, 1, initial(pref.fuzzy))
pref.offset_override = sanitize_integer(pref.offset_override, 0, 1, initial(pref.offset_override))
if(pref.voice_freq != 0)
pref.voice_freq = sanitize_integer(pref.voice_freq, MIN_VOICE_FREQ, MAX_VOICE_FREQ, initial(pref.fuzzy))
if(pref.size_multiplier == null || pref.size_multiplier < RESIZE_TINY || pref.size_multiplier > RESIZE_HUGE)
pref.size_multiplier = initial(pref.size_multiplier)
if(!(pref.custom_speech_bubble in GLOB.selectable_speech_bubbles))
pref.custom_speech_bubble = "default"
if(!(pref.custom_footstep))
pref.custom_footstep = "Default"
if(!(pref.species_sound))
pref.species_sound = "Unset"
/datum/category_item/player_setup_item/general/size/copy_to_mob(var/mob/living/carbon/human/character)
character.weight = pref.weight_vr
character.weight_gain = pref.weight_gain
character.weight_loss = pref.weight_loss
character.fuzzy = pref.fuzzy
character.offset_override = pref.offset_override
character.voice_freq = pref.voice_freq
character.resize(pref.size_multiplier, animate = FALSE, ignore_prefs = TRUE)
if(!pref.voice_sound)
character.voice_sounds_list = DEFAULT_TALK_SOUNDS
else
character.voice_sounds_list = get_talk_sound(pref.voice_sound)
character.custom_speech_bubble = pref.custom_speech_bubble
character.custom_footstep = pref.custom_footstep
/datum/category_item/player_setup_item/general/size/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
data["size_multiplier"] = round(pref.size_multiplier * 100)
data["fuzzy"] = pref.fuzzy
data["offset_override"] = pref.offset_override
data["voice_freq"] = pref.voice_freq
data["voice_sound"] = pref.voice_sound
data["custom_speech_bubble"] = pref.custom_speech_bubble
data["custom_footstep"] = pref.custom_footstep
data["custom_species_sound"] = pref.species_sound
data["weight_vr"] = pref.weight_vr
data["weight_gain"] = pref.weight_gain
data["weight_loss"] = pref.weight_loss
return data
/datum/category_item/player_setup_item/general/size/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
var/mob/user = ui.user
switch(action)
if("size_multiplier")
var/new_size = tgui_input_number(user, "Choose your character's size, ranging from [RESIZE_MINIMUM * 100]% to [RESIZE_MAXIMUM * 100]%", "Set Size", pref.size_multiplier * 100, RESIZE_MAXIMUM * 100, RESIZE_MINIMUM * 100)
if (!ISINRANGE(new_size, RESIZE_MINIMUM * 100, RESIZE_MAXIMUM * 100))
pref.size_multiplier = 1
to_chat(user, span_notice("Invalid size."))
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(new_size)
pref.size_multiplier = (new_size / 100)
return TOPIC_REFRESH_UPDATE_PREVIEW
if("toggle_fuzzy")
pref.fuzzy = pref.fuzzy ? 0 : 1;
return TOPIC_REFRESH_UPDATE_PREVIEW
if("toggle_offset_override")
pref.offset_override = pref.offset_override ? 0 : 1;
return TOPIC_REFRESH_UPDATE_PREVIEW
if("weight")
var/new_weight = tgui_input_number(user, "Choose your character's relative body weight.\n\
Note: Scifi characters come in all shapes and sizes in this game, and not all follow the traditional shape of a human. Like a naga or a taur or a giant will weigh a\n\
lot more than what this allows, or a micro will weigh a lot less. Just ignore all of that for a second and PRETEND the weight you're setting is visually for an \n\
average human. This is the best solution we have at the moment.!\n\
([WEIGHT_MIN]-[WEIGHT_MAX])", "Character Preference", null, WEIGHT_MAX, WEIGHT_MIN, round_value=FALSE)
if(new_weight)
var/unit_of_measurement = tgui_alert(user, "Is that number in pounds (lb) or kilograms (kg)?", "Confirmation", list("Pounds", "Kilograms"))
if(!unit_of_measurement)
return TOPIC_NOACTION
if(unit_of_measurement == "Pounds")
new_weight = round(text2num(new_weight),4)
if(unit_of_measurement == "Kilograms")
new_weight = round(2.20462*text2num(new_weight),4)
pref.weight_vr = sanitize_integer(new_weight, WEIGHT_MIN, WEIGHT_MAX, pref.weight_vr)
return TOPIC_REFRESH
if("weight_gain")
var/weight_gain_rate = tgui_input_number(user, "Choose your character's rate of weight gain between 100% \
(full realism body fat gain) and 0% (no body fat gain).\n\
(If you want to disable weight gain, set this to 0.01 to round it to 0%.)\
([WEIGHT_CHANGE_MIN]-[WEIGHT_CHANGE_MAX])", "Character Preference", pref.weight_gain, WEIGHT_CHANGE_MAX, WEIGHT_CHANGE_MIN, round_value=FALSE)
if(weight_gain_rate)
pref.weight_gain = round(text2num(weight_gain_rate),1)
return TOPIC_REFRESH
if("weight_loss")
var/weight_loss_rate = tgui_input_number(user, "Choose your character's rate of weight loss between 100% \
(full realism body fat loss) and 0% (no body fat loss).\n\
(If you want to disable weight loss, set this to 0.01 round it to 0%.)\
([WEIGHT_CHANGE_MIN]-[WEIGHT_CHANGE_MAX])", "Character Preference", pref.weight_loss, WEIGHT_CHANGE_MAX, WEIGHT_CHANGE_MIN, round_value=FALSE)
if(weight_loss_rate)
pref.weight_loss = round(text2num(weight_loss_rate),1)
return TOPIC_REFRESH
if("voice_freq")
var/list/preset_voice_freqs = list("high" = MAX_VOICE_FREQ, "middle-high" = 56250, "middle" = 42500, "middle-low"= 28750, "low" = MIN_VOICE_FREQ, "custom" = 1, "random" = 0)
var/choice = tgui_input_list(user, "What would you like to set your voice frequency to? ([MIN_VOICE_FREQ] - [MAX_VOICE_FREQ])", "Voice Frequency", preset_voice_freqs)
if(!choice)
return
choice = preset_voice_freqs[choice]
if(choice == 0)
pref.voice_freq = choice
return TOPIC_REFRESH
else if(choice == 1)
choice = tgui_input_number(user, "Choose your character's voice frequency, ranging from [MIN_VOICE_FREQ] to [MAX_VOICE_FREQ]", "Custom Voice Frequency", null, MAX_VOICE_FREQ, MIN_VOICE_FREQ)
if(choice > MAX_VOICE_FREQ)
choice = MAX_VOICE_FREQ
else if(choice < MIN_VOICE_FREQ)
choice = MIN_VOICE_FREQ
pref.voice_freq = choice
return TOPIC_REFRESH
if("voice_sounds_list")
var/choice = tgui_input_list(user, "Which set of sounds would you like to use for your character's speech sounds?", "Voice Sounds", SSsounds.talk_sound_map)
if(!choice)
pref.voice_sound = "beep-boop"
else
pref.voice_sound = choice
return TOPIC_REFRESH
if("customize_speech_bubble")
var/choice = tgui_input_list(user, "What speech bubble style do you want to use?", "Custom Speech Bubble", GLOB.selectable_speech_bubbles)
if(choice)
pref.custom_speech_bubble = choice
return TOPIC_REFRESH
if("customize_footsteps")
var/list/footstep_choice = selectable_footstep
var/choice = tgui_input_list(user, "What footstep sounds would your character make?", "Custom Foostep Sounds", footstep_choice)
if(choice)
pref.custom_footstep = footstep_choice[choice]
return TOPIC_REFRESH
if("voice_test")
var/sound/S = sound(pick(SSsounds.talk_sound_map[pref.voice_sound])) // talk_sound_map returns a list of sounds
if(S)
S.frequency = pick(pref.voice_freq)
S.volume = 50
SEND_SOUND(user, S)
if("customize_species_sounds") // You shouldn't be able to see this option if you don't have the option to select a custom icon base, so we don't need to re-check for safety here.
var/list/possible_species_sound_types = species_sound_map
var/choice = tgui_input_list(user, "Which set of sounds would you like to use for your character's species sounds? (Cough, Sneeze, Scream, Pain, Gasp, Death)", "Species Sounds", possible_species_sound_types)
if(choice)
pref.species_sound = choice
return TOPIC_REFRESH
if("cough_test")
var/sound/S
var/ourpref = pref.species_sound
var/oursound = get_species_sound(ourpref)["cough"]
S = sound(pick(oursound))
if(pref.species_sound == "Unset")
oursound = get_species_sound(select_default_species_sound(pref))["cough"]
S = sound(pick(oursound))
if(pref.species_sound == "None" || oursound == null)
to_chat(user, span_warning("This set does not have cough sounds!"))
return TOPIC_REFRESH
S.frequency = pick(pref.voice_freq)
S.volume = 20
SEND_SOUND(user, S)
if("sneeze_test")
var/sound/S
var/ourpref = pref.species_sound
var/oursound = get_species_sound(ourpref)["sneeze"]
S = sound(pick(oursound))
if(pref.species_sound == "Unset")
oursound = get_species_sound(select_default_species_sound(pref))["sneeze"]
S = sound(pick(oursound))
if(pref.species_sound == "None" || oursound == null)
to_chat(user, span_warning("This set does not have sneeze sounds!"))
return TOPIC_REFRESH
S.frequency = pick(pref.voice_freq)
S.volume = 20
SEND_SOUND(user, S)
if("scream_test")
var/sound/S
var/ourpref = pref.species_sound
var/oursound = get_species_sound(ourpref)["scream"]
S = sound(pick(oursound))
if(pref.species_sound == "Unset")
oursound = get_species_sound(select_default_species_sound(pref))["scream"]
S = sound(pick(oursound))
if(pref.species_sound == "None" || oursound == null)
to_chat(user, span_warning("This set does not have scream sounds!"))
return TOPIC_REFRESH
S.frequency = pick(pref.voice_freq)
S.volume = 20
SEND_SOUND(user, S)
if("pain_test")
var/sound/S
var/ourpref = pref.species_sound
var/oursound = get_species_sound(ourpref)["pain"]
S = sound(pick(oursound))
if(pref.species_sound == "Unset")
oursound = get_species_sound(select_default_species_sound(pref))["pain"]
S = sound(pick(oursound))
if(pref.species_sound == "None" || oursound == null)
to_chat(user, span_warning("This set does not have pain sounds!"))
return TOPIC_REFRESH
S.frequency = pick(pref.voice_freq)
S.volume = 20
SEND_SOUND(user, S)
if("gasp_test")
var/sound/S
var/ourpref = pref.species_sound
var/oursound = get_species_sound(ourpref)["gasp"]
S = sound(pick(oursound))
if(pref.species_sound == "Unset")
oursound = get_species_sound(select_default_species_sound(pref))["gasp"]
S = sound(pick(oursound))
if(pref.species_sound == "None" || oursound == null)
to_chat(user, span_warning("This set does not have gasp sounds!"))
return TOPIC_REFRESH
S.frequency = pick(pref.voice_freq)
S.volume = 20
SEND_SOUND(user, S)
if("death_test")
var/sound/S
var/ourpref = pref.species_sound
var/oursound = get_species_sound(ourpref)["death"]
S = sound(pick(oursound))
if(pref.species_sound == "Unset")
oursound = get_species_sound(select_default_species_sound(pref))["death"]
S = sound(pick(oursound))
if(pref.species_sound == "None" || oursound == null)
to_chat(user, span_warning("This set does not have death sounds!"))
return TOPIC_REFRESH
S.frequency = pick(pref.voice_freq)
S.volume = 20
SEND_SOUND(user, S)
#undef WEIGHT_CHANGE_MIN
#undef WEIGHT_CHANGE_MAX
@@ -0,0 +1,39 @@
// Define a place to save in character setup
/datum/preferences
var/persistence_settings = PERSIST_DEFAULT // Control what if anything is persisted for this character between rounds.
// Definition of the stuff for Sizing
/datum/category_item/player_setup_item/general/persistence
name = "Persistence"
sort_order = 10
/datum/category_item/player_setup_item/general/persistence/load_character(list/save_data)
pref.persistence_settings = save_data["persistence_settings"]
sanitize_character() // Don't let new characters start off with nulls
/datum/category_item/player_setup_item/general/persistence/save_character(list/save_data)
save_data["persistence_settings"] = pref.persistence_settings
/datum/category_item/player_setup_item/general/persistence/sanitize_character()
pref.persistence_settings = sanitize_integer(pref.persistence_settings, 0, (1<<(PERSIST_COUNT+1)-1), initial(pref.persistence_settings))
/datum/category_item/player_setup_item/general/persistence/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
data["persistence_settings"] = pref.persistence_settings
return data
/datum/category_item/player_setup_item/general/persistence/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
switch(action)
if("toggle_persist")
var/bit = text2num(params["bit"])
if(pref.persistence_settings & bit)
pref.persistence_settings &= ~bit
else
pref.persistence_settings |= bit
return TOPIC_REFRESH
@@ -0,0 +1,333 @@
// Define a place to save in character setup
/datum/preferences
var/vantag_volunteer = 0 // What state I want to be in, in terms of being affected by antags.
var/vantag_preference = VANTAG_NONE // Whether I'd like to volunteer to be an antag at some point.
var/resleeve_lock = 0 // Whether movs should have OOC reslieving protection. Default false.
var/resleeve_scan = 1 // Whether mob should start with a pre-spawn body scan. Default true.
var/mind_scan = 1 // Whether mob should start with a pre-spawn mind scan. Default true.
var/custom_species // Custom species name, can't be changed due to it having been used in savefiles already.
var/custom_say = null
var/custom_whisper = null
var/custom_ask = null
var/custom_exclaim = null
var/list/custom_heat = list()
var/list/custom_cold = list()
/datum/category_item/player_setup_item/general/vore_misc
name = "Misc Settings"
sort_order = 1
/datum/category_item/player_setup_item/general/vore_misc/load_character(list/save_data)
pref.show_in_directory = save_data["show_in_directory"]
pref.directory_tag = save_data["directory_tag"]
pref.directory_gendertag = save_data["directory_gendertag"]
pref.directory_sexualitytag = save_data["directory_sexualitytag"]
pref.directory_erptag = save_data["directory_erptag"]
pref.directory_ad = save_data["directory_ad"]
pref.sensorpref = save_data["sensorpref"]
pref.capture_crystal = save_data["capture_crystal"]
pref.auto_backup_implant = save_data["auto_backup_implant"]
pref.borg_petting = save_data["borg_petting"]
pref.resleeve_lock = save_data["resleeve_lock"]
pref.resleeve_scan = save_data["resleeve_scan"]
pref.mind_scan = save_data["mind_scan"]
pref.vantag_volunteer = save_data["vantag_volunteer"]
pref.vantag_preference = save_data["vantag_preference"]
pref.custom_species = save_data["custom_species"]
pref.custom_say = save_data["custom_say"]
pref.custom_whisper = save_data["custom_whisper"]
pref.custom_ask = save_data["custom_ask"]
pref.custom_exclaim = save_data["custom_exclaim"]
pref.custom_heat = check_list_copy(save_data["custom_heat"])
pref.custom_cold = check_list_copy(save_data["custom_cold"])
/datum/category_item/player_setup_item/general/vore_misc/save_character(list/save_data)
save_data["show_in_directory"] = pref.show_in_directory
save_data["directory_tag"] = pref.directory_tag
save_data["directory_gendertag"] = pref.directory_gendertag
save_data["directory_sexualitytag"] = pref.directory_sexualitytag
save_data["directory_erptag"] = pref.directory_erptag
save_data["directory_ad"] = pref.directory_ad
save_data["sensorpref"] = pref.sensorpref
save_data["capture_crystal"] = pref.capture_crystal
save_data["auto_backup_implant"] = pref.auto_backup_implant
save_data["borg_petting"] = pref.borg_petting
save_data["resleeve_lock"] = pref.resleeve_lock
save_data["resleeve_scan"] = pref.resleeve_scan
save_data["mind_scan"] = pref.mind_scan
save_data["vantag_volunteer"] = pref.vantag_volunteer
save_data["vantag_preference"] = pref.vantag_preference
save_data["custom_species"] = pref.custom_species
save_data["custom_say"] = pref.custom_say
save_data["custom_whisper"] = pref.custom_whisper
save_data["custom_ask"] = pref.custom_ask
save_data["custom_exclaim"] = pref.custom_exclaim
save_data["custom_heat"] = check_list_copy(pref.custom_heat)
save_data["custom_cold"] = check_list_copy(pref.custom_cold)
/datum/category_item/player_setup_item/general/vore_misc/copy_to_mob(var/mob/living/carbon/human/character)
character.custom_species = pref.custom_species
character.custom_say = lowertext(trim(pref.custom_say))
character.custom_ask = lowertext(trim(pref.custom_ask))
character.custom_whisper = lowertext(trim(pref.custom_whisper))
character.custom_exclaim = lowertext(trim(pref.custom_exclaim))
character.custom_heat = pref.custom_heat
character.custom_cold = pref.custom_cold
if(pref.sensorpref > 5 || pref.sensorpref < 1)
pref.sensorpref = 5
character.sensorpref = pref.sensorpref
character.capture_crystal = pref.capture_crystal
//Vore Stomach Sprite Preference
character.recalculate_vis()
if(character && !istype(character,/mob/living/carbon/human/dummy))
character.vantag_pref = pref.vantag_preference
BITSET(character.hud_updateflag, VANTAG_HUD)
spawn(50)
if(QDELETED(character) || QDELETED(pref))
return // They might have been deleted during the wait
if(!character.virtual_reality_mob && !(/mob/living/carbon/human/proc/perform_exit_vr in character.verbs)) //Janky fix to prevent resleeving VR avatars but beats refactoring transcore
if(pref.resleeve_scan)
var/datum/transhuman/body_record/BR = new()
BR.init_from_mob(character, pref.resleeve_scan, pref.resleeve_lock)
if(pref.mind_scan)
var/datum/transcore_db/our_db = SStranscore.db_by_key(null)
if(our_db)
our_db.m_backup(character.mind,character.nif,one_time = TRUE)
if(pref.resleeve_lock)
character.resleeve_lock = character.ckey
character.original_player = character.ckey
/datum/category_item/player_setup_item/general/vore_misc/sanitize_character()
pref.show_in_directory = sanitize_integer(pref.show_in_directory, 0, 1, initial(pref.show_in_directory))
pref.directory_tag = sanitize_inlist(pref.directory_tag, GLOB.char_directory_tags, initial(pref.directory_tag))
pref.directory_gendertag = sanitize_inlist(pref.directory_gendertag, GLOB.char_directory_gendertags, initial(pref.directory_gendertag))
pref.directory_sexualitytag = sanitize_inlist(pref.directory_sexualitytag, GLOB.char_directory_sexualitytags, initial(pref.directory_sexualitytag))
pref.directory_erptag = sanitize_inlist(pref.directory_erptag, GLOB.char_directory_erptags, initial(pref.directory_erptag))
pref.sensorpref = sanitize_integer(pref.sensorpref, 1, GLOB.sensorpreflist.len, initial(pref.sensorpref))
pref.capture_crystal = sanitize_integer(pref.capture_crystal, 0, 1, initial(pref.capture_crystal))
pref.auto_backup_implant = sanitize_integer(pref.auto_backup_implant, 0, 1, initial(pref.auto_backup_implant))
pref.borg_petting = sanitize_integer(pref.borg_petting, 0, 1, initial(pref.borg_petting))
pref.resleeve_lock = sanitize_integer(pref.resleeve_lock, 0, 1, initial(pref.resleeve_lock))
pref.resleeve_scan = sanitize_integer(pref.resleeve_scan, 0, 1, initial(pref.resleeve_scan))
pref.mind_scan = sanitize_integer(pref.mind_scan, 0, 1, initial(pref.mind_scan))
pref.vantag_volunteer = sanitize_integer(pref.vantag_volunteer, 0, 1, initial(pref.vantag_volunteer))
pref.vantag_preference = sanitize_inlist(pref.vantag_preference, GLOB.vantag_choices_list, initial(pref.vantag_preference))
pref.custom_say = lowertext(trim(pref.custom_say))
pref.custom_whisper = lowertext(trim(pref.custom_whisper))
pref.custom_ask = lowertext(trim(pref.custom_ask))
pref.custom_exclaim = lowertext(trim(pref.custom_exclaim))
if (islist(pref.custom_heat)) //don't bother checking these for actual singular message length, they should already have been checked and it'd take too long every time it's sanitized
if (length(pref.custom_heat) > 10)
pref.custom_heat.Cut(11)
else
pref.custom_heat = list()
if (islist(pref.custom_cold))
if (length(pref.custom_cold) > 10)
pref.custom_cold.Cut(11)
else
pref.custom_cold = list()
/datum/category_item/player_setup_item/general/vore_misc/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
data["show_in_directory"] = pref.show_in_directory
data["directory_tag"] = pref.directory_tag
data["directory_gendertag"] = pref.directory_gendertag
data["directory_sexualitytag"] = pref.directory_sexualitytag
data["directory_erptag"] = pref.directory_erptag
data["sensorpref"] = GLOB.sensorpreflist[pref.sensorpref]
data["capture_crystal"] = pref.capture_crystal
data["auto_backup_implant"] = pref.auto_backup_implant
data["borg_petting"] = pref.borg_petting
data["resleeve_lock"] = pref.resleeve_lock
data["resleeve_scan"] = pref.resleeve_scan
data["mind_scan"] = pref.mind_scan
data["vantag_volunteer"] = pref.vantag_volunteer
data["vantag_preference"] = GLOB.vantag_choices_list[pref.vantag_preference]
data["custom_species"] = pref.custom_species
return data
/datum/category_item/player_setup_item/general/vore_misc/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
var/mob/user = ui.user
switch(action)
if("toggle_show_in_directory")
pref.show_in_directory = pref.show_in_directory ? 0 : 1;
return TOPIC_REFRESH
if("directory_tag")
var/new_tag = tgui_input_list(user, "Pick a new Vore tag for the character directory", "Character Vore Tag", GLOB.char_directory_tags, pref.directory_tag)
if(!new_tag)
return
pref.directory_tag = new_tag
return TOPIC_REFRESH
if("directory_gendertag")
var/new_gendertag = tgui_input_list(user, "Pick a new Gender tag for the character directory. This is YOUR gender, not what you prefer.", "Character Gender Tag", GLOB.char_directory_gendertags, pref.directory_gendertag)
if(!new_gendertag)
return
pref.directory_gendertag = new_gendertag
return TOPIC_REFRESH
if("directory_sexualitytag")
var/new_sexualitytag = tgui_input_list(user, "Pick a new Sexuality/Orientation tag for the character directory", "Character Sexuality/Orientation Tag", GLOB.char_directory_sexualitytags, pref.directory_sexualitytag)
if(!new_sexualitytag)
return
pref.directory_sexualitytag = new_sexualitytag
return TOPIC_REFRESH
if("directory_erptag")
var/new_erptag = tgui_input_list(user, "Pick a new ERP tag for the character directory", "Character ERP Tag", GLOB.char_directory_erptags, pref.directory_erptag)
if(!new_erptag)
return
pref.directory_erptag = new_erptag
return TOPIC_REFRESH
if("directory_ad")
var/msg = sanitize(tgui_input_text(user,"Write your advertisement here!", "Flavor Text", html_decode(pref.directory_ad), multiline = TRUE, prevent_enter = TRUE), extra = 0) //VOREStation Edit: separating out OOC notes
if(!msg)
return
pref.directory_ad = msg
return TOPIC_REFRESH
if("toggle_sensor_setting")
var/new_sensorpref = tgui_input_list(user, "Choose your character's sensor preferences:", "Character Preferences", GLOB.sensorpreflist, GLOB.sensorpreflist[pref.sensorpref])
if (!isnull(new_sensorpref))
pref.sensorpref = GLOB.sensorpreflist.Find(new_sensorpref)
return TOPIC_REFRESH
if("toggle_capture_crystal")
pref.capture_crystal = pref.capture_crystal ? 0 : 1;
return TOPIC_REFRESH
if("toggle_implant")
pref.auto_backup_implant = pref.auto_backup_implant ? 0 : 1;
return TOPIC_REFRESH
if("toggle_borg_petting")
pref.borg_petting = pref.borg_petting ? 0 : 1;
return TOPIC_REFRESH
if("edit_private_notes")
var/new_metadata = sanitize(tgui_input_text(user,"Write some notes for yourself. These can be anything that is useful, whether it's character events that you want to remember or a bit of lore. Things that you would normally stick in a txt file for yourself!", "Private Notes", html_decode(pref.read_preference(/datum/preference/text/living/private_notes)), multiline = TRUE, prevent_enter = TRUE), extra = 0)
if(new_metadata)
pref.update_preference_by_type(/datum/preference/text/living/private_notes, new_metadata)
return TOPIC_REFRESH
if("toggle_resleeve_lock")
pref.resleeve_lock = pref.resleeve_lock ? 0 : 1;
return TOPIC_REFRESH
if("toggle_resleeve_scan")
pref.resleeve_scan = pref.resleeve_scan ? 0 : 1;
return TOPIC_REFRESH
if("toggle_mind_scan")
pref.mind_scan = pref.mind_scan ? 0 : 1;
return TOPIC_REFRESH
if("toggle_vantag_volunteer")
pref.vantag_volunteer = pref.vantag_volunteer ? 0 : 1
return TOPIC_REFRESH
if("change_vantag")
var/list/names_list = list()
for(var/C in GLOB.vantag_choices_list)
names_list[GLOB.vantag_choices_list[C]] = C
var/selection = tgui_input_list(user, "How do you want to be involved with VS Event Characters, ERP-wise? They will see this choice on you in a HUD. Event characters are admin-selected and spawned players, possibly with assigned objectives, who are obligated to respect ERP prefs and RP their actions like any other player, though it may be a slightly shorter RP if they are pressed for time or being caught.", "Event Preference", names_list)
if(selection && selection != "Normal")
pref.vantag_preference = names_list[selection]
return TOPIC_REFRESH
if("custom_say")
var/say_choice = sanitize(tgui_input_text(user, "This word or phrase will appear instead of 'says': [pref.real_name] says, \"Hi.\"", "Custom Say", pref.custom_say, 12), 12)
if(say_choice)
pref.custom_say = say_choice
return TOPIC_REFRESH
if("custom_whisper")
var/whisper_choice = sanitize(tgui_input_text(user, "This word or phrase will appear instead of 'whispers': [pref.real_name] whispers, \"Hi...\"", "Custom Whisper", pref.custom_whisper, 12), 12)
if(whisper_choice)
pref.custom_whisper = whisper_choice
return TOPIC_REFRESH
if("custom_ask")
var/ask_choice = sanitize(tgui_input_text(user, "This word or phrase will appear instead of 'asks': [pref.real_name] asks, \"Hi?\"", "Custom Ask", pref.custom_ask, 12), 12)
if(ask_choice)
pref.custom_ask = ask_choice
return TOPIC_REFRESH
if("custom_exclaim")
var/exclaim_choice = sanitize(tgui_input_text(user, "This word or phrase will appear instead of 'exclaims', 'shouts' or 'yells': [pref.real_name] exclaims, \"Hi!\"", "Custom Exclaim", pref.custom_exclaim, 12), 12)
if(exclaim_choice)
pref.custom_exclaim = exclaim_choice
return TOPIC_REFRESH
if("custom_heat")
tgui_alert(user, "You are setting custom heat messages. These will overwrite your species' defaults. To return to defaults, click reset.")
var/old_message = pref.custom_heat.Join("\n\n")
var/new_message = sanitize(tgui_input_text(user,"Use double enter between messages to enter a new one. Must be at least 3 characters long, 160 characters max and up to 10 messages are allowed.","Heat Discomfort messages",old_message, multiline= TRUE, prevent_enter = TRUE), MAX_MESSAGE_LEN,0,0,0)
if(length(new_message) > 0)
var/list/raw_list = splittext(new_message,"\n\n")
if(raw_list.len > 10)
raw_list.Cut(11)
for(var/i = 1, i <= raw_list.len, i++)
if(length(raw_list[i]) < 3 || length(raw_list[i]) > 160)
raw_list.Cut(i,i)
else
raw_list[i] = readd_quotes(raw_list[i])
ASSERT(raw_list.len <= 10)
pref.custom_heat = raw_list
return TOPIC_REFRESH
if("custom_cold")
tgui_alert(user, "You are setting custom cold messages. These will overwrite your species' defaults. To return to defaults, click reset.")
var/old_message = pref.custom_heat.Join("\n\n")
var/new_message = sanitize(tgui_input_text(user,"Use double enter between messages to enter a new one. Must be at least 3 characters long, 160 characters max and up to 10 messages are allowed.","Cold Discomfort messages",old_message, multiline= TRUE, prevent_enter = TRUE), MAX_MESSAGE_LEN,0,0,0)
if(length(new_message) > 0)
var/list/raw_list = splittext(new_message,"\n\n")
if(raw_list.len > 10)
raw_list.Cut(11)
for(var/i = 1, i <= raw_list.len, i++)
if(length(raw_list[i]) < 3 || length(raw_list[i]) > 160)
raw_list.Cut(i,i)
else
raw_list[i] = readd_quotes(raw_list[i])
ASSERT(raw_list.len <= 10)
pref.custom_cold = raw_list
return TOPIC_REFRESH
if("reset_say")
var/say_choice = tgui_alert(user, "Reset your Custom Say Verb?","Reset Verb",list("Yes","No"))
if(say_choice == "Yes")
pref.custom_say = null
return TOPIC_REFRESH
if("reset_whisper")
var/whisper_choice = tgui_alert(user, "Reset your Custom Whisper Verb?","Reset Verb",list("Yes","No"))
if(whisper_choice == "Yes")
pref.custom_whisper = null
return TOPIC_REFRESH
if("reset_ask")
var/ask_choice = tgui_alert(user, "Reset your Custom Ask Verb?","Reset Verb",list("Yes","No"))
if(ask_choice == "Yes")
pref.custom_ask = null
return TOPIC_REFRESH
if("reset_exclaim")
var/exclaim_choice = tgui_alert(user, "Reset your Custom Exclaim Verb?","Reset Verb",list("Yes","No"))
if(exclaim_choice == "Yes")
pref.custom_exclaim = null
return TOPIC_REFRESH
if("reset_cold")
var/cold_choice = tgui_alert(user, "Reset your Custom Cold Discomfort messages?", "Reset Discomfort",list("Yes","No"))
if(cold_choice == "Yes")
pref.custom_cold = list()
return TOPIC_REFRESH
if("reset_heat")
var/heat_choice = tgui_alert(user, "Reset your Custom Heat Discomfort messages?", "Reset Discomfort",list("Yes","No"))
if(heat_choice == "Yes")
pref.custom_heat = list()
return TOPIC_REFRESH
if("custom_species")
var/raw_choice = sanitize(tgui_input_text(user, "Input your custom species name:",
"Character Preference", pref.custom_species, MAX_NAME_LEN), MAX_NAME_LEN)
pref.custom_species = raw_choice
return TOPIC_REFRESH
@@ -0,0 +1,412 @@
#define POSITIVE_MODE 1
#define NEUTRAL_MODE 2
#define NEGATIVE_MODE 3
var/global/list/valid_bloodreagents = list("default",REAGENT_ID_IRON,REAGENT_ID_COPPER,REAGENT_ID_PHORON,REAGENT_ID_SILVER,REAGENT_ID_GOLD,REAGENT_ID_SLIMEJELLY) //allowlist-based so people don't make their blood restored by alcohol or something really silly. use reagent IDs!
/datum/preferences
var/custom_base // What to base the custom species on
var/blood_color = "#A10808"
var/list/pos_traits = list() // What traits they've selected for their custom species
var/list/neu_traits = list()
var/list/neg_traits = list()
var/traits_cheating = 0 //Varedit by admins allows saving new maximums on people who apply/etc
var/starting_trait_points = 0
var/max_traits = MAX_SPECIES_TRAITS
var/dirty_synth = 0 //Are you a synth
var/gross_meatbag = 0 //Where'd I leave my Voight-Kampff test kit?
/datum/preferences/proc/get_custom_bases_for_species(var/new_species)
if (!new_species)
new_species = species
var/list/choices
var/datum/species/spec = GLOB.all_species[new_species]
if (spec.selects_bodytype == SELECTS_BODYTYPE_SHAPESHIFTER)
choices = spec.get_valid_shapeshifter_forms()
choices = choices.Copy()
else if (spec.selects_bodytype == SELECTS_BODYTYPE_CUSTOM)
choices = GLOB.custom_species_bases.Copy()
if(new_species != SPECIES_CUSTOM)
choices = (choices | new_species)
return choices
/datum/category_item/player_setup_item/general/traits/proc/get_pref_choice_from_trait(var/mob/user, var/datum/trait/trait, var/preference)
if (!trait || !preference)
return
var/list/trait_prefs
var/datum/trait/instance = GLOB.all_traits[trait]
var/list/traitlist
switch(instance.category)
if (1)
traitlist = pref.pos_traits
if (0)
traitlist = pref.neu_traits
if (-1)
traitlist = pref.neg_traits
if (!LAZYLEN(instance.has_preferences) || !(preference in instance.has_preferences) || !traitlist)
return
if (!LAZYLEN(traitlist[trait]))
traitlist[trait] = instance.get_default_prefs()
trait_prefs = traitlist[trait]
if (!(preference in trait_prefs))
trait_prefs[preference] = instance.default_value_for_pref(preference) //won't be called at all often
switch(instance.has_preferences[preference][1])
if (1) //TRAIT_PREF_TYPE_BOOLEAN
trait_prefs[preference] = !trait_prefs[preference]
if (2) //TRAIT_PREF_TYPE_COLOR
var/new_color = tgui_color_picker(user, "Choose the color for this trait preference:", "Trait Preference", trait_prefs[preference])
if (new_color)
trait_prefs[preference] = new_color
if (3) //TRAIT_PREF_TYPE_STRING
var/new_string = instance.apply_sanitization_to_string(preference, tgui_input_text(user, "What should the new value be?", instance.has_preferences[preference][2], trait_prefs[preference], MAX_NAME_LEN))
trait_prefs[preference] = new_string
// Definition of the stuff for Ears
/datum/category_item/player_setup_item/general/traits
name = "Traits"
sort_order = 7
/datum/category_item/player_setup_item/general/traits/load_character(list/save_data)
pref.custom_base = save_data["custom_base"]
pref.pos_traits = text2path_list(save_data["pos_traits"])
pref.neu_traits = text2path_list(save_data["neu_traits"])
pref.neg_traits = text2path_list(save_data["neg_traits"])
pref.blood_color = save_data["blood_color"]
pref.blood_reagents = save_data["blood_reagents"]
pref.traits_cheating = save_data["traits_cheating"]
pref.max_traits = save_data["max_traits"]
pref.starting_trait_points = save_data["trait_points"]
/datum/category_item/player_setup_item/general/traits/save_character(list/save_data)
save_data["custom_base"] = pref.custom_base
save_data["pos_traits"] = check_list_copy(pref.pos_traits)
save_data["neu_traits"] = check_list_copy(pref.neu_traits)
save_data["neg_traits"] = check_list_copy(pref.neg_traits)
save_data["blood_color"] = pref.blood_color
save_data["blood_reagents"] = pref.blood_reagents
save_data["traits_cheating"] = pref.traits_cheating
save_data["max_traits"] = pref.max_traits
save_data["trait_points"] = pref.starting_trait_points
/datum/category_item/player_setup_item/general/traits/sanitize_character()
if(!pref.pos_traits) pref.pos_traits = list()
if(!pref.neu_traits) pref.neu_traits = list()
if(!pref.neg_traits) pref.neg_traits = list()
pref.blood_color = sanitize_hexcolor(pref.blood_color, default="#A10808")
pref.blood_reagents = sanitize_text(pref.blood_reagents, initial(pref.blood_reagents))
if(!pref.traits_cheating)
var/datum/species/S = GLOB.all_species[pref.species]
if(S)
pref.starting_trait_points = S.trait_points
else
pref.starting_trait_points = 0
pref.max_traits = MAX_SPECIES_TRAITS
if(pref.organ_data[O_BRAIN]) //Checking if we have a synth on our hands, boys.
pref.dirty_synth = 1
pref.gross_meatbag = 0
else
pref.gross_meatbag = 1
pref.dirty_synth = 0
// Clean up positive traits
for(var/datum/trait/path as anything in pref.pos_traits)
if(!(path in GLOB.positive_traits))
pref.pos_traits -= path
continue
if(!(pref.species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_positive))
pref.pos_traits -= path
continue
var/take_flags = initial(path.can_take)
if((pref.dirty_synth && !(take_flags & SYNTHETICS)) || (pref.gross_meatbag && !(take_flags & ORGANICS)))
pref.pos_traits -= path
//Neutral traits
for(var/datum/trait/path as anything in pref.neu_traits)
if(!(path in GLOB.neutral_traits))
to_world_log("removing [path] for not being in neutral_traits")
pref.neu_traits -= path
continue
if(!(pref.species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_neutral))
to_world_log("removing [path] for not being a custom species")
pref.neu_traits -= path
continue
var/take_flags = initial(path.can_take)
if((pref.dirty_synth && !(take_flags & SYNTHETICS)) || (pref.gross_meatbag && !(take_flags & ORGANICS)))
to_world_log("removing [path] for being a dirty synth")
pref.neu_traits -= path
//Negative traits
for(var/datum/trait/path as anything in pref.neg_traits)
if(!(path in GLOB.negative_traits))
pref.neg_traits -= path
continue
if(!(pref.species == SPECIES_CUSTOM) && !(path in GLOB.everyone_traits_negative))
pref.neg_traits -= path
continue
var/take_flags = initial(path.can_take)
if((pref.dirty_synth && !(take_flags & SYNTHETICS)) || (pref.gross_meatbag && !(take_flags & ORGANICS)))
pref.neg_traits -= path
var/datum/species/selected_species = GLOB.all_species[pref.species]
if(selected_species.selects_bodytype)
if (!(pref.custom_base in pref.get_custom_bases_for_species()))
pref.custom_base = SPECIES_HUMAN
//otherwise, allowed!
else if(!pref.custom_base || !(pref.custom_base in GLOB.custom_species_bases))
pref.custom_base = SPECIES_HUMAN
/datum/category_item/player_setup_item/general/traits/copy_to_mob(var/mob/living/carbon/human/character)
if(character.isSynthetic()) //Checking if we have a synth on our hands, boys.
pref.dirty_synth = 1
pref.gross_meatbag = 0
else
pref.gross_meatbag = 1
pref.dirty_synth = 0
var/datum/species/S = character.species
var/datum/species/new_S = S.produceCopy(pref.pos_traits + pref.neu_traits + pref.neg_traits, character, pref.custom_base, TRUE)
for(var/datum/trait/T in new_S.traits)
T.apply_pref(src)
//Any additional non-trait settings can be applied here
new_S.blood_color = pref.blood_color
if(!(pref.blood_reagents == "default"))
new_S.blood_reagents = pref.blood_reagents
var/species_sounds_to_copy = pref.species_sound // What sounds are we using?
if(species_sounds_to_copy == "Unset") // Are we unset?
species_sounds_to_copy = select_default_species_sound(pref) // This will also grab gendered versions of the sounds, if they exist.
new_S.species_sounds = species_sounds_to_copy // Now we send our sounds over to the mob
if(pref.species == SPECIES_CUSTOM)
//Statistics for this would be nice
var/english_traits = english_list(new_S.traits, and_text = ";", comma_text = ";")
log_game("TRAITS [pref.client_ckey]/([character]) with: [english_traits]") //Terrible 'fake' key_name()... but they aren't in the same entity yet
/datum/category_item/player_setup_item/general/traits/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
var/datum/species/selected_species = GLOB.all_species[pref.species]
data["selects_bodytype"] = selected_species.selects_bodytype
data["custom_base"] = pref.custom_base
data["blood_color"] = pref.blood_color
data["blood_reagents"] = pref.blood_reagents
data["pos_traits"] = pref.pos_traits
data["neu_traits"] = pref.neu_traits
data["neg_traits"] = pref.neg_traits
data["traits_cheating"] = pref.traits_cheating
data["max_traits"] = pref.max_traits
data["trait_points"] = pref.starting_trait_points
return data
/datum/category_item/player_setup_item/general/traits/tgui_constant_data()
var/list/data = ..()
var/list/all_traits = list()
for(var/path in GLOB.all_traits)
var/datum/trait/T = GLOB.all_traits[path]
all_traits[path] = list(
"cost" = T.cost,
"name" = T.name,
"category" = T.category,
"has_preferences" = T.has_preferences,
)
data["all_traits"] = all_traits
return data
/datum/category_item/player_setup_item/general/traits/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
. = ..()
if(.)
return
var/mob/user = ui.user
switch(action)
if("custom_base")
var/list/choices = pref.get_custom_bases_for_species()
var/text_choice = tgui_input_list(user, "Pick an icon set for your species:","Icon Base", choices)
if(text_choice in choices)
pref.custom_base = text_choice
return TOPIC_REFRESH_UPDATE_PREVIEW
if("blood_color")
var/color_choice = tgui_color_picker(user, "Pick a blood color (does not apply to synths)","Blood Color",pref.blood_color)
if(color_choice)
pref.blood_color = sanitize_hexcolor(color_choice, default="#A10808")
return TOPIC_REFRESH
if("blood_reset")
var/datum/species/spec = GLOB.all_species[pref.species]
var/new_blood = spec.blood_color ? spec.blood_color : "#A10808"
var/choice = tgui_alert(user, "Reset blood color to species default ([new_blood])?","Reset Blood Color",list("Reset","Cancel"))
if(choice == "Reset")
pref.blood_color = new_blood
return TOPIC_REFRESH
if("blood_reagents")
var/new_blood_reagents = tgui_input_list(user, "Choose your character's blood restoration reagent:", "Character Preference", valid_bloodreagents)
if(new_blood_reagents && CanUseTopic(user))
pref.blood_reagents = new_blood_reagents
return TOPIC_REFRESH
if("clicked_pos_trait")
var/datum/trait/trait = text2path(params["trait"])
var/choice = tgui_alert(user, "Remove [initial(trait.name)] and regain [initial(trait.cost)] points?","Remove Trait",list("Remove","Cancel"))
if(choice == "Remove")
pref.pos_traits -= trait
var/datum/trait/instance = GLOB.all_traits[trait]
instance.remove_pref(pref)
return TOPIC_REFRESH
if("clicked_neu_trait")
var/datum/trait/trait = text2path(params["trait"])
var/choice = tgui_alert(user, "Remove [initial(trait.name)]?","Remove Trait",list("Remove","Cancel"))
if(choice == "Remove")
pref.neu_traits -= trait
var/datum/trait/instance = GLOB.all_traits[trait]
instance.remove_pref(pref)
return TOPIC_REFRESH
if("clicked_neg_trait")
var/datum/trait/trait = text2path(params["trait"])
var/choice = tgui_alert(user, "Remove [initial(trait.name)] and lose [initial(trait.cost)] points?","Remove Trait",list("Remove","Cancel"))
if(choice == "Remove")
pref.neg_traits -= trait
var/datum/trait/instance = GLOB.all_traits[trait]
instance.remove_pref(pref)
return TOPIC_REFRESH
if("clicked_trait_pref")
var/datum/trait/trait = text2path(params["clicked_trait_pref"])
get_pref_choice_from_trait(user, trait, params["pref"])
return TOPIC_REFRESH
if("add_trait")
var/mode = text2num(params["add_trait"])
var/list/picklist
var/list/mylist
switch(mode)
if(POSITIVE_MODE)
if(pref.species == SPECIES_CUSTOM)
picklist = GLOB.positive_traits.Copy() - pref.pos_traits
mylist = pref.pos_traits
else
picklist = GLOB.everyone_traits_positive.Copy() - pref.pos_traits
mylist = pref.pos_traits
if(NEUTRAL_MODE)
if(pref.species == SPECIES_CUSTOM)
picklist = GLOB.neutral_traits.Copy() - pref.neu_traits
mylist = pref.neu_traits
else
picklist = GLOB.everyone_traits_neutral.Copy() - pref.neu_traits
mylist = pref.neu_traits
if(NEGATIVE_MODE)
if(pref.species == SPECIES_CUSTOM)
picklist = GLOB.negative_traits.Copy() - pref.neg_traits
mylist = pref.neg_traits
else
picklist = GLOB.everyone_traits_negative.Copy() - pref.neg_traits
mylist = pref.neg_traits
if(isnull(picklist))
return TOPIC_REFRESH
if(isnull(mylist))
return TOPIC_REFRESH
var/list/nicelist = list()
for(var/P in picklist)
var/datum/trait/T = picklist[P]
nicelist[T.name] = P
var/points_left = pref.starting_trait_points
for(var/T in pref.pos_traits + pref.neu_traits + pref.neg_traits)
points_left -= GLOB.traits_costs[T]
var/traits_left = pref.max_traits - (pref.pos_traits.len + pref.neg_traits.len)
var/message = "Select a trait to learn more."
if(mode != NEUTRAL_MODE)
message = "\[Remaining: [points_left] points, [traits_left] traits\]\n" + message
var/title = "Traits"
switch(mode)
if(POSITIVE_MODE)
title = "Positive Traits"
if(NEUTRAL_MODE)
title = "Neutral Traits"
if(NEGATIVE_MODE)
title = "Negative Traits"
var/trait_choice
var/done = FALSE
while(!done)
trait_choice = tgui_input_list(user, message, title, nicelist)
if(!trait_choice)
done = TRUE
if(trait_choice in nicelist)
var/datum/trait/path = nicelist[trait_choice]
var/choice = tgui_alert(user, "\[Cost:[initial(path.cost)]\] [initial(path.desc)]",initial(path.name), list("Take Trait","Go Back"))
if(choice == "Take Trait")
done = TRUE
if(!trait_choice)
return TOPIC_REFRESH
else if(trait_choice in nicelist)
var/datum/trait/path = nicelist[trait_choice]
var/datum/trait/instance = GLOB.all_traits[path]
var/conflict = FALSE
if(pref.dirty_synth && !(instance.can_take & SYNTHETICS))
tgui_alert_async(user, "The trait you've selected can only be taken by organic characters!", "Error")
return TOPIC_REFRESH
if(pref.gross_meatbag && !(instance.can_take & ORGANICS))
tgui_alert_async(user, "The trait you've selected can only be taken by synthetic characters!", "Error")
return TOPIC_REFRESH
if(pref.species in instance.banned_species)
tgui_alert_async(user, "The trait you've selected cannot be taken by the species you've chosen!", "Error")
return TOPIC_REFRESH
if( LAZYLEN(instance.allowed_species) && !(pref.species in instance.allowed_species))
tgui_alert_async(user, "The trait you've selected cannot be taken by the species you've chosen!", "Error")
return TOPIC_REFRESH
if(trait_choice in (pref.pos_traits + pref.neu_traits + pref.neg_traits))
conflict = instance.name
varconflict:
for(var/P in (pref.pos_traits + pref.neu_traits + pref.neg_traits))
var/datum/trait/instance_test = GLOB.all_traits[P]
if(path in instance_test.excludes)
conflict = instance_test.name
break varconflict
for(var/V in instance.var_changes)
if(V == "flags")
continue
if(V in instance_test.var_changes)
conflict = instance_test.name
break varconflict
for(var/V in instance.var_changes_pref)
if(V in instance_test.var_changes_pref)
conflict = instance_test.name
break varconflict
if(conflict)
tgui_alert_async(user, "You cannot take this trait and [conflict] at the same time. Please remove that trait, or pick another trait to add.", "Error")
return TOPIC_REFRESH
instance.apply_pref(pref)
mylist[path] = instance.get_default_prefs()
return TOPIC_REFRESH
#undef POSITIVE_MODE
#undef NEUTRAL_MODE
#undef NEGATIVE_MODE
@@ -0,0 +1,64 @@
//Pretty small file, mostly just for storage.
/datum/preferences
var/obj/item/nif/nif_path
var/nif_durability
var/list/nif_savedata
// Definition of the stuff for NIFs
// Magic bullshit, they're stored separately from everything else
/datum/category_item/player_setup_item/general/nif
name = "NIF Data"
sort_order = 8
/proc/nif_savefile_path(ckey)
if(!ckey)
return
return "data/player_saves/[copytext(ckey,1,2)]/[ckey]/nif.json"
/datum/category_item/player_setup_item/general/nif/load_character()
var/datum/json_savefile/savefile = new /datum/json_savefile(nif_savefile_path(pref.client_ckey))
var/list/save_data_file = savefile.get_entry("character[pref.default_slot]", list())
pref.nif_path = save_data_file["nif_path"]
pref.nif_durability = save_data_file["nif_durability"]
pref.nif_savedata = check_list_copy(save_data_file["nif_savedata"])
/datum/category_item/player_setup_item/general/nif/save_character()
var/datum/json_savefile/savefile = new /datum/json_savefile(nif_savefile_path(pref.client_ckey))
var/list/save_data_file = savefile.get_entry("character[pref.default_slot]", list())
save_data_file["nif_path"] = pref.nif_path
save_data_file["nif_durability"] = pref.nif_durability
save_data_file["nif_savedata"] = check_list_copy(pref.nif_savedata)
savefile.set_entry("character[pref.default_slot]", save_data_file)
savefile.save()
/datum/category_item/player_setup_item/general/nif/sanitize_character()
if(pref.nif_path && !ispath(pref.nif_path)) //We have at least a text string that should be a path.
pref.nif_path = text2path(pref.nif_path) //Try to convert it to a hard path.
if(!pref.nif_path) //If we couldn't, kill it.
pref.nif_path = null //Kill!
WARNING("Loaded a NIF but it was an invalid path, [pref.real_name]")
if (ispath(pref.nif_path, /obj/item/nif/protean) && pref.species != SPECIES_PROTEAN) //no free nifs
pref.nif_path = null
if(ispath(pref.nif_path) && isnull(pref.nif_durability)) //How'd you lose this?
pref.nif_durability = initial(pref.nif_path.durability) //Well, have a new one, my bad.
WARNING("Loaded a NIF but with no durability, [pref.real_name]")
if(!islist(pref.nif_savedata))
pref.nif_savedata = list()
/datum/category_item/player_setup_item/general/nif/copy_to_mob(var/mob/living/carbon/human/character)
//If you had a NIF...
if(istype(character) && ispath(pref.nif_path) && pref.nif_durability)
new pref.nif_path(character, pref.nif_durability, pref.nif_savedata)
/datum/category_item/player_setup_item/general/nif/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
data["nif"] = ispath(pref.nif_path)
return data