diff --git a/code/__DEFINES/~doppler_defines/preferences.dm b/code/__DEFINES/~doppler_defines/preferences.dm new file mode 100644 index 0000000000000..4ec3ef91d991e --- /dev/null +++ b/code/__DEFINES/~doppler_defines/preferences.dm @@ -0,0 +1,6 @@ +#define MAX_FLAVOR_SHORT_DESC_LEN 250 +#define MAX_FLAVOR_EXTENDED_DESC_LEN 4096 + +#define PREFERENCE_CATEGORY_DOPPLER_LORE "doppler_lore" + +#define READ_PREFS(target, pref) (target.client?.prefs?.read_preference(/datum/preference/pref)) diff --git a/code/__DEFINES/~doppler_defines/text.dm b/code/__DEFINES/~doppler_defines/text.dm new file mode 100644 index 0000000000000..f95563090bf40 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/text.dm @@ -0,0 +1,8 @@ +/proc/prefix_a_or_an(text) + var/start = LOWER_TEXT(text[1]) + if(!start) + return "a" + if(start == "a" || start == "e" || start == "i" || start == "o" || start == "u") + return "an" + else + return "a" diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm index afc5cef6aa4ec..673b3f40774f4 100644 --- a/code/datums/records/manifest.dm +++ b/code/datums/records/manifest.dm @@ -15,7 +15,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) if(readied_player.new_character) log_manifest(readied_player.ckey, readied_player.new_character.mind, readied_player.new_character) if(ishuman(readied_player.new_character)) - inject(readied_player.new_character) + inject(readied_player.new_character, readied_player.client) // DOPPLER EDIT, old code: inject(readied_player.new_character) CHECK_TICK /// Gets the current manifest. @@ -98,7 +98,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) /// Injects a record into the manifest. -/datum/manifest/proc/inject(mob/living/carbon/human/person) +/datum/manifest/proc/inject(mob/living/carbon/human/person, client/person_client) // DOPPLER EDIT: records & flavor text set waitfor = FALSE if(!(person.mind?.assigned_role.job_flags & JOB_CREW_MANIFEST)) return @@ -131,6 +131,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) // Locked specifics locked_dna = record_dna, mind_ref = person.mind, + age_chronological = person_client?.prefs.read_preference(/datum/preference/numeric/chronological_age), // DOPPLER EDIT ADDITION ) new /datum/record/crew( @@ -152,6 +153,13 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) minor_disabilities = person.get_quirk_string(FALSE, CAT_QUIRK_MINOR_DISABILITY, from_scan = TRUE), minor_disabilities_desc = person.get_quirk_string(TRUE, CAT_QUIRK_MINOR_DISABILITY), quirk_notes = person.get_quirk_string(TRUE, CAT_QUIRK_NOTES), + // DOPPLER EDIT BEGIN - records & flavor text + past_general_records = person_client?.prefs.read_preference(/datum/preference/text/past_general_records), + past_medical_records = person_client?.prefs.read_preference(/datum/preference/text/past_medical_records), + past_security_records = person_client?.prefs.read_preference(/datum/preference/text/past_security_records), + exploitable_records = person_client?.prefs.read_preference(/datum/preference/text/exploitable_records), + age_chronological = person_client?.prefs.read_preference(/datum/preference/numeric/chronological_age), + // DOPPLER EDIT END ) /// Edits the rank and trim of the found record. diff --git a/code/datums/records/record.dm b/code/datums/records/record.dm index 4c40a85d5fccd..e3dffd9d7e95e 100644 --- a/code/datums/records/record.dm +++ b/code/datums/records/record.dm @@ -108,6 +108,13 @@ physical_status = PHYSICAL_ACTIVE, mental_status = MENTAL_STABLE, quirk_notes, + // DOPPLER EDIT START - records & flavor text + past_general_records = "", + past_medical_records = "", + past_security_records = "", + exploitable_records = "", + age_chronological = 18, + // DOPPER EDIT END ) . = ..() src.lock_ref = lock_ref @@ -118,7 +125,13 @@ src.physical_status = physical_status src.mental_status = mental_status src.quirk_notes = quirk_notes - + // DOPPLER EDIT START + src.past_general_records = past_general_records + src.past_medical_records = past_medical_records + src.past_security_records = past_security_records + src.exploitable_records = exploitable_records + src.age_chronological = age_chronological + // DOPPLER EDIT END GLOB.manifest.general += src /datum/record/crew/Destroy() @@ -152,10 +165,12 @@ /// Locked specific datum/dna/locked_dna, datum/mind/mind_ref, + age_chronological = 18, // DOPPLER EDIT ADDITION ) . = ..() src.locked_dna = locked_dna src.mind_ref = WEAKREF(mind_ref) + src.age_chronological = age_chronological // DOPPLER EDIT ADDITION species_type = locked_dna.species.type GLOB.manifest.locked += src @@ -249,12 +264,17 @@ var/obj/item/paper/printed_paper = new var/final_paper_text = "
SR-[print_count]: [header]

" - final_paper_text += "Name: [name]
Gender: [gender]
Age: [age]
" + final_paper_text += "Name: [name]
Gender: [gender]
Age: [age]
Chronological Age: [age_chronological]
" // DOPPLER EDIT: chronological age if(alias != name) final_paper_text += "Alias: [alias]
" final_paper_text += "Species: [species]
Fingerprint: [fingerprint]
Wanted Status: [wanted_status]

" + // DOPPLER EDIT - records & flavour text + if(past_general_records != "") + final_paper_text += "
General Records:" + final_paper_text += "
[past_general_records]
" + // DOPPLER EDIT END final_paper_text += "
Security Data


" final_paper_text += "Crimes:
" diff --git a/code/game/machinery/computer/records/medical.dm b/code/game/machinery/computer/records/medical.dm index 6dd12acbdb678..f1b685abc949d 100644 --- a/code/game/machinery/computer/records/medical.dm +++ b/code/game/machinery/computer/records/medical.dm @@ -66,6 +66,11 @@ rank = target.rank, species = target.species, trim = target.trim, + // DOPPLER EDIT BEGIN - records & flavor text + past_medical_records = target.past_medical_records, + past_general_records = target.past_general_records, + age_chronological = target.age_chronological, + // DOPPLER EDIT END )) data["records"] = records diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index bdfa996dad68f..8e0ee17eb158a 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -130,6 +130,11 @@ species = target.species, trim = target.trim, wanted_status = target.wanted_status, + // DOPPLER EDIT BEGIN - records & flavor text + past_general_records = target.past_general_records, + past_security_records = target.past_security_records, + age_chronological = target.age_chronological, + // DOPPLER EDIT END )) data["records"] = records diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 1510783fc7cb8..109fb57ca3aea 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -553,7 +553,7 @@ ADMIN_VERB(spawn_debug_full_crew, R_DEBUG, "Spawn Debug Full Crew", "Creates a f // Finally, ensure the minds are tracked and in the manifest. SSticker.minds += character.mind if(ishuman(character)) - GLOB.manifest.inject(character) + GLOB.manifest.inject(character, character.client) // DOPPLER EDIT, old code: GLOB.manifest.inject(character) number_made++ CHECK_TICK diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index 488c670a19d4b..60ec46386c64b 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -284,7 +284,7 @@ ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player th if(!record_found && (new_character.mind.assigned_role.job_flags & JOB_CREW_MEMBER)) //Power to the user! if(tgui_alert(new_character,"Warning: No data core entry detected. Would you like to announce the arrival of this character by adding them to various databases, such as medical records?",,list("No","Yes")) == "Yes") - GLOB.manifest.inject(new_character) + GLOB.manifest.inject(new_character, new_character.client) // DOPPLER EDIT, old code: GLOB.manifest.inject(new_character) if(tgui_alert(new_character,"Would you like an active AI to announce this character?",,list("No","Yes")) == "Yes") announce_arrival(new_character, new_character.mind.assigned_role.title) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index f3b48b438b8ae..0f9ebc317ce5e 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -243,7 +243,7 @@ SSquirks.AssignQuirks(humanc, humanc.client) if(humanc) // Quirks may change manifest datapoints, so inject only after assigning quirks - GLOB.manifest.inject(humanc) + GLOB.manifest.inject(humanc, humanc.client) // DOPPLER EDIT, old code: GLOB.manifest.inject(humanc) var/area/station/arrivals = GLOB.areas_by_type[/area/station/hallway/secondary/entry] if(humanc && arrivals && !arrivals.power_environ) //arrivals depowered diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index dc03dce8541fb..9457fde6a292c 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -22,6 +22,15 @@ var/t_is = p_are() . = list() + // DOPPLER EDIT BEGIN - flavor text + if (dna.features["flavor_short_desc"]) + . += "[dna.features["flavor_short_desc"]] [get_extended_description_href("\[👁️\]")]" + ADD_NEWLINE_IF_NECESSARY(.) + if (dna.features["custom_species_name"]) + . += "[t_He] [t_is] [prefix_a_or_an(dna.features["custom_species_name"])] [get_species_description_href(dna.features["custom_species_name"])] of [dna.species.name] physiology." + else + . += "[t_He] [t_is] [prefix_a_or_an(dna.species.name)] [get_species_description_href(dna.species.name)]." + // DOPPLER EDIT END . += get_clothing_examine_info(user) // give us some space between clothing examine and the rest ADD_NEWLINE_IF_NECESSARY(.) diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 3091881c56f51..754fdce7e159a 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -1,8 +1,22 @@ +/// DOPPLER ADDITION START, Adds a newline to the examine list if the above entry is not empty and it is not the first element in the list +#define ADD_NEWLINE_IF_NECESSARY(list) if(length(list) > 0 && list[length(list)]) { list += "" } +// DOPPLER ADDITION END + /mob/living/silicon/robot/examine(mob/user) . = list() if(desc) . += "[desc]" + // DOPPLER EDIT BEGIN: flavor text + var/short_desc = READ_PREFS(src, text/silicon_short_desc) + if (short_desc) + . += "[short_desc] [get_extended_description_href("\[👁️\]")]" + ADD_NEWLINE_IF_NECESSARY(.) + var/custom_model_name = READ_PREFS(src, text/silicon_model_name) + if (custom_model_name) + . += "It is [prefix_a_or_an(custom_model_name)] [get_species_description_href(custom_model_name)] model construct." + // DOPPLER EDIT END + var/model_name = model ? "\improper [model.name]" : "\improper Default" . += "It is currently \a [model_name]-type cyborg." @@ -48,3 +62,5 @@ . += span_deadsay("It looks like its system is corrupted and requires a reset.") . += ..() + +#undef ADD_NEWLINE_IF_NECESSARY diff --git a/modular_doppler/flavortext_and_records/code/defines.dm b/modular_doppler/flavortext_and_records/code/defines.dm new file mode 100644 index 0000000000000..6e755c2b13a0c --- /dev/null +++ b/modular_doppler/flavortext_and_records/code/defines.dm @@ -0,0 +1,7 @@ +/mob/living/carbon/human + /// Chronological age. + var/age_chronological = 30 + +/mob/living/silicon/robot + /// Chronological age + var/age_chronological = 30 diff --git a/modular_doppler/flavortext_and_records/code/examine.dm b/modular_doppler/flavortext_and_records/code/examine.dm new file mode 100644 index 0000000000000..83a0f15c74fe8 --- /dev/null +++ b/modular_doppler/flavortext_and_records/code/examine.dm @@ -0,0 +1,151 @@ +/* + /mob/living procs for both humans and silicons +*/ + +/mob/living/proc/get_extended_description_href(input_text) + // Provides a href link with the `full_desc` arg, to be consumed by a Topic override (intended for flavour text descriptions) + return "[input_text]" + +/mob/living/proc/get_species_description_href(input_text) + // Provides a href link with the `species_info` arg, to be consumed by a Topic override (intended for species/model descriptions) + return "[input_text]" + +/mob/living/proc/compile_examined_text(short_desc, extended_desc, headshot, ooc_notes) + // Compiles the full examined description because I HATE code duplication + var/full_examine = span_slightly_larger(separator_hr("[src]")) + + full_examine += "
" + if (length(headshot)) // apply headshot + full_examine += "[src.name]" + full_examine += "
" + full_examine += jointext(list( + "[trim(short_desc)]
", + trim(extended_desc) + ), "
") + full_examine += "
" + if (length(ooc_notes)) + full_examine += span_slightly_larger(separator_hr("OOC Notes")) + full_examine += "
" + full_examine += trim(ooc_notes) + full_examine += "
" + + return full_examine + +/mob/living/proc/compile_species_info_text(species_name, species_desc, is_model = FALSE) + // Compiles the species description block, with a switch for synthetic/model stuff, because I REALLY hate code duplication + var/header_prefix = is_model ? "Model" : "Species" + var/full_examine = span_slightly_larger(separator_hr("[header_prefix]: [species_name]")) + + full_examine += trim(species_desc) + + return full_examine + +/* + CARBONS (AKA FLESHBAGS) +*/ +/mob/living/carbon/human/examine_title(mob/user, thats = FALSE) + . = ..() + var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE)) + + var/species_visible + var/species_name_string + if(skipface || get_visible_name() == "Unknown") + species_visible = FALSE + else + species_visible = TRUE + + if(!species_visible) + species_name_string = "" + else if (dna.features["custom_species_name"]) + species_name_string = ", [prefix_a_or_an(dna.features["custom_species_name"])] [dna.features["custom_species_name"]]" + else + species_name_string = ", [prefix_a_or_an(dna.species.name)] [dna.species.name]" + + . += species_name_string + +/mob/living/carbon/human/Topic(href, href_list) + . = ..() + + if (href_list["full_desc"]) + // scuffed not-tgui flavor text stuff + var/mob/viewer = usr + var/can_see = (viewer in viewers(src)) + + if (HAS_TRAIT(src, TRAIT_UNKNOWN)) + to_chat(viewer, span_notice("You can't discern a thing about them!")) + return + + if (can_see) + var/short_desc = src.dna.features["flavor_short_desc"] + var/extended_desc = src.dna.features["flavor_extended_desc"] + var/headshot_url = src.dna.features["headshot_url"] + var/ooc_notes = src.dna.features["ooc_notes"] + + var/full_examine = compile_examined_text(short_desc, extended_desc, headshot_url, ooc_notes) + + to_chat(viewer, examine_block(span_info(full_examine))) + return + else + to_chat(viewer, span_notice("You're too far away to get a good look at [src]!")) + return + else if (href_list["species_info"]) + // return a blurb detailing their species + var/mob/viewer = usr + var/can_see = (viewer in viewers(src)) + if (can_see) + var/species_name = src.dna.features["custom_species_name"] ? src.dna.features["custom_species_name"] : src.dna.species.name + var/species_desc = src.dna.features["custom_species_desc"] ? src.dna.features["custom_species_desc"] : src.dna.species.get_species_description() + + var/full_examine = compile_species_info_text(species_name, species_desc, FALSE) + + to_chat(viewer, examine_block(span_info(full_examine))) + return +/* + SILICONS (AKA HORRIBLE RUSTBUCKETS) +*/ + +/mob/living/silicon/robot/examine_title(mob/user, thats) + . = ..() + + // much simpler for silicons since disguises aren't really a thing... for now + var/model_name = READ_PREFS(src, text/silicon_model_name) + if (model_name) + . += ", [prefix_a_or_an(model_name)] [model_name]" + + +/mob/living/silicon/robot/Topic(href, href_list) + . = ..() + + if (href_list["full_desc"]) + var/mob/viewer = usr + var/can_see = (viewer in viewers(src)) + + if (HAS_TRAIT(src, TRAIT_UNKNOWN)) + to_chat(viewer, span_notice("You can't discern a thing about them!")) + return + + if (can_see) + var/short_desc = READ_PREFS(src, text/silicon_short_desc) + var/extended_desc = READ_PREFS(src, text/silicon_extended_desc) + var/headshot_url = READ_PREFS(src, text/headshot/silicon) + var/ooc_notes = READ_PREFS(src, text/ooc_notes) + + var/full_examine = compile_examined_text(short_desc, extended_desc, headshot_url, ooc_notes) + + to_chat(viewer, examine_block(span_info(full_examine))) + return + else + to_chat(viewer, span_notice("You're too far away to get a good look at [src]!")) + return + else if (href_list["species_info"]) + var/mob/viewer = usr + var/can_see = (viewer in viewers(src)) + + if (can_see) + var/model_name = READ_PREFS(src, text/silicon_model_name) + var/model_desc = READ_PREFS(src, text/silicon_model_desc) + + var/full_examine = compile_species_info_text(model_name, model_desc, TRUE) + + to_chat(viewer, examine_block(span_info(full_examine))) + return diff --git a/modular_doppler/flavortext_and_records/code/flavor_text.dm b/modular_doppler/flavortext_and_records/code/flavor_text.dm new file mode 100644 index 0000000000000..1093bc86656e8 --- /dev/null +++ b/modular_doppler/flavortext_and_records/code/flavor_text.dm @@ -0,0 +1,81 @@ +/* + "Short descs" are a brief one to three sentence written text block that describes the core, immediately-recognizable aspects of a given character. As a general rule + + Example: + "Standing at roughly five foot ten in height, this grizzled male human sports a great array of old laser scars, poorly healed-over." +*/ +/datum/preference/text/flavor_short_desc + category = PREFERENCE_CATEGORY_DOPPLER_LORE // probably not appropriate, need to make a new lore category one + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "flavor_short_desc" + maximum_value_length = MAX_FLAVOR_SHORT_DESC_LEN + +/datum/preference/text/flavor_short_desc/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["flavor_short_desc"] = value // applying this to DNA for now, probably a better way to do it + +/datum/preference/text/flavor_extended_desc + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "flavor_extended_desc" + maximum_value_length = MAX_FLAVOR_EXTENDED_DESC_LEN + +/datum/preference/text/flavor_extended_desc/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["flavor_extended_desc"] = value + +/datum/preference/text/custom_species_name + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "custom_species_name" + maximum_value_length = 128 + +/datum/preference/text/custom_species_name/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["custom_species_name"] = value + +/datum/preference/text/custom_species_desc + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "custom_species_desc" + maximum_value_length = 4096 + +/datum/preference/text/custom_species_desc/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["custom_species_desc"] = value + +/* + Silicon specific things +*/ + +/datum/preference/text/silicon_short_desc + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "silicon_flavor_short_desc" + maximum_value_length = MAX_FLAVOR_SHORT_DESC_LEN + +/datum/preference/text/silicon_short_desc/apply_to_human(mob/living/carbon/human/target, value) + return // we handle this manually via pref lookups in appropriate procs + +/datum/preference/text/silicon_extended_desc + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "silicon_flavor_extended_desc" + maximum_value_length = MAX_FLAVOR_EXTENDED_DESC_LEN + +/datum/preference/text/silicon_extended_desc/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/silicon_model_name + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "silicon_model_name" + maximum_value_length = 128 + +/datum/preference/text/silicon_model_name/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/silicon_model_desc + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "silicon_model_desc" + maximum_value_length = 4096 + +/datum/preference/text/silicon_model_desc/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_doppler/flavortext_and_records/code/headshot.dm b/modular_doppler/flavortext_and_records/code/headshot.dm new file mode 100644 index 0000000000000..b37cc8a5a75c6 --- /dev/null +++ b/modular_doppler/flavortext_and_records/code/headshot.dm @@ -0,0 +1,44 @@ +/datum/preference/text/headshot + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "headshot_url" + maximum_value_length = MAX_MESSAGE_LEN + var/list/stored_link = list() + var/static/link_regex = regex("i.gyazo.com|files.byondhome.com|images2.imgbox.com|files.catbox.moe") + var/static/list/valid_extensions = list("jpg", "png", "jpeg") + +/datum/preference/text/headshot/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["headshot_url"] = value + +/datum/preference/text/headshot/is_valid(value) + if (!length(value)) + return TRUE + + var/find_index = findtext(value, "https://") + if (find_index != 1) + to_chat(usr, span_warning("Your link must be https!")) + return + + var/sanity_check = findtext(value, ".") + if (!sanity_check) + to_chat(usr, span_warning("Your link doesn't appear to be valid!")) + return + + var/list/value_split = splittext(value, ".") + var/extension = value_split[length(value_split)] + if (!(extension in valid_extensions)) + to_chat(usr, span_warning("The image must be one of the following extensions: '[english_list(valid_extensions)]'")) + return + + find_index = findtext(value, link_regex) + if(find_index != 9) + to_chat(usr, span_warning("The image must be hosted on one of the following sites: 'Gyazo (i.gyazo.com), Byond (files.byondhome.com), Imgbox (images2.imgbox.com) or Catbox (files.catbox.moe)'")) + return + + return TRUE + +/datum/preference/text/headshot/silicon + savefile_key = "silicon_headshot_url" + +/datum/preference/text/headshot/silicon/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_doppler/flavortext_and_records/code/physiology.dm b/modular_doppler/flavortext_and_records/code/physiology.dm new file mode 100644 index 0000000000000..110176f122a27 --- /dev/null +++ b/modular_doppler/flavortext_and_records/code/physiology.dm @@ -0,0 +1,33 @@ +// Just a bunch of override name replacements to shape species into 'physiologies' to better reflect their actual mechanical effect.area +// The reason we do this is because base species are formatted in our new examine to appear as physiologies instead of actual species, so you don't get shit like "This is Juniper, a Space Elf! She is a Humanoid." Instead, you get "This is Juniper, a Space Elf! She is a Space Elf of Anthropoid physiology." +// Sounds a bit obtuse but if you go into it realizing that most people are going to be using customized species, it makes a *lot* more sense. +// Lore people will probably want to change some of these. + +/datum/species/human + name = "Anthropoid" // i have a feeling people won't like this + +/datum/species/monkey + name = "Primate" + +/datum/species/abductor + name = "Alien" // ayyyyy + +/datum/species/ethereal + name = "Crystalline" + +/datum/species/jelly + name = "Mucosid" + +/datum/species/lizard + name = "Reptilian" + +/datum/species/moth + name = "Lepidopteran" + +/datum/species/plasmaman + name = "Plasmoid" + +/datum/species/pod + name = "Viridian" + + diff --git a/modular_doppler/flavortext_and_records/code/records.dm b/modular_doppler/flavortext_and_records/code/records.dm new file mode 100644 index 0000000000000..5066440001803 --- /dev/null +++ b/modular_doppler/flavortext_and_records/code/records.dm @@ -0,0 +1,77 @@ +/datum/record + /// Character's chronological age. + var/age_chronological + +/datum/record/crew + /// Self-written past general records. + var/past_general_records + /// Self-written past medical records. + var/past_medical_records + /// Self-written past security records. + var/past_security_records + /// Self-written exploitables/vulnerable information intended for antagonists to make use of. + var/exploitable_records + +/// PREFERENCES + +/datum/preference/numeric/age + category = PREFERENCE_CATEGORY_DOPPLER_LORE // moves age to our funny lore page, needs manual inclusion on LorePage.tsx though + +/datum/preference/numeric/chronological_age + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "age_chronological" + minimum = 18 + maximum = 999 + +/datum/preference/numeric/chronological_age/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["age_chronological"] = value + target.age_chronological = value + +/datum/preference/numeric/chronological_age/create_informed_default_value(datum/preferences/preferences) + return preferences.read_preference(/datum/preference/numeric/age) + +/datum/preference/text/past_general_records + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "past_general_records" + maximum_value_length = 4096 + +/datum/preference/text/past_general_records/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/past_medical_records + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "past_medical_records" + maximum_value_length = 4096 + +/datum/preference/text/past_medical_records/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/past_security_records + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "past_security_records" + maximum_value_length = 4096 + +/datum/preference/text/past_security_records/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/exploitable_records + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "exploitable_records" + maximum_value_length = 4096 + +/datum/preference/text/exploitable_records/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/text/ooc_notes + category = PREFERENCE_CATEGORY_DOPPLER_LORE + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "ooc_notes" + maximum_value_length = 4096 + +/datum/preference/text/ooc_notes/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["ooc_notes"] = value diff --git a/tgstation.dme b/tgstation.dme index af38d01445a7c..04e2efd930051 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -420,6 +420,7 @@ #include "code\__DEFINES\~doppler_defines\mutant_variations.dm" #include "code\__DEFINES\~doppler_defines\obj_flags_doppler.dm" #include "code\__DEFINES\~doppler_defines\organ_slots.dm" +#include "code\__DEFINES\~doppler_defines\preferences.dm" #include "code\__DEFINES\~doppler_defines\reagent_forging_tools.dm" #include "code\__DEFINES\~doppler_defines\reskin_defines.dm" #include "code\__DEFINES\~doppler_defines\role_preferences.dm" @@ -431,6 +432,7 @@ #include "code\__DEFINES\~doppler_defines\speech_channels.dm" #include "code\__DEFINES\~doppler_defines\strippable.dm" #include "code\__DEFINES\~doppler_defines\techweb_nodes.dm" +#include "code\__DEFINES\~doppler_defines\text.dm" #include "code\__DEFINES\~doppler_defines\traits.dm" #include "code\__DEFINES\~doppler_defines\wounds.dm" #include "code\__HELPERS\_auxtools_api.dm" @@ -6536,6 +6538,12 @@ #include "modular_doppler\enterprise_resource_planning\code\erp_prefs.dm" #include "modular_doppler\examinemore\code\examine_more.dm" #include "modular_doppler\face_mouse_preferences\code\face_mouse_pref.dm" +#include "modular_doppler\flavortext_and_records\code\defines.dm" +#include "modular_doppler\flavortext_and_records\code\examine.dm" +#include "modular_doppler\flavortext_and_records\code\flavor_text.dm" +#include "modular_doppler\flavortext_and_records\code\headshot.dm" +#include "modular_doppler\flavortext_and_records\code\physiology.dm" +#include "modular_doppler\flavortext_and_records\code\records.dm" #include "modular_doppler\food_replicator\code\clothing.dm" #include "modular_doppler\food_replicator\code\medical.dm" #include "modular_doppler\food_replicator\code\rationpacks.dm" diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss index 78be30f5d4c9f..98d89378cf126 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss @@ -1018,6 +1018,26 @@ em { .img_by_text_container .img_text { flex-grow: 1; } +/*DOPPLER ADDITION START + Larger images by text, used by flavor-text examines. No flex shenanigans.*/ +.large_img_by_text_container { + display: inline-block; + align-items: center; + flex-wrap: wrap; +} + +.large_img_by_text_container img { + width: 250px; + height: auto; + margin-right: 12px; + margin-top: 4px; + float: left; +} + +.large_img_by_text_container .img_text { + flex-grow: 1; +} +/*DOPPLER ADDITION END*/ $alert-stripe-colors: ( 'default': #00283a, diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss index 51ff6ac35b03f..3769c79771c38 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss @@ -1037,6 +1037,27 @@ h2.alert { flex-grow: 1; } +/*DOPPLER ADDITION START + Larger images by text, used by flavor-text examines. No flex shenanigans.*/ +.large_img_by_text_container { + display: inline-block; + align-items: center; + flex-wrap: wrap; +} + +.large_img_by_text_container img { + width: 250px; + height: auto; + margin-right: 12px; + margin-top: 4px; + float: left; +} + +.large_img_by_text_container .img_text { + flex-grow: 1; +} +/*DOPPLER ADDITION END*/ + $alert-stripe-colors: ( 'default': #b3bfff, 'green': #adffad, diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/RecordView.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/RecordView.tsx index 0bcfd4fc7d618..fdb94ec5d662b 100644 --- a/tgui/packages/tgui/interfaces/MedicalRecords/RecordView.tsx +++ b/tgui/packages/tgui/interfaces/MedicalRecords/RecordView.tsx @@ -47,6 +47,11 @@ export const MedicalRecordView = (props) => { quirk_notes, rank, species, + // DOPPLER EDIT BEGIN - records & flavor text + past_general_records, + past_medical_records, + age_chronological, + // DOPPLER EDIT END } = foundRecord; const minor_disabilities_array = getQuirkStrings(minor_disabilities); @@ -87,7 +92,9 @@ export const MedicalRecordView = (props) => { - + {/* DOPPLER EDIT START */} + + {/* DOPPLER EDIT, old code: */} { value={age} /> + {/* DOPPLER EDIT ADDITION BEGIN - chronological age */} + + + act('edit_field', { + field: 'age_chronological', + ref: crew_ref, + value: value, + }) + } + value={age_chronological} + /> + + {/* DOPPLER EDIT ADDITION END */} { • {quirk} ))} + {/* DOPPLER EDIT START - records & flavor text */} + + + {past_general_records || 'N/A'} + + + + + {past_medical_records || 'N/A'} + + + {/* DOPPLER EDIT END */} diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts index 878f81ab65e2c..58912bc2af818 100644 --- a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts +++ b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts @@ -13,6 +13,8 @@ export type MedicalRecordData = { export type MedicalRecord = { age: number; + // DOPPLER EDIT: chronological age + age_chronological: number; blood_type: string; crew_ref: string; dna: string; @@ -27,6 +29,10 @@ export type MedicalRecord = { rank: string; species: string; trim: string; + // DOPPLER EDIT BEGIN - records & flavor text + past_general_records: string; + past_medical_records: string; + // DOPPLER EDIT END }; export type MedicalNote = { diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx index 8193384e6ae88..c93566e8f726c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx @@ -8,6 +8,7 @@ import { AntagsPage } from './AntagsPage'; import { PreferencesMenuData } from './data'; import { JobsPage } from './JobsPage'; import { LoadoutPage } from './loadout/index'; +import { LorePage } from './LorePage'; /* DOPPLER EDIT ADDITION */ import { MainPage } from './MainPage'; import { PageButton } from './PageButton'; import { QuirksPage } from './QuirksPage'; @@ -20,6 +21,7 @@ enum Page { Species, Quirks, Loadout, + Lore /* DOPPLER EDIT ADDITION */, } const CharacterProfiles = (props: { @@ -81,6 +83,11 @@ export const CharacterPreferenceWindow = (props) => { case Page.Loadout: pageContents = ; break; + /* DOPPLER ADDITION START */ + case Page.Lore: + pageContents = ; + break; + /* DOPPLER ADDITION END */ default: exhaustiveCheck(currentPage); @@ -119,7 +126,21 @@ export const CharacterPreferenceWindow = (props) => { Character - + { + // DOPPLER EDIT: fancy flavour text & character report stuff + } + + + Lore + + { + // DOPPLER EDIT END + } + { + const { act, data } = useBackend(); + const dopplerLorePreferences = { + ...data.character_preferences.doppler_lore, + }; + return ( + + + +
+ + + + + +
+
+ + +
+
+ + + + + +
+
+ + + + +
+
+ +
+
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/SinglePreference.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/SinglePreference.tsx new file mode 100644 index 0000000000000..6fda40dc261fc --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/SinglePreference.tsx @@ -0,0 +1,40 @@ +import { sendAct } from '../../backend'; +import { LabeledList } from '../../components/LabeledList'; +import { Stack } from '../../components/Stack'; +import features from './preferences/features'; +import { FeatureValueInput } from './preferences/features/base'; + +export const PreferenceSingle = (props: { + act: typeof sendAct; + pref_key: string; + preferences: Record; +}) => { + const feature = features[props.pref_key]; + const value = props.preferences[props.pref_key]; + + if (feature === undefined) { + return ( + + Feature {props.pref_key} is not recognized. + + ); + } + + return ( + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts index b1447d54f1fd5..3f3a341bcffdd 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts @@ -138,6 +138,7 @@ export type PreferencesMenuData = { random_body: RandomSetting; [otherKey: string]: unknown; }; + doppler_lore: Record /* DOPPLER EDIT ADDITION */; secondary_features: Record; supplemental_features: Record; manually_rendered_features: Record; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx index 9a32ec336133b..09b4a86c6750c 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx @@ -17,6 +17,7 @@ import { NumberInput, Slider, Stack, + TextArea /* DOPPLER EDIT ADDITION */, } from '../../../../components'; import { createSetPreference, PreferencesMenuData } from '../../data'; import { ServerPreferencesFetcher } from '../../ServerPreferencesFetcher'; @@ -315,3 +316,22 @@ export const FeatureShortTextInput = ( /> ); }; + +// DOPPLER EDIT START: DOPPLER FEATURES BELOW + +export const FeatureTextInput = ( + props: FeatureValueProps, +) => { + if (!props.serverData) { + return Loading...; + } + + return ( +