diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 05338f347020c..5f1fe7ce47318 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -98,7 +98,7 @@ #define DNA_HAIR_STYLE_BLOCK 7 /// This number needs to equal the total number of DNA blocks -#define DNA_FEATURE_BLOCKS 22 +#define DNA_FEATURE_BLOCKS 28 #define DNA_MUTANT_COLOR_BLOCK 1 #define DNA_ETHEREAL_COLOR_BLOCK 2 @@ -123,6 +123,12 @@ #define DNA_PRETERNIS_WEATHERING_BLOCK 20 #define DNA_PRETERNIS_ANTENNA_BLOCK 21 #define DNA_PRETERNIS_EYE_BLOCK 22 +#define DNA_VOX_QUILLS_BLOCK 23 +#define DNA_VOX_FACIAL_QUILLS_BLOCK 24 +#define DNA_VOX_TAIL_MARKINGS_BLOCK 25 +#define DNA_VOX_BODY_MARKINGS_BLOCK 26 +#define DNA_VOX_SKIN_TONE_BLOCK 27 +#define DNA_MUTANT_COLOR_SECONDARY 28 #define DNA_SEQUENCE_LENGTH 4 #define DNA_MUTATION_BLOCKS 8 @@ -183,6 +189,9 @@ /// has a tail #define HAS_TAIL 24 #define NONANITES 25 +#define HAIRCOLOR 26 +#define FACEHAIRCOLOR 27 +#define MUTCOLORS_SECONDARY 28 //organ slots #define ORGAN_SLOT_BRAIN "brain" diff --git a/code/__DEFINES/species_clothing_paths.dm b/code/__DEFINES/species_clothing_paths.dm new file mode 100644 index 0000000000000..b504e8594a806 --- /dev/null +++ b/code/__DEFINES/species_clothing_paths.dm @@ -0,0 +1,7 @@ +//HUMAN PATHS +///The dmi for humanoid uniforms +#define DEFAULT_UNIFORM_FILE 'icons/mob/clothing/uniform/uniform.dmi' +///The dmi for humanoid shoes +#define DEFAULT_SHOES_FILE 'icons/mob/clothing/feet/feet.dmi' +///The dmi for humanoid oversuits +#define DEFAULT_SUIT_FILE 'icons/mob/clothing/suit/suit.dmi' diff --git a/code/__DEFINES/{yogs_defines}/colors.dm b/code/__DEFINES/{yogs_defines}/colors.dm new file mode 100644 index 0000000000000..c8312ec5ccc9c --- /dev/null +++ b/code/__DEFINES/{yogs_defines}/colors.dm @@ -0,0 +1,10 @@ +//Vox blood color +#define COLOR_BLOOD_VOX "#2299FC" + +//Color blending modes +#define COLOR_BLEND_MULTIPLY "multiply" +#define COLOR_BLEND_ADD "add" + +//Color matrix +#define COLOR_MATRIX_ADD(color) list(COLOR_RED, COLOR_VIBRANT_LIME, COLOR_BLUE, color) +#define COLOR_MATRIX_OVERLAY(color) list(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, color) diff --git a/code/__DEFINES/{yogs_defines}/is_helpers.dm b/code/__DEFINES/{yogs_defines}/is_helpers.dm index c7f9e20420089..f16192ad56698 100644 --- a/code/__DEFINES/{yogs_defines}/is_helpers.dm +++ b/code/__DEFINES/{yogs_defines}/is_helpers.dm @@ -1,3 +1,5 @@ +#define isvox(A) (is_species(A, /datum/species/vox)) + #define isdarkspawn(A) (A?.mind?.has_antag_datum(/datum/antagonist/darkspawn)) #define isthrall(A) (A?.mind?.has_antag_datum(/datum/antagonist/thrall)) #define ispsyche(A) (A?.mind?.has_antag_datum(/datum/antagonist/psyche)) //non thrall teammates diff --git a/code/__DEFINES/{yogs_defines}/mobs.dm b/code/__DEFINES/{yogs_defines}/mobs.dm index 816023c8161ac..dc4c11e90278d 100644 --- a/code/__DEFINES/{yogs_defines}/mobs.dm +++ b/code/__DEFINES/{yogs_defines}/mobs.dm @@ -8,3 +8,7 @@ #define REGEN_BLOOD_REQUIREMENT 40 // The amount of "blood" that a slimeperson consumes when regenerating a single limb. #define MONKIFY_BLOOD_COEFFICIENT (BLOOD_VOLUME_MONKEY/BLOOD_VOLUME_GENERIC) //the ratio of monkey to human blood volume so a 100% blood volume monkey will not instantly die when you turn it into a human with ~58% blood volume + +#define SPECIES_VOX "vox" + +#define BUTT_SPRITE_VOX "vox" diff --git a/code/__DEFINES/{yogs_defines}/species_clothing_paths.dm b/code/__DEFINES/{yogs_defines}/species_clothing_paths.dm new file mode 100644 index 0000000000000..cb02eb5bf2680 --- /dev/null +++ b/code/__DEFINES/{yogs_defines}/species_clothing_paths.dm @@ -0,0 +1,11 @@ +//VOX PATHS +#define VOX_MASK_FILE 'icons/mob/clothing/species/vox/mask.dmi' +#define VOX_HEAD_FILE 'icons/mob/clothing/species/vox/head.dmi' +#define VOX_BACK_FILE 'icons/mob/clothing/species/vox/back.dmi' +#define VOX_EARS_FILE 'icons/mob/clothing/species/vox/ears.dmi' +#define VOX_EYES_FILE 'icons/mob/clothing/species/vox/eyes.dmi' +#define VOX_SHOES_FILE 'icons/mob/clothing/species/vox/shoes.dmi' +#define VOX_GLOVES_FILE 'icons/mob/clothing/species/vox/gloves.dmi' +#define VOX_HELMET_FILE 'icons/mob/clothing/species/vox/helmet.dmi' +#define VOX_SUIT_FILE 'icons/mob/clothing/species/vox/suit.dmi' +#define VOX_UNIFORM_FILE 'icons/mob/clothing/species/vox/uniform.dmi' diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index ab1c0a2c5ed81..3b538f1b8d9af 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -45,6 +45,15 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_screens, GLOB.ipc_screens_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_antennas, GLOB.ipc_antennas_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_chassis, GLOB.ipc_chassis_list) + // Vox bodyparts + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_quills, GLOB.vox_quills_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_facial_quills, GLOB.vox_facial_quills_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_tails, GLOB.vox_tails_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_body_markings, GLOB.vox_body_markings_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_tail_markings, GLOB.vox_tail_markings_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails_animated/vox, GLOB.animated_vox_tails_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_tail_markings_animated, GLOB.animated_vox_tail_markings_list) + diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index f9f7109482573..773eab6e1cee8 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -228,10 +228,13 @@ world /icon/proc/Greyify() MapColors(0.75,0.3,0.3, 0.6,0.75,0.6, 0.10,0.10,0.50, 0,0,0) -/icon/proc/ColorTone(tone) - Greyify() +/icon/proc/ColorTone(tone, greyify = FALSE) + if(greyify) + Greyify() + else + 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 @@ -922,7 +925,7 @@ world /proc/getHologramIcon(icon/A, safety=1)//If safety is on, a new icon is not created. var/icon/flat_icon = safety ? A : new(A)//Has to be a new icon to not constantly change the same icon. - flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish. + flat_icon.ColorTone(rgb(125,180,225), greyify = TRUE)//Let's make it bluish. flat_icon.ChangeOpacity(0.5)//Make it half transparent. var/icon/alpha_mask = new('icons/effects/effects.dmi', "scanline")//Scanline effect. flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect. diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 1ab59833e0f09..936ddf1b2e1f7 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -95,10 +95,21 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_antennas, GLOB.ipc_antennas_list) if(!GLOB.ipc_chassis_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_chassis, GLOB.ipc_chassis_list) + if(!GLOB.vox_quills_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_quills, GLOB.vox_quills_list) + if(!GLOB.vox_facial_quills_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_facial_quills, GLOB.vox_facial_quills_list) + if(!GLOB.vox_tails_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_tails, GLOB.vox_tails_list) + if(!GLOB.vox_body_markings_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_body_markings, GLOB.vox_body_markings_list) + if(!GLOB.vox_tail_markings_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_tail_markings, GLOB.vox_tail_markings_list) //For now we will always return none for tail_human and ears. this shit was unreadable if you do somethign like this make it at least readable return(list( "mcolor" = "#[pick("7F","FF")][pick("7F","FF")][pick("7F","FF")]", + "mcolor_secondary" = "#[pick("7F","FF")][pick("7F","FF")][pick("7F","FF")]", "gradientstyle" = random_hair_gradient_style(10), "gradientcolor" = "#[pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")]", "tail_lizard" = pick(GLOB.tails_list_lizard), @@ -126,7 +137,12 @@ "pod_hair" = pick(GLOB.pod_hair_list), "ipc_screen" = pick(GLOB.ipc_screens_list), "ipc_antenna" = pick(GLOB.ipc_antennas_list), - "ipc_chassis" = pick(GLOB.ipc_chassis_list) + "ipc_chassis" = pick(GLOB.ipc_chassis_list), + "vox_skin_tone" = pick(GLOB.vox_skin_tones), + "vox_quills" = pick(GLOB.vox_quills_list), + "vox_facial_quills" = pick(GLOB.vox_facial_quills_list), + "vox_body_markings" = pick(GLOB.vox_body_markings_list), + "vox_tail_markings" = pick(GLOB.vox_tail_markings_list) )) /proc/random_hair_style(gender) diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index 0bda2b22d1bce..0a879c2632648 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -80,12 +80,14 @@ GLOBAL_LIST_INIT(maintenance_loot_traditional,list( /obj/item/clothing/mask/breath = W_UNCOMMON, /obj/item/tank/internals/air = W_COMMON, /obj/item/tank/internals/anesthetic = W_RARE, + /obj/item/tank/internals/nitrogen = W_RARE, /obj/item/tank/internals/emergency_oxygen = W_UNCOMMON, /obj/item/tank/internals/emergency_oxygen/empty = W_UNCOMMON, /obj/item/tank/internals/emergency_oxygen/engi = W_RARE, /obj/item/tank/internals/emergency_oxygen/engi/empty = W_RARE, /obj/item/tank/internals/emergency_oxygen/double = W_MYTHICAL, /obj/item/tank/internals/emergency_oxygen/double/empty = W_MYTHICAL, + /obj/item/tank/internals/emergency_oxygen/vox = W_MYTHICAL, /obj/item/tank/internals/ipc_coolant = W_RARE, /obj/item/tank/internals/ipc_coolant/empty = W_RARE, /obj/item/tank/internals/plasma = W_LEGENDARY, @@ -365,6 +367,7 @@ GLOBAL_LIST_INIT(maintenance_loot_traditional,list( /obj/item/stack/sheet/animalhide/gorilla = W_RARE, /obj/item/stack/sheet/animalhide/human = W_RARE, /obj/item/stack/sheet/animalhide/lizard = W_RARE, + /obj/item/stack/sheet/animalhide/vox = W_RARE, /obj/item/stack/sheet/animalhide/monkey = W_RARE, /obj/item/stack/sheet/animalhide/xeno = W_RARE, /obj/item/storage/bag/money = W_RARE, @@ -581,6 +584,7 @@ GLOBAL_LIST_INIT(maintenance_loot_makeshift,list( /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/golem/adamantine = W_MYTHICAL, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/gorilla = W_MYTHICAL, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard = W_MYTHICAL, + /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/vox = W_MYTHICAL, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/moth = W_MYTHICAL, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/plant = W_MYTHICAL, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/shadow = W_MYTHICAL, diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm index 5f3f0c4c1f0f9..e668b1bcf95ee 100644 --- a/code/controllers/subsystem/traumas.dm +++ b/code/controllers/subsystem/traumas.dm @@ -139,7 +139,10 @@ SUBSYSTEM_DEF(traumas) /obj/item/clothing/suit/chickensuit, /obj/item/clothing/head/chicken, /obj/item/clothing/suit/toggle/owlwings, /obj/item/clothing/under/costume/owl, /obj/item/clothing/mask/gas/owl_mask, /obj/item/clothing/under/costume/griffin, /obj/item/clothing/shoes/griffin, /obj/item/clothing/head/griffin, - /obj/item/clothing/head/helmet/space/freedom, /obj/item/clothing/suit/space/freedom)), + /obj/item/clothing/head/helmet/space/freedom, /obj/item/clothing/suit/space/freedom, /obj/item/toy/plush/voxplushie, + /obj/item/clothing/mask/breath/vox, /obj/item/clothing/suit/space/vox, /obj/item/clothing/head/helmet/space/vox, + /obj/item/clothing/shoes/magboots/vox, /obj/item/clothing/gloves/color/yellow/vox, /obj/item/flag/species/vox, /obj/item/stack/sheet/animalhide/vox, + /obj/item/organ/tail/vox)), "anime" = typecacheof(list(/obj/item/clothing/under/costume/schoolgirl, /obj/item/katana, /obj/item/reagent_containers/food/snacks/sashimi, /obj/item/reagent_containers/food/snacks/chawanmushi, /obj/item/reagent_containers/food/drinks/bottle/sake, /obj/item/throwing_star, /obj/item/clothing/head/kitty/genuine, /obj/item/clothing/suit/space/space_ninja, @@ -162,7 +165,8 @@ SUBSYSTEM_DEF(traumas) "the supernatural" = typecacheof(list(/datum/species/golem/clockwork, /datum/species/golem/runic)), "aliens" = typecacheof(list(/datum/species/abductor, /datum/species/jelly, /datum/species/pod, /datum/species/shadow, /datum/species/polysmorph)), - "anime" = typecacheof(list(/datum/species/human/felinid)) + "anime" = typecacheof(list(/datum/species/human/felinid)), + "birds" = typecacheof(list(/datum/species/vox)) ) return SS_INIT_SUCCESS diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm index 77a842eed651a..261266e8cc48b 100644 --- a/code/datums/components/bloodysoles.dm +++ b/code/datums/components/bloodysoles.dm @@ -215,7 +215,7 @@ Like its parent but can be applied to carbon mobs instead of clothing items */ /datum/component/bloodysoles/feet - var/static/mutable_appearance/bloody_feet + var/mutable_appearance/bloody_feet /datum/component/bloodysoles/feet/Initialize() if(!iscarbon(parent)) @@ -236,6 +236,11 @@ Like its parent but can be applied to carbon mobs instead of clothing items /datum/component/bloodysoles/feet/update_icon() . = list() if(ishuman(wielder))// Monkeys get no bloody feet :( + var/obj/item/bodypart/l_leg/left_leg = wielder.get_bodypart(BODY_ZONE_L_LEG) + var/obj/item/bodypart/r_leg/right_leg = wielder.get_bodypart(BODY_ZONE_R_LEG) + if(left_leg?.species_id == right_leg?.species_id) + if(icon_exists(bloody_feet.icon, "shoeblood_[left_leg.species_id]")) + bloody_feet.icon_state = "shoeblood_[left_leg.species_id]" if(HAS_BLOOD_DNA(wielder)) bloody_feet.color = get_blood_dna_color(wielder.return_blood_DNA()) . += bloody_feet diff --git a/code/datums/diseases/advance/symptoms/shedding.dm b/code/datums/diseases/advance/symptoms/shedding.dm index 5b667d4a6d540..588181d5b52a3 100644 --- a/code/datums/diseases/advance/symptoms/shedding.dm +++ b/code/datums/diseases/advance/symptoms/shedding.dm @@ -44,14 +44,13 @@ BONUS to_chat(H, span_warning("Your hair starts to fall out in clumps...")) addtimer(CALLBACK(src, PROC_REF(Shed), H, FALSE), 50) if(5) - if(!(H.facial_hair_style == "Shaved") || !(H.hair_style == "Bald")) + if(!(H.facial_hair_style == "Shaved") || !(H.hair_style == "Bald") || !(H.hair_style == "None")) to_chat(H, span_warning("Your hair starts to fall out in clumps...")) addtimer(CALLBACK(src, PROC_REF(Shed), H, TRUE), 50) /datum/symptom/shedding/proc/Shed(mob/living/carbon/human/H, fullbald) if(fullbald) - H.facial_hair_style = "Shaved" - H.hair_style = "Bald" + H.dna.species.go_bald() else H.hair_style = "Balding Hair" H.update_hair() diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 64884ff14bf3b..5759cb356131a 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -191,6 +191,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(features["mcolor"]) L[DNA_MUTANT_COLOR_BLOCK] = sanitize_hexcolor(features["mcolor"], include_crunch = FALSE) + if(features["mcolor_secondary"]) + L[DNA_MUTANT_COLOR_SECONDARY] = sanitize_hexcolor(features["mcolor_secondary"], include_crunch = FALSE) if(features["body_markings"]) L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len) if(features["tail_lizard"]) @@ -231,6 +233,16 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_POD_HAIR_BLOCK] = construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len) if(features["pod_flower"]) L[DNA_POD_FLOWER_BLOCK] = construct_block(GLOB.pod_flower_list.Find(features["pod_flower"]), GLOB.pod_flower_list.len) + if(features["vox_quills"]) + L[DNA_VOX_QUILLS_BLOCK] = construct_block(GLOB.vox_quills_list.Find(features["vox_quills"]), GLOB.vox_quills_list.len) + if(features["vox_facial_quills"]) + L[DNA_VOX_FACIAL_QUILLS_BLOCK] = construct_block(GLOB.vox_facial_quills_list.Find(features["vox_facial_quills"]), GLOB.vox_facial_quills_list.len) + if(features["vox_tail_markings"]) + L[DNA_VOX_TAIL_MARKINGS_BLOCK] = construct_block(GLOB.vox_tail_markings_list.Find(features["vox_tail_markings"]), GLOB.vox_tail_markings_list.len) + if(features["vox_body_markings"]) + L[DNA_VOX_BODY_MARKINGS_BLOCK] = construct_block(GLOB.vox_body_markings_list.Find(features["vox_body_markings"]), GLOB.vox_body_markings_list.len) + if(features["vox_skin_tone"]) + L[DNA_VOX_SKIN_TONE_BLOCK] = construct_block(GLOB.vox_skin_tones.Find(features["vox_skin_tone"]), GLOB.vox_skin_tones.len) for(var/blocknum in 1 to DNA_FEATURE_BLOCKS) . += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters) @@ -348,6 +360,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) switch(blocknumber) if(DNA_MUTANT_COLOR_BLOCK) set_uni_feature_block(blocknumber, sanitize_hexcolor(features["mcolor"], include_crunch = FALSE)) + if(DNA_MUTANT_COLOR_SECONDARY) + set_uni_feature_block(blocknumber, sanitize_hexcolor(features["mcolor_secondary"], include_crunch = FALSE)) if(DNA_LIZARD_MARKINGS_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len)) if(DNA_LIZARD_TAIL_BLOCK) @@ -388,6 +402,16 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) set_uni_feature_block(blocknumber, construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len)) if(DNA_POD_FLOWER_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.pod_flower_list.Find(features["pod_flower"]), GLOB.pod_flower_list.len)) + if(DNA_VOX_QUILLS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.vox_quills_list.Find(features["vox_quills"]), GLOB.vox_quills_list.len)) + if(DNA_VOX_FACIAL_QUILLS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.vox_facial_quills_list.Find(features["vox_facial_quills"]), GLOB.vox_facial_quills_list.len)) + if(DNA_VOX_TAIL_MARKINGS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.vox_tail_markings_list.Find(features["vox_tail_markings"]), GLOB.vox_tail_markings_list.len)) + if(DNA_VOX_BODY_MARKINGS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.vox_body_markings_list.Find(features["vox_body_markings"]), GLOB.vox_body_markings_list.len)) + if(DNA_VOX_SKIN_TONE_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.vox_skin_tones.Find(features["vox_skin_tone"]), GLOB.vox_skin_tones.len)) //Please use add_mutation or activate_mutation instead /datum/dna/proc/force_give(datum/mutation/human/HM) @@ -596,12 +620,18 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) eye_color = sanitize_hexcolor(get_uni_identity_block(structure, DNA_EYE_COLOR_BLOCK)) facial_hair_style = GLOB.facial_hair_styles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIR_STYLE_BLOCK), GLOB.facial_hair_styles_list.len)] if(HAS_TRAIT(src, TRAIT_BALD)) - hair_style = "Bald" + if(isvox(src)) + dna.features["vox_quills"] = "None" + dna.update_uf_block(DNA_VOX_QUILLS_BLOCK) + else + hair_style = "Bald" else hair_style = GLOB.hair_styles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIR_STYLE_BLOCK), GLOB.hair_styles_list.len)] var/features = dna.unique_features if(dna.features["mcolor"]) dna.features["mcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_MUTANT_COLOR_BLOCK)) + if(dna.features["mcolor_secondary"]) + dna.features["mcolor_secondary"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_MUTANT_COLOR_SECONDARY)) if(dna.features["body_markings"]) dna.features["body_markings"] = GLOB.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), GLOB.body_markings_list.len)] if(dna.features["tail_lizard"]) @@ -645,6 +675,16 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.features["pod_hair"] = GLOB.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), GLOB.pod_hair_list.len)] if(dna.features["pod_flower"]) dna.features["pod_flower"] = GLOB.pod_flower_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_FLOWER_BLOCK), GLOB.pod_flower_list.len)] + if(dna.features["vox_quills"]) + dna.features["vox_quills"] = GLOB.vox_quills_list[deconstruct_block(get_uni_feature_block(features, DNA_VOX_QUILLS_BLOCK), GLOB.vox_quills_list.len)] + if(dna.features["vox_facial_quills"]) + dna.features["vox_facial_quills"] = GLOB.vox_facial_quills_list[deconstruct_block(get_uni_feature_block(features, DNA_VOX_FACIAL_QUILLS_BLOCK), GLOB.vox_facial_quills_list.len)] + if(dna.features["vox_tail_markings"]) + dna.features["vox_tail_markings"] = GLOB.vox_tail_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_VOX_TAIL_MARKINGS_BLOCK), GLOB.vox_tail_markings_list.len)] + if(dna.features["vox_body_markings"]) + dna.features["vox_body_markings"] = GLOB.vox_body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_VOX_BODY_MARKINGS_BLOCK), GLOB.vox_body_markings_list.len)] + if(dna.features["vox_skin_tone"]) + dna.features["vox_skin_tone"] = GLOB.vox_skin_tones[deconstruct_block(get_uni_feature_block(features, DNA_VOX_SKIN_TONE_BLOCK), GLOB.vox_skin_tones.len)] if(icon_update) dna.species.handle_body(src) // We want 'update_body_parts()' to be called only if mutcolor_update is TRUE, so no 'update_body()' here. diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 5ff180ddfe0f6..2ea07ea48d0e8 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -146,6 +146,8 @@ . = message_monkey else if(isipc(user) && message_ipc) . = message_ipc + else if(isvox(user) && message_vox) + . = message_vox else if(isanimal(user) && message_simple) . = message_simple diff --git a/code/datums/greyscale/json_configs/jumpsuit_prison_worn.json b/code/datums/greyscale/json_configs/jumpsuit_prison_worn.json index 0096c95e812a0..abe6be92981d7 100644 --- a/code/datums/greyscale/json_configs/jumpsuit_prison_worn.json +++ b/code/datums/greyscale/json_configs/jumpsuit_prison_worn.json @@ -12,6 +12,19 @@ "blend_mode": "overlay" } ], + "jumpsuit_vox": [ + { + "type": "icon_state", + "icon_state": "jumpsuit_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "jumpsuit_prison_vox", + "blend_mode": "overlay" + } + ], "jumpsuit_d" : [ { "type": "icon_state", @@ -25,6 +38,19 @@ "blend_mode": "overlay" } ], + "jumpsuit_d_vox": [ + { + "type": "icon_state", + "icon_state": "jumpsuit_d_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "jumpsuit_d_prison_vox", + "blend_mode": "overlay" + } + ], "jumpskirt": [ { "type": "icon_state", @@ -38,6 +64,19 @@ "blend_mode": "overlay" } ], + "jumpskirt_vox": [ + { + "type": "icon_state", + "icon_state": "jumpskirt_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "jumpskirt_prison_vox", + "blend_mode": "overlay" + } + ], "jumpskirt_d" : [ { "type": "icon_state", @@ -50,5 +89,18 @@ "icon_state": "jumpskirt_d_prison", "blend_mode": "overlay" } + ], + "jumpskirt_d_vox" : [ + { + "type": "icon_state", + "icon_state": "jumpskirt_d_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "jumpskirt_d_prison_vox", + "blend_mode": "overlay" + } ] } diff --git a/code/datums/greyscale/json_configs/jumpsuit_worn.json b/code/datums/greyscale/json_configs/jumpsuit_worn.json index 99bc3fc19874d..04eb78e8dac14 100644 --- a/code/datums/greyscale/json_configs/jumpsuit_worn.json +++ b/code/datums/greyscale/json_configs/jumpsuit_worn.json @@ -12,6 +12,19 @@ "blend_mode": "overlay" } ], + "jumpsuit_vox": [ + { + "type": "icon_state", + "icon_state": "jumpsuit_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "jumpsuit_accessories_vox", + "blend_mode": "overlay" + } + ], "jumpsuit_d" : [ { "type": "icon_state", @@ -20,6 +33,14 @@ "color_ids": [ 1 ] } ], + "jumpsuit_d_vox": [ + { + "type": "icon_state", + "icon_state": "jumpsuit_d_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], "jumpsuit_l": [ { "type": "icon_state", @@ -54,6 +75,19 @@ "blend_mode": "overlay" } ], + "jumpskirt_vox": [ + { + "type": "icon_state", + "icon_state": "jumpskirt_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "jumpskirt_accessories_vox", + "blend_mode": "overlay" + } + ], "jumpskirt_d" : [ { "type": "icon_state", @@ -61,5 +95,13 @@ "blend_mode": "overlay", "color_ids": [ 1 ] } + ], + "jumpskirt_d_vox" : [ + { + "type": "icon_state", + "icon_state": "jumpskirt_d_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } ] } diff --git a/code/datums/greyscale/json_configs/sneakers_orange_worn.json b/code/datums/greyscale/json_configs/sneakers_orange_worn.json index fb0a07ff1969f..d28b36812f6ef 100644 --- a/code/datums/greyscale/json_configs/sneakers_orange_worn.json +++ b/code/datums/greyscale/json_configs/sneakers_orange_worn.json @@ -13,6 +13,20 @@ "color_ids": [ 2 ] } ], + "sneakers_vox": [ + { + "type": "icon_state", + "icon_state": "sneakers_back_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "sneakers_front_vox", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } + ], "sneakers_chained": [ { "type": "icon_state", @@ -31,5 +45,24 @@ "icon_state": "sneakers_chained", "blend_mode": "overlay" } + ], + "sneakers_chained_vox": [ + { + "type": "icon_state", + "icon_state": "sneakers_back_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "sneakers_front_vox", + "blend_mode": "overlay", + "color_ids": [ 2 ] + }, + { + "type": "icon_state", + "icon_state": "sneakers_chained_vox", + "blend_mode": "overlay" + } ] } diff --git a/code/datums/greyscale/json_configs/sneakers_worn.json b/code/datums/greyscale/json_configs/sneakers_worn.json index 50a064bb02b66..4d808820ec05d 100644 --- a/code/datums/greyscale/json_configs/sneakers_worn.json +++ b/code/datums/greyscale/json_configs/sneakers_worn.json @@ -12,5 +12,19 @@ "blend_mode": "overlay", "color_ids": [ 2 ] } + ], + "sneakers_vox": [ + { + "type": "icon_state", + "icon_state": "sneakers_back_vox", + "blend_mode": "overlay", + "color_ids": [ 1 ] + }, + { + "type": "icon_state", + "icon_state": "sneakers_front_vox", + "blend_mode": "overlay", + "color_ids": [ 2 ] + } ] } diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm index 6f1bc7dcac91f..ce82580ff2a6d 100644 --- a/code/datums/traits/good.dm +++ b/code/datums/traits/good.dm @@ -356,10 +356,12 @@ /datum/quirk/telomeres_long/check_quirk(datum/preferences/prefs) var/datum/species/species_type = prefs.read_preference(/datum/preference/choiced/species) - var/disallowed_trait = (NO_DNA_COPY in initial(species_type.species_traits)) //Can't pick if you have no DNA bruv. - - if(disallowed_trait) + var/no_dna = (NO_DNA_COPY in initial(species_type.species_traits)) //Can't pick if you have no DNA bruv. + var/no_clone = (TRAIT_NOCLONE in initial(species_type.inherent_traits)) + if(no_dna) return "You have no DNA!" + else if(no_clone) + return "Your species cannot be cloned!" return FALSE /datum/quirk/marine diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index 5c9498f595fdc..2e025359558e3 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -828,10 +828,12 @@ /datum/quirk/telomeres_short/check_quirk(datum/preferences/prefs) var/datum/species/species_type = prefs.read_preference(/datum/preference/choiced/species) - var/disallowed_trait = (NO_DNA_COPY in initial(species_type.species_traits)) //Can't pick if you have no DNA bruv. - - if(disallowed_trait) + var/no_dna = (NO_DNA_COPY in initial(species_type.species_traits)) //Can't pick if you have no DNA bruv. + var/no_clone = (TRAIT_NOCLONE in initial(species_type.inherent_traits)) + if(no_dna) return "You have no DNA!" + else if(no_clone) + return "Your species cannot be cloned!" return FALSE /datum/quirk/body_purist diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm index bcfea380f6014..8cbb39d5c893b 100644 --- a/code/datums/traits/neutral.dm +++ b/code/datums/traits/neutral.dm @@ -174,7 +174,7 @@ /datum/quirk/colorist/check_quirk(datum/preferences/prefs) var/datum/species/species_type = prefs.read_preference(/datum/preference/choiced/species) - var/disallowed_trait = (HAIR in initial(species_type.species_traits)) // No Hair + var/disallowed_trait = (HAIR in initial(species_type.species_traits)) || ("vox_quills" in initial(species_type.mutant_bodyparts)) // No Hair if(!disallowed_trait) return "You don't have hair!" diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index bdfdd5ff63a93..ba228387fefb7 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -219,6 +219,7 @@ GLOBAL_VAR(changeling_team_objective_type) new_flesh_item.item_state = chosen_prof.inhand_icon_state_list[slot] new_flesh_item.worn_icon = chosen_prof.worn_icon_list[slot] new_flesh_item.worn_icon_state = chosen_prof.worn_icon_state_list[slot] + new_flesh_item.sprite_sheets = chosen_prof.sprite_sheets_list[slot] if(equip) user.equip_to_slot_or_del(new_flesh_item, GLOB.slot2slot[slot]) diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 6086a909e646e..321b34a75505c 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -53,7 +53,8 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( /obj/item/storage/box/heretic_box = 1, /obj/item/toy/plush/mothplushie = 2, /obj/item/toy/plush/abductor = 2, - /obj/item/toy/plush/abductor/agent = 1)) + /obj/item/toy/plush/abductor/agent = 1, + /obj/item/toy/plush/voxplushie = 2)) /obj/machinery/computer/arcade name = "random arcade" diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 7fac837c3ec37..c49b87da94c4e 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -24,7 +24,7 @@ /// Our internal techweb for limbgrower designs. var/datum/techweb/stored_research /// All the categories of organs we can print. - var/list/categories = list("human", "lizard", "moth", "plasmaman", "ethereal", "polysmorph", "other") + var/list/categories = list("human", "lizard", "moth", "plasmaman", "ethereal", "polysmorph", "vox", "other") //yogs grower a little different because we're going to allow meats to be converted to synthflesh because hugbox var/list/accepted_biomass = list( /obj/item/reagent_containers/food/snacks/meat/slab/monkey = 25, diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index 39962577f6f6d..4dc99243424b4 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -84,12 +84,15 @@ ///obj/item/organ/tongue/ethereal, /obj/item/organ/tongue/robot, /obj/item/organ/tongue/zombie, + /obj/item/organ/tongue/vox, /obj/item/organ/appendix, /obj/item/organ/liver/fly, /obj/item/organ/lungs/plasmaman, /obj/item/organ/lungs/ethereal, + /obj/item/organ/lungs/vox, /obj/item/organ/tail/cat, /obj/item/organ/tail/lizard, + /obj/item/organ/tail/vox ) /obj/effect/spawner/lootdrop/plushies @@ -115,7 +118,8 @@ /obj/item/toy/plush/inorixplushie, /obj/item/toy/plush/flowerbunch, /obj/item/toy/plush/goatplushie, - /obj/item/toy/plush/realgoat + /obj/item/toy/plush/realgoat, + /obj/item/toy/plush/voxplushie ) /obj/effect/spawner/lootdrop/techshell diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index 60e4073b12dca..120a3366f1701 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -118,10 +118,18 @@ return BRUTELOSS /obj/item/razor/proc/shave(mob/living/carbon/human/H, location = BODY_ZONE_PRECISE_MOUTH) - if(location == BODY_ZONE_PRECISE_MOUTH) - H.facial_hair_style = "Shaved" + if(isvox(H))//both hair and bodyparts need refactors to do this cleanly + if(location == BODY_ZONE_PRECISE_MOUTH) + H.dna.features["vox_facial_quills"] = "None" + H.dna.update_uf_block(DNA_VOX_FACIAL_QUILLS_BLOCK) + else + H.dna.features["vox_quills"] = "None" + H.dna.update_uf_block(DNA_VOX_QUILLS_BLOCK) else - H.hair_style = "Skinhead" + if(location == BODY_ZONE_PRECISE_MOUTH) + H.facial_hair_style = "Shaved" + else + H.hair_style = "Skinhead" H.update_hair() playsound(loc, 'sound/items/welder2.ogg', 20, 1) @@ -134,85 +142,117 @@ if((location in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_HEAD)) && !H.get_bodypart(BODY_ZONE_HEAD)) to_chat(user, span_warning("[H] doesn't have a head!")) return + var/hair_name = "hair" + if(isvox(H)) + hair_name = "quills" if(location == BODY_ZONE_PRECISE_MOUTH) if(!user.combat_mode) if(H.gender == MALE) if (H == user) - to_chat(user, span_warning("You need a mirror to properly style your own facial hair!")) + to_chat(user, span_warning("You need a mirror to properly style your own facial [hair_name]!")) return if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return - var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in GLOB.facial_hair_styles_list + var/list/hair_list = GLOB.facial_hair_styles_list + if(isvox(H)) + hair_list = GLOB.vox_facial_quills_list + var/new_style = input(user, "Select a facial [hair_name] style", "Grooming") as null|anything in hair_list if(!get_location_accessible(H, location)) to_chat(user, span_warning("The mask is in the way!")) return - user.visible_message(span_notice("[user] tries to change [H]'s facial hair style using [src]."), span_notice("You try to change [H]'s facial hair style using [src].")) + user.visible_message(span_notice("[user] tries to change [H]'s facial [hair_name] style using [src]."), span_notice("You try to change [H]'s facial [hair_name] style using [src].")) if(new_style && do_after(user, 6 SECONDS, H)) - user.visible_message(span_notice("[user] successfully changes [H]'s facial hair style using [src]."), span_notice("You successfully change [H]'s facial hair style using [src].")) - H.facial_hair_style = new_style + user.visible_message(span_notice("[user] successfully changes [H]'s facial [hair_name] style using [src]."), span_notice("You successfully change [H]'s facial [hair_name] style using [src].")) + if(isvox(H)) + H.dna.features["vox_facial_quills"] = new_style + H.dna.update_uf_block(DNA_VOX_FACIAL_QUILLS_BLOCK) + else + H.facial_hair_style = new_style H.update_hair() return else return else - if(!(FACEHAIR in H.dna.species.species_traits)) - to_chat(user, span_warning("There is no facial hair to shave!")) - return if(!get_location_accessible(H, location)) to_chat(user, span_warning("The mask is in the way!")) return - if(H.facial_hair_style == "Shaved") - to_chat(user, span_warning("Already clean-shaven!")) - return - + if(!isvox(H)) + if(!(FACEHAIR in H.dna.species.species_traits)) + to_chat(user, span_warning("There is no facial hair to shave!")) + return + if(H.facial_hair_style == "Shaved") + to_chat(user, span_warning("Already clean-shaven!")) + return + else + if(!("vox_facial_quills" in H.dna.species.mutant_bodyparts)) + to_chat(user, span_warning("There are no facial quills to shave!")) + return + if(H.dna.species.mutant_bodyparts["vox_facial_quills"] == "None") + to_chat(user, span_warning("Already clean-shaven!")) + return if(H == user) //shaving yourself - user.visible_message("[user] starts to shave [user.p_their()] facial hair with [src].", \ - span_notice("You take a moment to shave your facial hair with [src]...")) + user.visible_message("[user] starts to shave [user.p_their()] facial [hair_name] with [src].", \ + span_notice("You take a moment to shave your facial [hair_name] with [src]...")) if(do_after(user, 5 SECONDS, H)) - user.visible_message("[user] shaves [user.p_their()] facial hair clean with [src].", \ + user.visible_message("[user] shaves [user.p_their()] facial [hair_name] clean with [src].", \ span_notice("You finish shaving with [src]. Fast and clean!")) shave(H, location) else - user.visible_message(span_warning("[user] tries to shave [H]'s facial hair with [src]."), \ - span_notice("You start shaving [H]'s facial hair...")) + user.visible_message(span_warning("[user] tries to shave [H]'s facial [hair_name] with [src]."), \ + span_notice("You start shaving [H]'s facial [hair_name]...")) if(do_after(user, 5 SECONDS, target = H)) - user.visible_message(span_warning("[user] shaves off [H]'s facial hair with [src]."), \ - span_notice("You shave [H]'s facial hair clean off.")) + user.visible_message(span_warning("[user] shaves off [H]'s facial [hair_name] with [src]."), \ + span_notice("You shave [H]'s facial [hair_name] clean off.")) shave(H, location) else if(location == BODY_ZONE_HEAD) if(!user.combat_mode) if (H == user) - to_chat(user, span_warning("You need a mirror to properly style your own hair!")) + to_chat(user, span_warning("You need a mirror to properly style your own [hair_name]!")) return if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return - var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in GLOB.hair_styles_list + var/hair_list = GLOB.hair_styles_list + if(isvox(H)) + hair_list = GLOB.vox_quills_list + var/new_style = input(user, "Select a [hair_name] style", "Grooming") as null|anything in hair_list if(!get_location_accessible(H, location)) to_chat(user, span_warning("The headgear is in the way!")) return if(HAS_TRAIT(H, TRAIT_BALD)) to_chat(user, span_warning("[H] is just way too bald. Like, really really bald.")) return - user.visible_message(span_notice("[user] tries to change [H]'s hairstyle using [src]."), span_notice("You try to change [H]'s hairstyle using [src].")) + user.visible_message(span_notice("[user] tries to change [H]'s [hair_name]style using [src]."), span_notice("You try to change [H]'s [hair_name]style using [src].")) if(new_style && do_after(user, 6 SECONDS, H)) - user.visible_message(span_notice("[user] successfully changes [H]'s hairstyle using [src]."), span_notice("You successfully change [H]'s hairstyle using [src].")) - H.hair_style = new_style + user.visible_message(span_notice("[user] successfully changes [H]'s [hair_name]style using [src]."), span_notice("You successfully change [H]'s [hair_name]style using [src].")) + if(isvox(H)) + H.dna.features["vox_quills"] = new_style + H.dna.update_uf_block(DNA_VOX_QUILLS_BLOCK) + else + H.hair_style = new_style H.update_hair() return else - if(!(HAIR in H.dna.species.species_traits)) - to_chat(user, span_warning("There is no hair to shave!")) - return if(!get_location_accessible(H, location)) to_chat(user, span_warning("The headgear is in the way!")) return - if(H.hair_style == "Bald" || H.hair_style == "Balding Hair" || H.hair_style == "Skinhead") - to_chat(user, span_warning("There is not enough hair left to shave!")) - return - + if(!isvox(H)) + if(!(HAIR in H.dna.species.species_traits)) + to_chat(user, span_warning("There is no hair to shave!")) + return + + if(H.hair_style == "Bald" || H.hair_style == "Balding Hair" || H.hair_style == "Skinhead") + to_chat(user, span_warning("There is not enough hair left to shave!")) + return + else + if(!("vox_quills" in H.dna.species.mutant_bodyparts)) + to_chat(user, span_warning("There are no quills to shave!")) + return + if(H.dna.species.mutant_bodyparts["vox_quills"] == "None") + to_chat(user, span_warning("There are not enough quills left to shave!")) + return if(H == user) //shaving yourself user.visible_message("[user] starts to shave [user.p_their()] head with [src].", \ span_notice("You start to shave your head with [src]...")) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index ea46fd2a4d7c7..2785da73c02da 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -35,7 +35,7 @@ var/drawtype var/text_buffer = "" - var/static/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","star","poseur tag","prolizard","antilizard") + var/static/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","star","poseur tag","prolizard","antilizard","voxpox") var/static/list/symbols = list("danger","firedanger","electricdanger","biohazard","radiation","safe","evac","space","med","trade","shop","food","peace","like","skull","nay","heart","credit") var/static/list/drawings = list("smallbrush","brush","largebrush","splatter","snake","stickman","carp","ghost","clown","taser","disk","fireaxe","toolbox","corgi","cat","toilet","blueprint","beepsky","scroll","bottle","shotgun") var/static/list/oriented = list("arrow","line","thinline","shortline","body","chevron","footprint","clawprint","pawprint") // These turn to face the same way as the drawer diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index ce024afeadc7a..c61caed09844f 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -264,6 +264,7 @@ languages = list( /datum/language/bonespeak, /datum/language/draconic, + /datum/language/vox, /datum/language/english, /datum/language/etherean, /datum/language/felinid, @@ -280,6 +281,7 @@ languages = list( /datum/language/bonespeak, /datum/language/draconic, + /datum/language/vox, /datum/language/english, /datum/language/etherean, /datum/language/felinid, diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 2458430625dad..364f4a9640bff 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -146,13 +146,16 @@ new /obj/item/radio/off(src) /obj/item/storage/box/survival/proc/wardrobe_removal() - if(!isplasmaman(loc)) //We need to specially fill the box with plasmaman gear, since it's intended for one + if(!ishuman(loc)) return - var/obj/item/mask = locate(/obj/item/clothing/mask/breath) in src - var/obj/item/internals = locate(/obj/item/tank/internals/emergency_oxygen) in src - new /obj/item/tank/internals/plasmaman/belt(src) - qdel(mask) // Get rid of the items that shouldn't be - qdel(internals) + var/mob/living/carbon/human/box_owner = loc + if(!length(box_owner.dna?.species?.survival_box_replacements)) + return + var/list/survival_box_replacements_delete = box_owner.dna.species.survival_box_replacements["items_to_delete"] + var/list/survival_box_replacements_add = box_owner.dna.species.survival_box_replacements["new_items"] + var/list/items_to_delete = survival_box_replacements_delete?.Copy() || list() + var/list/new_items = survival_box_replacements_add?.Copy() || list() + box_owner.dna.species.survival_box_replacement(box_owner, src, items_to_delete, new_items) /obj/item/storage/box/survival/mining mask_type = /obj/item/clothing/mask/gas/explorer diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index e16f595fed15a..fe85b6ecc311c 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -134,7 +134,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e if(!(resistance_flags & ON_FIRE) && (resistance_flags & FLAMMABLE) && !(resistance_flags & FIRE_PROOF)) resistance_flags |= ON_FIRE SSfire_burning.processing[src] = src - add_overlay(GLOB.fire_overlay, TRUE) + add_overlay(custom_fire_overlay ? custom_fire_overlay : GLOB.fire_overlay) return 1 ///called when the obj is destroyed by fire diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 1043e7bafec1e..f3707d937dd7d 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -156,6 +156,7 @@ new /obj/item/reagent_containers/blood/OMinus(src) new /obj/item/reagent_containers/blood/OPlus(src) new /obj/item/reagent_containers/blood/lizard(src) + new /obj/item/reagent_containers/blood/vox(src) new /obj/item/reagent_containers/blood/gorilla(src) // yogs -- gorilla people new /obj/item/reagent_containers/blood/ethereal(src) for(var/i in 1 to 3) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index c056418554c9e..8c032d362b999 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -28,11 +28,16 @@ /obj/structure/mirror/proc/get_choices(mob/living/carbon/human/H) . = list() var/datum/species/S = H.dna.species - if((FACEHAIR in S.species_traits)) - . += list(FACIAL_HAIR = list("select a facial hair style", GLOB.facial_hair_styles_list)) + var/list/facial_hair_list = GLOB.facial_hair_styles_list + var/list/hair_list = GLOB.hair_styles_list + if(isvox(H)) + facial_hair_list = GLOB.vox_facial_quills_list + hair_list = GLOB.vox_quills_list + if((FACEHAIR in S.species_traits) || (FACEHAIRCOLOR in S.species_traits)) + . += list(FACIAL_HAIR = list("select a facial hair style", facial_hair_list)) . += list(FACE_HAIR_COLOR) - if((HAIR in S.species_traits)) - . += list(HEAD_HAIR = list("select a hair style", GLOB.hair_styles_list)) + if((HAIR in S.species_traits) || (HAIRCOLOR in S.species_traits)) + . += list(HEAD_HAIR = list("select a hair style", hair_list)) . += list(HAIR_COLOR) // for things that dont use a list style syntax @@ -60,14 +65,22 @@ return switch(selectiontype) if(FACIAL_HAIR) - H.facial_hair_style = selection + if(isvox(H)) + H.dna.features["vox_facial_quills"] = selection + H.dna.update_uf_block(DNA_VOX_FACIAL_QUILLS_BLOCK) + else + H.facial_hair_style = selection H.update_hair() return TRUE if(HEAD_HAIR) - if(HAS_TRAIT(H, TRAIT_BALD) && selection != "Bald") + if(HAS_TRAIT(H, TRAIT_BALD) && !((selection == "Bald") || (selection == ("None")))) to_chat(H, span_notice("If only growing back hair were that easy for you...")) return TRUE - H.hair_style = selection + if(isvox(H)) + H.dna.features["vox_quills"] = selection + H.dna.update_uf_block(DNA_VOX_QUILLS_BLOCK) + else + H.hair_style = selection H.update_hair() return TRUE @@ -190,6 +203,8 @@ . += list(SKIN_COLOR = list("select a new skintone", GLOB.skin_tones)) if((MUTCOLORS in S.species_traits) && !(NOCOLORCHANGE in S.species_traits)) . += list(MUTANT_COLOR) + if((MUTCOLORS_SECONDARY in S.species_traits)) + . += list("Secondary mutant color") . += list(NAME) /obj/structure/mirror/magic/preapply_choices(selectiontype, mob/living/carbon/human/H) @@ -228,6 +243,16 @@ H.update_hair() H.update_body_parts() H.update_mutations_overlay() // no hulk lizard + if("Secondary mutant color") + var/new_mutantcolor = input(H, "Choose your secondary mutant color:", "Race change",H.dna.features["mcolor_secondary"]) as color|null + if(!new_mutantcolor) + return TRUE + H.dna.features["mcolor_secondary"] = sanitize_hexcolor(new_mutantcolor) + H.dna.update_uf_block(DNA_MUTANT_COLOR_SECONDARY) + H.update_body() + H.update_hair() + H.update_body_parts() + H.update_mutations_overlay() return TRUE diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 49c1f9927fdf1..700d5182b9dc3 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -25,6 +25,7 @@ // Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant. human.dna.features["mcolor"] = "#[random_color()]" + human.dna.features["mcolor_secondary"] = "#[random_color()]" human.dna.features["pretcolor"] = GLOB.color_list_preternis[pick(GLOB.color_list_preternis)] human.dna.features["tail_lizard"] = pick(GLOB.tails_list_lizard) human.dna.features["tail_polysmorph"] = pick(GLOB.tails_list_polysmorph) @@ -44,6 +45,11 @@ human.dna.features["preternis_core"] = pick(GLOB.preternis_core_list) human.dna.features["pod_hair"] = pick(GLOB.pod_hair_list) human.dna.features["pod_flower"] = GLOB.pod_flower_list[human.dna.features["pod_hair"]] + human.dna.features["vox_skin_tone"] = pick(GLOB.vox_skin_tones) + human.dna.features["vox_quills"] = pick(GLOB.vox_quills_list) + human.dna.features["vox_facial_quills"] = pick(GLOB.vox_facial_quills_list) + human.dna.features["vox_body_markings"] = pick(GLOB.vox_body_markings_list) + human.dna.features["vox_tail_markings"] = pick(GLOB.vox_tail_markings_list) human.update_body() human.update_hair() diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index eb305df0c8ddf..6834a5b0ab36d 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -345,6 +345,7 @@ prof.righthand_file_list[slot] = I.righthand_file prof.worn_icon_list[slot] = I.worn_icon prof.worn_icon_state_list[slot] = I.worn_icon_state + prof.sprite_sheets_list[slot] = I.sprite_sheets prof.exists_list[slot] = 1 else continue @@ -676,6 +677,7 @@ new_profile.socks = socks new_profile.worn_icon_list = worn_icon_list.Copy() new_profile.worn_icon_state_list = worn_icon_state_list.Copy() + new_profile.sprite_sheets_list = sprite_sheets_list.Copy() new_profile.stored_scars = stored_scars.Copy() /datum/antagonist/changeling/xenobio diff --git a/code/modules/antagonists/highlander/highlander.dm b/code/modules/antagonists/highlander/highlander.dm index 09fe1626b5a95..b31ac8c0e8ce6 100644 --- a/code/modules/antagonists/highlander/highlander.dm +++ b/code/modules/antagonists/highlander/highlander.dm @@ -48,6 +48,10 @@ if(!isplasmaman(H)) //no killing plasmies H.equip_to_slot_or_del(new /obj/item/clothing/under/costume/kilt/highlander(H), ITEM_SLOT_ICLOTHING) H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), ITEM_SLOT_HEAD) + if(isvox(H)) + H.equip_to_slot_or_del(new /obj/item/tank/internals/emergency_oxygen/vox(H), ITEM_SLOT_BELT) + H.equip_to_slot_or_del(new /obj/item/clothing/mask/breath(H), ITEM_SLOT_MASK) + H.open_internals(H.get_item_by_slot(ITEM_SLOT_BELT)) else H.equip_to_slot_or_del(new /obj/item/clothing/under/plasmaman(H), ITEM_SLOT_ICLOTHING) H.equip_to_slot_or_del(new /obj/item/tank/internals/plasmaman/belt/full(H), ITEM_SLOT_BELT) diff --git a/code/modules/atmospherics/auxgm/gas_types.dm b/code/modules/atmospherics/auxgm/gas_types.dm index 0c559d9d8e3aa..616d26f9978ad 100644 --- a/code/modules/atmospherics/auxgm/gas_types.dm +++ b/code/modules/atmospherics/auxgm/gas_types.dm @@ -3,6 +3,16 @@ specific_heat = 20 name = "Oxygen" label = "O₂" + breath_alert_info = list( + not_enough_alert = list( + alert_category = "not_enough_oxy", + alert_type = /atom/movable/screen/alert/not_enough_oxy + ), + too_much_alert = list( + alert_category = "too_much_oxy", + alert_type = /atom/movable/screen/alert/too_much_oxy + ) + ) ui_color = "blue" /datum/gas/nitrogen @@ -47,6 +57,16 @@ gas_overlay = "plasma" moles_visible = MOLES_GAS_VISIBLE flags = GAS_FLAG_DANGEROUS + breath_alert_info = list( + not_enough_alert = list( + alert_category = "not_enough_tox", + alert_type = /atom/movable/screen/alert/not_enough_tox, + ), + too_much_alert = list( + alert_category = "too_much_tox", + alert_type = /atom/movable/screen/alert/too_much_tox, + ) + ) ui_color = "orange" /datum/gas/water_vapor diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 2c5d754fd67ba..be718754a097f 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -1428,7 +1428,7 @@ /datum/supply_pack/medical/bloodpacks name = "Blood Pack Variety Crate" - desc = "Contains eight different blood packs for reintroducing blood to patients." + desc = "Contains many different blood packs for reintroducing blood to patients." cost = 3500 contains = list(/obj/item/reagent_containers/blood, /obj/item/reagent_containers/blood, @@ -1439,6 +1439,7 @@ /obj/item/reagent_containers/blood/OPlus, /obj/item/reagent_containers/blood/OMinus, /obj/item/reagent_containers/blood/lizard, + /obj/item/reagent_containers/blood/vox, /obj/item/reagent_containers/blood/ethereal) crate_name = "blood freezer" crate_type = /obj/structure/closet/crate/freezer diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index f2ed776c0e41e..884667cb24b5e 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -317,12 +317,12 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) /datum/preference/proc/is_accessible(datum/preferences/preferences) SHOULD_CALL_PARENT(TRUE) SHOULD_NOT_SLEEP(TRUE) - - if (!isnull(relevant_mutant_bodypart) || !isnull(relevant_species_trait)) - var/species_type = preferences.read_preference(/datum/preference/choiced/species) - - var/datum/species/species = new species_type - if (!(savefile_key in species.get_features())) + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species = new species_type + if(species_type in blacklisted_species) + return FALSE + if(!isnull(relevant_mutant_bodypart) || !isnull(relevant_species_trait)) + if(!(savefile_key in species.get_features())) return FALSE if (!should_show_on_page(preferences.current_window)) diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm index 44e72c844861e..1b110178739ea 100644 --- a/code/modules/client/preferences/clothing.dm +++ b/code/modules/client/preferences/clothing.dm @@ -1,16 +1,22 @@ -/proc/generate_values_for_underwear(icon_file, list/accessory_list, list/icons) +/proc/generate_values_for_underwear(icon_file, list/accessory_list, list/icons, bodyparts_file = 'icons/mob/human_parts_greyscale.dmi') var/icon/lower_half = icon('icons/blanks/32x32.dmi', "nothing") for (var/icon in icons) - lower_half.Blend(icon('icons/mob/human_parts_greyscale.dmi', icon), ICON_OVERLAY) + lower_half.Blend(icon(bodyparts_file, icon), ICON_OVERLAY) var/list/values = list() - - for (var/accessory_name in accessory_list) + var/list/undergarment_list = accessory_list.Copy() + for(var/undergarment_accessory in undergarment_list) + if(undergarment_accessory == "Nude") + continue + var/datum/sprite_accessory/undergarment = undergarment_list[undergarment_accessory] + if(!icon_exists(icon_file, undergarment.icon_state)) + undergarment_list -= undergarment_accessory + for (var/accessory_name in undergarment_list) var/icon/icon_with_socks = new(lower_half) if (accessory_name != "Nude") - var/datum/sprite_accessory/accessory = accessory_list[accessory_name] + var/datum/sprite_accessory/accessory = undergarment_list[accessory_name] var/icon/accessory_icon = icon(icon_file, accessory.icon_state) icon_with_socks.Blend(accessory_icon, ICON_OVERLAY) diff --git a/code/modules/client/preferences/middleware/species.dm b/code/modules/client/preferences/middleware/species.dm index 05fffbb328119..ed33227c8b033 100644 --- a/code/modules/client/preferences/middleware/species.dm +++ b/code/modules/client/preferences/middleware/species.dm @@ -22,9 +22,10 @@ dummy.equipOutfit(/datum/outfit/job/assistant/consistent, visualsOnly = TRUE) dummy.dna.species.prepare_human_for_preview(dummy) var/icon/dummy_icon = getFlatIcon(dummy) - if(ismoth(dummy)) + var/list/lazy_icons_species = list("moth", SPECIES_VOX)//no idea why it fails to render properly the normal way + if(dummy.dna.species.id in lazy_icons_species) dummy_icon = null - dummy_icon = icon('icons/mob/human.dmi', "moth") + dummy_icon = icon('icons/mob/human.dmi', "[dummy.dna.species.id]") dummy_icon.Scale(64, 64) dummy_icon.Crop(15, 64, 15 + 31, 64 - 31) dummy_icon.Scale(64, 64) diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm index 1378543606a85..31e78911e304b 100644 --- a/code/modules/client/verbs/suicide.dm +++ b/code/modules/client/verbs/suicide.dm @@ -1,18 +1,18 @@ -#define SUICIDE_MESSAGE(p_their, p_theyre, p_them) pick( \ - "[src] is attempting to push [p_their] own head off [p_their] shoulders! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is pushing [p_their] thumbs into [p_their] eye sockets! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is ripping [p_their] own arms off! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is attempting to pull [p_their] own head off! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is aggressively grabbing [p_their] own neck! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is pulling [p_their] eyes out of their sockets! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is hugging [p_them]self to death! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is high-fiving [p_them]self to death! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is getting too high on life! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is attempting to bite [p_their] tongue off! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is jamming [p_their] thumbs into [p_their] eye sockets! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is twisting [p_their] own neck! It looks like [p_theyre] trying to commit suicide.", \ - "[src] is holding [p_their] breath! It looks like [p_theyre] trying to commit suicide.", \ -) +GLOBAL_LIST_INIT(human_suicide_messages, list( \ + "%%SUICIDER%% is attempting to push %%P_THEIR%% own head off %%P_THEIR%% shoulders! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is pushing %%P_THEIR%% thumbs into %%P_THEIR%% eye sockets! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is ripping %%P_THEIR%% own arms off! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is attempting to pull %%P_THEIR%% own head off! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is aggressively grabbing %%P_THEIR%% own neck! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is pulling %%P_THEIR%% eyes out of their sockets! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is hugging %%P_THEM%%self to death! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is high-fiving %%P_THEM%%self to death! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is getting too high on life! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is attempting to bite %%P_THEIR%% tongue off! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is jamming %%P_THEIR%% thumbs into %%P_THEIR%% eye sockets! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is twisting %%P_THEIR%% own neck! It looks like %%P_THEYRE%% trying to commit suicide.", \ + "%%SUICIDER%% is holding %%P_THEIR%% breath! It looks like %%P_THEYRE%% trying to commit suicide.", \ +)) /mob/var/suiciding = 0 @@ -101,9 +101,13 @@ return - var/suicide_message = SUICIDE_MESSAGE(p_their(), p_theyre(), p_them()) - - visible_message(span_danger("[suicide_message]"), span_userdanger("[suicide_message]")) + var/list/suicide_messages = GLOB.human_suicide_messages.Copy() + suicide_messages |= dna.species.suicide_messages + var/chosen_message = pick(suicide_messages) + var/list/text_replacements = list("%%SUICIDER%%" = "[src]", "%%P_THEIR%%" = "[p_their()]", "%%P_THEM%%" = "[p_them()]", "%%P_THEYRE%%" = "[p_theyre()]") + for(var/find_text in text_replacements) + chosen_message = replacetext(chosen_message, find_text, text_replacements[find_text]) + visible_message(span_danger(chosen_message), span_userdanger(chosen_message)) suicide_log() @@ -278,5 +282,3 @@ to_chat(src, "Something inside your head stops your action!") return return TRUE - -#undef SUICIDE_MESSAGE diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 28563976c4674..d3eafcd6e8a9f 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -252,6 +252,7 @@ item_target.worn_icon_state = initial(picked_item.worn_icon_state) item_target.item_state = initial(picked_item.item_state) + item_target.sprite_sheets = initial(picked_item.sprite_sheets) if(isclothing(item_target) && ispath(picked_item, /obj/item/clothing)) var/obj/item/clothing/CL = item_target var/obj/item/clothing/PCL = picked_item diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index a382e315bca89..d48ba7b96b3a9 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -33,6 +33,8 @@ . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves") if(HAS_BLOOD_DNA(src)) var/mutable_appearance/bloody_hands = mutable_appearance('icons/effects/blood.dmi', "bloodyhands") + if(species_fitted && icon_exists(bloody_hands.icon, "bloodyhands_[species_fitted]")) + bloody_hands.icon_state = "bloodyhands_[species_fitted]" bloody_hands.color = get_blood_dna_color(return_blood_DNA()) . += bloody_hands diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm index bcf9327ed8000..72dc63c19166a 100644 --- a/code/modules/clothing/head/_head.dm +++ b/code/modules/clothing/head/_head.dm @@ -33,6 +33,8 @@ bloody_helmet = mutable_appearance('icons/effects/64x64.dmi', "helmetblood_large") else bloody_helmet = mutable_appearance('icons/effects/blood.dmi', "helmetblood") + if(species_fitted && icon_exists(bloody_helmet.icon, "helmetblood_[species_fitted]")) + bloody_helmet.icon_state = "helmetblood_[species_fitted]" bloody_helmet.color = get_blood_dna_color(return_blood_DNA()) . += bloody_helmet diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm index 0bb43ccddeea2..771569397c8ca 100644 --- a/code/modules/clothing/masks/_masks.dm +++ b/code/modules/clothing/masks/_masks.dm @@ -38,6 +38,8 @@ . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") if(HAS_BLOOD_DNA(src)) var/mutable_appearance/bloody_mask = mutable_appearance('icons/effects/blood.dmi', "maskblood") + if(species_fitted && icon_exists(bloody_mask.icon, "maskblood_[species_fitted]")) + bloody_mask.icon_state = "maskblood_[species_fitted]" bloody_mask.color = get_blood_dna_color(return_blood_DNA()) . += bloody_mask diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm index 8e9af7a6a789b..9b5b599d1d1aa 100644 --- a/code/modules/clothing/masks/breath.dm +++ b/code/modules/clothing/masks/breath.dm @@ -42,7 +42,8 @@ /obj/item/clothing/mask/breath/examine(mob/user) . = ..() - . += span_notice("Alt-click [src] to adjust it.") + if(length(actions_types)) + . += span_notice("Alt-click [src] to adjust it.") /obj/item/clothing/mask/breath/medical desc = "A close-fitting sterile mask that can be connected to an air supply." diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 8916c9fc230a9..f83ba0f70d3db 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -16,6 +16,8 @@ . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") if(HAS_BLOOD_DNA(src)) var/mutable_appearance/bloody_mask = mutable_appearance('icons/effects/blood.dmi', "maskblood") + if(species_fitted && icon_exists(bloody_mask.icon, "maskblood_[species_fitted]")) + bloody_mask.icon_state = "maskblood_[species_fitted]" bloody_mask.color = get_blood_dna_color(return_blood_DNA()) . += bloody_mask diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index a9aa009a16a44..d8560612d8e5c 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -54,6 +54,8 @@ bloody_shoes = mutable_appearance('icons/effects/64x64.dmi', "shoeblood_large") else bloody_shoes = mutable_appearance('icons/effects/blood.dmi', "shoeblood") + if(species_fitted && icon_exists(bloody_shoes.icon, "shoeblood_[species_fitted]")) + bloody_shoes.icon_state = "shoeblood_[species_fitted]" bloody_shoes.color = get_blood_dna_color(return_blood_DNA()) . += bloody_shoes diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm index 112d2a0dc2b57..14f7f33bc0d0a 100644 --- a/code/modules/clothing/suits/_suits.dm +++ b/code/modules/clothing/suits/_suits.dm @@ -30,6 +30,8 @@ . += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform") if(HAS_BLOOD_DNA(src)) var/mutable_appearance/bloody_armor = mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood") + if(species_fitted && icon_exists(bloody_armor.icon, "[bloody_armor.icon_state]_[species_fitted]")) + bloody_armor.icon_state = "[bloody_armor.icon_state]_[species_fitted]" bloody_armor.color = get_blood_dna_color(return_blood_DNA()) . += bloody_armor var/mob/living/carbon/human/M = loc diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 1bebc3b9dff3b..a909f3deb696b 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -372,7 +372,7 @@ /obj/item/clothing/head/hooded/human_head name = "bloated human head" desc = "A horribly bloated and mismatched human head." - icon_state = "lingspacehelmet" + icon_state = "humanheadhat" body_parts_covered = HEAD flags_cover = HEADCOVERSEYES flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 66ef8c2e4c66a..25aa84df63d10 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -33,6 +33,8 @@ . += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform") if(HAS_BLOOD_DNA(src)) var/mutable_appearance/bloody_uniform = mutable_appearance('icons/effects/blood.dmi', "uniformblood") + if(species_fitted && icon_exists(bloody_uniform.icon, "uniformblood_[species_fitted]")) + bloody_uniform.icon_state = "uniformblood_[species_fitted]" bloody_uniform.color = get_blood_dna_color(return_blood_DNA()) . += bloody_uniform if(accessory_overlay) diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm index 31298dfc77ced..c5d616b1a3af7 100644 --- a/code/modules/food_and_drinks/food/snacks_pie.dm +++ b/code/modules/food_and_drinks/food/snacks_pie.dm @@ -43,10 +43,7 @@ if(ishuman(hit_atom)) var/mob/living/carbon/human/H = hit_atom var/mutable_appearance/creamoverlay = mutable_appearance('icons/effects/creampie.dmi') - if(H.dna.species.limbs_id == "lizard") - creamoverlay.icon_state = "creampie_lizard" - else - creamoverlay.icon_state = "creampie_human" + creamoverlay.icon_state = H.dna.species.creampie_id if(stunning) H.Paralyze(20) //splat! H.adjust_eye_blur(1) diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index c7fac4fd301db..38677ad30da7e 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -392,6 +392,7 @@ Key procs /datum/language/bonespeak = list(LANGUAGE_ATOM), /datum/language/sylvan = list(LANGUAGE_ATOM), /datum/language/draconic = list(LANGUAGE_ATOM), + /datum/language/vox = list(LANGUAGE_ATOM), /datum/language/machine = list(LANGUAGE_ATOM)) spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), /datum/language/felinid = list(LANGUAGE_ATOM), @@ -402,6 +403,7 @@ Key procs /datum/language/bonespeak = list(LANGUAGE_ATOM), /datum/language/sylvan = list(LANGUAGE_ATOM), /datum/language/draconic = list(LANGUAGE_ATOM), + /datum/language/vox = list(LANGUAGE_ATOM), /datum/language/machine = list(LANGUAGE_ATOM)) /datum/language_holder/empty diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 99171e324ffb1..71a46b48d5087 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -34,11 +34,10 @@ if(!brain) icon_state = "mmi_off" return + icon_state = brain.get_mmi_brain_sprite() if(istype(brain, /obj/item/organ/brain/alien)) - icon_state = "mmi_brain_alien" braintype = "Xenoborg" //HISS....Beep. else - icon_state = "mmi_brain" braintype = "Cyborg" /obj/item/mmi/update_overlays() @@ -73,7 +72,7 @@ return var/mob/living/brain/B = newbrain.brainmob if(!B.key) - B.notify_ghost_cloning("Someone has put your brain in a MMI!", source = src) + B.notify_ghost_cloning("Someone has put your [newbrain.brain_name] in an MMI!", source = src) user.visible_message("[user] sticks \a [newbrain] into [src].", span_notice("[src]'s indicator light turn on as you insert [newbrain].")) brainmob = newbrain.brainmob @@ -130,14 +129,15 @@ /obj/item/mmi/attack_self(mob/user) if(brain) - user.visible_message(span_notice("[user] begins to remove the brain from [src]."), span_danger("You begin to pry the brain out of [src], ripping out the wires and probes.")) + var/brain_flavor_name = brain.brain_name + user.visible_message(span_notice("[user] begins to remove the [brain_flavor_name] from [src]."), span_danger("You begin to pry the [brain_flavor_name] out of [src], ripping out the wires and probes.")) to_chat(brainmob, span_userdanger("You feel your mind failing as you are slowly ripped from the [src].")) if(do_after(user, remove_time, src)) - to_chat(brainmob, span_userdanger("Due to the traumatic danger of your removal, all memories of the events leading to your brain being removed are lost[rebooting ? ", along with all memories of the events leading to your death as a cyborg." : ""].")) + to_chat(brainmob, span_userdanger("Due to the traumatic danger of your removal, all memories of the events leading to your [brain_flavor_name] being removed are lost[rebooting ? ", along with all memories of the events leading to your death as a cyborg." : ""].")) eject_brain(user) update_appearance(UPDATE_ICON) name = initial(name) - user.visible_message(span_notice("[user] rips the brain out of [src]."), span_danger("You successfully remove the brain from the [src][rebooting ? ", interrupting the reboot process." : ""].")) + user.visible_message(span_notice("[user] rips the [brain_flavor_name] out of [src]."), span_danger("You successfully remove the [brain_flavor_name] from the [src][rebooting ? ", interrupting the reboot process." : ""].")) if(rebooting) rebooting = FALSE deltimer(reboot_timer) @@ -192,7 +192,7 @@ brain = newbrain else if(!brain) brain = new(src) - brain.name = "[L.real_name]'s brain" + brain.name = "[L.real_name]'s [brain.brain_name]" name = "[initial(name)]: [brainmob.real_name]" to_chat(brainmob, welcome_message) @@ -262,13 +262,13 @@ if(brainmob) var/mob/living/brain/B = brainmob if(!B.key || !B.mind || B.stat == DEAD) - . += span_warning("The MMI indicates the brain is completely unresponsive.") + . += span_warning("The MMI indicates the [brain.brain_name] is completely unresponsive.") else if(!B.client) - . += span_warning("The MMI indicates the brain is currently inactive; it might change.") + . += span_warning("The MMI indicates the [brain.brain_name] is currently inactive; it might change.") else - . += span_notice("The MMI indicates the brain is active.") + . += span_notice("The MMI indicates the [brain.brain_name] is active.") . += span_notice("It has a port for reading AI law modules.") if(laws) . += span_notice("Any AI created using this MMI will use these uploaded laws:") diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index ec755053510e6..f3dd1fa5f7eb2 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -35,7 +35,7 @@ if(C.mind && C.mind.has_antag_datum(/datum/antagonist/changeling) && !no_id_transfer) //congrats, you're trapped in a body you don't control if(brainmob && !(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_DEATHCOMA)))) - to_chat(brainmob, "You can't feel your body! You're still just a brain!") + to_chat(brainmob, span_danger("You can't feel your body! You're still just a [brain_name]!")) forceMove(C) C.update_hair() return @@ -90,7 +90,7 @@ ..() /obj/item/organ/brain/proc/transfer_identity(mob/living/L) - name = "[L.name]'s brain" + name = "[L.name]'s [brain_name]" if(brainmob || decoy_override) return if(!L.mind) @@ -115,7 +115,7 @@ brainmob.set_species(ZI.old_species) //For if the brain is cloned if(L.mind && L.mind.current) L.mind.transfer_to(brainmob) - to_chat(brainmob, span_notice("You feel slightly disoriented. That's normal when you're just a brain.")) + to_chat(brainmob, span_notice("You feel slightly disoriented. That's normal when you're just a [brain_name].")) /obj/item/organ/brain/attackby(obj/item/O, mob/user, params) user.changeNext_move(CLICK_CD_MELEE) @@ -138,7 +138,7 @@ to_chat(user, span_warning("You failed to pour [O] onto [src]!")) return - user.visible_message("[user] pours the contents of [O] onto [src], causing it to reform its original shape and turn a slightly brighter shade of pink.", span_notice("You pour the contents of [O] onto [src], causing it to reform its original shape and turn a slightly brighter shade of pink.")) + user.visible_message("[user] pours the contents of [O] onto [src], causing it to reform its original shape and turn a slightly brighter shade[brain_name == "brain" ? " of pink." : "."]", span_notice("You pour the contents of [O] onto [src], causing it to reform its original shape and turn a slightly brighter shade[brain_name == "brain" ? " of pink." : "."]")) setOrganDamage(damage - (0.05 * maxHealth)) //heals a small amount, and by using "setorgandamage", we clear the failing variable if that was up O.reagents.clear_reagents() @@ -193,7 +193,7 @@ // This should be a better check but this covers 99.9% of cases if(!(compatible_biotypes & C.mob_biotypes)) - to_chat(user, span_warner("This brain is incompatiable with this beings biology!")) + to_chat(user, span_warner("This brain is incompatible with this being's biology!")) return if(!target_has_brain && C.is_eyes_covered() && user.zone_selected == BODY_ZONE_HEAD) @@ -226,7 +226,7 @@ /obj/item/organ/brain/on_life() if(damage >= BRAIN_DAMAGE_DEATH) //rip - to_chat(owner, span_userdanger("The last spark of life in your brain fizzles out...")) + to_chat(owner, span_userdanger("The last spark of life in your [brain_name] fizzles out...")) owner.death() brain_death = TRUE diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 664adf0832a21..c1780eb93fa78 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -30,10 +30,9 @@ GLOBAL_LIST_EMPTY(features_by_species) var/grad_style ///The gradient color used to color the gradient. var/grad_color - /// does it use skintones or not? (spoiler alert this is only used by humans) var/use_skintones = FALSE - + var/icon_husk var/forced_skintone /// What genders can this race be? @@ -135,6 +134,8 @@ GLOBAL_LIST_EMPTY(features_by_species) var/grab_sound ///yogs - audio of a species' scream var/screamsound //yogs - grabs scream from screamsound list or string + var/husk_color = "#A6A6A6" + var/creampie_id = "creampie_human" /// The visual effect of the attack. var/attack_effect = ATTACK_EFFECT_PUNCH ///is a flying species, just a check for some things @@ -148,7 +149,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/species_gibs = "human" /// Can this species use numbers in its name? var/allow_numbers_in_name = FALSE - + var/is_dimorphic = TRUE /// species-only traits. Can be found in DNA.dm var/list/species_traits = list() /// generic traits tied to having the species @@ -385,6 +386,10 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/organ/tail/lizard/new_lizard_tail = neworgan new_lizard_tail.tail_type = C.dna.features["tail_lizard"] new_lizard_tail.spines = C.dna.features["spines"] + if(isvox(C)) + var/obj/item/organ/tail/vox/new_vox_tail = neworgan + new_vox_tail.tail_type = C.dna.features["vox_skin_tone"] + new_vox_tail.tail_markings = C.dna.features["vox_tail_markings"] // if(tail && (!should_have_tail || replace_current)) // tail.Remove(C,1) @@ -497,7 +502,7 @@ GLOBAL_LIST_EMPTY(features_by_species) fly.Grant(C) C.add_movespeed_modifier(MOVESPEED_ID_SPECIES, TRUE, 100, override=TRUE, multiplicative_slowdown=speedmod, movetypes=(~FLYING)) - + C.regenerate_icons() SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species) @@ -551,7 +556,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(!HD) //Decapitated return - if(HAS_TRAIT(H, TRAIT_HUSK)) + if(HD.is_husked) return var/datum/sprite_accessory/S var/list/standing = list() @@ -581,6 +586,17 @@ GLOBAL_LIST_EMPTY(features_by_species) if(M.flags_inv & HIDEFACIALHAIR) facialhair_hidden = TRUE + if(("vox_facial_quills" in H.dna.species.mutant_bodyparts) && !facialhair_hidden) + S = GLOB.vox_facial_quills_list[H.dna.features["vox_facial_quills"]] + if(S) + var/mutable_appearance/facial_quills_overlay = mutable_appearance(layer = -HAIR_LAYER, appearance_flags = KEEP_TOGETHER) + var/mutable_appearance/facial_quills_base = mutable_appearance(S.icon, S.icon_state) + facial_quills_base.color = forced_colour || H.facial_hair_color + if(S.color_blend_mode == COLOR_BLEND_ADD) + facial_quills_base.color = COLOR_MATRIX_ADD(facial_quills_base.color) + facial_quills_overlay.overlays += facial_quills_base + facial_quills_overlay.alpha = hair_alpha + standing += facial_quills_overlay if(H.facial_hair_style && (FACEHAIR in species_traits) && (!facialhair_hidden || dynamic_fhair_suffix)) S = GLOB.facial_hair_styles_list[H.facial_hair_style] if(S) @@ -726,7 +742,7 @@ GLOBAL_LIST_EMPTY(features_by_species) hair_overlay.color = H.hair_color hair_overlay.alpha = hair_alpha standing+=hair_overlay - //var/mutable_appearance/pod_flower = mutable_appearance(GLOB.pod_flower_list[H.dna.features["pod_flower"]].icon, GLOB.pod_flower_list[H.dna.features["pod_flower"]].icon_state, -HAIR_LAYER) + //var/mutable_appearance/pod_flower = mutable_appearance(GLOB.pod_flower_list[H.dna.features["pod_flower"]].icon, GLOB.pod_flower_list[H.dna.features["pod_flower"]].icon_state, -HAIR_LAYER) S = GLOB.pod_flower_list[H.dna.features["pod_flower"]] if(S) var/flower_state = S.icon_state @@ -746,6 +762,26 @@ GLOBAL_LIST_EMPTY(features_by_species) flower_overlay.color = H.facial_hair_color flower_overlay.alpha = hair_alpha standing += flower_overlay + if(("vox_quills" in H.dna.species.mutant_bodyparts) && !hair_hidden) + S = GLOB.vox_quills_list[H.dna.features["vox_quills"]] + if(S) + var/mutable_appearance/quills_overlay = mutable_appearance(layer = -HAIR_LAYER, appearance_flags = KEEP_TOGETHER) + var/mutable_appearance/quills_base = mutable_appearance(S.icon, S.icon_state) + quills_base.color = forced_colour || H.hair_color + if(S.color_blend_mode == COLOR_BLEND_ADD) + quills_base.color = COLOR_MATRIX_ADD(quills_base.color) + quills_overlay.overlays += quills_base + //Gradients + grad_style = H.grad_style + grad_color = H.grad_color + if(grad_style) + var/datum/sprite_accessory/gradient = GLOB.hair_gradients_list[grad_style] + var/mutable_appearance/gradient_quills = mutable_appearance(gradient.icon, gradient.icon_state) + gradient_quills.color = COLOR_MATRIX_OVERLAY(grad_color) + gradient_quills.blend_mode = BLEND_INSET_OVERLAY + quills_overlay.overlays += gradient_quills + quills_overlay.alpha = hair_alpha + standing += quills_overlay if(standing.len) H.overlays_standing[HAIR_LAYER] = standing @@ -758,7 +794,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) - if(HD && !(HAS_TRAIT(H, TRAIT_HUSK))) + if(HD && !HD.is_husked) // lipstick if(H.lip_style && (LIPS in species_traits)) var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER) @@ -794,22 +830,34 @@ GLOBAL_LIST_EMPTY(features_by_species) if(HAS_TRAIT(H, TRAIT_SKINNY)) standing += wear_skinny_version(underwear.icon_state, underwear.icon, BODY_LAYER) //Neat, this works else - standing += mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) + var/mutable_appearance/underwear_overlay = mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) + if(H.dna.species.id in underwear.sprite_sheets) + if(icon_exists(underwear.sprite_sheets[H.dna.species.id], underwear.icon_state)) + underwear_overlay.icon = underwear.sprite_sheets[H.dna.species.id] + standing += underwear_overlay if(H.undershirt) var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[H.undershirt] if(undershirt) if(HAS_TRAIT(H, TRAIT_SKINNY)) //Check for skinny first standing += wear_skinny_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) - else if(H.gender == FEMALE && (FEMALE in possible_genders)) + else if((H.gender == FEMALE && (FEMALE in possible_genders)) && H.dna.species.is_dimorphic) standing += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) else - standing += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) + var/mutable_appearance/undershirt_overlay = mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) + if(H.dna.species.id in undershirt.sprite_sheets) + if(icon_exists(undershirt.sprite_sheets[H.dna.species.id], undershirt.icon_state)) + undershirt_overlay.icon = undershirt.sprite_sheets[H.dna.species.id] + standing += undershirt_overlay if(H.socks && H.get_num_legs(FALSE) >= 2 && !(DIGITIGRADE in species_traits)) var/datum/sprite_accessory/socks/socks = GLOB.socks_list[H.socks] if(socks) - standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) + var/mutable_appearance/socks_overlay = mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) + if(H.dna.species.id in socks.sprite_sheets) + if(icon_exists(socks.sprite_sheets[H.dna.species.id], socks.icon_state)) + socks_overlay.icon = socks.sprite_sheets[H.dna.species.id] + standing += socks_overlay if(standing.len) H.overlays_standing[BODY_LAYER] = standing @@ -819,6 +867,8 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour) var/list/bodyparts_to_add = mutant_bodyparts.Copy() + if(HAS_TRAIT(H, TRAIT_HUSK) && length(parts_to_husk)) + bodyparts_to_add &= parts_to_husk var/list/relevent_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) var/list/standing = list() @@ -930,10 +980,10 @@ GLOBAL_LIST_EMPTY(features_by_species) if((H.wear_mask && (H.wear_mask.flags_inv & HIDEEYES)) || (H.head && (H.head.flags_inv & HIDEEYES)) || !HD) bodyparts_to_add -= "preternis_eye" + if("preternis_core" in mutant_bodyparts) if(!get_location_accessible(H, BODY_ZONE_CHEST)) bodyparts_to_add -= "preternis_core" - if("pod_hair" in mutant_bodyparts) if((H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || (H.head && (H.head.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC) bodyparts_to_add -= "pod_hair" @@ -944,6 +994,26 @@ GLOBAL_LIST_EMPTY(features_by_species) if(H.dna.features["pod_flower"] != H.dna.features["pod_hair"]) H.dna.features["pod_flower"] = H.dna.features["pod_hair"] + if("vox_tail" in mutant_bodyparts) + if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) + bodyparts_to_add -= "vox_tail" + + if("wagging_vox_tail" in mutant_bodyparts) + if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) + bodyparts_to_add -= "wagging_vox_tail" + else if ("vox_tail" in mutant_bodyparts) + bodyparts_to_add -= "wagging_vox_tail" + + if("vox_tail_markings" in mutant_bodyparts) + if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) + bodyparts_to_add -= "vox_tail_markings" + + if("wagging_vox_tail_markings" in mutant_bodyparts) + if(!H.dna.features["vox_tail_markings"] || H.dna.features["vox_tail_markings"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) + bodyparts_to_add -= "vox_tail_markings" + else if ("vox_tail" in mutant_bodyparts) + bodyparts_to_add -= "wagging_vox_tail_markings" + //Digitigrade legs are stuck in the phantom zone between true limbs and mutant bodyparts. Mainly it just needs more agressive updating than most limbs. var/update_needed = FALSE var/not_digitigrade = TRUE @@ -982,7 +1052,6 @@ GLOBAL_LIST_EMPTY(features_by_species) H.update_body_parts() if(not_digitigrade && (DIGITIGRADE in species_traits)) //Curse is lifted species_traits -= DIGITIGRADE - if(!bodyparts_to_add) return @@ -1056,15 +1125,33 @@ GLOBAL_LIST_EMPTY(features_by_species) S = GLOB.ipc_antennas_list[H.dna.features["ipc_antenna"]] if("ipc_chassis") S = GLOB.ipc_chassis_list[H.dna.features["ipc_chassis"]] + if("vox_tail") + var/obj/item/organ/tail/vox/vox_tail = H.getorganslot(ORGAN_SLOT_TAIL) + if(vox_tail && istype(vox_tail)) + S = GLOB.vox_tails_list[vox_tail.tail_type] + if("wagging_vox_tail") + var/obj/item/organ/tail/vox/vox_tail = H.getorganslot(ORGAN_SLOT_TAIL) + if(vox_tail && istype(vox_tail)) + S = GLOB.animated_vox_tails_list[vox_tail.tail_type] + if("vox_body_markings") + S = GLOB.vox_body_markings_list[H.dna.features["vox_body_markings"]] + if("vox_tail_markings") + var/obj/item/organ/tail/vox/vox_tail = H.getorganslot(ORGAN_SLOT_TAIL) + if(vox_tail && istype(vox_tail)) + S = GLOB.vox_tail_markings_list[vox_tail.tail_markings] + if("wagging_vox_tail_markings") + var/obj/item/organ/tail/vox/vox_tail = H.getorganslot(ORGAN_SLOT_TAIL) + if(vox_tail && istype(vox_tail)) + S = GLOB.animated_vox_tail_markings_list[vox_tail.tail_markings] if(!S || S.icon_state == "none") continue var/mutable_appearance/accessory_overlay = mutable_appearance(S.icon, layer = -layer) //A little rename so we don't have to use tail_lizard or tail_human when naming the sprites. - if(bodypart == "tail_lizard" || bodypart == "tail_human" || bodypart == "tail_polysmorph") + if(bodypart == "tail_lizard" || bodypart == "tail_human" || bodypart == "tail_polysmorph" || bodypart == "vox_tail") bodypart = "tail" - else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human") + else if(bodypart == "waggingtail_lizard" || bodypart == "waggingtail_human" || bodypart == "wagging_vox_tail") bodypart = "waggingtail" if(S.gender_specific) @@ -1085,6 +1172,11 @@ GLOBAL_LIST_EMPTY(features_by_species) accessory_overlay.color = fixed_mut_color else //Then snowflake color accessory_overlay.color = H.dna.features["mcolor"] + if(MUTCOLORS_SECONDARY) + if(fixed_mut_color) + accessory_overlay.color = fixed_mut_color + else + accessory_overlay.color = H.dna.features["mcolor_secondary"] if(HAIR) if(hair_color == "mutcolor") accessory_overlay.color = H.dna.features["mcolor"] @@ -1098,6 +1190,8 @@ GLOBAL_LIST_EMPTY(features_by_species) accessory_overlay.color = H.eye_color else accessory_overlay.color = forced_colour + if(S.color_blend_mode == COLOR_BLEND_ADD) + accessory_overlay.color = COLOR_MATRIX_ADD(accessory_overlay.color) standing += accessory_overlay if(S.emissive && !(HAS_TRAIT(H, TRAIT_HUSK)) && !istype(H, /mob/living/carbon/human/dummy))//don't put emissives on dummy mobs as they're used for the preference menu, which doesn't draw emissives properly @@ -1136,6 +1230,8 @@ GLOBAL_LIST_EMPTY(features_by_species) emissive_accessory_overlay.color = forced_colour standing += emissive_accessory_overlay + if(length(S.body_slots) || length(S.external_slots)) + standing += return_accessory_layer(layer, S, H, accessory_overlay.color) if(S.hasinner) var/mutable_appearance/inner_accessory_overlay = mutable_appearance(S.icon, layer = -layer) if(S.gender_specific) @@ -1147,7 +1243,10 @@ GLOBAL_LIST_EMPTY(features_by_species) inner_accessory_overlay = center_image(inner_accessory_overlay, S.dimension_x, S.dimension_y) standing += inner_accessory_overlay - + if(HAS_TRAIT(H, TRAIT_HUSK)) + for(var/image/sprite_image as anything in standing) + huskify_image(sprite_image, H, draw_blood = FALSE) + sprite_image.color = H.dna.species.husk_color H.overlays_standing[layer] = standing.Copy() standing = list() @@ -1155,7 +1254,6 @@ GLOBAL_LIST_EMPTY(features_by_species) H.apply_overlay(BODY_ADJ_LAYER) H.apply_overlay(BODY_FRONT_LAYER) - //This exists so sprite accessories can still be per-layer without having to include that layer's //number in their sprite name, which causes issues when those numbers change. /datum/species/proc/mutant_bodyparts_layertext(layer) @@ -2215,10 +2313,10 @@ GLOBAL_LIST_EMPTY(features_by_species) if(H.IsParalyzed() || H.IsStun()) return FALSE // var/obj/item/organ/tail = H.getorganslot(ORGAN_SLOT_TAIL) - return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts) || ("tail_lizard" in mutant_bodyparts) || ("waggingtail_lizard" in mutant_bodyparts) + return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts) || ("tail_lizard" in mutant_bodyparts) || ("waggingtail_lizard" in mutant_bodyparts) || ("vox_tail" in mutant_bodyparts) || ("wagging_vox_tail" in mutant_bodyparts) /datum/species/proc/is_wagging_tail(mob/living/carbon/human/H) - return ("waggingtail_human" in mutant_bodyparts) || ("waggingtail_lizard" in mutant_bodyparts) + return ("waggingtail_human" in mutant_bodyparts) || ("waggingtail_lizard" in mutant_bodyparts) || ("wagging_vox_tail" in mutant_bodyparts) /datum/species/proc/start_wagging_tail(mob/living/carbon/human/H) if("tail_human" in mutant_bodyparts) @@ -2229,6 +2327,11 @@ GLOBAL_LIST_EMPTY(features_by_species) mutant_bodyparts -= "spines" mutant_bodyparts |= "waggingtail_lizard" mutant_bodyparts |= "waggingspines" + if("vox_tail" in mutant_bodyparts) + mutant_bodyparts -= "vox_tail" + mutant_bodyparts -= "vox_tail_markings" + mutant_bodyparts |= "wagging_vox_tail" + mutant_bodyparts |= "wagging_vox_tail_markings" H.update_body() /datum/species/proc/stop_wagging_tail(mob/living/carbon/human/H) @@ -2240,6 +2343,11 @@ GLOBAL_LIST_EMPTY(features_by_species) mutant_bodyparts -= "waggingspines" mutant_bodyparts |= "tail_lizard" mutant_bodyparts |= "spines" + if("wagging_vox_tail" in mutant_bodyparts) + mutant_bodyparts |= "vox_tail" + mutant_bodyparts |= "vox_tail_markings" + mutant_bodyparts -= "wagging_vox_tail" + mutant_bodyparts -= "wagging_vox_tail_markings" H.update_body() /////////////// @@ -2362,6 +2470,9 @@ GLOBAL_LIST_EMPTY(features_by_species) if(HAS_BONE in species_traits) . |= BIO_JUST_BONE +/datum/species/proc/get_footprint_sprite() + return null + /datum/species/proc/eat_text(fullness, eatverb, obj/O, mob/living/carbon/C, mob/user) . = TRUE if(C == user) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index f4b38a0eb575d..8736b752f2a77 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -80,6 +80,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) target.dna.features["frills"] = "None" target.dna.features["horns"] = "None" target.dna.features["mcolor"] = COLOR_VIBRANT_LIME + target.dna.features["mcolor_secondary"] = COLOR_RED target.dna.features["moth_antennae"] = "Plain" target.dna.features["moth_markings"] = "None" target.dna.features["moth_wings"] = "Plain" @@ -88,6 +89,11 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) target.dna.features["tail_cat"] = "None" target.dna.features["tail_lizard"] = "Smooth" target.dna.features["pod_hair"] = "Ivy" + target.dna.features["vox_quills"] = "None" + target.dna.features["vox_facial_quills"] = "None" + target.dna.features["vox_skin_tone"] = "lime" + target.dna.features["vox_tail_markings"] = "None" + target.dna.features["vox_body_markings"] = "None" /// Provides a dummy that is consistently bald, white, naked, etc. /mob/living/carbon/human/dummy/consistent diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 9c9526e2924c6..af39fdd088d5d 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -420,7 +420,14 @@ /mob/living/carbon/human/get_footprint_sprite() var/obj/item/bodypart/l_leg/left_leg = get_bodypart(BODY_ZONE_L_LEG) var/obj/item/bodypart/r_leg/right_leg = get_bodypart(BODY_ZONE_R_LEG) - return shoes?.footprint_sprite || left_leg?.footprint_sprite || right_leg?.footprint_sprite + var/species_id + var/datum/species/species + if(left_leg?.species_id == right_leg?.species_id) + species_id = left_leg.species_id + var/species_type = GLOB.species_list[species_id] + if(species_type) + species = new species_type() + return species?.get_footprint_sprite() || shoes?.footprint_sprite || left_leg?.footprint_sprite || right_leg?.footprint_sprite /mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) if(judgement_criteria & JUDGE_EMAGGED) @@ -685,6 +692,7 @@ if(creamed) //clean both to prevent a rare bug cut_overlay(mutable_appearance('icons/effects/creampie.dmi', "creampie_lizard")) cut_overlay(mutable_appearance('icons/effects/creampie.dmi', "creampie_human")) + cut_overlay(mutable_appearance('icons/effects/creampie.dmi', "creampie_vox")) creamed = FALSE //Turns a mob black, flashes a skeleton overlay 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 7ca856b5669c7..7a676d6667e6d 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -20,6 +20,7 @@ attack_verbs = list("slash", "scratch", "claw") attack_effect = ATTACK_EFFECT_CLAW barefoot_step_sound = FOOTSTEP_MOB_CLAW + creampie_id = "creampie_lizard" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard 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 792a3f98f72ce..acc4dde95a25f 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -28,7 +28,8 @@ liked_food = DAIRY changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC species_language_holder = /datum/language_holder/plasmaman - + survival_box_replacements = list(items_to_delete = list(/obj/item/clothing/mask/breath, /obj/item/tank/internals/emergency_oxygen),\ + new_items = list(/obj/item/tank/internals/plasmaman/belt)) screamsound = list('sound/voice/plasmaman/plasmeme_scream_1.ogg', 'sound/voice/plasmaman/plasmeme_scream_2.ogg', 'sound/voice/plasmaman/plasmeme_scream_3.ogg') smells_like = "plasma-caked calcium" diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index d00c376059650..de86f33fcdcb0 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -32,7 +32,7 @@ update_hair() /mob/living/carbon/human/become_husk(source) - if(NOHUSK in dna.species.species_traits) + if(NOHUSK in dna?.species?.species_traits) cure_husk() return . = ..() diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 2991dbe2b0ccb..a892565fa24fe 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -155,17 +155,36 @@ There are several things that need to be remembered: //Friendly reminder that icon_exists(file, state, scream = TRUE) is your friend when debugging this code. var/icon_file var/target_overlay = RESOLVE_ICON_STATE(uniform) //Selects proper icon from the vars the clothing has (Search define for more.) - + var/obj/item/bodypart/l_leg = get_bodypart(BODY_ZONE_L_LEG) + var/obj/item/bodypart/r_leg = get_bodypart(BODY_ZONE_R_LEG) + var/obj/item/bodypart/chest/chest = get_bodypart(BODY_ZONE_CHEST) + uniform.species_fitted = null if(uniform.adjusted == ALT_STYLE) target_overlay = "[target_overlay]_d" else if(uniform.adjusted == DIGITIGRADE_STYLE) // yogs - digitigrade alt sprites target_overlay = "[target_overlay]_l" else if(uniform.adjusted == DIGIALT_STYLE) target_overlay = "[target_overlay]_d_l" // yogs end + //Checks for GAGS + if(uniform.greyscale_config && uniform.greyscale_colors) + if("GAGS_sprite" in uniform.sprite_sheets) + var/list/GAGS_species = uniform.sprite_sheets["GAGS_sprite"] + if((SPECIES_VOX in GAGS_species) && l_leg?.species_id == SPECIES_VOX && r_leg?.species_id == SPECIES_VOX) + target_overlay += "_vox" + uniform.species_fitted = SPECIES_VOX + if(l_leg?.species_id == SPECIES_VOX && (r_leg?.species_id == SPECIES_VOX))//for Vox, it's the Vox legs that make regular sprites not fit + if(SPECIES_VOX in uniform.sprite_sheets) + if(icon_exists(uniform.sprite_sheets[SPECIES_VOX], uniform.icon_state)) + icon_file = uniform.sprite_sheets[SPECIES_VOX] + uniform.species_fitted = SPECIES_VOX + else if(chest?.species_id in uniform.sprite_sheets) + if(icon_exists(uniform.sprite_sheets[chest.species_id], uniform.icon_state)) + icon_file = uniform.sprite_sheets[chest.species_id] + uniform.species_fitted = chest.species_id var/mutable_appearance/uniform_overlay - if(gender == FEMALE && uniform.fitted != NO_FEMALE_UNIFORM) + if((gender == FEMALE && dna.species.is_dimorphic) && uniform.fitted != NO_FEMALE_UNIFORM) uniform_overlay = uniform.build_worn_icon( default_layer = UNIFORM_LAYER, default_icon_file = icon_file, @@ -173,6 +192,7 @@ There are several things that need to be remembered: femaleuniform = uniform.fitted, override_state = target_overlay, ) + else uniform_overlay = uniform.build_worn_icon( default_layer = UNIFORM_LAYER, @@ -223,13 +243,21 @@ There are several things that need to be remembered: var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_GLOVES) + 1] inv.update_appearance(UPDATE_ICON) + var/obj/item/bodypart/l_arm = get_bodypart(BODY_ZONE_L_ARM) + var/obj/item/bodypart/r_arm = get_bodypart(BODY_ZONE_R_ARM) if(!gloves && blood_in_hands) var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER) + if(icon_exists(bloody_overlay.icon, "[bloody_overlay.icon_state]_[l_arm?.species_id]")) + bloody_overlay.icon_state = "bloodyhands_[l_arm.species_id]" if(get_num_arms(FALSE) < 2) if(has_left_hand(FALSE)) bloody_overlay.icon_state = "bloodyhands_left" + if(icon_exists(bloody_overlay.icon, "[bloody_overlay.icon_state]_[l_arm?.species_id]")) + bloody_overlay.icon_state += "_[l_arm.species_id]" else if(has_right_hand(FALSE)) bloody_overlay.icon_state = "bloodyhands_right" + if(icon_exists(bloody_overlay.icon, "[bloody_overlay.icon_state]_[r_arm?.species_id]")) + bloody_overlay.icon_state += "_[r_arm.species_id]" bloody_overlay.color = get_blood_dna_color(return_blood_DNA()) overlays_standing[GLOVES_LAYER] = bloody_overlay @@ -241,7 +269,14 @@ There are several things that need to be remembered: if(hud_used.inventory_shown) client.screen += gloves update_observer_view(gloves,1) - overlays_standing[GLOVES_LAYER] = gloves.build_worn_icon(default_layer = GLOVES_LAYER, default_icon_file = 'icons/mob/clothing/hands/hands.dmi') + var/icon_to_use = 'icons/mob/clothing/hands/hands.dmi' + gloves.species_fitted = null + if(l_arm?.species_id == r_arm?.species_id) + if(l_arm.species_id in gloves.sprite_sheets) + if(icon_exists(gloves.sprite_sheets[l_arm.species_id], gloves.icon_state)) + icon_to_use = gloves.sprite_sheets[l_arm.species_id] + gloves.species_fitted = l_arm.species_id + overlays_standing[GLOVES_LAYER] = gloves.build_worn_icon(default_layer = GLOVES_LAYER, default_icon_file = icon_to_use) gloves_overlay = overlays_standing[GLOVES_LAYER] if(OFFSET_GLOVES in dna.species.offset_features) gloves_overlay.pixel_x += dna.species.offset_features[OFFSET_GLOVES][1] @@ -253,7 +288,8 @@ There are several things that need to be remembered: /mob/living/carbon/human/update_inv_glasses() remove_overlay(GLASSES_LAYER) - if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated + var/obj/item/bodypart/head/head = get_bodypart(BODY_ZONE_HEAD) + if(!head) //decapitated return if(client && hud_used) @@ -267,7 +303,13 @@ There are several things that need to be remembered: client.screen += glasses //Either way, add the item to the HUD update_observer_view(glasses,1) if(!(head && (head.flags_inv & HIDEEYES)) && !(wear_mask && (wear_mask.flags_inv & HIDEEYES))) - overlays_standing[GLASSES_LAYER] = glasses.build_worn_icon(default_layer = GLASSES_LAYER, default_icon_file = 'icons/mob/clothing/eyes/eyes.dmi') + var/icon_to_use = 'icons/mob/clothing/eyes/eyes.dmi' + glasses.species_fitted = null + if(head.species_id in glasses.sprite_sheets) + if(icon_exists(glasses.sprite_sheets[head.species_id], glasses.icon_state)) + icon_to_use = glasses.sprite_sheets[head.species_id] + glasses.species_fitted = head.species_id + overlays_standing[GLASSES_LAYER] = glasses.build_worn_icon(default_layer = GLASSES_LAYER, default_icon_file = icon_to_use) var/mutable_appearance/glasses_overlay = overlays_standing[GLASSES_LAYER] if(glasses_overlay) @@ -281,7 +323,8 @@ There are several things that need to be remembered: /mob/living/carbon/human/update_inv_ears() remove_overlay(EARS_LAYER) - if(!get_bodypart(BODY_ZONE_HEAD)) //decapitated + var/obj/item/bodypart/head/head = get_bodypart(BODY_ZONE_HEAD) + if(!head) //decapitated return if(client && hud_used) @@ -294,7 +337,13 @@ There are several things that need to be remembered: if(hud_used.inventory_shown) //if the inventory is open client.screen += ears //add it to the client's screen update_observer_view(ears,1) - overlays_standing[EARS_LAYER] = ears.build_worn_icon(default_layer = EARS_LAYER, default_icon_file = 'icons/mob/clothing/ears/ears.dmi') + var/icon_to_use = 'icons/mob/clothing/ears/ears.dmi' + ears.species_fitted = null + if(head.species_id in ears.sprite_sheets) + if(icon_exists(ears.sprite_sheets[head.species_id], ears.icon_state)) + icon_to_use = ears.sprite_sheets[head.species_id] + ears.species_fitted = head.species_id + overlays_standing[EARS_LAYER] = ears.build_worn_icon(default_layer = EARS_LAYER, default_icon_file = icon_to_use) var/mutable_appearance/ears_overlay = overlays_standing[EARS_LAYER] if(OFFSET_EARS in dna.species.offset_features) ears_overlay.pixel_x += dna.species.offset_features[OFFSET_EARS][1] @@ -336,16 +385,29 @@ There are several things that need to be remembered: if(shoes) var/target_overlay = RESOLVE_ICON_STATE(shoes) + var/obj/item/bodypart/l_leg = get_bodypart(BODY_ZONE_L_LEG) + var/obj/item/bodypart/r_leg = get_bodypart(BODY_ZONE_R_LEG) + shoes.species_fitted = null if(istype(shoes, /obj/item/clothing/shoes)) var/obj/item/clothing/shoes/S = shoes if(S.adjusted == DIGITIGRADE_STYLE) target_overlay = "[target_overlay]_l" + if("GAGS_sprite" in S.sprite_sheets) + var/list/GAGS_species = S.sprite_sheets["GAGS_sprite"] + if((l_leg?.species_id == r_leg?.species_id) && (l_leg.species_id in GAGS_species)) + target_overlay += "_[l_leg.species_id]" + S.species_fitted = l_leg.species_id shoes.screen_loc = ui_shoes //move the item to the appropriate screen loc if(client && hud_used && hud_used.hud_shown) if(hud_used.inventory_shown) //if the inventory is open client.screen += shoes //add it to client's screen update_observer_view(shoes,1) - overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(default_layer = SHOES_LAYER, default_icon_file = 'icons/mob/clothing/feet/feet.dmi', override_state = target_overlay) + var/icon_to_use = DEFAULT_SHOES_FILE + if((l_leg?.species_id == r_leg?.species_id) && (l_leg.species_id in shoes.sprite_sheets)) + if(icon_exists(shoes.sprite_sheets[l_leg.species_id], shoes.icon_state)) + icon_to_use = shoes.sprite_sheets[l_leg.species_id] + shoes.species_fitted = l_leg.species_id + overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(default_layer = SHOES_LAYER, default_icon_file = icon_to_use, override_state = target_overlay) var/mutable_appearance/shoes_overlay = overlays_standing[SHOES_LAYER] if(OFFSET_SHOES in dna.species.offset_features) shoes_overlay.pixel_x += dna.species.offset_features[OFFSET_SHOES][1] @@ -380,18 +442,25 @@ There are several things that need to be remembered: /mob/living/carbon/human/update_inv_head() - ..() - update_mutant_bodyparts() + remove_overlay(HEAD_LAYER) + if(client && hud_used?.inv_slots[TOBITSHIFT(ITEM_SLOT_BACK) + 1]) + var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_HEAD) + 1] + inv.update_appearance(UPDATE_ICON) if(head) update_hud_head(head) - overlays_standing[HEAD_LAYER] = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/clothing/head/head.dmi') - var/mutable_appearance/head_overlay = overlays_standing[HEAD_LAYER] - if(head_overlay) - remove_overlay(HEAD_LAYER) + var/obj/item/bodypart/head/head_bodypart = get_bodypart(BODY_ZONE_HEAD) + var/icon_to_use = 'icons/mob/clothing/head/head.dmi' + head.species_fitted = null + if(head_bodypart?.species_id in head.sprite_sheets) + if(icon_exists(head.sprite_sheets[head_bodypart.species_id], head.icon_state)) + icon_to_use = head.sprite_sheets[head_bodypart.species_id] + head.species_fitted = head_bodypart.species_id + overlays_standing[HEAD_LAYER] = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = icon_to_use) + var/mutable_appearance/head_overlay = overlays_standing[HEAD_LAYER] if(OFFSET_HEAD in dna.species.offset_features) head_overlay.pixel_x += dna.species.offset_features[OFFSET_HEAD][1] head_overlay.pixel_y += dna.species.offset_features[OFFSET_HEAD][2] - overlays_standing[HEAD_LAYER] = head_overlay + update_mutant_bodyparts() apply_overlay(HEAD_LAYER) /mob/living/carbon/human/update_inv_belt() @@ -406,7 +475,14 @@ There are several things that need to be remembered: if(client && hud_used && hud_used.hud_shown) client.screen += belt update_observer_view(belt) - overlays_standing[BELT_LAYER] = belt.build_worn_icon(default_layer = BELT_LAYER, default_icon_file = 'icons/mob/clothing/belt.dmi') + var/obj/item/bodypart/chest/chest = get_bodypart(BODY_ZONE_CHEST) + var/icon_to_use = 'icons/mob/clothing/belt.dmi' + belt.species_fitted = null + if(chest?.species_id in belt.sprite_sheets) + if(icon_exists(belt.sprite_sheets[chest.species_id], belt.icon_state)) + icon_to_use = belt.sprite_sheets[chest.species_id] + belt.species_fitted = chest.species_id + overlays_standing[BELT_LAYER] = belt.build_worn_icon(default_layer = BELT_LAYER, default_icon_file = icon_to_use) var/mutable_appearance/belt_overlay = overlays_standing[BELT_LAYER] if(OFFSET_BELT in dna.species.offset_features) belt_overlay.pixel_x += dna.species.offset_features[OFFSET_BELT][1] @@ -433,7 +509,20 @@ There are several things that need to be remembered: if(client && hud_used && hud_used.hud_shown) if(hud_used.inventory_shown) client.screen += wear_suit - overlays_standing[SUIT_LAYER] = wear_suit.build_worn_icon(default_layer = SUIT_LAYER, default_icon_file = 'icons/mob/clothing/suit/suit.dmi', override_state = worn_suit_icon) + var/obj/item/bodypart/chest/chest = get_bodypart(BODY_ZONE_CHEST) + var/icon_to_use = DEFAULT_SUIT_FILE + S.species_fitted = null + var/obj/item/bodypart/l_leg = get_bodypart(BODY_ZONE_L_LEG) + var/obj/item/bodypart/r_leg = get_bodypart(BODY_ZONE_R_LEG) + if(l_leg?.species_id == r_leg?.species_id == SPECIES_VOX)//for Vox, it's the Vox legs that make regular sprites not fit + if(icon_exists(S.sprite_sheets[l_leg.species_id], S.icon_state)) + icon_to_use = S.sprite_sheets[l_leg.species_id] + S.species_fitted = l_leg.species_id + else if(chest?.species_id in S.sprite_sheets) + if(icon_exists(S.sprite_sheets[chest.species_id], S.icon_state)) + icon_to_use = S.sprite_sheets[chest.species_id] + S.species_fitted = chest.species_id + overlays_standing[SUIT_LAYER] = wear_suit.build_worn_icon(default_layer = SUIT_LAYER, default_icon_file = icon_to_use, override_state = worn_suit_icon) var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER] if(OFFSET_SUIT in dna.species.offset_features) suit_overlay.pixel_x += dna.species.offset_features[OFFSET_SUIT][1] @@ -487,7 +576,14 @@ There are several things that need to be remembered: target_overlay = "[target_overlay]_l" update_hud_wear_mask(wear_mask) if(!(head && (head.flags_inv & HIDEMASK))) - overlays_standing[FACEMASK_LAYER] = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/clothing/mask/mask.dmi', override_state = target_overlay) + var/obj/item/bodypart/head/head_bodypart = get_bodypart(BODY_ZONE_HEAD) + var/icon_to_use = 'icons/mob/clothing/mask/mask.dmi' + wear_mask.species_fitted = null + if(head_bodypart.species_id in wear_mask.sprite_sheets) + if(icon_exists(wear_mask.sprite_sheets[head_bodypart.species_id], wear_mask.icon_state)) + icon_to_use = wear_mask.sprite_sheets[head_bodypart.species_id] + wear_mask.species_fitted = head_bodypart.species_id + overlays_standing[FACEMASK_LAYER] = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = icon_to_use, override_state = target_overlay) var/mutable_appearance/mask_overlay = overlays_standing[FACEMASK_LAYER] if(mask_overlay) remove_overlay(FACEMASK_LAYER) @@ -507,7 +603,14 @@ There are several things that need to be remembered: if(back) update_hud_back(back) - overlays_standing[BACK_LAYER] = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = 'icons/mob/clothing/back.dmi') + var/obj/item/bodypart/chest/chest = get_bodypart(BODY_ZONE_CHEST) + var/icon_to_use = 'icons/mob/clothing/back.dmi' + back.species_fitted = null + if(chest?.species_id in back.sprite_sheets) + if(icon_exists(back.sprite_sheets[chest.species_id], back.icon_state)) + icon_to_use = back.sprite_sheets[chest.species_id] + back.species_fitted = chest.species_id + overlays_standing[BACK_LAYER] = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = icon_to_use) var/mutable_appearance/back_overlay = overlays_standing[BACK_LAYER] if(back_overlay) remove_overlay(BACK_LAYER) @@ -614,12 +717,16 @@ generate/load female uniform sprites matching all previously decided variables t_state = !isinhands ? (worn_icon_state ? worn_icon_state : icon_state) : (item_state ? item_state : icon_state) //Find a valid icon file from variables+arguments - var/file2use = !isinhands ? (worn_icon ? worn_icon : default_icon_file) : default_icon_file + var/file2use = default_icon_file + if(!isinhands && worn_icon) + if(!species_fitted || (species_fitted && greyscale_config)) + file2use = worn_icon //Find a valid layer from variables+arguments var/layer2use = alternate_worn_layer ? alternate_worn_layer : default_layer var/mob/living/carbon/human/H = loc + var/mutable_appearance/standing if(femaleuniform) if(HAS_TRAIT(H, TRAIT_SKINNY) && (H.underwear == "Nude")) @@ -680,12 +787,15 @@ generate/load female uniform sprites matching all previously decided variables . += "-coloured-[dna.species.forced_skintone]" else if(dna.species.fixed_mut_color) . += "-coloured-[dna.species.fixed_mut_color]" + else if(dna.species.get_icon_variant(src)) + . += "-limb-variant-[dna.species.get_icon_variant(src)]" else if(dna.features["mcolor"]) . += "-coloured-[dna.features["mcolor"]]" else . += "-not_coloured" - . += "-[gender]" + if(dna.species.is_dimorphic) + . += "-[gender]" for(var/X in bodyparts) var/obj/item/bodypart/BP = X @@ -701,6 +811,11 @@ generate/load female uniform sprites matching all previously decided variables . += "-digitigrade[BP.use_digitigrade]" if(BP.dmg_overlay_type) . += "-[BP.dmg_overlay_type]" + if(BP.has_static_sprite_part) + var/static_text = "-static" + if(BP.limb_icon_variant in dna.species.get_special_statics()) + static_text += "-special-[BP.limb_icon_variant]" + . += static_text if(HAS_TRAIT(src, TRAIT_HUSK)) . += "-husk" @@ -772,3 +887,4 @@ generate/load female uniform sprites matching all previously decided variables update_inv_wear_mask() #undef RESOLVE_ICON_STATE + diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm index 3c6c6731fd173..09ee7a2554b48 100644 --- a/code/modules/mob/living/carbon/update_icons.dm +++ b/code/modules/mob/living/carbon/update_icons.dm @@ -490,9 +490,9 @@ . += "-organic" else . += "-robotic" + if(BP.is_husked) + . += "-husk" - if(HAS_TRAIT(src, TRAIT_HUSK)) - . += "-husk" //change the mob's icon to the one matching its key diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 7bcec196672f3..2e1cfeaeb9c41 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -102,7 +102,7 @@ /obj/item/reagent_containers/blood/random/Initialize(mapload) icon_state = "bloodpack" - blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L") + blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L", "V") return ..() /obj/item/reagent_containers/blood/APlus diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm index ce5690cd7e5e6..9ea17d9001685 100644 --- a/code/modules/research/designs/limbgrower_designs.dm +++ b/code/modules/research/designs/limbgrower_designs.dm @@ -8,7 +8,7 @@ build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/synthflesh = 25) build_path = /obj/item/bodypart/l_arm - category = list("initial","human","lizard","fly","moth","plasmaman","polysmorph") + category = list("initial","human","lizard","fly","moth","plasmaman","polysmorph","vox") /datum/design/rightarm name = "Right Arm" @@ -16,7 +16,7 @@ build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/synthflesh = 25) build_path = /obj/item/bodypart/r_arm - category = list("initial","human","lizard","fly","moth","plasmaman","polysmorph") + category = list("initial","human","lizard","fly","moth","plasmaman","polysmorph","vox") /datum/design/leftleg name = "Left Leg" @@ -24,7 +24,7 @@ build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/synthflesh = 25) build_path = /obj/item/bodypart/l_leg - category = list("initial","human","lizard","fly","moth","plasmaman","polysmorph") + category = list("initial","human","lizard","fly","moth","plasmaman","polysmorph","vox") /datum/design/rightleg name = "Right Leg" @@ -32,7 +32,7 @@ build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/synthflesh = 25) build_path = /obj/item/bodypart/r_leg - category = list("initial","human","lizard","fly","moth","plasmaman","polysmorph") + category = list("initial","human","lizard","fly","moth","plasmaman","polysmorph","vox") /datum/design/digi_leftleg name = "Digitigrade Left Leg" diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 326707ee031cc..85cd95a2eb983 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -78,7 +78,7 @@ display_name = "Xeno-organ Biology" description = "Plasmaman, Ethereals, Lizardpeople... What makes our non-human crewmembers tick?" prereq_ids = list("adv_biotech") - design_ids = list("limbdesign_felinid", "limbdesign_lizard", "limbdesign_plasmaman", "limbdesign_ethereal", "limbdesign_polysmorph") + design_ids = list("limbdesign_felinid", "limbdesign_lizard", "limbdesign_plasmaman", "limbdesign_ethereal", "limbdesign_polysmorph", "limbdesign_vox") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) /datum/techweb_node/bio_process diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 579543f086c64..17325de1343ac 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -52,6 +52,7 @@ var/skin_tone = "" var/body_gender = "" var/species_id = "" + var/is_husked = FALSE var/should_draw_gender = FALSE var/should_draw_greyscale = FALSE var/species_color = "" @@ -824,16 +825,23 @@ no_update = TRUE else no_update = FALSE - + is_husked = FALSE if(HAS_TRAIT(C, TRAIT_HUSK) && is_organic_limb()) if(ishuman(C)) var/mob/living/carbon/human/S = C if(isszlachta(S)) return - species_id = "husk" //overrides species_id + var/datum/species/id_to_species + var/species_type = GLOB.species_list[species_id] + if(species_type) + id_to_species = new species_type() + if(id_to_species && !id_to_species.generate_husk_icon) + species_id = "husk" //overrides species_id + dmg_overlay_type = "" //no damage overlay shown when husked should_draw_gender = FALSE should_draw_greyscale = FALSE + is_husked = TRUE no_update = TRUE if(no_update) @@ -846,6 +854,14 @@ var/datum/species/S = H.dna.species if(!limb_override) species_id = S.limbs_id + var/datum/species/id_to_species + var/species_type = GLOB.species_list[species_id] + if(species_type) + id_to_species = new species_type() + if(id_to_species && (body_zone in id_to_species.static_part_body_zones)) + has_static_sprite_part = TRUE + else + has_static_sprite_part = FALSE species_flags_list = S.species_traits if(S.use_skintones) @@ -859,10 +875,13 @@ body_gender = H.gender - should_draw_gender = (FEMALE in S.possible_genders) + if(S.is_dimorphic) + should_draw_gender = (FEMALE in S.possible_genders) + limb_icon_variant = S.get_icon_variant(H) + limb_icon_file = S.limb_icon_file use_damage_color = S.use_damage_color - if((MUTCOLORS in S.species_traits) || (DYNCOLORS in S.species_traits)) + if((MUTCOLORS in S.species_traits) && !limb_icon_variant || (DYNCOLORS in S.species_traits)) if(S.fixed_mut_color) species_color = S.fixed_mut_color else @@ -918,6 +937,7 @@ . += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir) var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir) + var/image/limb_static var/image/aux . += limb @@ -934,8 +954,11 @@ return var/icon_gender = (body_gender == FEMALE) ? "f" : "m" //gender of the icon, if applicable - - if((body_zone != BODY_ZONE_HEAD && body_zone != BODY_ZONE_CHEST)) + var/datum/species/id_to_species + var/species_type = GLOB.species_list[species_id] + if(species_type) + id_to_species = new species_type() + if(((body_zone != BODY_ZONE_HEAD && body_zone != BODY_ZONE_CHEST )) || (id_to_species && !id_to_species.is_dimorphic)) should_draw_gender = FALSE if(status == BODYPART_ORGANIC || (status == BODYPART_ROBOTIC && render_like_organic == TRUE)) // So IPC augments can be colorful without disrupting normal BODYPART_ROBOTIC render code. @@ -953,15 +976,25 @@ else limb.icon_state = "[species_id]_[body_zone]" else - limb.icon = 'yogstation/icons/mob/human_parts.dmi' // yogs -- use yogs icon instead of tg, gorilla people + limb.icon = limb_icon_file || 'yogstation/icons/mob/human_parts.dmi' // yogs -- use yogs icon instead of tg, gorilla people if(should_draw_gender) limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" else limb.icon_state = "[species_id]_[body_zone]" + if(limb_icon_variant) + limb.icon_state += "_[limb_icon_variant]" if(aux_zone) - aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir) + var/aux_icon_name = "[species_id]_[aux_zone]_[limb_icon_variant]" + if(!icon_exists(limb.icon, "[aux_icon_name]")) + aux_icon_name = "[species_id]_[aux_zone]" + aux = image(limb.icon, aux_icon_name, -aux_layer, image_dir) . += aux - + if(has_static_sprite_part) + var/limb_static_icon_name = "[species_id]_[body_zone]_static" + if(id_to_species && (limb_icon_variant in id_to_species.get_special_statics())) + limb_static_icon_name += "_[limb_icon_variant]" + limb_static = image(limb.icon, limb_static_icon_name, limb.layer, limb.dir) + . += limb_static else limb.icon = icon if(should_draw_gender) @@ -977,13 +1010,34 @@ . += aux return - + var/draw_color if(should_draw_greyscale) - var/draw_color = mutation_color || species_color || (skin_tone && skintone2hex(skin_tone)) - if(draw_color) - limb.color = "[draw_color]" - if(aux_zone) - aux.color = "[draw_color]" + draw_color = mutation_color || species_color || (skin_tone && skintone2hex(skin_tone)) + + if(is_husked) + huskify_image(limb, owner, TRUE, id_to_species) + if(aux) + huskify_image(aux, owner, TRUE, id_to_species) + if(limb_static) + huskify_image(limb_static, owner, TRUE, id_to_species) + draw_color = id_to_species?.husk_color || owner?.dna?.species?.husk_color + + if(draw_color) + limb.color = "[draw_color]" + if(aux_zone) + aux.color = "[draw_color]" + +/proc/huskify_image(image/thing_to_husk, mob/living/carbon/husked_guy, draw_blood = TRUE, datum/species/passed_species) + var/husk_color_mod = rgb(96, 88, 80) + var/icon/husk_icon = new(thing_to_husk.icon) + husk_icon.ColorTone(husk_color_mod) + thing_to_husk.icon = husk_icon + var/icon_of_husk = husked_guy?.dna?.species?.icon_husk || passed_species?.icon_husk + if(draw_blood) + var/mutable_appearance/husk_blood = mutable_appearance(icon_of_husk || 'yogstation/icons/mob/human_parts.dmi', "overlay_[husked_guy?.dna?.species?.id || passed_species?.id]husk", appearance_flags = RESET_COLOR) + husk_blood.blend_mode = BLEND_INSET_OVERLAY + husk_blood.dir = thing_to_husk.dir + thing_to_husk.add_overlay(husk_blood) /obj/item/bodypart/deconstruct(disassembled = TRUE) drop_organs() diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index a4de79fd173ba..af39d0dfa9e6f 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -22,7 +22,7 @@ var/obj/item/organ/eyes/eyes var/obj/item/organ/ears/ears var/obj/item/organ/tongue/tongue - + var/eyes_icon = 'icons/mob/human_face.dmi' //Limb appearance info: var/real_name = "" //Replacement name //Hair colour and style @@ -190,6 +190,10 @@ else hair_color = "000" hair_alpha = initial(hair_alpha) + if(HAIRCOLOR in S.species_traits) + hair_color = H.hair_color + if(FACEHAIRCOLOR in S.species_traits) + facial_hair_color = H.facial_hair_color // lipstick if(H.lip_style && (LIPS in S.species_traits)) lip_style = H.lip_style @@ -197,6 +201,9 @@ else lip_style = null lip_color = "white" + if(S.eyes_icon) + eyes_icon = S.eyes_icon + eyes_static = S.get_eyes_static(H) ..() /obj/item/bodypart/head/update_icon_dropped() @@ -253,13 +260,17 @@ . += lips_overlay // eyes - var/image/eyes_overlay = image('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER, SOUTH) + var/image/eyes_overlay = image(eyes_icon, "eyes_missing", -BODY_LAYER, SOUTH) . += eyes_overlay if(eyes) eyes_overlay.icon_state = eyes.eye_icon_state - if(eyes.eye_color) eyes_overlay.color = eyes.eye_color + if(eyes_static) + var/mutable_appearance/eyes_static_sprite = mutable_appearance(eyes_overlay.icon, "[eyes_overlay.icon_state]_static_[eyes_static]", eyes_overlay.layer) + eyes_static_sprite.dir = eyes_overlay.dir + eyes_static_sprite.appearance_flags |= RESET_COLOR + eyes_overlay.add_overlay(eyes_static_sprite) /obj/item/bodypart/head/monkey icon = 'icons/mob/animal_parts.dmi' diff --git a/code/modules/surgery/organs/appendix.dm b/code/modules/surgery/organs/appendix.dm index e45511648e94d..8c0baea181ce7 100644 --- a/code/modules/surgery/organs/appendix.dm +++ b/code/modules/surgery/organs/appendix.dm @@ -13,16 +13,16 @@ /obj/item/organ/appendix/update_name(updates=ALL) . = ..() if(inflamed) - name = "inflamed appendix" + name = "inflamed [initial(name)]" else - name = "appendix" + name = initial(name) /obj/item/organ/appendix/update_icon_state() . = ..() if(inflamed) - icon_state = "appendixinflamed" + icon_state = "[initial(icon_state)]inflamed" else - icon_state = "appendix" + icon_state = initial(icon_state) /obj/item/organ/appendix/on_life() ..() diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 468ccea83bf29..7c8af8cdc31a4 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -94,16 +94,20 @@ /obj/item/organ/eyes/proc/generate_body_overlay(mob/living/carbon/human/parent) if(!istype(parent) || parent.getorgan(/obj/item/organ/eyes) != src) CRASH("Generating a body overlay for [src] targeting an invalid parent '[parent]'.") - - var/mutable_appearance/eye_overlay = mutable_appearance('icons/mob/human_face.dmi', eye_icon_state, -BODY_LAYER) + var/obj/item/bodypart/head/head = parent.get_bodypart(BODY_ZONE_HEAD) + var/mutable_appearance/eye_overlay = mutable_appearance(head.eyes_icon, eye_icon_state, -BODY_LAYER) var/list/overlays = list(eye_overlay) if((EYECOLOR in parent.dna.species.species_traits)) eye_overlay.color = eye_color + if(head.eyes_static) + var/mutable_appearance/eyes_static_sprite = mutable_appearance(eye_overlay.icon, "[eye_overlay.icon_state]_static_[head.eyes_static]", eye_overlay.layer, appearance_flags = RESET_COLOR) + eye_overlay.add_overlay(eyes_static_sprite) + // Cry emote overlay - if (HAS_TRAIT(parent, TRAIT_CRYING)) // Caused by the *cry emote - var/mutable_appearance/tears_overlay = mutable_appearance('icons/mob/human_face.dmi', "tears", -BODY_ADJ_LAYER) + if(HAS_TRAIT(parent, TRAIT_CRYING)) // Caused by the *cry emote + var/mutable_appearance/tears_overlay = mutable_appearance(head.eyes_icon, "tears", -BODY_ADJ_LAYER) tears_overlay.color = COLOR_DARK_CYAN overlays += tears_overlay diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 35d93c8863dea..526b2cb6046fe 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -117,6 +117,17 @@ alert_type = alert["alert_type"] if(alert_category) H.throw_alert(alert_category, alert_type) + var/list/too_much_gas_alerts = list() + for(var/gas in gas_max) + var/gas_alert_category + if(ispath(gas)) + var/datum/breathing_class/breathclass = gas + gas_alert_category = breathclass.high_alert_category + else + gas_alert_category = GLOB.gas_data.breath_alert_info[gas]["too_much_alert"]["alert_category"] + too_much_gas_alerts += gas_alert_category + for(var/alert as anything in too_much_gas_alerts) + H.clear_alert(alert) return FALSE #define PP_MOLES(X) ((X / total_moles) * pressure) diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index 92b50110451d1..3db5fb0b582af 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -29,6 +29,7 @@ /datum/language/japanese, /datum/language/machine, //yogs /datum/language/darkspawn, //also yogs + /datum/language/vox, /datum/language/encrypted, /datum/language/felinid, /datum/language/english, diff --git a/config/game_options.txt b/config/game_options.txt index 3d919ac808919..e8d5a9a5c87b6 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -19,10 +19,10 @@ REVIVAL_BRAIN_LIFE -1 JOB_SPECIES_WHITELIST /datum/job/captain human JOB_SPECIES_WHITELIST /datum/job/hop human,lizard,plasmaman,ipc -JOB_SPECIES_WHITELIST /datum/job/hos human,lizard,pod,preternis,polysmorph -JOB_SPECIES_WHITELIST /datum/job/chief_engineer human,lizard,pod,plasmaman,moth,ethereal,preternis,polysmorph,ipc -JOB_SPECIES_WHITELIST /datum/job/rd human,lizard,pod,plasmaman,moth,ethereal,preternis,polysmorph,ipc -JOB_SPECIES_WHITELIST /datum/job/cmo human,lizard,pod,plasmaman,moth,ethereal,preternis,polysmorph,ipc +JOB_SPECIES_WHITELIST /datum/job/hos human,lizard,pod,preternis,polysmorph,vox +JOB_SPECIES_WHITELIST /datum/job/chief_engineer human,lizard,pod,plasmaman,moth,ethereal,preternis,polysmorph,ipc,vox +JOB_SPECIES_WHITELIST /datum/job/rd human,lizard,pod,plasmaman,moth,ethereal,preternis,polysmorph,ipc,vox +JOB_SPECIES_WHITELIST /datum/job/cmo human,lizard,pod,plasmaman,moth,ethereal,preternis,polysmorph,ipc,vox ## OOC DURING ROUND ### @@ -562,6 +562,7 @@ ROUNDSTART_RACES preternis ROUNDSTART_RACES polysmorph #ROUNDSTART_RACES snail ROUNDSTART_RACES ipc +ROUNDSTART_RACES vox ## Races that are better than humans in some ways, but worse in others ROUNDSTART_RACES ethereal diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi index 483ab04442334..63b8a39a11900 100644 Binary files a/icons/effects/blood.dmi and b/icons/effects/blood.dmi differ diff --git a/icons/effects/crayondecal.dmi b/icons/effects/crayondecal.dmi index c9e7f880c8092..d1f9461a20433 100755 Binary files a/icons/effects/crayondecal.dmi and b/icons/effects/crayondecal.dmi differ diff --git a/icons/effects/creampie.dmi b/icons/effects/creampie.dmi index 6caecf7d767c3..bdb39e5698ff7 100644 Binary files a/icons/effects/creampie.dmi and b/icons/effects/creampie.dmi differ diff --git a/icons/misc/language.dmi b/icons/misc/language.dmi index 86e8a0aeacb41..188d9b834227e 100644 Binary files a/icons/misc/language.dmi and b/icons/misc/language.dmi differ diff --git a/icons/mob/butts.dmi b/icons/mob/butts.dmi index ae4b41961a1cd..fb14886ba10a4 100644 Binary files a/icons/mob/butts.dmi and b/icons/mob/butts.dmi differ diff --git a/icons/mob/clothing/feet/feet.dmi b/icons/mob/clothing/feet/feet.dmi index b6a4e7dc80fde..44cd673724a93 100644 Binary files a/icons/mob/clothing/feet/feet.dmi and b/icons/mob/clothing/feet/feet.dmi differ diff --git a/icons/mob/clothing/head/head.dmi b/icons/mob/clothing/head/head.dmi index 40c4208387301..6710eb3d925f8 100644 Binary files a/icons/mob/clothing/head/head.dmi and b/icons/mob/clothing/head/head.dmi differ diff --git a/icons/mob/clothing/species/vox/back.dmi b/icons/mob/clothing/species/vox/back.dmi new file mode 100644 index 0000000000000..9288778584d1a Binary files /dev/null and b/icons/mob/clothing/species/vox/back.dmi differ diff --git a/icons/mob/clothing/species/vox/collar.dmi b/icons/mob/clothing/species/vox/collar.dmi new file mode 100644 index 0000000000000..6c442c62f7751 Binary files /dev/null and b/icons/mob/clothing/species/vox/collar.dmi differ diff --git a/icons/mob/clothing/species/vox/ears.dmi b/icons/mob/clothing/species/vox/ears.dmi new file mode 100644 index 0000000000000..cd43d1a1893a7 Binary files /dev/null and b/icons/mob/clothing/species/vox/ears.dmi differ diff --git a/icons/mob/clothing/species/vox/eyes.dmi b/icons/mob/clothing/species/vox/eyes.dmi new file mode 100644 index 0000000000000..5962060f0d23e Binary files /dev/null and b/icons/mob/clothing/species/vox/eyes.dmi differ diff --git a/icons/mob/clothing/species/vox/gloves.dmi b/icons/mob/clothing/species/vox/gloves.dmi new file mode 100644 index 0000000000000..4ac7a044f2f02 Binary files /dev/null and b/icons/mob/clothing/species/vox/gloves.dmi differ diff --git a/icons/mob/clothing/species/vox/head.dmi b/icons/mob/clothing/species/vox/head.dmi new file mode 100644 index 0000000000000..7e4d425a948e0 Binary files /dev/null and b/icons/mob/clothing/species/vox/head.dmi differ diff --git a/icons/mob/clothing/species/vox/held.dmi b/icons/mob/clothing/species/vox/held.dmi new file mode 100644 index 0000000000000..973f8aa94cccb Binary files /dev/null and b/icons/mob/clothing/species/vox/held.dmi differ diff --git a/icons/mob/clothing/species/vox/helmet.dmi b/icons/mob/clothing/species/vox/helmet.dmi new file mode 100644 index 0000000000000..a36767b34a282 Binary files /dev/null and b/icons/mob/clothing/species/vox/helmet.dmi differ diff --git a/icons/mob/clothing/species/vox/mask.dmi b/icons/mob/clothing/species/vox/mask.dmi new file mode 100644 index 0000000000000..4653947806427 Binary files /dev/null and b/icons/mob/clothing/species/vox/mask.dmi differ diff --git a/icons/mob/clothing/species/vox/shoes.dmi b/icons/mob/clothing/species/vox/shoes.dmi new file mode 100644 index 0000000000000..eba8a11aa2ee9 Binary files /dev/null and b/icons/mob/clothing/species/vox/shoes.dmi differ diff --git a/icons/mob/clothing/species/vox/socks.dmi b/icons/mob/clothing/species/vox/socks.dmi new file mode 100644 index 0000000000000..e9e433a82db6b Binary files /dev/null and b/icons/mob/clothing/species/vox/socks.dmi differ diff --git a/icons/mob/clothing/species/vox/suit.dmi b/icons/mob/clothing/species/vox/suit.dmi new file mode 100644 index 0000000000000..ccf234e740ea9 Binary files /dev/null and b/icons/mob/clothing/species/vox/suit.dmi differ diff --git a/icons/mob/clothing/species/vox/undershirt.dmi b/icons/mob/clothing/species/vox/undershirt.dmi new file mode 100644 index 0000000000000..b43f2ed8cd124 Binary files /dev/null and b/icons/mob/clothing/species/vox/undershirt.dmi differ diff --git a/icons/mob/clothing/species/vox/underwear.dmi b/icons/mob/clothing/species/vox/underwear.dmi new file mode 100644 index 0000000000000..81fb752d12e27 Binary files /dev/null and b/icons/mob/clothing/species/vox/underwear.dmi differ diff --git a/icons/mob/clothing/species/vox/uniform.dmi b/icons/mob/clothing/species/vox/uniform.dmi new file mode 100644 index 0000000000000..cd8bb9bee358d Binary files /dev/null and b/icons/mob/clothing/species/vox/uniform.dmi differ diff --git a/icons/mob/clothing/suit/suit.dmi b/icons/mob/clothing/suit/suit.dmi index e796e64a1e664..a41781c796743 100644 Binary files a/icons/mob/clothing/suit/suit.dmi and b/icons/mob/clothing/suit/suit.dmi differ diff --git a/icons/mob/clothing/uniform/color.dmi b/icons/mob/clothing/uniform/color.dmi index 9b06725cbba7e..4e63fcd41719f 100644 Binary files a/icons/mob/clothing/uniform/color.dmi and b/icons/mob/clothing/uniform/color.dmi differ diff --git a/icons/mob/corgi_head.dmi b/icons/mob/corgi_head.dmi index a525a36c2d461..7c610b8007761 100644 Binary files a/icons/mob/corgi_head.dmi and b/icons/mob/corgi_head.dmi differ diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi index 63284a0012f27..2a5ee78d27cb3 100644 Binary files a/icons/mob/human.dmi and b/icons/mob/human.dmi differ diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index dd22f1dc5bc42..dcc27abd3c09b 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/inhands/equipment/tanks_lefthand.dmi b/icons/mob/inhands/equipment/tanks_lefthand.dmi index 47f9e4be647b2..b07ed1e5d5307 100644 Binary files a/icons/mob/inhands/equipment/tanks_lefthand.dmi and b/icons/mob/inhands/equipment/tanks_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/tanks_righthand.dmi b/icons/mob/inhands/equipment/tanks_righthand.dmi index 2de83e274a256..84ffef493adee 100644 Binary files a/icons/mob/inhands/equipment/tanks_righthand.dmi and b/icons/mob/inhands/equipment/tanks_righthand.dmi differ diff --git a/icons/mob/inhands/flags_lefthand.dmi b/icons/mob/inhands/flags_lefthand.dmi new file mode 100644 index 0000000000000..6b5c936dcc8d6 Binary files /dev/null and b/icons/mob/inhands/flags_lefthand.dmi differ diff --git a/icons/mob/inhands/flags_righthand.dmi b/icons/mob/inhands/flags_righthand.dmi new file mode 100644 index 0000000000000..85088c7a8df59 Binary files /dev/null and b/icons/mob/inhands/flags_righthand.dmi differ diff --git a/icons/mob/inhands/misc/food_lefthand.dmi b/icons/mob/inhands/misc/food_lefthand.dmi index c58a87284eb39..02281580dd52d 100644 Binary files a/icons/mob/inhands/misc/food_lefthand.dmi and b/icons/mob/inhands/misc/food_lefthand.dmi differ diff --git a/icons/mob/inhands/misc/food_righthand.dmi b/icons/mob/inhands/misc/food_righthand.dmi index 186dc8d55537e..a7690f04eed83 100644 Binary files a/icons/mob/inhands/misc/food_righthand.dmi and b/icons/mob/inhands/misc/food_righthand.dmi differ diff --git a/icons/mob/species/vox/body_markings.dmi b/icons/mob/species/vox/body_markings.dmi new file mode 100644 index 0000000000000..0a6b23ed2e1e4 Binary files /dev/null and b/icons/mob/species/vox/body_markings.dmi differ diff --git a/icons/mob/species/vox/bodyparts.dmi b/icons/mob/species/vox/bodyparts.dmi new file mode 100644 index 0000000000000..99a579d462cf7 Binary files /dev/null and b/icons/mob/species/vox/bodyparts.dmi differ diff --git a/icons/mob/species/vox/eyes.dmi b/icons/mob/species/vox/eyes.dmi new file mode 100644 index 0000000000000..64ec6f77ec629 Binary files /dev/null and b/icons/mob/species/vox/eyes.dmi differ diff --git a/icons/mob/species/vox/facial_quills.dmi b/icons/mob/species/vox/facial_quills.dmi new file mode 100644 index 0000000000000..b4a79df754ba0 Binary files /dev/null and b/icons/mob/species/vox/facial_quills.dmi differ diff --git a/icons/mob/species/vox/quills.dmi b/icons/mob/species/vox/quills.dmi new file mode 100644 index 0000000000000..da5af684da145 Binary files /dev/null and b/icons/mob/species/vox/quills.dmi differ diff --git a/icons/mob/species/vox/tail_markings.dmi b/icons/mob/species/vox/tail_markings.dmi new file mode 100644 index 0000000000000..69f372ddcb9ed Binary files /dev/null and b/icons/mob/species/vox/tail_markings.dmi differ diff --git a/icons/mob/species/vox/tails.dmi b/icons/mob/species/vox/tails.dmi new file mode 100644 index 0000000000000..ae23a1fae9ae0 Binary files /dev/null and b/icons/mob/species/vox/tails.dmi differ diff --git a/icons/obj/assemblies.dmi b/icons/obj/assemblies.dmi index 25d4a2a9cac04..c66dba6228275 100644 Binary files a/icons/obj/assemblies.dmi and b/icons/obj/assemblies.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 01d73a179eec4..e5bb9f997b55a 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/species/vox/gloves.dmi b/icons/obj/clothing/species/vox/gloves.dmi new file mode 100644 index 0000000000000..eeca4b63f30b2 Binary files /dev/null and b/icons/obj/clothing/species/vox/gloves.dmi differ diff --git a/icons/obj/clothing/species/vox/hats.dmi b/icons/obj/clothing/species/vox/hats.dmi new file mode 100644 index 0000000000000..922ede57f1afd Binary files /dev/null and b/icons/obj/clothing/species/vox/hats.dmi differ diff --git a/icons/obj/clothing/species/vox/shoes.dmi b/icons/obj/clothing/species/vox/shoes.dmi new file mode 100644 index 0000000000000..a1dde383ff727 Binary files /dev/null and b/icons/obj/clothing/species/vox/shoes.dmi differ diff --git a/icons/obj/clothing/species/vox/suits.dmi b/icons/obj/clothing/species/vox/suits.dmi new file mode 100644 index 0000000000000..4dc0ade4fb89c Binary files /dev/null and b/icons/obj/clothing/species/vox/suits.dmi differ diff --git a/icons/obj/clothing/species/vox/uniforms.dmi b/icons/obj/clothing/species/vox/uniforms.dmi new file mode 100644 index 0000000000000..4bf1b92308d09 Binary files /dev/null and b/icons/obj/clothing/species/vox/uniforms.dmi differ diff --git a/icons/obj/clothing/suits/suits.dmi b/icons/obj/clothing/suits/suits.dmi index bfe2f6a535d3d..e646f0eb2016d 100644 Binary files a/icons/obj/clothing/suits/suits.dmi and b/icons/obj/clothing/suits/suits.dmi differ diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi index 8ed868f984c64..8f069529592ba 100644 Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ diff --git a/icons/obj/flag.dmi b/icons/obj/flag.dmi new file mode 100644 index 0000000000000..a311c47f8840d Binary files /dev/null and b/icons/obj/flag.dmi differ diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi index 310033272db2d..495105e65e45c 100644 Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi index 82665c089b15a..a66158ffde33e 100644 Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi index ce2743612a4da..d88ae0e3504d3 100644 Binary files a/icons/obj/stack_objects.dmi and b/icons/obj/stack_objects.dmi differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index a728c79817a94..e779a3f2e0b76 100755 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ diff --git a/sound/effects/voxrustle.ogg b/sound/effects/voxrustle.ogg new file mode 100644 index 0000000000000..fe400fc5dd181 Binary files /dev/null and b/sound/effects/voxrustle.ogg differ diff --git a/sound/voice/vox/ashriek.ogg b/sound/voice/vox/ashriek.ogg new file mode 100644 index 0000000000000..125ba868fdbf4 Binary files /dev/null and b/sound/voice/vox/ashriek.ogg differ diff --git a/sound/voice/vox/shriek1.ogg b/sound/voice/vox/shriek1.ogg new file mode 100644 index 0000000000000..bb13db1ca0ee6 Binary files /dev/null and b/sound/voice/vox/shriek1.ogg differ diff --git a/sound/voice/vox/shriekcough.ogg b/sound/voice/vox/shriekcough.ogg new file mode 100644 index 0000000000000..15dc2e3873cbd Binary files /dev/null and b/sound/voice/vox/shriekcough.ogg differ diff --git a/sound/voice/vox/shrieksneeze.ogg b/sound/voice/vox/shrieksneeze.ogg new file mode 100644 index 0000000000000..9b1a5d1cca735 Binary files /dev/null and b/sound/voice/vox/shrieksneeze.ogg differ diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx index e25bec52472c3..f4a6ae3e5fbe9 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx @@ -78,7 +78,7 @@ export const CharacterPreferenceWindow = (props, context) => { diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx index e53f1b3ee5c85..9fd6b472df2e2 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx @@ -341,7 +341,11 @@ const createSetRandomization = ( const sortPreferences = sortBy<[string, unknown]>( ([featureId, _]) => { const feature = features[featureId]; - return feature?.name; + if (feature?.sortingPrefix) { + return feature.sortingPrefix + feature.name; + } else { + return feature?.name; + } }); const PreferenceList = (props: { diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx index 0800d809c5fd8..75487daff1794 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx @@ -22,6 +22,7 @@ export type Feature< >; category?: string; description?: string; + sortingPrefix?: string; }; /** diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx index 3ee93eb571bd3..e6b47438e0362 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skin_tone.tsx @@ -2,17 +2,17 @@ import { sortBy } from "common/collections"; import { Box, Stack } from "../../../../../components"; import { Feature, FeatureChoicedServerData, FeatureValueProps, StandardizedDropdown } from "../base"; -type HexValue = { +export type HexValue = { lightness: number, value: string, }; -type SkinToneServerData = FeatureChoicedServerData & { +export type SkinToneServerData = FeatureChoicedServerData & { display_names: NonNullable, to_hex: Record, }; -const sortHexValues +export const sortHexValues = sortBy<[string, HexValue]>(([_, hexValue]) => -hexValue.lightness); export const skin_tone: Feature = { 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 51171da675986..8a8fc54c19872 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx @@ -1,7 +1,11 @@ -import { FeatureColorInput, Feature, FeatureChoiced, FeatureDropdownInput } from "./base"; +import { Box, Stack } from "../../../../components"; +import { FeatureColorInput, FeatureChoicedServerData, FeatureValueProps, StandardizedDropdown, Feature, FeatureChoiced, FeatureDropdownInput } from "./base"; +import { SkinToneServerData } from "./character_preferences/skin_tone"; +import { sortHexValues } from "./character_preferences/skin_tone"; export const eye_color: Feature = { - name: "Eye color", + name: "Eye Color", + sortingPrefix: "aaaa", component: FeatureColorInput, }; @@ -50,6 +54,45 @@ export const feature_mcolor: Feature = { component: FeatureColorInput, }; +export const feature_mcolor_secondary: Feature = { + name: "Secondary Mutant color", + component: FeatureColorInput, +}; + +export const feature_quill_color: Feature = { + name: "Quill Color", + component: FeatureColorInput, +}; + +export const feature_facial_quill_color: Feature = { + name: "Facial Quill Color", + component: FeatureColorInput, +}; + +export const feature_quill_gradientstyle: FeatureChoiced = { + name: "Quill Gradient", + sortingPrefix: "v1", + component: FeatureDropdownInput, +}; + +export const feature_quill_gradientcolor: Feature = { + name: "Quill Gradient Color", + sortingPrefix: "v2", + component: FeatureColorInput, +}; + +export const feature_body_markings_color: Feature = { + name: "Body Markings Color", + sortingPrefix: "v6", + component: FeatureColorInput, +}; + +export const feature_tail_markings_color: Feature = { + name: "Tail Markings Color", + sortingPrefix: "v4", + component: FeatureColorInput, +}; + export const feature_ipc_screen: FeatureChoiced = { name: "Screen", component: FeatureDropdownInput, @@ -134,3 +177,100 @@ export const feature_preternis_eye: FeatureChoiced = { name: "Eye", component: FeatureDropdownInput, }; + +export const feature_vox_quills: FeatureChoiced = { + name: 'Quillstyle', + component: FeatureDropdownInput, +}; + +export const feature_vox_facial_quills: FeatureChoiced = { + name: 'Facial Quillstyle', + component: FeatureDropdownInput, +}; + +export const feature_vox_tail_markings: FeatureChoiced = { + name: 'Tail Markings', + sortingPrefix: "v3", + component: FeatureDropdownInput, +}; + +export const feature_vox_body_markings: FeatureChoiced = { + name: 'Body Markings', + sortingPrefix: "v5", + component: FeatureDropdownInput, +}; + +export const feature_vox_skin_tone: Feature = { + name: "Skin Tone", + sortingPrefix: "a", + component: (props: FeatureValueProps) => { + const { + handleSetValue, + serverData, + value, + } = props; + + if (!serverData) { + return null; + } + + return ( + key)} + displayNames={Object.fromEntries( + Object.entries(serverData.display_names) + .map(([key, displayName]) => { + const hexColor = serverData.to_hex[key]; + + return [key, ( + + + + + + + {displayName} + + + )]; + }) + )} + onSetValue={handleSetValue} + value={value} + /> + ); + }, +}; + +export const feature_vox_underwear: FeatureChoiced = { + name: 'Underwear', + component: FeatureDropdownInput, +}; + +export const feature_vox_socks: FeatureChoiced = { + name: 'Socks', + component: FeatureDropdownInput, +}; + +export const feature_vox_undershirt: FeatureChoiced = { + name: 'Undershirt', + component: FeatureDropdownInput, +}; + +export const feature_vox_tank_type: FeatureChoiced = { + name: 'N² Tank', + component: FeatureDropdownInput, +}; + +export const feature_vox_mask: FeatureChoiced = { + name: 'Mask', + component: FeatureDropdownInput, +}; diff --git a/yogstation.dme b/yogstation.dme index 248ebfefdb6de..41d59cdfd67cc 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -143,6 +143,7 @@ #include "code\__DEFINES\space.dm" #include "code\__DEFINES\spaceman_dmm.dm" #include "code\__DEFINES\span.dm" +#include "code\__DEFINES\species_clothing_paths.dm" #include "code\__DEFINES\speech_channels.dm" #include "code\__DEFINES\stat.dm" #include "code\__DEFINES\stat_tracking.dm" @@ -226,6 +227,7 @@ #include "code\__DEFINES\{yogs_defines}\admin.dm" #include "code\__DEFINES\{yogs_defines}\antagonists.dm" #include "code\__DEFINES\{yogs_defines}\atmospherics.dm" +#include "code\__DEFINES\{yogs_defines}\colors.dm" #include "code\__DEFINES\{yogs_defines}\components.dm" #include "code\__DEFINES\{yogs_defines}\darkspawn.dm" #include "code\__DEFINES\{yogs_defines}\DNA.dm" @@ -244,6 +246,7 @@ #include "code\__DEFINES\{yogs_defines}\reactions.dm" #include "code\__DEFINES\{yogs_defines}\shuttles.dm" #include "code\__DEFINES\{yogs_defines}\spacepods.dm" +#include "code\__DEFINES\{yogs_defines}\species_clothing_paths.dm" #include "code\__DEFINES\{yogs_defines}\status_effects.dm" #include "code\__DEFINES\{yogs_defines}\telecomms.dm" #include "code\__DEFINES\{yogs_defines}\traits.dm" @@ -4013,6 +4016,7 @@ #include "yogstation\code\__HELPERS\unsorted.dm" #include "yogstation\code\_globalvars\configuration.dm" #include "yogstation\code\_globalvars\logging.dm" +#include "yogstation\code\_globalvars\lists\flavor_misc.dm" #include "yogstation\code\_globalvars\lists\game.dm" #include "yogstation\code\_globalvars\lists\mentors.dm" #include "yogstation\code\_globalvars\lists\names.dm" @@ -4029,6 +4033,9 @@ #include "yogstation\code\controllers\subsystem\yogs.dm" #include "yogstation\code\controllers\subsystem\processing\quirks.dm" #include "yogstation\code\datums\action.dm" +#include "yogstation\code\datums\blood_types.dm" +#include "yogstation\code\datums\dog_fashion.dm" +#include "yogstation\code\datums\emotes.dm" #include "yogstation\code\datums\mind.dm" #include "yogstation\code\datums\mutations.dm" #include "yogstation\code\datums\shuttles.dm" @@ -4067,6 +4074,7 @@ #include "yogstation\code\datums\ruins\station.dm" #include "yogstation\code\datums\status_effects\buffs.dm" #include "yogstation\code\datums\status_effects\neutral.dm" +#include "yogstation\code\datums\traits\good.dm" #include "yogstation\code\datums\wires\disposals.dm" #include "yogstation\code\datums\wires\smartfridge.dm" #include "yogstation\code\game\communications.dm" @@ -4122,6 +4130,8 @@ #include "yogstation\code\game\mecha\mecha_wreckage.dm" #include "yogstation\code\game\mecha\makeshift\lockermech.dm" #include "yogstation\code\game\mecha\makeshift\makeshift_tools.dm" +#include "yogstation\code\game\objects\items.dm" +#include "yogstation\code\game\objects\objs.dm" #include "yogstation\code\game\objects\effects\contraband.dm" #include "yogstation\code\game\objects\effects\countdown.dm" #include "yogstation\code\game\objects\effects\landmarks.dm" @@ -4140,6 +4150,7 @@ #include "yogstation\code\game\objects\items\crayons.dm" #include "yogstation\code\game\objects\items\dna_injector.dm" #include "yogstation\code\game\objects\items\extinguisher.dm" +#include "yogstation\code\game\objects\items\flag.dm" #include "yogstation\code\game\objects\items\fryingpan.dm" #include "yogstation\code\game\objects\items\manuals.dm" #include "yogstation\code\game\objects\items\plushes.dm" @@ -4148,6 +4159,7 @@ #include "yogstation\code\game\objects\items\tool_switcher.dm" #include "yogstation\code\game\objects\items\tools.dm" #include "yogstation\code\game\objects\items\toys.dm" +#include "yogstation\code\game\objects\items\trash.dm" #include "yogstation\code\game\objects\items\weaponry.dm" #include "yogstation\code\game\objects\items\circuitboards\computer_circuitboards.dm" #include "yogstation\code\game\objects\items\circuitboards\machine_circuitboards.dm" @@ -4182,6 +4194,7 @@ #include "yogstation\code\game\objects\items\storage\mre.dm" #include "yogstation\code\game\objects\items\storage\toolbox.dm" #include "yogstation\code\game\objects\items\storage\uplink_kits.dm" +#include "yogstation\code\game\objects\items\tanks\tank_types.dm" #include "yogstation\code\game\objects\items\wielded\big_spoon.dm" #include "yogstation\code\game\objects\items\wielded\sledgehammer.dm" #include "yogstation\code\game\objects\items\wielded\vxtvulhammer.dm" @@ -4198,8 +4211,10 @@ #include "yogstation\code\game\objects\structures\bar_stuff\bar_stuff.dm" #include "yogstation\code\game\objects\structures\beds_chairs\chair.dm" #include "yogstation\code\game\objects\structures\beds_chairs\electric_bed.dm" +#include "yogstation\code\game\objects\structures\signs\_signs.dm" #include "yogstation\code\game\objects\structures\signs\signs_plaques.dm" #include "yogstation\code\game\turfs\change_turf.dm" +#include "yogstation\code\game\turfs\open\floor\plating\asteroid.dm" #include "yogstation\code\game\turfs\simulated\ballpit.dm" #include "yogstation\code\game\turfs\simulated\minerals.dm" #include "yogstation\code\game\turfs\simulated\floor\fancy_floor.dm" @@ -4226,6 +4241,7 @@ #include "yogstation\code\modules\antagonists\_common\antag_menu.dm" #include "yogstation\code\modules\antagonists\abductor\equipment\abduction_outfits.dm" #include "yogstation\code\modules\antagonists\blob\blob\blobs\core.dm" +#include "yogstation\code\modules\antagonists\changeling\changeling.dm" #include "yogstation\code\modules\antagonists\darkspawn\_psi_web.dm" #include "yogstation\code\modules\antagonists\darkspawn\darkspawn_antag.dm" #include "yogstation\code\modules\antagonists\darkspawn\darkspawn_illusions.dm" @@ -4280,14 +4296,21 @@ #include "yogstation\code\modules\antagonists\traitor\backstory\traitor_factions.dm" #include "yogstation\code\modules\assembly\signaler.dm" #include "yogstation\code\modules\atmospherics\airalarm.dm" +#include "yogstation\code\modules\atmospherics\auxgm\breathing_classes.dm" #include "yogstation\code\modules\atmospherics\machinery\pipes\bluespace.dm" #include "yogstation\code\modules\atmospherics\unary_devices\vent_pump.dm" #include "yogstation\code\modules\cargo\cargo_packs.dm" +#include "yogstation\code\modules\cargo\bounties\medical.dm" +#include "yogstation\code\modules\cargo\exports\organs.dm" #include "yogstation\code\modules\cargo\exports\sheets.dm" #include "yogstation\code\modules\cargo\exports\weapons.dm" #include "yogstation\code\modules\client\client_defines.dm" #include "yogstation\code\modules\client\client_procs.dm" #include "yogstation\code\modules\client\preferences_savefile.dm" +#include "yogstation\code\modules\client\preferences\_preference.dm" +#include "yogstation\code\modules\client\preferences\clothing.dm" +#include "yogstation\code\modules\client\preferences\species_features\mutants.dm" +#include "yogstation\code\modules\client\preferences\species_features\vox.dm" #include "yogstation\code\modules\client\verbs\afk.dm" #include "yogstation\code\modules\client\verbs\antag_token.dm" #include "yogstation\code\modules\client\verbs\looc.dm" @@ -4300,24 +4323,36 @@ #include "yogstation\code\modules\clothing\mask.dm" #include "yogstation\code\modules\clothing\shoe.dm" #include "yogstation\code\modules\clothing\under.dm" +#include "yogstation\code\modules\clothing\ears\_ears.dm" #include "yogstation\code\modules\clothing\glasses\_glasses.dm" +#include "yogstation\code\modules\clothing\gloves\_gloves.dm" #include "yogstation\code\modules\clothing\gloves\miscellaneous.dm" +#include "yogstation\code\modules\clothing\head\_head.dm" #include "yogstation\code\modules\clothing\head\helmet.dm" #include "yogstation\code\modules\clothing\head\jobs.dm" #include "yogstation\code\modules\clothing\head\misc.dm" #include "yogstation\code\modules\clothing\head\misc_special.dm" +#include "yogstation\code\modules\clothing\masks\_masks.dm" +#include "yogstation\code\modules\clothing\masks\breath.dm" #include "yogstation\code\modules\clothing\masks\hailer.dm" #include "yogstation\code\modules\clothing\neck\_neck.dm" #include "yogstation\code\modules\clothing\outfits\event.dm" +#include "yogstation\code\modules\clothing\shoes\_shoes.dm" +#include "yogstation\code\modules\clothing\shoes\colour.dm" +#include "yogstation\code\modules\clothing\shoes\magboots.dm" #include "yogstation\code\modules\clothing\shoes\miscellaneous.dm" #include "yogstation\code\modules\clothing\shoes\special_shoes.dm" +#include "yogstation\code\modules\clothing\spacesuits\alien.dm" #include "yogstation\code\modules\clothing\spacesuits\hardsuit.dm" +#include "yogstation\code\modules\clothing\suits\_suits.dm" #include "yogstation\code\modules\clothing\suits\armor.dm" #include "yogstation\code\modules\clothing\suits\explorer_gear.dm" #include "yogstation\code\modules\clothing\suits\labcoat.dm" #include "yogstation\code\modules\clothing\suits\miscellaneous.dm" #include "yogstation\code\modules\clothing\suits\nerd.dm" #include "yogstation\code\modules\clothing\suits\wiz_robe.dm" +#include "yogstation\code\modules\clothing\under\_under.dm" +#include "yogstation\code\modules\clothing\under\color.dm" #include "yogstation\code\modules\clothing\under\miscellaneous.dm" #include "yogstation\code\modules\clothing\under\jobs\civilian.dm" #include "yogstation\code\modules\clothing\under\jobs\engineering.dm" @@ -4339,6 +4374,8 @@ #include "yogstation\code\modules\events\probabilistic_anomaly.dm" #include "yogstation\code\modules\events\weightless.dm" #include "yogstation\code\modules\food_and_drinks\food\condiment.dm" +#include "yogstation\code\modules\food_and_drinks\food\snacks_meat.dm" +#include "yogstation\code\modules\food_and_drinks\food\recipes\tablecraft\recipes_meat.dm" #include "yogstation\code\modules\food_and_drinks\food\snacks\meat.dm" #include "yogstation\code\modules\goals\station_goals\bluespace_tap.dm" #include "yogstation\code\modules\guardian\guardian.dm" @@ -4387,6 +4424,8 @@ #include "yogstation\code\modules\jungleland\kinetic_javelin.dm" #include "yogstation\code\modules\language\darkspeak.dm" #include "yogstation\code\modules\language\japanese.dm" +#include "yogstation\code\modules\language\language_holder.dm" +#include "yogstation\code\modules\language\voxpidgin.dm" #include "yogstation\code\modules\mentor\follow.dm" #include "yogstation\code\modules\mentor\mentor.dm" #include "yogstation\code\modules\mentor\mentor_memo.dm" @@ -4414,6 +4453,7 @@ #include "yogstation\code\modules\mob\living\carbon\alien\humanoid\humanoid.dm" #include "yogstation\code\modules\mob\living\carbon\alien\humanoid\humanoid_defense.dm" #include "yogstation\code\modules\mob\living\carbon\alien\humanoid\queen.dm" +#include "yogstation\code\modules\mob\living\carbon\human\emote.dm" #include "yogstation\code\modules\mob\living\carbon\human\human.dm" #include "yogstation\code\modules\mob\living\carbon\human\human_defense.dm" #include "yogstation\code\modules\mob\living\carbon\human\human_defines.dm" @@ -4426,6 +4466,7 @@ #include "yogstation\code\modules\mob\living\carbon\human\species_types\lizard.dm" #include "yogstation\code\modules\mob\living\carbon\human\species_types\plantpeople.dm" #include "yogstation\code\modules\mob\living\carbon\human\species_types\szlachta.dm" +#include "yogstation\code\modules\mob\living\carbon\human\species_types\vox.dm" #include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\organs.dm" #include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\power_suck.dm" #include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\preternis.dm" @@ -4479,6 +4520,7 @@ #include "yogstation\code\modules\reagents\chemistry\reagents\food_reagents.dm" #include "yogstation\code\modules\reagents\chemistry\reagents\other_reagents.dm" #include "yogstation\code\modules\reagents\chemistry\recipes\slime_extracts.dm" +#include "yogstation\code\modules\reagents\reagent_containers\blood_pack.dm" #include "yogstation\code\modules\reagents\reagent_containers\bottle.dm" #include "yogstation\code\modules\reagents\reagent_containers\gummies.dm" #include "yogstation\code\modules\reagents\reagent_containers\hypospray.dm" @@ -4488,6 +4530,7 @@ #include "yogstation\code\modules\research\rdconsole.dm" #include "yogstation\code\modules\research\designs\bluespace_designs.dm" #include "yogstation\code\modules\research\designs\comp_board_designs.dm" +#include "yogstation\code\modules\research\designs\limbgrower_designs.dm" #include "yogstation\code\modules\research\designs\medical_designs.dm" #include "yogstation\code\modules\research\designs\misc_designs.dm" #include "yogstation\code\modules\research\designs\spacepod_designs.dm" @@ -4531,10 +4574,18 @@ #include "yogstation\code\modules\spells\spell_types\projectile\animation.dm" #include "yogstation\code\modules\spells\spell_types\self\cauterize.dm" #include "yogstation\code\modules\spells\spell_types\shapeshift\mouse.dm" -#include "yogstation\code\modules\surgery\bodypart.dm" #include "yogstation\code\modules\surgery\gender_reassignment.dm" +#include "yogstation\code\modules\surgery\bodyparts\_bodyparts.dm" +#include "yogstation\code\modules\surgery\bodyparts\head.dm" +#include "yogstation\code\modules\surgery\organs\appendix.dm" +#include "yogstation\code\modules\surgery\organs\ears.dm" +#include "yogstation\code\modules\surgery\organs\eyes.dm" #include "yogstation\code\modules\surgery\organs\heart.dm" +#include "yogstation\code\modules\surgery\organs\liver.dm" #include "yogstation\code\modules\surgery\organs\lungs.dm" +#include "yogstation\code\modules\surgery\organs\stomach.dm" +#include "yogstation\code\modules\surgery\organs\tails.dm" +#include "yogstation\code\modules\surgery\organs\tongue.dm" #include "yogstation\code\modules\uplink\uplink_item.dm" #include "yogstation\code\modules\vending\fishing.dm" #include "yogstation\code\modules\vending\gift.dm" diff --git a/yogstation/code/__HELPERS/mobs.dm b/yogstation/code/__HELPERS/mobs.dm index 2f69fc04ac154..051949f879767 100644 --- a/yogstation/code/__HELPERS/mobs.dm +++ b/yogstation/code/__HELPERS/mobs.dm @@ -5,6 +5,25 @@ if(!findname(.)) break +/proc/random_unique_vox_name(attempts_to_find_unique_name=10) + for(var/i in 1 to attempts_to_find_unique_name) + . = capitalize(vox_name()) + + if(!findname(.)) + break + +GLOBAL_LIST_INIT(vox_skin_tones, sortList(list( + "lime", + "crimson", + "nebula", + "azure", + "emerald", + "brown", + "plum", + "grey", + "mossy" + ))) + /proc/is_admin(user) if(ismob(user)) var/mob/temp = user diff --git a/yogstation/code/__HELPERS/names.dm b/yogstation/code/__HELPERS/names.dm index fe32630465994..23861e1403c57 100644 --- a/yogstation/code/__HELPERS/names.dm +++ b/yogstation/code/__HELPERS/names.dm @@ -3,3 +3,10 @@ return "[pick(GLOB.gorilla_names_male)] [pick(GLOB.last_names)]" else return "[pick(GLOB.gorilla_names_female)] [pick(GLOB.last_names)]" + +/proc/vox_name() + var/sounds = rand(2,8) + var/vox_name = "" + for(var/sound in 1 to sounds) + vox_name += pick("ti","hi","ki","ya","ta","ha","ka","yi","chi","cha","kah") + return vox_name diff --git a/yogstation/code/_globalvars/lists/flavor_misc.dm b/yogstation/code/_globalvars/lists/flavor_misc.dm new file mode 100644 index 0000000000000..920f3c028b5ba --- /dev/null +++ b/yogstation/code/_globalvars/lists/flavor_misc.dm @@ -0,0 +1,8 @@ +//Vox prefs and sprite accessories +GLOBAL_LIST_EMPTY(vox_quills_list) +GLOBAL_LIST_EMPTY(vox_facial_quills_list) +GLOBAL_LIST_EMPTY(vox_tails_list) +GLOBAL_LIST_EMPTY(vox_body_markings_list) +GLOBAL_LIST_EMPTY(vox_tail_markings_list) +GLOBAL_LIST_EMPTY(animated_vox_tails_list) +GLOBAL_LIST_EMPTY(animated_vox_tail_markings_list) diff --git a/yogstation/code/datums/blood_types.dm b/yogstation/code/datums/blood_types.dm new file mode 100644 index 0000000000000..720f16bdbabb1 --- /dev/null +++ b/yogstation/code/datums/blood_types.dm @@ -0,0 +1,4 @@ +/datum/blood_type/vox + name = "V" + color = COLOR_BLOOD_VOX + compatible_types = list(/datum/blood_type/vox) diff --git a/yogstation/code/datums/dog_fashion.dm b/yogstation/code/datums/dog_fashion.dm new file mode 100644 index 0000000000000..9ab978ec2221f --- /dev/null +++ b/yogstation/code/datums/dog_fashion.dm @@ -0,0 +1,3 @@ +/datum/dog_fashion/head/fried_vox_empty + name = "Colonel REAL_NAME" + desc = "Keep away from live Vox." diff --git a/yogstation/code/datums/emotes.dm b/yogstation/code/datums/emotes.dm new file mode 100644 index 0000000000000..c295343cfe409 --- /dev/null +++ b/yogstation/code/datums/emotes.dm @@ -0,0 +1,3 @@ +/datum/emote + /// Message to display if the user is a vox + var/message_vox = "" diff --git a/yogstation/code/datums/traits/good.dm b/yogstation/code/datums/traits/good.dm new file mode 100644 index 0000000000000..06779e2aae935 --- /dev/null +++ b/yogstation/code/datums/traits/good.dm @@ -0,0 +1,6 @@ +/datum/quirk/multilingual/voxpidgin + name = "Multilingual (Vox-pidgin)" + desc = "You spent a portion of your life learning to understand Vox-pidgin. You may or may not be able to speak it based on your anatomy." + specific = /datum/language/vox + gain_text = span_notice("You have learned to understand Vox-pidgin.") + lose_text = span_notice("You have forgotten how to understand Vox-pidgin.") diff --git a/yogstation/code/game/objects/items.dm b/yogstation/code/game/objects/items.dm new file mode 100644 index 0000000000000..f5b158c922182 --- /dev/null +++ b/yogstation/code/game/objects/items.dm @@ -0,0 +1,3 @@ +/obj/item + var/list/sprite_sheets = null + var/species_fitted = null diff --git a/yogstation/code/game/objects/items/flag.dm b/yogstation/code/game/objects/items/flag.dm new file mode 100644 index 0000000000000..c56520a5f54ba --- /dev/null +++ b/yogstation/code/game/objects/items/flag.dm @@ -0,0 +1,299 @@ +/obj/item/flag + name = "flag" + desc = "It's a flag." + icon = 'icons/obj/flag.dmi' + icon_state = "ntflag" + lefthand_file = 'icons/mob/inhands/flags_lefthand.dmi' + righthand_file = 'icons/mob/inhands/flags_righthand.dmi' + w_class = WEIGHT_CLASS_BULKY + max_integrity = 40 + resistance_flags = FLAMMABLE + custom_fire_overlay = "fire" + var/rolled = FALSE + +/obj/item/flag/attackby(obj/item/item, mob/user, params) + . = ..() + if(item.is_hot() && !(resistance_flags & ON_FIRE)) + user.visible_message(span_notice("[user] lights [src] with [item]."), span_notice("You light [src] with [item]."), span_warning("You hear a low whoosh.")) + fire_act() + +/obj/item/flag/attack_self(mob/user) + rolled = !rolled + user.visible_message(span_notice("[user] [rolled ? "rolls up" : "unfurls"] [src]."), span_notice("You [rolled ? "roll up" : "unfurl"] [src]."), span_warning("You hear fabric rustling.")) + update_icon() + +/obj/item/flag/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = FALSE) + ..() + update_icon() + +/obj/item/flag/extinguish() + ..() + update_icon() + +/obj/item/flag/update_icon_state() + . = ..() + icon_state = initial(icon_state) + item_state = icon_state + if(rolled) + icon_state = "[icon_state]_rolled" + custom_fire_overlay = "fire_rolled" + else + custom_fire_overlay = initial(custom_fire_overlay) + if(resistance_flags & ON_FIRE) + item_state = "[item_state]_fire" + if(ismob(loc)) + var/mob/M = loc + M.update_inv_hands() + +/obj/item/flag/nt + name = "\improper Nanotrasen flag" + desc = "A flag proudly boasting the logo of NT." + icon_state = "ntflag" + +/obj/item/flag/clown + name = "\improper Clown Planet flag" + desc = "The banner of His Majesty, King Squiggles the Eighth." + icon_state = "clownflag" + +/obj/item/flag/mime + name = "\improper Mime Revolution flag" + desc = "The banner of the glorious revolutionary forces fighting the oppressors on Clown Planet." + icon_state = "mimeflag" + +/obj/item/flag/ian + name = "\improper Ian flag" + desc = "The banner of Ian, because SQUEEEEE." + icon_state = "ianflag" + + +//Species flags + +/obj/item/flag/species/slime + name = "\improper Slime People flag" + desc = "A flag proudly proclaiming the superior heritage of Slime People." + icon_state = "slimeflag" + +/obj/item/flag/species/skrell + //name = "\improper Skrell flag" + //desc = "A flag proudly proclaiming the superior heritage of Skrell." + icon_state = "skrellflag" + +/obj/item/flag/species/vox + name = "\improper Vox flag" + desc = "A flag proudly proclaiming the superior heritage of Vox." + icon_state = "voxflag" + +/obj/item/flag/species/machine + name = "\improper Synthetics flag" + desc = "A flag proudly proclaiming the superior heritage of Synthetics." + icon_state = "machineflag" + +/obj/item/flag/species/diona + //name = "\improper Diona flag" //phytosians maybe? + //desc = "A flag proudly proclaiming the superior heritage of Dionae." + icon_state = "dionaflag" + +/obj/item/flag/species/human + name = "\improper Human flag" + desc = "A flag proudly proclaiming the superior heritage of Humans." + icon_state = "humanflag" + +/obj/item/flag/species/greys + //name = "\improper Greys flag" + //desc = "A flag proudly proclaiming the superior heritage of Greys." + icon_state = "greysflag" + +/obj/item/flag/species/kidan + //name = "\improper Kidan flag" //preternis maybe? + //desc = "A flag proudly proclaiming the superior heritage of Kidan." + icon_state = "kidanflag" + +/obj/item/flag/species/taj + //name = "\improper Tajaran flag" + //desc = "A flag proudly proclaiming the superior heritage of Tajaran." + icon_state = "tajflag" + +/obj/item/flag/species/lizard + name = "\improper Vuulek flag" + desc = "A flag proudly proclaiming the superior heritage of Vuulek." + icon_state = "lizardflag" + +/obj/item/flag/species/vulp + //name = "\improper Vulpkanin flag" + //desc = "A flag proudly proclaiming the superior heritage of Vulpkanin." + icon_state = "vulpflag" + +/obj/item/flag/species/drask + //name = "\improper Drask flag" + //desc = "A flag proudly proclaiming the superior heritage of Drask." + icon_state = "draskflag" + +/obj/item/flag/species/plasma + name = "\improper Plasmaman flag" + desc = "A flag proudly proclaiming the superior heritage of Plasmamen." + icon_state = "plasmaflag" + +/obj/item/flag/species/moth + name ="\improper Ex'hai flag" + desc = "An eccentric handmade standard, luxuriously soft due to exotic silks and embossed with lustrous gold. Although inspired by the pride that Ex'hai take in their baubles, it ultimately feels melancholic. Beauty knows no pain, afterall." + icon_state = "mothflag" + +//Department Flags + +/obj/item/flag/cargo + name = "\improper Cargonia flag" + desc = "The flag of the independent, sovereign nation of Cargonia." + icon_state = "cargoflag" + +/obj/item/flag/med + name = "\improper Medistan flag" + desc = "The flag of the independent, sovereign nation of Medistan." + icon_state = "medflag" + +/obj/item/flag/sec + name = "\improper Brigston flag" + desc = "The flag of the independent, sovereign nation of Brigston." + icon_state = "secflag" + +/obj/item/flag/rnd + name = "\improper Scientopia flag" + desc = "The flag of the independent, sovereign nation of Scientopia." + icon_state = "rndflag" + +/obj/item/flag/atmos + name = "\improper Atmosia flag" + desc = "The flag of the independent, sovereign nation of Atmosia." + icon_state = "atmosflag" + +/obj/item/flag/command + name = "\improper Command flag" + desc = "The flag of the independent, sovereign nation of Command." + icon_state = "ntflag" + +//Antags + +/obj/item/flag/grey + name = "\improper Greytide flag" + desc = "A banner made from an old grey jumpsuit." + icon_state = "greyflag" + +/obj/item/flag/syndi + name = "\improper Syndicate flag" + desc = "A flag proudly boasting the logo of the Syndicate, in defiance of NT." + icon_state = "syndiflag" + +/obj/item/flag/wiz + name = "\improper Wizard Federation flag" + desc = "A flag proudly boasting the logo of the Wizard Federation, sworn enemies of NT." + icon_state = "wizflag" + +/obj/item/flag/cult + name = "\improper Nar'Sie Cultist flag" + desc = "A flag proudly boasting the logo of the cultists, sworn enemies of NT." + icon_state = "cultflag" + +/obj/item/flag/ussp + name = "\improper USSP flag" + desc = "A flag proudly boasting the logo of the USSP, a noticeable faction in the galaxy." + icon_state = "usspflag" + +/obj/item/flag/solgov + name = "\improper Trans-Solar Federation flag" + desc = "A flag proudly boasting the logo of the SolGov, allied to NT government originated from Earth." + icon_state = "solgovflag" + +//Chameleon +/* +/obj/item/flag/chameleon + name = "chameleon flag" + desc = "A poor recreation of the official NT flag. It seems to shimmer a little." + icon_state = "ntflag" + origin_tech = "syndicate=1;magnets=4" + var/updated_icon_state = null + var/used = FALSE + var/obj/item/grenade/boobytrap = null + var/mob/trapper = null + +/obj/item/flag/chameleon/New() + updated_icon_state = icon_state + ..() + +/obj/item/flag/chameleon/attack_self(mob/user) + if(used) + return ..() + + var/list/flag_types = typesof(/obj/item/flag) - list(/obj/item/flag, /obj/item/flag/chameleon, /obj/item/flag/chameleon/depot) + var/list/flag = list() + + for(var/flag_type in flag_types) + var/obj/item/flag/F = new flag_type + flag[capitalize(F.name)] = F + + var/list/show_flag = list("EXIT" = null) + sortList(flag) + + var/input_flag = input(user, "Choose a flag to disguise as.", "Choose a flag.") in show_flag + + if(user && (src in user.contents)) + + var/obj/item/flag/chosen_flag = flag[input_flag] + + if(chosen_flag && !used) + name = chosen_flag.name + icon_state = chosen_flag.icon_state + updated_icon_state = icon_state + desc = chosen_flag.desc + used = TRUE + +/obj/item/flag/chameleon/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/grenade) && !boobytrap) + if(user.drop_item()) + boobytrap = I + trapper = user + I.forceMove(src) + to_chat(user, "You hide [I] in [src]. It will detonate some time after the flag is lit on fire.") + var/turf/bombturf = get_turf(src) + var/area/A = get_area(bombturf) + log_game("[key_name(user)] has hidden [I] in [src] ready for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).") + investigate_log("[key_name(user)] has hidden [I] in [src] ready for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has hidden [I] ready for detonation in", ATKLOG_MOST) + else if(I.get_heat() && !(resistance_flags & ON_FIRE) && boobytrap && trapper) + var/turf/bombturf = get_turf(src) + var/area/A = get_area(bombturf) + log_game("[key_name_admin(user)] has lit [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).") + investigate_log("[key_name_admin(user)] has lit [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has lit (booby trapped with [boobytrap]", ATKLOG_FEW) + burn() + else + return ..() + +/obj/item/flag/chameleon/screwdriver_act(mob/user, obj/item/I) + if(!boobytrap || user != trapper) + return + . = TRUE + if(!I.use_tool(src, user, 0, volume = I.tool_volume)) + return + to_chat(user, "You remove [boobytrap] from [src].") + boobytrap.forceMove(get_turf(src)) + boobytrap = null + trapper = null + +/obj/item/flag/chameleon/burn() + if(boobytrap) + fire_act() + addtimer(CALLBACK(src, PROC_REF(prime_boobytrap)), boobytrap.det_time) + else + ..() + +/obj/item/flag/chameleon/proc/prime_boobytrap() + boobytrap.forceMove(get_turf(loc)) + boobytrap.prime() + boobytrap = null + burn() + +/obj/item/flag/chameleon/updateFlagIcon() + icon_state = updated_icon_state + +/obj/item/flag/chameleon/depot/New() + ..() + boobytrap = new /obj/item/grenade/gas/plasma(src) +*/ diff --git a/yogstation/code/game/objects/items/plushes.dm b/yogstation/code/game/objects/items/plushes.dm index e8948ea04e3c8..1f72cd81668b1 100644 --- a/yogstation/code/game/objects/items/plushes.dm +++ b/yogstation/code/game/objects/items/plushes.dm @@ -176,4 +176,11 @@ squeak_override = list( 'sound/weapons/egloves.ogg' = 2, 'sound/weapons/cablecuff.ogg' = 1 - ) \ No newline at end of file + ) + +/obj/item/toy/plush/voxplushie + name = "vox plushie" + desc = "A stitched-together Vox, fresh from the skipjack. Press its belly to hear it skree!" + icon_state = "plushie_vox" + item_state = "plushie_vox" + squeak_override = list('sound/voice/vox/shriek1.ogg' = 1) diff --git a/yogstation/code/game/objects/items/stacks/sheets/leather.dm b/yogstation/code/game/objects/items/stacks/sheets/leather.dm index 61b7a43e7ed23..87e7c2d6f964d 100644 --- a/yogstation/code/game/objects/items/stacks/sheets/leather.dm +++ b/yogstation/code/game/objects/items/stacks/sheets/leather.dm @@ -10,4 +10,10 @@ desc = "This would make a nice rug." singular_name = "gorilla skin piece" icon_state = "sheet-gorilla" - item_state = "sheet-gorilla" \ No newline at end of file + item_state = "sheet-gorilla" + +/obj/item/stack/sheet/animalhide/vox + name = "vox hide" + desc = "SKREE!" + singular_name = "vox hide piece" + icon_state = "sheet-vox" diff --git a/yogstation/code/game/objects/items/storage/backpack.dm b/yogstation/code/game/objects/items/storage/backpack.dm index b79d23c427539..87a0f08483e97 100644 --- a/yogstation/code/game/objects/items/storage/backpack.dm +++ b/yogstation/code/game/objects/items/storage/backpack.dm @@ -1,3 +1,6 @@ +/obj/item/storage/backpack + sprite_sheets = list(SPECIES_VOX = VOX_BACK_FILE) + /obj/item/storage/backpack/holding icon = 'yogstation/icons/obj/storage.dmi' icon_state = "holdingpack" diff --git a/yogstation/code/game/objects/items/tanks/tank_types.dm b/yogstation/code/game/objects/items/tanks/tank_types.dm new file mode 100644 index 0000000000000..da9c60b792b07 --- /dev/null +++ b/yogstation/code/game/objects/items/tanks/tank_types.dm @@ -0,0 +1,26 @@ +/obj/item/tank/internals/nitrogen + name = "nitrogen tank" + desc = "A tank of nitrogen." + icon_state = "oxygen_fr" + force = 10 + distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE + +/obj/item/tank/internals/nitrogen/populate_gas() + air_contents.set_moles(GAS_N2, (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)) + +/obj/item/tank/internals/emergency_oxygen/nitrogen + name = "emergency nitrogen tank" + desc = "An emergency tank designed specifically for Vox." + icon_state = "emergency_nitrogen" + +/obj/item/tank/internals/emergency_oxygen/nitrogen/populate_gas() + air_contents.set_moles(GAS_N2, (10*ONE_ATMOSPHERE)* volume/(R_IDEAL_GAS_EQUATION*T20C)) + +/obj/item/tank/internals/emergency_oxygen/vox + name = "vox specialized nitrogen tank" + desc = "A high-tech nitrogen tank designed specifically for Vox." + icon_state = "emergency_vox" + volume = 35 + +/obj/item/tank/internals/emergency_oxygen/vox/populate_gas() + air_contents.set_moles(GAS_N2, (10*ONE_ATMOSPHERE)* volume/(R_IDEAL_GAS_EQUATION*T20C)) diff --git a/yogstation/code/game/objects/items/trash.dm b/yogstation/code/game/objects/items/trash.dm new file mode 100644 index 0000000000000..88a6ffaa1b23e --- /dev/null +++ b/yogstation/code/game/objects/items/trash.dm @@ -0,0 +1,6 @@ +/obj/item/trash/fried_vox + name = "Kentucky Fried Vox" + icon_state = "fried_vox_empty" + item_state = "fried_vox_empty" + slot_flags = ITEM_SLOT_HEAD + dog_fashion = /datum/dog_fashion/head/fried_vox_empty diff --git a/yogstation/code/game/objects/objs.dm b/yogstation/code/game/objects/objs.dm new file mode 100644 index 0000000000000..d5e06d66cc204 --- /dev/null +++ b/yogstation/code/game/objects/objs.dm @@ -0,0 +1,2 @@ +/obj + var/custom_fire_overlay // Update_fire_overlay will check if a different icon state should be used diff --git a/yogstation/code/game/objects/structures/signs/_signs.dm b/yogstation/code/game/objects/structures/signs/_signs.dm new file mode 100644 index 0000000000000..d1351d3b841fd --- /dev/null +++ b/yogstation/code/game/objects/structures/signs/_signs.dm @@ -0,0 +1,19 @@ +/obj/structure/sign/pox + name = "NO VOX ALLOWED" + icon_state = "novox1-b" + desc = "A sign which reads 'NO VOX ALLOWED'." + +/obj/structure/sign/pox/no_cross + icon_state = "novox2-b" + +/obj/structure/sign/pox/red + icon_state = "novox1-r" + +/obj/structure/sign/pox/red/no_cross + icon_state = "novox2-r" + +/obj/structure/sign/pox/red/cicle + icon_state = "novox_circle1" + +/obj/structure/sign/pox/red/cicle/no_cross + icon_state = "novox_circle2" diff --git a/yogstation/code/game/turfs/open/floor/plating/asteroid.dm b/yogstation/code/game/turfs/open/floor/plating/asteroid.dm new file mode 100644 index 0000000000000..a042e95179576 --- /dev/null +++ b/yogstation/code/game/turfs/open/floor/plating/asteroid.dm @@ -0,0 +1 @@ +#define BREATH_VOX /datum/breathing_class/vox diff --git a/yogstation/code/modules/antagonists/changeling/changeling.dm b/yogstation/code/modules/antagonists/changeling/changeling.dm new file mode 100644 index 0000000000000..4cc43fb18adc4 --- /dev/null +++ b/yogstation/code/modules/antagonists/changeling/changeling.dm @@ -0,0 +1,2 @@ +/datum/changelingprofile + var/list/sprite_sheets_list = list() diff --git a/yogstation/code/modules/atmospherics/auxgm/breathing_classes.dm b/yogstation/code/modules/atmospherics/auxgm/breathing_classes.dm new file mode 100644 index 0000000000000..dda45a896de5d --- /dev/null +++ b/yogstation/code/modules/atmospherics/auxgm/breathing_classes.dm @@ -0,0 +1,12 @@ +/datum/breathing_class/vox + gases = list( + GAS_N2 = 1, + GAS_CO2 = -0.7, + ) + products = list( + GAS_CO2 = 1 + ) + low_alert_category = "not_enough_nitro" + low_alert_datum = /atom/movable/screen/alert/not_enough_nitro + high_alert_category = "too_much_nitro" + high_alert_datum = /atom/movable/screen/alert/too_much_nitro diff --git a/yogstation/code/modules/cargo/bounties/medical.dm b/yogstation/code/modules/cargo/bounties/medical.dm new file mode 100644 index 0000000000000..1916f7a4aba75 --- /dev/null +++ b/yogstation/code/modules/cargo/bounties/medical.dm @@ -0,0 +1,5 @@ +/datum/bounty/item/medical/vox_tail + name = "Vox Tail" + description = "Negotiations have broken down between Central Command and a group of Vox raiders. Ship us a vox tail so we can show them we mean business." + reward = 3000 + wanted_types = list(/obj/item/organ/tail/vox) diff --git a/yogstation/code/modules/cargo/cargo_packs.dm b/yogstation/code/modules/cargo/cargo_packs.dm index 638d4b90c0ea8..68905411b5c21 100644 --- a/yogstation/code/modules/cargo/cargo_packs.dm +++ b/yogstation/code/modules/cargo/cargo_packs.dm @@ -106,6 +106,7 @@ /obj/item/toy/plush/inorixplushie, /obj/item/toy/plush/beeplushie, /obj/item/toy/plush/slimeplushie, + /obj/item/toy/plush/voxplushie, /obj/item/toy/plush/cdragon) crate_name = "plush crate" crate_type = /obj/structure/closet/crate/wooden diff --git a/yogstation/code/modules/cargo/exports/organs.dm b/yogstation/code/modules/cargo/exports/organs.dm new file mode 100644 index 0000000000000..5440334e34b83 --- /dev/null +++ b/yogstation/code/modules/cargo/exports/organs.dm @@ -0,0 +1,4 @@ +/datum/export/organ/mutant/vox_tail + cost = 300 + unit_name = "vox tail" + export_types = list(/obj/item/organ/tail/vox) diff --git a/yogstation/code/modules/cargo/exports/sheets.dm b/yogstation/code/modules/cargo/exports/sheets.dm index e2718f56ca14b..b2a65d50088d3 100644 --- a/yogstation/code/modules/cargo/exports/sheets.dm +++ b/yogstation/code/modules/cargo/exports/sheets.dm @@ -1,4 +1,10 @@ /datum/export/stack/skin/gorilla cost = 150 unit_name = "gorilla hide" - export_types = list(/obj/item/stack/sheet/animalhide/gorilla) \ No newline at end of file + export_types = list(/obj/item/stack/sheet/animalhide/gorilla) + +/datum/export/stack/skin/vox + cost = 2500 + export_limit = 200 + unit_name = "vox hide" + export_types = list(/obj/item/stack/sheet/animalhide/vox) diff --git a/yogstation/code/modules/client/preferences/_preference.dm b/yogstation/code/modules/client/preferences/_preference.dm new file mode 100644 index 0000000000000..0df2a785aeb1a --- /dev/null +++ b/yogstation/code/modules/client/preferences/_preference.dm @@ -0,0 +1,2 @@ +/datum/preference + var/list/blacklisted_species = list() diff --git a/yogstation/code/modules/client/preferences/clothing.dm b/yogstation/code/modules/client/preferences/clothing.dm new file mode 100644 index 0000000000000..9eebd30d1d6a6 --- /dev/null +++ b/yogstation/code/modules/client/preferences/clothing.dm @@ -0,0 +1,8 @@ +/datum/preference/choiced/socks + blacklisted_species = list(/datum/species/vox) + +/datum/preference/choiced/undershirt + blacklisted_species = list(/datum/species/vox) + +/datum/preference/choiced/underwear + blacklisted_species = list(/datum/species/vox) diff --git a/yogstation/code/modules/client/preferences/species_features/mutants.dm b/yogstation/code/modules/client/preferences/species_features/mutants.dm new file mode 100644 index 0000000000000..d9db94b95fbb0 --- /dev/null +++ b/yogstation/code/modules/client/preferences/species_features/mutants.dm @@ -0,0 +1,15 @@ +/datum/preference/color/mutant_color + blacklisted_species = list(/datum/species/vox) + +/datum/preference/color/mutant_color_secondary + savefile_key = "feature_mcolor_secondary" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + relevant_species_trait = MUTCOLORS_SECONDARY + blacklisted_species = list(/datum/species/vox) + +/datum/preference/color/mutant_color_secondary/create_default_value() + return sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]") + +/datum/preference/color/mutant_color_secondary/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["mcolor_secondary"] = value diff --git a/yogstation/code/modules/client/preferences/species_features/vox.dm b/yogstation/code/modules/client/preferences/species_features/vox.dm new file mode 100644 index 0000000000000..3b08c4b224ea1 --- /dev/null +++ b/yogstation/code/modules/client/preferences/species_features/vox.dm @@ -0,0 +1,255 @@ +/proc/generate_vox_side_shots(list/sprite_accessories, accessory_color = COLOR_DARKER_BROWN) + var/list/values = list() + var/icon/vox_head = icon('icons/mob/species/vox/bodyparts.dmi', "vox_head_lime") + var/icon/eyes = icon('icons/mob/species/vox/eyes.dmi', "eyes") + var/icon/eyes_static = icon('icons/mob/species/vox/eyes.dmi', "eyes_static_green") + eyes.Blend(COLOR_CYAN, ICON_MULTIPLY) + vox_head.Blend(eyes, ICON_OVERLAY) + vox_head.Blend(eyes_static, ICON_OVERLAY) + var/icon/beak = icon('icons/mob/species/vox/bodyparts.dmi', "vox_head_static") + vox_head.Blend(beak, ICON_OVERLAY) + for(var/name in sprite_accessories) + var/datum/sprite_accessory/sprite_accessory = sprite_accessories[name] + var/icon/final_icon = icon(vox_head) + if(name != "None") + var/icon/accessory_icon = icon(sprite_accessory.icon, sprite_accessory.icon_state) + accessory_icon.Blend(accessory_color, sprite_accessory.color_blend_mode == COLOR_BLEND_ADD ? ICON_ADD : ICON_MULTIPLY) + final_icon.Blend(accessory_icon, ICON_OVERLAY) + final_icon.Crop(10, 19, 22, 31) + final_icon.Scale(32, 32) + values[name] = final_icon + return values + +/datum/preference/choiced/vox_skin_tone + savefile_key = "feature_vox_skin_tone" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + relevant_mutant_bodypart = "vox_tail" + main_feature_name = "Skin Tone" + +/datum/preference/choiced/vox_skin_tone/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["vox_skin_tone"] = value + +/datum/preference/choiced/vox_skin_tone/init_possible_values() + return GLOB.vox_skin_tones + +/datum/preference/choiced/vox_skin_tone/compile_constant_data() + var/list/data = ..() + var/list/capitalized_skin_tones = list() + for(var/skin_tone in GLOB.vox_skin_tones) + capitalized_skin_tones[skin_tone] = capitalize(skin_tone) + data[CHOICED_PREFERENCE_DISPLAY_NAMES] = capitalized_skin_tones + var/list/skin_tones_to_hex = list( + "lime" = "#617b0f", + "crimson" = "#a32e2e", + "plum" = "#564759", + "azure" = "#124746", + "emerald" = "#04572d", + "brown" = "#774c22", + "grey" = "#4a514b", + "nebula" = "#5a4787", + "mossy" = "#626d0d" + ) + var/list/to_hex = list() + for (var/choice in get_choices()) + var/hex_value = skin_tones_to_hex[choice] + var/list/hsl = rgb2num(hex_value, COLORSPACE_HSL) + to_hex[choice] = list( + "lightness" = hsl[3], + "value" = hex_value, + ) + data["to_hex"] = to_hex + return data + +/datum/preference/choiced/vox_tail_markings + savefile_key = "feature_vox_tail_markings" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + relevant_mutant_bodypart = "vox_tail_markings" + +/datum/preference/choiced/vox_tail_markings/init_possible_values() + return assoc_to_keys(GLOB.vox_tail_markings_list) + +/datum/preference/choiced/vox_tail_markings/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["vox_tail_markings"] = value + +/datum/preference/choiced/vox_body_markings + savefile_key = "feature_vox_body_markings" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + relevant_mutant_bodypart = "vox_body_markings" + +/datum/preference/choiced/vox_body_markings/init_possible_values() + return assoc_to_keys(GLOB.vox_body_markings_list) + +/datum/preference/choiced/vox_body_markings/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["vox_body_markings"] = value + +/datum/preference/choiced/vox_quills + savefile_key = "feature_vox_quills" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_FEATURES + should_generate_icons = TRUE + relevant_mutant_bodypart = "vox_quills" + main_feature_name = "Quills" + +/datum/preference/choiced/vox_quills/init_possible_values() + return generate_vox_side_shots(GLOB.vox_quills_list) + +/datum/preference/choiced/vox_quills/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["vox_quills"] = value + +/datum/preference/choiced/vox_quills/compile_constant_data() + var/list/data = ..() + data[SUPPLEMENTAL_FEATURE_KEY] = "feature_quill_color" + return data + +/datum/preference/choiced/vox_facial_quills + savefile_key = "feature_vox_facial_quills" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_FEATURES + should_generate_icons = TRUE + relevant_mutant_bodypart = "vox_facial_quills" + main_feature_name = "Facial Quills" + +/datum/preference/choiced/vox_facial_quills/init_possible_values() + return generate_vox_side_shots(GLOB.vox_facial_quills_list) + +/datum/preference/choiced/vox_facial_quills/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["vox_facial_quills"] = value + +/datum/preference/choiced/vox_facial_quills/compile_constant_data() + var/list/data = ..() + data[SUPPLEMENTAL_FEATURE_KEY] = "feature_facial_quill_color" + return data + +/datum/preference/color/hair_color/vox + category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES + savefile_key = "feature_quill_color" + relevant_species_trait = null + relevant_mutant_bodypart = "vox_quills" + unique = TRUE + +/datum/preference/color/facial_hair_color/vox + category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES + savefile_key = "feature_facial_quill_color" + relevant_species_trait = null + relevant_mutant_bodypart = "vox_facial_quills" + unique = TRUE + +/datum/preference/color/mutant_color/vox_body_markings_color + savefile_key = "feature_body_markings_color" + relevant_mutant_bodypart = "vox_body_markings" + relevant_species_trait = null + blacklisted_species = null + unique = TRUE + +/datum/preference/color/mutant_color/vox_body_markings_color/is_valid(value) + return findtext(value, GLOB.is_color) + +/datum/preference/color/mutant_color_secondary/vox_tail_markings_color + savefile_key = "feature_tail_markings_color" + relevant_mutant_bodypart = "vox_tail_markings" + relevant_species_trait = null + blacklisted_species = null + unique = TRUE + +/datum/preference/choiced/underwear/vox + savefile_key = "feature_vox_underwear" + relevant_mutant_bodypart = "vox_tail" + blacklisted_species = null + unique = TRUE + +/datum/preference/choiced/underwear/vox/init_possible_values() + return generate_values_for_underwear('icons/mob/clothing/species/vox/underwear.dmi', GLOB.underwear_list, list("vox_chest_lime", "vox_r_leg_lime", "vox_l_leg_lime", "vox_r_leg_static", "vox_l_leg_static"), 'icons/mob/species/vox/bodyparts.dmi') + +/datum/preference/choiced/socks/vox + savefile_key = "feature_vox_socks" + relevant_mutant_bodypart = "vox_tail" + blacklisted_species = null + unique = TRUE + +/datum/preference/choiced/socks/vox/init_possible_values() + return generate_values_for_underwear('icons/mob/clothing/species/vox/socks.dmi', GLOB.socks_list, list("vox_r_leg_lime", "vox_l_leg_lime", "vox_r_leg_static", "vox_l_leg_static"), 'icons/mob/species/vox/bodyparts.dmi') + +/datum/preference/choiced/undershirt/vox + savefile_key = "feature_vox_undershirt" + should_generate_icons = TRUE + relevant_mutant_bodypart = "vox_tail" + blacklisted_species = null + unique = TRUE + +/datum/preference/choiced/undershirt/vox/init_possible_values() + var/bodyparts_icon = 'icons/mob/species/vox/bodyparts.dmi' + var/icon/body = icon(bodyparts_icon, "vox_r_leg_lime") + body.Blend(icon(bodyparts_icon, "vox_l_leg_lime"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_r_arm_lime"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_l_arm_lime"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_r_hand"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_l_hand"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_chest_lime"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_l_arm_static"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_r_arm_static"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_l_leg_static"), ICON_OVERLAY) + body.Blend(icon(bodyparts_icon, "vox_r_leg_static"), ICON_OVERLAY) + var/vox_undershirt_icon = 'icons/mob/clothing/species/vox/undershirt.dmi' + var/list/values = list() + var/list/undershirt_list = GLOB.undershirt_list.Copy() + for(var/undershirt in undershirt_list) + if(undershirt == "Nude") + continue + var/datum/sprite_accessory/undershirt_accessory = undershirt_list[undershirt] + if(!icon_exists(vox_undershirt_icon, undershirt_accessory.icon_state)) + undershirt_list -= undershirt + for(var/accessory_name in undershirt_list) + var/icon/icon_with_undershirt = icon(body) + if(accessory_name != "Nude") + var/datum/sprite_accessory/accessory = undershirt_list[accessory_name] + icon_with_undershirt.Blend(icon(vox_undershirt_icon, accessory.icon_state), ICON_OVERLAY) + icon_with_undershirt.Crop(9, 9, 23, 23) + icon_with_undershirt.Scale(32, 32) + values[accessory_name] = icon_with_undershirt + return values + +/datum/preference/choiced/vox_tank_type + savefile_key = "feature_vox_tank_type" + relevant_mutant_bodypart = "vox_tail" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_NON_CONTEXTUAL + +/datum/preference/choiced/vox_tank_type/init_possible_values() + return list("Large", "Specialized") + +/datum/preference/choiced/vox_tank_type/create_default_value() + return "Specialized" + +/datum/preference/choiced/vox_tank_type/apply_to_human() + return + +/datum/preference/choiced/vox_mask + savefile_key = "feature_vox_mask" + relevant_mutant_bodypart = "vox_tail" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_NON_CONTEXTUAL + +/datum/preference/choiced/vox_mask/init_possible_values() + return list("Breath Mask", "Respirator") + +/datum/preference/choiced/vox_mask/create_default_value() + return "Breath Mask" + +/datum/preference/choiced/vox_mask/apply_to_human() + return + +/datum/preference/choiced/hair_gradient/vox + savefile_key = "feature_quill_gradientstyle" + relevant_species_trait = null + relevant_mutant_bodypart = "vox_quills" + unique = TRUE + +/datum/preference/color/hair_gradient/vox + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + savefile_key = "feature_quill_gradientcolor" + relevant_species_trait = null + relevant_mutant_bodypart = "vox_quills" + unique = TRUE diff --git a/yogstation/code/modules/clothing/clothing.dm b/yogstation/code/modules/clothing/clothing.dm index d3cf29df1b586..5e66750d7cc25 100644 --- a/yogstation/code/modules/clothing/clothing.dm +++ b/yogstation/code/modules/clothing/clothing.dm @@ -1,3 +1,32 @@ +/obj/item/clothing + var/list/species_restricted = null //Only these species can wear this kit. + +//BS12: Species-restricted clothing check. +/obj/item/clothing/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) + //if we can't equip the item anyway, don't bother with species_restricted (also cuts down on spam) + if(!..()) + return FALSE + // Skip species restriction checks on non-equipment slots + if(slot in list(ITEM_SLOT_BACKPACK, ITEM_SLOT_LPOCKET, ITEM_SLOT_RPOCKET)) + return TRUE + if(species_restricted && ishuman(M)) + var/wearable + var/exclusive + var/mob/living/carbon/human/H = M + if("exclude" in species_restricted) + exclusive = TRUE + if(H.dna.species) + if(exclusive) + if(!(H.dna.species.id in species_restricted)) + wearable = TRUE + else + if(H.dna.species.id in species_restricted) + wearable = TRUE + if(!wearable) + to_chat(M, span_warning("Your species cannot wear [src].")) + return FALSE + return TRUE + /obj/item/clothing/ears/yogs worn_icon = 'yogstation/icons/mob/clothing/ears/ears.dmi' icon = 'yogstation/icons/obj/clothing/ears.dmi' diff --git a/yogstation/code/modules/clothing/ears/_ears.dm b/yogstation/code/modules/clothing/ears/_ears.dm new file mode 100644 index 0000000000000..240afdcf4cddc --- /dev/null +++ b/yogstation/code/modules/clothing/ears/_ears.dm @@ -0,0 +1,2 @@ +/obj/item/clothing/ears + sprite_sheets = list(SPECIES_VOX = VOX_EARS_FILE) diff --git a/yogstation/code/modules/clothing/glasses/_glasses.dm b/yogstation/code/modules/clothing/glasses/_glasses.dm index 0481844811b64..63d733d5f1bc4 100644 --- a/yogstation/code/modules/clothing/glasses/_glasses.dm +++ b/yogstation/code/modules/clothing/glasses/_glasses.dm @@ -1,3 +1,6 @@ +/obj/item/clothing/glasses + sprite_sheets = list(SPECIES_VOX = VOX_EYES_FILE) + /obj/item/clothing/glasses/sunglasses/cheap name = "cheap sunglasses" desc = "Made in China." diff --git a/yogstation/code/modules/clothing/gloves/_gloves.dm b/yogstation/code/modules/clothing/gloves/_gloves.dm new file mode 100644 index 0000000000000..5ab19a74c0959 --- /dev/null +++ b/yogstation/code/modules/clothing/gloves/_gloves.dm @@ -0,0 +1,2 @@ +/obj/item/clothing/gloves + sprite_sheets = list(SPECIES_VOX = VOX_GLOVES_FILE) diff --git a/yogstation/code/modules/clothing/gloves/miscellaneous.dm b/yogstation/code/modules/clothing/gloves/miscellaneous.dm index f30b0e6b7063f..7754204b13f84 100644 --- a/yogstation/code/modules/clothing/gloves/miscellaneous.dm +++ b/yogstation/code/modules/clothing/gloves/miscellaneous.dm @@ -29,3 +29,11 @@ heat_protection = HANDS max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE + +/obj/item/clothing/gloves/color/yellow/vox + name = "insulated gauntlets" + desc = "These bizarre gauntlets seem to be fitted for...bird claws?" + icon_state = "gloves-vox" + item_state = "gloves-vox" + icon = 'icons/obj/clothing/species/vox/gloves.dmi' + species_restricted = list(SPECIES_VOX) diff --git a/yogstation/code/modules/clothing/head/_head.dm b/yogstation/code/modules/clothing/head/_head.dm new file mode 100644 index 0000000000000..fa710799e9d67 --- /dev/null +++ b/yogstation/code/modules/clothing/head/_head.dm @@ -0,0 +1,2 @@ +/obj/item/clothing/head + sprite_sheets = list(SPECIES_VOX = VOX_HEAD_FILE) diff --git a/yogstation/code/modules/clothing/head/helmet.dm b/yogstation/code/modules/clothing/head/helmet.dm index 6a397a4aec93f..6b550b0aed7ac 100644 --- a/yogstation/code/modules/clothing/head/helmet.dm +++ b/yogstation/code/modules/clothing/head/helmet.dm @@ -1,4 +1,5 @@ /obj/item/clothing/head/helmet + sprite_sheets = list(SPECIES_VOX = VOX_HELMET_FILE) var/initial_state /obj/item/clothing/head/helmet/Initialize(mapload) diff --git a/yogstation/code/modules/clothing/masks/_masks.dm b/yogstation/code/modules/clothing/masks/_masks.dm new file mode 100644 index 0000000000000..c4e18c7b3fd9e --- /dev/null +++ b/yogstation/code/modules/clothing/masks/_masks.dm @@ -0,0 +1,2 @@ +/obj/item/clothing/mask + sprite_sheets = list(SPECIES_VOX = VOX_MASK_FILE) diff --git a/yogstation/code/modules/clothing/masks/breath.dm b/yogstation/code/modules/clothing/masks/breath.dm new file mode 100644 index 0000000000000..c546778831760 --- /dev/null +++ b/yogstation/code/modules/clothing/masks/breath.dm @@ -0,0 +1,20 @@ +/obj/item/clothing/mask/breath/vox + name = "vox breath mask" + desc = "A weirdly-shaped breath mask." + icon_state = "voxmask" + species_restricted = list(SPECIES_VOX) + flags_cover = NONE + visor_flags_cover = NONE + actions_types = list() + +/obj/item/clothing/mask/breath/vox/attack_self(mob/user) + return + +/obj/item/clothing/mask/breath/vox/AltClick(mob/user) + return + +/obj/item/clothing/mask/breath/vox/respirator + name = "vox respirator" + desc = "A weirdly-shaped breath mask, this one seems to be designed for a vox beak." + icon_state = "voxmask2" + item_state = "voxmask2" diff --git a/yogstation/code/modules/clothing/shoes/_shoes.dm b/yogstation/code/modules/clothing/shoes/_shoes.dm new file mode 100644 index 0000000000000..31cb4a1d40b6c --- /dev/null +++ b/yogstation/code/modules/clothing/shoes/_shoes.dm @@ -0,0 +1,2 @@ +/obj/item/clothing/shoes + sprite_sheets = list(SPECIES_VOX = VOX_SHOES_FILE) diff --git a/yogstation/code/modules/clothing/shoes/colour.dm b/yogstation/code/modules/clothing/shoes/colour.dm new file mode 100644 index 0000000000000..f072d8caf51e5 --- /dev/null +++ b/yogstation/code/modules/clothing/shoes/colour.dm @@ -0,0 +1,5 @@ +/obj/item/clothing/shoes/sneakers + sprite_sheets = list("GAGS_sprite" = list(SPECIES_VOX)) + +/obj/item/clothing/shoes/sneakers/orange + sprite_sheets = list("GAGS_sprite" = list(SPECIES_VOX)) diff --git a/yogstation/code/modules/clothing/shoes/magboots.dm b/yogstation/code/modules/clothing/shoes/magboots.dm new file mode 100644 index 0000000000000..74db4dc7fd684 --- /dev/null +++ b/yogstation/code/modules/clothing/shoes/magboots.dm @@ -0,0 +1,45 @@ +/obj/item/clothing/shoes/magboots/vox + name = "vox magclaws" + desc = "A pair of heavy, jagged armoured foot pieces, seemingly suitable for a velociraptor." + item_state = "boots-vox" + icon_state = "boots-vox" + icon = 'icons/obj/clothing/species/vox/shoes.dmi' + species_restricted = list(SPECIES_VOX) + +/obj/item/clothing/shoes/magboots/vox/attack_self(mob/user) + if(magpulse) + clothing_flags &= ~NOSLIP + REMOVE_TRAIT(src, TRAIT_NODROP, "vox_magclaws") + to_chat(user, "You relax your deathgrip on the flooring.") + else + //make sure these can only be used when equipped. + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + if(H.shoes != src) + to_chat(user, span_warning("You will have to put on [src] before you can do that.")) + return + clothing_flags |= NOSLIP //kinda hard to take off magclaws when you are gripping them tightly. + ADD_TRAIT(src, TRAIT_NODROP, "vox_magclaws") + to_chat(user, "You dig your claws deeply into the flooring, bracing yourself.") + to_chat(user, "It would be hard to take off [src] without relaxing your grip first.") + magpulse = !magpulse + user.update_inv_shoes() //so our mob-overlays update + user.update_gravity(user.has_gravity()) + for(var/X in actions) + var/datum/action/A = X + A.build_all_button_icons() + +//In case they somehow come off while enabled. +/obj/item/clothing/shoes/magboots/vox/dropped(mob/user) + ..() + if(magpulse) + user.visible_message("[src] go limp as they are removed from [usr]'s feet.", "[src] go limp as they are removed from your feet.") + magpulse = FALSE + clothing_flags &= ~NOSLIP + REMOVE_TRAIT(src, TRAIT_NODROP, "vox_magclaws") + +/obj/item/clothing/shoes/magboots/vox/examine(mob/user) + . = ..() + if(magpulse) + . += "It would be hard to take these off without relaxing your grip first."//theoretically this message should only be seen by the wearer when the claws are equipped. diff --git a/yogstation/code/modules/clothing/spacesuits/alien.dm b/yogstation/code/modules/clothing/spacesuits/alien.dm new file mode 100644 index 0000000000000..fa1c19291caee --- /dev/null +++ b/yogstation/code/modules/clothing/spacesuits/alien.dm @@ -0,0 +1,68 @@ +// Vox space gear (vaccuum suit, low pressure armour) +// Can't be equipped by any other species due to bone structure and vox cybernetics. + +/obj/item/clothing/suit/space/vox + w_class = WEIGHT_CLASS_NORMAL + allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword, \ + /obj/item/restraints/handcuffs, /obj/item/tank/internals) + armor = list(MELEE = 40, BULLET = 40, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 80, ACID = 85) + icon = 'icons/obj/clothing/species/vox/suits.dmi' + species_restricted = list(SPECIES_VOX) + slowdown = 2 + +/obj/item/clothing/head/helmet/space/vox + armor = list(MELEE = 40, BULLET = 40, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 80, ACID = 85) + clothing_flags = STOPSPRESSUREDAMAGE + flags_cover = HEADCOVERSEYES + icon = 'icons/obj/clothing/species/vox/hats.dmi' + species_restricted = list(SPECIES_VOX) + sprite_sheets = list(SPECIES_VOX = VOX_HEAD_FILE) + +/obj/item/clothing/head/helmet/space/vox/pressure + name = "alien helmet" + icon_state = "vox-pressure" + item_state = "vox-pressure" + desc = "Hey, wasn't this a prop in \'The Abyss\'?" + +/obj/item/clothing/suit/space/vox/pressure + name = "alien pressure suit" + icon_state = "vox-pressure" + item_state = "vox-pressure" + desc = "A huge, armoured, pressurized suit, designed for distinctly nonhuman proportions." + +/obj/item/clothing/head/helmet/space/vox/carapace + name = "alien visor" + icon_state = "vox-carapace" + item_state = "vox-carapace" + desc = "A glowing visor, perhaps stolen from a depressed Cylon." + +/obj/item/clothing/suit/space/vox/carapace + name = "alien carapace armour" + icon_state = "vox-carapace" + item_state = "vox-carapace" + desc = "An armoured, segmented carapace with glowing purple lights. It looks pretty run-down." + slowdown = 1 + +/obj/item/clothing/head/helmet/space/vox/stealth + name = "alien stealth helmet" + icon_state = "vox-stealth" + item_state = "vox-stealth" + desc = "A smoothly contoured, matte-black alien helmet." + +/obj/item/clothing/suit/space/vox/stealth + name = "alien stealth suit" + icon_state = "vox-stealth" + item_state = "vox-stealth" + desc = "A sleek black suit. It seems to have a tail, and is very heavy." + +/obj/item/clothing/head/helmet/space/vox/medic + name = "alien goggled helmet" + icon_state = "vox-medic" + item_state = "vox-medic" + desc = "An alien helmet with enormous goggled lenses." + +/obj/item/clothing/suit/space/vox/medic + name = "alien armour" + icon_state = "vox-medic" + item_state = "vox-medic" + desc = "An almost organic looking nonhuman pressure suit." diff --git a/yogstation/code/modules/clothing/suits/_suits.dm b/yogstation/code/modules/clothing/suits/_suits.dm new file mode 100644 index 0000000000000..3772a3097154a --- /dev/null +++ b/yogstation/code/modules/clothing/suits/_suits.dm @@ -0,0 +1,2 @@ +/obj/item/clothing/suit + sprite_sheets = list(SPECIES_VOX = VOX_SUIT_FILE) diff --git a/yogstation/code/modules/clothing/suits/miscellaneous.dm b/yogstation/code/modules/clothing/suits/miscellaneous.dm index 09dec5e8907e6..f5d7016d9b9df 100644 --- a/yogstation/code/modules/clothing/suits/miscellaneous.dm +++ b/yogstation/code/modules/clothing/suits/miscellaneous.dm @@ -403,3 +403,32 @@ desc = "You're taking the piss outta this, aren't you?" icon_state = "urinal" item_state = "urinal" + +/obj/item/clothing/suit/hooded/vox_robes + name = "alien hooded robes" + desc = "Large, comfortable robes worn by those who need a bit more covering. The thick fabric contains a pocket suitable for those that need their hands free during their work, while the cloth serves to cover scars or other injuries to the wearer's body." + icon = VOX_SUIT_FILE + icon_state = "vox-robes" + item_state = "vox-robes" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + hoodtype = /obj/item/clothing/head/hooded/vox_robe_hood + species_restricted = list(SPECIES_VOX) + +/obj/item/clothing/head/hooded/vox_robe_hood + name = "alien hood" + desc = "The thick fabric of this hood serves a variety of purposes to the vox wearing it - serving as a method to hide a scarred face or a way to keep warm in the coldest areas onboard the ship." + icon = VOX_HEAD_FILE + icon_state = "vox-robes-hood" + item_state = "vox-robes-hood" + flags_inv = HIDEHAIR + flags_cover = HEADCOVERSEYES + species_restricted = list(SPECIES_VOX) + +/obj/item/clothing/suit/armor/vox_scrap + name = "rusted metal armor" + desc = "A hodgepodge of various pieces of metal scrapped together into a rudimentary vox-shaped piece of armor." + allowed = list(/obj/item/gun, /obj/item/tank) + armor = list(MELEE = 70, BULLET = 30, LASER = 20, ENERGY = 5, BOMB = 40, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, WOUND = 15) //Higher melee armor versus lower everything else. + icon_state = "vox-scrap" + body_parts_covered = CHEST|ARMS|GROIN|LEGS + species_restricted = list(SPECIES_VOX) diff --git a/yogstation/code/modules/clothing/under/_under.dm b/yogstation/code/modules/clothing/under/_under.dm new file mode 100644 index 0000000000000..9b8a4beeba166 --- /dev/null +++ b/yogstation/code/modules/clothing/under/_under.dm @@ -0,0 +1,2 @@ +/obj/item/clothing/under + sprite_sheets = list(SPECIES_VOX = VOX_UNIFORM_FILE) diff --git a/yogstation/code/modules/clothing/under/color.dm b/yogstation/code/modules/clothing/under/color.dm new file mode 100644 index 0000000000000..ece2b7d9933bc --- /dev/null +++ b/yogstation/code/modules/clothing/under/color.dm @@ -0,0 +1,5 @@ +/obj/item/clothing/under/color + sprite_sheets = list("GAGS_sprite" = list(SPECIES_VOX)) + +/obj/item/clothing/under/skirt/color + sprite_sheets = list("GAGS_sprite" = list(SPECIES_VOX)) diff --git a/yogstation/code/modules/clothing/under/miscellaneous.dm b/yogstation/code/modules/clothing/under/miscellaneous.dm index 0ae9bc0d23803..193b7b42e5cd2 100644 --- a/yogstation/code/modules/clothing/under/miscellaneous.dm +++ b/yogstation/code/modules/clothing/under/miscellaneous.dm @@ -574,3 +574,28 @@ item_state = "hawaiian_skirt" fitted = FEMALE_UNIFORM_TOP //no hole in the skirt can_adjust = 0 + +/obj/item/clothing/under/rank/prisoner + sprite_sheets = list("GAGS_sprite" = list(SPECIES_VOX)) + +/obj/item/clothing/under/vox + icon = 'icons/obj/clothing/species/vox/uniforms.dmi' + species_restricted = list(SPECIES_VOX) + +/obj/item/clothing/under/vox/vox_casual + name = "alien clothing" + desc = "This doesn't look very comfortable." + icon_state = "vox-casual-1" + item_state = "vox-casual-1" + +/obj/item/clothing/under/vox/vox_robes + name = "alien robes" + desc = "Weird and flowing!" + icon_state = "vox-casual-2" + item_state = "vox-casual-2" + +/obj/item/clothing/under/vox/vox_casual + name = "alien jumpsuit" + desc = "These loose clothes are optimized for the labors of the lower castes onboard the arkships. Large openings in the top allow for breathability while the pants are durable yet flexible enough to not restrict movement." + icon_state = "vox-jumpsuit" + item_state = "vox-jumpsuit" diff --git a/yogstation/code/modules/food_and_drinks/food/recipes/tablecraft/recipes_meat.dm b/yogstation/code/modules/food_and_drinks/food/recipes/tablecraft/recipes_meat.dm new file mode 100644 index 0000000000000..c1ee2c11344e1 --- /dev/null +++ b/yogstation/code/modules/food_and_drinks/food/recipes/tablecraft/recipes_meat.dm @@ -0,0 +1,8 @@ +/datum/crafting_recipe/food/fried_vox + name = "Kentucky Fried Vox" + reqs = list( + /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/vox = 1, + /obj/item/stack/sheet/animalhide/vox = 1 + ) + result = /obj/item/reagent_containers/food/snacks/fried_vox + category = CAT_MEAT diff --git a/yogstation/code/modules/food_and_drinks/food/snacks/meat.dm b/yogstation/code/modules/food_and_drinks/food/snacks/meat.dm index fd94bd15add46..18cede39ff294 100644 --- a/yogstation/code/modules/food_and_drinks/food/snacks/meat.dm +++ b/yogstation/code/modules/food_and_drinks/food/snacks/meat.dm @@ -3,4 +3,11 @@ desc = "Damn dirty steak." filling_color = "#FF0000" tastes = list("meat" = 4, "fur" = 1) - foodtype = MEAT | RAW \ No newline at end of file + foodtype = MEAT | RAW + +/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/vox + icon_state = "voxmeat" + desc = "Surprisingly, it doesn't actually taste like chicken." + filling_color = COLOR_BLOOD_VOX + tastes = list("skrek" = 1) + foodtype = MEAT | RAW | TOXIC diff --git a/yogstation/code/modules/food_and_drinks/food/snacks_meat.dm b/yogstation/code/modules/food_and_drinks/food/snacks_meat.dm new file mode 100644 index 0000000000000..edf48bd61ff9b --- /dev/null +++ b/yogstation/code/modules/food_and_drinks/food/snacks_meat.dm @@ -0,0 +1,7 @@ +/obj/item/reagent_containers/food/snacks/fried_vox + name = "Kentucky Fried Vox" + desc = "11 herbs and spices." + icon_state = "fried_vox" + trash = /obj/item/trash/fried_vox + list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/protein = 5) + tastes = list("quills" = 1, "the Shoal" = 1) diff --git a/yogstation/code/modules/language/language_holder.dm b/yogstation/code/modules/language/language_holder.dm new file mode 100644 index 0000000000000..df4e5f7e51fb6 --- /dev/null +++ b/yogstation/code/modules/language/language_holder.dm @@ -0,0 +1,5 @@ +/datum/language_holder/vox + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/vox = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/vox = list(LANGUAGE_ATOM)) diff --git a/yogstation/code/modules/language/voxpidgin.dm b/yogstation/code/modules/language/voxpidgin.dm new file mode 100644 index 0000000000000..353c94f8a99b0 --- /dev/null +++ b/yogstation/code/modules/language/voxpidgin.dm @@ -0,0 +1,11 @@ +/datum/language/vox + name = "Vox-pidgin" + desc = "The common tongue of the various Vox ships making up the Shoal. It sounds like chaotic shrieking to everyone else." + speech_verb = "shrieks" + ask_verb = "creels" + exclaim_verb = "loudly skrees" + key = "v" + syllables = list("ti","ti","ti","hi","hi","ki","ki","ki","ki","ya","ta","ha","ka","ya","yi","chi","cha","kah", \ + "SKRE","AHK","EHK","RAWK","KRA","AAA","EEE","KI","II","KRI","KA") + default_priority = 90 + icon_state = "voxpidgin" diff --git a/yogstation/code/modules/mob/dead/new_player/sprite_accessories.dm b/yogstation/code/modules/mob/dead/new_player/sprite_accessories.dm index b6c3742e18d4f..8b4a7c4825887 100644 --- a/yogstation/code/modules/mob/dead/new_player/sprite_accessories.dm +++ b/yogstation/code/modules/mob/dead/new_player/sprite_accessories.dm @@ -1,5 +1,303 @@ +/datum/sprite_accessory + var/color_blend_mode = COLOR_BLEND_MULTIPLY + ///the body slots outside of the main slot this accessory exists in, so we can draw to those spots seperately + var/list/body_slots = list() + /// the list of external organs covered + var/list/external_slots = list() + var/list/sprite_sheets = list() //For accessories common across species but need to use 'fitted' sprites (like underwear). e.g. list(SPECIES_VOX = 'icons/mob/species/vox/iconfile.dmi') + +/datum/sprite_accessory/undershirt + sprite_sheets = list(SPECIES_VOX = 'icons/mob/clothing/species/vox/undershirt.dmi') + /datum/sprite_accessory/undershirt/goose name = "Shirt (Vomit Goose)" icon_state = "vomitgooseshirt" icon = 'yogstation/icons/mob/clothing/sprite_accessories/undershirt.dmi' gender = NEUTER + +/datum/sprite_accessory/underwear + sprite_sheets = list(SPECIES_VOX = 'icons/mob/clothing/species/vox/underwear.dmi') + +/datum/sprite_accessory/socks + sprite_sheets = list(SPECIES_VOX = 'icons/mob/clothing/species/vox/socks.dmi') + +// Vox Accessories + +/datum/sprite_accessory/vox_quills + icon = 'icons/mob/species/vox/quills.dmi' + color_src = HAIR + color_blend_mode = COLOR_BLEND_ADD + +/datum/sprite_accessory/vox_quills/none + name = "None" + icon_state = "none" + +/datum/sprite_accessory/vox_quills/crested + name = "Crested" + icon_state = "crested" + +/datum/sprite_accessory/vox_quills/emperor + name = "Emperor" + icon_state = "emperor" + +/datum/sprite_accessory/vox_quills/keel + name = "Keel" + icon_state = "keel" + +/datum/sprite_accessory/vox_quills/keet + name = "Keet" + icon_state = "keet" + +/datum/sprite_accessory/vox_quills/short + name = "Short" + icon_state = "short" + +/datum/sprite_accessory/vox_quills/tiel + name = "Tiel" + icon_state = "tiel" + +/datum/sprite_accessory/vox_quills/kingly + name = "Kingly" + icon_state = "kingly" + +/datum/sprite_accessory/vox_quills/afro + name = "Fluffy" + icon_state = "afro" + +/datum/sprite_accessory/vox_quills/yasuhiro + name = "Long" + icon_state = "yasuhiro" + +/datum/sprite_accessory/vox_quills/razor + name = "Razorback" + icon_state = "razor" + +/datum/sprite_accessory/vox_quills/razor_clipped + name = "Clipped Razorback" + icon_state = "razor_clipped" + +/datum/sprite_accessory/vox_quills/long_braid + name = "Long Braided" + icon_state = "long_braid" + +/datum/sprite_accessory/vox_quills/short_braid + name = "Short Braided" + icon_state = "short_braid" + +/datum/sprite_accessory/vox_quills/mowhawk + name = "Mohawk" + icon_state = "mohawk" + +/datum/sprite_accessory/vox_quills/hawk + name = "Hawk" + icon_state = "hawk" + +/datum/sprite_accessory/vox_quills/horns + name = "Horns" + icon_state = "horns" + +/datum/sprite_accessory/vox_quills/mange + name = "Mange" + icon_state = "mange" + +/datum/sprite_accessory/vox_quills/ponytail + name = "Ponytail" + icon_state = "ponytail" + +/datum/sprite_accessory/vox_quills/rows + name = "Rows" + icon_state = "rows" + +/datum/sprite_accessory/vox_quills/surf + name = "Surf" + icon_state = "surf" + +/datum/sprite_accessory/vox_quills/flowing + name = "Flowing" + icon_state = "flowing" + +/datum/sprite_accessory/vox_quills/nights + name = "Nights" + icon_state = "nights" + +/datum/sprite_accessory/vox_quills/cropped + name = "Cropped" + icon_state = "cropped" + +/datum/sprite_accessory/vox_facial_quills + icon = 'icons/mob/species/vox/facial_quills.dmi' + color_src = FACEHAIR + color_blend_mode = COLOR_BLEND_ADD + +/datum/sprite_accessory/vox_facial_quills/none + name = "None" + icon_state = "none" + +/datum/sprite_accessory/vox_facial_quills/colonel + name = "Colonel" + icon_state = "colonel" + +/datum/sprite_accessory/vox_facial_quills/fu + name = "Fu" + icon_state = "fu" + +/datum/sprite_accessory/vox_facial_quills/neck + name = "Neck" + icon_state = "neck" + +/datum/sprite_accessory/vox_facial_quills/beard + name = "Beard" + icon_state = "beard" + +/datum/sprite_accessory/vox_facial_quills/ruff + name = "Ruff" + icon_state = "ruff" + +/datum/sprite_accessory/vox_tails + icon = 'icons/mob/species/vox/tails.dmi' + color_src = NONE + +/datum/sprite_accessory/vox_tails/lime + name = "lime" + icon_state = "lime" + +/datum/sprite_accessory/vox_tails/crimson + name = "crimson" + icon_state = "crimson" + +/datum/sprite_accessory/vox_tails/grey + name = "grey" + icon_state = "grey" + +/datum/sprite_accessory/vox_tails/nebula + name = "nebula" + icon_state = "nebula" + +/datum/sprite_accessory/vox_tails/azure + name = "azure" + icon_state = "azure" + +/datum/sprite_accessory/vox_tails/emerald + name = "emerald" + icon_state = "emerald" + +/datum/sprite_accessory/vox_tails/brown + name = "brown" + icon_state = "brown" + +/datum/sprite_accessory/vox_tails/plum + name = "plum" + icon_state = "plum" + +/datum/sprite_accessory/vox_tails/mossy + name = "mossy" + icon_state = "mossy" + +/datum/sprite_accessory/tails_animated/vox + icon = 'icons/mob/species/vox/tails.dmi' + color_src = NONE + +/datum/sprite_accessory/tails_animated/vox/lime + name = "lime" + icon_state = "lime" + +/datum/sprite_accessory/tails_animated/vox/crimson + name = "crimson" + icon_state = "crimson" + +/datum/sprite_accessory/tails_animated/vox/grey + name = "grey" + icon_state = "grey" + +/datum/sprite_accessory/tails_animated/vox/nebula + name = "nebula" + icon_state = "nebula" + +/datum/sprite_accessory/tails_animated/vox/azure + name = "azure" + icon_state = "azure" + +/datum/sprite_accessory/tails_animated/vox/emerald + name = "emerald" + icon_state = "emerald" + +/datum/sprite_accessory/tails_animated/vox/brown + name = "brown" + icon_state = "brown" + +/datum/sprite_accessory/tails_animated/vox/plum + name = "plum" + icon_state = "plum" + +/datum/sprite_accessory/tails_animated/vox/mossy + name = "mossy" + icon_state = "mossy" + +/datum/sprite_accessory/vox_body_markings + icon = 'icons/mob/species/vox/body_markings.dmi' + color_blend_mode = COLOR_BLEND_ADD + +/datum/sprite_accessory/vox_body_markings/none + name = "None" + +/datum/sprite_accessory/vox_body_markings/heart + name = "Heart" + icon_state = "heart" + body_slots = list(BODY_ZONE_R_ARM) + +/datum/sprite_accessory/vox_body_markings/hive + name = "Hive" + icon_state = "hive" + body_slots = list(BODY_ZONE_CHEST) + +/datum/sprite_accessory/vox_body_markings/nightling + name = "Nightling" + icon_state = "nightling" + body_slots = list(BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) + +/datum/sprite_accessory/vox_body_markings/tiger_body + name = "Tiger-stripe" + icon_state = "tiger" + body_slots = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + +/datum/sprite_accessory/vox_tail_markings + icon = 'icons/mob/species/vox/tail_markings.dmi' + color_src = MUTCOLORS_SECONDARY + color_blend_mode = COLOR_BLEND_ADD + +/datum/sprite_accessory/vox_tail_markings/none + name = "None" + icon_state = "none" + +/datum/sprite_accessory/vox_tail_markings/bands + name = "Bands" + icon_state = "bands" + +/datum/sprite_accessory/vox_tail_markings/tip + name = "Tip" + icon_state = "tip" + +/datum/sprite_accessory/vox_tail_markings/stripe + name = "Stripe" + icon_state = "stripe" + +/datum/sprite_accessory/vox_tail_markings_animated + icon = 'icons/mob/species/vox/tail_markings.dmi' + color_src = MUTCOLORS_SECONDARY + color_blend_mode = COLOR_BLEND_ADD + +/datum/sprite_accessory/vox_tail_markings_animated/none + name = "None" + icon_state = "none" + +/datum/sprite_accessory/vox_tail_markings_animated/bands + name = "Bands" + icon_state = "bands" + +/datum/sprite_accessory/vox_tail_markings_animated/tip + name = "Tip" + icon_state = "tip" + +/datum/sprite_accessory/vox_tail_markings_animated/stripe + name = "Stripe" + icon_state = "stripe" diff --git a/yogstation/code/modules/mob/living/brain/MMI.dm b/yogstation/code/modules/mob/living/brain/MMI.dm index 6fc408eca8df5..f95595d96224f 100644 --- a/yogstation/code/modules/mob/living/brain/MMI.dm +++ b/yogstation/code/modules/mob/living/brain/MMI.dm @@ -6,7 +6,7 @@ brain = newbrain name = "[initial(name)]: [brain.real_name]" - to_chat(brainmob, "(If your brain was removed after your death you don't remember how you died, or who killed you. See rule 1.6.") //yogs + to_chat(brainmob, "(If your [brain.brain_name] was removed after your death you don't remember how you died, or who killed you. See rule 1.6.") //yogs update_appearance(UPDATE_ICON) return diff --git a/yogstation/code/modules/mob/living/brain/brain_item.dm b/yogstation/code/modules/mob/living/brain/brain_item.dm index 72746d0c20e7e..f97f3554decb0 100644 --- a/yogstation/code/modules/mob/living/brain/brain_item.dm +++ b/yogstation/code/modules/mob/living/brain/brain_item.dm @@ -1,6 +1,27 @@ /obj/item/organ/brain var/real_name = null //the name we use for MMIs, only used by changelings + var/brain_name = "brain" /obj/item/organ/brain/transfer_identity(mob/living/L) real_name = L.real_name - .=..() \ No newline at end of file + .=..() + +/obj/item/organ/brain/proc/get_mmi_brain_sprite() + return "mmi_brain" + +/obj/item/organ/brain/alien/get_mmi_brain_sprite() + return "mmi_brain_alien" + +/obj/item/organ/brain/vox + name = "cortical stack" + brain_name = "cortical stack" + desc = "A peculiarly advanced bio-electronic device that seems to hold the memories and identity of a Vox." + icon_state = "cortical-stack" + decay_factor = 0 + +/obj/item/organ/brain/vox/get_mmi_brain_sprite() + return "mmi_cortical_stack" + +/obj/item/organ/brain/vox/emp_act(severity) + to_chat(owner, span_warning("Your head hurts.")) + owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, clamp(severity*5, 5, 50)) diff --git a/yogstation/code/modules/mob/living/carbon/human/emote.dm b/yogstation/code/modules/mob/living/carbon/human/emote.dm new file mode 100644 index 0000000000000..52f0013ab290f --- /dev/null +++ b/yogstation/code/modules/mob/living/carbon/human/emote.dm @@ -0,0 +1,20 @@ +/datum/emote/living/carbon/human/scream + message_vox = "shrieks!" + +/datum/emote/living/carbon/human/quill + key = "quill" + key_third_person = "quills" + message = "rustles their quills." + message_param = "rustles their quills at %t." + emote_type = EMOTE_AUDIBLE + // Credit to sound-ideas (freesfx.co.uk) for the sound. + +/datum/emote/living/carbon/human/quill/get_sound(mob/living/user) + return 'sound/effects/voxrustle.ogg' + +/datum/emote/living/carbon/human/quill/can_run_emote(mob/user, status_check, intentional) + . = ..() + if(!.) + return FALSE + if(!isvox(user)) + return FALSE diff --git a/yogstation/code/modules/mob/living/carbon/human/human.dm b/yogstation/code/modules/mob/living/carbon/human/human.dm index ea569d177b534..df1047b565ec5 100644 --- a/yogstation/code/modules/mob/living/carbon/human/human.dm +++ b/yogstation/code/modules/mob/living/carbon/human/human.dm @@ -16,6 +16,9 @@ /mob/living/carbon/human/species/pod/ivymen //jungleland race = /datum/species/pod/ivymen +/mob/living/carbon/human/species/vox + race = /datum/species/vox + /mob/living/carbon/human/get_blood_state() if(NOBLOOD in dna.species.species_traits) //Can't have blood problems if your species doesn't have any blood, innit? return BLOOD_SAFE diff --git a/yogstation/code/modules/mob/living/carbon/human/species.dm b/yogstation/code/modules/mob/living/carbon/human/species.dm index ad7bc8cb70482..f33f7a51deed7 100644 --- a/yogstation/code/modules/mob/living/carbon/human/species.dm +++ b/yogstation/code/modules/mob/living/carbon/human/species.dm @@ -4,6 +4,13 @@ /datum/species var/yogs_draw_robot_hair = FALSE //DAMN ROBOTS STEALING OUR HAIR AND AIR var/yogs_virus_infect_chance = 100 + var/generate_husk_icon = FALSE + var/limb_icon_file + var/list/parts_to_husk + var/eyes_icon = 'icons/mob/human_face.dmi' + var/list/static_part_body_zones + var/list/suicide_messages + var/list/survival_box_replacements /*= list(items_to_delete= list(), new_items= list())*/ /datum/species/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) . = ..() @@ -18,3 +25,58 @@ /datum/species/proc/spec_AltClickOn(atom/A,mob/living/carbon/human/H) return FALSE + +/datum/species/proc/return_accessory_layer(layer, datum/sprite_accessory/added_accessory, mob/living/carbon/human/host, passed_color) + var/list/return_list = list() + var/layertext = mutant_bodyparts_layertext(layer) + var/g = (host.gender == FEMALE) ? "f" : "m" + for(var/list_item in added_accessory.external_slots) + var/can_hidden_render = return_external_render_state(list_item, host) + if(!can_hidden_render) + continue // we failed the render check just dont bother + if(!host.getorganslot(list_item)) + continue + var/mutable_appearance/new_overlay = mutable_appearance(added_accessory.icon, layer = -layer) + if(added_accessory.gender_specific) + new_overlay.icon_state = "[g]_[list_item]_[added_accessory.icon_state]_[layertext]" + else + new_overlay.icon_state = "m_[list_item]_[added_accessory.icon_state]_[layertext]" + new_overlay.color = passed_color + return_list += new_overlay + + for(var/list_item in added_accessory.body_slots) + if(!host.get_bodypart(list_item)) + continue + var/mutable_appearance/new_overlay = mutable_appearance(added_accessory.icon, layer = -layer) + if(added_accessory.gender_specific) + new_overlay.icon_state = "[g]_[list_item]_[added_accessory.icon_state]_[layertext]" + else + new_overlay.icon_state = "m_[list_item]_[added_accessory.icon_state]_[layertext]" + new_overlay.color = passed_color + return_list += new_overlay + + return return_list + +/proc/return_external_render_state(external_slot, mob/living/carbon/human/human) + switch(external_slot) + if(ORGAN_SLOT_TAIL) + if(human.wear_suit && (human.wear_suit.flags_inv & HIDEJUMPSUIT)) + return FALSE + return TRUE + +/datum/species/proc/get_icon_variant(mob/living/carbon/person_to_check) + return + +/datum/species/proc/get_eyes_static(mob/living/carbon/person_to_check) + return + +/datum/species/proc/get_special_statics(mob/living/carbon/person_to_check) + return list() + +/datum/species/proc/survival_box_replacement(mob/living/carbon/human/box_holder, obj/item/storage/box/survival_box, list/soon_deleted_items, list/soon_added_items) + for(var/item as anything in soon_deleted_items) + var/obj/item/item_to_delete = (locate(item) in survival_box) + if(item_to_delete) + qdel(item_to_delete) + for(var/item as anything in soon_added_items) + new item(survival_box) diff --git a/yogstation/code/modules/mob/living/carbon/human/species_types/vox.dm b/yogstation/code/modules/mob/living/carbon/human/species_types/vox.dm new file mode 100644 index 0000000000000..7ca6869956d43 --- /dev/null +++ b/yogstation/code/modules/mob/living/carbon/human/species_types/vox.dm @@ -0,0 +1,185 @@ +/datum/species/vox + name = "Vox" + plural_form = "Vox" + id = SPECIES_VOX + is_dimorphic = FALSE + generate_husk_icon = TRUE + species_traits = list(EYECOLOR, HAS_TAIL, HAS_FLESH, HAS_BONE, HAIRCOLOR, FACEHAIRCOLOR, MUTCOLORS, MUTCOLORS_SECONDARY) // Robust, but cannot be cloned easily. + inherent_traits = list(TRAIT_RESISTCOLD, TRAIT_NOCLONE) + mutant_bodyparts = list("vox_quills", "vox_body_markings", "vox_facial_quills", "vox_tail", "vox_tail_markings") + default_features = list("vox_quills" = "None", "vox_facial_quills" = "None", "vox_body_markings" = "None", "vox_tail" = "lime", "vox_tail_markings" = "None", "vox_skin_tone" = "lime") + attack_verbs = list("scratch", "claw") + attack_effect = ATTACK_EFFECT_CLAW + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + screamsound = list('sound/voice/vox/shriek1.ogg'/*, 'sound/voice/vox/ashriek.ogg'*/) + mutantbrain = /obj/item/organ/brain/vox // Brain damage on EMP + mutantheart = /obj/item/organ/heart/vox + mutantliver = /obj/item/organ/liver/vox // Liver damage on EMP + mutantstomach = /obj/item/organ/stomach/vox // Disgust on EMP + mutanttongue = /obj/item/organ/tongue/vox + mutantlungs = /obj/item/organ/lungs/vox // Causes them to.. gasp. + mutantears = /obj/item/organ/ears/vox // Very brief deafness + mutanteyes = /obj/item/organ/eyes/vox // Quick hallucination + mutanttail = /obj/item/organ/tail/vox + mutantappendix = /obj/item/organ/appendix/vox + meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/vox + skinned_type = /obj/item/stack/sheet/animalhide/vox + changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT + breathid = "n2" + suicide_messages = list( + "%%SUICIDER%% is jamming %%P_THEIR%% claws into %%P_THEIR%% eye sockets!", + "%%SUICIDER%% is deeply inhaling oxygen!") + husk_color = null + eyes_icon = 'icons/mob/species/vox/eyes.dmi' + icon_husk = 'icons/mob/species/vox/bodyparts.dmi' + limb_icon_file = 'icons/mob/species/vox/bodyparts.dmi' + static_part_body_zones = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + parts_to_husk = list("vox_tail", "vox_tail_markings", "wagging_vox_tail", "wagging_vox_tail_markings", "vox_body_markings") + survival_box_replacements = list(items_to_delete = list(/obj/item/clothing/mask/breath, /obj/item/tank/internals/emergency_oxygen),\ + new_items = list(/obj/item/tank/internals/emergency_oxygen/nitrogen, /obj/item/clothing/mask/breath/vox)) + creampie_id = "creampie_vox" + exotic_bloodtype = "V" + smells_like = "musty quills" + liked_food = MEAT | FRIED + species_language_holder = /datum/language_holder/vox + +/datum/species/vox/get_species_description() + return "The Vox are remnants of an ancient race, that originate from arkships. \ + These bioengineered, reptilian, beaked, and quilled beings have a physiological caste system and follow 'The Inviolate' tenets. \ + Breathing pure nitrogen, they need specialized masks and tanks for survival outside their arkships. \ + Their insular nature limits their involvement in broader galactic affairs, maintaining a distinct, yet isolated presence away from other species." + +/datum/species/vox/get_species_lore() + return list("Vox have no colonies of their own to speak of. Most Vox originate from a location known as the Shoal, a sprawling, labyrinth-like space megalith of debris and asteroids fused together over countless orbits. It is there where their cutthroat and opportunistic behavior stems from.",\ + "Little is known of Vox history itself, as the Vox do not keep many records beyond personal accomplishments and tales of profit and triumph. They have lived among the Shoal and the stars as long as they or anyone else can remember.",\ + "It is possible the species went through a dark age before being introduced to the greater galactic community. Those taken by Vox raiders are rumored to be taken back to the Shoal to be sold as slaves. Other rumors speculate those not cut out to be slaves are sold by fleshpeddlers for “extraction”.",\ + "Many Vox have grown fond of life among the stars, and typically avoid living on planetary colonies. They have a penchant for capitalism and goods peddling, deep space salvage, and sometimes interstellar crime. Many Vox now seek their fortune on the border of civilized space. Some trading with stations and worlds as (questionably legal) merchants, or applying to work for any one of the countless mega-corporations on the frontier. Others profit off crime and marauding, hijacking ships, cargo, and sometimes people to bring back to the Shoal.") + +/datum/species/vox/get_butt_sprite() + return BUTT_SPRITE_VOX + +/datum/species/vox/get_cough_sound(mob/living/carbon/human/vox) + return 'sound/voice/vox/shriekcough.ogg' + +/datum/species/vox/get_sneeze_sound(mob/living/carbon/human/vox) + return 'sound/voice/vox/shrieksneeze.ogg' + +/datum/species/vox/random_name(unique) + if(unique) + return random_unique_vox_name() + return capitalize(vox_name()) + +/datum/species/vox/go_bald(mob/living/carbon/human/vox) + if(QDELETED(vox)) //may be called from a timer + return + vox.dna.features["vox_facial_quills"] = "None" + vox.dna.features["vox_quills"] = "None" + vox.dna.update_uf_block(DNA_VOX_FACIAL_QUILLS_BLOCK) + vox.dna.update_uf_block(DNA_VOX_QUILLS_BLOCK) + vox.update_hair() + +/datum/species/vox/survival_box_replacement(mob/living/carbon/human/box_holder, obj/item/storage/box/survival_box, list/soon_deleted_items, list/soon_added_items) + var/mask_to_replace = /obj/item/clothing/mask/breath/vox + if(mask_to_replace in soon_added_items) + var/list/possible_masks = list(/obj/item/clothing/mask/breath/vox, /obj/item/clothing/mask/breath/vox/respirator) + soon_added_items -= mask_to_replace + soon_added_items += pick(possible_masks) + ..() + +/datum/species/vox/after_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE) // Don't forget your voxygen tank + if(!H.can_breathe_mask()) + var/obj/item/clothing/mask/current_mask = H.get_item_by_slot(ITEM_SLOT_MASK) + if(!H.equip_to_slot_if_possible(current_mask, ITEM_SLOT_BACKPACK, disable_warning = TRUE)) + H.put_in_hands(current_mask) + var/obj/item/clothing/mask/vox_mask + var/mask_pref = H.client?.prefs?.read_preference(/datum/preference/choiced/vox_mask) + if(mask_pref == "Respirator") + vox_mask = new /obj/item/clothing/mask/breath/vox/respirator + else + vox_mask = new /obj/item/clothing/mask/breath/vox + H.equip_to_slot_or_del(vox_mask, ITEM_SLOT_MASK) + var/obj/item/tank/internals_tank + var/tank_pref = H.client?.prefs?.read_preference(/datum/preference/choiced/vox_tank_type) + if(tank_pref == "Large") + internals_tank = new /obj/item/tank/internals/nitrogen + else + internals_tank = new /obj/item/tank/internals/emergency_oxygen/vox + if(!H.equip_to_appropriate_slot(internals_tank)) + H.put_in_hands(internals_tank) + to_chat(H, span_notice("You are now running on nitrogen internals from [internals_tank]. Your species finds oxygen toxic, so you must breathe pure nitrogen.")) + H.open_internals(internals_tank) + +/datum/species/vox/get_icon_variant(mob/living/carbon/person_to_check) + return person_to_check.dna.features["vox_skin_tone"] + +/datum/species/vox/get_footprint_sprite() + return FOOTPRINT_SPRITE_CLAWS + +/datum/species/vox/get_eyes_static(mob/living/carbon/person_to_check) + var/list/blue_static_skin_tones = list("crimson", "mossy") + if(person_to_check.dna.features["vox_skin_tone"] in blue_static_skin_tones) + return "blue" + else + return "green" + +/datum/species/vox/handle_body(mob/living/carbon/human/H) + update_skin_tone(H) + ..() + +/datum/species/vox/proc/update_skin_tone(mob/living/carbon/human/vox, skin_tone) + if(!skin_tone) + skin_tone = vox.dna.features["vox_skin_tone"] + vox.dna.features["vox_skin_tone"] = skin_tone + vox.dna.update_uf_block(DNA_VOX_SKIN_TONE_BLOCK) + var/obj/item/organ/tail/vox/vox_tail = vox.getorganslot(ORGAN_SLOT_TAIL) + if(vox_tail && istype(vox_tail)) + vox_tail.update_tail_appearance(vox) + +/datum/species/vox/get_special_statics(mob/living/carbon/human/vox) + return list("mossy") + +/datum/species/vox/create_pref_unique_perks() + var/list/to_add = list() + + to_add += list( + list( + SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK, + SPECIES_PERK_ICON = "temperature-low", + SPECIES_PERK_NAME = "Cold Resistance", + SPECIES_PERK_DESC = "Vox hides provide excellent insulation against the coldness of space.", + ), + list( + SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK, + SPECIES_PERK_ICON = "heart-circle-check", + SPECIES_PERK_NAME = "Imperishable Organs", + SPECIES_PERK_DESC = "Vox organs contain advanced cybernetics that prevent them from decaying.", + ), + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "bolt", + SPECIES_PERK_NAME = "EMP Sensitivity", + SPECIES_PERK_DESC = "Due to their organs being partially synthetic, they are susceptible to EMP damage.", + ), + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "head-side-mask", + SPECIES_PERK_NAME = "Nitrogen Breathing", + SPECIES_PERK_DESC = "Oxygen is toxic to Vox, they must breathe pure nitrogen.", + ), + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "dna", + SPECIES_PERK_NAME = "Unclonable", + SPECIES_PERK_DESC = "Their peculiar physiology prevents Vox from being cloned.", + ), + ) + + return to_add + +/datum/species/vox/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.type == /datum/reagent/gas/oxygen) + H.adjustToxLoss(1*REAGENTS_EFFECT_MULTIPLIER) + H.reagents.remove_reagent(chem.type, chem.metabolization_rate) + return FALSE + return ..() diff --git a/yogstation/code/modules/reagents/chemistry/reagents/other_reagents.dm b/yogstation/code/modules/reagents/chemistry/reagents/other_reagents.dm index 21fd26add6eda..62336c19d1fc8 100644 --- a/yogstation/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/yogstation/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -12,6 +12,11 @@ race = /datum/species/pod/ivymen mutationtext = span_danger("The pain subsides. You feel... thorny.") +/datum/reagent/mutationtoxin/vox + name = "Vox Mutation Toxin" + race = /datum/species/vox + mutationtext = span_danger("The pain subsides. You feel... beaked.") + /datum/reagent/cluwnification name = "Cluwne Tears" description = "Tears from thousands of cluwnes compressed into a dangerous cluwnification virus." diff --git a/yogstation/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/yogstation/code/modules/reagents/chemistry/recipes/slime_extracts.dm index 21de610a504a3..6edc2bf3ca81e 100644 --- a/yogstation/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/yogstation/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -4,4 +4,12 @@ results = list(/datum/reagent/mutationtoxin/gorilla = 1) required_reagents = list(/datum/reagent/consumable/milk = 1) required_other = TRUE - required_container = /obj/item/slime_extract/green \ No newline at end of file + required_container = /obj/item/slime_extract/green + +/datum/chemical_reaction/slime/slimevox + name = "Vox Mutation Toxin" + id = "voxmuttoxin" + results = list(/datum/reagent/mutationtoxin/vox = 1) + required_reagents = list(/datum/reagent/gas/nitrogen = 1) + required_other = TRUE + required_container = /obj/item/slime_extract/green diff --git a/yogstation/code/modules/reagents/reagent_containers/blood_pack.dm b/yogstation/code/modules/reagents/reagent_containers/blood_pack.dm new file mode 100644 index 0000000000000..30b21a33d047b --- /dev/null +++ b/yogstation/code/modules/reagents/reagent_containers/blood_pack.dm @@ -0,0 +1,2 @@ +/obj/item/reagent_containers/blood/vox + blood_type = "V" diff --git a/yogstation/code/modules/research/designs/limbgrower_designs.dm b/yogstation/code/modules/research/designs/limbgrower_designs.dm new file mode 100644 index 0000000000000..f3956b3dc7b0c --- /dev/null +++ b/yogstation/code/modules/research/designs/limbgrower_designs.dm @@ -0,0 +1,49 @@ +/datum/design/vox_tail + name = "Vox Tail" + id = "voxtail" + build_type = LIMBGROWER + reagents_list = list(/datum/reagent/medicine/synthflesh = 20) + build_path = /obj/item/organ/tail/vox/fake + category = list("vox") + +/datum/design/vox_tongue + name = "Vox Tongue" + id = "voxtongue" + build_type = LIMBGROWER + reagents_list = list(/datum/reagent/medicine/synthflesh = 10) + build_path = /obj/item/organ/tongue/vox + category = list("vox") + +/datum/design/vox_eyes + name = "Vox Eyes" + id = "voxeyes" + build_type = LIMBGROWER + reagents_list = list(/datum/reagent/medicine/synthflesh = 10) + build_path = /obj/item/organ/eyes/vox + category = list("vox") + +/datum/design/vox_liver + name = "Vox Liver" + id = "voxliver" + build_type = LIMBGROWER + reagents_list = list(/datum/reagent/medicine/synthflesh = 10) + build_path = /obj/item/organ/liver/vox + category = list("vox") + +/datum/design/vox_lungs + name = "Vox Lungs" + id = "voxlungs" + build_type = LIMBGROWER + reagents_list = list(/datum/reagent/medicine/synthflesh = 10) + build_path = /obj/item/organ/lungs/vox + category = list("vox") + +/obj/item/disk/design_disk/limbs/vox + name = "Vox Limb Design Disk" + limb_designs = list(/datum/design/vox_tail, /datum/design/vox_tongue, /datum/design/vox_eyes, /datum/design/vox_liver, /datum/design/vox_lungs) + +/datum/design/limb_disk/vox + name = "Vox Limb Design Disk" + desc = "Contains designs for vox organs for the limbgrower - Vox tail, tongue, eyes, liver, and lungs." + id = "limbdesign_vox" + build_path = /obj/item/disk/design_disk/limbs/vox diff --git a/yogstation/code/modules/scripting/Implementations/telecomms_translator.dm b/yogstation/code/modules/scripting/Implementations/telecomms_translator.dm index a8e16f0520250..64ebda9594e76 100644 --- a/yogstation/code/modules/scripting/Implementations/telecomms_translator.dm +++ b/yogstation/code/modules/scripting/Implementations/telecomms_translator.dm @@ -13,6 +13,7 @@ #define MOTH (1<<9) #define CAT (1<<10) #define ENGLISH (1<<11) +#define VOXPIDGIN (1<<12) ///Span classes that players are allowed to set in a radio transmission. GLOBAL_LIST_INIT(allowed_custom_spans, list( @@ -146,6 +147,8 @@ GLOBAL_LIST_INIT(allowed_translations, list( "mothian" = MOTH, "cat" = CAT, "english" = ENGLISH, + "voxpidgin" = VOXPIDGIN, + ))) interpreter.Run() // run the thing @@ -194,6 +197,8 @@ GLOBAL_LIST_INIT(allowed_translations, list( oldlangbits = CAT if(/datum/language/english) oldlangbits = ENGLISH + if(/datum/language/vox) + oldlangbits = VOXPIDGIN // Signal data var/datum/n_struct/signal/script_signal = new(list( @@ -336,6 +341,8 @@ GLOBAL_LIST_INIT(allowed_translations, list( return /datum/language/felinid if(ENGLISH) return /datum/language/english + if(VOXPIDGIN) + return /datum/language/vox /datum/n_function/default/mem name = "mem" @@ -516,3 +523,4 @@ GLOBAL_LIST_INIT(allowed_translations, list( #undef MOTH #undef CAT #undef ENGLISH +#undef VOXPIDGIN diff --git a/yogstation/code/modules/surgery/bodypart.dm b/yogstation/code/modules/surgery/bodypart.dm deleted file mode 100644 index 14ac6280c2fce..0000000000000 --- a/yogstation/code/modules/surgery/bodypart.dm +++ /dev/null @@ -1,2 +0,0 @@ -/obj/item/bodypart - var/yogs_draw_robot_hair = FALSE \ No newline at end of file diff --git a/yogstation/code/modules/surgery/bodyparts/_bodyparts.dm b/yogstation/code/modules/surgery/bodyparts/_bodyparts.dm new file mode 100644 index 0000000000000..0bc726993e3c1 --- /dev/null +++ b/yogstation/code/modules/surgery/bodyparts/_bodyparts.dm @@ -0,0 +1,5 @@ +/obj/item/bodypart + var/yogs_draw_robot_hair = FALSE + var/has_static_sprite_part = FALSE + var/limb_icon_variant + var/limb_icon_file diff --git a/yogstation/code/modules/surgery/bodyparts/head.dm b/yogstation/code/modules/surgery/bodyparts/head.dm new file mode 100644 index 0000000000000..f7bea89ccf543 --- /dev/null +++ b/yogstation/code/modules/surgery/bodyparts/head.dm @@ -0,0 +1,2 @@ +/obj/item/bodypart/head + var/eyes_static diff --git a/yogstation/code/modules/surgery/organs/appendix.dm b/yogstation/code/modules/surgery/organs/appendix.dm new file mode 100644 index 0000000000000..04d6e36bc17ad --- /dev/null +++ b/yogstation/code/modules/surgery/organs/appendix.dm @@ -0,0 +1,4 @@ +/obj/item/organ/appendix/vox + name = "vox appendix" + icon_state = "appendix-vox" + decay_factor = 0 diff --git a/yogstation/code/modules/surgery/organs/ears.dm b/yogstation/code/modules/surgery/organs/ears.dm new file mode 100644 index 0000000000000..c34b92c799573 --- /dev/null +++ b/yogstation/code/modules/surgery/organs/ears.dm @@ -0,0 +1,8 @@ +/obj/item/organ/ears/vox + name = "vox ears" + icon_state = "ears-vox" + desc = "Researchers hypothesize that the titanium reinforced tympanic membrane takes the piercing edge off their own shrieking." + decay_factor = 0 + +/obj/item/organ/ears/vox/emp_act() + deaf = 10 diff --git a/yogstation/code/modules/surgery/organs/eyes.dm b/yogstation/code/modules/surgery/organs/eyes.dm new file mode 100644 index 0000000000000..6c15ab93a4be8 --- /dev/null +++ b/yogstation/code/modules/surgery/organs/eyes.dm @@ -0,0 +1,7 @@ +/obj/item/organ/eyes/vox + name = "vox eyes" + icon_state = "eyes-vox" + decay_factor = 0 + +/obj/item/organ/eyes/vox/emp_act() + owner.adjust_hallucinations(10 SECONDS) diff --git a/yogstation/code/modules/surgery/organs/heart.dm b/yogstation/code/modules/surgery/organs/heart.dm index da98967b4da45..e78fb3ee7e2cd 100644 --- a/yogstation/code/modules/surgery/organs/heart.dm +++ b/yogstation/code/modules/surgery/organs/heart.dm @@ -20,3 +20,8 @@ to_chat(owner, span_userdanger("You feel your heart collapse in on itself!")) Remove(owner) //the heart is made of nanites so without them it just breaks down qdel(src) + +/obj/item/organ/heart/vox + name = "vox heart" + icon_state = "heart-vox" + decay_factor = 0 diff --git a/yogstation/code/modules/surgery/organs/liver.dm b/yogstation/code/modules/surgery/organs/liver.dm new file mode 100644 index 0000000000000..ad6e152497ae3 --- /dev/null +++ b/yogstation/code/modules/surgery/organs/liver.dm @@ -0,0 +1,4 @@ +/obj/item/organ/liver/vox + name = "vox liver" + icon_state = "liver-vox" + decay_factor = 0 diff --git a/yogstation/code/modules/surgery/organs/lungs.dm b/yogstation/code/modules/surgery/organs/lungs.dm index 0260538d8ce5f..1df5ddd6e405d 100644 --- a/yogstation/code/modules/surgery/organs/lungs.dm +++ b/yogstation/code/modules/surgery/organs/lungs.dm @@ -61,3 +61,18 @@ heat_level_2_threshold = 600 heat_level_3_threshold = 1100 +/obj/item/organ/lungs/vox + name = "vox lungs" + icon_state = "lungs-vox" + desc = "They're filled with dust...wow." + decay_factor = 0 + breathing_class = BREATH_VOX + +/obj/item/organ/lungs/vox/populate_gas_info() + ..() + gas_max[GAS_O2] = 0.05 + gas_max -= BREATH_VOX + gas_damage[GAS_O2] = list(min = MIN_TOXIC_GAS_DAMAGE, max = MAX_TOXIC_GAS_DAMAGE, damage_type = TOX) + +/obj/item/organ/lungs/vox/emp_act() + owner.emote("gasp") diff --git a/yogstation/code/modules/surgery/organs/stomach.dm b/yogstation/code/modules/surgery/organs/stomach.dm new file mode 100644 index 0000000000000..e52c02acff6f2 --- /dev/null +++ b/yogstation/code/modules/surgery/organs/stomach.dm @@ -0,0 +1,8 @@ +/obj/item/organ/stomach/vox + name = "gizzard" + icon_state = "stomach-vox" + desc = "Mechanical digestion." + decay_factor = 0 + +/obj/item/organ/stomach/vox/emp_act() + owner.adjust_disgust(10) diff --git a/yogstation/code/modules/surgery/organs/tails.dm b/yogstation/code/modules/surgery/organs/tails.dm new file mode 100644 index 0000000000000..8e90291f0c8da --- /dev/null +++ b/yogstation/code/modules/surgery/organs/tails.dm @@ -0,0 +1,73 @@ +/obj/item/organ/tail/vox + name = "vox tail" + desc = "A severed vox tail. Somewhere, no doubt, a vox hater is very pleased with themselves." + icon = 'icons/mob/species/vox/tails.dmi' + icon_state = "m_tail_lime_BEHIND" + tail_type = "lime" + var/icon_state_text = "m_tail_lime" + var/icon/constructed_tail_icon + var/tail_markings = "None" + var/tail_markings_color + var/original_owner + +/obj/item/organ/tail/vox/Initialize(mapload) + . = ..() + set_icon_state() + +/obj/item/organ/tail/vox/proc/set_icon_state() + icon_state_text = "m_tail_[tail_type]" + icon_state = "[icon_state_text]_BEHIND" + constructed_tail_icon = icon(initial(icon), icon_state) + var/icon/constructed_tail_icon_north = icon(constructed_tail_icon, dir = SOUTH) + constructed_tail_icon_north.Turn(180) + constructed_tail_icon.Insert(constructed_tail_icon_north, dir = NORTH) + if(tail_markings && tail_markings != "None") + var/datum/sprite_accessory/vox_tail_markings/vox_markings = GLOB.vox_tail_markings_list[tail_markings] + var/vox_markings_state_text = "m_vox_tail_markings_[vox_markings.icon_state]" + var/icon/constructed_markings = icon(vox_markings.icon, "[vox_markings_state_text]_BEHIND") + var/icon/constructed_markings_north = icon(constructed_markings, dir = SOUTH) + constructed_markings_north.Turn(180) + constructed_markings.Insert(constructed_markings_north, dir = NORTH) + constructed_markings.Blend(tail_markings_color, ICON_ADD) + constructed_tail_icon.Blend(constructed_markings, ICON_OVERLAY) + icon = constructed_tail_icon + +/obj/item/organ/tail/vox/Insert(mob/living/carbon/human/H, special = 0, drop_if_replaced = TRUE) + ..() + if(istype(H)) + if(!original_owner) + original_owner = H + var/default_part = H.dna.species.mutant_bodyparts["vox_tail"] + if(!default_part || default_part == "None") + if(original_owner != H) + H.dna.species.mutant_bodyparts["vox_tail"] = tail_type + else + tail_type = H.dna.species.mutant_bodyparts["vox_tail"] = H.dna.features["vox_skin_tone"] + + default_part = H.dna.species.mutant_bodyparts["vox_tail_markings"] + if(!default_part || default_part == "None") + if(original_owner != H) + H.dna.species.mutant_bodyparts["vox_tail_markings"] = tail_markings + else + tail_markings = H.dna.species.mutant_bodyparts["vox_tail_markings"] = H.dna.features["vox_tail_markings"] + H.update_body() + +/obj/item/organ/tail/vox/Remove(mob/living/carbon/human/H, special = 0) + ..() + if(istype(H)) + H.dna.species.mutant_bodyparts -= "vox_tail" + H.dna.species.mutant_bodyparts -= "vox_tail_markings" + update_tail_appearance(H) + set_icon_state() + H.update_body() + +/obj/item/organ/tail/vox/proc/update_tail_appearance(mob/living/carbon/human/tail_owner) + if(original_owner && original_owner != tail_owner) + return + tail_type = tail_owner.dna.features["vox_skin_tone"] + tail_markings = tail_owner.dna.features["vox_tail_markings"] + tail_markings_color = tail_owner.dna.features["mcolor_secondary"] + +/obj/item/organ/tail/vox/fake + name = "fabricated vox tail" + desc = "A fabricated severed vox tail. This one's made of synthflesh." diff --git a/yogstation/code/modules/surgery/organs/tongue.dm b/yogstation/code/modules/surgery/organs/tongue.dm new file mode 100644 index 0000000000000..e8c6e7a2cdf01 --- /dev/null +++ b/yogstation/code/modules/surgery/organs/tongue.dm @@ -0,0 +1,14 @@ +/obj/item/organ/tongue/vox + name = "vox tongue" + desc = "You almost swear you can hear it shrieking." + icon_state = "tongue-vox" + taste_sensitivity = 50 // There's not much need for taste when you're a scavenger. + +/obj/item/organ/tongue/vox/Initialize(mapload) + . = ..() + attack_verb += "skree'd" + +/obj/item/organ/tongue/vox/handle_speech(datum/source, list/speech_args) + ..() + if(prob(20)) + playsound(owner, 'sound/voice/vox/shriek1.ogg', 25, 1, 1) diff --git a/yogstation/code/modules/vending/gift.dm b/yogstation/code/modules/vending/gift.dm index a08225e21103b..b7edf63050ef3 100644 --- a/yogstation/code/modules/vending/gift.dm +++ b/yogstation/code/modules/vending/gift.dm @@ -39,6 +39,37 @@ /obj/item/toy/plush/foxplushie = 2, /obj/item/toy/plush/pkplushie = 2, /obj/item/toy/plush/cdragon = 2, + /obj/item/toy/plush/voxplushie = 2, + /obj/item/flag/nt = 2, + /obj/item/flag/clown = 2, + /obj/item/flag/mime = 2, + /obj/item/flag/ian = 2, + /obj/item/flag/species/slime = 2, + /obj/item/flag/species/skrell = 2, + /obj/item/flag/species/vox = 2, + /obj/item/flag/species/machine = 2, + /obj/item/flag/species/diona = 2, + /obj/item/flag/species/human = 2, + /obj/item/flag/species/greys = 2, + /obj/item/flag/species/kidan = 2, + /obj/item/flag/species/taj = 2, + /obj/item/flag/species/lizard = 2, + /obj/item/flag/species/vulp = 2, + /obj/item/flag/species/drask = 2, + /obj/item/flag/species/plasma = 2, + /obj/item/flag/species/moth = 2, + /obj/item/flag/cargo = 2, + /obj/item/flag/med = 2, + /obj/item/flag/sec = 2, + /obj/item/flag/rnd = 2, + /obj/item/flag/atmos = 2, + /obj/item/flag/command = 2, + /obj/item/flag/grey = 2, + /obj/item/flag/syndi = 2, + /obj/item/flag/wiz = 2, + /obj/item/flag/cult = 2, + /obj/item/flag/ussp = 2, + /obj/item/flag/solgov = 2, /obj/item/clothing/head/yogs/froghat = 3, /obj/item/instrument/accordion = 1, /obj/item/instrument/eguitar = 1, diff --git a/yogstation/icons/obj/janitor.dmi b/yogstation/icons/obj/janitor.dmi index 9dde83583ea10..46c2e2d07af9c 100644 Binary files a/yogstation/icons/obj/janitor.dmi and b/yogstation/icons/obj/janitor.dmi differ diff --git a/yogstation/icons/obj/stack_objects.dmi b/yogstation/icons/obj/stack_objects.dmi index 972399a583d3b..d1ea574ddcf41 100644 Binary files a/yogstation/icons/obj/stack_objects.dmi and b/yogstation/icons/obj/stack_objects.dmi differ diff --git a/yogstation/icons/obj/tank.dmi b/yogstation/icons/obj/tank.dmi index 999bdfbfb5799..25b84b4483456 100644 Binary files a/yogstation/icons/obj/tank.dmi and b/yogstation/icons/obj/tank.dmi differ