diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index e43002ba50b5..9d042a26fcf9 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -57098,7 +57098,7 @@ desc = "A cold, hard place for your final rest."; name = "Morgue Slab" }, -/mob/living/carbon/human/species/monkey/humand_legged{ +/mob/living/carbon/human/species/monkey{ name = "Charles"; real_name = "Charles" }, diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index 6a71a8d6c3c0..c7da3473fa3b 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -430,3 +430,5 @@ GLOBAL_LIST_INIT(cable_colors, list( CABLE_COLOR_YELLOW = CABLE_HEX_COLOR_YELLOW, CABLE_COLOR_BROWN = CABLE_HEX_COLOR_BROWN )) + +#define HUSK_COLOR_TONE rgb(96, 88, 80) diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index ab131cc3d728..479373bb6518 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -64,6 +64,20 @@ /// Total amount of slots #define SLOTS_AMT 20 // Keep this up to date! +///Inventory slots that can be blacklisted by a species from being equipped into +DEFINE_BITFIELD(no_equip_flags, list( + "EXOSUIT" = ITEM_SLOT_OCLOTHING, + "JUMPSUIT" = ITEM_SLOT_ICLOTHING, + "GLOVES" = ITEM_SLOT_GLOVES, + "GLASSES" = ITEM_SLOT_EYES, + "EARPIECES" = ITEM_SLOT_EARS, + "MASKS" = ITEM_SLOT_MASK, + "HATS" = ITEM_SLOT_HEAD, + "SHOES" = ITEM_SLOT_FEET, + "BACKPACKS" = ITEM_SLOT_BACK, + "TIES" = ITEM_SLOT_NECK, +)) + //SLOT GROUP HELPERS #define ITEM_SLOT_POCKETS (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET) /// Slots that are physically on you @@ -135,11 +149,10 @@ #define CLOTHING_DIGITIGRADE_VARIATION (1<<1) ///The sprite works fine for digitigrade legs as-is. #define CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON (1<<2) -///has a sprite for monkeys -#define CLOTHING_MONKEY_VARIATION (1<<3) /// When worn by a mob with digitigrade, apply a filter #define CLOTHING_DIGITIGRADE_FILTER (1<<3) +/// Any flag which has a variation for digi #define DIGITIGRADE_VARIATIONS (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON|CLOTHING_DIGITIGRADE_FILTER) //flags for covering body parts diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 4696b532ed38..1e4e1ddd1c52 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -120,9 +120,7 @@ #define SPECIES_LIZARD_SILVER "silverscale" #define SPECIES_NIGHTMARE "nightmare" #define SPECIES_MONKEY "monkey" -#define SPECIES_MONKEY_FREAK "monkey_freak" -#define SPECIES_MONKEY_HOLODECK "monkey_holodeck" -#define SPECIES_MONKEY_HUMAN_LEGGED "monkey_human_legged" +#define SPECIES_MONKEY_LIZARD "kobold" #define SPECIES_MOTH "moth" #define SPECIES_MUSHROOM "mush" #define SPECIES_PLASMAMAN "plasmaman" @@ -130,7 +128,6 @@ #define SPECIES_SHADOW "shadow" #define SPECIES_SKELETON "skeleton" #define SPECIES_SNAIL "snail" -#define SPECIES_TALLBOY "tallboy" #define SPECIES_VAMPIRE "vampire" #define SPECIES_ZOMBIE "zombie" #define SPECIES_ZOMBIE_INFECTIOUS "memezombie" @@ -668,18 +665,22 @@ // - They do not start at 0 for futureproofing // - They skip numbers for futureproofing as well // Otherwise they are completely arbitrary -#define HUMAN_HEIGHT_DWARF 2 -#define HUMAN_HEIGHT_SHORTEST 4 -#define HUMAN_HEIGHT_SHORT 6 -#define HUMAN_HEIGHT_MEDIUM 8 -#define HUMAN_HEIGHT_TALL 10 -#define HUMAN_HEIGHT_TALLER 12 -#define HUMAN_HEIGHT_TALLEST 14 +#define MONKEY_HEIGHT_DWARF 2 +#define MONKEY_HEIGHT_MEDIUM 4 +#define HUMAN_HEIGHT_DWARF 6 +#define HUMAN_HEIGHT_SHORTEST 8 +#define HUMAN_HEIGHT_SHORT 10 +#define HUMAN_HEIGHT_MEDIUM 12 +#define HUMAN_HEIGHT_TALL 14 +#define HUMAN_HEIGHT_TALLER 16 +#define HUMAN_HEIGHT_TALLEST 18 /// Assoc list of all heights, cast to strings, to """"tuples""""" /// The first """tuple""" index is the upper body offset /// The second """tuple""" index is the lower body offset GLOBAL_LIST_INIT(human_heights_to_offsets, list( + "[MONKEY_HEIGHT_DWARF]" = list(-9, -3), + "[MONKEY_HEIGHT_MEDIUM]" = list(-7, -4), "[HUMAN_HEIGHT_DWARF]" = list(-5, -4), "[HUMAN_HEIGHT_SHORTEST]" = list(-2, -1), "[HUMAN_HEIGHT_SHORT]" = list(-1, -1), diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm index 12a114439c7d..24a29f7bda7c 100644 --- a/code/__DEFINES/research/anomalies.dm +++ b/code/__DEFINES/research/anomalies.dm @@ -20,11 +20,6 @@ GLOBAL_LIST_INIT(bioscrambler_parts_blacklist, typecacheof(list( /obj/item/bodypart/chest/larva, /obj/item/bodypart/head/larva, - // Re-add the ones below this line when the bug with offset is fixed - /obj/item/bodypart/leg/left/monkey, - /obj/item/bodypart/leg/right/monkey, - /obj/item/bodypart/leg/left/tallboy, - /obj/item/bodypart/leg/right/tallboy, ))) /// Blacklist of organs which should not appear when bioscrambled. diff --git a/code/__DEFINES/species_clothing_paths.dm b/code/__DEFINES/species_clothing_paths.dm index 2582d81b613b..99fe7baab1dd 100644 --- a/code/__DEFINES/species_clothing_paths.dm +++ b/code/__DEFINES/species_clothing_paths.dm @@ -6,10 +6,6 @@ ///The dmi for humanoid oversuits #define DEFAULT_SUIT_FILE 'icons/mob/clothing/suits/default.dmi' -//MONKEY PATHS -///The dmi for monkey uniforms -#define MONKEY_UNIFORM_FILE 'icons/mob/human/species/monkey/uniform.dmi' - //DIGITIGRADE PATHS ///The dmi containing digitigrade uniforms #define DIGITIGRADE_UNIFORM_FILE 'icons/mob/human/species/misc/digitigrade.dmi' diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 928a1b13c3d2..1c29bf639b3b 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -17,7 +17,7 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard, add_blank = TRUE) - init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, GLOB.tails_list_monkey, add_blank = TRUE) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, GLOB.tails_list_monkey, add_blank = FALSE) init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list) @@ -40,13 +40,6 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/plumage, GLOB.avian_ears_list) //NON-MODULE CHANGE init_sprite_accessory_subtypes(/datum/sprite_accessory/synth_head_cover, GLOB.synth_head_cover_list) //NON-MODULE CHANGE -/// Inits GLOB.species_list. Not using GLOBAL_LIST_INIT b/c it depends on GLOB.string_lists -/proc/init_species_list() - for(var/species_path in subtypesof(/datum/species)) - var/datum/species/species = new species_path() - GLOB.species_list[species.id] = species_path - sort_list(GLOB.species_list, GLOBAL_PROC_REF(cmp_typepaths_asc)) - /// Inits GLOB.surgeries /proc/init_surgeries() var/surgeries = list() diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 02f2450630d2..0d0d75d6df7e 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -227,7 +227,7 @@ world /icon/proc/ColorTone(tone) GrayScale() - var/list/TONE = ReadRGB(tone) + var/list/TONE = rgb2num(tone) var/gray = round(TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11, 1) var/icon/upper = (255-gray) ? new(src) : null @@ -1544,7 +1544,7 @@ GLOBAL_LIST_EMPTY(transformation_animation_objects) var/list/icon_dimensions = get_icon_dimensions(source.icon) var/width = icon_dimensions["width"] var/height = icon_dimensions["height"] - + if(width > world.icon_size) alert_overlay.pixel_x = -(world.icon_size / 2) * ((width - world.icon_size) / world.icon_size) if(height > world.icon_size) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index a45b6b92cc63..d17019bff426 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -40,6 +40,20 @@ else return "#000000" +/proc/random_hair_color() + var/static/list/natural_hair_colors = list( + "#111111", "#362925", "#3B3831", "#41250C", "#412922", + "#544C49", "#583322", "#593029", "#703b30", "#714721", + "#744729", "#74482a", "#7b746e", "#855832", "#863019", + "#8c4734", "#9F550E", "#A29A96", "#A4381C", "#B17B41", + "#C0BAB7", "#EFE5E4", "#F7F3F1", "#FFF2D6", "#a15537", + "#a17e61", "#b38b67", "#ba673c", "#c89f73", "#d9b380", + "#dbc9b8", "#e1621d", "#e17d17", "#e1af93", "#f1cc8f", + "#fbe7a1", + ) + + return pick(natural_hair_colors) + /proc/random_underwear(gender) if(!GLOB.underwear_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f) @@ -88,47 +102,6 @@ else return pick(GLOB.facial_hairstyles_list) -/proc/random_unique_name(gender, attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - if(gender == FEMALE) - . = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) - else - . = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - - if(!findname(.)) - break - -/proc/random_unique_lizard_name(gender, attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - . = capitalize(lizard_name(gender)) - - if(!findname(.)) - break - -/proc/random_unique_plasmaman_name(attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - . = capitalize(plasmaman_name()) - - if(!findname(.)) - break - -/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - . = capitalize(ethereal_name()) - - if(!findname(.)) - break - -/proc/random_unique_moth_name(attempts_to_find_unique_name=10) - for(var/i in 1 to attempts_to_find_unique_name) - . = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last)) - - if(!findname(.)) - break - -/proc/random_skin_tone() - return pick(GLOB.skin_tones) - GLOBAL_LIST_INIT(skin_tones, sort_list(list( "albino", "caucasian1", @@ -167,9 +140,6 @@ GLOBAL_LIST_INIT(skin_tone_names, list( "mixed4" = "Macadamia", )) -/// An assoc list of species IDs to type paths -GLOBAL_LIST_EMPTY(species_list) - /proc/age2agedescription(age) switch(age) if(0 to 1) diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index 33bb0348df56..95e6938330cc 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -1,20 +1,75 @@ -/proc/lizard_name(gender) - if(gender == MALE) - return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]" - else - return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]" +/** + * Generate a random name based off of one of the roundstart languages + * + * * gender - What gender to pick from. Picks between male, female if not provided. + * * unique - If the name should be unique, IE, avoid picking names that mobs already have. + * * list/language_weights - A list of language weights to pick from. + * If not provided, it will default to a list of roundstart languages, with common being the most likely. + */ +/proc/generate_random_name(gender, unique, list/language_weights) + if(isnull(language_weights)) + language_weights = list() + for(var/lang_type in GLOB.uncommon_roundstart_languages) + language_weights[lang_type] = 1 + language_weights[/datum/language/common] = 20 + + var/datum/language/picked = GLOB.language_datum_instances[pick_weight(language_weights)] + if(unique) + return picked.get_random_unique_name(gender) + return picked.get_random_name(gender) + +/** + * Generate a random name based off of a species + * This will pick a name from the species language, and avoid picking common if there are alternatives + * + * * gender - What gender to pick from. Picks between male, female if not provided. + * * unique - If the name should be unique, IE, avoid picking names that mobs already have. + * * datum/species/species_type - The species to pick from + * * include_all - Makes the generated name a mix of all the languages the species can speak rather than just one of them + * Does this on a per-name basis, IE "Lizard first name, uncommon last name". + */ +/proc/generate_random_name_species_based(gender, unique, datum/species/species_type, include_all = FALSE) + ASSERT(ispath(species_type, /datum/species)) + var/datum/language_holder/holder = GLOB.prototype_language_holders[species_type::species_language_holder] -/proc/ethereal_name() - var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]" - if(prob(65)) - tempname += random_capital_letter() - return tempname + var/list/languages_to_pick_from = list() + for(var/language in holder.spoken_languages) + languages_to_pick_from[language] = 1 -/proc/plasmaman_name() - return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]" + if(length(languages_to_pick_from) >= 2) + // Basically, if we have alternatives, don't pick common it's boring + languages_to_pick_from -= /datum/language/common -/proc/moth_name() - return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]" + if(!include_all || length(languages_to_pick_from) <= 1) + return generate_random_name(gender, unique, languages_to_pick_from) + + var/list/name_parts = list() + for(var/lang_type in shuffle(languages_to_pick_from)) + name_parts += GLOB.language_datum_instances[lang_type].get_random_name(gender, name_count = 1, force_use_syllables = TRUE) + return jointext(name_parts, " ") + +/** + * Generates a random name for the mob based on their gender or species (for humans) + * + * * unique - If the name should be unique, IE, avoid picking names that mobs already have. + */ +/mob/proc/generate_random_mob_name(unique) + return generate_random_name_species_based(gender, unique, /datum/species/human) + +/mob/living/carbon/generate_random_mob_name(unique) + return generate_random_name_species_based(gender, unique, dna?.species?.type || /datum/species/human) + +/mob/living/silicon/generate_random_mob_name(unique) + return generate_random_name(gender, unique, list(/datum/language/machine = 1)) + +/mob/living/basic/drone/generate_random_mob_name(unique) + return generate_random_name(gender, unique, list(/datum/language/machine = 1)) + +/mob/living/basic/bot/generate_random_mob_name(unique) + return generate_random_name(gender, unique, list(/datum/language/machine = 1)) + +/mob/living/simple_animal/bot/generate_random_mob_name(unique) + return generate_random_name(gender, unique, list(/datum/language/machine = 1)) GLOBAL_VAR(command_name) /proc/command_name() @@ -194,16 +249,11 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex) if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc. switch(rand(1,2))//Mainly to add more options later. if(1) - if(names.len && prob(70)) + if(length(names) && prob(70)) . += pick(names) else - if(prob(10)) - . += pick(lizard_name(MALE),lizard_name(FEMALE)) - else - var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female)) - new_name += " " - new_name += pick(GLOB.last_names) - . += new_name + . += generate_random_name() + if(2) var/datum/job/job = pick(SSjob.joinable_occupations) if(job) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index fda5f03d38d8..8d35f2192062 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -117,6 +117,23 @@ GLOBAL_LIST_INIT(language_types_by_name, init_language_types_by_name()) lang_list[initial(lang_type.name)] = lang_type return lang_list +/// An assoc list of species IDs to type paths +GLOBAL_LIST_INIT(species_list, init_species_list()) +/// List of all species prototypes to reference, assoc [type] = prototype +GLOBAL_LIST_INIT_TYPED(species_prototypes, /datum/species, init_species_prototypes()) + +/proc/init_species_list() + var/list/species_list = list() + for(var/datum/species/species_path as anything in subtypesof(/datum/species)) + species_list[initial(species_path.id)] = species_path + return species_list + +/proc/init_species_prototypes() + var/list/species_list = list() + for(var/species_type in subtypesof(/datum/species)) + species_list[species_type] = new species_type() + return species_list + GLOBAL_LIST_EMPTY(sentient_disease_instances) GLOBAL_LIST_EMPTY(latejoin_ai_cores) diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm index c51fbaa9eb7a..81fe08373b31 100644 --- a/code/_globalvars/lists/names.dm +++ b/code/_globalvars/lists/names.dm @@ -8,12 +8,12 @@ GLOBAL_LIST_INIT(first_names, world.file2list("strings/names/first.txt")) GLOBAL_LIST_INIT(first_names_male, world.file2list("strings/names/first_male.txt")) GLOBAL_LIST_INIT(first_names_female, world.file2list("strings/names/first_female.txt")) GLOBAL_LIST_INIT(last_names, world.file2list("strings/names/last.txt")) -GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt")) -GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt")) GLOBAL_LIST_INIT(clown_names, world.file2list("strings/names/clown.txt")) GLOBAL_LIST_INIT(mime_names, world.file2list("strings/names/mime.txt")) GLOBAL_LIST_INIT(religion_names, world.file2list("strings/names/religion.txt")) GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt")) +GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt")) +GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt")) GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt")) GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt")) GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt")) diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 664bf50fd666..1d17c515cd9d 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -126,8 +126,8 @@ /// Randomise friend name and appearance /mob/camera/imaginary_friend/proc/setup_friend() - var/gender = pick(MALE, FEMALE) - real_name = random_unique_name(gender) + gender = pick(MALE, FEMALE) + real_name = generate_random_name_species_based(gender, FALSE, /datum/species/human) name = real_name human_image = get_flat_human_icon(null, pick(SSjob.joinable_occupations)) Show() diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 0cf6631f8074..1f432efc7345 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -107,6 +107,12 @@ var/final_effectiveness = effectiveness - target.butcher_difficulty var/bonus_chance = max(0, (final_effectiveness - 100) + bonus_modifier) //so 125 total effectiveness = 25% extra chance + if(target.flags_1 & HOLOGRAM_1) + butcher.visible_message(span_notice("[butcher] tries to butcher [target], but it vanishes."), \ + span_notice("You try to butcher [target], but it vanishes.")) + qdel(target) + return + for(var/result_typepath in target.butcher_results) var/obj/remains = result_typepath var/amount = target.butcher_results[remains] diff --git a/code/datums/datum.dm b/code/datums/datum.dm index bf2b1084d7f2..77d787eb85ba 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -313,6 +313,16 @@ filter_data[name] = copied_parameters update_filters() +///A version of add_filter that takes a list of filters to add rather than being individual, to limit calls to update_filters(). +/datum/proc/add_filters(list/list/filters) + LAZYINITLIST(filter_data) + for(var/list/individual_filter as anything in filters) + var/list/params = individual_filter["params"] + var/list/copied_parameters = params.Copy() + copied_parameters["priority"] = individual_filter["priority"] + filter_data[individual_filter["name"]] = copied_parameters + update_filters() + /// Reapplies all the filters. /datum/proc/update_filters() ASSERT(isatom(src) || isimage(src)) diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm index 255c2a3f3a7f..9654365c49d3 100644 --- a/code/datums/diseases/advance/symptoms/voice_change.dm +++ b/code/datums/diseases/advance/symptoms/voice_change.dm @@ -54,7 +54,7 @@ else if(ishuman(M)) var/mob/living/carbon/human/H = M - H.SetSpecialVoice(H.dna.species.random_name(H.gender)) + H.SetSpecialVoice(H.generate_random_mob_name()) if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure. current_language = pick(subtypesof(/datum/language) - /datum/language/common) H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 2d84900d7955..c275ed4b55cd 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -410,8 +410,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(holder && (human_mutation in mutations)) set_se(0, human_mutation) . = human_mutation.on_losing(holder) - qdel(human_mutation) // qdel mutations on removal - update_instability(FALSE) + if(!(human_mutation in mutations)) + qdel(human_mutation) // qdel mutations on removal + update_instability(FALSE) return /** @@ -478,14 +479,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(create_mutation_blocks) //I hate this generate_dna_blocks() if(randomize_features) - var/static/list/all_species_protoypes - if(isnull(all_species_protoypes)) - all_species_protoypes = list() - for(var/species_path in subtypesof(/datum/species)) - all_species_protoypes += new species_path() - - for(var/datum/species/random_species as anything in all_species_protoypes) - features |= random_species.randomize_features() + for(var/species_type in GLOB.species_prototypes) + var/list/new_features = GLOB.species_prototypes[species_type].randomize_features() + for(var/feature in new_features) + features[feature] = new_features[feature] features["mcolor"] = "#[random_color()]" diff --git a/code/datums/mutations/_mutations.dm b/code/datums/mutations/_mutations.dm index 0f5a15206d8a..4913a057e011 100644 --- a/code/datums/mutations/_mutations.dm +++ b/code/datums/mutations/_mutations.dm @@ -49,6 +49,7 @@ * make sure to enter it both ways (so that A conflicts with B, and B with A) */ var/list/conflicts + var/remove_on_aheal = TRUE /** * can we take chromosomes? diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index ef028e14fb70..7686c00dde48 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -191,26 +191,35 @@ /datum/mutation/human/race name = "Monkified" desc = "A strange genome, believing to be what differentiates monkeys from humans." - text_gain_indication = "You feel unusually monkey-like." - text_lose_indication = "You feel like your old self." + text_gain_indication = span_green("You feel unusually primitive.") + text_lose_indication = span_notice("You feel like your old self.") quality = NEGATIVE + remove_on_aheal = FALSE locked = TRUE //Species specific, keep out of actual gene pool var/datum/species/original_species = /datum/species/human var/original_name /datum/mutation/human/race/on_acquiring(mob/living/carbon/human/owner) - if(..()) + . = ..() + if(.) return - if(!ismonkey(owner)) - original_species = owner.dna.species.type - original_name = owner.real_name - owner.fully_replace_character_name(null, "monkey ([rand(1,999)])") - . = owner.monkeyize() + if(ismonkey(owner)) + return + original_species = owner.dna.species.type + original_name = owner.real_name + owner.monkeyize() /datum/mutation/human/race/on_losing(mob/living/carbon/human/owner) - if(!QDELETED(owner) && owner.stat != DEAD && (owner.dna.mutations.Remove(src)) && ismonkey(owner)) - owner.fully_replace_character_name(null, original_name) - . = owner.humanize(original_species) + if(owner.stat == DEAD) + return + . = ..() + if(.) + return + if(QDELETED(owner)) + return + + owner.fully_replace_character_name(null, original_name) + owner.humanize(original_species) /datum/mutation/human/glow name = "Glowy" diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm index bf4da0d98ea8..5264267417ee 100644 --- a/code/datums/sprite_accessories.dm +++ b/code/datums/sprite_accessories.dm @@ -55,7 +55,7 @@ /// Determines if the accessory will be skipped or included in random hair generations. var/gender = NEUTER /// Something that can be worn by either gender, but looks different on each. - var/gender_specific + var/gender_specific = FALSE /// Determines if the accessory will be skipped by color preferences. var/use_static /** @@ -75,6 +75,9 @@ var/dimension_y = 32 /// Should this sprite block emissives? var/em_block = FALSE + /// Determines if this is considered "sane" for the purpose of [/proc/randomize_human_normie] + /// Basically this is to blacklist the extremely wacky stuff from being picked in random human generation. + var/natural_spawn = TRUE /datum/sprite_accessory/blank name = "None" @@ -103,11 +106,13 @@ /datum/sprite_accessory/hair/afro_large name = "Afro (Large)" icon_state = "hair_bigafro" + natural_spawn = FALSE /datum/sprite_accessory/hair/afro_huge name = "Afro (Huge)" icon_state = "hair_hugeafro" y_offset = 6 + natural_spawn = FALSE /datum/sprite_accessory/hair/allthefuzz name = "All The Fuzz" @@ -148,6 +153,7 @@ /datum/sprite_accessory/hair/bedheadfloorlength name = "Floorlength Bedhead" icon_state = "hair_floorlength_bedhead" + natural_spawn = FALSE /datum/sprite_accessory/hair/badlycut name = "Shorter Long Bedhead" @@ -388,6 +394,7 @@ /datum/sprite_accessory/hair/bigflattop name = "Flat Top (Big)" icon_state = "hair_bigflattop" + natural_spawn = FALSE /datum/sprite_accessory/hair/flow_hair name = "Flow Hair" @@ -448,6 +455,7 @@ /datum/sprite_accessory/hair/joestar name = "Joestar" icon_state = "hair_joestar" + natural_spawn = FALSE /datum/sprite_accessory/hair/keanu name = "Keanu Hair" @@ -504,22 +512,27 @@ /datum/sprite_accessory/hair/mohawk name = "Mohawk" icon_state = "hair_d" + natural_spawn = FALSE // sorry little one /datum/sprite_accessory/hair/nitori name = "Nitori" icon_state = "hair_nitori" + natural_spawn = FALSE /datum/sprite_accessory/hair/reversemohawk name = "Mohawk (Reverse)" icon_state = "hair_reversemohawk" + natural_spawn = FALSE /datum/sprite_accessory/hair/shavedmohawk name = "Mohawk (Shaved)" icon_state = "hair_shavedmohawk" + natural_spawn = FALSE /datum/sprite_accessory/hair/unshavenmohawk name = "Mohawk (Unshaven)" icon_state = "hair_unshaven_mohawk" + natural_spawn = FALSE /datum/sprite_accessory/hair/mulder name = "Mulder" @@ -528,6 +541,7 @@ /datum/sprite_accessory/hair/odango name = "Odango" icon_state = "hair_odango" + natural_spawn = FALSE /datum/sprite_accessory/hair/ombre name = "Ombre" @@ -560,14 +574,17 @@ /datum/sprite_accessory/hair/kagami name = "Pigtails" icon_state = "hair_kagami" + natural_spawn = FALSE /datum/sprite_accessory/hair/pigtail name = "Pigtails 2" icon_state = "hair_pigtails" + natural_spawn = FALSE /datum/sprite_accessory/hair/pigtail2 name = "Pigtails 3" icon_state = "hair_pigtails2" + natural_spawn = FALSE /datum/sprite_accessory/hair/pixie name = "Pixie Cut" @@ -946,6 +963,7 @@ /datum/sprite_accessory/facial_hair/brokenman name = "Beard (Broken Man)" icon_state = "facial_brokenman" + natural_spawn = FALSE /datum/sprite_accessory/facial_hair/chinstrap name = "Beard (Chinstrap)" @@ -990,6 +1008,7 @@ /datum/sprite_accessory/facial_hair/martialartist name = "Beard (Martial Artist)" icon_state = "facial_martialartist" + natural_spawn = FALSE /datum/sprite_accessory/facial_hair/chinlessbeard name = "Beard (Chinless Beard)" @@ -1739,17 +1758,17 @@ /datum/sprite_accessory/body_markings/dtiger name = "Dark Tiger Body" icon_state = "dtiger" - gender_specific = 1 + gender_specific = TRUE /datum/sprite_accessory/body_markings/ltiger name = "Light Tiger Body" icon_state = "ltiger" - gender_specific = 1 + gender_specific = TRUE /datum/sprite_accessory/body_markings/lbelly name = "Light Belly" icon_state = "lbelly" - gender_specific = 1 + gender_specific = TRUE /datum/sprite_accessory/tails em_block = TRUE @@ -1787,14 +1806,12 @@ icon_state = "default" color_src = HAIR_COLOR -/datum/sprite_accessory/tails/monkey +/datum/sprite_accessory/tails/monkey/default + name = "Monkey" icon = 'icons/mob/human/species/monkey/monkey_tail.dmi' + icon_state = "default" color_src = FALSE -/datum/sprite_accessory/tails/monkey/standard - name = "Monkey" - icon_state = "monkey" - /datum/sprite_accessory/pod_hair icon = 'icons/mob/human/species/podperson_hair.dmi' em_block = TRUE diff --git a/code/datums/status_effects/_status_effect.dm b/code/datums/status_effects/_status_effect.dm index b8d77db4ff7f..637f2c3a0767 100644 --- a/code/datums/status_effects/_status_effect.dm +++ b/code/datums/status_effects/_status_effect.dm @@ -13,7 +13,7 @@ /// -1 = will prevent ticks, and if duration is also unlimited (-1), stop processing wholesale. var/tick_interval = 1 SECONDS /// The mob affected by the status effect. - var/mob/living/owner + VAR_FINAL/mob/living/owner /// How many of the effect can be on one mob, and/or what happens when you try to add a duplicate. var/status_type = STATUS_EFFECT_UNIQUE /// If TRUE, we call [proc/on_remove] when owner is deleted. Otherwise, we call [proc/be_replaced]. @@ -22,7 +22,9 @@ /// Status effect "name"s and "description"s are shown to the owner here. var/alert_type = /atom/movable/screen/alert/status_effect /// The alert itself, created in [proc/on_creation] (if alert_type is specified). - var/atom/movable/screen/alert/status_effect/linked_alert + VAR_FINAL/atom/movable/screen/alert/status_effect/linked_alert + /// If TRUE, and we have an alert, we will show a duration on the alert + var/show_duration = FALSE /// Used to define if the status effect should be using SSfastprocess or SSprocessing var/processing_speed = STATUS_EFFECT_FAST_PROCESS /// Do we self-terminate when a fullheal is called? @@ -30,7 +32,7 @@ /// If remove_on_fullheal is TRUE, what flag do we need to be removed? var/heal_flag_necessary = HEAL_STATUS /// A particle effect, for things like embers - Should be set on update_particles() - var/obj/effect/abstract/particle_holder/particle_effect + VAR_FINAL/obj/effect/abstract/particle_holder/particle_effect /datum/status_effect/New(list/arguments) on_creation(arglist(arguments)) @@ -57,6 +59,7 @@ var/atom/movable/screen/alert/status_effect/new_alert = owner.throw_alert(id, alert_type) new_alert.attached_effect = src //so the alert can reference us, if it needs to linked_alert = new_alert //so we can reference the alert, if we need to + update_shown_duration() if(duration > world.time || tick_interval > world.time) //don't process if we don't care switch(processing_speed) @@ -86,14 +89,24 @@ QDEL_NULL(particle_effect) return ..() +/// Updates the status effect alert's maptext (if possible) +/datum/status_effect/proc/update_shown_duration() + PRIVATE_PROC(TRUE) + if(!linked_alert || !show_duration) + return + + linked_alert.maptext = MAPTEXT_TINY_UNICODE("[round((duration - world.time)/10, 1)]s") + // Status effect process. Handles adjusting its duration and ticks. // If you're adding processed effects, put them in [proc/tick] // instead of extending / overriding the process() proc. /datum/status_effect/process(seconds_per_tick) SHOULD_NOT_OVERRIDE(TRUE) + if(QDELETED(owner)) qdel(src) return + if(tick_interval != -1 && tick_interval < world.time) var/tick_length = initial(tick_interval) tick(tick_length / (1 SECONDS)) @@ -101,8 +114,12 @@ if(QDELING(src)) // tick deleted us, no need to continue return - if(duration != -1 && duration < world.time) - qdel(src) + + if(duration != -1) + if(duration < world.time) + qdel(src) + return + update_shown_duration() /// Called whenever the effect is applied in on_created /// Returning FALSE will cause it to delete itself during creation instead. @@ -185,24 +202,25 @@ qdel(src) return TRUE + update_shown_duration() return FALSE /** * Updates the particles for the status effects * Should be handled by subtypes! */ - /datum/status_effect/proc/update_particles() SHOULD_CALL_PARENT(FALSE) + return /// Alert base type for status effect alerts /atom/movable/screen/alert/status_effect name = "Curse of Mundanity" desc = "You don't feel any different..." + maptext_y = 2 /// The status effect we're linked to var/datum/status_effect/attached_effect /atom/movable/screen/alert/status_effect/Destroy() attached_effect = null //Don't keep a ref now return ..() - diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 6cd180ab5970..744f32fca8f8 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -114,6 +114,7 @@ id = "fleshmend" duration = 10 SECONDS alert_type = /atom/movable/screen/alert/status_effect/fleshmend + show_duration = TRUE /datum/status_effect/fleshmend/on_apply() . = ..() @@ -376,6 +377,7 @@ duration = 1 MINUTES status_type = STATUS_EFFECT_REPLACE alert_type = /atom/movable/screen/alert/status_effect/regenerative_core + show_duration = TRUE /datum/status_effect/regenerative_core/on_apply() ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, STATUS_EFFECT_TRAIT) @@ -395,6 +397,7 @@ id = "Lightning Orb" duration = 30 SECONDS alert_type = /atom/movable/screen/alert/status_effect/lightningorb + show_duration = TRUE /datum/status_effect/lightningorb/on_apply() . = ..() @@ -457,6 +460,7 @@ id = "speed_boost" duration = 2 SECONDS status_type = STATUS_EFFECT_REPLACE + show_duration = TRUE /datum/status_effect/speed_boost/on_creation(mob/living/new_owner, set_duration) if(isnum(set_duration)) diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 3c751432d3b5..f4e70c637ea9 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -677,6 +677,7 @@ duration = 150 status_type = STATUS_EFFECT_REFRESH alert_type = /atom/movable/screen/alert/status_effect/convulsing + show_duration = TRUE /datum/status_effect/convulsing/on_creation(mob/living/zappy_boy) . = ..() diff --git a/code/datums/status_effects/food_effects.dm b/code/datums/status_effects/food_effects.dm index e41ef67ad105..625a3fcc8762 100644 --- a/code/datums/status_effects/food_effects.dm +++ b/code/datums/status_effects/food_effects.dm @@ -3,6 +3,8 @@ id = "food_buff" duration = 5 MINUTES // Same as food mood buffs status_type = STATUS_EFFECT_REPLACE // Only one food buff allowed + alert_type = /atom/movable/screen/alert/status_effect/food + show_duration = TRUE /// Buff power var/strength diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 638f4e3367a5..1fe2c90a7791 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -20,7 +20,7 @@ #define GENETIC_DAMAGE_ACCURACY_MULTIPLIER 3 /// Special status indicating a scanner occupant is transforming eg. from monkey to human -#define STATUS_TRANSFORMING 4 +#define STATUS_TRANSFORMING 5 /// Multiplier for how much genetic damage received from DNA Console functionality #define GENETIC_DAMAGE_IRGENETIC_DAMAGE_MULTIPLIER 1 diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index 3a929f7a298a..00dba3722944 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -49,10 +49,8 @@ if(prob(10/severity)) switch(rand(1,5)) if(1) - if(prob(10)) - target.name = "[pick(lizard_name(MALE),lizard_name(FEMALE))]" - else - target.name = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]" + target.name = generate_random_name() + if(2) target.gender = pick("Male", "Female", "Other") if(3) diff --git a/code/game/machinery/medical_kiosk.dm b/code/game/machinery/medical_kiosk.dm index 8978bd4150a1..b9094192a917 100644 --- a/code/game/machinery/medical_kiosk.dm +++ b/code/game/machinery/medical_kiosk.dm @@ -239,6 +239,7 @@ var/blood_percent = round((patient.blood_volume / BLOOD_VOLUME_NORMAL)*100) var/blood_type = "[patient.get_blood_type() || "None"]" // NON-MODULE CHANGE var/blood_warning = " " + var/blood_alcohol = patient.get_blood_alcohol_content() for(var/thing in patient.diseases) //Disease Information var/datum/disease/D = thing @@ -354,6 +355,7 @@ data["bleed_status"] = bleed_status data["blood_levels"] = blood_percent - (chaos_modifier * (rand(1,35))) data["blood_status"] = blood_status + data["blood_alcohol"] = blood_alcohol data["chemical_list"] = chemical_list data["overdose_list"] = overdose_list data["addict_list"] = addict_list diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm index f58ea90211d1..9f5d9e6cc9e7 100644 --- a/code/game/objects/items/cardboard_cutouts.dm +++ b/code/game/objects/items/cardboard_cutouts.dm @@ -296,7 +296,7 @@ outfit = /datum/outfit/ashwalker/spear /datum/cardboard_cutout/ash_walker/get_name() - return lizard_name(pick(MALE, FEMALE)) + return generate_random_name_species_based(species_type = /datum/species/lizard) /datum/cardboard_cutout/death_squad name = "Deathsquad Officer" diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm index 4f6239acbe81..44f53df2c2b2 100644 --- a/code/game/objects/items/debug_items.dm +++ b/code/game/objects/items/debug_items.dm @@ -21,7 +21,7 @@ /obj/item/debug/human_spawner/attack_self(mob/user) ..() - var/choice = input("Select a species", "Human Spawner", null) in GLOB.species_list + var/choice = input("Select a species", "Human Spawner", null) in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc)) selected_species = GLOB.species_list[choice] /obj/item/debug/omnitool @@ -168,4 +168,3 @@ var/turf/loc_turf = get_turf(src) for(var/spawn_atom in (choice == "No" ? typesof(path) : subtypesof(path))) new spawn_atom(loc_turf) - diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 3866afd6add1..19db85cec156 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -372,6 +372,14 @@ render_list += "Blood level: [blood_percent] %, [target.blood_volume] cl, type: [blood_type]\n" // NON-MODULE CHANGE END + // Blood Alcohol Content + var/blood_alcohol_content = target.get_blood_alcohol_content() + if(blood_alcohol_content > 0) + if(blood_alcohol_content >= 0.24) + render_list += "Blood alcohol content: CRITICAL [blood_alcohol_content]%\n" + else + render_list += "Blood alcohol content: [blood_alcohol_content]%\n" + // Cybernetics if(iscarbon(target)) var/mob/living/carbon/carbontarget = target diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index eab3f34d343f..ca1425fe06ac 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -311,6 +311,7 @@ young = TRUE name = "[Mama] Jr" //Icelandic naming convention pending normal_desc = "[src] is a little baby of [maternal_parent] and [paternal_parent]!" //original desc won't be used so the child can have moods + transform *= 0.75 update_desc() Mama.mood_message = pick(Mama.parent_message) diff --git a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm index c89fae800b9b..ee459ec6e317 100644 --- a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm +++ b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm @@ -3,6 +3,7 @@ id = "golem_status" duration = 5 MINUTES alert_type = /atom/movable/screen/alert/status_effect/golem_status + show_duration = TRUE /// Icon state prefix for overlay to display on golem limbs var/overlay_state_prefix /// Name of the mineral we ate to get this diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm index b48cafc85d99..5f19807e4d3d 100644 --- a/code/game/objects/structures/headpike.dm +++ b/code/game/objects/structures/headpike.dm @@ -32,7 +32,7 @@ victim = locate() in parts_list if(!victim) //likely a mapspawned one victim = new(src) - victim.real_name = random_unique_name(prob(50)) + victim.real_name = generate_random_name() spear = locate(speartype) in parts_list if(!spear) spear = new speartype(src) diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 72f28ed82517..339f10b6b181 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -23,6 +23,7 @@ if(length(give_turf_traits)) give_turf_traits = string_list(give_turf_traits) AddElement(/datum/element/give_turf_traits, give_turf_traits) + AddElement(/datum/element/footstep_override, footstep = FOOTSTEP_CATWALK) /datum/armor/structure_lattice melee = 50 @@ -100,10 +101,6 @@ obj_flags = CAN_BE_HIT | BLOCK_Z_OUT_DOWN | BLOCK_Z_IN_UP give_turf_traits = list(TRAIT_TURF_IGNORE_SLOWDOWN, TRAIT_LAVA_STOPPED, TRAIT_CHASM_STOPPED, TRAIT_IMMERSE_STOPPED, TRAIT_HYPERSPACE_STOPPED) -/obj/structure/lattice/catwalk/Initialize(mapload) - . = ..() - AddElement(/datum/element/footstep_override, footstep = FOOTSTEP_CATWALK) - /obj/structure/lattice/catwalk/deconstruction_hints(mob/user) return span_notice("The supporting rods look like they could be cut.") diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 64aa0c60de77..b4cad70d7584 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -11,12 +11,12 @@ user << browse(create_panel_helper(create_mob_html), "window=create_mob;size=425x475") /** - * Randomizes everything about a human, including DNA and name + * Fully randomizes everything about a human, including DNA and name. */ /proc/randomize_human(mob/living/carbon/human/human, randomize_mutations = FALSE) human.gender = human.dna.species.sexes ? pick(MALE, FEMALE, PLURAL, NEUTER) : PLURAL human.physique = human.gender - human.real_name = human.dna?.species.random_name(human.gender) || random_unique_name(human.gender) + human.real_name = human.generate_random_mob_name() human.name = human.get_visible_name() human.set_hairstyle(random_hairstyle(human.gender), update = FALSE) human.set_facial_hairstyle(random_facial_hairstyle(human.gender), update = FALSE) @@ -24,10 +24,39 @@ human.set_facial_haircolor(human.hair_color, update = FALSE) human.eye_color_left = random_eye_color() human.eye_color_right = human.eye_color_left - human.skin_tone = random_skin_tone() + human.skin_tone = pick(GLOB.skin_tones) human.dna.species.randomize_active_underwear_only(human) // Needs to be called towards the end to update all the UIs just set above human.dna.initialize_dna(create_mutation_blocks = randomize_mutations, randomize_features = TRUE) // Snowflake for Ethereals human.updatehealth() human.updateappearance(mutcolor_update = TRUE) + +/** + * Randomizes a human, but produces someone who looks exceedingly average (by most standards). + * + * (IE, no wacky hair styles / colors) + */ +/proc/randomize_human_normie(mob/living/carbon/human/human, randomize_mutations = FALSE) + // Sorry enbys but statistically you are not average enough + human.gender = human.dna.species.sexes ? pick(MALE, FEMALE) : PLURAL + human.physique = human.gender + human.real_name = human.generate_random_mob_name() + human.name = human.get_visible_name() + human.eye_color_left = random_eye_color() + human.eye_color_right = human.eye_color_left + human.skin_tone = pick(GLOB.skin_tones) + // No underwear generation handled here + var/picked_color = random_hair_color() + human.set_haircolor(picked_color, update = FALSE) + human.set_facial_haircolor(picked_color, update = FALSE) + var/datum/sprite_accessory/hairstyle = GLOB.hairstyles_list[random_hairstyle(human.gender)] + if(hairstyle && hairstyle.natural_spawn && !hairstyle.locked) + human.set_hairstyle(hairstyle.name, update = FALSE) + var/datum/sprite_accessory/facial_hair = GLOB.facial_hairstyles_list[random_facial_hairstyle(human.gender)] + if(facial_hair && facial_hair.natural_spawn && !facial_hair.locked) + human.set_facial_hairstyle(facial_hair.name, update = FALSE) + // Normal DNA init stuff, these can generally be wacky but we care less, they're aliens after all + human.dna.initialize_dna(create_mutation_blocks = randomize_mutations, randomize_features = TRUE) + human.updatehealth() + human.updateappearance(mutcolor_update = TRUE) diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index c8c3b660920e..31c34957544e 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -231,10 +231,10 @@ if(isliving(M)) if(iscarbon(M)) //Carbon stuff - if(ismonkey(M)) - M_job = "Monkey" - else if(ishuman(M)) + if(ishuman(M) && M.job) M_job = M.job + else if(ismonkey(M)) + M_job = "Monkey" else if(isalien(M)) //aliens if(islarva(M)) M_job = "Alien larva" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index e5cd0cf21e5e..2313c1741315 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -199,7 +199,12 @@ if(posttransformoutfit && istype(newmob)) newmob.equipOutfit(posttransformoutfit) if("monkey") - M.change_mob_type( /mob/living/carbon/human/species/monkey , null, null, delmob ) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + H.dna.add_mutation(/datum/mutation/human/race, MUT_NORMAL) + H.dna.activate_mutation(/datum/mutation/human/race) + else + M.change_mob_type( /mob/living/carbon/human/species/monkey , null, null, delmob ) if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob ) diff --git a/code/modules/admin/verbs/anonymousnames.dm b/code/modules/admin/verbs/anonymousnames.dm index 9a71d68637a8..7f56155c9989 100644 --- a/code/modules/admin/verbs/anonymousnames.dm +++ b/code/modules/admin/verbs/anonymousnames.dm @@ -94,7 +94,7 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme) return var/mob/living/carbon/human/human_mob = player var/original_name = player.real_name //id will not be changed if you do not do this - randomize_human(player) //do this first so the special name can be given + randomize_human_normie(player) //do this first so the special name can be given player.fully_replace_character_name(original_name, anonymous_name(player)) if(extras_enabled) player_extras(player) @@ -131,8 +131,7 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme) /datum/anonymous_theme/proc/anonymous_name(mob/target) var/datum/client_interface/client = GET_CLIENT(target) var/species_type = client.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type - return species.random_name(target.gender,1) + return generate_random_name_species_based(target.gender, TRUE, species_type) /** * anonymous_ai_name: generates a random name, based off of whatever the round's anonymousnames is set to (but for sillycones). diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index f69745f1f1d6..4bc8fb042354 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -307,7 +307,7 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) else for(var/obj/item/I in D) qdel(I) - randomize_human(D) + randomize_human_normie(D) D.dress_up_as_job( equipping = JB, visual_only = TRUE, diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm index f9879428ddfe..93354850b847 100644 --- a/code/modules/admin/verbs/secrets.dm +++ b/code/modules/admin/verbs/secrets.dm @@ -225,7 +225,7 @@ GLOBAL_DATUM(everyone_a_traitor, /datum/everyone_is_a_traitor_controller) if("allspecies") if(!is_funmin) return - var/result = input(holder, "Please choose a new species","Species") as null|anything in GLOB.species_list + var/result = input(holder, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc)) if(result) SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Species Change", "[result]")) log_admin("[key_name(holder)] turned all humans into [result]") diff --git a/code/modules/antagonists/heretic/magic/realignment.dm b/code/modules/antagonists/heretic/magic/realignment.dm index 081138b7181b..d3ddc03fbbef 100644 --- a/code/modules/antagonists/heretic/magic/realignment.dm +++ b/code/modules/antagonists/heretic/magic/realignment.dm @@ -53,6 +53,7 @@ duration = 8 SECONDS alert_type = /atom/movable/screen/alert/status_effect/realignment tick_interval = 0.2 SECONDS + show_duration = TRUE /datum/status_effect/realignment/get_examine_text() return span_notice("[owner.p_Theyre()] glowing a soft white.") diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm index 607f485ff642..4a6586caa45e 100644 --- a/code/modules/antagonists/heretic/status_effects/buffs.dm +++ b/code/modules/antagonists/heretic/status_effects/buffs.dm @@ -6,6 +6,7 @@ status_type = STATUS_EFFECT_REFRESH duration = 15 SECONDS alert_type = /atom/movable/screen/alert/status_effect/crucible_soul + show_duration = TRUE var/turf/location /datum/status_effect/crucible_soul/on_apply() @@ -30,6 +31,7 @@ id = "Blessing of Dusk and Dawn" status_type = STATUS_EFFECT_REFRESH duration = 60 SECONDS + show_duration = TRUE alert_type =/atom/movable/screen/alert/status_effect/duskndawn /datum/status_effect/duskndawn/on_apply() @@ -47,6 +49,7 @@ status_type = STATUS_EFFECT_REFRESH duration = 60 SECONDS tick_interval = 1 SECONDS + show_duration = TRUE alert_type = /atom/movable/screen/alert/status_effect/marshal /datum/status_effect/marshal/on_apply() @@ -299,6 +302,7 @@ id = "Moon Grasp Hide Identity" status_type = STATUS_EFFECT_REFRESH duration = 15 SECONDS + show_duration = TRUE alert_type = /atom/movable/screen/alert/status_effect/moon_grasp_hide /datum/status_effect/moon_grasp_hide/on_apply() diff --git a/code/modules/antagonists/wizard/grand_ritual/finales/clown.dm b/code/modules/antagonists/wizard/grand_ritual/finales/clown.dm index bda79c908c04..d2f4a5a07635 100644 --- a/code/modules/antagonists/wizard/grand_ritual/finales/clown.dm +++ b/code/modules/antagonists/wizard/grand_ritual/finales/clown.dm @@ -24,8 +24,7 @@ var/datum/action/cooldown/spell/conjure_item/clown_pockets/new_spell = new(victim) new_spell.Grant(victim) continue - if (!ismonkey(victim)) // Monkeys cannot yet wear clothes - dress_as_magic_clown(victim) + dress_as_magic_clown(victim) if (prob(15)) create_vendetta(victim.mind, invoker.mind) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm index 50054417362d..b506b1f4df48 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm @@ -83,21 +83,6 @@ . = ..() disconnect_from_area(area_to_unregister) -///adds a gas or list of gases to our filter_types. used so that the scrubber can check if its supposed to be processing after each change -/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/add_filters(filter_or_filters) - if(!islist(filter_or_filters)) - filter_or_filters = list(filter_or_filters) - - for(var/gas_to_filter in filter_or_filters) - var/translated_gas = istext(gas_to_filter) ? gas_id2path(gas_to_filter) : gas_to_filter - - if(ispath(translated_gas, /datum/gas)) - filter_types |= translated_gas - continue - - atmos_conditions_changed() - return TRUE - ///remove a gas or list of gases from our filter_types.used so that the scrubber can check if its supposed to be processing after each change /obj/machinery/atmospherics/components/unary/vent_scrubber/proc/remove_filters(filter_or_filters) if(!islist(filter_or_filters)) diff --git a/code/modules/capture_the_flag/medieval_sim/medisim_game.dm b/code/modules/capture_the_flag/medieval_sim/medisim_game.dm index 3546ce0881d6..9b274de740f4 100644 --- a/code/modules/capture_the_flag/medieval_sim/medisim_game.dm +++ b/code/modules/capture_the_flag/medieval_sim/medisim_game.dm @@ -23,7 +23,7 @@ if(!.) return var/mob/living/carbon/human/human_knight = . - randomize_human(human_knight) + randomize_human_normie(human_knight) human_knight.dna.add_mutation(/datum/mutation/human/medieval, MUT_OTHER) var/oldname = human_knight.name var/title = "error" diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index 82a9d24451d2..7522e4ff3af7 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -18,16 +18,19 @@ /// support the "use gender" option. #define PREFERENCE_PRIORITY_BODY_TYPE 5 +/// Used for preferences that rely on body setup being finalized. +#define PREFERENCE_PRORITY_LATE_BODY_TYPE 6 + /// Equpping items based on preferences. /// Should happen after species and body type to make sure it looks right. /// Mostly redundant, but a safety net for saving/loading. -#define PREFERENCE_PRIORITY_LOADOUT 6 +#define PREFERENCE_PRIORITY_LOADOUT 7 /// The priority at which names are decided, needed for proper randomization. -#define PREFERENCE_PRIORITY_NAMES 7 +#define PREFERENCE_PRIORITY_NAMES 8 /// Preferences that aren't names, but change the name changes set by PREFERENCE_PRIORITY_NAMES. -#define PREFERENCE_PRIORITY_NAME_MODIFICATIONS 8 +#define PREFERENCE_PRIORITY_NAME_MODIFICATIONS 9 /// The maximum preference priority, keep this updated, but don't use it for `priority`. #define MAX_PREFERENCE_PRIORITY PREFERENCE_PRIORITY_NAME_MODIFICATIONS @@ -336,7 +339,7 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) ) var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] if (!(savefile_key in species.get_features())) return FALSE diff --git a/code/modules/client/preferences/age.dm b/code/modules/client/preferences/age.dm index cad9786ce1fe..07b4644bc6a9 100644 --- a/code/modules/client/preferences/age.dm +++ b/code/modules/client/preferences/age.dm @@ -8,3 +8,6 @@ /datum/preference/numeric/age/apply_to_human(mob/living/carbon/human/target, value) target.age = value + +/datum/preference/numeric/age/create_informed_default_value(datum/preferences/preferences) + return rand(max(minimum, 21), min(maximum, 50)) diff --git a/code/modules/client/preferences/body_type.dm b/code/modules/client/preferences/body_type.dm index 469b564e46f7..6b27e0f0f0da 100644 --- a/code/modules/client/preferences/body_type.dm +++ b/code/modules/client/preferences/body_type.dm @@ -5,6 +5,7 @@ priority = PREFERENCE_PRIORITY_BODY_TYPE savefile_key = "body_type" savefile_identifier = PREFERENCE_CHARACTER + can_randomize = FALSE /datum/preference/choiced/body_type/init_possible_values() return list(USE_GENDER, MALE, FEMALE) diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm index cf200ad1ffd6..b81291c7cbdd 100644 --- a/code/modules/client/preferences/clothing.dm +++ b/code/modules/client/preferences/clothing.dm @@ -33,6 +33,9 @@ DMESSENGER, ) +/datum/preference/choiced/backpack/create_default_value() + return GBACKPACK + /datum/preference/choiced/backpack/icon_for(value) switch (value) if (GBACKPACK) @@ -66,6 +69,7 @@ /datum/preference/choiced/jumpsuit savefile_key = "jumpsuit_style" savefile_identifier = PREFERENCE_CHARACTER + priority = PREFERENCE_PRIORITY_BODY_TYPE main_feature_name = "Jumpsuit" category = PREFERENCE_CATEGORY_CLOTHING should_generate_icons = TRUE @@ -86,6 +90,15 @@ /datum/preference/choiced/jumpsuit/apply_to_human(mob/living/carbon/human/target, value) target.jumpsuit_style = value +/datum/preference/choiced/jumpsuit/create_informed_default_value(datum/preferences/preferences) + switch(preferences.read_preference(/datum/preference/choiced/gender)) + if(MALE) + return PREF_SUIT + if(FEMALE) + return PREF_SKIRT + + return ..() + /// Socks preference /datum/preference/choiced/socks savefile_key = "socks" @@ -93,10 +106,14 @@ main_feature_name = "Socks" category = PREFERENCE_CATEGORY_CLOTHING should_generate_icons = TRUE + can_randomize = FALSE /datum/preference/choiced/socks/init_possible_values() return assoc_to_keys_features(GLOB.socks_list) +/datum/preference/choiced/socks/create_default_value() + return /datum/sprite_accessory/socks/nude::name + /datum/preference/choiced/socks/icon_for(value) var/static/icon/lower_half @@ -114,13 +131,27 @@ /datum/preference/choiced/undershirt savefile_key = "undershirt" savefile_identifier = PREFERENCE_CHARACTER + priority = PREFERENCE_PRIORITY_BODY_TYPE main_feature_name = "Undershirt" category = PREFERENCE_CATEGORY_CLOTHING should_generate_icons = TRUE + can_randomize = FALSE /datum/preference/choiced/undershirt/init_possible_values() return assoc_to_keys_features(GLOB.undershirt_list) +/datum/preference/choiced/undershirt/create_default_value() + return /datum/sprite_accessory/undershirt/nude::name + +/datum/preference/choiced/undershirt/create_informed_default_value(datum/preferences/preferences) + switch(preferences.read_preference(/datum/preference/choiced/gender)) + if(MALE) + return /datum/sprite_accessory/undershirt/nude::name + if(FEMALE) + return /datum/sprite_accessory/undershirt/sports_bra::name + + return ..() + /datum/preference/choiced/undershirt/icon_for(value) var/static/icon/body if (isnull(body)) @@ -152,10 +183,14 @@ main_feature_name = "Underwear" category = PREFERENCE_CATEGORY_CLOTHING should_generate_icons = TRUE + can_randomize = FALSE /datum/preference/choiced/underwear/init_possible_values() return assoc_to_keys_features(GLOB.underwear_list) +/datum/preference/choiced/underwear/create_default_value() + return /datum/sprite_accessory/underwear/male_hearts::name + /datum/preference/choiced/underwear/icon_for(value) var/static/icon/lower_half @@ -175,7 +210,7 @@ return FALSE var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) /datum/preference/choiced/underwear/compile_constant_data() diff --git a/code/modules/client/preferences/gender.dm b/code/modules/client/preferences/gender.dm index bea6674d7b08..a95874f16068 100644 --- a/code/modules/client/preferences/gender.dm +++ b/code/modules/client/preferences/gender.dm @@ -11,3 +11,8 @@ if(!target.dna.species.sexes) value = PLURAL //disregard gender preferences on this species target.gender = value + +/datum/preference/choiced/gender/create_informed_default_value(datum/preferences/preferences) + // The only reason I'm limiting this to male or female + // is that hairstyle randomization handles enbies poorly + return pick(MALE, FEMALE) diff --git a/code/modules/client/preferences/glasses.dm b/code/modules/client/preferences/glasses.dm index 03c975abce78..d8ec141dbe8d 100644 --- a/code/modules/client/preferences/glasses.dm +++ b/code/modules/client/preferences/glasses.dm @@ -4,6 +4,9 @@ savefile_identifier = PREFERENCE_CHARACTER should_generate_icons = TRUE +/datum/preference/choiced/glasses/create_default_value() + return "Random" + /datum/preference/choiced/glasses/init_possible_values() return assoc_to_keys(GLOB.nearsighted_glasses) + "Random" diff --git a/code/modules/client/preferences/language.dm b/code/modules/client/preferences/language.dm index f602d6b3a66c..637c4542da27 100644 --- a/code/modules/client/preferences/language.dm +++ b/code/modules/client/preferences/language.dm @@ -3,6 +3,9 @@ savefile_key = "language" savefile_identifier = PREFERENCE_CHARACTER +/datum/preference/choiced/language/create_default_value() + return "Random" + /datum/preference/choiced/language/is_accessible(datum/preferences/preferences) if (!..(preferences)) return FALSE diff --git a/code/modules/client/preferences/names.dm b/code/modules/client/preferences/names.dm index 476fc7381a28..9afc8da18c1a 100644 --- a/code/modules/client/preferences/names.dm +++ b/code/modules/client/preferences/names.dm @@ -45,12 +45,11 @@ target.log_mob_tag("TAG: [target.tag] RENAMED: [key_name(target)]") /datum/preference/name/real_name/create_informed_default_value(datum/preferences/preferences) - var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/gender = preferences.read_preference(/datum/preference/choiced/gender) - - var/datum/species/species = new species_type - - return species.random_name(gender, unique = TRUE) + return generate_random_name_species_based( + preferences.read_preference(/datum/preference/choiced/gender), + TRUE, + preferences.read_preference(/datum/preference/choiced/species), + ) /datum/preference/name/real_name/deserialize(input, datum/preferences/preferences) input = ..(input) @@ -73,9 +72,7 @@ savefile_key = "human_name" /datum/preference/name/backup_human/create_informed_default_value(datum/preferences/preferences) - var/gender = preferences.read_preference(/datum/preference/choiced/gender) - - return random_unique_name(gender) + return generate_random_name(preferences.read_preference(/datum/preference/choiced/gender)) /datum/preference/name/clown savefile_key = "clown_name" diff --git a/code/modules/client/preferences/species.dm b/code/modules/client/preferences/species.dm index 9e4923d2b11d..1c74d7981b65 100644 --- a/code/modules/client/preferences/species.dm +++ b/code/modules/client/preferences/species.dm @@ -34,7 +34,7 @@ for (var/species_id in get_selectable_species()) var/species_type = GLOB.species_list[species_id] - var/datum/species/species = new species_type() + var/datum/species/species = GLOB.species_prototypes[species_type] data[species_id] = list() data[species_id]["name"] = species.name @@ -47,6 +47,4 @@ data[species_id]["perks"] = species.get_species_perks() data[species_id]["diet"] = species.get_species_diet() - qdel(species) - return data diff --git a/code/modules/client/preferences/species_features/basic.dm b/code/modules/client/preferences/species_features/basic.dm index abf4ea0e44e2..68fac62f43dd 100644 --- a/code/modules/client/preferences/species_features/basic.dm +++ b/code/modules/client/preferences/species_features/basic.dm @@ -7,7 +7,7 @@ var/icon/final_icon = new(head_icon) if (!isnull(sprite_accessory)) ASSERT(istype(sprite_accessory)) - + var/icon/head_accessory_icon = icon(sprite_accessory.icon, sprite_accessory.icon_state) if(y_offset) head_accessory_icon.Shift(NORTH, y_offset) @@ -52,7 +52,7 @@ return random_eye_color() /datum/preference/choiced/facial_hairstyle - priority = PREFERENCE_PRIORITY_BODYPARTS + priority = PREFERENCE_PRORITY_LATE_BODY_TYPE savefile_key = "facial_style_name" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_FEATURES @@ -69,15 +69,32 @@ /datum/preference/choiced/facial_hairstyle/apply_to_human(mob/living/carbon/human/target, value) target.set_facial_hairstyle(value, update = FALSE) +/datum/preference/choiced/facial_hairstyle/create_default_value() + return /datum/sprite_accessory/facial_hair/shaved::name + +/datum/preference/choiced/facial_hairstyle/create_informed_default_value(datum/preferences/preferences) + var/gender = preferences.read_preference(/datum/preference/choiced/gender) + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species_real = GLOB.species_prototypes[species_type] + if(!gender || !species_real || !species_real.sexes) + return ..() + + var/picked_beard = random_facial_hairstyle(gender) + var/datum/sprite_accessory/beard_style = GLOB.facial_hairstyles_list[picked_beard] + if(!beard_style || !beard_style.natural_spawn || beard_style.locked) // Invalid, go with god(bald) + return ..() + + return picked_beard + /datum/preference/choiced/facial_hairstyle/compile_constant_data() var/list/data = ..() - data[SUPPLEMENTAL_FEATURE_KEY] = "facial_hair_color" + data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/color/facial_hair_color::savefile_key return data /datum/preference/color/facial_hair_color - priority = PREFERENCE_PRIORITY_BODYPARTS + priority = PREFERENCE_PRORITY_LATE_BODY_TYPE // Need to happen after hair oclor is set so we can match by default savefile_key = "facial_hair_color" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES @@ -86,12 +103,16 @@ /datum/preference/color/facial_hair_color/apply_to_human(mob/living/carbon/human/target, value) target.set_facial_haircolor(value, update = FALSE) +/datum/preference/color/facial_hair_color/create_informed_default_value(datum/preferences/preferences) + return preferences.read_preference(/datum/preference/color/hair_color) || random_hair_color() + /datum/preference/choiced/facial_hair_gradient - priority = PREFERENCE_PRIORITY_BODYPARTS + priority = PREFERENCE_PRORITY_LATE_BODY_TYPE category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "facial_hair_gradient" relevant_head_flag = HEAD_FACIAL_HAIR + can_randomize = FALSE /datum/preference/choiced/facial_hair_gradient/init_possible_values() return assoc_to_keys_features(GLOB.facial_hair_gradients_list) @@ -100,10 +121,10 @@ target.set_facial_hair_gradient_style(new_style = value, update = FALSE) /datum/preference/choiced/facial_hair_gradient/create_default_value() - return "None" + return /datum/sprite_accessory/gradient/none::name /datum/preference/color/facial_hair_gradient - priority = PREFERENCE_PRIORITY_BODYPARTS + priority = PREFERENCE_PRORITY_LATE_BODY_TYPE category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "facial_hair_gradient_color" @@ -115,10 +136,10 @@ /datum/preference/color/facial_hair_gradient/is_accessible(datum/preferences/preferences) if (!..(preferences)) return FALSE - return preferences.read_preference(/datum/preference/choiced/facial_hair_gradient) != "None" + return preferences.read_preference(/datum/preference/choiced/facial_hair_gradient) != /datum/sprite_accessory/gradient/none::name /datum/preference/color/hair_color - priority = PREFERENCE_PRIORITY_BODYPARTS + priority = PREFERENCE_PRIORITY_BODY_TYPE savefile_key = "hair_color" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES @@ -127,8 +148,11 @@ /datum/preference/color/hair_color/apply_to_human(mob/living/carbon/human/target, value) target.set_haircolor(value, update = FALSE) +/datum/preference/color/hair_color/create_informed_default_value(datum/preferences/preferences) + return random_hair_color() + /datum/preference/choiced/hairstyle - priority = PREFERENCE_PRIORITY_BODYPARTS + priority = PREFERENCE_PRIORITY_BODY_TYPE // Happens after gender so we can picka hairstyle based on that savefile_key = "hairstyle_name" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_FEATURES @@ -146,19 +170,37 @@ /datum/preference/choiced/hairstyle/apply_to_human(mob/living/carbon/human/target, value) target.set_hairstyle(value, update = FALSE) +/datum/preference/choiced/hairstyle/create_default_value() + return /datum/sprite_accessory/hair/bald::name + +/datum/preference/choiced/hairstyle/create_informed_default_value(datum/preferences/preferences) + var/gender = preferences.read_preference(/datum/preference/choiced/gender) + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species_real = GLOB.species_prototypes[species_type] + if(!gender || !species_real || !species_real.sexes) + return ..() + + var/picked_hair = random_hairstyle(gender) + var/datum/sprite_accessory/hair_style = GLOB.hairstyles_list[picked_hair] + if(!hair_style || !hair_style.natural_spawn || hair_style.locked) // Invalid, go with god(bald) + return ..() + + return picked_hair + /datum/preference/choiced/hairstyle/compile_constant_data() var/list/data = ..() - data[SUPPLEMENTAL_FEATURE_KEY] = "hair_color" + data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/color/hair_color::savefile_key return data /datum/preference/choiced/hair_gradient - priority = PREFERENCE_PRIORITY_BODYPARTS + priority = PREFERENCE_PRIORITY_BODY_TYPE category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "hair_gradient" relevant_head_flag = HEAD_HAIR + can_randomize = FALSE /datum/preference/choiced/hair_gradient/init_possible_values() return assoc_to_keys_features(GLOB.hair_gradients_list) @@ -167,10 +209,10 @@ target.set_hair_gradient_style(new_style = value, update = FALSE) /datum/preference/choiced/hair_gradient/create_default_value() - return "None" + return /datum/sprite_accessory/gradient/none::name /datum/preference/color/hair_gradient - priority = PREFERENCE_PRIORITY_BODYPARTS + priority = PREFERENCE_PRIORITY_BODY_TYPE category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "hair_gradient_color" @@ -182,4 +224,4 @@ /datum/preference/color/hair_gradient/is_accessible(datum/preferences/preferences) if (!..(preferences)) return FALSE - return preferences.read_preference(/datum/preference/choiced/hair_gradient) != "None" + return preferences.read_preference(/datum/preference/choiced/hair_gradient) != /datum/sprite_accessory/gradient/none::name diff --git a/code/modules/client/preferences/species_features/felinid.dm b/code/modules/client/preferences/species_features/felinid.dm index b9f3c7bfa337..de794d3b770a 100644 --- a/code/modules/client/preferences/species_features/felinid.dm +++ b/code/modules/client/preferences/species_features/felinid.dm @@ -29,5 +29,4 @@ target.dna.features["ears"] = value /datum/preference/choiced/ears/create_default_value() - var/datum/sprite_accessory/ears/cat/ears = /datum/sprite_accessory/ears/cat - return initial(ears.name) + return /datum/sprite_accessory/ears/cat::name diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm index 8c53d0ba45c6..c070b195f498 100644 --- a/code/modules/client/preferences/species_features/lizard.dm +++ b/code/modules/client/preferences/species_features/lizard.dm @@ -142,5 +142,4 @@ target.dna.features["tail_lizard"] = value /datum/preference/choiced/lizard_tail/create_default_value() - var/datum/sprite_accessory/tails/lizard/smooth/tail = /datum/sprite_accessory/tails/lizard/smooth - return initial(tail.name) + return /datum/sprite_accessory/tails/lizard/smooth::name diff --git a/code/modules/client/preferences/species_features/monkey.dm b/code/modules/client/preferences/species_features/monkey.dm new file mode 100644 index 000000000000..7ad357e21afd --- /dev/null +++ b/code/modules/client/preferences/species_features/monkey.dm @@ -0,0 +1,15 @@ +/datum/preference/choiced/monkey_tail + savefile_key = "feature_monkey_tail" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + relevant_external_organ = /obj/item/organ/external/tail/monkey + can_randomize = FALSE + +/datum/preference/choiced/monkey_tail/init_possible_values() + return assoc_to_keys_features(GLOB.tails_list_monkey) + +/datum/preference/choiced/monkey_tail/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["tail_monkey"] = value + +/datum/preference/choiced/monkey_tail/create_default_value() + return /datum/sprite_accessory/tails/monkey/default::name diff --git a/code/modules/client/preferences/species_features/mutants.dm b/code/modules/client/preferences/species_features/mutants.dm index 7ecf25d9abce..1d18c78ee1ad 100644 --- a/code/modules/client/preferences/species_features/mutants.dm +++ b/code/modules/client/preferences/species_features/mutants.dm @@ -9,7 +9,7 @@ return FALSE var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] return !(TRAIT_FIXED_MUTANT_COLORS in species.inherent_traits) /datum/preference/color/mutant_color/create_default_value() diff --git a/code/modules/client/preferences/underwear_color.dm b/code/modules/client/preferences/underwear_color.dm index 6e64b4423e50..1304bdaf2da8 100644 --- a/code/modules/client/preferences/underwear_color.dm +++ b/code/modules/client/preferences/underwear_color.dm @@ -8,7 +8,7 @@ return FALSE var/species_type = preferences.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) /datum/preference/color/underwear_color/apply_to_human(mob/living/carbon/human/target, value) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 15ba900b756a..6451d180e46a 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -291,13 +291,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car return FALSE // Read everything into cache - for (var/preference_type in GLOB.preference_entries) - var/datum/preference/preference = GLOB.preference_entries[preference_type] + // Uses priority order as some values may rely on others for creating default values + for (var/datum/preference/preference as anything in get_preferences_in_priority_order()) if (preference.savefile_identifier != PREFERENCE_CHARACTER) continue - value_cache -= preference_type - read_preference(preference_type) + value_cache -= preference.type + read_preference(preference.type) //Character randomise = save_data?["randomise"] diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm index 9a3d94e1dbf4..ca82b687d8b4 100644 --- a/code/modules/clothing/suits/labcoat.dm +++ b/code/modules/clothing/suits/labcoat.dm @@ -69,6 +69,10 @@ greyscale_config_worn = /datum/greyscale_config/labcoat/worn greyscale_colors = "#EEEEEE#4A77A1#4A77A1#7095C2" +/obj/item/clothing/suit/toggle/labcoat/genetics/Initialize(mapload) + . = ..() + allowed += /obj/item/sequence_scanner + /obj/item/clothing/suit/toggle/labcoat/chemist name = "chemist labcoat" desc = "A suit that protects against minor chemical spills. Has an orange stripe on the shoulder." @@ -106,6 +110,9 @@ allowed += list( /obj/item/autopsy_scanner, /obj/item/scythe, + /obj/item/shovel, + /obj/item/shovel/serrated, + /obj/item/trench_tool, ) /obj/item/clothing/suit/toggle/labcoat/science diff --git a/code/modules/clothing/suits/wintercoats.dm b/code/modules/clothing/suits/wintercoats.dm index 7ade6df6f7c3..45f17146617c 100644 --- a/code/modules/clothing/suits/wintercoats.dm +++ b/code/modules/clothing/suits/wintercoats.dm @@ -388,6 +388,9 @@ allowed += list( /obj/item/autopsy_scanner, /obj/item/scythe, + /obj/item/shovel, + /obj/item/shovel/serrated, + /obj/item/trench_tool, ) /obj/item/clothing/head/hooded/winterhood/medical/coroner @@ -503,6 +506,10 @@ inhand_icon_state = null hoodtype = /obj/item/clothing/head/hooded/winterhood/science/genetics +/obj/item/clothing/suit/hooded/wintercoat/science/genetics/Initialize(mapload) + . = ..() + allowed += /obj/item/sequence_scanner + /obj/item/clothing/head/hooded/winterhood/science/genetics desc = "A white winter coat hood. It's warm." icon_state = "hood_genetics" @@ -630,6 +637,8 @@ /obj/item/storage/bag/ore, /obj/item/t_scanner/adv_mining_scanner, /obj/item/tank/internals, + /obj/item/shovel, + /obj/item/trench_tool, ) armor_type = /datum/armor/wintercoat_miner hoodtype = /obj/item/clothing/head/hooded/winterhood/miner diff --git a/code/modules/clothing/under/suits.dm b/code/modules/clothing/under/suits.dm index 02f047c2f489..0dbf1880d7d2 100644 --- a/code/modules/clothing/under/suits.dm +++ b/code/modules/clothing/under/suits.dm @@ -84,7 +84,6 @@ desc = "It's a very smart uniform with a special pocket for tip." icon_state = "waiter" inhand_icon_state = "waiter" - supports_variations_flags = CLOTHING_MONKEY_VARIATION /obj/item/clothing/under/suit/black_really name = "executive suit" diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm index 20a5cda05920..e6f7c9f26d00 100644 --- a/code/modules/clothing/under/syndicate.dm +++ b/code/modules/clothing/under/syndicate.dm @@ -8,7 +8,6 @@ alt_covers_chest = TRUE icon = 'icons/obj/clothing/under/syndicate.dmi' worn_icon = 'icons/mob/clothing/under/syndicate.dmi' - supports_variations_flags = CLOTHING_MONKEY_VARIATION /datum/armor/clothing_under/syndicate melee = 10 diff --git a/code/modules/food_and_drinks/machinery/gibber.dm b/code/modules/food_and_drinks/machinery/gibber.dm index 57c3248f8cdc..a33a8d75f177 100644 --- a/code/modules/food_and_drinks/machinery/gibber.dm +++ b/code/modules/food_and_drinks/machinery/gibber.dm @@ -147,6 +147,12 @@ if(!occupant) audible_message(span_hear("You hear a loud metallic grinding sound.")) return + if(occupant.flags_1 & HOLOGRAM_1) + audible_message(span_hear("You hear a very short metallic grinding sound.")) + playsound(loc, 'sound/machines/hiss.ogg', 20, TRUE) + qdel(occupant) + set_occupant(null) + return use_power(active_power_usage) audible_message(span_hear("You hear a loud squelchy grinding sound.")) diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm index 1bbedefb2e0e..afd4c2270388 100644 --- a/code/modules/holodeck/holo_effect.dm +++ b/code/modules/holodeck/holo_effect.dm @@ -62,11 +62,9 @@ mobtype = pick(mobtype) our_mob = new mobtype(loc) our_mob.flags_1 |= HOLOGRAM_1 - ADD_TRAIT(our_mob, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT) // these vars are not really standardized but all would theoretically create stuff on death - for(var/v in list("butcher_results","corpse","weapon1","weapon2","blood_volume") & our_mob.vars) - our_mob.vars[v] = null + our_mob.add_traits(list(TRAIT_PERMANENTLY_MORTAL, TRAIT_NO_BLOOD_OVERLAY, TRAIT_NOBLOOD, TRAIT_NOHUNGER), INNATE_TRAIT) RegisterSignal(our_mob, COMSIG_QDELETING, PROC_REF(handle_mob_delete)) return our_mob @@ -103,7 +101,7 @@ mobtype = /mob/living/basic/bee/toxin /obj/effect/holodeck_effect/mobspawner/monkey - mobtype = /mob/living/carbon/human/species/monkey/holodeck + mobtype = /mob/living/carbon/human/species/monkey /obj/effect/holodeck_effect/mobspawner/monkey/activate(obj/machinery/computer/holodeck/computer) var/mob/living/carbon/human/monkey = ..() diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 06cb8cbc55d9..65b5d9a4100d 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -117,6 +117,9 @@ ///RPG job names, for the memes var/rpg_title + /// Alternate titles to register as pointing to this job. + var/list/alternate_titles + /// Does this job ignore human authority? var/ignore_human_authority = FALSE @@ -545,11 +548,11 @@ dna.species.roundstart_changed = TRUE apply_pref_name(/datum/preference/name/backup_human, player_client) if(CONFIG_GET(flag/force_random_names)) - var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type - - var/gender = player_client.prefs.read_preference(/datum/preference/choiced/gender) - real_name = species.random_name(gender, TRUE) + real_name = generate_random_name_species_based( + player_client.prefs.read_preference(/datum/preference/choiced/gender), + TRUE, + player_client.prefs.read_preference(/datum/preference/choiced/species), + ) dna.update_dna_identity() @@ -571,9 +574,11 @@ if(!player_client) return // Disconnected while checking the appearance ban. - var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type - organic_name = species.random_name(player_client.prefs.read_preference(/datum/preference/choiced/gender), TRUE) + organic_name = generate_random_name_species_based( + player_client.prefs.read_preference(/datum/preference/choiced/gender), + TRUE, + player_client.prefs.read_preference(/datum/preference/choiced/species), + ) else if(!player_client) return // Disconnected while checking the appearance ban. diff --git a/code/modules/language/_language.dm b/code/modules/language/_language.dm new file mode 100644 index 000000000000..3876720cbd44 --- /dev/null +++ b/code/modules/language/_language.dm @@ -0,0 +1,164 @@ +/// maximum of 50 specific scrambled lines per language +#define SCRAMBLE_CACHE_LEN 50 + +/// Datum based languages. Easily editable and modular. +/datum/language + /// Fluff name of language if any. + var/name = "an unknown language" + /// Short description for 'Check Languages'. + var/desc = "A language." + /// Character used to speak in language + /// If key is null, then the language isn't real or learnable. + var/key + /// Various language flags. + var/flags = NONE + /// Used when scrambling text for a non-speaker. + var/list/syllables + /// List of characters that will randomly be inserted between syllables. + var/list/special_characters + /// Likelihood of making a new sentence after each syllable. + var/sentence_chance = 5 + /// Likelihood of getting a space in the random scramble string + var/space_chance = 55 + /// Spans to apply from this language + var/list/spans + /// Cache of recently scrambled text + /// This allows commonly reused words to not require a full re-scramble every time. + var/list/scramble_cache = list() + /// The language that an atom knows with the highest "default_priority" is selected by default. + var/default_priority = 0 + /// If TRUE, when generating names, we will always use the default human namelist, even if we have syllables set. + /// This is to be used for languages with very outlandish syllable lists (like pirates). + var/always_use_default_namelist = FALSE + /// Icon displayed in the chat window when speaking this language. + /// if you are seeing someone speak popcorn language, then something is wrong. + var/icon = 'icons/misc/language.dmi' + /// Icon state displayed in the chat window when speaking this language. + var/icon_state = "popcorn" + + /// By default, random names picks this many names + var/default_name_count = 2 + /// By default, random names picks this many syllables (min) + var/default_name_syllable_min = 2 + /// By default, random names picks this many syllables (max) + var/default_name_syllable_max = 4 + /// What char to place in between randomly generated names + var/random_name_spacer = " " + +/// Checks whether we should display the language icon to the passed hearer. +/datum/language/proc/display_icon(atom/movable/hearer) + var/understands = hearer.has_language(src.type) + if((flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD) && understands) + return FALSE + if((flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD) && !understands) + return FALSE + return TRUE + +/// Returns the icon to display in the chat window when speaking this language. +/datum/language/proc/get_icon() + var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat) + return sheet.icon_tag("language-[icon_state]") + +/// Simple helper for getting a default firstname lastname +/datum/language/proc/default_name(gender = NEUTER) + if(gender != MALE) + gender = pick(MALE, FEMALE) + if(gender == FEMALE) + return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + + +/** + * Generates a random name this language would use. + * + * * gender: What gender to generate from, if neuter / plural coin flips between male and female + * * name_count: How many names to generate in, by default 2, for firstname lastname + * * syllable_count: How many syllables to generate in each name, min + * * syllable_max: How many syllables to generate in each name, max + * * force_use_syllables: If the name should be generated from the syllables list. + * Only used for subtypes which implement custom name lists. Also requires the language has syllables set. + */ +/datum/language/proc/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(gender != MALE) + gender = pick(MALE, FEMALE) + if(!length(syllables) || always_use_default_namelist) + return default_name(gender) + + var/list/full_name = list() + for(var/i in 1 to name_count) + var/new_name = "" + for(var/j in 1 to rand(default_name_syllable_min, default_name_syllable_max)) + new_name += pick_weight_recursive(syllables) + full_name += capitalize(lowertext(new_name)) + + return jointext(full_name, random_name_spacer) + +/// Generates a random name, and attempts to ensure it is unique (IE, no other mob in the world has it) +/datum/language/proc/get_random_unique_name(...) + var/result = get_random_name(arglist(args)) + for(var/i in 1 to 10) + if(!findname(result)) + break + result = get_random_name(arglist(args)) + + return result + +/datum/language/proc/check_cache(input) + var/lookup = scramble_cache[input] + if(lookup) + scramble_cache -= input + scramble_cache[input] = lookup + . = lookup + +/datum/language/proc/add_to_cache(input, scrambled_text) + // Add it to cache, cutting old entries if the list is too long + scramble_cache[input] = scrambled_text + if(scramble_cache.len > SCRAMBLE_CACHE_LEN) + scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1) + +/datum/language/proc/scramble(input) + + if(!length(syllables)) + return stars(input) + + // If the input is cached already, move it to the end of the cache and return it + var/lookup = check_cache(input) + if(lookup) + return lookup + + var/input_size = length_char(input) + var/scrambled_text = "" + var/capitalize = TRUE + + while(length_char(scrambled_text) < input_size) + var/next = (length(scrambled_text) && length(special_characters) && prob(1)) ? pick(special_characters) : pick_weight_recursive(syllables) + if(capitalize) + next = capitalize(next) + capitalize = FALSE + scrambled_text += next + var/chance = rand(100) + if(chance <= sentence_chance) + scrambled_text += ". " + capitalize = TRUE + else if(chance > sentence_chance && chance <= space_chance) + scrambled_text += " " + + scrambled_text = trim(scrambled_text) + var/ending = copytext_char(scrambled_text, -1) + if(ending == ".") + scrambled_text = copytext_char(scrambled_text, 1, -2) + var/input_ending = copytext_char(input, -1) + if(input_ending in list("!","?",".")) + scrambled_text += input_ending + + add_to_cache(input, scrambled_text) + + return scrambled_text + +#undef SCRAMBLE_CACHE_LEN diff --git a/code/modules/language/language_holder.dm b/code/modules/language/_language_holder.dm similarity index 100% rename from code/modules/language/language_holder.dm rename to code/modules/language/_language_holder.dm diff --git a/code/modules/language/language_manuals.dm b/code/modules/language/_language_manuals.dm similarity index 100% rename from code/modules/language/language_manuals.dm rename to code/modules/language/_language_manuals.dm diff --git a/code/modules/language/language_menu.dm b/code/modules/language/_language_menu.dm similarity index 100% rename from code/modules/language/language_menu.dm rename to code/modules/language/_language_menu.dm diff --git a/code/modules/language/aphasia.dm b/code/modules/language/aphasia.dm index 9d4e317c4d88..2d82b79892ee 100644 --- a/code/modules/language/aphasia.dm +++ b/code/modules/language/aphasia.dm @@ -7,3 +7,4 @@ space_chance = 20 default_priority = 10 icon_state = "aphasia" + always_use_default_namelist = TRUE // Shouldn't generate names for this anyways diff --git a/code/modules/language/beachbum.dm b/code/modules/language/beachbum.dm index d78be9788f35..bd319e717ffd 100644 --- a/code/modules/language/beachbum.dm +++ b/code/modules/language/beachbum.dm @@ -17,5 +17,5 @@ "heavy", "stellar", "excellent", "triumphant", "babe", "four", "tail", "trim", "tube", "wobble", "roll", "gnarly", "epic", ) - icon_state = "beach" + always_use_default_namelist = TRUE diff --git a/code/modules/language/buzzwords.dm b/code/modules/language/buzzwords.dm index c46088c0ad5b..2ed033bca345 100644 --- a/code/modules/language/buzzwords.dm +++ b/code/modules/language/buzzwords.dm @@ -8,3 +8,4 @@ ) icon_state = "buzz" default_priority = 90 + always_use_default_namelist = TRUE // Otherwise we get Bzzbzbz Zzzbzbz. diff --git a/code/modules/language/calcic.dm b/code/modules/language/calcic.dm index f4882e1105b9..477e442203bc 100644 --- a/code/modules/language/calcic.dm +++ b/code/modules/language/calcic.dm @@ -13,4 +13,16 @@ icon_state = "calcic" default_priority = 90 +/datum/language/calcic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + + return "[pick(GLOB.plasmaman_names)] \Roman[rand(1, 99)]" + // Yeah, this goes to skeletons too, since it's basically just skeleton clacking. diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm index 09db7ef511b4..242095b3bb7f 100644 --- a/code/modules/language/codespeak.dm +++ b/code/modules/language/codespeak.dm @@ -5,6 +5,7 @@ default_priority = 0 flags = TONGUELESS_SPEECH | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD icon_state = "codespeak" + always_use_default_namelist = TRUE // No syllables anyways /datum/language/codespeak/scramble(input) var/lookup = check_cache(input) diff --git a/code/modules/language/common.dm b/code/modules/language/common.dm index 2dc7294983c0..6bad808fef26 100644 --- a/code/modules/language/common.dm +++ b/code/modules/language/common.dm @@ -7,50 +7,51 @@ default_priority = 100 icon_state = "galcom" - -//Syllable Lists -/* - This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed, - and the english syllables had to be duplicated so that there is roughly a 50-50 weighting. - - Sources: - http://www.sttmedia.com/syllablefrequency-english - http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm -*/ -/datum/language/common/syllables = list( - // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese - list( - "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", - "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", - "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", - "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", - "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", - "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", - "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", - "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", - "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", - "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", - "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", - "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", - "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", - "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", - "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", - "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", - "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", - "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", - "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", - "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", - "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", - "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", - "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", - "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", - "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", - "zong", "zou", "zuan", "zui", "zun", "zuo", "zu", - ), - list( - "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", - "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", - "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", - "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", - ), -) + // Default namelist is the human namelist, and common is the human language, so might as well. + // Feel free to remove this at some point because common can generate some pretty cool names. + always_use_default_namelist = TRUE + /** + * This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed, + * and the english syllables had to be duplicated so that there is roughly a 50-50 weighting. + * + * Sources: + * http://www.sttmedia.com/syllablefrequency-english + * http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm + */ + syllables = list( + // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese + list( + "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", + "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", + "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", + "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", + "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", + "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", + "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", + "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", + "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", + "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", + "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", + "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", + "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", + "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", + "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", + "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", + "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", + "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", + "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", + "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", + "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", + "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", + "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", + "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", + "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", + "zong", "zou", "zuan", "zui", "zun", "zuo", "zu", + ), + list( + "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", + "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", + "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", + "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", + ), + ) diff --git a/code/modules/language/draconic.dm b/code/modules/language/draconic.dm index f812c8dc1311..55ebd1ec2026 100644 --- a/code/modules/language/draconic.dm +++ b/code/modules/language/draconic.dm @@ -13,5 +13,25 @@ "ra", "ar", "re", "er", "ri", "ir", "ro", "or", "ru", "ur", "rs", "sr", "a", "a", "e", "e", "i", "i", "o", "o", "u", "u", "s", "s" ) + special_characters = list("-") icon_state = "lizard" default_priority = 90 + default_name_syllable_min = 3 + default_name_syllable_max = 5 + random_name_spacer = "-" + +/datum/language/draconic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + if(gender != MALE) + gender = pick(MALE, FEMALE) + + if(gender == MALE) + return "[pick(GLOB.lizard_names_male)][random_name_spacer][pick(GLOB.lizard_names_male)]" + return "[pick(GLOB.lizard_names_female)][random_name_spacer][pick(GLOB.lizard_names_female)]" diff --git a/code/modules/language/drone.dm b/code/modules/language/drone.dm index 5b47533d45e3..09fb6546e4a1 100644 --- a/code/modules/language/drone.dm +++ b/code/modules/language/drone.dm @@ -11,3 +11,4 @@ default_priority = 20 icon_state = "drone" + always_use_default_namelist = TRUE // Nonsense language diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm deleted file mode 100644 index a47d097dd140..000000000000 --- a/code/modules/language/language.dm +++ /dev/null @@ -1,107 +0,0 @@ -#define SCRAMBLE_CACHE_LEN 50 //maximum of 50 specific scrambled lines per language - -/* - Datum based languages. Easily editable and modular. -*/ - -/datum/language - var/name = "an unknown language" // Fluff name of language if any. - var/desc = "A language." // Short description for 'Check Languages'. - var/key // Character used to speak in language - // If key is null, then the language isn't real or learnable. - var/flags // Various language flags. - var/list/syllables // Used when scrambling text for a non-speaker. - var/sentence_chance = 5 // Likelihood of making a new sentence after each syllable. - var/space_chance = 55 // Likelihood of getting a space in the random scramble string - var/list/spans = list() - var/list/scramble_cache = list() - var/default_priority = 0 // the language that an atom knows with the highest "default_priority" is selected by default. - - // if you are seeing someone speak popcorn language, then something is wrong. - var/icon = 'icons/misc/language.dmi' - var/icon_state = "popcorn" - -/datum/language/proc/display_icon(atom/movable/hearer) - var/understands = hearer.has_language(src.type) - if(flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD && understands) - return FALSE - if(flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD && !understands) - return FALSE - return TRUE - -/datum/language/proc/get_icon() - var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat) - return sheet.icon_tag("language-[icon_state]") - -/datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2) - if(!syllables || !syllables.len) - if(gender == FEMALE) - return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) - else - return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - - var/full_name = "" - var/new_name = "" - - for(var/i in 0 to name_count) - new_name = "" - var/Y = rand(FLOOR(syllable_count/syllable_divisor, 1), syllable_count) - for(var/x in Y to 0) - new_name += pick_weight_recursive(syllables) - full_name += " [capitalize(lowertext(new_name))]" - - return "[trim(full_name)]" - -/datum/language/proc/check_cache(input) - var/lookup = scramble_cache[input] - if(lookup) - scramble_cache -= input - scramble_cache[input] = lookup - . = lookup - -/datum/language/proc/add_to_cache(input, scrambled_text) - // Add it to cache, cutting old entries if the list is too long - scramble_cache[input] = scrambled_text - if(scramble_cache.len > SCRAMBLE_CACHE_LEN) - scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1) - -/datum/language/proc/scramble(input) - - if(!syllables || !syllables.len) - return stars(input) - - // If the input is cached already, move it to the end of the cache and return it - var/lookup = check_cache(input) - if(lookup) - return lookup - - var/input_size = length_char(input) - var/scrambled_text = "" - var/capitalize = TRUE - - while(length_char(scrambled_text) < input_size) - var/next = pick_weight_recursive(syllables) - if(capitalize) - next = capitalize(next) - capitalize = FALSE - scrambled_text += next - var/chance = rand(100) - if(chance <= sentence_chance) - scrambled_text += ". " - capitalize = TRUE - else if(chance > sentence_chance && chance <= space_chance) - scrambled_text += " " - - scrambled_text = trim(scrambled_text) - var/ending = copytext_char(scrambled_text, -1) - if(ending == ".") - scrambled_text = copytext_char(scrambled_text, 1, -2) - var/input_ending = copytext_char(input, -1) - if(input_ending in list("!","?",".")) - scrambled_text += input_ending - - add_to_cache(input, scrambled_text) - - return scrambled_text - -#undef SCRAMBLE_CACHE_LEN diff --git a/code/modules/language/machine.dm b/code/modules/language/machine.dm index 36962a712a1b..4be282a5e281 100644 --- a/code/modules/language/machine.dm +++ b/code/modules/language/machine.dm @@ -14,7 +14,16 @@ icon_state = "eal" -/datum/language/machine/get_random_name() +/datum/language/machine/get_random_name( + gender = NEUTER, + name_count = 2, + syllable_min = 2, + syllable_max = 4, + unique = FALSE, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() if(prob(70)) return "[pick(GLOB.posibrain_names)]-[rand(100, 999)]" return pick(GLOB.ai_names) diff --git a/code/modules/language/moffic.dm b/code/modules/language/moffic.dm index 1d0aea96697f..fb8dea63dcc8 100644 --- a/code/modules/language/moffic.dm +++ b/code/modules/language/moffic.dm @@ -13,4 +13,20 @@ icon_state = "moth" default_priority = 90 + default_name_syllable_min = 5 + default_name_syllable_max = 10 + +/datum/language/moffic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + + return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]" + + // Fuck guest accounts, and fuck language testing. diff --git a/code/modules/language/monkey.dm b/code/modules/language/monkey.dm index e44f6a6268e2..423e94f22bd8 100644 --- a/code/modules/language/monkey.dm +++ b/code/modules/language/monkey.dm @@ -7,3 +7,12 @@ default_priority = 80 icon_state = "animal" + +/datum/language/monkey/get_random_name( + gender = NEUTER, + name_count = 2, + syllable_min = 2, + syllable_max = 4, + force_use_syllables = FALSE, +) + return "monkey ([rand(1, 999)])" diff --git a/code/modules/language/mushroom.dm b/code/modules/language/mushroom.dm index 08d494cc04d6..910489fd6dd9 100644 --- a/code/modules/language/mushroom.dm +++ b/code/modules/language/mushroom.dm @@ -5,3 +5,5 @@ sentence_chance = 0 default_priority = 80 syllables = list("poof", "pff", "pFfF", "piff", "puff", "pooof", "pfffff", "piffpiff", "puffpuff", "poofpoof", "pifpafpofpuf") + default_name_syllable_min = 1 + default_name_syllable_max = 2 diff --git a/code/modules/language/nekomimetic.dm b/code/modules/language/nekomimetic.dm index 82edc2afcb57..4be943f84417 100644 --- a/code/modules/language/nekomimetic.dm +++ b/code/modules/language/nekomimetic.dm @@ -12,3 +12,16 @@ ) icon_state = "neko" default_priority = 90 + default_name_syllable_min = 2 + default_name_syllable_max = 2 + +/datum/language/nekomimetic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(prob(33)) + return default_name(gender) + return ..() diff --git a/code/modules/language/piratespeak.dm b/code/modules/language/piratespeak.dm index 5f6cb4897715..a2faddb544f7 100644 --- a/code/modules/language/piratespeak.dm +++ b/code/modules/language/piratespeak.dm @@ -10,3 +10,4 @@ "shiver", "timbers", "matey", "swashbuckler" ) icon_state = "pirate" + always_use_default_namelist = TRUE diff --git a/code/modules/language/shadowtongue.dm b/code/modules/language/shadowtongue.dm index 9c0adb5eea3f..351589393856 100644 --- a/code/modules/language/shadowtongue.dm +++ b/code/modules/language/shadowtongue.dm @@ -16,3 +16,5 @@ ) icon_state = "shadow" default_priority = 90 + default_name_syllable_min = 2 + default_name_syllable_max = 3 diff --git a/code/modules/language/slime.dm b/code/modules/language/slime.dm index fcb471774118..15960898673d 100644 --- a/code/modules/language/slime.dm +++ b/code/modules/language/slime.dm @@ -2,7 +2,8 @@ name = "Slime" desc = "A melodic and complex language spoken by slimes. Some of the notes are inaudible to humans." key = "k" - syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!") + syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix") + special_characters = list("!","*") default_priority = 70 icon_state = "slime" diff --git a/code/modules/language/sylvan.dm b/code/modules/language/sylvan.dm index 68cb73f9d525..4f66fb5931c1 100644 --- a/code/modules/language/sylvan.dm +++ b/code/modules/language/sylvan.dm @@ -13,3 +13,5 @@ ) icon_state = "plant" default_priority = 90 + default_name_syllable_min = 2 + default_name_syllable_max = 3 diff --git a/code/modules/language/terrum.dm b/code/modules/language/terrum.dm index 361106ed16c9..63b527202f4c 100644 --- a/code/modules/language/terrum.dm +++ b/code/modules/language/terrum.dm @@ -7,8 +7,25 @@ "sha", "vu", "nah", "ha", "yom", "ma", "cha", "ar", "et", "mol", "lua", "ch", "na", "sh", "ni", "yah", "bes", "ol", "hish", "ev", "la", "ot", "la", "khe", "tza", "chak", "hak", "hin", "hok", "lir", "tov", "yef", "yfe", - "cho", "ar", "kas", "kal", "ra", "lom", "im", "'", "'", "'", "'", "bok", + "cho", "ar", "kas", "kal", "ra", "lom", "im", "bok", "erev", "shlo", "lo", "ta", "im", "yom" ) + special_characters = list("'") icon_state = "golem" default_priority = 90 + +/datum/language/terrum/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + + var/name = pick(GLOB.golem_names) + // 3% chance to be given a human surname for "lore reasons" + if (prob(3)) + name += " [pick(GLOB.last_names)]" + return name diff --git a/code/modules/language/voltaic.dm b/code/modules/language/voltaic.dm index 40fa9dcb1e82..90ab90dbe48e 100644 --- a/code/modules/language/voltaic.dm +++ b/code/modules/language/voltaic.dm @@ -12,3 +12,21 @@ ) icon_state = "volt" default_priority = 90 + default_name_syllable_min = 2 + default_name_syllable_max = 3 + + +/datum/language/voltaic/get_random_name( + gender = NEUTER, + name_count = default_name_count, + syllable_min = default_name_syllable_min, + syllable_max = default_name_syllable_max, + force_use_syllables = FALSE, +) + if(force_use_syllables) + return ..() + + var/picked = "[pick(GLOB.ethereal_names)] [random_capital_letter()]" + if(prob(65)) + picked += random_capital_letter() + return picked diff --git a/code/modules/language/xenocommon.dm b/code/modules/language/xenocommon.dm index c5e6366715d8..f4949b7d73cb 100644 --- a/code/modules/language/xenocommon.dm +++ b/code/modules/language/xenocommon.dm @@ -6,3 +6,4 @@ default_priority = 50 icon_state = "xeno" + always_use_default_namelist = TRUE // Sssss Ssss? diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index ed69e8af884b..3824bc9eefff 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -921,8 +921,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) var/datum/species/new_human_species = GLOB.species_list[species_to_pick] if(new_human_species) new_human.set_species(new_human_species) - new_human_species = new_human.dna.species - new_human.fully_replace_character_name(new_human.real_name, new_human_species.random_name(new_human.gender, TRUE, TRUE)) + new_human.fully_replace_character_name(new_human.real_name, new_human.generate_random_mob_name()) else stack_trace("failed to spawn cadaver with species ID [species_to_pick]") //if it's invalid they'll just be a human, so no need to worry too much aside from yelling at the server owner lol. else diff --git a/code/modules/mining/equipment/monster_organs/rush_gland.dm b/code/modules/mining/equipment/monster_organs/rush_gland.dm index b3932afdaab7..7a97248df0bc 100644 --- a/code/modules/mining/equipment/monster_organs/rush_gland.dm +++ b/code/modules/mining/equipment/monster_organs/rush_gland.dm @@ -41,6 +41,7 @@ id = "lobster_rush" duration = 3 SECONDS alert_type = /atom/movable/screen/alert/status_effect/lobster_rush + show_duration = TRUE var/spawned_last_move = FALSE /atom/movable/screen/alert/status_effect/lobster_rush diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 525f6c636df9..0c9a5b942ab2 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -89,15 +89,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) gender = body.gender if(body.mind && body.mind.name) - if(body.mind.ghostname) - name = body.mind.ghostname - else - name = body.mind.name + name = body.mind.ghostname || body.mind.name else - if(body.real_name) - name = body.real_name - else - name = random_unique_name(gender) + name = body.real_name || generate_random_mob_name(gender) + mind = body.mind //we don't transfer the mind but we keep a reference to it. @@ -125,8 +120,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) abstract_move(T) - if(!name) //To prevent nameless ghosts - name = random_unique_name(gender) + //To prevent nameless ghosts + name ||= generate_random_mob_name(FALSE) real_name = name if(!fun_verbs) @@ -860,7 +855,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp client.prefs.apply_character_randomization_prefs() var/species_type = client.prefs.read_preference(/datum/preference/choiced/species) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] if(species.check_head_flags(HEAD_HAIR)) hairstyle = client.prefs.read_preference(/datum/preference/choiced/hairstyle) hair_color = brighten_color(client.prefs.read_preference(/datum/preference/color/hair_color)) @@ -869,8 +864,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp facial_hairstyle = client.prefs.read_preference(/datum/preference/choiced/facial_hairstyle) facial_hair_color = brighten_color(client.prefs.read_preference(/datum/preference/color/facial_hair_color)) - qdel(species) - update_appearance() /mob/dead/observer/can_perform_action(atom/movable/target, action_bitflags) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 219d8e357e7c..b5957a70b852 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -467,7 +467,12 @@ if(M.active_storage?.attempt_insert(src, M)) return TRUE - var/list/obj/item/possible = list(M.get_inactive_held_item(), M.get_item_by_slot(ITEM_SLOT_BELT), M.get_item_by_slot(ITEM_SLOT_DEX_STORAGE), M.get_item_by_slot(ITEM_SLOT_BACK)) + var/list/obj/item/possible = list( + M.get_inactive_held_item(), + M.get_item_by_slot(ITEM_SLOT_BELT), + M.get_item_by_slot(ITEM_SLOT_DEX_STORAGE), + M.get_item_by_slot(ITEM_SLOT_BACK), + ) for(var/i in possible) if(!i) continue diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index 5a901fa2c79c..c906ce17c319 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -102,7 +102,7 @@ RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned)) RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move)) RegisterSignal(src, COMSIG_LIVING_LIFE, PROC_REF(on_life)) - set_random_revenant_name() + name = generate_random_mob_name() GLOB.revenant_relay_mobs |= src @@ -345,13 +345,13 @@ returnable_list += span_bold("Be sure to read the wiki page to learn more.") return returnable_list -/mob/living/basic/revenant/proc/set_random_revenant_name() +/mob/living/basic/revenant/generate_random_mob_name() var/list/built_name_strings = list() built_name_strings += pick(strings(REVENANT_NAME_FILE, "spirit_type")) built_name_strings += " of " built_name_strings += pick(strings(REVENANT_NAME_FILE, "adverb")) built_name_strings += pick(strings(REVENANT_NAME_FILE, "theme")) - name = built_name_strings.Join("") + return built_name_strings.Join("") /mob/living/basic/revenant/proc/on_baned(obj/item/weapon, mob/living/user) SIGNAL_HANDLER diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm index 70b3506527a1..bba6e0eb460c 100644 --- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm +++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/inflation.dm @@ -39,6 +39,7 @@ id = "wumbo_inflated" duration = 10 SECONDS alert_type = /atom/movable/screen/alert/status_effect/inflated + show_duration = TRUE /atom/movable/screen/alert/status_effect/inflated name = "WUMBO" diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 58df9bb19bf3..702c0725735c 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -1,4 +1,6 @@ #define BLOOD_DRIP_RATE_MOD 90 //Greater number means creating blood drips more often while bleeding +// Conversion between internal drunk power and common blood alcohol content +#define DRUNK_POWER_TO_BLOOD_ALCOHOL 0.003 /**************************************************** BLOOD SYSTEM @@ -310,4 +312,13 @@ // NON-MODULE CHANGE END +/mob/living/proc/get_blood_alcohol_content() + var/blood_alcohol_content = 0 + var/datum/status_effect/inebriated/inebriation = has_status_effect(/datum/status_effect/inebriated) + if(!isnull(inebriation)) + blood_alcohol_content = round(inebriation.drunk_value * DRUNK_POWER_TO_BLOOD_ALCOHOL, 0.01) + + return blood_alcohol_content + #undef BLOOD_DRIP_RATE_MOD +#undef DRUNK_POWER_TO_BLOOD_ALCOHOL diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index e1f2fc05c99b..f1516906b387 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1370,7 +1370,6 @@ else set_lying_angle(new_lying_angle) - /mob/living/carbon/vv_edit_var(var_name, var_value) switch(var_name) if(NAMEOF(src, disgust)) @@ -1386,17 +1385,18 @@ return ..() - /mob/living/carbon/get_attack_type() if(has_active_hand()) var/obj/item/bodypart/arm/active_arm = get_active_hand() return active_arm.attack_type return ..() - /mob/living/carbon/proc/attach_rot() - if(mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD)) - AddComponent(/datum/component/rot, 6 MINUTES, 10 MINUTES, 1) + if(flags_1 & HOLOGRAM_1) + return + if(!(mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD))) + return + AddComponent(/datum/component/rot, 6 MINUTES, 10 MINUTES, 1) /** * This proc is used to determine whether or not the mob can handle touching an acid affected object. diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index 5071bdcbc1ea..3cc47547c479 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -483,7 +483,7 @@ var/old_key = icon_render_keys?[limb.body_zone] //Checks the mob's icon render key list for the bodypart icon_render_keys[limb.body_zone] = (limb.is_husked) ? limb.generate_husk_key().Join() : limb.generate_icon_key().Join() //Generates a key for the current bodypart - if(icon_render_keys[limb.body_zone] != old_key || get_top_offset() != last_top_offset) //If the keys match, that means the limb doesn't need to be redrawn + if(icon_render_keys[limb.body_zone] != old_key) //If the keys match, that means the limb doesn't need to be redrawn needs_update += limb var/list/missing_bodyparts = get_missing_limbs() @@ -500,15 +500,10 @@ for(var/obj/item/bodypart/limb as anything in bodyparts) if(limb in needs_update) var/bodypart_icon = limb.get_limb_icon() - if(!istype(limb, /obj/item/bodypart/leg)) - var/top_offset = get_top_offset() - for(var/image/image as anything in bodypart_icon) - image.pixel_y += top_offset new_limbs += bodypart_icon limb_icon_cache[icon_render_keys[limb.body_zone]] = bodypart_icon //Caches the icon with the bodypart key, as it is new else new_limbs += limb_icon_cache[icon_render_keys[limb.body_zone]] //Pulls existing sprites from the cache - last_top_offset = get_top_offset() remove_overlay(BODYPARTS_LAYER) @@ -518,19 +513,6 @@ apply_overlay(BODYPARTS_LAYER) -/// This looks at the chest and legs of the mob and decides how much our chest, arms, and head should be adjusted. This is useful for limbs that are larger or smaller than the scope of normal human height while keeping the feet anchored to the bottom of the tile -/mob/living/carbon/proc/get_top_offset() - var/from_chest - var/from_leg - for(var/obj/item/bodypart/leg/leg_checked in bodyparts) - if(leg_checked.top_offset > from_leg || isnull(from_leg)) // We find the tallest leg available - from_leg = leg_checked.top_offset - if(isnull(from_leg)) - from_leg = 0 // If we have no legs, we set this to zero to avoid any math issues that might stem from it being NULL - for(var/obj/item/bodypart/chest/chest_checked in bodyparts) // Take the height from the chest - from_chest = chest_checked.top_offset - return (from_chest + from_leg) // The total hight of the chest and legs together - ///////////////////////// // Limb Icon Cache 2.0 // ///////////////////////// @@ -568,6 +550,7 @@ /obj/item/bodypart/proc/generate_husk_key() RETURN_TYPE(/list) . = list() + . += "[limb_id]-" . += "[husk_type]" . += "-husk" . += "-[body_zone]" diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index b31169401098..83be5e52acef 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -190,6 +190,9 @@ GLOBAL_LIST_EMPTY(features_by_species) ///A list containing outfits that will be overridden in the species_equip_outfit proc. [Key = Typepath passed in] [Value = Typepath of outfit you want to equip for this specific species instead]. var/list/outfit_override_registry = list() + /// What species is our monkey form + var/datum/species/monkey_type = /datum/species/monkey + /////////// // PROCS // /////////// @@ -211,6 +214,7 @@ GLOBAL_LIST_EMPTY(features_by_species) GLOB.roundstart_races = generate_selectable_species_and_languages() return GLOB.roundstart_races + /** * Generates species available to choose in character setup at roundstart * @@ -221,14 +225,12 @@ GLOBAL_LIST_EMPTY(features_by_species) var/list/selectable_species = list() for(var/species_type in subtypesof(/datum/species)) - var/datum/species/species = new species_type + var/datum/species/species = GLOB.species_prototypes[species_type] if(species.check_roundstart_eligible()) selectable_species += species.id - var/datum/language_holder/temp_holder = new species.species_language_holder + var/datum/language_holder/temp_holder = GLOB.prototype_language_holders[species.species_language_holder] for(var/datum/language/spoken_language as anything in temp_holder.understood_languages) GLOB.uncommon_roundstart_languages |= spoken_language - qdel(temp_holder) - qdel(species) GLOB.uncommon_roundstart_languages -= /datum/language/common if(!selectable_species.len) @@ -247,32 +249,6 @@ GLOBAL_LIST_EMPTY(features_by_species) return TRUE return FALSE -/** - * Generates a random name for a carbon. - * - * This generates a random unique name based on a human's species and gender. - * Arguments: - * * gender - The gender that the name should adhere to. Use MALE for male names, use anything else for female names. - * * unique - If true, ensures that this new name is not a duplicate of anyone else's name currently on the station. - * * last_name - Do we use a given last name or pick a random new one? - */ -/datum/species/proc/random_name(gender, unique, last_name) - if(unique) - return random_unique_name(gender) - - var/randname - if(gender == MALE) - randname = pick(GLOB.first_names_male) - else - randname = pick(GLOB.first_names_female) - - if(last_name) - randname += " [last_name]" - else - randname += " [pick(GLOB.last_names)]" - - return randname - /** * Copies some vars and properties over that should be kept when creating a copy of this species. * @@ -613,7 +589,6 @@ GLOBAL_LIST_EMPTY(features_by_species) */ /datum/species/proc/handle_body(mob/living/carbon/human/species_human) species_human.remove_overlay(BODY_LAYER) - var/height_offset = species_human.get_top_offset() // From high changed by varying limb height if(HAS_TRAIT(species_human, TRAIT_INVISIBLE_MAN)) return handle_mutant_bodyparts(species_human) var/list/standing = list() @@ -625,9 +600,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/organ/internal/eyes/eye_organ = species_human.get_organ_slot(ORGAN_SLOT_EYES) if(eye_organ) eye_organ.refresh(call_update = FALSE) - for(var/mutable_appearance/eye_overlay in eye_organ.generate_body_overlay(species_human)) - eye_overlay.pixel_y += height_offset - standing += eye_overlay + standing += eye_organ.generate_body_overlay(species_human) // organic body markings (oh my god this is terrible please rework this to be done on the limbs themselves i beg you) if(HAS_TRAIT(species_human, TRAIT_HAS_MARKINGS)) @@ -638,29 +611,23 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/bodypart/leg/left/left_leg = species_human.get_bodypart(BODY_ZONE_L_LEG) var/datum/sprite_accessory/markings = GLOB.moth_markings_list[species_human.dna.features["moth_markings"]] var/mutable_appearance/marking = mutable_appearance(layer = -BODY_LAYER, appearance_flags = KEEP_TOGETHER) - if(noggin && (IS_ORGANIC_LIMB(noggin))) - var/mutable_appearance/markings_head_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_head") - marking.overlays += markings_head_overlay + if(noggin && IS_ORGANIC_LIMB(noggin)) + marking.overlays += mutable_appearance(markings.icon, "[markings.icon_state]_head") - if(chest && (IS_ORGANIC_LIMB(chest))) - var/mutable_appearance/markings_chest_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_chest") - marking.overlays += markings_chest_overlay + if(chest && IS_ORGANIC_LIMB(chest)) + marking.overlays += mutable_appearance(markings.icon, "[markings.icon_state]_chest") - if(right_arm && (IS_ORGANIC_LIMB(right_arm))) - var/mutable_appearance/markings_r_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_arm") - marking.overlays += markings_r_arm_overlay + if(right_arm && IS_ORGANIC_LIMB(right_arm)) + marking.overlays += mutable_appearance(markings.icon, "[markings.icon_state]_r_arm") - if(left_arm && (IS_ORGANIC_LIMB(left_arm))) - var/mutable_appearance/markings_l_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_arm") - marking.overlays += markings_l_arm_overlay + if(left_arm && IS_ORGANIC_LIMB(left_arm)) + marking.overlays += mutable_appearance(markings.icon, "[markings.icon_state]_l_arm") - if(right_leg && (IS_ORGANIC_LIMB(right_leg))) - var/mutable_appearance/markings_r_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_leg") - marking.overlays += markings_r_leg_overlay + if(right_leg && IS_ORGANIC_LIMB(right_leg)) + marking.overlays += mutable_appearance(markings.icon, "[markings.icon_state]_r_leg") - if(left_leg && (IS_ORGANIC_LIMB(left_leg))) - var/mutable_appearance/markings_l_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_leg") - marking.overlays += markings_l_leg_overlay + if(left_leg && IS_ORGANIC_LIMB(left_leg)) + marking.overlays += mutable_appearance(markings.icon, "[markings.icon_state]_l_leg") standing += marking @@ -676,7 +643,6 @@ GLOBAL_LIST_EMPTY(features_by_species) underwear_overlay = mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) if(!underwear.use_static) underwear_overlay.color = species_human.underwear_color - underwear_overlay.pixel_y += height_offset standing += underwear_overlay if(species_human.undershirt) @@ -687,7 +653,6 @@ GLOBAL_LIST_EMPTY(features_by_species) working_shirt = wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) else working_shirt = mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) - working_shirt.pixel_y += height_offset standing += working_shirt if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodytype & BODYTYPE_DIGITIGRADE)) @@ -929,12 +894,6 @@ GLOBAL_LIST_EMPTY(features_by_species) return FALSE return equip_delay_self_check(I, H, bypass_equip_delay_self) if(ITEM_SLOT_ICLOTHING) - var/obj/item/bodypart/chest = H.get_bodypart(BODY_ZONE_CHEST) - if(chest && (chest.bodytype & BODYTYPE_MONKEY)) - if(!(I.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) - if(!disable_warning) - to_chat(H, span_warning("[I] doesn't fit your [chest.name]!")) - return FALSE return equip_delay_self_check(I, H, bypass_equip_delay_self) if(ITEM_SLOT_ID) var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 7d31dd5ff90d..6d15f696bed5 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -6,6 +6,8 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) new /obj/effect/temp_visual/dust_animation(loc, dna.species.dust_anim) /mob/living/carbon/human/spawn_gibs(drop_bitflags=NONE) + if(flags_1 & HOLOGRAM_1) + return if(drop_bitflags & DROP_BODYPARTS) new /obj/effect/gibspawner/human(drop_location(), src, get_static_viruses()) else diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 305bf132f721..c172288da651 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -76,7 +76,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) cut_overlays(TRUE) /mob/living/carbon/human/dummy/setup_human_dna() - randomize_human(src, randomize_mutations = FALSE) + randomize_human_normie(src, randomize_mutations = FALSE) /mob/living/carbon/human/dummy/log_mob_tag(text) return @@ -102,6 +102,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) target.dna.features["spines"] = get_consistent_feature_entry(GLOB.spines_list) target.dna.features["tail_cat"] = get_consistent_feature_entry(GLOB.tails_list_human) // it's a lie target.dna.features["tail_lizard"] = get_consistent_feature_entry(GLOB.tails_list_lizard) + target.dna.features["tail_monkey"] = get_consistent_feature_entry(GLOB.tails_list_monkey) target.dna.features["pod_hair"] = get_consistent_feature_entry(GLOB.pod_hair_list) target.dna.features["head_tentacles"] = get_consistent_feature_entry(GLOB.head_tentacles_list) // NON-MODULE CHANGE target.dna.features["arm_wings"] = get_consistent_feature_entry(GLOB.arm_wings_list) // NON-MODULE CHANGE diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 3a086be09583..bbe8c103ba25 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -202,7 +202,7 @@ emote_type = EMOTE_AUDIBLE /datum/emote/living/carbon/human/hiss/get_sound(mob/user) - if(islizard(user)) + if(islizard(user) || ismonkey(user)) return pick(user.get_speech_sounds()) return null diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index e025308b8c4b..d91915f932a3 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -56,7 +56,7 @@ ADD_TRAIT(src, TRAIT_AGEUSIA, NO_TONGUE_TRAIT) /mob/living/carbon/human/proc/setup_human_dna() - randomize_human(src, randomize_mutations = TRUE) + randomize_human_normie(src, randomize_mutations = TRUE) /mob/living/carbon/human/Destroy() QDEL_NULL(physiology) @@ -691,7 +691,7 @@ /mob/living/carbon/human/fully_heal(heal_flags = HEAL_ALL) if(heal_flags & HEAL_NEGATIVE_MUTATIONS) for(var/datum/mutation/human/existing_mutation in dna.mutations) - if(existing_mutation.quality != POSITIVE) + if(existing_mutation.quality != POSITIVE && existing_mutation.remove_on_aheal) dna.remove_mutation(existing_mutation) if(heal_flags & HEAL_TEMP) @@ -718,6 +718,10 @@ /mob/living/carbon/human/vv_edit_var(var_name, var_value) if(var_name == NAMEOF(src, mob_height)) + var/static/list/monkey_heights = list( + MONKEY_HEIGHT_DWARF, + MONKEY_HEIGHT_MEDIUM, + ) var/static/list/heights = list( HUMAN_HEIGHT_SHORTEST, HUMAN_HEIGHT_SHORT, @@ -726,7 +730,10 @@ HUMAN_HEIGHT_TALLER, HUMAN_HEIGHT_TALLEST ) - if(!(var_value in heights)) + if(ismonkey(src)) + if(!(var_value in monkey_heights)) + return + else if(!(var_value in heights)) return . = set_mob_height(var_value) @@ -803,7 +810,7 @@ if(href_list[VV_HK_SET_SPECIES]) if(!check_rights(R_SPAWN)) return - var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list + var/result = input(usr, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc)) if(result) var/newtype = GLOB.species_list[result] admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src] to [result]") @@ -995,7 +1002,7 @@ /mob/living/carbon/human/species/set_species(datum/species/mrace, icon_update, pref_load) . = ..() if(use_random_name) - fully_replace_character_name(real_name, dna.species.random_name()) + fully_replace_character_name(real_name, generate_random_mob_name()) /mob/living/carbon/human/species/abductor race = /datum/species/abductor diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index ef44318676e7..79ef66af7d6c 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -259,7 +259,7 @@ if (preference.is_randomizable()) preference.apply_to_human(src, preference.create_random_value(preferences)) - fully_replace_character_name(real_name, dna.species.random_name()) + fully_replace_character_name(real_name, generate_random_mob_name()) /** * Setter for mob height @@ -271,8 +271,10 @@ /mob/living/carbon/human/proc/set_mob_height(new_height) if(mob_height == new_height) return FALSE - if(new_height == HUMAN_HEIGHT_DWARF) - CRASH("Don't set height to dwarf height directly, use dwarf trait") + if(new_height == HUMAN_HEIGHT_DWARF || new_height == MONKEY_HEIGHT_DWARF) + CRASH("Don't set height to dwarf height directly, use dwarf trait instead.") + if(new_height == MONKEY_HEIGHT_MEDIUM) + CRASH("Don't set height to monkey height directly, use monkified gene/species instead.") mob_height = new_height regenerate_icons() @@ -287,7 +289,10 @@ */ /mob/living/carbon/human/proc/get_mob_height() if(HAS_TRAIT(src, TRAIT_DWARF)) - return HUMAN_HEIGHT_DWARF + return ismonkey(src) ? MONKEY_HEIGHT_DWARF : HUMAN_HEIGHT_DWARF + + if(ismonkey(src)) + return MONKEY_HEIGHT_MEDIUM return mob_height diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 82676f62eca0..99d08f9c716d 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -102,9 +102,7 @@ There are several things that need to be remembered: var/icon_file var/woman //BEGIN SPECIES HANDLING - if((bodytype & BODYTYPE_MONKEY) && (uniform.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) - icon_file = MONKEY_UNIFORM_FILE - else if((bodytype & BODYTYPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) + if((bodytype & BODYTYPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) // NON-MODULE CHANGE kapu why if(uniform.greyscale_config_worn && uniform.digitigrade_greyscale_config_worn && uniform.greyscale_colors) icon_file = SSgreyscale.GetColoredIconByType(uniform.digitigrade_greyscale_config_worn, uniform.greyscale_colors) @@ -709,9 +707,6 @@ generate/load female uniform sprites matching all previously decided variables .[2] = offsets["y"] else .[2] = worn_y_offset - if(ishuman(loc) && slot_flags != ITEM_SLOT_FEET) /// we adjust the human body for high given by body parts, execpt shoes, because they are always on the bottom - var/mob/living/carbon/human/human_holder = loc - .[2] += human_holder.get_top_offset() //Can't think of a better way to do this, sadly /mob/proc/get_item_offsets_for_index(i) @@ -816,26 +811,97 @@ generate/load female uniform sprites matching all previously decided variables "Lenghten_Torso", "Gnome_Cut_Torso", "Gnome_Cut_Legs", + "Monkey_Torso", + "Monkey_Legs", + "Monkey_Gnome_Cut_Torso", + "Monkey_Gnome_Cut_Legs", )) switch(get_mob_height()) // Don't set this one directly, use TRAIT_DWARF + if(MONKEY_HEIGHT_DWARF) + appearance.add_filters(list( + list( + "name" = "Monkey_Gnome_Cut_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 3), + ), + list( + "name" = "Monkey_Gnome_Cut_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 4), + ), + )) + if(MONKEY_HEIGHT_MEDIUM) + appearance.add_filters(list( + list( + "name" = "Monkey_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 2), + ), + list( + "name" = "Monkey_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 4), + ), + )) + // Don't set this one directly, use TRAIT_DWARF if(HUMAN_HEIGHT_DWARF) - appearance.add_filter("Gnome_Cut_Torso", 1, displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 2)) - appearance.add_filter("Gnome_Cut_Legs", 1, displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 3)) + appearance.add_filters(list( + list( + "name" = "Gnome_Cut_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 2), + ), + list( + "name" = "Gnome_Cut_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 3), + ), + )) if(HUMAN_HEIGHT_SHORTEST) - appearance.add_filter("Cut_Torso", 1, displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 1)) - appearance.add_filter("Cut_Legs", 1, displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 1)) + appearance.add_filters(list( + list( + "name" = "Cut_Torso", + "priority" = 1, + "params" = displacement_map_filter(cut_torso_mask, x = 0, y = 0, size = 1), + ), + list( + "name" = "Cut_Legs", + "priority" = 1, + "params" = displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 1), + ), + )) if(HUMAN_HEIGHT_SHORT) appearance.add_filter("Cut_Legs", 1, displacement_map_filter(cut_legs_mask, x = 0, y = 0, size = 1)) if(HUMAN_HEIGHT_TALL) appearance.add_filter("Lenghten_Legs", 1, displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 1)) if(HUMAN_HEIGHT_TALLER) - appearance.add_filter("Lenghten_Torso", 1, displacement_map_filter(lenghten_torso_mask, x = 0, y = 0, size = 1)) - appearance.add_filter("Lenghten_Legs", 1, displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 1)) + appearance.add_filters(list( + list( + "name" = "Lenghten_Torso", + "priority" = 1, + "params" = displacement_map_filter(lenghten_torso_mask, x = 0, y = 0, size = 1), + ), + list( + "name" = "Lenghten_Legs", + "priority" = 1, + "params" = displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 1), + ), + )) if(HUMAN_HEIGHT_TALLEST) - appearance.add_filter("Lenghten_Torso", 1, displacement_map_filter(lenghten_torso_mask, x = 0, y = 0, size = 1)) - appearance.add_filter("Lenghten_Legs", 1, displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 2)) + appearance.add_filters(list( + list( + "name" = "Lenghten_Torso", + "priority" = 1, + "params" = displacement_map_filter(lenghten_torso_mask, x = 0, y = 0, size = 1), + ), + list( + "name" = "Lenghten_Legs", + "priority" = 1, + "params" = displacement_map_filter(lenghten_legs_mask, x = 0, y = 0, size = 2), + ), + )) // Kinda gross but because many humans overlays do not use KEEP_TOGETHER we need to manually propogate the filter // Otherwise overlays, such as worn overlays on icons, won't have the filter "applied", and the effect kinda breaks diff --git a/code/modules/mob/living/carbon/human/monkey.dm b/code/modules/mob/living/carbon/human/monkey.dm index 88d46855a5e3..d11e4f5208bc 100644 --- a/code/modules/mob/living/carbon/human/monkey.dm +++ b/code/modules/mob/living/carbon/human/monkey.dm @@ -32,12 +32,6 @@ equip_to_slot_or_del(helmet, ITEM_SLOT_HEAD) helmet.attack_self(src) // todo encapsulate toggle -/mob/living/carbon/human/species/monkey/holodeck - race = /datum/species/monkey/holodeck - -/mob/living/carbon/human/species/monkey/holodeck/spawn_gibs() // no blood and no gibs - return - GLOBAL_DATUM(the_one_and_only_punpun, /mob/living/carbon/human/species/monkey/punpun) /mob/living/carbon/human/species/monkey/punpun diff --git a/code/modules/mob/living/carbon/human/species_types/abominations.dm b/code/modules/mob/living/carbon/human/species_types/abominations.dm deleted file mode 100644 index 43ca71311c22..000000000000 --- a/code/modules/mob/living/carbon/human/species_types/abominations.dm +++ /dev/null @@ -1,51 +0,0 @@ -/// These won't appear normally in games, they are meant to for debuging the adjustment of limbs based on the height of a humans bodyparts. -/datum/species/human/tallboy - name = "\improper Tall Boy" - id = SPECIES_TALLBOY - examine_limb_id = SPECIES_HUMAN - changesource_flags = MIRROR_BADMIN | WABBAJACK - bodypart_overrides = list( - BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left, - BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right, - BODY_ZONE_HEAD = /obj/item/bodypart/head, - BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/tallboy, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/tallboy, - BODY_ZONE_CHEST = /obj/item/bodypart/chest, - ) - -/datum/species/monkey/human_legged - name = "human-legged monkey" - id = SPECIES_MONKEY_HUMAN_LEGGED - examine_limb_id = SPECIES_MONKEY - changesource_flags = MIRROR_BADMIN | WABBAJACK - bodypart_overrides = list( - BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/monkey, - BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/monkey, - BODY_ZONE_HEAD = /obj/item/bodypart/head/monkey, - BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right, - BODY_ZONE_CHEST = /obj/item/bodypart/chest/monkey, - ) - -/datum/species/monkey/monkey_freak - name = "human-armed monkey" - id = SPECIES_MONKEY_FREAK - examine_limb_id = SPECIES_MONKEY - changesource_flags = MIRROR_BADMIN | WABBAJACK - bodypart_overrides = list( - BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left, - BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right, - BODY_ZONE_HEAD = /obj/item/bodypart/head/monkey, - BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/monkey, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/monkey, - BODY_ZONE_CHEST = /obj/item/bodypart/chest, - ) - -/mob/living/carbon/human/species/monkey/humand_legged - race = /datum/species/monkey/human_legged - -/mob/living/carbon/human/species/monkey/monkey_freak - race = /datum/species/monkey/monkey_freak - -/mob/living/carbon/human/species/tallboy - race = /datum/species/human/tallboy diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 9fc68a635095..e5d53d9d58bd 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -89,22 +89,6 @@ QDEL_NULL(ethereal_light) return ..() -// NON-MODULE CHANGE -// /datum/species/ethereal/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies = list()) -// if(istype(quirk, /datum/quirk/blooddeficiency)) -// mail_goodies += list( -// /obj/item/reagent_containers/blood/ethereal -// ) -// return ..() - -/datum/species/ethereal/random_name(gender,unique,lastname) - if(unique) - return random_unique_ethereal_name() - - var/randname = ethereal_name() - - return randname - /datum/species/ethereal/randomize_features() var/list/features = ..() features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 0a9232476cc3..56de52b77108 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -50,15 +50,6 @@ BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem, ) - /// Chance that we will generate a human surname, for lore reasons - var/human_surname_chance = 3 - -/datum/species/golem/random_name(gender,unique,lastname) - var/name = pick(GLOB.golem_names) - if (prob(human_surname_chance)) - name += " [pick(GLOB.last_names)]" - return name - /datum/species/golem/get_physical_attributes() return "Golems are hardy creatures made out of stone, which are thus naturally resistant to many dangers, including asphyxiation, fire, radiation, electricity, and viruses.\ They gain special abilities depending on the type of material consumed, but they need to consume material to keep their body animated." diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 9907d28ef933..cde32fc6726a 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -45,36 +45,12 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/lizard, ) -// NON-MODULE CHANGE -// /datum/species/lizard/on_species_gain(mob/living/carbon/new_lizard, datum/species/old_species, pref_load) -// . = ..() -// if(ishuman(new_lizard)) -// update_mail_goodies(new_lizard) - -// /datum/species/lizard/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies = list()) -// if(istype(quirk, /datum/quirk/blooddeficiency)) -// mail_goodies += list( -// /obj/item/reagent_containers/blood/lizard -// ) -// return ..() -// NON-MODULE CHANGE end + monkey_type = /datum/species/monkey/lizard /// Lizards are cold blooded and do not stabilize body temperature naturally /datum/species/lizard/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired) return -/datum/species/lizard/random_name(gender,unique,lastname) - if(unique) - return random_unique_lizard_name(gender) - - var/randname = lizard_name(gender) - - if(lastname) - randname += " [lastname]" - - return randname - - /datum/species/lizard/randomize_features() var/list/features = ..() features["body_markings"] = pick(GLOB.body_markings_list) @@ -182,9 +158,10 @@ Lizard subspecies: ASHWALKERS mutantlungs = /obj/item/organ/internal/lungs/lavaland mutantbrain = /obj/item/organ/internal/brain/primitive inherent_traits = list( + TRAIT_FORBID_MINING_SHUTTLE_CONSOLE_OUTSIDE_STATION, TRAIT_MUTANT_COLORS, + TRAIT_TACKLING_TAILED_DEFENDER, TRAIT_VIRUSIMMUNE, - TRAIT_FORBID_MINING_SHUTTLE_CONSOLE_OUTSIDE_STATION, ) species_language_holder = /datum/language_holder/lizard/ash digitigrade_customization = DIGITIGRADE_FORCED @@ -215,6 +192,7 @@ Lizard subspecies: SILVER SCALED TRAIT_PIERCEIMMUNE, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, + TRAIT_TACKLING_TAILED_DEFENDER, TRAIT_VIRUSIMMUNE, TRAIT_WINE_TASTER, ) diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index fea8b71cb677..0de795f74ef6 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -1,10 +1,10 @@ #define MONKEY_SPEC_ATTACK_BITE_MISS_CHANCE 25 /datum/species/monkey - name = "Monkey" + name = "\improper Monkey" id = SPECIES_MONKEY external_organs = list( - /obj/item/organ/external/tail/monkey = "Monkey" + /obj/item/organ/external/tail/monkey = "Monkey", ) mutanttongue = /obj/item/organ/internal/tongue/monkey mutantbrain = /obj/item/organ/internal/brain/primate @@ -22,6 +22,7 @@ ) no_equip_flags = ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_SUITSTORE changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN | SLIME_EXTRACT + species_cookie = /obj/item/food/grown/banana sexes = FALSE species_language_holder = /datum/language_holder/monkey @@ -39,31 +40,21 @@ payday_modifier = 1.5 ai_controlled_species = TRUE + monkey_type = null -/datum/species/monkey/random_name(gender,unique,lastname) - var/randname = "monkey ([rand(1,999)])" - - return randname - -/datum/species/monkey/on_species_gain(mob/living/carbon/human/H, datum/species/old_species) +/datum/species/monkey/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load) . = ..() - passtable_on(H, SPECIES_TRAIT) - H.dna.add_mutation(/datum/mutation/human/race, MUT_NORMAL) - H.dna.activate_mutation(/datum/mutation/human/race) - H.AddElement(/datum/element/human_biter) + passtable_on(human_who_gained_species, SPECIES_TRAIT) + human_who_gained_species.dna.add_mutation(/datum/mutation/human/race, MUT_NORMAL) + human_who_gained_species.dna.activate_mutation(/datum/mutation/human/race) + human_who_gained_species.AddElement(/datum/element/human_biter) -/datum/species/monkey/on_species_loss(mob/living/carbon/C) +/datum/species/monkey/on_species_loss(mob/living/carbon/human/C) . = ..() passtable_off(C, SPECIES_TRAIT) C.dna.remove_mutation(/datum/mutation/human/race) C.RemoveElement(/datum/element/human_biter) -/datum/species/monkey/check_roundstart_eligible() - // STOP ADDING MONKEY SUBTYPES YOU HEATHEN - if(check_holidays(MONKEYDAY) && id == SPECIES_MONKEY) - return TRUE - return ..() - /datum/species/monkey/get_scream_sound(mob/living/carbon/human/monkey) return get_sfx(SFX_SCREECH) @@ -158,7 +149,6 @@ to_chat(monkey_brain.owner, span_notice("You will now stumble while while colliding with people who are in combat mode.")) build_all_button_icons() - /obj/item/organ/internal/brain/primate/on_mob_insert(mob/living/carbon/primate) . = ..() RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed), TRUE) @@ -183,23 +173,99 @@ /obj/item/organ/internal/brain/primate/get_attacking_limb(mob/living/carbon/human/target) return owner.get_bodypart(BODY_ZONE_HEAD) -/// Virtual monkeys that crave virtual bananas. Everything about them is ephemeral (except that bite). -/datum/species/monkey/holodeck - id = SPECIES_MONKEY_HOLODECK - knife_butcher_results = list() - meat = null - skinned_type = null +#undef MONKEY_SPEC_ATTACK_BITE_MISS_CHANCE + +/datum/species/monkey/lizard + name = "\improper Kobold" + id = SPECIES_MONKEY_LIZARD + examine_limb_id = SPECIES_LIZARD inherent_traits = list( - TRAIT_GENELESS, + // monke TRAIT_GUN_NATURAL, TRAIT_NO_AUGMENTS, TRAIT_NO_BLOOD_OVERLAY, TRAIT_NO_DNA_COPY, TRAIT_NO_UNDERWEAR, - TRAIT_NO_ZOMBIFY, - TRAIT_NOBLOOD, - TRAIT_NOHUNGER, TRAIT_VENTCRAWLER_NUDE, + TRAIT_WEAK_SOUL, + // unique + TRAIT_MUTANT_COLORS, + TRAIT_TACKLING_TAILED_DEFENDER, ) + inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE + digitigrade_customization = DIGITIGRADE_FORCED + mutant_bodyparts = list("legs" = DIGITIGRADE_LEGS) + external_organs = list( + /obj/item/organ/external/horns = "None", + /obj/item/organ/external/frills = "None", + /obj/item/organ/external/snout = "Round", + /obj/item/organ/external/spines = "None", + /obj/item/organ/external/tail/lizard = "Smooth", + ) + mutanttongue = /datum/species/lizard::mutanttongue + species_cookie = /datum/species/lizard::species_cookie + meat = /datum/species/lizard::meat + skinned_type = /datum/species/lizard::skinned_type + knife_butcher_results = list(/datum/species/lizard::meat = 5, /datum/species/lizard::skinned_type = 1) + species_language_holder = /datum/language_holder/lizard/ash/primative -#undef MONKEY_SPEC_ATTACK_BITE_MISS_CHANCE + bodytemp_heat_damage_limit = /datum/species/lizard::bodytemp_heat_damage_limit + bodytemp_cold_damage_limit = /datum/species/lizard::bodytemp_cold_damage_limit + + ass_image = /datum/species/lizard::ass_image + + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/lizard, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/lizard/lizmonkey, + BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/lizard/lizmonkey, + BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/lizard/lizmonkey, + BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/digitigrade, + BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/digitigrade, + ) + +/datum/species/monkey/lizard/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired) + return + +/datum/species/monkey/lizard/get_scream_sound(mob/living/carbon/human/lizard) + return pick( + 'sound/voice/lizard/lizard_scream_1.ogg', + 'sound/voice/lizard/lizard_scream_2.ogg', + 'sound/voice/lizard/lizard_scream_3.ogg', + ) + +/datum/species/monkey/lizard/get_laugh_sound(mob/living/carbon/human/lizard) + return 'sound/voice/lizard/lizard_laugh1.ogg' + +/obj/item/bodypart/arm/left/lizard/lizmonkey + wound_resistance = -10 + unarmed_damage_low = 1 + unarmed_damage_high = 2 + unarmed_effectiveness = 0 + +/obj/item/bodypart/arm/left/lizard/lizmonkey/Initialize(mapload) + . = ..() + name = "kobold [plaintext_zone]" + +/obj/item/bodypart/arm/right/lizard/lizmonkey + wound_resistance = -10 + unarmed_damage_low = 1 + unarmed_damage_high = 2 + unarmed_effectiveness = 0 + +/obj/item/bodypart/arm/right/lizard/lizmonkey/Initialize(mapload) + . = ..() + name = "kobold [plaintext_zone]" + +/obj/item/bodypart/chest/lizard/lizmonkey + wound_resistance = -10 + +/obj/item/bodypart/chest/lizard/lizmonkey/Initialize(mapload) + . = ..() + name = "kobold [plaintext_zone]" + +/obj/item/bodypart/head/lizard/lizmonkey + wound_resistance = -10 + +/obj/item/bodypart/head/lizard/lizmonkey/Initialize(mapload) + . = ..() + name = "kobold [plaintext_zone]" diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index d3b98fe67424..85c61cc26d85 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -34,17 +34,6 @@ var/mob/living/carbon/human/H = C handle_mutant_bodyparts(H) -/datum/species/moth/random_name(gender,unique,lastname) - if(unique) - return random_unique_moth_name() - - var/randname = moth_name() - - if(lastname) - randname += " [lastname]" - - return randname - /datum/species/moth/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load) . = ..() RegisterSignal(human_who_gained_species, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness)) diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 1e0e3ad564b8..aeb0f2e0bf4a 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -124,17 +124,6 @@ else give_important_for_life(equipping) -/datum/species/plasmaman/random_name(gender,unique,lastname) - if(unique) - return random_unique_plasmaman_name() - - var/randname = plasmaman_name() - - if(lastname) - randname += " [lastname]" - - return randname - /datum/species/plasmaman/get_scream_sound(mob/living/carbon/human/plasmaman) return pick( 'sound/voice/plasmaman/plasmeme_scream_1.ogg', diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 4da845c11df4..0c228775662d 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -37,6 +37,8 @@ * * DROP_BODYPARTS - Gibs will spawn with bodypart limbs present **/ /mob/living/proc/spawn_gibs(drop_bitflags=NONE) + if(flags_1 & HOLOGRAM_1) + return new /obj/effect/gibspawner/generic(drop_location(), src, get_static_viruses()) /** diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 1dbe5626e912..7b3e04263876 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -658,13 +658,15 @@ return copytext(sanitize(input("Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN) /datum/emote/living/custom/proc/get_custom_emote_type_from_user() - var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable") + var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable", "Both") switch(type) if("Visible") return EMOTE_VISIBLE if("Hearable") return EMOTE_AUDIBLE + if("Both") + return EMOTE_VISIBLE | EMOTE_AUDIBLE else tgui_alert(usr,"Unable to use this emote, must be either hearable or visible.") return FALSE diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 7770179bcf5e..267deaed7b39 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -198,9 +198,9 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( spans |= speech_span - if(language) - var/datum/language/L = GLOB.language_datum_instances[language] - spans |= L.spans + var/datum/language/spoken_lang = GLOB.language_datum_instances[language] + if(LAZYLEN(spoken_lang?.spans)) + spans |= spoken_lang.spans if(message_mods[MODE_SING]) var/randomnote = pick("\u2669", "\u266A", "\u266B") diff --git a/code/modules/mob/mob_say.dm b/code/modules/mob/mob_say.dm index da8bd502fb1e..8c6bb0d917c5 100644 --- a/code/modules/mob/mob_say.dm +++ b/code/modules/mob/mob_say.dm @@ -42,6 +42,7 @@ /mob/verb/me_verb(message as text) set name = "Me" set category = "IC" + set desc = "Perform a custom emote. Leave blank to pick between an audible or a visible emote (Defaults to visible)." if(GLOB.say_disabled) //This is here to try to identify lag problems to_chat(usr, span_danger("Speech is currently admin-disabled.")) @@ -49,7 +50,7 @@ message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)) - QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_PROC_REF(/mob, emote), "me", 1, message, TRUE), SSspeech_controller) + QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_PROC_REF(/mob, emote), "me", EMOTE_VISIBLE|EMOTE_AUDIBLE, message, TRUE), SSspeech_controller) /mob/try_speak(message, ignore_spam = FALSE, forced = null, filterproof = FALSE) SHOULD_CALL_PARENT(TRUE) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index ca82e13e803e..537da8eae2da 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -8,7 +8,7 @@ if (transformation_timer || HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) return - if(ismonkey(src)) + if(!dna?.species?.monkey_type) return if(instant) @@ -17,7 +17,7 @@ //Make mob invisible and spawn animation ADD_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT) - Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE) + Stun(TRANSFORMATION_DURATION, ignore_canstun = TRUE) icon = null cut_overlays() @@ -29,12 +29,13 @@ /mob/living/carbon/proc/finish_monkeyize() transformation_timer = null - to_chat(src, span_boldnotice("You are now a monkey.")) REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT) icon = initial(icon) RemoveInvisibility(type) - set_species(/datum/species/monkey) - name = "monkey" + set_species(dna.species.monkey_type) + to_chat(src, span_boldnotice("You are now \a [dna.species.name].")) + name = lowertext(dna.species.name) + regenerate_icons() set_name() SEND_SIGNAL(src, COMSIG_HUMAN_MONKEYIZE) uncuff() @@ -56,7 +57,7 @@ //Make mob invisible and spawn animation ADD_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT) - Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE) + Stun(TRANSFORMATION_DURATION, ignore_canstun = TRUE) icon = null cut_overlays() @@ -66,16 +67,23 @@ transformation_timer = addtimer(CALLBACK(src, PROC_REF(finish_humanize), species), TRANSFORMATION_DURATION, TIMER_UNIQUE) + /mob/living/carbon/proc/finish_humanize(species = /datum/species/human) transformation_timer = null - to_chat(src, span_boldnotice("You are now a human.")) REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT) icon = initial(icon) RemoveInvisibility(type) set_species(species) + to_chat(src, span_boldnotice("You are now \a [dna.species.name].")) SEND_SIGNAL(src, COMSIG_MONKEY_HUMANIZE) return src +/mob/living/carbon/human/finish_humanize(species = /datum/species/human) + underwear = "Nude" + undershirt = "Nude" + socks = "Nude" + return ..() + /mob/proc/AIize(client/preference_source, move = TRUE) var/list/turf/landmark_loc = list() diff --git a/code/modules/mob_spawn/ghost_roles/golem_roles.dm b/code/modules/mob_spawn/ghost_roles/golem_roles.dm index b3475e9207f8..5fc643bffa62 100644 --- a/code/modules/mob_spawn/ghost_roles/golem_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/golem_roles.dm @@ -36,8 +36,7 @@ if(forced_name || !iscarbon(spawned_mob)) return ..() - var/datum/species/golem/golem_species = new() - forced_name = golem_species.random_name() + forced_name = generate_random_name_species_based(spawned_mob.gender, TRUE, species_type = /datum/species/golem) return ..() /obj/effect/mob_spawn/ghost_role/human/golem/special(mob/living/new_spawn, mob/mob_possessor) diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm index 208a74a3edbf..53fa00109703 100644 --- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm @@ -194,9 +194,9 @@ /obj/structure/ash_walker_eggshell/Destroy() if(!egg) return ..() - var/mob/living/carbon/human/yolk = new /mob/living/carbon/human/(get_turf(src)) - yolk.fully_replace_character_name(null,random_unique_lizard_name(gender)) + var/mob/living/carbon/human/yolk = new(get_turf(src)) yolk.set_species(/datum/species/lizard/ashwalker) + yolk.fully_replace_character_name(null, yolk.generate_random_mob_name(TRUE)) yolk.underwear = "Nude" yolk.equipOutfit(/datum/outfit/ashwalker)//this is an authentic mess we're making yolk.update_body() @@ -235,7 +235,7 @@ /obj/effect/mob_spawn/ghost_role/human/ash_walker/special(mob/living/carbon/human/spawned_human) . = ..() - spawned_human.fully_replace_character_name(null,random_unique_lizard_name(gender)) + spawned_human.fully_replace_character_name(null, spawned_human.generate_random_mob_name(TRUE)) to_chat(spawned_human, "Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Invade the strange structure of the outsiders if you must. Do not cause unnecessary destruction, as littering the wastes with ugly wreckage is certain to not gain you favor. Glory to the Necropolis!") spawned_human.mind.add_antag_datum(/datum/antagonist/ashwalker, team) diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm index 086254aae388..b0c8bdadac9f 100644 --- a/code/modules/mob_spawn/mob_spawn.dm +++ b/code/modules/mob_spawn/mob_spawn.dm @@ -59,26 +59,15 @@ spawned_human.underwear = "Nude" spawned_human.undershirt = "Nude" spawned_human.socks = "Nude" + randomize_human_normie(spawned_human) if(hairstyle) - spawned_human.hairstyle = hairstyle - else - spawned_human.hairstyle = random_hairstyle(spawned_human.gender) + spawned_human.set_hairstyle(hairstyle, update = FALSE) if(facial_hairstyle) - spawned_human.facial_hairstyle = facial_hairstyle - else - spawned_human.facial_hairstyle = random_facial_hairstyle(spawned_human.gender) + spawned_human.set_facial_hairstyle(facial_hairstyle, update = FALSE) if(haircolor) - spawned_human.hair_color = haircolor - else - spawned_human.hair_color = "#[random_color()]" + spawned_human.set_haircolor(haircolor, update = FALSE) if(facial_haircolor) - spawned_human.facial_hair_color = facial_haircolor - else - spawned_human.facial_hair_color = "#[random_color()]" - if(skin_tone) - spawned_human.skin_tone = skin_tone - else - spawned_human.skin_tone = random_skin_tone() + spawned_human.set_facial_haircolor(facial_haircolor, update = FALSE) spawned_human.update_body(is_creating = TRUE) /obj/effect/mob_spawn/proc/name_mob(mob/living/spawned_mob, forced_name) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 0340d5b860dd..6df2e99c098f 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -912,7 +912,7 @@ return to_chat(affected_mob, span_warning("You grit your teeth in pain as your body rapidly mutates!")) affected_mob.visible_message("[affected_mob] suddenly transforms!") - randomize_human(affected_mob) + randomize_human_normie(affected_mob) /datum/reagent/aslimetoxin name = "Advanced Mutation Toxin" diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 29ccd0ccd872..4458793027f4 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -188,10 +188,10 @@ /obj/item/reagent_containers/hypospray/medipen/methamphetamine name = "methamphetamine medipen" - volume = 24 - amount_per_transfer_from_this = 24 + volume = 25 + amount_per_transfer_from_this = 25 desc = "Contains a relatively safe quantity of methamphetamine, along with mannitol to ensure that brain damage is kept at a minimum." - list_reagents = list(/datum/reagent/drug/methamphetamine = 10, /datum/reagent/medicine/mannitol = 14) + list_reagents = list(/datum/reagent/drug/methamphetamine = 10, /datum/reagent/medicine/mannitol = 15) // NON-MODULE CHANGE replacing this /* diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index ac144938ea7f..393d165da9a4 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -144,7 +144,7 @@ name = "mannitol pill" desc = "Used to treat brain damage." icon_state = "pill17" - list_reagents = list(/datum/reagent/medicine/mannitol = 14) + list_reagents = list(/datum/reagent/medicine/mannitol = 15) rename_with_volume = TRUE /obj/item/reagent_containers/pill/sansufentanyl diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index a1d4eff50a6e..ca4b71f48c7e 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -7,6 +7,7 @@ id = "rainbow_protection" duration = 100 alert_type = /atom/movable/screen/alert/status_effect/rainbow_protection + show_duration = TRUE var/originalcolor /datum/status_effect/rainbow_protection/on_apply() @@ -37,6 +38,7 @@ id = "slimeskin" duration = 300 alert_type = /atom/movable/screen/alert/status_effect/slimeskin + show_duration = TRUE var/originalcolor /datum/status_effect/slimeskin/on_apply() diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index e6b701d015b0..1f14aeb07f32 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -282,13 +282,12 @@ obj_flags |= EMAGGED SSshuttle.emergency.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL - var/datum/species/S = new for(var/i in 1 to 10) // the shuttle system doesn't know who these people are, but they // must be important, surely var/obj/item/card/id/ID = new(src) var/datum/job/J = pick(SSjob.joinable_occupations) - ID.registered_name = S.random_name(pick(MALE, FEMALE)) + ID.registered_name = generate_random_name_species_based(species_type = /datum/species/human) ID.assignment = J.title authorized += ID diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 50ac0e5021ac..d4309bd48831 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -17,6 +17,8 @@ VAR_PROTECTED/icon_invisible = 'icons/mob/human/bodyparts.dmi' ///The type of husk for building an iconstate var/husk_type = "humanoid" + ///The color to multiply the greyscaled husk sprites by. Can be null. Old husk sprite chest color is #A6A6A6 + var/husk_color = "#A6A6A6" layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor grind_results = list(/datum/reagent/bone_dust = 10, /datum/reagent/consumable/liquidgibs = 5) // robotic bodyparts and chests/heads cannot be ground /// The mob that "owns" this limb @@ -178,8 +180,6 @@ var/unarmed_damage_high = 1 ///Determines the accuracy bonus, armor penetration and knockdown probability. var/unarmed_effectiveness = 10 - /// How many pixels this bodypart will offset the top half of the mob, used for abnormally sized torsos and legs - var/top_offset = 0 /// Traits that are given to the holder of the part. If you want an effect that changes this, don't add directly to this. Use the add_bodypart_trait() proc var/list/bodypart_traits = list() @@ -1041,16 +1041,6 @@ var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir) var/image/aux - // Handles making bodyparts look husked - if(is_husked) - limb.icon = icon_husk - limb.icon_state = "[husk_type]_husk_[body_zone]" - icon_exists(limb.icon, limb.icon_state, scream = TRUE) //Prints a stack trace on the first failure of a given iconstate. - . += limb - if(aux_zone) //Hand shit - aux = image(limb.icon, "[husk_type]_husk_[aux_zone]", -aux_layer, image_dir) - . += aux - // Handles invisibility (not alpha or actual invisibility but invisibility) if(is_invisible) limb.icon = icon_invisible @@ -1059,38 +1049,42 @@ return . // Normal non-husk handling - if(!is_husked) // This is the MEAT of limb icon code - limb.icon = icon_greyscale - if(!should_draw_greyscale || !icon_greyscale) - limb.icon = icon_static + limb.icon = icon_greyscale + if(!should_draw_greyscale || !icon_greyscale) + limb.icon = icon_static - if(is_dimorphic) //Does this type of limb have sexual dimorphism? - limb.icon_state = "[limb_id]_[body_zone]_[limb_gender]" - else - limb.icon_state = "[limb_id]_[body_zone]" - - icon_exists(limb.icon, limb.icon_state, TRUE) //Prints a stack trace on the first failure of a given iconstate. + if(is_dimorphic) //Does this type of limb have sexual dimorphism? + limb.icon_state = "[limb_id]_[body_zone]_[limb_gender]" + else + limb.icon_state = "[limb_id]_[body_zone]" - . += limb + icon_exists(limb.icon, limb.icon_state, TRUE) //Prints a stack trace on the first failure of a given iconstate. - if(aux_zone) //Hand shit - aux = image(limb.icon, "[limb_id]_[aux_zone]", -aux_layer, image_dir) - . += aux + . += limb - draw_color = variable_color - if(should_draw_greyscale) //Should the limb be colored outside of a forced color? - draw_color ||= (species_color) || (skin_tone && skintone2hex(skin_tone)) + if(aux_zone) //Hand shit + aux = image(limb.icon, "[limb_id]_[aux_zone]", -aux_layer, image_dir) + . += aux + draw_color = variable_color + if(should_draw_greyscale) //Should the limb be colored outside of a forced color? + draw_color ||= (species_color) || (skin_tone && skintone2hex(skin_tone)) - if(draw_color) - limb.color = "[draw_color]" - if(aux_zone) - aux.color = "[draw_color]" + if(is_husked) + huskify_image(thing_to_husk = limb) + if(aux) + huskify_image(thing_to_husk = aux) + draw_color = husk_color + if(draw_color) + limb.color = "[draw_color]" + if(aux_zone) + aux.color = "[draw_color]" //EMISSIVE CODE START // For some reason this was applied as an overlay on the aux image and limb image before. // I am very sure that this is unnecessary, and i need to treat it as part of the return list // to be able to mask it proper in case this limb is a leg. + if(!is_husked) if(blocks_emissive != EMISSIVE_BLOCK_NONE) var/atom/location = loc || owner || src var/mutable_appearance/limb_em_block = emissive_blocker(limb.icon, limb.icon_state, location, layer = limb.layer, alpha = limb.alpha) @@ -1126,6 +1120,17 @@ return . +/obj/item/bodypart/proc/huskify_image(image/thing_to_husk, draw_blood = TRUE) + var/icon/husk_icon = new(thing_to_husk.icon) + husk_icon.ColorTone(HUSK_COLOR_TONE) + thing_to_husk.icon = husk_icon + if(draw_blood) + var/mutable_appearance/husk_blood = mutable_appearance(icon_husk, "[husk_type]_husk_[body_zone]") + husk_blood.blend_mode = BLEND_INSET_OVERLAY + husk_blood.appearance_flags |= RESET_COLOR + husk_blood.dir = thing_to_husk.dir + thing_to_husk.add_overlay(husk_blood) + ///Add a bodypart overlay and call the appropriate update procs /obj/item/bodypart/proc/add_bodypart_overlay(datum/bodypart_overlay/overlay) bodypart_overlays += overlay diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index fcf3f8f19ecc..eee42c49afb0 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -72,7 +72,6 @@ icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi' icon_husk = 'icons/mob/human/species/monkey/bodyparts.dmi' husk_type = "monkey" - top_offset = -5 icon_state = "default_monkey_chest" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE @@ -453,7 +452,6 @@ icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi' icon_husk = 'icons/mob/human/species/monkey/bodyparts.dmi' husk_type = "monkey" - top_offset = -3 icon_state = "default_monkey_l_leg" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE @@ -542,7 +540,6 @@ icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi' icon_husk = 'icons/mob/human/species/monkey/bodyparts.dmi' husk_type = "monkey" - top_offset = -3 icon_state = "default_monkey_r_leg" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE @@ -566,15 +563,3 @@ can_be_disabled = FALSE max_damage = LIMB_MAX_HP_ALIEN_LIMBS should_draw_greyscale = FALSE - -/obj/item/bodypart/leg/right/tallboy - limb_id = SPECIES_TALLBOY - top_offset = 23 - unarmed_damage_low = 30 - unarmed_damage_low = 50 - -/obj/item/bodypart/leg/left/tallboy - limb_id = SPECIES_TALLBOY - top_offset = 23 - unarmed_damage_low = 30 - unarmed_damage_low = 50 diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm index bd60e84d2427..dd2f66000be2 100644 --- a/code/modules/surgery/lipoplasty.dm +++ b/code/modules/surgery/lipoplasty.dm @@ -81,14 +81,17 @@ var/mob/living/carbon/human/human = target var/typeofmeat = /obj/item/food/meat/slab/human - if(human.dna && human.dna.species) + if(target.flags_1 & HOLOGRAM_1) + typeofmeat = null + else if(human.dna && human.dna.species) typeofmeat = human.dna.species.meat - var/obj/item/food/meat/slab/human/newmeat = new typeofmeat - newmeat.name = "fatty meat" - newmeat.desc = "Extremely fatty tissue taken from a patient." - newmeat.subjectname = human.real_name - newmeat.subjectjob = human.job - newmeat.reagents.add_reagent (/datum/reagent/consumable/nutriment, (removednutriment / 15)) //To balance with nutriment_factor of nutriment - newmeat.forceMove(target.loc) + if(typeofmeat) + var/obj/item/food/meat/slab/human/newmeat = new typeofmeat + newmeat.name = "fatty meat" + newmeat.desc = "Extremely fatty tissue taken from a patient." + newmeat.subjectname = human.real_name + newmeat.subjectjob = human.job + newmeat.reagents.add_reagent (/datum/reagent/consumable/nutriment, (removednutriment / 15)) //To balance with nutriment_factor of nutriment + newmeat.forceMove(target.loc) return ..() diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index 9fda5a87f1b8..2643dba07528 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -141,13 +141,16 @@ var/wagging = FALSE /datum/bodypart_overlay/mutant/tail/get_base_icon_state() - return (wagging ? "wagging_" : "") + sprite_datum.icon_state //add the wagging tag if we be wagging + return "[wagging ? "wagging_" : ""][sprite_datum.icon_state]" //add the wagging tag if we be wagging /datum/bodypart_overlay/mutant/tail/can_draw_on_bodypart(mob/living/carbon/human/human) if(human.wear_suit && (human.wear_suit.flags_inv & HIDEJUMPSUIT)) return FALSE return TRUE +/datum/bodypart_overlay/mutant/tail/get_global_feature_list() + return GLOB.tails_list_human + /obj/item/organ/external/tail/cat name = "tail" preference = "feature_human_tail" @@ -161,12 +164,14 @@ feature_key = "tail_cat" color_source = ORGAN_COLOR_HAIR -/datum/bodypart_overlay/mutant/tail/cat/get_global_feature_list() - return GLOB.tails_list_human - /obj/item/organ/external/tail/monkey + name = "monkey tail" + preference = "feature_monkey_tail" + bodypart_overlay = /datum/bodypart_overlay/mutant/tail/monkey + dna_block = null + ///Monkey tail bodypart overlay /datum/bodypart_overlay/mutant/tail/monkey color_source = NONE diff --git a/code/modules/surgery/organs/internal/lungs/_lungs.dm b/code/modules/surgery/organs/internal/lungs/_lungs.dm index b77238400bee..aa709771d4db 100644 --- a/code/modules/surgery/organs/internal/lungs/_lungs.dm +++ b/code/modules/surgery/organs/internal/lungs/_lungs.dm @@ -47,6 +47,7 @@ var/safe_plasma_min = 0 ///How much breath partial pressure is a safe amount of plasma. 0 means that we are immune to plasma. var/safe_plasma_max = 0.05 + var/n2o_detect_min = 0.08 //Minimum n2o for effects var/n2o_para_min = 1 //Sleeping agent var/n2o_sleep_min = 5 //Sleeping agent var/BZ_trip_balls_min = 1 //BZ gas @@ -503,12 +504,12 @@ /obj/item/organ/internal/lungs/proc/too_much_n2o(mob/living/carbon/breather, datum/gas_mixture/breath, n2o_pp, old_n2o_pp) if(n2o_pp < n2o_para_min) // Small amount of N2O, small side-effects. - if(n2o_pp <= 0.01) - if(old_n2o_pp > 0.01) + if(n2o_pp <= n2o_detect_min) + if(old_n2o_pp > n2o_detect_min) return BREATH_LOST return // No alert for small amounts, but the mob randomly feels euphoric. - if(old_n2o_pp >= n2o_para_min || old_n2o_pp <= 0.01) + if(old_n2o_pp >= n2o_para_min || old_n2o_pp <= n2o_detect_min) breather.clear_alert(ALERT_TOO_MUCH_N2O) if(prob(20)) diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm index d8d22c881610..b8ecb875fbe7 100644 --- a/code/modules/surgery/plastic_surgery.dm +++ b/code/modules/surgery/plastic_surgery.dm @@ -95,11 +95,11 @@ else user.visible_message(span_warning("You have no picture to base the appearance on, reverting to random appearances.")) for(var/i in 1 to 10) - names += target.dna.species.random_name(target.gender, TRUE) + names += target.generate_random_mob_name(TRUE) else - for(var/_i in 1 to 9) + for(var/j in 1 to 9) names += "Subject [target.gender == MALE ? "i" : "o"]-[pick("a", "b", "c", "d", "e")]-[rand(10000, 99999)]" - names += target.dna.species.random_name(target.gender, TRUE) //give one normal name in case they want to do regular plastic surgery + names += target.generate_random_mob_name(TRUE) //give one normal name in case they want to do regular plastic surgery var/chosen_name = tgui_input_list(user, "New name to assign", "Plastic Surgery", names) if(isnull(chosen_name)) return diff --git a/code/modules/transport/tram/tram_doors.dm b/code/modules/transport/tram/tram_doors.dm index d836685acf11..6008c383ec93 100644 --- a/code/modules/transport/tram/tram_doors.dm +++ b/code/modules/transport/tram/tram_doors.dm @@ -136,7 +136,7 @@ for(var/mob/living/future_pancake in checked_turf) future_pancake.visible_message(span_warning("[src] beeps angrily and closes on [future_pancake]!"), span_userdanger("[src] beeps angrily and closes on you!")) SEND_SIGNAL(future_pancake, COMSIG_LIVING_DOORCRUSHED, src) - if(ishuman(future_pancake) || ismonkey(future_pancake)) + if(ishuman(future_pancake)) future_pancake.emote("scream") future_pancake.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 2) future_pancake.Paralyze(2 SECONDS) diff --git a/code/modules/unit_tests/limbsanity.dm b/code/modules/unit_tests/limbsanity.dm index 9988c7471e29..d7acfeedf4a6 100644 --- a/code/modules/unit_tests/limbsanity.dm +++ b/code/modules/unit_tests/limbsanity.dm @@ -10,29 +10,3 @@ TEST_FAIL("[path] does not have a valid icon for female variants") else if(!icon_exists(UNLINT(part.should_draw_greyscale ? part.icon_greyscale : part.icon_static), "[part.limb_id]_[part.body_zone]")) TEST_FAIL("[path] does not have a valid icon") - -/// Tests the height adjustment system which dynamically changes how much the chest, head, and arms of a carbon are adjusted upwards or downwards based on the length of their legs and chest. -/datum/unit_test/limb_height_adjustment - -/datum/unit_test/limb_height_adjustment/Run() - var/mob/living/carbon/human/john_doe = allocate(/mob/living/carbon/human/consistent) - var/mob/living/carbon/human/species/monkey/monkey = allocate(/mob/living/carbon/human/species/monkey) - var/mob/living/carbon/human/tallboy = allocate(/mob/living/carbon/human/consistent) - - tallboy.set_species(/datum/species/human/tallboy) - TEST_ASSERT_EQUAL(john_doe.get_top_offset(), 0, "John Doe found to have a top offset other than zero.") - TEST_ASSERT_EQUAL(monkey.get_top_offset(), -8, "Monkey found to have a top offset other than -8.") - TEST_ASSERT_EQUAL(tallboy.get_top_offset(), 23, "Tallboy human varient found to have a top offset other than 23.") - - - var/obj/item/bodypart/leg/left/monkey/left_monky_leg = allocate(/obj/item/bodypart/leg/left/monkey) - var/obj/item/bodypart/leg/right/monkey/right_monky_leg = allocate(/obj/item/bodypart/leg/right/monkey) - - left_monky_leg.replace_limb(john_doe, TRUE) - - TEST_ASSERT_EQUAL(john_doe.get_top_offset(), 0, "John Doe has a top offset other than 0 with one human leg and one monkey leg.") - - right_monky_leg.replace_limb(john_doe, TRUE) - - TEST_ASSERT_EQUAL(john_doe.get_top_offset(), -3, "John Doe has a top offset other than -3 with two monkey legs.") - diff --git a/code/modules/unit_tests/preference_species.dm b/code/modules/unit_tests/preference_species.dm index 8e49f49cdd6a..8d913cc8fb64 100644 --- a/code/modules/unit_tests/preference_species.dm +++ b/code/modules/unit_tests/preference_species.dm @@ -12,7 +12,7 @@ for(var/species_id in get_selectable_species()) var/species_type = GLOB.species_list[species_id] - var/datum/species/species = new species_type() + var/datum/species/species = GLOB.species_prototypes[species_type] // Check the species decription. // If it's not overridden, a stack trace will be thrown (and fail the test). @@ -29,5 +29,3 @@ TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore().") else if(!islist(species_lore)) TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore() (Did not return a list).") - - qdel(species) diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_tallboy.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_tallboy.png deleted file mode 100644 index 262353dc0a95..000000000000 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_tallboy.png and /dev/null differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png index d1bac73e30e9..5fd259a0ed4f 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_holodeck.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_holodeck.png deleted file mode 100644 index d1bac73e30e9..000000000000 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_holodeck.png and /dev/null differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_human_legged.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_human_legged.png deleted file mode 100644 index 21cb8c508530..000000000000 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_human_legged.png and /dev/null differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_lizard.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_lizard.png new file mode 100644 index 000000000000..581daeed9c69 Binary files /dev/null and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_lizard.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_monkey_freak.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_monkey_freak.png deleted file mode 100644 index dc13acaeffcc..000000000000 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_monkey_monkey_freak.png and /dev/null differ diff --git a/code/modules/unit_tests/screenshots/screenshot_husk_body.png b/code/modules/unit_tests/screenshots/screenshot_husk_body.png index 2911277fcd97..d113b4738467 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_husk_body.png and b/code/modules/unit_tests/screenshots/screenshot_husk_body.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png b/code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png index 6c526af2ebb2..1a1db7dfd87f 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png and b/code/modules/unit_tests/screenshots/screenshot_husk_body_missing_limbs.png differ diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi index fbe6871c92e2..62f24a9d9033 100644 Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ diff --git a/icons/mob/clothing/belt_mirror.dmi b/icons/mob/clothing/belt_mirror.dmi index eb06288d800b..a5c2fcef7784 100644 Binary files a/icons/mob/clothing/belt_mirror.dmi and b/icons/mob/clothing/belt_mirror.dmi differ diff --git a/icons/mob/human/bodyparts.dmi b/icons/mob/human/bodyparts.dmi index 2150b3c2c810..d6e4472973a3 100644 Binary files a/icons/mob/human/bodyparts.dmi and b/icons/mob/human/bodyparts.dmi differ diff --git a/icons/mob/human/species/monkey/bodyparts.dmi b/icons/mob/human/species/monkey/bodyparts.dmi index 689ef5e63d7e..95e8ae05deff 100644 Binary files a/icons/mob/human/species/monkey/bodyparts.dmi and b/icons/mob/human/species/monkey/bodyparts.dmi differ diff --git a/icons/mob/human/species/monkey/monkey_tail.dmi b/icons/mob/human/species/monkey/monkey_tail.dmi index 2a06af25b797..ffebf714f9aa 100644 Binary files a/icons/mob/human/species/monkey/monkey_tail.dmi and b/icons/mob/human/species/monkey/monkey_tail.dmi differ diff --git a/icons/mob/human/species/monkey/uniform.dmi b/icons/mob/human/species/monkey/uniform.dmi deleted file mode 100644 index a835629528ae..000000000000 Binary files a/icons/mob/human/species/monkey/uniform.dmi and /dev/null differ diff --git a/maplestation.dme b/maplestation.dme index 24ded6fe9583..f47914369b91 100644 --- a/maplestation.dme +++ b/maplestation.dme @@ -4234,6 +4234,10 @@ #include "code\modules\keybindings\bindings_client.dm" #include "code\modules\keybindings\focus.dm" #include "code\modules\keybindings\setup.dm" +#include "code\modules\language\_language.dm" +#include "code\modules\language\_language_holder.dm" +#include "code\modules\language\_language_manuals.dm" +#include "code\modules\language\_language_menu.dm" #include "code\modules\language\aphasia.dm" #include "code\modules\language\beachbum.dm" #include "code\modules\language\buzzwords.dm" @@ -4242,10 +4246,6 @@ #include "code\modules\language\common.dm" #include "code\modules\language\draconic.dm" #include "code\modules\language\drone.dm" -#include "code\modules\language\language.dm" -#include "code\modules\language\language_holder.dm" -#include "code\modules\language\language_manuals.dm" -#include "code\modules\language\language_menu.dm" #include "code\modules\language\machine.dm" #include "code\modules\language\moffic.dm" #include "code\modules\language\monkey.dm" @@ -4853,7 +4853,6 @@ #include "code\modules\mob\living\carbon\human\status_procs.dm" #include "code\modules\mob\living\carbon\human\suicides.dm" #include "code\modules\mob\living\carbon\human\species_types\abductors.dm" -#include "code\modules\mob\living\carbon\human\species_types\abominations.dm" #include "code\modules\mob\living\carbon\human\species_types\android.dm" #include "code\modules\mob\living\carbon\human\species_types\dullahan.dm" #include "code\modules\mob\living\carbon\human\species_types\ethereal.dm" diff --git a/maplestation_modules/code/controllers/subsystem/economy.dm b/maplestation_modules/code/controllers/subsystem/economy.dm index e732e0c52fb5..8454df13759b 100644 --- a/maplestation_modules/code/controllers/subsystem/economy.dm +++ b/maplestation_modules/code/controllers/subsystem/economy.dm @@ -101,11 +101,11 @@ all_tracked_data += "subject_two" if(findtext(paper_contents, "victim")) var/list/possible_names = list( - "human" = random_unique_name(), - "lizard" = random_unique_lizard_name(), - "plasmaman" = random_unique_plasmaman_name(), - "ethereal" = random_unique_ethereal_name(), - "moth" = random_unique_moth_name(), + "human" = generate_random_name_species_based(species_type = /datum/species/human), + "lizard" = generate_random_name_species_based(species_type = /datum/species/lizard), + "plasmaman" = generate_random_name_species_based(species_type = /datum/species/plasmaman), + "ethereal" = generate_random_name_species_based(species_type = /datum/species/ethereal), + "moth" = generate_random_name_species_based(species_type = /datum/species/moth), ) paper_victim_species = pick(possible_names) paper_victim = possible_names[paper_victim_species] diff --git a/maplestation_modules/code/modules/language/highdraconic.dm b/maplestation_modules/code/modules/language/highdraconic.dm index 6006bb2f8ed6..b671914981b3 100644 --- a/maplestation_modules/code/modules/language/highdraconic.dm +++ b/maplestation_modules/code/modules/language/highdraconic.dm @@ -4,10 +4,6 @@ /datum/language/impdraconic name = "Tiziran Draconic" desc = "A distinct dialect of Draconic common to lizards born and raised on Tizira." - //speech_verb = "hisses" - //ask_verb = "hisses" - //exclaim_verb = "roars" - //sing_verb = "sings" key = "l" flags = TONGUELESS_SPEECH space_chance = 25 @@ -49,3 +45,12 @@ selected_language = /datum/language/uncommon #endif + +/datum/language_holder/lizard/ash/primative + selected_language = /datum/language/impdraconic + understood_languages = list( + /datum/language/impdraconic = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/impdraconic = list(LANGUAGE_ATOM), + ) diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index f7ce076b139d..7556ed04f675 100644 --- a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -26,3 +26,12 @@ horns?.bodypart_overlay.set_appearance_from_name("Simple") human.update_body(is_creating = TRUE) + +// Same for the small ones +/datum/species/monkey/lizard/get_species_speech_sounds(sound_type) + // These sounds have been ported from Goonstation. + return string_assoc_list(list( + 'maplestation_modules/sound/voice/lizard_1.ogg' = 80, + 'maplestation_modules/sound/voice/lizard_2.ogg' = 80, + 'maplestation_modules/sound/voice/lizard_3.ogg' = 80, + )) diff --git a/tgstation.dme b/tgstation.dme index 927ad6508a7c..5fa34ee2aa8f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3631,6 +3631,7 @@ #include "code\modules\client\preferences\species_features\ethereal.dm" #include "code\modules\client\preferences\species_features\felinid.dm" #include "code\modules\client\preferences\species_features\lizard.dm" +#include "code\modules\client\preferences\species_features\monkey.dm" #include "code\modules\client\preferences\species_features\moth.dm" #include "code\modules\client\preferences\species_features\mushperson.dm" #include "code\modules\client\preferences\species_features\mutants.dm" @@ -4234,6 +4235,10 @@ #include "code\modules\keybindings\bindings_client.dm" #include "code\modules\keybindings\focus.dm" #include "code\modules\keybindings\setup.dm" +#include "code\modules\language\_language.dm" +#include "code\modules\language\_language_holder.dm" +#include "code\modules\language\_language_manuals.dm" +#include "code\modules\language\_language_menu.dm" #include "code\modules\language\aphasia.dm" #include "code\modules\language\beachbum.dm" #include "code\modules\language\buzzwords.dm" @@ -4242,10 +4247,6 @@ #include "code\modules\language\common.dm" #include "code\modules\language\draconic.dm" #include "code\modules\language\drone.dm" -#include "code\modules\language\language.dm" -#include "code\modules\language\language_holder.dm" -#include "code\modules\language\language_manuals.dm" -#include "code\modules\language\language_menu.dm" #include "code\modules\language\machine.dm" #include "code\modules\language\moffic.dm" #include "code\modules\language\monkey.dm" @@ -4853,7 +4854,6 @@ #include "code\modules\mob\living\carbon\human\status_procs.dm" #include "code\modules\mob\living\carbon\human\suicides.dm" #include "code\modules\mob\living\carbon\human\species_types\abductors.dm" -#include "code\modules\mob\living\carbon\human\species_types\abominations.dm" #include "code\modules\mob\living\carbon\human\species_types\android.dm" #include "code\modules\mob\living\carbon\human\species_types\dullahan.dm" #include "code\modules\mob\living\carbon\human\species_types\ethereal.dm" diff --git a/tgui/packages/tgui/interfaces/DnaConsole/DnaScanner.jsx b/tgui/packages/tgui/interfaces/DnaConsole/DnaScanner.jsx index 22fff93dfdda..8d6e53dbba63 100644 --- a/tgui/packages/tgui/interfaces/DnaConsole/DnaScanner.jsx +++ b/tgui/packages/tgui/interfaces/DnaConsole/DnaScanner.jsx @@ -10,6 +10,7 @@ import { import { SUBJECT_CONCIOUS, SUBJECT_DEAD, + SUBJECT_HARD_CRIT, SUBJECT_SOFT_CRIT, SUBJECT_TRANSFORMING, SUBJECT_UNCONSCIOUS, @@ -81,7 +82,7 @@ const SubjectStatus = (props) => { ); } - if (status === SUBJECT_UNCONSCIOUS) { + if (status === SUBJECT_UNCONSCIOUS || status === SUBJECT_HARD_CRIT) { return ( Unconscious diff --git a/tgui/packages/tgui/interfaces/DnaConsole/constants.ts b/tgui/packages/tgui/interfaces/DnaConsole/constants.ts index c588c765e765..e3d11a5dcd50 100644 --- a/tgui/packages/tgui/interfaces/DnaConsole/constants.ts +++ b/tgui/packages/tgui/interfaces/DnaConsole/constants.ts @@ -31,8 +31,9 @@ export const STORAGE_MODE_ADVINJ = 'injector'; export const SUBJECT_CONCIOUS = 0; export const SUBJECT_SOFT_CRIT = 1; export const SUBJECT_UNCONSCIOUS = 2; -export const SUBJECT_DEAD = 3; -export const SUBJECT_TRANSFORMING = 4; +export const SUBJECT_HARD_CRIT = 3; +export const SUBJECT_DEAD = 4; +export const SUBJECT_TRANSFORMING = 5; export const PULSE_STRENGTH_MAX = 15; export const PULSE_DURATION_MAX = 30; diff --git a/tgui/packages/tgui/interfaces/MedicalKiosk.jsx b/tgui/packages/tgui/interfaces/MedicalKiosk.jsx index 5d8b081e0ef4..98d71c043314 100644 --- a/tgui/packages/tgui/interfaces/MedicalKiosk.jsx +++ b/tgui/packages/tgui/interfaces/MedicalKiosk.jsx @@ -248,6 +248,7 @@ const MedicalKioskScanResults4 = (props) => { overdose_list = [], addict_list = [], hallucinating_status, + blood_alcohol, } = data; return (
@@ -281,6 +282,19 @@ const MedicalKioskScanResults4 = (props) => { {hallucinating_status} + + + + +
); diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx index 457e67fd0a61..b7d0d69959f0 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx @@ -68,6 +68,15 @@ export const feature_human_tail: FeatureChoiced = { }, }; +export const feature_monkey_tail: FeatureChoiced = { + name: 'Tail', + component: ( + props: FeatureValueProps, + ) => { + return ; + }, +}; + export const feature_lizard_legs: FeatureChoiced = { name: 'Legs', component: ( diff --git a/tgui/packages/tgui/interfaces/Vending.tsx b/tgui/packages/tgui/interfaces/Vending.tsx index 2f8cd42dade9..d3e9071a8f26 100644 --- a/tgui/packages/tgui/interfaces/Vending.tsx +++ b/tgui/packages/tgui/interfaces/Vending.tsx @@ -12,7 +12,10 @@ import { Stack, Table, } from 'tgui/components'; -import { Window } from 'tgui/layouts'; + +import { createSearch } from '../../common/string'; +import { Input } from '../components'; +import { Window } from '../layouts'; type VendingData = { onstation: boolean; @@ -24,7 +27,7 @@ type VendingData = { coin_records: CoinRecord[]; hidden_records: HiddenRecord[]; user: UserData; - stock: StockItem[]; + stock: Record[]; extended_inventory: boolean; access: boolean; vending_machine_input: CustomInput[]; @@ -81,11 +84,17 @@ export const Vending = (props) => { product_records = [], coin_records = [], hidden_records = [], - stock, + categories, } = data; const [selectedCategory, setSelectedCategory] = useState( - Object.keys(data.categories)[0], + Object.keys(categories)[0], + ); + + const [stockSearch, setStockSearch] = useState(''); + const stockSearchFn = createSearch( + stockSearch, + (item: ProductRecord | CustomInput) => item.name, ); let inventory: (ProductRecord | CustomInput)[]; @@ -100,12 +109,15 @@ export const Vending = (props) => { } } - inventory = inventory - // Just in case we still have undefined values in the list - .filter((item) => !!item); + // Just in case we still have undefined values in the list + inventory = inventory.filter((item) => !!item); + + if (stockSearch.length >= 2) { + inventory = inventory.filter(stockSearchFn); + } const filteredCategories = Object.fromEntries( - Object.entries(data.categories).filter(([categoryName]) => { + Object.entries(categories).filter(([categoryName]) => { return inventory.find((product) => { if ('category' in product) { return product.category === categoryName; @@ -114,7 +126,7 @@ export const Vending = (props) => { } }); }), - ); + ) as { [k: string]: Category }; return ( @@ -129,19 +141,23 @@ export const Vending = (props) => { - {Object.keys(filteredCategories).length > 1 && ( - - - - )} + {stockSearch.length < 2 && + Object.keys(filteredCategories).length > 1 && ( + + + + )} @@ -155,7 +171,9 @@ export const UserDetails = (props) => { if (!user) { return ( - No ID detected! Contact the Head of Personnel. +
+ No ID detected! Contact the Head of Personnel. +
); } else { return ( @@ -181,11 +199,21 @@ export const UserDetails = (props) => { /** Displays products in a section, with user balance at top */ const ProductDisplay = (props: { custom: boolean; - selectedCategory: string | null; inventory: (ProductRecord | CustomInput)[]; + stockSearch: string; + setStockSearch: (search: string) => void; + selectedCategory: string | null; + setSelectedCategory: (category: string) => void; }) => { const { data } = useBackend(); - const { custom, inventory, selectedCategory } = props; + const { + custom, + inventory, + stockSearch, + setStockSearch, + selectedCategory, + setSelectedCategory, + } = props; const { stock, onstation, @@ -200,20 +228,28 @@ const ProductDisplay = (props: { scrollable title="Products" buttons={ - !!onstation && - user && ( - - {(user && user.cash) || 0} - {displayed_currency_name}{' '} - - - ) + + {!!onstation && user && ( + + {(user && user.cash) || 0} + {displayed_currency_name}{' '} + + + )} + + setStockSearch(value)} + placeholder="Search..." + value={stockSearch} + /> + + } > {inventory .filter((product) => { - if ('category' in product) { + if (!stockSearch && 'category' in product) { return product.category === selectedCategory; } else { return true;