From fec150523d4068c5ba09f57680ba8fa98b023aa9 Mon Sep 17 00:00:00 2001 From: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> Date: Sun, 25 Jun 2023 20:33:36 -0400 Subject: [PATCH] Augments Tab (#387) * teshari augs * grr naming * fix legs * emp nerf * var * make it all work * fixes * I am so stupid * Organs are now stored inside their bodyparts. * This might be better * remove skrell, clean up code * amputation * need to redo some ear code but this is good * IMPLANTS * update screenshot tests * qdel replaced organs --- code/__DEFINES/DNA.dm | 22 ++- code/__DEFINES/augments.dm | 26 +++ code/__DEFINES/external_organs.dm | 4 - code/__DEFINES/is_helpers.dm | 1 - code/__DEFINES/mobs.dm | 11 +- code/__DEFINES/preferences.dm | 2 + code/__DEFINES/traits.dm | 2 + code/__HELPERS/global_lists.dm | 49 ++++-- code/__HELPERS/mobs.dm | 7 +- code/_globalvars/lists/flavor_misc.dm | 1 - code/datums/components/tackle.dm | 2 - code/datums/diseases/_MobProcs.dm | 12 +- code/datums/dna.dm | 6 - code/datums/quirks/negative.dm | 36 ---- code/game/atoms.dm | 2 +- code/game/objects/items/crayons.dm | 15 +- .../structures/crates_lockers/crates.dm | 1 - code/modules/cargo/packs.dm | 4 +- code/modules/client/client_colour.dm | 3 + .../modules/client/preferences/_preference.dm | 17 +- .../client/preferences/augments/_augment.dm | 56 ++++++ .../preferences/augments/augment_bodypart.dm | 96 +++++++++++ .../preferences/augments/augment_organ.dm | 76 +++++++++ .../client/preferences/augments/augments.dm | 160 ++++++++++++++++++ .../preferences/augments/implants/implant.dm | 34 ++++ code/modules/client/preferences/flavortext.dm | 2 +- .../html_prefs/categories/augments.dm | 71 ++++++++ .../client/preferences/loadout/loadout.dm | 2 +- .../client/preferences/loadout_override.dm | 2 +- code/modules/client/preferences/occupation.dm | 2 +- .../preferences/species_features/basic.dm | 4 +- .../preferences/species_features/skrell.dm | 9 - .../preferences/species_features/teshari.dm | 8 +- .../preferences/species_features/vox.dm | 4 +- code/modules/language/language_holder.dm | 8 - code/modules/language/language_manuals.dm | 1 - code/modules/language/skrell.dm | 10 -- .../mob/dead/new_player/preferences_setup.dm | 1 + .../sprite_accessories/_sprite_accessories.dm | 2 +- .../new_player/sprite_accessories/ears.dm | 6 +- .../new_player/sprite_accessories/frills.dm | 4 - .../new_player/sprite_accessories/hair.dm | 4 - .../sprite_accessories/headtails.dm | 15 -- .../new_player/sprite_accessories/horns.dm | 4 - .../new_player/sprite_accessories/snouts.dm | 8 +- .../new_player/sprite_accessories/spines.dm | 37 ---- code/modules/mob/living/brain/brain_item.dm | 6 +- code/modules/mob/living/carbon/human/dummy.dm | 47 ++--- code/modules/mob/living/carbon/human/emote.dm | 28 +-- code/modules/mob/living/carbon/human/human.dm | 3 - .../mob/living/carbon/human/human_defense.dm | 32 ++-- .../mob/living/carbon/human/species.dm | 79 ++++++--- .../carbon/human/species_types/skrell.dm | 144 ---------------- .../carbon/human/species_types/teshari.dm | 7 + .../living/carbon/human/species_types/vox.dm | 3 + .../reagents/reagent_containers/blood_pack.dm | 3 - .../designs/mechfabricator_designs.dm | 62 +++++++ code/modules/surgery/bodyparts/_bodyparts.dm | 65 ++++++- .../surgery/bodyparts/dismemberment.dm | 151 +++++++---------- code/modules/surgery/bodyparts/head.dm | 4 +- code/modules/surgery/bodyparts/rendering.dm | 8 +- .../surgery/bodyparts/robot_bodyparts.dm | 52 +++--- .../species_parts/skrell_bodyparts.dm | 34 ---- .../species_parts/teshari_bodyparts.dm | 38 +++++ code/modules/surgery/organs/_organ.dm | 40 ++--- code/modules/surgery/organs/ears.dm | 30 ++-- .../organs/external/_external_organs.dm | 45 ++--- .../organs/external/skrell_headtails.dm | 24 --- .../modules/surgery/organs/external/snouts.dm | 1 + code/modules/surgery/organs/external/tails.dm | 53 +----- code/modules/surgery/organs/eyes.dm | 21 ++- code/modules/surgery/organs/heart.dm | 5 - code/modules/surgery/organs/liver.dm | 7 - code/modules/surgery/organs/lungs.dm | 22 --- code/modules/surgery/organs/tongue.dm | 7 - ...anoids__datum_species_lizard_ashwalker.png | Bin 1169 -> 2996 bytes ...oids__datum_species_lizard_silverscale.png | Bin 1154 -> 3165 bytes ...creenshot_humanoids__datum_species_pod.png | Bin 1253 -> 1217 bytes ...nshot_humanoids__datum_species_teshari.png | Bin 1118 -> 1182 bytes ...creenshot_humanoids__datum_species_vox.png | Bin 1369 -> 1387 bytes daedalus.dme | 13 +- icons/misc/language.dmi | Bin 6988 -> 6226 bytes icons/mob/augmentation/surplus_augments.dmi | Bin 1162 -> 3158 bytes icons/mob/mutant_bodyparts.dmi | Bin 34588 -> 10838 bytes icons/mob/species/skrell/bodyparts.dmi | Bin 3776 -> 0 bytes icons/mob/species/skrell/eyes.dmi | Bin 683 -> 0 bytes icons/mob/species/skrell/skrell_headtails.dmi | Bin 625 -> 0 bytes icons/mob/species/teshari/augments.dmi | Bin 0 -> 3410 bytes 88 files changed, 1068 insertions(+), 815 deletions(-) create mode 100644 code/__DEFINES/augments.dm create mode 100644 code/modules/client/preferences/augments/_augment.dm create mode 100644 code/modules/client/preferences/augments/augment_bodypart.dm create mode 100644 code/modules/client/preferences/augments/augment_organ.dm create mode 100644 code/modules/client/preferences/augments/augments.dm create mode 100644 code/modules/client/preferences/augments/implants/implant.dm create mode 100644 code/modules/client/preferences/html_prefs/categories/augments.dm delete mode 100644 code/modules/client/preferences/species_features/skrell.dm delete mode 100644 code/modules/language/skrell.dm delete mode 100644 code/modules/mob/dead/new_player/sprite_accessories/headtails.dm delete mode 100644 code/modules/mob/living/carbon/human/species_types/skrell.dm delete mode 100644 code/modules/surgery/bodyparts/species_parts/skrell_bodyparts.dm delete mode 100644 code/modules/surgery/organs/external/skrell_headtails.dm delete mode 100644 icons/mob/species/skrell/bodyparts.dmi delete mode 100644 icons/mob/species/skrell/eyes.dmi delete mode 100644 icons/mob/species/skrell/skrell_headtails.dmi create mode 100644 icons/mob/species/teshari/augments.dmi diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 823662cada4f..72a6aabb710c 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -55,17 +55,16 @@ #define DNA_MUSHROOM_CAPS_BLOCK 14 #define DNA_MONKEY_TAIL_BLOCK 15 #define DNA_POD_HAIR_BLOCK 16 -#define DNA_HEADTAILS_BLOCK 17 -#define DNA_MUTANT_COLOR_BLOCK_2 18 -#define DNA_MUTANT_COLOR_BLOCK_3 19 -#define DNA_TESHARI_FEATHERS_BLOCK 20 -#define DNA_TESHARI_EARS_BLOCK 21 -#define DNA_TESHARI_BODY_FEATHERS_BLOCK 22 -#define DNA_TESHARI_TAIL_BLOCK 23 -#define DNA_VOX_HAIR_BLOCK 24 -#define DNA_VOX_FACIAL_HAIR_BLOCK 25 -#define DNA_VOX_TAIL_BLOCK 26 -#define DNA_VOX_SNOUT_BLOCK 27 +#define DNA_MUTANT_COLOR_BLOCK_2 17 +#define DNA_MUTANT_COLOR_BLOCK_3 18 +#define DNA_TESHARI_FEATHERS_BLOCK 19 +#define DNA_TESHARI_EARS_BLOCK 20 +#define DNA_TESHARI_BODY_FEATHERS_BLOCK 21 +#define DNA_TESHARI_TAIL_BLOCK 22 +#define DNA_VOX_HAIR_BLOCK 23 +#define DNA_VOX_FACIAL_HAIR_BLOCK 24 +#define DNA_VOX_TAIL_BLOCK 25 +#define DNA_VOX_SNOUT_BLOCK 26 #define DNA_SEQUENCE_LENGTH 4 #define DNA_MUTATION_BLOCKS 8 @@ -149,7 +148,6 @@ #define ORGAN_SLOT_EXTERNAL_POD_HAIR "pod_hair" #define ORGAN_SLOT_EXTERNAL_VOX_HAIR "vox_hair" #define ORGAN_SLOT_EXTERNAL_VOX_FACIAL_HAIR "vox_facial_hair" -#define ORGAN_SLOT_EXTERNAL_HEADTAILS "headtails" #define ORGAN_SLOT_EXTERNAL_TESHARI_FEATHERS "teshari_feathers" #define ORGAN_SLOT_EXTERNAL_TESHARI_EARS "teshari_ears" #define ORGAN_SLOT_EXTERNAL_TESHARI_BODY_FEATHERS "teshari_body_feathers" diff --git a/code/__DEFINES/augments.dm b/code/__DEFINES/augments.dm new file mode 100644 index 000000000000..18cccc14ab0f --- /dev/null +++ b/code/__DEFINES/augments.dm @@ -0,0 +1,26 @@ +#define AUGMENT_CATEGORY_NONE "ERROR" +#define AUGMENT_SLOT_NONE "ERROR" + +//ALL OF THOSE DEFINES NEED TO BE UNIQUE!!! +//Limbs +#define AUGMENT_CATEGORY_BODYPARTS "Limbs" +#define AUGMENT_SLOT_HEAD "Head" +#define AUGMENT_SLOT_CHEST "Chest" +#define AUGMENT_SLOT_L_ARM "Left Arm" +#define AUGMENT_SLOT_R_ARM "Right Arm" +#define AUGMENT_SLOT_L_LEG "Left Leg" +#define AUGMENT_SLOT_R_LEG "Right Leg" + +//Organs +#define AUGMENT_CATEGORY_ORGANS "Organs" +#define AUGMENT_SLOT_HEART "Heart" +#define AUGMENT_SLOT_LUNGS "Lungs" +#define AUGMENT_SLOT_LIVER "Liver" +#define AUGMENT_SLOT_STOMACH "Stomach" +#define AUGMENT_SLOT_EYES "Eyes" +#define AUGMENT_SLOT_TONGUE "Tongue" + +//Implants +#define AUGMENT_CATEGORY_IMPLANTS "Implants" +#define AUGMENT_SLOT_IMPLANTS "Code Reasons" + diff --git a/code/__DEFINES/external_organs.dm b/code/__DEFINES/external_organs.dm index 265f86d5f6f7..dbfb23478e89 100644 --- a/code/__DEFINES/external_organs.dm +++ b/code/__DEFINES/external_organs.dm @@ -8,7 +8,3 @@ #define ORGAN_COLOR_STATIC (1<<3) ///Uses the mutcolor list #define ORGAN_COLOR_INHERIT_ALL (1<<4) - -///Tail wagging -#define WAG_ABLE (1<<0) -#define WAG_WAGGING (1<<1) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 45f9a3cec1b1..b71353c789ae 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -83,7 +83,6 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isdullahan(A) (is_species(A, /datum/species/dullahan)) #define ismonkey(A) (is_species(A, /datum/species/monkey)) #define isandroid(A) (is_species(A, /datum/species/android)) -#define isskrell(A) (is_species(A, /datum/species/skrell)) #define isteshari(A) (is_species(A, /datum/species/teshari)) //More carbon mobs diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 12821980432e..a5a7883a6bc9 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -80,16 +80,14 @@ #define BODYTYPE_MONKEY (1<<4) ///The limb is snouted. #define BODYTYPE_SNOUTED (1<<5) -///The limb has skrelly bits -#define BODYTYPE_SKRELL (1<<6) ///The limb is voxed -#define BODYTYPE_VOX_BEAK (1<<7) +#define BODYTYPE_VOX_BEAK (1<<6) ///The limb is in the shape of a vox leg. -#define BODYTYPE_VOX_LEGS (1<<8) +#define BODYTYPE_VOX_LEGS (1<<7) ///Vox limb that isnt a head or legs. -#define BODYTYPE_VOX_OTHER (1<<9) +#define BODYTYPE_VOX_OTHER (1<<8) ///The limb is small and feathery -#define BODYTYPE_TESHARI (1<<10) +#define BODYTYPE_TESHARI (1<<9) //Defines for Species IDs ///A placeholder bodytype for xeno larva, so their limbs cannot be attached to anything. @@ -120,7 +118,6 @@ #define SPECIES_PODPERSON "pod" #define SPECIES_SHADOW "shadow" #define SPECIES_SKELETON "skeleton" -#define SPECIES_SKRELL "skrell" #define SPECIES_SNAIL "snail" #define SPECIES_TESHARI "teshari" #define SPECIES_VAMPIRE "vampire" diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 60afc17d0494..051bd733ea58 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -120,3 +120,5 @@ #define PLAYTIME_HARDCORE_RANDOM 120 // 2 hours /// The time needed to unlock the gamer cloak in preferences #define PLAYTIME_VETERAN 300000 // 5,000 hours + +#define SPRITE_ACCESSORY_NONE "None" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index d1027c8f80f5..d19899ed82ef 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -842,6 +842,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define ORBITING_TRAIT "orbiting" /// From the item_scaling element #define ITEM_SCALING_TRAIT "item_scaling" +/// From EMPs +#define EMP_TRAIT "emp" /** * Trait granted by [/mob/living/carbon/Initialize] and diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index a4389e2261a0..ce083f05a76e 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -14,35 +14,40 @@ //socks init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list) //bodypart accessories (blizzard intensifies) + + //Snowflakes init_sprite_accessory_subtypes(/datum/sprite_accessory/tails, GLOB.tails_list, add_blank = TRUE) + init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human, add_blank = TRUE) - init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard, add_blank = TRUE) - init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open, GLOB.wings_open_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/spines_animated, GLOB.animated_spines_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/caps, GLOB.caps_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list) + + // Lizadhs + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard) + init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list, add_blank = TRUE) + init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list, add_blank = TRUE) + init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list, add_blank = TRUE) + init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list) + // Moths init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae, GLOB.moth_antennae_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, GLOB.moth_markings_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/headtails, GLOB.headtails_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_hair, GLOB.moth_hairstyles_list) + + // Teshari init_sprite_accessory_subtypes(/datum/sprite_accessory/teshari_feathers, GLOB.teshari_feathers_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/teshari_ears, GLOB.teshari_ears_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/teshari_body_feathers, GLOB.teshari_body_feathers_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/teshari, GLOB.teshari_tails_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_hair, GLOB.vox_hair_list) + //Vox + init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_hair, GLOB.vox_hair_list, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_vox_hair, GLOB.vox_facial_hair_list, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/vox, GLOB.tails_list_vox) init_sprite_accessory_subtypes(/datum/sprite_accessory/vox_snouts, GLOB.vox_snouts_list) - //Moths have a whitelist - init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_hair, GLOB.moth_hairstyles_list) //Species for(var/spath in subtypesof(/datum/species)) @@ -70,6 +75,7 @@ init_crafting_recipes(GLOB.crafting_recipes) init_loadout_references() + init_augment_references() /// Inits the crafting recipe list, sorting crafting recipe requirements in the process. /proc/init_crafting_recipes(list/crafting_recipes) @@ -169,3 +175,20 @@ GLOBAL_LIST_INIT(WALLITEMS_EXTERIOR, typecacheof(list( for(var/category as anything in GLOB.loadout_category_to_subcategory_to_items) for(var/subcategory as anything in GLOB.loadout_category_to_subcategory_to_items[category]) GLOB.loadout_category_to_subcategory_to_items[category][subcategory] = sortTim(GLOB.loadout_category_to_subcategory_to_items[category][subcategory], GLOBAL_PROC_REF(cmp_loadout_name)) + +/proc/init_augment_references() + // Here we build the global loadout lists + for(var/path in subtypesof(/datum/augment_item)) + var/datum/augment_item/L = path + if(!initial(L.path)) + continue + + L = new path() + GLOB.augment_items[L.type] = L + + if(!GLOB.augment_slot_to_items[L.slot]) + GLOB.augment_slot_to_items[L.slot] = list() + if(!GLOB.augment_categories_to_slots[L.category]) + GLOB.augment_categories_to_slots[L.category] = list() + GLOB.augment_categories_to_slots[L.category] += L.slot + GLOB.augment_slot_to_items[L.slot] += L.type diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index f520efa84219..96a64aaee618 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -70,7 +70,7 @@ if(!GLOB.horns_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/horns, GLOB.horns_list) if(!GLOB.ears_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.horns_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list) if(!GLOB.frills_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list) if(!GLOB.spines_list.len) @@ -87,8 +87,6 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, GLOB.moth_markings_list) if(!GLOB.pod_hair_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list) - if(!GLOB.headtails_list.len) - init_sprite_accessory_subtypes(/datum/sprite_accessory/headtails, GLOB.headtails_list) if(!GLOB.teshari_feathers_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/teshari_feathers, GLOB.teshari_feathers_list) if(!GLOB.teshari_ears_list.len) @@ -125,7 +123,6 @@ "moth_markings" = pick(GLOB.moth_markings_list), "tail_monkey" = "None", "pod_hair" = pick(GLOB.pod_hair_list), - "headtails" = (pick(GLOB.headtails_list)), "vox_snout" = pick(GLOB.vox_snouts_list), "tail_vox" = pick(GLOB.tails_list_vox), "vox_hair" = pick(GLOB.vox_hair_list), @@ -790,6 +787,8 @@ GLOBAL_LIST_EMPTY(species_list) return BODY_ZONE_CHEST if(BODY_ZONE_PRECISE_EYES) return BODY_ZONE_HEAD + if(BODY_ZONE_PRECISE_MOUTH) + return BODY_ZONE_HEAD if(BODY_ZONE_PRECISE_R_HAND) return BODY_ZONE_R_ARM if(BODY_ZONE_PRECISE_L_HAND) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index a06196eb4236..2b406b22e4b1 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -46,7 +46,6 @@ GLOBAL_LIST_EMPTY(moth_antennae_list) GLOBAL_LIST_EMPTY(moth_markings_list) GLOBAL_LIST_EMPTY(caps_list) GLOBAL_LIST_EMPTY(pod_hair_list) -GLOBAL_LIST_EMPTY(headtails_list) GLOBAL_LIST_EMPTY(teshari_feathers_list) GLOBAL_LIST_EMPTY(teshari_ears_list) GLOBAL_LIST_EMPTY(teshari_body_feathers_list) diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index dad09d592e89..d21460e24b80 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -291,8 +291,6 @@ var/obj/item/organ/tail/el_tail = T.getorganslot(ORGAN_SLOT_EXTERNAL_TAIL) if(!el_tail) // lizards without tails are off-balance defense_mod -= 1 - else if(el_tail.wag_flags & WAG_WAGGING) // lizard tail wagging is robust and can swat away assailants! - defense_mod += 1 // OF-FENSE var/mob/living/carbon/sacker = parent diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index aa81d7433e37..08678f50d263 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -146,4 +146,14 @@ return !is_mouth_covered() /mob/living/carbon/CanSpreadAirborneDisease() - return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.returnArmor().getRating(BIO) >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.returnArmor().getRating(BIO) >= 25))) + if(head && (head.flags_cover & HEADCOVERSMOUTH) && head.returnArmor().getRating(BIO) >= 25) + return FALSE + + if(wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && wear_mask.returnArmor().getRating(BIO) >= 25) + return FALSE + + var/obj/item/bodypart/head/realhead = get_bodypart(BODY_ZONE_HEAD) + if(realhead && realhead.returnArmor().getRating(BIO) >= 100) + return FALSE + + return TRUE diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 42294b7acb76..f3e3f73b7723 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -227,8 +227,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len) if(features["pod_hair"]) L[DNA_POD_HAIR_BLOCK] = construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len) - if(features["headtails"]) - L[DNA_HEADTAILS_BLOCK] = construct_block(GLOB.headtails_list.Find(features["headtails"]), GLOB.headtails_list.len) if(features["teshari_feathers"]) L[DNA_TESHARI_FEATHERS_BLOCK] = construct_block(GLOB.teshari_feathers_list.Find(features["teshari_feathers"]), GLOB.teshari_feathers_list.len) if(features["teshari_ears"]) @@ -380,8 +378,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) set_uni_feature_block(blocknumber, construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len)) if(DNA_POD_HAIR_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len)) - if(DNA_HEADTAILS_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.headtails_list.Find(features["headtails"]), GLOB.headtails_list.len)) if(DNA_TESHARI_FEATHERS_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.teshari_feathers_list.Find(features["teshari_feathers"]), GLOB.teshari_feathers_list.len)) if(DNA_TESHARI_EARS_BLOCK) @@ -680,8 +676,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.features["caps"] = GLOB.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), GLOB.caps_list.len)] if(dna.features["pod_hair"]) 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["headtails"]) - dna.features["headtails"] = GLOB.headtails_list[deconstruct_block(get_uni_feature_block(features, DNA_HEADTAILS_BLOCK), GLOB.headtails_list.len)] if(dna.features["teshari_feathers"]) dna.features["teshari_feathers"] = GLOB.teshari_feathers_list[deconstruct_block(get_uni_feature_block(features, DNA_TESHARI_FEATHERS_BLOCK), GLOB.teshari_feathers_list.len)] if(dna.features["teshari_ears"]) diff --git a/code/datums/quirks/negative.dm b/code/datums/quirks/negative.dm index 06ab16b12e08..f9f5582487ab 100644 --- a/code/datums/quirks/negative.dm +++ b/code/datums/quirks/negative.dm @@ -424,42 +424,6 @@ medical_record_text = "Patient suffers from prosopagnosia and cannot recognize faces." hardcore_value = 5 -/datum/quirk/prosthetic_limb - name = "Prosthetic Limb" - desc = "An accident caused you to lose one of your limbs. Because of this, you now have a random prosthetic!" - icon = "tg-prosthetic-leg" - value = -4 - var/slot_string = "limb" - medical_record_text = "During physical examination, patient was found to have a prosthetic limb." - hardcore_value = 3 - quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE - -/datum/quirk/prosthetic_limb/add_unique(client/client_source) - var/limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - var/mob/living/carbon/human/human_holder = quirk_holder - var/obj/item/bodypart/old_part = human_holder.get_bodypart(limb_slot) - var/obj/item/bodypart/prosthetic - switch(limb_slot) - if(BODY_ZONE_L_ARM) - prosthetic = new/obj/item/bodypart/arm/left/robot/surplus(quirk_holder) - slot_string = "left arm" - if(BODY_ZONE_R_ARM) - prosthetic = new/obj/item/bodypart/arm/right/robot/surplus(quirk_holder) - slot_string = "right arm" - if(BODY_ZONE_L_LEG) - prosthetic = new/obj/item/bodypart/leg/left/robot/surplus(quirk_holder) - slot_string = "left leg" - if(BODY_ZONE_R_LEG) - prosthetic = new/obj/item/bodypart/leg/right/robot/surplus(quirk_holder) - slot_string = "right leg" - prosthetic.replace_limb(human_holder) - qdel(old_part) - human_holder.regenerate_icons() - -/datum/quirk/prosthetic_limb/post_add() - to_chat(quirk_holder, "Your [slot_string] has been replaced with a surplus prosthetic. It is fragile and will easily come apart under duress. Additionally, \ - you need to use a welding tool and cables to repair it, instead of bruise packs and ointment.") - /datum/quirk/pushover name = "Pushover" desc = "Your first instinct is always to let people push you around. Resisting out of grabs will take conscious effort." diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 47c00d490fd3..a05a91cf0968 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -684,7 +684,7 @@ if(desc) . += desc - if(z && user.z != z) + if(z && user.z && user.z != z) var/diff = abs(user.z - z) . += span_notice("[p_theyre(TRUE)] [diff] level\s below you.") diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index b3b37632780d..9e93cbfb8127 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -797,16 +797,29 @@ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN if(istype(target, /obj/item/bodypart) && actually_paints) + var/obj/item/bodypart/limb = target + if(!(limb.bodytype & BODYTYPE_HUMANOID)) + to_chat(user, span_notice("You can't think of anything to change about [src].")) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + if(!IS_ORGANIC_LIMB(limb)) var/list/skins = list() - var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi') + var/static/list/style_list_icons = list( + "standard" = 'icons/mob/augmentation/augments.dmi', + "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', + "security" = 'icons/mob/augmentation/augments_security.dmi', + "mining" = 'icons/mob/augmentation/augments_mining.dmi' + ) + for(var/skin_option in style_list_icons) var/image/part_image = image(icon = style_list_icons[skin_option], icon_state = "[limb.limb_id]_[limb.body_zone]") if(limb.aux_zone) //Hands part_image.overlays += image(icon = style_list_icons[skin_option], icon_state = "[limb.limb_id]_[limb.aux_zone]") skins += list("[skin_option]" = part_image) + var/choice = show_radial_menu(user, src, skins, require_near = TRUE) + if(choice && (use_charges(user, 5, requires_full = FALSE) == 5)) playsound(user.loc, 'sound/effects/spray.ogg', 5, TRUE, 5) limb.change_appearance(style_list_icons[choice], greyscale = FALSE) diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 6791fb2caec3..3f89f592ff1a 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -202,7 +202,6 @@ new /obj/item/reagent_containers/blood/o_plus(src) new /obj/item/reagent_containers/blood/lizard(src) new /obj/item/reagent_containers/blood/ethereal(src) - new /obj/item/reagent_containers/blood/skrell(src) for(var/i in 1 to 3) new /obj/item/reagent_containers/blood/random(src) diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 4b227b1d1ae5..f95891d89fc9 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -1179,8 +1179,8 @@ /obj/item/reagent_containers/blood/o_plus, /obj/item/reagent_containers/blood/o_minus, /obj/item/reagent_containers/blood/lizard, - /obj/item/reagent_containers/blood/ethereal, - /obj/item/reagent_containers/blood/skrell) + /obj/item/reagent_containers/blood/ethereal + ) crate_name = "blood freezer" crate_type = /obj/structure/closet/crate/freezer diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm index 1e4792317ff1..5a5b86674dd7 100644 --- a/code/modules/client/client_colour.dm +++ b/code/modules/client/client_colour.dm @@ -188,6 +188,9 @@ /datum/client_colour/glass_colour/nightmare colour = list(255,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, -130,0,0,0) //every color is either red or black +/datum/client_colour/malfunction + colour = list(/*R*/ 0,0,0,0, /*G*/ 0,175,0,0, /*B*/ 0,0,0,0, /*A*/ 0,0,0,1, /*C*/0,-130,0,0) // Matrix colors + /datum/client_colour/monochrome colour = list(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0)) priority = PRIORITY_HIGH //we can't see colors anyway! diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index e0f49a8d0302..b553dd1dceb7 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -10,15 +10,17 @@ /// The priority at which body type is decided, applied after gender so we can /// support the "use gender" option. #define PREFERENCE_PRIORITY_BODY_TYPE 5 +/// Augments come after species and bodytype. +#define PREFERENCE_PRIORITY_AUGMENTS 6 /// The priority hair is applied. We apply human hair first, and moth hair after, only if they are a moth. Sorry. -#define PREFERENCE_PRIORITY_HUMAN_HAIR 6 +#define PREFERENCE_PRIORITY_HUMAN_HAIR 7 /// The priority non-human hair is applied (used to apply moth hair after normal hair) -#define PREFERENCE_PRIORITY_NONHUMAN_HAIR 7 +#define PREFERENCE_PRIORITY_NONHUMAN_HAIR 8 /// The priority at which names are decided, needed for proper randomization. -#define PREFERENCE_PRIORITY_NAMES 8 +#define PREFERENCE_PRIORITY_NAMES 9 /// Preferences that aren't names, but change the name changes set by PREFERENCE_PRIORITY_NAMES. -#define PREFERENCE_PRIORITY_NAME_MODIFICATIONS 9 -#define PREFERENCE_PRIORITY_APPEARANCE_MODS 10 +#define PREFERENCE_PRIORITY_NAME_MODIFICATIONS 10 +#define PREFERENCE_PRIORITY_APPEARANCE_MODS 11 /// The maximum preference priority, keep this updated, but don't use it for `priority`. #define MAX_PREFERENCE_PRIORITY PREFERENCE_PRIORITY_APPEARANCE_MODS @@ -227,7 +229,7 @@ GLOBAL_LIST_INIT(all_pref_groups, init_all_pref_groups()) /// Apply this preference onto the given human. /// Must be overriden by subtypes. /// Called when the savefile_identifier == PREFERENCE_CHARACTER. -/datum/preference/proc/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) //PARIAH EDIT +/datum/preference/proc/apply_to_human(mob/living/carbon/human/target, value) SHOULD_NOT_SLEEP(TRUE) SHOULD_CALL_PARENT(FALSE) CRASH("`apply_to_human()` was not implemented for [type]!") @@ -603,6 +605,7 @@ GLOBAL_LIST_INIT(all_pref_groups, init_all_pref_groups()) ///Holds any kind of abstract list data you'd like it to. MUST impliment `is_valid`! /datum/preference/blob abstract_type = /datum/preference/blob + can_randomize = FALSE /datum/preference/blob/create_default_value() return list() @@ -615,5 +618,5 @@ GLOBAL_LIST_INIT(all_pref_groups, init_all_pref_groups()) /datum/preference/blob/is_valid(value) return islist(value) -/datum/preference/blob/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/blob/apply_to_human(mob/living/carbon/human/target, value) return diff --git a/code/modules/client/preferences/augments/_augment.dm b/code/modules/client/preferences/augments/_augment.dm new file mode 100644 index 000000000000..c7b767efa7cd --- /dev/null +++ b/code/modules/client/preferences/augments/_augment.dm @@ -0,0 +1,56 @@ +GLOBAL_LIST_EMPTY(augment_items) +GLOBAL_LIST_EMPTY(augment_categories_to_slots) +GLOBAL_LIST_EMPTY(augment_slot_to_items) +/// Map of species > category > slot > item +GLOBAL_LIST_EMPTY(species_augment_tree) + +/datum/augment_item + var/name + ///Description of the loadout augment, automatically set by New() if null + var/description + ///Category in which the augment belongs to. check "_DEFINES/augment.dm" + var/category = AUGMENT_CATEGORY_NONE + ///Slot in which the augment belongs to, MAKE SURE THE SAME SLOT IS ONLY IN ONE CATEGORY + var/slot = AUGMENT_SLOT_NONE + ///Can multiple of this type be taken? + var/exclusive = TRUE + ///Typepath to the augment being used + var/path + +/datum/augment_item/New() + if(!description && path) + var/obj/O = path + description = initial(O.desc) + +/datum/augment_item/proc/apply_to_human(mob/living/carbon/human/H, datum/species/S) + return + +/datum/augment_item/proc/can_apply_to_species(datum/species/S) + return TRUE + +/// Returns a tree of species > category > slot > item path +/proc/get_species_augments(datum/species/S) + RETURN_TYPE(/list) + + var/static/list/augment_tree = list() + if(istype(S)) + S = S.type + + if(augment_tree[S]) + return augment_tree[S] + + S = new S() + + if(!augment_tree[S.type]) + augment_tree[S.type] = list() + + for(var/datum/augment_item/A as anything in GLOB.augment_items) + A = GLOB.augment_items[A] + + if(!A.can_apply_to_species(S)) + continue + if(!augment_tree[S.type][A.category]) + augment_tree[S.type][A.category] = list() + if(!augment_tree[S.type][A.category][A.slot]) + augment_tree[S.type][A.category][A.slot] = list() + augment_tree[S.type][A.category][A.slot] += A.type diff --git a/code/modules/client/preferences/augments/augment_bodypart.dm b/code/modules/client/preferences/augments/augment_bodypart.dm new file mode 100644 index 000000000000..c949b88354c6 --- /dev/null +++ b/code/modules/client/preferences/augments/augment_bodypart.dm @@ -0,0 +1,96 @@ +/datum/augment_item/bodypart + category = AUGMENT_CATEGORY_BODYPARTS + + +/datum/augment_item/bodypart/apply_to_human(mob/living/carbon/human/H, datum/species/S) + var/newpath = S.robotic_bodyparts[initial(path:body_zone)] + + var/obj/item/bodypart/BP = new newpath() + var/obj/item/bodypart/old = H.get_bodypart(BP.body_zone) + BP.replace_limb(H, TRUE) + qdel(old) + +/datum/augment_item/bodypart/can_apply_to_species(datum/species/S) + var/obj/item/bodypart/BP = path + if(S.robotic_bodyparts?[initial(BP.body_zone)]) + return TRUE + return FALSE + +/datum/augment_item/bodypart/head + slot = AUGMENT_SLOT_HEAD + +/datum/augment_item/bodypart/chest + slot = AUGMENT_SLOT_CHEST + +/datum/augment_item/bodypart/l_arm + slot = AUGMENT_SLOT_L_ARM + +/datum/augment_item/bodypart/r_arm + slot = AUGMENT_SLOT_R_ARM + +/datum/augment_item/bodypart/l_leg + slot = AUGMENT_SLOT_L_LEG + +/datum/augment_item/bodypart/r_leg + slot = AUGMENT_SLOT_R_LEG + + +// ROBOTIC LIMBS +/datum/augment_item/bodypart/head/robotic + name = "Prosthetic" + slot = AUGMENT_SLOT_HEAD + path = /obj/item/bodypart/head/robot/surplus + +/datum/augment_item/bodypart/chest/robotic + name = "Prosthetic" + slot = AUGMENT_SLOT_CHEST + path = /obj/item/bodypart/chest/robot/surplus + +/datum/augment_item/bodypart/l_arm/robotic + name = "Prosthetic" + slot = AUGMENT_SLOT_L_ARM + path = /obj/item/bodypart/arm/left/robot/surplus + +/datum/augment_item/bodypart/r_arm/robotic + name = "Prosthetic" + slot = AUGMENT_SLOT_R_ARM + path = /obj/item/bodypart/arm/right/robot/surplus + +/datum/augment_item/bodypart/l_leg/robotic + name = "Prosthetic" + slot = AUGMENT_SLOT_L_LEG + path = /obj/item/bodypart/leg/left/robot/surplus + +/datum/augment_item/bodypart/r_leg/robotic + name = "Prosthetic" + slot = AUGMENT_SLOT_R_LEG + path = /obj/item/bodypart/leg/right/robot/surplus + +/// AMPUTATION +/datum/augment_item/bodypart/amputated/l_arm + name = "Amputated" + path = /obj/item/bodypart/arm/left + slot = AUGMENT_SLOT_L_ARM + +/datum/augment_item/bodypart/amputated/r_arm + name = "Amputated" + path = /obj/item/bodypart/arm/right + slot = AUGMENT_SLOT_R_ARM + +/datum/augment_item/bodypart/amputated/l_leg + name = "Amputated" + path = /obj/item/bodypart/leg/left + slot = AUGMENT_SLOT_L_LEG + +/datum/augment_item/bodypart/amputated/r_leg + name = "Amputated" + path = /obj/item/bodypart/leg/right + slot = AUGMENT_SLOT_R_LEG + +/datum/augment_item/bodypart/amputated/apply_to_human(mob/living/carbon/human/H, datum/species/S) + var/obj/item/bodypart/path = src.path + var/obj/item/bodypart/BP = H.get_bodypart(initial(path.body_zone)) + qdel(BP) + +/datum/augment_item/bodypart/amputated/can_apply_to_species(datum/species/S) + return TRUE diff --git a/code/modules/client/preferences/augments/augment_organ.dm b/code/modules/client/preferences/augments/augment_organ.dm new file mode 100644 index 000000000000..454cac2f81fc --- /dev/null +++ b/code/modules/client/preferences/augments/augment_organ.dm @@ -0,0 +1,76 @@ +/datum/augment_item/organ + category = AUGMENT_CATEGORY_ORGANS + +/datum/augment_item/organ/apply_to_human(mob/living/carbon/human/H) + if(istype(H, /mob/living/carbon/human/dummy)) + return + var/obj/item/organ/new_organ = new path() + new_organ.Insert(H,TRUE,FALSE) + +//HEARTS +/datum/augment_item/organ/heart + slot = AUGMENT_SLOT_HEART + +/datum/augment_item/organ/heart/cybernetic + name = "Cybernetic" + path = /obj/item/organ/heart/cybernetic + +/datum/augment_item/organ/heart/can_apply_to_species(datum/species/S) + return !(NOBLOOD in S.species_traits) + +//LUNGS +/datum/augment_item/organ/lungs + slot = AUGMENT_SLOT_LUNGS + +/datum/augment_item/organ/lungs/cybernetic + name = "Cybernetic" + path = /obj/item/organ/lungs/cybernetic + +/datum/augment_item/organ/lungs/can_apply_to_species(datum/species/S) + return !(TRAIT_NOBREATH in S.inherent_traits) + +//LIVERS +/datum/augment_item/organ/liver + slot = AUGMENT_SLOT_LIVER + +/datum/augment_item/organ/liver/cybernetic + name = "Cybernetic" + path = /obj/item/organ/liver/cybernetic + +/datum/augment_item/organ/liver/can_apply_to_species(datum/species/S) + return !(TRAIT_NOMETABOLISM in S.inherent_traits) + +//STOMACHES +/datum/augment_item/organ/stomach + slot = AUGMENT_SLOT_STOMACH + +/datum/augment_item/organ/stomach/cybernetic + name = "Cybernetic" + path = /obj/item/organ/stomach/cybernetic + +/datum/augment_item/organ/stomach/can_apply_to_species(datum/species/S) + return !(TRAIT_NOHUNGER in S.inherent_traits) + +//EYES +/datum/augment_item/organ/eyes + slot = AUGMENT_SLOT_EYES + +/datum/augment_item/organ/eyes/cybernetic + name = "Cybernetic" + path = /obj/item/organ/eyes/robotic + +//TONGUES +/datum/augment_item/organ/tongue + slot = AUGMENT_SLOT_TONGUE + +/datum/augment_item/organ/tongue/normal + name = "Organic" + path = /obj/item/organ/tongue + +/datum/augment_item/organ/tongue/robo + name = "Robotic" + path = /obj/item/organ/tongue/robot + +/datum/augment_item/organ/tongue/forked + name = "Forked" + path = /obj/item/organ/tongue/lizard diff --git a/code/modules/client/preferences/augments/augments.dm b/code/modules/client/preferences/augments/augments.dm new file mode 100644 index 000000000000..a277c4d2a2ba --- /dev/null +++ b/code/modules/client/preferences/augments/augments.dm @@ -0,0 +1,160 @@ +/// Augments! +/* + expected format: + list( + AUGMENT_SLOT_R_ARM = /datum/augment_item/bodypart/r_arm/amputated + ) + + The AUGMENT_SLOT_IMPLANTS slot expects a list in the format of: + list( + /datum/augment_item/implant/cat_ears = "Cat" + ) +*/ + +/datum/preference/blob/augments + savefile_identifier = PREFERENCE_CHARACTER + savefile_key = "augments" + priority = PREFERENCE_PRIORITY_AUGMENTS + +/datum/preference/blob/augments/apply_to_human(mob/living/carbon/human/target, value) + var/datum/species/S = target.dna.species + + for(var/slot in value - AUGMENT_SLOT_IMPLANTS) + var/path = value[slot] + var/datum/augment_item/A = GLOB.augment_items[path] + A.apply_to_human(target, S) + + for(var/datum/augment_item/A as anything in value[AUGMENT_SLOT_IMPLANTS]) + A = GLOB.augment_items[A] + A.apply_to_human(target, S, value[AUGMENT_SLOT_IMPLANTS][A.type]) + +/datum/preference/blob/augments/create_default_value() + return list() + +/datum/preference/blob/augments/deserialize(input, datum/preferences/preferences) + var/datum/species/S = preferences.read_preference(/datum/preference/choiced/species) + S = new S() + var/list/species_tree = get_species_augments(S) + + for(var/slot in input) + if(slot == AUGMENT_SLOT_IMPLANTS) + continue // handled later + if(!GLOB.augment_slot_to_items[slot]) + input -= slot + continue + + var/datum/augment_item/A = GLOB.augment_items[input[slot]] + if(!A) + input -= slot + continue + if(!A.can_apply_to_species(S)) + input -= slot + continue + + var/list/implants = input[AUGMENT_SLOT_IMPLANTS] + if(implants) + if(!islist(implants)) + input -= AUGMENT_SLOT_IMPLANTS + else + for(var/path as anything in implants) + var/datum/augment_item/implant/A = GLOB.augment_items[path] + if(!A) + implants -= path + continue + if(!A.can_apply_to_species(S)) + implants -= path + continue + if(!(A.type in species_tree?[AUGMENT_CATEGORY_IMPLANTS][AUGMENT_SLOT_IMPLANTS])) + implants -= path + continue + if(!(implants[path] in A.get_choices())) + implants -= path + continue + + + return input + +/datum/preference/blob/augments/user_edit(mob/user, datum/preferences/prefs, list/params) + var/list/user_augs = prefs.read_preference(type) + var/datum/species/S = prefs.read_preference(/datum/preference/choiced/species) + var/list/species_augment_tree = get_species_augments(S) + + if(params["switch_augment"]) + var/datum/augment_item/old = GLOB.augment_items[user_augs[params["switch_augment"]]] + if(!old) + return + + var/list/datum/options = list() + for(var/datum/augment_item/A as anything in GLOB.augment_slot_to_items[old.slot]) + A = GLOB.augment_items[A] + options[A.name] = A.type + + var/input = tgui_input_list(user, "Switch Augment", "Augments", options) + if(!input) + return + + user_augs[old.slot] = options[input] + return prefs.update_preference(src, user_augs) + + if(params["remove_augment"]) + var/datum/augment_item/removing = GLOB.augment_items[user_augs[params["remove_augment"]]] + user_augs -= removing.slot + return prefs.update_preference(src, user_augs) + + if(params["add_augment"]) + var/category = params["add_augment"] + var/slot = tgui_input_list(user, "Add Augment", "Augments", species_augment_tree?[category]) + if(!slot) + return + + var/list/choices = list() + + for(var/datum/augment_item/path as anything in species_augment_tree?[category][slot]) + choices[initial(path.name)] = path + + var/augment = tgui_input_list(user, "Add [slot] Augment", "Augments", choices) + if(!augment) + return + + user_augs[slot] = choices[augment] + return prefs.update_preference(src, user_augs) + + + if(params["add_implant"]) + var/list/choices = list() + for(var/datum/augment_item/implant/path as anything in species_augment_tree?[AUGMENT_CATEGORY_IMPLANTS][AUGMENT_SLOT_IMPLANTS]) + choices[initial(path.name)] = path + + var/datum/augment_item/implant/implant = tgui_input_list(user, "Add Implant", "Implants", choices) + if(!implant) + return + + implant = GLOB.augment_items[choices[implant]] + LAZYADDASSOC(user_augs[AUGMENT_SLOT_IMPLANTS], implant.type, implant.get_choices()[1]) + return prefs.update_preference(src, user_augs) + + if(params["modify_implant"]) + var/datum/augment_item/implant/I = text2path(params["modify_implant"]) + if(!ispath(I)) + return + if(!(I in user_augs[AUGMENT_SLOT_IMPLANTS])) + return + + I = GLOB.augment_items[I] + var/new_look = tgui_input_list(user, "Modify Implant", "Implants", I.get_choices() - SPRITE_ACCESSORY_NONE, user_augs[AUGMENT_SLOT_IMPLANTS][I.type]) + if(!new_look) + return + + user_augs[AUGMENT_SLOT_IMPLANTS][I.type] = new_look + + return prefs.update_preference(src, user_augs) + + if(params["remove_implant"]) + var/path = params["remove_implant"] + path = text2path(path) + if(!ispath(path)) + return + + var/datum/augment_item/removing = GLOB.augment_items[path] + user_augs -= removing.slot + return prefs.update_preference(src, user_augs) diff --git a/code/modules/client/preferences/augments/implants/implant.dm b/code/modules/client/preferences/augments/implants/implant.dm new file mode 100644 index 000000000000..5d166d4ce02c --- /dev/null +++ b/code/modules/client/preferences/augments/implants/implant.dm @@ -0,0 +1,34 @@ +/datum/augment_item/implant + category = AUGMENT_CATEGORY_IMPLANTS + slot = AUGMENT_SLOT_IMPLANTS + /// What species can use this implant? + var/list/allowed_species = list() + +/datum/augment_item/implant/apply_to_human(mob/living/carbon/human/H, datum/species/S, feature_value) + if(!feature_value) // wtf did you do + CRASH("Tried to assign an implant without a feature value") + + var/obj/item/organ/O = new path + + H.dna.features[O.feature_key] = feature_value + O.Insert(H, TRUE, FALSE) + +/datum/augment_item/implant/can_apply_to_species(datum/species/S) + if(S.id in allowed_species) + return TRUE + return FALSE + +/// Return a list of sprite accessories to choose from +/datum/augment_item/implant/proc/get_choices() + CRASH("get_choices() unimplimented on [type]") + +/datum/augment_item/implant/cat_ears + name = "Feline Ears" + path = /obj/item/organ/ears/cat + allowed_species = list( + SPECIES_HUMAN + ) + +/datum/augment_item/implant/cat_ears/get_choices() + return GLOB.ears_list + diff --git a/code/modules/client/preferences/flavortext.dm b/code/modules/client/preferences/flavortext.dm index aa452705a9f7..68745f79af3b 100644 --- a/code/modules/client/preferences/flavortext.dm +++ b/code/modules/client/preferences/flavortext.dm @@ -2,5 +2,5 @@ savefile_identifier = PREFERENCE_CHARACTER savefile_key = "flavor_text" -/datum/preference/text/flavor_text/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/text/flavor_text/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["flavor_text"] = value diff --git a/code/modules/client/preferences/html_prefs/categories/augments.dm b/code/modules/client/preferences/html_prefs/categories/augments.dm new file mode 100644 index 000000000000..64c30be394f1 --- /dev/null +++ b/code/modules/client/preferences/html_prefs/categories/augments.dm @@ -0,0 +1,71 @@ +/datum/preference_group/category/augments + name = "Augments" + +/datum/preference_group/category/augments/get_content(datum/preferences/prefs) + . = ..() + var/list/user_augs = prefs.read_preference(/datum/preference/blob/augments) + + for(var/category in GLOB.augment_categories_to_slots - AUGMENT_CATEGORY_IMPLANTS) + . += {" +
+ + [category] + + + + + "} + + for(var/slot in GLOB.augment_categories_to_slots[category]) + if(isnull(user_augs[slot])) + continue + + var/datum/augment_item/augment = GLOB.augment_items[user_augs[slot]] + if(!augment) + continue + + . += {" + + + + + "} + + . += "
[button_element(prefs, "Add Augment", "pref_act=/datum/preference/blob/augments;add_augment=[category]")]
+ [augment.name] [augment.slot] + + [button_element(prefs, "Switch Augment", "pref_act=/datum/preference/blob/augments;switch_augment=[slot]")] + [button_element(prefs, "Remove Augment", "pref_act=/datum/preference/blob/augments;remove_augment=[slot]")] +
" + + // Special handling for implants :) + if(!length(get_species_augments(prefs.read_preference(/datum/preference/choiced/species))?[AUGMENT_CATEGORY_IMPLANTS]?[AUGMENT_SLOT_IMPLANTS])) + return + + . += {" +
+ + Implants + + + + + "} + + for(var/path in user_augs[AUGMENT_SLOT_IMPLANTS]) + var/datum/augment_item/implant = GLOB.augment_items[path] + if(!implant) + continue + . += {" + + + + + "} + + . += "
[button_element(prefs, "Add Implant", "pref_act=/datum/preference/blob/augments;add_implant=1")]
+ [implant.name] + + [button_element(prefs, "Modify Implant", "pref_act=/datum/preference/blob/augments;modify_implant=[implant.type]")] + [button_element(prefs, "Remove Implant", "pref_act=/datum/preference/blob/augments;remove_implant=[implant.type]")] +
" diff --git a/code/modules/client/preferences/loadout/loadout.dm b/code/modules/client/preferences/loadout/loadout.dm index a27b97171897..babaac3c9394 100644 --- a/code/modules/client/preferences/loadout/loadout.dm +++ b/code/modules/client/preferences/loadout/loadout.dm @@ -2,7 +2,7 @@ savefile_identifier = PREFERENCE_CHARACTER savefile_key = "nu_loadout" -/datum/preference/blob/loadout/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/blob/loadout/apply_to_human(mob/living/carbon/human/target, value) return //We handle this in job code. /datum/preference/blob/loadout/create_default_value() diff --git a/code/modules/client/preferences/loadout_override.dm b/code/modules/client/preferences/loadout_override.dm index 559230f01810..d77bfae767a1 100644 --- a/code/modules/client/preferences/loadout_override.dm +++ b/code/modules/client/preferences/loadout_override.dm @@ -10,5 +10,5 @@ /datum/preference/choiced/loadout_override_preference/create_default_value() return LOADOUT_OVERRIDE_BACKPACK -/datum/preference/choiced/loadout_override_preference/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/choiced/loadout_override_preference/apply_to_human(mob/living/carbon/human/target, value) return TRUE diff --git a/code/modules/client/preferences/occupation.dm b/code/modules/client/preferences/occupation.dm index ebf96de4ef20..5973f2560567 100644 --- a/code/modules/client/preferences/occupation.dm +++ b/code/modules/client/preferences/occupation.dm @@ -29,7 +29,7 @@ /datum/preference/blob/job_priority/create_default_value() return list() -/datum/preference/blob/job_priority/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/blob/job_priority/apply_to_human(mob/living/carbon/human/target, value) return /datum/preference/blob/job_priority/deserialize(input, datum/preferences/preferences) diff --git a/code/modules/client/preferences/species_features/basic.dm b/code/modules/client/preferences/species_features/basic.dm index 165c9afe06af..1e07b913af1d 100644 --- a/code/modules/client/preferences/species_features/basic.dm +++ b/code/modules/client/preferences/species_features/basic.dm @@ -184,7 +184,7 @@ /datum/preference/color/sclera/create_default_value() return "#f8ef9e" -/datum/preference/color/sclera/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/color/sclera/apply_to_human(mob/living/carbon/human/target, value) target.sclera_color = value target.update_eyes() /datum/preference/tri_color @@ -261,7 +261,7 @@ serialized_mods[serial_mod_data["path"]] = serial_mod_data return serialized_mods -/datum/preference/appearance_mods/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/appearance_mods/apply_to_human(mob/living/carbon/human/target, value) var/list/deserialized_mods = value if(!value) return diff --git a/code/modules/client/preferences/species_features/skrell.dm b/code/modules/client/preferences/species_features/skrell.dm deleted file mode 100644 index 774369d58815..000000000000 --- a/code/modules/client/preferences/species_features/skrell.dm +++ /dev/null @@ -1,9 +0,0 @@ -/datum/preference/choiced/headtails - savefile_key = "feature_headtails" - savefile_identifier = PREFERENCE_CHARACTER - -/datum/preference/choiced/headtails/init_possible_values() - return GLOB.headtails_list - -/datum/preference/choiced/headtails/apply_to_human(mob/living/carbon/human/target, value) - target.dna.features["headtails"] = value diff --git a/code/modules/client/preferences/species_features/teshari.dm b/code/modules/client/preferences/species_features/teshari.dm index 08cef96db2e1..6d4871721fc0 100644 --- a/code/modules/client/preferences/species_features/teshari.dm +++ b/code/modules/client/preferences/species_features/teshari.dm @@ -12,7 +12,7 @@ /datum/preference/choiced/teshari_feathers/init_possible_values() return GLOB.teshari_feathers_list -/datum/preference/choiced/teshari_feathers/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/choiced/teshari_feathers/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["teshari_feathers"] = value /datum/preference/choiced/teshari_ears @@ -26,7 +26,7 @@ /datum/preference/choiced/teshari_ears/init_possible_values() return GLOB.teshari_ears_list -/datum/preference/choiced/teshari_ears/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/choiced/teshari_ears/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["teshari_ears"] = value /datum/preference/choiced/teshari_body_feathers @@ -40,7 +40,7 @@ /datum/preference/choiced/teshari_body_feathers/init_possible_values() return GLOB.teshari_body_feathers_list -/datum/preference/choiced/teshari_body_feathers/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/choiced/teshari_body_feathers/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["teshari_body_feathers"] = value /datum/preference/choiced/tail_teshari @@ -54,7 +54,7 @@ /datum/preference/choiced/tail_teshari/init_possible_values() return GLOB.teshari_tails_list -/datum/preference/choiced/tail_teshari/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/choiced/tail_teshari/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["tail_teshari"] = value /datum/preference/tri_color/teshari_tail diff --git a/code/modules/client/preferences/species_features/vox.dm b/code/modules/client/preferences/species_features/vox.dm index 989d468d27d3..b666327ae00d 100644 --- a/code/modules/client/preferences/species_features/vox.dm +++ b/code/modules/client/preferences/species_features/vox.dm @@ -28,6 +28,7 @@ /datum/preference/choiced/vox_facial_hair/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["vox_facial_hair"] = value +/* VOX CURRENTLY ONLY HAVE ONE TAIL, THIS IS REDUNDANT /datum/preference/choiced/tail_vox explanation = "Tail" savefile_key = "tail_vox" @@ -37,8 +38,9 @@ /datum/preference/choiced/tail_vox/init_possible_values() return GLOB.tails_list_vox -/datum/preference/choiced/tail_vox/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences) +/datum/preference/choiced/tail_vox/apply_to_human(mob/living/carbon/human/target, value) target.dna.features["tail_vox"] = value +*/ #undef VOX_BODY_COLOR #undef VOX_SNOUT_COLOR diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index ff88e743062f..747d4f732cec 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -404,14 +404,6 @@ Key procs spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), /datum/language/vox = list(LANGUAGE_ATOM)) -/datum/language_holder/skrell - understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/skrell = list(LANGUAGE_ATOM), - /datum/language/slime = list(LANGUAGE_ATOM)) - spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), - /datum/language/skrell = list(LANGUAGE_ATOM), - /datum/language/slime = list(LANGUAGE_ATOM)) - /datum/language_holder/teshari understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), /datum/language/schechi = list(LANGUAGE_ATOM)) diff --git a/code/modules/language/language_manuals.dm b/code/modules/language/language_manuals.dm index 076b4cfdbddf..d174550e190b 100644 --- a/code/modules/language/language_manuals.dm +++ b/code/modules/language/language_manuals.dm @@ -68,7 +68,6 @@ /datum/language/draconic, /datum/language/moffic, /datum/language/calcic, - /datum/language/skrell, /datum/language/schechi, /datum/language/vox, ) diff --git a/code/modules/language/skrell.dm b/code/modules/language/skrell.dm deleted file mode 100644 index 88a66cb15107..000000000000 --- a/code/modules/language/skrell.dm +++ /dev/null @@ -1,10 +0,0 @@ -/datum/language/skrell - name = "Sk'Xrum" - desc = "The language of the skrells. A bunch of warbling and musical tone." - space_chance = 100 - flags = TONGUELESS_SPEECH - key = "l" - syllables = list("qr", "qrr", "xuq", "qil", "quum", "xuqm", "vol", "xrim", "zaoo", "qu-uu", "qix", "qoo", "zix") - default_priority = 90 - icon_state = "skrell" - icon = 'icons/misc/language.dmi' diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index c87bec1e2b85..c33544864332 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -27,6 +27,7 @@ var/datum/job/preview_job = get_highest_priority_job() // Set up the dummy for its photoshoot + mannequin.dna.species.replace_missing_bodyparts(mannequin) // Augments modify bodyparts, so we need to reset them incase augs were removed. apply_prefs_to(mannequin, TRUE) switch(preview_pref) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm index 579c23991b18..778c2890b6d0 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm @@ -46,7 +46,7 @@ female += D.name if(add_blank) - L["None"] = new /datum/sprite_accessory/blank + L[SPRITE_ACCESSORY_NONE] = new /datum/sprite_accessory/blank sortTim(L, GLOBAL_PROC_REF(cmp_text_asc), FALSE) if(male) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm index 72a1864fb61f..47714ca8ddc7 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm @@ -2,12 +2,8 @@ icon = 'icons/mob/mutant_bodyparts.dmi' em_block = TRUE -/datum/sprite_accessory/ears/none - name = "None" - icon_state = "none" - /datum/sprite_accessory/ears/cat name = "Cat" icon_state = "cat" - hasinner = 1 + hasinner = TRUE color_src = HAIR diff --git a/code/modules/mob/dead/new_player/sprite_accessories/frills.dm b/code/modules/mob/dead/new_player/sprite_accessories/frills.dm index cd8bffbfccdc..1534b6eac035 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/frills.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/frills.dm @@ -1,10 +1,6 @@ /datum/sprite_accessory/frills icon = 'icons/mob/mutant_bodyparts.dmi' -/datum/sprite_accessory/frills/none - name = "None" - icon_state = "none" - /datum/sprite_accessory/frills/simple name = "Simple" icon_state = "simple" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair.dm index abda26faf314..30caca703440 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair.dm @@ -1256,7 +1256,3 @@ /datum/sprite_accessory/vox_hair/ruffhawk name = "Vox Ruffhawk" icon_state = "ruffhawk" - -/datum/sprite_accessory/vox_hair/none - name = "None" - icon_state = "none" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/headtails.dm b/code/modules/mob/dead/new_player/sprite_accessories/headtails.dm deleted file mode 100644 index de585f61cb4a..000000000000 --- a/code/modules/mob/dead/new_player/sprite_accessories/headtails.dm +++ /dev/null @@ -1,15 +0,0 @@ -/* -Skrell Headtails -*/ - -/datum/sprite_accessory/headtails - icon = 'icons/mob/species/skrell/skrell_headtails.dmi' - color_src = HAIR - -/datum/sprite_accessory/headtails/long - name = "Long" - icon_state = "long" - -/datum/sprite_accessory/headtails/short - name = "Short" - icon_state = "short" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm index 6a4568db7ea4..8bf8891974a7 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm @@ -2,10 +2,6 @@ icon = 'icons/mob/mutant_bodyparts.dmi' em_block = TRUE -/datum/sprite_accessory/horns/none - name = "None" - icon_state = "none" - /datum/sprite_accessory/horns/simple name = "Simple" icon_state = "simple" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm index 61ed872b7d4f..fff6084abf35 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm @@ -18,9 +18,11 @@ name = "Round + Light" icon_state = "roundlight" -/datum/sprite_accessory/vox_snouts/vox +/datum/sprite_accessory/vox_snouts icon = 'icons/mob/species/vox/vox_snouts.dmi' - name = "Vox Snout" - icon_state = "vox" em_block = TRUE color_src = MUTCOLORS2 + +/datum/sprite_accessory/vox_snouts/vox + name = "Vox Snout" + icon_state = "vox" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/spines.dm b/code/modules/mob/dead/new_player/sprite_accessories/spines.dm index d129a4630352..09fbad673b66 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/spines.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/spines.dm @@ -1,55 +1,18 @@ /datum/sprite_accessory/spines icon = 'icons/mob/mutant_bodyparts.dmi' em_block = TRUE - -/datum/sprite_accessory/spines_animated - icon = 'icons/mob/mutant_bodyparts.dmi' - em_block = TRUE - -/datum/sprite_accessory/spines/none - name = "None" - icon_state = "none" - -/datum/sprite_accessory/spines_animated/none - name = "None" - icon_state = "none" - /datum/sprite_accessory/spines/short name = "Short" icon_state = "short" - -/datum/sprite_accessory/spines_animated/short - name = "Short" - icon_state = "short" - /datum/sprite_accessory/spines/shortmeme name = "Short + Membrane" icon_state = "shortmeme" - -/datum/sprite_accessory/spines_animated/shortmeme - name = "Short + Membrane" - icon_state = "shortmeme" - /datum/sprite_accessory/spines/long name = "Long" icon_state = "long" - -/datum/sprite_accessory/spines_animated/long - name = "Long" - icon_state = "long" - /datum/sprite_accessory/spines/longmeme name = "Long + Membrane" icon_state = "longmeme" - -/datum/sprite_accessory/spines_animated/longmeme - name = "Long + Membrane" - icon_state = "longmeme" - /datum/sprite_accessory/spines/aqautic name = "Aquatic" icon_state = "aqua" - -/datum/sprite_accessory/spines_animated/aqautic - name = "Aquatic" - icon_state = "aqua" diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index 572bd9a9a64c..9070e837567b 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -3,6 +3,8 @@ desc = "A piece of juicy meat found in a person's head." icon_state = "brain" visual = TRUE + color_source = ORGAN_COLOR_STATIC + draw_color = null throw_speed = 3 throw_range = 5 layer = ABOVE_MOB_LAYER @@ -352,10 +354,6 @@ owner.adjust_timed_status_effect(10 SECONDS, /datum/status_effect/speech/stutter) owner.adjust_timed_status_effect(3 SECONDS, /datum/status_effect/confusion) -/obj/item/organ/brain/skrell - name = "spongy brain" - icon_state = "skrell-brain" - ////////////////////////////////////TRAUMAS//////////////////////////////////////// diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 03ea2f899003..d9d96e6c465d 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -85,29 +85,34 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /mob/living/carbon/human/dummy/consistent/setup_human_dna() create_dna(src) dna.initialize_dna(skip_index = TRUE) - dna.features["ears"] = "None" + dna.features["ears"] = get_consistent_feature_entry(GLOB.ears_list) dna.features["ethcolor"] = COLOR_WHITE - dna.features["frills"] = "None" - dna.features["horns"] = "None" + dna.features["frills"] = get_consistent_feature_entry(GLOB.frills_list) + dna.features["horns"] = get_consistent_feature_entry(GLOB.horns_list) dna.set_all_mutant_colors(COLOR_VIBRANT_LIME) - dna.features["moth_antennae"] = "Plain" - dna.features["moth_markings"] = "None" - dna.features["moth_wings"] = "Plain" - dna.features["snout"] = "Round" - dna.features["spines"] = "None" - dna.features["tail_human"] = "None" - dna.features["tail_lizard"] = "Smooth" - dna.features["tail_vox"] = "Vox Tail" - dna.features["vox_hair"] = "None" - dna.features["vox_facial_hair"] = "None" - dna.features["vox_snout"] = "Vox Snout" - dna.features["tail_cat"] = "None" - dna.features["pod_hair"] = "Ivy" - dna.features["teshari_feathers"] = "Mane" - dna.features["teshari_body_feathers"] = "Plain" - dna.features["teshari_ears"] = "None" - dna.features["tail_teshari"] = "Default" - dna.features["headtails"] = "Long" + dna.features["moth_antennae"] = get_consistent_feature_entry(GLOB.moth_antennae_list) + dna.features["moth_markings"] = get_consistent_feature_entry(GLOB.moth_markings_list) + dna.features["moth_wings"] = get_consistent_feature_entry(GLOB.wings_list) + dna.features["snout"] = get_consistent_feature_entry(GLOB.snouts_list) + dna.features["spines"] = get_consistent_feature_entry(GLOB.spines_list) + dna.features["tail_human"] = get_consistent_feature_entry(GLOB.tails_list_human) + dna.features["tail_lizard"] = get_consistent_feature_entry(GLOB.tails_list_lizard) + dna.features["tail_vox"] = get_consistent_feature_entry(GLOB.tails_list_vox) + dna.features["vox_hair"] = get_consistent_feature_entry(GLOB.vox_hair_list) + dna.features["vox_facial_hair"] = get_consistent_feature_entry(GLOB.vox_facial_hair_list) + dna.features["vox_snout"] = get_consistent_feature_entry(GLOB.vox_snouts_list) + dna.features["tail_cat"] = get_consistent_feature_entry(GLOB.tails_list_human) + dna.features["pod_hair"] = get_consistent_feature_entry(GLOB.pod_hair_list) + dna.features["teshari_feathers"] = get_consistent_feature_entry(GLOB.teshari_feathers_list) + dna.features["teshari_body_feathers"] = get_consistent_feature_entry(GLOB.teshari_body_feathers_list) + dna.features["teshari_ears"] = get_consistent_feature_entry(GLOB.teshari_ears_list) + dna.features["tail_teshari"] = get_consistent_feature_entry(GLOB.teshari_tails_list) + +/// Takes in an accessory list and returns the first entry from that list, ensuring that we dont return SPRITE_ACCESSORY_NONE in the process. +/proc/get_consistent_feature_entry(list/accessory_feature_list) + var/consistent_entry = (accessory_feature_list- SPRITE_ACCESSORY_NONE)[1] + ASSERT(!isnull(consistent_entry)) + return consistent_entry //Inefficient pooling/caching way. GLOBAL_LIST_EMPTY(human_dummy_list) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index c02a9cf047a2..6bfbd75ea1b9 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -103,26 +103,6 @@ key_third_person = "shrugs" message = "shrugs." -/datum/emote/living/carbon/human/wag - key = "wag" - key_third_person = "wags" - message = "wags their tail." - -/datum/emote/living/carbon/human/wag/run_emote(mob/user, params, type_override, intentional) - . = ..() - if(!.) - return - var/obj/item/organ/tail/oranges_accessory = user.getorganslot(ORGAN_SLOT_EXTERNAL_TAIL) - if(oranges_accessory.wag_flags & WAG_WAGGING) //We verified the tail exists in can_run_emote() - SEND_SIGNAL(user, COMSIG_ORGAN_WAG_TAIL, FALSE) - else - SEND_SIGNAL(user, COMSIG_ORGAN_WAG_TAIL, TRUE) - -/datum/emote/living/carbon/human/wag/can_run_emote(mob/user, status_check, intentional) - var/obj/item/organ/tail/tail = user.getorganslot(ORGAN_SLOT_EXTERNAL_TAIL) - if(tail?.wag_flags & WAG_ABLE) - return ..() - return FALSE /datum/emote/living/carbon/human/wing key = "wing" key_third_person = "wings" @@ -265,7 +245,7 @@ sound = 'sound/emotes/voxrustle.ogg' species_type_whitelist_typecache = list(/datum/species/vox) -//Shared custody between skrell and teshari +// Teshari emotes. for some reason. /datum/emote/living/carbon/human/warble key = "warble" key_third_person = "warbles!" @@ -273,7 +253,7 @@ sound = 'sound/voice/warbles.ogg' emote_type = EMOTE_AUDIBLE vary = TRUE - species_type_whitelist_typecache = list(/datum/species/skrell, /datum/species/teshari) + species_type_whitelist_typecache = list(/datum/species/teshari) /datum/emote/living/carbon/human/warble/get_frequency(mob/living/user) //no regular warbling sound but oh well if(isteshari(user)) @@ -288,7 +268,7 @@ emote_type = EMOTE_AUDIBLE vary = TRUE sound = 'sound/voice/trills.ogg' - species_type_whitelist_typecache = list(/datum/species/skrell, /datum/species/teshari) + species_type_whitelist_typecache = list(/datum/species/teshari) /datum/emote/living/carbon/human/wurble key = "wurble" @@ -297,7 +277,7 @@ emote_type = EMOTE_AUDIBLE vary = TRUE sound = 'sound/voice/wurble.ogg' - species_type_whitelist_typecache = list(/datum/species/skrell, /datum/species/teshari) + species_type_whitelist_typecache = list(/datum/species/teshari) //Teshari emotes /datum/emote/living/carbon/human/chirp diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index d5ab8345f464..fb4cf7cef0a3 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1186,8 +1186,5 @@ /mob/living/carbon/human/species/zombie/infectious race = /datum/species/zombie/infectious -/mob/living/carbon/human/species/skrell - race = /datum/species/skrell - /mob/living/carbon/human/species/vox race = /datum/species/vox diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index f26c48150230..dd336a4d0c99 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -13,25 +13,22 @@ //If a specific bodypart is targetted, check how that bodypart is protected and return the value. //If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X + for(var/obj/item/bodypart/BP as anything in bodyparts) armorval += checkarmor(BP, type) organnum++ return (armorval/max(organnum, 1)) -/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, d_type) +/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/limb, d_type) if(!d_type) return 0 - var/protection = 0 + var/protection = limb.returnArmor().getRating(d_type) var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id, wear_neck) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor) - for(var/bp in body_parts) - if(!bp) - continue - if(bp && istype(bp , /obj/item/clothing)) - var/obj/item/clothing/C = bp - if(C.body_parts_covered & def_zone.body_part) - protection += C.returnArmor().getRating(d_type) + + for(var/obj/item/clothing/C in body_parts) + if(C.body_parts_covered & limb.body_part) + protection += C.returnArmor().getRating(d_type) + protection += physiology.returnArmor().getRating(d_type) return protection @@ -528,19 +525,10 @@ . = ..() if(. & EMP_PROTECT_CONTENTS) return - var/informed = FALSE + for(var/obj/item/bodypart/L as anything in src.bodyparts) if(!IS_ORGANIC_LIMB(L)) - if(!informed) - to_chat(src, span_userdanger("You feel a sharp pain as your robotic limbs overload.")) - informed = TRUE - switch(severity) - if(1) - L.receive_damage(0,10) - Paralyze(200) - if(2) - L.receive_damage(0,5) - Paralyze(100) + L.emp_act() /mob/living/carbon/human/acid_act(acidpwr, acid_volume, bodyzone_hit) //todo: update this to utilize check_obscured_slots() //and make sure it's check_obscured_slots(TRUE) to stop aciding through visors etc var/list/damaged = list() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index cb4312af3070..f42be4e1f46a 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -94,6 +94,14 @@ GLOBAL_LIST_EMPTY(features_by_species) BODY_ZONE_CHEST = /obj/item/bodypart/chest, ) + /// Robotic bodyparts for preference selection + var/list/robotic_bodyparts = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/robot/surplus, + BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/robot/surplus, + BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/robot/surplus, + BODY_ZONE_R_LEG= /obj/item/bodypart/leg/right/robot/surplus, + ) + ///List of cosmetic organs to generate like horns, frills, wings, etc. list(typepath of organ = "Round Beautiful BDSM Snout"). Still WIP var/list/cosmetic_organs = list() @@ -329,6 +337,18 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/copy_properties_from(datum/species/old_species) return +/datum/species/proc/should_organ_apply_to(mob/living/carbon/target, obj/item/organ/organpath) + if(isnull(organpath) || isnull(target)) + CRASH("passed a null path or mob to 'should_external_organ_apply_to'") + + var/feature_key = initial(organpath.feature_key) + if(isnull(feature_key)) + return TRUE + + if(target.dna.features[feature_key] != SPRITE_ACCESSORY_NONE) + return TRUE + return FALSE + /** * Corrects organs in a carbon, removing ones it doesn't need and adding ones it does. * @@ -391,7 +411,15 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/organ/I = C.getorgan(mutantorgan) if(I) I.Remove(C) - QDEL_NULL(I) + qdel(I) + + for(var/mutantorgan in old_species.cosmetic_organs) + if(mutantorgan in cosmetic_organs) + continue + var/obj/item/organ/I = C.getorgan(mutantorgan) + if(I) + I.Remove(C) + qdel(I) for(var/organ_path in mutant_organs) var/obj/item/organ/current_organ = C.getorgan(organ_path) @@ -405,6 +433,13 @@ GLOBAL_LIST_EMPTY(features_by_species) // organ.Insert will qdel any current organs in that slot, so we don't need to. replacement.Insert(C, TRUE, FALSE) + for(var/obj/item/organ/organ_path as anything in cosmetic_organs) + if(!should_organ_apply_to(C, organ_path)) + continue + //Load a persons preferences from DNA + var/obj/item/organ/new_organ = SSwardrobe.provide_type(organ_path) + new_organ.Insert(C) + /** * Proc called when a carbon becomes this species. * @@ -430,7 +465,7 @@ GLOBAL_LIST_EMPTY(features_by_species) C.mob_size = species_mob_size C.mob_biotypes = inherent_biotypes - if(old_species.type != type) + if(type != old_species.type) replace_body(C, src) regenerate_organs(C, old_species, visual_only = C.visual_only_organs) @@ -453,13 +488,6 @@ GLOBAL_LIST_EMPTY(features_by_species) else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand INVOKE_ASYNC(C, TYPE_PROC_REF(/mob, put_in_hands), new mutanthands) - if(ishuman(C)) - var/mob/living/carbon/human/human = C - for(var/obj/item/organ/organ_path as anything in cosmetic_organs) - //Load a persons preferences from DNA - var/obj/item/organ/new_organ = SSwardrobe.provide_type(organ_path) - new_organ.Insert(human) - for(var/X in inherent_traits) ADD_TRAIT(C, X, SPECIES_TRAIT) @@ -653,12 +681,6 @@ GLOBAL_LIST_EMPTY(features_by_species) if(!mutant_bodyparts || HAS_TRAIT(source, TRAIT_INVISIBLE_MAN)) return - var/obj/item/bodypart/head/noggin = source.get_bodypart(BODY_ZONE_HEAD) - - if(mutant_bodyparts["ears"]) - if(!source.dna.features["ears"] || source.dna.features["ears"] == "None" || source.head && (source.head.flags_inv & HIDEHAIR) || (source.wear_mask && (source.wear_mask.flags_inv & HIDEHAIR)) || !noggin || !IS_ORGANIC_LIMB(noggin)) - bodyparts_to_add -= "ears" - if(!bodyparts_to_add) return @@ -670,14 +692,10 @@ GLOBAL_LIST_EMPTY(features_by_species) for(var/bodypart in bodyparts_to_add) var/datum/sprite_accessory/accessory switch(bodypart) - if("ears") - accessory = GLOB.ears_list[source.dna.features["ears"]] if("legs") accessory = GLOB.legs_list[source.dna.features["legs"]] if("caps") accessory = GLOB.caps_list[source.dna.features["caps"]] - if("headtails") - accessory = GLOB.headtails_list[source.dna.features["headtails"]] if(!accessory || accessory.icon_state == "none") continue @@ -2127,3 +2145,26 @@ GLOBAL_LIST_EMPTY(features_by_species) /// Creates body parts for the target completely from scratch based on the species /datum/species/proc/create_fresh_body(mob/living/carbon/target) target.create_bodyparts(bodypart_overrides) + +/datum/species/proc/replace_missing_bodyparts(mob/living/carbon/target) + if((digitigrade_customization == DIGITIGRADE_OPTIONAL && target.dna.features["legs"] == "Digitigrade Legs") || digitigrade_customization == DIGITIGRADE_FORCED) + bodypart_overrides[BODY_ZONE_R_LEG] = /obj/item/bodypart/leg/right/digitigrade + bodypart_overrides[BODY_ZONE_L_LEG] = /obj/item/bodypart/leg/left/digitigrade + + for(var/slot in target.get_missing_limbs()) + var/obj/item/bodypart/path = bodypart_overrides[slot] + if(path) + path = new path() + path.attach_limb(target, TRUE) + path.update_limb(is_creating = TRUE) + + for(var/obj/item/bodypart/BP as anything in target.bodyparts) + if(BP.type == bodypart_overrides[BP.body_zone]) + continue + + var/obj/item/bodypart/new_part = bodypart_overrides[BP.body_zone] + if(new_part) + new_part = new new_part() + new_part.replace_limb(target, TRUE) + new_part.update_limb(is_creating = TRUE) + qdel(BP) diff --git a/code/modules/mob/living/carbon/human/species_types/skrell.dm b/code/modules/mob/living/carbon/human/species_types/skrell.dm deleted file mode 100644 index 12c9af6d94e4..000000000000 --- a/code/modules/mob/living/carbon/human/species_types/skrell.dm +++ /dev/null @@ -1,144 +0,0 @@ -/datum/species/skrell - name = "\improper Skrell" - id = SPECIES_SKRELL - say_mod = "warbles" - default_color = "42F58D" - species_traits = list(MUTCOLORS, HAIRCOLOR, EYECOLOR, LIPS, HAS_FLESH, HAS_BONE, BODY_RESIZABLE) - inherent_traits = list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_LIGHT_DRINKER) - liked_food = VEGETABLES | FRUIT - disliked_food = GROSS | MEAT | RAW | DAIRY - toxic_food = TOXIC | SEAFOOD - payday_modifier = 0.95 - job_outfit_type = SPECIES_HUMAN - changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT - species_language_holder = /datum/language_holder/skrell - exotic_bloodtype = "S" - - species_eye_path = 'icons/mob/species/skrell/eyes.dmi' - - mutantbrain = /obj/item/organ/brain/skrell - mutanteyes = /obj/item/organ/eyes/skrell - mutantlungs = /obj/item/organ/lungs/skrell - mutantheart = /obj/item/organ/heart/skrell - mutantliver = /obj/item/organ/liver/skrell - mutanttongue = /obj/item/organ/tongue/skrell - - cosmetic_organs = list( - /obj/item/organ/skrell_headtails = "Long" - ) - - bodypart_overrides = list( - BODY_ZONE_HEAD = /obj/item/bodypart/head/skrell, - BODY_ZONE_CHEST = /obj/item/bodypart/chest/skrell, - BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/skrell, - BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/skrell, - BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/skrell, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/skrell, - ) - -/datum/species/skrell/spec_life(mob/living/carbon/human/skrell_mob, delta_time, times_fired) - . = ..() - if(skrell_mob.nutrition > NUTRITION_LEVEL_ALMOST_FULL) - skrell_mob.set_nutrition(NUTRITION_LEVEL_ALMOST_FULL) - -/datum/species/skrell/prepare_human_for_preview(mob/living/carbon/human/human) - human.dna.mutant_colors[MUTCOLORS_GENERIC_1] = COLOR_BLUE_GRAY - human.hair_color = COLOR_BLUE_GRAY - human.update_body(TRUE) - -// Copper restores blood for Skrell instead of iron. -/datum/species/skrell/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, delta_time, times_fired) - . = ..() - if(chem.type == /datum/reagent/copper) - if(H.blood_volume < BLOOD_VOLUME_NORMAL) - H.blood_volume += 0.5 * delta_time - H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * delta_time) - return TRUE - if(chem.type == /datum/reagent/iron) - H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * delta_time) - return TRUE - -/datum/species/skrell/random_name(gender, unique, lastname, attempts) - . = "" - - var/full_name = "" - var/new_name = "" - var/static/list/syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix") - for(var/x = rand(1,2) to 0 step -1) - new_name += pick(syllables) - full_name += pick(syllables) - - full_name += " [capitalize(new_name)]" - . += "[capitalize(full_name)]" - - if(unique && attempts < 10) - if(findname(new_name)) - . = .(gender, TRUE, null, attempts++) - - return . - -//Skrell lore -/datum/species/skrell/get_species_description() - return "Skrells are aquatic humanoids coming from the planet of Qerrbalak, often deeply ceremonial and focused on learning more about the galaxy. \ - Their inherent fondness for learning and technology has resulted in them advancing further in science when compared to humanity, \ - however progress has mostly gone stagnant due to recent political turmoil and the economic crisis back home." - -/datum/species/skrell/get_species_lore() - return list( - "Skrellian society is obviously quite different from that of humanity, and many outsiders often call Skrell emotionless however this is wrong, \ - as Skrell lack facial muscles and frequently make use of their tone of voice, movement and more. \ - Skrell also sees things far more in the long term side of things because of their long lifespan.", - - "Despite the good relations enjoyed with most other species, there is a deep fear within the federation of foreign influence, and because of this \ - fear, the federation adopted a rather isolationist foreign policy which was mostly caused by the recent political turmoil and \ - economic crash.", - - "The economic crash also known as \"Qerrbalak recession\" was caused when a large disaster happened on huge mining facility at Urmx housing one \ - of the federations biggest plasma mines, this disaster was caused when a fire erupted in one of the lower tunnels of XM-2 a mining site, this \ - caused an immense plasmafire that raged for 6 years and lead to the casualities of 84 employees of the facility, with 4356 being injured and around \ - 50.0000 people living on the planet being directly affected.", - - "Not only did this fire destroy one of the biggest mining sites of the federation, but as well affected various other nearby sites causing a huge scarcity in plasma. \ - As plasma supply dropped around various worlds in federation such as Qerrbalak were unable to maintain the demand in plasma, and caused a \ - huge rise in unemployment and caused a stock crash in the plasma market in federation.", - ) - -//Skrell features - -/datum/species/skrell/create_pref_unique_perks() - var/list/to_add = list() - - to_add += list( - list( - SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK, - SPECIES_PERK_ICON = "biohazard", - SPECIES_PERK_NAME = "Toxin Tolerance", - SPECIES_PERK_DESC = "Skrell have a higher resistance to toxins.", - ), - list( - SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK, - SPECIES_PERK_ICON = "syringe", - SPECIES_PERK_NAME = "Haemocyanin-Based Circulatory System", - SPECIES_PERK_DESC = "Skrell blood is restored faster with copper, iron doesn't work.", - ), - list( - SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, - SPECIES_PERK_ICON = "thermometer", - SPECIES_PERK_NAME = "Temperature Intolerance", - SPECIES_PERK_DESC = "Skrell lungs cannot handle temperature differences.", - ), - list( - SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, - SPECIES_PERK_ICON = "sun", - SPECIES_PERK_NAME = "High Light Sensitivity", - SPECIES_PERK_DESC = "Skrell eyes are sensitive to bright lights and are more susceptible to damage when not sufficiently protected.", - ), - list( - SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, - SPECIES_PERK_ICON = "wine-bottle", - SPECIES_PERK_NAME = "Low Alcohol Tolerance", - SPECIES_PERK_DESC = "Skrell have a low tolerance to alcohol, resulting in them feeling the effects of it much earlier compared to other species." - ), - ) - - return to_add diff --git a/code/modules/mob/living/carbon/human/species_types/teshari.dm b/code/modules/mob/living/carbon/human/species_types/teshari.dm index fc306a801d4e..ee9ab864aabc 100644 --- a/code/modules/mob/living/carbon/human/species_types/teshari.dm +++ b/code/modules/mob/living/carbon/human/species_types/teshari.dm @@ -49,6 +49,13 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/teshari, ) + robotic_bodyparts = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/robot/surplus/teshari, + BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/robot/surplus/teshari, + BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/robot/surplus/teshari, + BODY_ZONE_R_LEG= /obj/item/bodypart/leg/right/robot/surplus/teshari, + ) + #define TESH_BODY_COLOR "#DEB887" // Also in code\modules\client\preferences\species_features\teshari.dm #define TESH_FEATHER_COLOR "#996633" diff --git a/code/modules/mob/living/carbon/human/species_types/vox.dm b/code/modules/mob/living/carbon/human/species_types/vox.dm index b5fff99314f3..4b0fb5a0d967 100644 --- a/code/modules/mob/living/carbon/human/species_types/vox.dm +++ b/code/modules/mob/living/carbon/human/species_types/vox.dm @@ -42,6 +42,7 @@ outfit_important_for_life = /datum/outfit/vox species_language_holder = /datum/language_holder/vox changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT + bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/vox, BODY_ZONE_CHEST = /obj/item/bodypart/chest/vox, @@ -51,6 +52,8 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/vox, ) + robotic_bodyparts = null + #define VOX_BODY_COLOR "#C4DB1A" // Also in code\modules\client\preferences\species_features\vox.dm #define VOX_SNOUT_COLOR "#E5C04B" diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 854e3cd2a1ae..c24bc637f126 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -65,9 +65,6 @@ blood_type = "LE" unique_blood = /datum/reagent/consumable/liquidelectricity -/obj/item/reagent_containers/blood/skrell - blood_type = "S" - /obj/item/reagent_containers/blood/universal blood_type = "U" diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index df9a84cf1aff..1417373e49ab 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -69,6 +69,68 @@ category = list(DCAT_CYBORG) mapload_design_flags = DESIGN_FAB_ROBOTICS +//Teshari Augs +/datum/design/teshari_chest + name = "Prototype Teshari Torso" + id = "teshari_borg_chest" + build_type = MECHFAB + build_path = /obj/item/bodypart/chest/robot/surplus/teshari + materials = list(/datum/material/iron=40000) + construction_time = 350 + category = list(DCAT_CYBORG) + mapload_design_flags = DESIGN_FAB_ROBOTICS + + +/datum/design/teshari_head + name = "Prototype Teshari Head" + id = "teshari_borg_head" + build_type = MECHFAB + build_path = /obj/item/bodypart/head/robot/surplus/teshari + materials = list(/datum/material/iron=5000) + construction_time = 350 + category = list(DCAT_CYBORG) + mapload_design_flags = DESIGN_FAB_ROBOTICS + +/datum/design/teshari_r_arm + name = "Prototype Teshari Right Arm" + id = "teshari_borg_r_arm" + build_type = MECHFAB + build_path = /obj/item/bodypart/arm/right/robot/surplus/teshari + materials = list(/datum/material/iron=10000) + construction_time = 350 + category = list(DCAT_CYBORG) + mapload_design_flags = DESIGN_FAB_ROBOTICS + +/datum/design/teshari_l_arm + name = "Prototype Teshari Left Arm" + id = "teshari_borg_l_arm" + build_type = MECHFAB + build_path = /obj/item/bodypart/arm/left/robot/surplus/teshari + materials = list(/datum/material/iron=10000) + construction_time = 350 + category = list(DCAT_CYBORG) + mapload_design_flags = DESIGN_FAB_ROBOTICS + +/datum/design/teshari_l_leg + name = "Prototype Teshari Left Leg" + id = "teshari_borg_l_leg" + build_type = MECHFAB + build_path = /obj/item/bodypart/leg/left/robot/surplus/teshari + materials = list(/datum/material/iron=10000) + construction_time = 350 + category = list(DCAT_CYBORG) + mapload_design_flags = DESIGN_FAB_ROBOTICS + +/datum/design/teshari_r_leg + name = "Prototype Teshari Right Leg" + id = "teshari_borg_r_leg" + build_type = MECHFAB + build_path = /obj/item/bodypart/leg/right/robot/surplus/teshari + materials = list(/datum/material/iron=10000) + construction_time = 350 + category = list(DCAT_CYBORG) + mapload_design_flags = DESIGN_FAB_ROBOTICS + //Ripley /datum/design/ripley_chassis name = "Exosuit Chassis (APLU \"Ripley\")" diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 0a097c28a52a..88b3b1d62cb7 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -158,8 +158,8 @@ /// If something is currently grasping this bodypart and trying to staunch bleeding (see [/obj/item/hand_item/self_grasp]) var/obj/item/hand_item/self_grasp/grasped_by - ///A list of all the cosmetic organs we've got stored to draw horns, wings and stuff with (special because we are actually in the limbs unlike normal organs :/ ) - var/list/obj/item/organ/cosmetic_organs = list() + ///A list of all the organs inside of us. + var/list/obj/item/organ/contained_organs = list() /// Type of an attack from this limb does. Arms will do punches, Legs for kicks, and head for bites. (TO ADD: tactical chestbumps) var/attack_type = BRUTE @@ -206,6 +206,9 @@ if(length(wounds)) stack_trace("[type] qdeleted with [length(wounds)] uncleared wounds") wounds.Cut() + + QDEL_LIST(contained_organs) + if(owner) drop_limb(TRUE) return ..() @@ -331,14 +334,13 @@ playsound(bodypart_turf, 'sound/misc/splort.ogg', 50, TRUE, -1) seep_gauze(9999) // destroy any existing gauze if any exists - for(var/obj/item/organ/bodypart_organ in get_organs()) - bodypart_organ.transfer_to_limb(src, null) - for(var/obj/item/item_in_bodypart in src) - if(istype(item_in_bodypart, /obj/item/organ)) + if(isorgan(item_in_bodypart)) var/obj/item/organ/O = item_in_bodypart if(O.organ_flags & ORGAN_UNREMOVABLE) continue + else + remove_organ(O) item_in_bodypart.forceMove(bodypart_turf) @@ -987,8 +989,10 @@ ///Loops through all of the bodypart's external organs and update's their color. /obj/item/bodypart/proc/recolor_cosmetic_organs() - for(var/obj/item/organ/ext_organ as anything in cosmetic_organs) - ext_organ.inherit_color(force = TRUE) + for(var/obj/item/organ/O as anything in contained_organs) + if(!O.visual) + continue + O.inherit_color(force = TRUE) ///A multi-purpose setter for all things immediately important to the icon and iconstate of the limb. /obj/item/bodypart/proc/change_appearance(icon, id, greyscale, dimorphic) @@ -1055,3 +1059,48 @@ return list(0,-3) if(WEST) return list(0,-3) + +/obj/item/bodypart/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_WIRES || !(bodytype & BODYTYPE_ROBOTIC)) + return FALSE + + if(!(body_zone == BODY_ZONE_CHEST)) + owner.visible_message(span_danger("[owner]'s [src.name] falls limp!")) + + var/time_needed = 10 SECONDS + var/brute_damage = 1.5 + var/burn_damage = 2.5 + + if(severity == EMP_HEAVY) + time_needed *= 2 + brute_damage *= 2 + burn_damage *= 2 + + receive_damage(brute_damage, burn_damage) + do_sparks(number = 1, cardinal_only = FALSE, source = owner) + ADD_TRAIT(src, TRAIT_PARALYSIS, EMP_TRAIT) + addtimer(CALLBACK(src, PROC_REF(un_paralyze)), time_needed) + return TRUE + +/obj/item/bodypart/proc/un_paralyze() + REMOVE_TRAITS_IN(src, EMP_TRAIT) + +/obj/item/bodypart/leg/emp_act(severity) + . = ..() + if(!.) + return + owner.Knockdown(severity == EMP_HEAVY ? 20 SECONDS : 10 SECONDS) + +/obj/item/bodypart/chest/robot/emp_act(severity) + . = ..() + if(!.) + return + to_chat(owner, span_danger("Your [src.name]'s logic boards temporarily become unresponsive!")) + if(severity == EMP_HEAVY) + owner.Stun(6 SECONDS) + owner.Shake(pixelshiftx = 5, pixelshifty = 2, duration = 4 SECONDS) + return + + owner.Stun(3 SECONDS) + owner.Shake(pixelshiftx = 3, pixelshifty = 0, duration = 2.5 SECONDS) diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 50a915846e96..22d7ec53d2c9 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -146,15 +146,9 @@ to_chat(phantom_owner, span_warning("You feel your [mutation] deactivating from the loss of your [body_zone]!")) phantom_owner.dna.force_lose(mutation) - for(var/obj/item/organ/organ as anything in phantom_owner.organs) //internal organs inside the dismembered limb are dropped. - var/org_zone = check_zone(organ.zone) - if(org_zone != body_zone) - continue - organ.transfer_to_limb(src, null) - - else - for(var/obj/item/organ/O as anything in cosmetic_organs) - O.remove_from_limb() + for(var/obj/item/organ/O as anything in contained_organs) + O.Remove(phantom_owner, special) + add_organ(O) //Remove() removes it from the limb as well. for(var/trait in bodypart_traits) REMOVE_TRAIT(phantom_owner, trait, bodypart_trait_source) @@ -163,7 +157,6 @@ synchronize_bodytypes(phantom_owner) phantom_owner.update_health_hud() //update the healthdoll phantom_owner.update_body() - phantom_owner.update_body_parts() if(!drop_loc) // drop_loc = null happens when a "dummy human" used for rendering icons on prefs screen gets its limbs replaced. if(!QDELETED(src)) @@ -179,85 +172,56 @@ if(!QDELETED(src)) forceMove(drop_loc) -///Transfers the organ to the limb, and to the limb's owner, if it has one. This is done on drop_limb(). -/obj/item/organ/proc/transfer_to_limb(obj/item/bodypart/bodypart, mob/living/carbon/bodypart_owner, special) - if(owner) - Remove(owner, special) - else if(ownerlimb) - remove_from_limb(FALSE) - - if(bodypart_owner) - Insert(bodypart_owner, special) - else - add_to_limb(bodypart, TRUE) - -///Adds the organ to a bodypart, used in transfer_to_limb() -/obj/item/organ/proc/add_to_limb(obj/item/bodypart/bodypart, move) - ownerlimb = bodypart - if(visual) - ownerlimb.cosmetic_organs |= src - if(ownerlimb.owner && external_bodytypes) - ownerlimb.synchronize_bodytypes(ownerlimb.owner) - inherit_color() - - if(move) - forceMove(bodypart) - -///Removes the organ from the limb, placing it into nullspace. -/obj/item/organ/proc/remove_from_limb(move) - if(visual) - ownerlimb.cosmetic_organs -= src - if(ownerlimb.owner && external_bodytypes) - ownerlimb.synchronize_bodytypes(ownerlimb.owner) - - ownerlimb = null - - if(move) - moveToNullspace() - -/obj/item/organ/brain/transfer_to_limb(obj/item/bodypart/head/head, mob/living/carbon/human/head_owner) +///Adds the organ to a bodypart. +/obj/item/bodypart/proc/add_organ(obj/item/organ/O) + O.ownerlimb = src + contained_organs |= O + if(O.visual) + if(owner && O.external_bodytypes) + synchronize_bodytypes(owner) + O.inherit_color() + +///Removes the organ from the limb. +/obj/item/bodypart/proc/remove_organ(obj/item/organ/O) + contained_organs -= O + + if(owner && O.visual && O.external_bodytypes) + synchronize_bodytypes(owner) + + O.ownerlimb = null + +/obj/item/bodypart/head/add_organ(obj/item/organ/O) . = ..() - head.brain = src - if(brainmob) - head.brainmob = brainmob + if(istype(O, /obj/item/organ/ears)) + ears = O + + else if(istype(O, /obj/item/organ/eyes)) + eyes = O + + else if(istype(O, /obj/item/organ/tongue)) + tongue = O + + else if(istype(O, /obj/item/organ/brain)) + brain = O + +/obj/item/bodypart/head/remove_organ(obj/item/organ/O) + if(O == brain && brainmob) + var/obj/item/organ/brain/B = O + brainmob.container = null + B.brainmob = brainmob brainmob = null - head.brainmob.forceMove(head) - head.brainmob.set_stat(DEAD) - -/obj/item/organ/brain/remove_from_limb(move) - if(istype(ownerlimb, /obj/item/bodypart/head)) - var/obj/item/bodypart/head/head = ownerlimb - if(head.brainmob) - head.brainmob.container = null - brainmob = head.brainmob - head.brainmob = null - head.brain = null - head.brainmob.forceMove(src) - return ..() + brain = null + B.brainmob.forceMove(B) + + else if(O == tongue) + tongue = null + + else if(O == eyes) + eyes = null + + else if(O == ears) + ears = null -/obj/item/organ/eyes/transfer_to_limb(obj/item/bodypart/head/head, mob/living/carbon/human/head_owner) - head.eyes = src - ..() - -/obj/item/organ/ears/transfer_to_limb(obj/item/bodypart/head/head, mob/living/carbon/human/head_owner) - head.ears = src - ..() - -/obj/item/organ/tongue/transfer_to_limb(obj/item/bodypart/head/head, mob/living/carbon/human/head_owner) - head.tongue = src - ..() - -/obj/item/organ/remove_from_limb(move) - if(istype(ownerlimb, /obj/item/bodypart/head)) - var/obj/item/bodypart/head/head = ownerlimb - if(src == head.eyes) - head.eyes = null - /*else if(src == head.brain) //This is handled by the brain's override. This is here for clarity. - head.brain = null*/ - else if(src == head.ears) - head.ears = null - else if(src == head.tongue) - head.tongue = null return ..() /obj/item/bodypart/chest/drop_limb(special) @@ -339,7 +303,14 @@ pill.forceMove(src) name = "[owner.real_name]'s head" - return ..() + + . = ..() + + if(!special) + if(brain?.brainmob) + brainmob = brain.brainmob + brain.brainmob = null + brainmob.set_stat(DEAD) ///Try to attach this bodypart to a mob, while replacing one if it exists, does nothing if it fails. /obj/item/bodypart/proc/replace_limb(mob/living/carbon/limb_owner, special) @@ -385,7 +356,7 @@ qdel(attach_surgery) break - for(var/obj/item/organ/limb_organ in contents) + for(var/obj/item/organ/limb_organ as anything in contained_organs) limb_organ.Insert(new_limb_owner, special) for(var/datum/wound/W as anything in wounds) @@ -461,7 +432,9 @@ return var/all_limb_flags for(var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts) - for(var/obj/item/organ/ext_organ as anything in limb.cosmetic_organs) + for(var/obj/item/organ/ext_organ as anything in limb.contained_organs) + if(!ext_organ.visual) + continue all_limb_flags = all_limb_flags | ext_organ.external_bodytypes all_limb_flags = all_limb_flags | limb.bodytype diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index f1030ffc9cc0..eb32a9212994 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -152,7 +152,7 @@ var/turf/head_turf = get_turf(src) for(var/obj/item/head_item in src.contents) if(head_item == brain) - brain.remove_from_limb() + remove_organ(brain) if(user) user.visible_message(span_warning("[user] saws [src] open and pulls out a brain!"), span_notice("You saw [src] open and pull out a brain.")) if(violent_removal && prob(rand(80, 100))) //ghetto surgery can damage the brain. @@ -168,7 +168,7 @@ var/obj/item/organ/organ = head_item if(organ.organ_flags & ORGAN_UNREMOVABLE) continue - organ.remove_from_limb() + remove_organ(organ) head_item.forceMove(head_turf) eyes = null ears = null diff --git a/code/modules/surgery/bodyparts/rendering.dm b/code/modules/surgery/bodyparts/rendering.dm index d772fb2cfd48..1d7ff52d17f0 100644 --- a/code/modules/surgery/bodyparts/rendering.dm +++ b/code/modules/surgery/bodyparts/rendering.dm @@ -170,8 +170,8 @@ GLOBAL_LIST_INIT(limb_overlays_cache, list()) if(!is_husked) //Draw external organs like horns and frills - for(var/obj/item/organ/visual_organ in cosmetic_organs) - if(!dropped && !visual_organ.can_draw_on_bodypart(owner)) + for(var/obj/item/organ/visual_organ as anything in contained_organs) + if(!visual_organ.visual || (!dropped && !visual_organ.can_draw_on_bodypart(owner))) continue //Some externals have multiple layers for background, foreground and between . += visual_organ.get_overlays(limb_gender, image_dir) @@ -201,7 +201,9 @@ GLOBAL_LIST_INIT(limb_overlays_cache, list()) if(should_draw_greyscale && draw_color) . += "-[draw_color]" - for(var/obj/item/organ/O as anything in cosmetic_organs) + for(var/obj/item/organ/O as anything in contained_organs) + if(!O.visual) + continue . += "-[json_encode(O.build_cache_key())]" for(var/datum/appearance_modifier/mod as anything in appearance_mods) diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index c6bcec35e047..800768971a2e 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -23,13 +23,11 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC - change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" - bodypart_flags = STOCK_BP_FLAGS_ARMS & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) + armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 5, ACID = 10) - brute_reduction = 5 - burn_reduction = 4 + bodypart_flags = STOCK_BP_FLAGS_ARMS & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -52,13 +50,11 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC - change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" - bodypart_flags = STOCK_BP_FLAGS_ARMS & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) + armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 5, ACID = 10) - brute_reduction = 5 - burn_reduction = 4 + bodypart_flags = STOCK_BP_FLAGS_ARMS & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -81,13 +77,11 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC - change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" - bodypart_flags = STOCK_BP_FLAGS_LEGS & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) + armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 5, ACID = 10) - brute_reduction = 5 - burn_reduction = 4 + bodypart_flags = STOCK_BP_FLAGS_LEGS & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -110,13 +104,11 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC - change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" - bodypart_flags = STOCK_BP_FLAGS_LEGS & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) + armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 5, ACID = 10) - brute_reduction = 5 - burn_reduction = 4 + bodypart_flags = STOCK_BP_FLAGS_LEGS & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -138,13 +130,11 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC - change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" - bodypart_flags = STOCK_BP_FLAGS_CHEST & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) + armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 5, ACID = 10) - brute_reduction = 5 - burn_reduction = 4 + bodypart_flags = STOCK_BP_FLAGS_CHEST & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -249,13 +239,11 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC - change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" - bodypart_flags = STOCK_BP_FLAGS_HEAD & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) + armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 5, ACID = 10) - brute_reduction = 5 - burn_reduction = 4 + bodypart_flags = STOCK_BP_FLAGS_HEAD & ~(BP_HAS_BLOOD|BP_HAS_BONES|BP_HAS_TENDON|BP_HAS_ARTERY) light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG @@ -346,32 +334,32 @@ name = "surplus prosthetic left arm" desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing." icon = 'icons/mob/augmentation/surplus_augments.dmi' - brute_reduction = 0 - burn_reduction = 0 + icon_static = 'icons/mob/augmentation/surplus_augments.dmi' + limb_id = "surplus" max_damage = 20 /obj/item/bodypart/arm/right/robot/surplus name = "surplus prosthetic right arm" desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing." icon = 'icons/mob/augmentation/surplus_augments.dmi' - brute_reduction = 0 - burn_reduction = 0 + icon_static = 'icons/mob/augmentation/surplus_augments.dmi' + limb_id = "surplus" max_damage = 20 /obj/item/bodypart/leg/left/robot/surplus name = "surplus prosthetic left leg" desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing." icon = 'icons/mob/augmentation/surplus_augments.dmi' - brute_reduction = 0 - burn_reduction = 0 + icon_static = 'icons/mob/augmentation/surplus_augments.dmi' + limb_id = "surplus" max_damage = 20 /obj/item/bodypart/leg/right/robot/surplus name = "surplus prosthetic right leg" desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing." icon = 'icons/mob/augmentation/surplus_augments.dmi' - brute_reduction = 0 - burn_reduction = 0 + icon_static = 'icons/mob/augmentation/surplus_augments.dmi' + limb_id = "surplus" max_damage = 20 diff --git a/code/modules/surgery/bodyparts/species_parts/skrell_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/skrell_bodyparts.dm deleted file mode 100644 index 14206d4ee823..000000000000 --- a/code/modules/surgery/bodyparts/species_parts/skrell_bodyparts.dm +++ /dev/null @@ -1,34 +0,0 @@ -/obj/item/bodypart/head/skrell - icon_greyscale = 'icons/mob/species/skrell/bodyparts.dmi' - limb_id = SPECIES_SKRELL - is_dimorphic = FALSE - should_draw_greyscale = TRUE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_SKRELL - - eyes_icon_file = 'icons/mob/species/skrell/eyes.dmi' - -/obj/item/bodypart/chest/skrell - icon_greyscale = 'icons/mob/species/skrell/bodyparts.dmi' - limb_id = SPECIES_SKRELL - should_draw_greyscale = TRUE - is_dimorphic = TRUE - -/obj/item/bodypart/arm/left/skrell - icon_greyscale = 'icons/mob/species/skrell/bodyparts.dmi' - limb_id = SPECIES_SKRELL - should_draw_greyscale = TRUE - -/obj/item/bodypart/arm/right/skrell - icon_greyscale = 'icons/mob/species/skrell/bodyparts.dmi' - limb_id = SPECIES_SKRELL - should_draw_greyscale = TRUE - -/obj/item/bodypart/leg/left/skrell - icon_greyscale = 'icons/mob/species/skrell/bodyparts.dmi' - limb_id = SPECIES_SKRELL - should_draw_greyscale = TRUE - -/obj/item/bodypart/leg/right/skrell - icon_greyscale = 'icons/mob/species/skrell/bodyparts.dmi' - limb_id = SPECIES_SKRELL - should_draw_greyscale = TRUE diff --git a/code/modules/surgery/bodyparts/species_parts/teshari_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/teshari_bodyparts.dm index ec3ae1766635..a47d3bdcb362 100644 --- a/code/modules/surgery/bodyparts/species_parts/teshari_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/teshari_bodyparts.dm @@ -44,6 +44,7 @@ unarmed_attack_sound = 'sound/weapons/slash.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' unarmed_damage_high = 6 + /obj/item/bodypart/leg/right/teshari icon_greyscale = 'icons/mob/species/teshari/bodyparts.dmi' icon_husk = 'icons/mob/species/teshari/bodyparts.dmi' @@ -59,3 +60,40 @@ limb_id = SPECIES_TESHARI should_draw_greyscale = TRUE bodytype = BODYTYPE_TESHARI | BODYTYPE_ORGANIC + +/////////////////////////////////////////////////////////// +/obj/item/bodypart/head/robot/surplus/teshari + icon = 'icons/mob/species/teshari/augments.dmi' + icon_static = 'icons/mob/species/teshari/augments.dmi' + limb_id = "robotesh" + bodytype = BODYTYPE_TESHARI | BODYTYPE_ROBOTIC + +/obj/item/bodypart/chest/robot/surplus/teshari + icon = 'icons/mob/species/teshari/augments.dmi' + icon_static = 'icons/mob/species/teshari/augments.dmi' + limb_id = "robotesh" + bodytype = BODYTYPE_TESHARI | BODYTYPE_ROBOTIC + +/obj/item/bodypart/arm/right/robot/surplus/teshari + icon = 'icons/mob/species/teshari/augments.dmi' + icon_static = 'icons/mob/species/teshari/augments.dmi' + limb_id = "robotesh" + bodytype = BODYTYPE_TESHARI | BODYTYPE_ROBOTIC + +/obj/item/bodypart/arm/left/robot/surplus/teshari + icon = 'icons/mob/species/teshari/augments.dmi' + icon_static = 'icons/mob/species/teshari/augments.dmi' + limb_id = "robotesh" + bodytype = BODYTYPE_TESHARI | BODYTYPE_ROBOTIC + +/obj/item/bodypart/leg/right/robot/surplus/teshari + icon = 'icons/mob/species/teshari/augments.dmi' + icon_static = 'icons/mob/species/teshari/augments.dmi' + limb_id = "robotesh" + bodytype = BODYTYPE_TESHARI | BODYTYPE_ROBOTIC + +/obj/item/bodypart/leg/left/robot/surplus/teshari + icon = 'icons/mob/species/teshari/augments.dmi' + icon_static = 'icons/mob/species/teshari/augments.dmi' + limb_id = "robotesh" + bodytype = BODYTYPE_TESHARI | BODYTYPE_ROBOTIC diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index 8af73511cd5a..863d1364a208 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -78,25 +78,16 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) Remove(owner, special=TRUE) if(ownerlimb) - remove_from_limb() + ownerlimb.remove_organ(src) if(!cosmetic_only) STOP_PROCESSING(SSobj, src) return ..() -/obj/item/organ/forceMove(atom/destination, check_dest = TRUE) - if(check_dest && destination) //Nullspace is always a valid location for organs. Because reasons. - if(organ_flags & ORGAN_UNREMOVABLE) //If this organ is unremovable, it should delete itself if it tries to be moved to anything besides a bodypart. - if(!istype(destination, /obj/item/bodypart) && !iscarbon(destination)) - stack_trace("Unremovable organ tried to be removed!") - qdel(src) - return //Don't move it out of nullspace if it's deleted. - return ..() - -/// A little hack to ensure old behavior for now. +/// A little hack to ensure old behavior. /obj/item/organ/ex_act(severity, target) - if(visual && ownerlimb) + if(ownerlimb) return return ..() @@ -112,10 +103,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) return FALSE var/obj/item/bodypart/limb - if(visual) - limb = reciever.get_bodypart(deprecise_zone(zone)) - if(!limb) - return FALSE + limb = reciever.get_bodypart(deprecise_zone(zone)) + if(!limb) + return FALSE var/obj/item/organ/replaced = reciever.getorganslot(slot) if(replaced) @@ -146,16 +136,16 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) /// Otherwise life processing breaks down sortTim(owner.processing_organs, GLOBAL_PROC_REF(cmp_organ_slot_asc)) - if(visual) //Brains are visual and I don't know why. Blame lemon. + if(ownerlimb) + ownerlimb.remove_organ(src) + limb.add_organ(src) + forceMove(limb) + + if(visual) if(!stored_feature_id && reciever.dna?.features) //We only want this set *once* stored_feature_id = reciever.dna.features[feature_key] reciever.cosmetic_organs.Add(src) - - if(ownerlimb) - remove_from_limb() - add_to_limb(limb) - reciever.update_body_parts() return TRUE @@ -175,6 +165,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) owner = null for(var/datum/action/action as anything in actions) action.Remove(organ_owner) + for(var/trait in organ_traits) REMOVE_TRAIT(organ_owner, trait, REF(src)) @@ -191,10 +182,11 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) organ_owner.processing_organs -= src START_PROCESSING(SSobj, src) + if(ownerlimb) + ownerlimb.remove_organ(src) + if(visual) organ_owner.cosmetic_organs.Remove(src) - if(ownerlimb) - remove_from_limb() organ_owner.update_body_parts() /// Updates the traits of the organ on the specific organ it is called on. Should be called anytime an organ is given a trait while it is already in a body. diff --git a/code/modules/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm index 91b1c6492271..1a0bfd8d815c 100644 --- a/code/modules/surgery/organs/ears.dm +++ b/code/modules/surgery/organs/ears.dm @@ -67,23 +67,25 @@ visual = TRUE damage_multiplier = 2 -/obj/item/organ/ears/cat/Insert(mob/living/carbon/human/ear_owner, special = 0, drop_if_replaced = TRUE) + dna_block = DNA_EARS_BLOCK + feature_key = "ears" + layers = list(BODY_FRONT_LAYER, BODY_BEHIND_LAYER) + color_source = ORGAN_COLOR_HAIR + +/obj/item/organ/ears/cat/can_draw_on_bodypart(mob/living/carbon/human/human) . = ..() - if(!.) - return + if(human.head && (human.head.flags_inv & HIDEHAIR) || (human.wear_mask && (human.wear_mask.flags_inv & HIDEHAIR))) + return FALSE - if(istype(ear_owner)) - color = ear_owner.hair_color - ear_owner.dna.features["ears"] = ear_owner.dna.species.mutant_bodyparts["ears"] = "Cat" - ear_owner.dna.update_uf_block(DNA_EARS_BLOCK) - ear_owner.update_body() +/obj/item/organ/ears/cat/get_global_feature_list() + return GLOB.ears_list + +/obj/item/organ/ears/cat/build_overlays(physique, image_dir) + . = ..() + if(sprite_datum.hasinner) + for(var/image_layer in layers) + . += image(sprite_datum.icon, "m_earsinner_[sprite_datum.icon_state]_[global.layer2text["[image_layer]"]]", layer = -image_layer) -/obj/item/organ/ears/cat/Remove(mob/living/carbon/human/ear_owner, special = 0) - ..() - if(istype(ear_owner)) - color = ear_owner.hair_color - ear_owner.dna.species.mutant_bodyparts -= "ears" - ear_owner.update_body() /obj/item/organ/ears/penguin name = "penguin ears" diff --git a/code/modules/surgery/organs/external/_external_organs.dm b/code/modules/surgery/organs/external/_external_organs.dm index dec0d5f8dbf5..987711996ecf 100644 --- a/code/modules/surgery/organs/external/_external_organs.dm +++ b/code/modules/surgery/organs/external/_external_organs.dm @@ -210,31 +210,6 @@ var/list/rgb_list = rgb2num(rgb_value) return rgb(255 - rgb_list[1], 255 - rgb_list[2], 255 - rgb_list[3]) -//skrell -/obj/item/organ/headtails - ///Unremovable is until the features are completely finished - organ_flags = ORGAN_UNREMOVABLE | ORGAN_EDIBLE - visual = TRUE - cosmetic_only = TRUE - - zone = BODY_ZONE_HEAD - slot = ORGAN_SLOT_EXTERNAL_HEADTAILS - layers = list(BODY_FRONT_LAYER | BODY_ADJ_LAYER) - dna_block = DNA_HEADTAILS_BLOCK - - feature_key = "headtails" - preference = "feature_headtails" - -/obj/item/organ/headtails/can_draw_on_bodypart(mob/living/carbon/human/human) - . = TRUE - if(human.head && (human.head.flags_inv & HIDEHAIR)) - return FALSE - if(human.wear_mask && (human.wear_mask.flags_inv & HIDEHAIR)) - return FALSE - -/obj/item/organ/headtails/get_global_feature_list() - return GLOB.headtails_list - // Teshari head feathers /obj/item/organ/teshari_feathers name = "head feathers" @@ -347,6 +322,8 @@ var/state2use = build_icon_state(physique, image_layer) for(var/obj/item/bodypart/BP as anything in owner.bodyparts - owner.get_bodypart(BODY_ZONE_CHEST)) + if(!IS_ORGANIC_LIMB(BP)) + continue var/mutable_appearance/new_overlay = mutable_appearance(sprite_datum.icon, "[state2use]_[BP.body_zone]", layer = -image_layer) new_overlay.color = mutcolors[bodypart_color_indexes[BP.body_zone]] . += new_overlay @@ -354,11 +331,17 @@ /obj/item/organ/teshari_body_feathers/build_cache_key() . = ..() if(ishuman(owner)) - . += "[!!owner.get_bodypart(BODY_ZONE_CHEST)]" - . += "[!!owner.get_bodypart(BODY_ZONE_HEAD)]" - . += "[!!owner.get_bodypart(BODY_ZONE_L_ARM)]" - . += "[!!owner.get_bodypart(BODY_ZONE_R_ARM)]" - . += "[!!owner.get_bodypart(BODY_ZONE_L_LEG)]" - . += "[!!owner.get_bodypart(BODY_ZONE_R_LEG)]" + var/obj/item/bodypart/BP = owner.get_bodypart(BODY_ZONE_CHEST) + . += BP ? "[IS_ORGANIC_LIMB(BP)]" : "NOAPPLY" + BP = owner.get_bodypart(BODY_ZONE_HEAD) + . += BP ? "[IS_ORGANIC_LIMB(BP)]" : "NOAPPLY" + BP = owner.get_bodypart(BODY_ZONE_R_ARM) + . += BP ? "[IS_ORGANIC_LIMB(BP)]" : "NOAPPLY" + BP = owner.get_bodypart(BODY_ZONE_L_ARM) + . += BP ? "[IS_ORGANIC_LIMB(BP)]" : "NOAPPLY" + BP = owner.get_bodypart(BODY_ZONE_R_LEG) + . += BP ? "[IS_ORGANIC_LIMB(BP)]" : "NOAPPLY" + BP = owner.get_bodypart(BODY_ZONE_L_LEG) + . += BP ? "[IS_ORGANIC_LIMB(BP)]" : "NOAPPLY" else . += "CHEST_ONLY" diff --git a/code/modules/surgery/organs/external/skrell_headtails.dm b/code/modules/surgery/organs/external/skrell_headtails.dm deleted file mode 100644 index 8c62111d6224..000000000000 --- a/code/modules/surgery/organs/external/skrell_headtails.dm +++ /dev/null @@ -1,24 +0,0 @@ -/obj/item/organ/skrell_headtails - ///Unremovable is until the features are completely finished - organ_flags = ORGAN_UNREMOVABLE | ORGAN_EDIBLE - visual = TRUE - cosmetic_only = TRUE - - zone = BODY_ZONE_HEAD - slot = ORGAN_SLOT_EXTERNAL_HEADTAILS - layers = list(BODY_FRONT_LAYER, BODY_ADJ_LAYER) - - dna_block = DNA_HEADTAILS_BLOCK - - feature_key = "headtails" - preference = "feature_headtails" - - color_source = ORGAN_COLOR_HAIR - -/obj/item/organ/skrell_headtails/can_draw_on_bodypart(mob/living/carbon/human/human) - if(!(human.head?.flags_inv & HIDEHAIR) || (human.wear_mask?.flags_inv & HIDEHAIR)) - return TRUE - return FALSE - -/obj/item/organ/skrell_headtails/get_global_feature_list() - return GLOB.headtails_list diff --git a/code/modules/surgery/organs/external/snouts.dm b/code/modules/surgery/organs/external/snouts.dm index 8d52ccee7586..45c457ac9728 100644 --- a/code/modules/surgery/organs/external/snouts.dm +++ b/code/modules/surgery/organs/external/snouts.dm @@ -27,6 +27,7 @@ /obj/item/organ/snout/vox name = "beak" feature_key = "vox_snout" + preference = null external_bodytypes = BODYTYPE_VOX_BEAK dna_block = DNA_VOX_SNOUT_BLOCK diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index 076fa562ee32..4f7a0fac0b88 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -15,8 +15,7 @@ feature_key = "tail" render_key = "tail" dna_block = DNA_TAIL_BLOCK - ///Does this tail have a wagging sprite, and is it currently wagging? - var/wag_flags = NONE + ///The original owner of this tail var/original_owner //Yay, snowflake code! @@ -32,7 +31,6 @@ /obj/item/organ/tail/Insert(mob/living/carbon/reciever, special, drop_if_replaced) . = ..() if(.) - RegisterSignal(reciever, COMSIG_ORGAN_WAG_TAIL, PROC_REF(wag)) original_owner ||= reciever //One and done SEND_SIGNAL(reciever, COMSIG_CLEAR_MOOD_EVENT, "tail_lost") @@ -44,44 +42,20 @@ SEND_SIGNAL(reciever, COMSIG_ADD_MOOD_EVENT, "wrong_tail_regained", /datum/mood_event/tail_regained_wrong) /obj/item/organ/tail/Remove(mob/living/carbon/organ_owner, special, moving) - if(wag_flags & WAG_WAGGING) - wag(FALSE) . = ..() - UnregisterSignal(organ_owner, COMSIG_ORGAN_WAG_TAIL) if(type in organ_owner.dna.species.cosmetic_organs) SEND_SIGNAL(organ_owner, COMSIG_ADD_MOOD_EVENT, "tail_lost", /datum/mood_event/tail_lost) SEND_SIGNAL(organ_owner, COMSIG_ADD_MOOD_EVENT, "tail_balance_lost", /datum/mood_event/tail_balance_lost) -/obj/item/organ/tail/build_cache_key() - . = ..() - if((wag_flags & WAG_WAGGING)) - . += "wagging" - return . - /obj/item/organ/tail/get_global_feature_list() return GLOB.tails_list -/obj/item/organ/tail/proc/wag(mob/user, start = TRUE, stop_after = 0) - if(!(wag_flags & WAG_ABLE)) - return - - if(start) - render_key = "wagging[initial(render_key)]" - wag_flags |= WAG_WAGGING - if(stop_after) - addtimer(CALLBACK(src, PROC_REF(wag), FALSE), stop_after, TIMER_STOPPABLE|TIMER_DELETE_ME) - else - render_key = initial(render_key) - wag_flags &= ~WAG_WAGGING - owner.update_body_parts() - /obj/item/organ/tail/cat name = "tail" preference = "feature_human_tail" feature_key = "tail_cat" color_source = ORGAN_COLOR_HAIR - wag_flags = WAG_ABLE /obj/item/organ/tail/monkey color_source = NONE @@ -91,8 +65,8 @@ desc = "A severed lizard tail. Somewhere, no doubt, a lizard hater is very pleased with themselves." preference = "feature_lizard_tail" feature_key = "tail_lizard" - wag_flags = WAG_ABLE dna_block = DNA_LIZARD_TAIL_BLOCK + ///A reference to the paired_spines, since for some fucking reason tail spines are tied to the spines themselves. var/obj/item/organ/spines/paired_spines @@ -115,25 +89,6 @@ if(paired_spines) paired_spines.paired_tail = src -/obj/item/organ/tail/lizard/wag(mob/user, start = TRUE, stop_after = 0) - if(!(wag_flags & WAG_ABLE)) - return - - if(start) - render_key = "wagging[initial(render_key)]" - wag_flags |= WAG_WAGGING - if(stop_after) - addtimer(CALLBACK(src, PROC_REF(wag), FALSE), stop_after, TIMER_STOPPABLE|TIMER_DELETE_ME) - if(paired_spines) - paired_spines.render_key = "wagging[initial(paired_spines.render_key)]" - else - render_key = initial(render_key) - wag_flags &= ~WAG_WAGGING - if(paired_spines) - paired_spines.render_key = initial(paired_spines.render_key) - - owner.update_body_parts() - /obj/item/organ/tail/lizard/fake name = "fabricated lizard tail" desc = "A fabricated severed lizard tail. This one's made of synthflesh. Probably not usable for lizard wine." @@ -177,10 +132,8 @@ // Vox tail /obj/item/organ/tail/vox - wag_flags = WAG_ABLE - feature_key = "tail_vox" - preference = "tail_vox" + preference = null render_key = "tail_vox" dna_block = DNA_VOX_TAIL_BLOCK diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index ad204a107a58..b82f565b5637 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -224,6 +224,15 @@ status = ORGAN_ROBOTIC organ_flags = ORGAN_SYNTHETIC + ///Incase the eyes are removed before the timer expires + var/emp_timer + +/obj/item/organ/eyes/robotic/Remove(mob/living/carbon/eye_owner, special) + if(emp_timer) + deltimer(emp_timer) + remove_malfunction() + ..() + /obj/item/organ/eyes/robotic/emp_act(severity) . = ..() if(!owner || . & EMP_PROTECT_SELF) @@ -232,6 +241,12 @@ return to_chat(owner, span_warning("Static obfuscates your vision!")) owner.flash_act(visual = 1) + owner.add_client_colour(/datum/client_colour/malfunction) + emp_timer = addtimer(CALLBACK(src, PROC_REF(remove_malfunction)), 10 SECONDS, TIMER_STOPPABLE) + +/obj/item/organ/eyes/robotic/proc/remove_malfunction() + owner.remove_client_colour(/datum/client_colour/malfunction) + emp_timer = null /obj/item/organ/eyes/robotic/basic name = "basic robotic eyes" @@ -542,12 +557,6 @@ eye_icon_state = "flyeyes" icon_state = "eyeballs-fly" -/obj/item/organ/eyes/skrell - name = "amphibian eyes" - desc = "Large black orbs." - eye_icon_state = "skrelleyes" - icon_state = "eyeballs-skrell" - /obj/item/organ/eyes/fly/Insert(mob/living/carbon/eye_owner, special = FALSE) . = ..() if(!.) diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 75d594fe0840..7169dce2d046 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -98,11 +98,6 @@ /obj/item/organ/heart/get_availability(datum/species/owner_species) return !(NOBLOOD in owner_species.species_traits) -/obj/item/organ/heart/skrell - name = "skrell heart" - icon_state = "heart-skrell-on" - base_icon_state = "heart-skrell" - /obj/item/organ/heart/cursed name = "cursed heart" desc = "A heart that, when inserted, will force you to pump it manually." diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm index cde1a39f8ae3..d2133ceea34b 100755 --- a/code/modules/surgery/organs/liver.dm +++ b/code/modules/surgery/organs/liver.dm @@ -220,13 +220,6 @@ icon_state = "vox-liver" alcohol_tolerance = 0.008 // 60% more toxic -/obj/item/organ/liver/skrell - name = "skrell liver" - icon_state = "liver-skrell" - alcohol_tolerance = 5 - toxTolerance = 10 //can shrug off up to 10u of toxins. - toxLethality = 0.8 * LIVER_DEFAULT_TOX_LETHALITY //20% less damage than a normal liver - /obj/item/organ/liver/cybernetic name = "basic cybernetic liver" icon_state = "liver-c" diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 3bf2980055c8..884582646fcf 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -381,28 +381,6 @@ var/plasma_pp = breath.getBreathPartialPressure(breath.getGroupGas(GAS_PLASMA)) owner.blood_volume += (0.2 * plasma_pp) // 10/s when breathing literally nothing but plasma, which will suffocate you. -/obj/item/organ/lungs/skrell - name = "skrell lungs" - icon_state = "lungs-skrell" - safe_plasma_max = 40 - safe_co2_max = 40 - - cold_level_1_threshold = 248 - cold_level_2_threshold = 220 - cold_level_3_threshold = 170 - cold_level_1_damage = COLD_GAS_DAMAGE_LEVEL_2 //Keep in mind with gas damage levels, you can set these to be negative, if you want someone to heal, instead. - cold_level_2_damage = COLD_GAS_DAMAGE_LEVEL_2 - cold_level_3_damage = COLD_GAS_DAMAGE_LEVEL_3 - cold_damage_type = BRUTE - - heat_level_1_threshold = 318 - heat_level_2_threshold = 348 - heat_level_3_threshold = 1000 - heat_level_1_damage = HEAT_GAS_DAMAGE_LEVEL_2 - heat_level_2_damage = HEAT_GAS_DAMAGE_LEVEL_2 - heat_level_3_damage = HEAT_GAS_DAMAGE_LEVEL_3 - heat_damage_type = BURN - /obj/item/organ/lungs/teshari name = "teshari lungs" diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index c1eaf3ee9cbe..e5a21dc5348d 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -31,7 +31,6 @@ /datum/language/shadowtongue, /datum/language/terrum, /datum/language/nekomimetic, - /datum/language/skrell, /datum/language/schechi, /datum/language/vox, )) @@ -325,12 +324,6 @@ /obj/item/organ/tongue/alien/modify_speech(datum/source, list/speech_args) playsound(owner, SFX_HISS, 25, TRUE, TRUE) -/obj/item/organ/tongue/skrell - name = "internal vocal sacs" - desc = "A strange looking sac." - icon_state = "tongue-skrell" - taste_sensitivity = 5 - /obj/item/organ/tongue/bone name = "bone \"tongue\"" desc = "Apparently skeletons alter the sounds they produce through oscillation of their teeth, hence their characteristic rattling." diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png index 29ce88f47e59c35374ddef2be96f3de88d4d4318..0fd38022ae7954107be1e4b0cd708ed8322aa2c8 100644 GIT binary patch literal 2996 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 KMNUMnLSTXeFaq5G diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_pod.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_pod.png index f77e21d1f523c9ac4aa38c15c1a1c099dba5baa9..461b22135699fa5ee93f462a34c8e5887ee4ac5d 100644 GIT binary patch delta 961 zcmV;y13vua3Bd`FBt*1OOjJd{z`%z9s@(v}wE(*SmjD3Z008*_0LK9R0LRAw#{jqh z0OSCazqSAX0Evl-0MP&djR3H)umFVsXlQ7Tkdu*I908}1e^>-?8nT>`+kt;dNkllW%>XAt9KNZo>(I|l!rcabO^_}qt92e z;u#@6HoRWkNY0(P3{O(@`o1j7`jx8OD%XMlzP8G)+fx z%mB7zo^5Bj+~RJqlcu{EsSJPK0{%11-_Ej~u!Us2H%a{nTOb34AA5|2=|D~>unA#{ zLs?`PaySj@BAF&ckleGz_a*LMA}=My2M3v1v&nZ_tMFadvn!3NB<|6}xq z99VMD^fO4;wcmqU2Xr{J0((FJSNW^H{<4ICE*jhX0idhC{tD>p0w=6^0Tj5})aPa4 zo&c^W=bO5~ce%4lHA-2RBYRUXvbl3Lg>!SZo#G4(X!ja85b}^m)%A z2qjjgl!1eWE*M>LIt72u3LT{2IeU*z&)VWHfm8Af@Ol)`h|nQ<0l<9|I0OF>;EjYg z0S#jP@iG1Q_++sVi^a+DF{3XRr{Z+6Wc0K1i^~%LPA)Ib&w~1L;Q@Qnv3_!YXLc;FG$%KE(dt^T9Kh@rFbw+3i@wE%1a2+^N{Kg_ZD{{aMOti6i??yP0o0}9_9-1GYVx`&7Wd~@)?$q!FG j1Rv|>;E|Ib1I@#4x3*}ftxHNt00000NkvXXu0mjfqfNTC delta 998 zcmVl?;y33I^!ah(pqP91Z$c0kWx_&$t8w(Lk=lj8#C-8;X#0j$>|2aw1-}Nj83J@CWmTz4Nlq8RBLnMee{Ye2X8_(hSvln@l!4c4 z${gOiS$tfC&s#{L;VJzyRl9HG62T9XckTL z3TSY*t*_c9J_BOYuC{f7&z3P*TU#6A65iW-vslGglEt{fYTJNzxonS$SbQqt=Oelq zWw;`p4Ek!6e<27hc4nwU7v}w^=U#szqq_Q0pR57^5UG;PuBxr zeah)Y?r_7Ms|)N;F>-2%-(rRdE}D4B8fLot*gADcWlo=76@vgWLv)e;9j6i-vmNiU+K&Z*H!e1>E{LiYEm6 z{<68f{r)MH!QIWxU4!Z4hzl1q2er*I*S_z5{JdK>?RY?XBV^mZ_ywa8An5=?_Ny=) z=3M-L00HU{?sI_q5R&5o*)SYDr1gi*43Pm0!@*-pete!G(zY26o>KA?Gd%nTDBD>2 U5Qi4`7ytkO07*qoM6N<$f}ilvkN^Mx diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_teshari.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_teshari.png index 497cca72afa079ae9e99d0b9f1238d98e57ca953..4a8dea92d58724cd4a79af0c3c19c744e54541d2 100644 GIT binary patch delta 959 zcmV;w13>)V2%ZU$Br&c~OjJd{z`y_i007(o0L%aYwEzH%0F=MB0FnRz{Q!xHiLkJ+ z0HXi^$p8S)007{TLp}a@sHug(ZRmi7`kP@)cnd3*tb4 zlt3@<|6*M^HZ&8h=%mv>o$e%J#^>y(we0aOA^%)Z`j-Jtof_RZ5YsiC&>n4~hXJnW zq<8aXxaoaPC;iUQw-<2H?IqB@_h#_yh7NFx0tUBqNa4@(?1p~70o?WNe-*+B-}`hl zqW%DRR&?-I;XV2kXh6qfSg@zi<)iNcCBbA8ppO{@pHd&!31K`4I78)-aUnPh@%*Xe zTuxDf2t^dZf&=1&%Opkt(=^JmD4nAD`7GfondJz9iFul3>0DqtumUPblDI$tK!AJ) zU?u@DLjh$uhbT)-&x=@ce<|a_eh(}cX}MUGsj%x0LzV+T$v9`jhmU$SWO1BooyIX6 zRyM$L#rQOiA30ksEdZlWW3A&yyH2Wrgkh)@EF`e((CDhJ6`~sl9DoUq=}JnirBrqu z0v>^sNx~7CDD|ZElTw%t0P`w40EtveCN2PP7Yv}<1tmyAB${uMe+hBrleMW}jq4lG z)*A<4^GwLI!>~5GV}tGXvVKPYAMJPl^QN|KTpch_SJU{f5!(5{X6hQZlVH@gM6 zorH_yqlvx^K(_h*Yh4WYsM zZGPQJ`d|>{5&%iELh^xdIv!6j0jOnZ(!2c|LVYO9vZ{cvs#ew;Fmd|&?F9K%1?EGo z-)XhhZ~+PkNhLlCe}@1IY^Zf@btp68p!pC+ceHmUl}r8&i&`s3^ELqn*A~y4A7(`O h1H*Q^cC~+t{1ekXOPYv`1|a|d002ovPDHLkV1hR)x5xkh delta 913 zcmV;C18)4D3El{hBp;|yOjJd{z`y_i0F=MB0Q~@oiHWeVumGa~0N?-s&yiI=RP_J= zrvLzz006!K0K@=FN=g8Y00930CnqO4IXN^mG#nfp0LcIVuK-R?P8k^)T3T8lARqv= z0GODV)z#Gip8$r2hE!Bkv9YmgYHBGdDPD4;K9Spie**JKL_t(oh3%GWSK=@bhEtIe zl7=+BkhVw-R*;(_vX}q=&vsG^>TV`@*^kb_;ORT>Gn2q!LdbW#jv#pZ{&79{>z|M5 z_IW_s7Ygv|t#FLb=wAnrcj_0oei8Hn`|@{iiEp7F+Jx}j7W%#x2ZOU)K>ap_4u=$% ziSLBke_)(a&QLjGTnNr0+&_|>%MnTtk%(hhaDYm=`KpsEUps>1ZVRFX@nO7|XEF4Af;sZ!zAucj;q zfR-v})2n~=`kE<~8j~u;u4@-yHf4OI)D36Tf0+YtHJ!1MGDh97nX3S)=`4yOtznr_ zM}=0`O`{RrX21d1;FzwZG)7A8)*;{{kTOX)A``7|jk(nt(*a<=${s)>wU&twz`F$l z=x#v?k`Rgdt(g#?pUiCsb6j75HeYxEi#tN@JPC8FdkQRz=NICk+t}ESigb)U26tNYp-QUFee{sKm zj9|cqoxeFsW@i!A8URW1g!qAQ*zXT;1JG;x$?uN!TSBv|s;aJm@KirJH(=xN%swo`53>x&00000NkvXXu0mjfH7TOG diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vox.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vox.png index ca41a653a1d128f617e9d8941906e91b8c94fd42..896167f6eaf54c8ff7ad1c8aefe5ffe0df563eb9 100644 GIT binary patch delta 1086 zcmV-E1i|~+3hN4xEgb*=0Js1EtpJq2wuy;}w3j=uu&~dqL;!LC0E+;TO<)25d6BF- z1g9SQSdr?1f9pv^K~z|Uot6t*;y4tB)1n|qdI>Qz(wlCylmSO*?da^f`~QE|emNk+ zB`H3hK3v-GJ8zQH!U<#h;nCraZXMbt9G-JJ`_R2F>fU~QLEkw1p5Li==U*Vd=Op|| zzi<&Qk>4jm_Y5u_MHoQq_xqn%!oUvj2AIGVrZ7AMe;BxK(+K%jAdDRPx!cUHy)o3W zckR?Y&bjB-gU}majlD3iJFa=iqbS0=gAfL>!1y8#LWjpgDwNz!ExOcxk!xwu*~9d~+-WI=c?;?M zR2MV@VbR$m4gfH^5C&k*Pjvv0FDyEp!Vs!le}$XJ5(+a|=MW-Nu{s5eYnSTy_ z>d*~ZS*8`0Z@UGm7(=PHGo3TW^6XA5(hw6RRsgy9eOb7ES+)Vd9IX!tJgRGj zRJAq+7ocg@3K&(_(S9AZ)>J|zGPN1O4am64grYKP^B+z5d7f`-VDH2$WFJSIZgW@ZMK-y+T67b0s@%8zrCX9xvR(EHbQo1~ekp%d`>`YTJ5 z7AuHj8ok&7@*s}mG)de0@3-Hiogm*{U*B4oU=8ve0RPlPC~%}$10EFh+dhN0zyARs zC9B@0ZbNHaerO+%pQ#r+;1&T3e~ceD;2>~Y9A?Rs9t~hYC8Re000002uVdwM6N<$ Ef+pbyw*UYD delta 1067 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%0A6g$$AJbuh2K0(<5BT3x>& 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 Z`~|yu6!#Cfg%JP%002ovPDHLkV1g)9?GgY0 diff --git a/icons/mob/mutant_bodyparts.dmi b/icons/mob/mutant_bodyparts.dmi index d86e51bae0f771faa42ae3ab185f7f44887f9469..dd3a55467798b2377f02b1e41e1ac05803b9b347 100644 GIT binary patch literal 10838 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 kOVg3Q9+M4OliHB1lI{R6wOS=_Q~b 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 UvpV<=F!eEby85}Sb4q9e0M#f4@c;k- diff --git a/icons/mob/species/skrell/skrell_headtails.dmi b/icons/mob/species/skrell/skrell_headtails.dmi deleted file mode 100644 index 2d9941500c6b18127c13fbe300a3a62d8a3176df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 625 zcmV-%0*?KOP)Ujt)U~y>^v+EG00001bW%=J06^y0W&i*Hj(SvBbVOxyV{&P5 zbZKvH004NLQ&wtNt%i?@{3ByuneLPk8R2du6{1ypa1}hhEqicYUe`$00C`DL_t(&f$f+2aKLL?4`JD}C zVD;`c^jOyHgu{UxfFNL3aDj>ZV3?pz3m!FevB2uE7z^5cfhsi&v7p!BXq^#&S_>3i z$O)F4hy;#pYo+$TgwLDc2LwS7ehJjc8u&h20JJSewW(>X&_v~Gp|Duc&Qy3)kMw81 zG`uqzNB2#;e746ANIB-FaXCmN_(BPA20{#vn0SBIgpz^!>S>O$?b2a~5psEkSk@g3w(vZI_ ztq=r35QO`M|3COXH<=$K(>s0J;6;ZAu6y=6PaWSvvo00000 LNkvXXu0mjfmSq!% diff --git a/icons/mob/species/teshari/augments.dmi b/icons/mob/species/teshari/augments.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b0c0ce1824129f7265b5902d3bdd8d3ce1b9bfd5 GIT binary patch literal 3410 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 literal 0 HcmV?d00001