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) + . += {" +
" + + // Special handling for implants :) + if(!length(get_species_augments(prefs.read_preference(/datum/preference/choiced/species))?[AUGMENT_CATEGORY_IMPLANTS]?[AUGMENT_SLOT_IMPLANTS])) + return + + . += {" + " 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 zcmV;l3rqBgP)MOhW9a<;>N ztO!d#f0yS1QozLD--|=ve}|LDj$`0ZFW>LP2vl0P;lz_7s7~d&Pj{ft6SK^h1Qt(H zZ|I$bv{Bl}RV|yxBmbQh_~P3$@IJCAWQ?3ho#q1B6GRS>zt{^$zAWp$ssDA@xqm;3 z8Oe08RcyA?fhAu-J_3p$B^+bPcpMu@7hP6V1R6^yKUayCHCa&9T=-qgsT6W7X5}g+ zVp2d9Dytdsm9?m@u7-bPC)B>UBY6DkstTMqupgbT=^1PjWRoW0RVRRp0E$cT^f)%+0St-;PQNnIr2ybf^a;nE^ z*H`$vkaN3>3X9OMTQ|&j<}bW+?FXxsDfj%ATLqDx+BFp$wtR}1@+#g(?WCw@|NN9n zV|!hd#-3Cw(NOz2YNBFU;%#6X8?KN7SU75M!C&7T6*X0;t*c{OE&TLaL7D)Umz~3| zy}MA)@<*qud*Eo{_c(j*ELtSA2r5C4zhn0foH$tZ9?_$b@uFGQ8!gD6IRl)Hf|L2+rGt=79x(J%ltwKaS>ffmwKMs#d) z5;HGtyl=rPN?yif)$gxI!JYz^O;l7>RiUh+482o(@vuZVUUJg(eu?~l`ombHbV>@g z#V588mX#&icv1q@-?34G@nP(Irl@k*(dPe!ma?4HoKiMBS(B#-B@nrP%lo@>pYK;H zO2PMqR|pxJ1&wcU6&}lcOnLeFG3xX&oe>@1fan+%?r27Eyp{(V;6aJ* z^(;iW*(_;E?h4(r04X8=(J75{XEv|uaZNMqD%_3gx( 1Q 1NvAp^Kh-gv*L6C0*g`Y1zS{JOp^V$mT2_hU( zNp)%$AbA=m>gN;Z&Bh2Xu(Eu!-!|}6IAig=U?YVau}`Fn&|~bA#}KB?`wX#c?&^te zg=l8wZZ_XnJZVtkdNGgCJjGvIhsyGDy!7UL$2Uq!AmRo2M(a=Qn1p^er(x&+ZV!eY zB3OhYDydHG)K79GPvc}n`Xp=xPH=#HrFUV-ld)0Wb~ThNUMAfM7Cx^n+RdJtfil0B z&1@97J#Nfi{1WeXV);K7WZgt?$~{jj2i82H79BBv1|USTpk@ZMwIFZX394P#kzuQV zaKF*DgK_2aLJ)txIA0|+#d36$|32UfB7^Nulzj8<)P5#3b=@Uvy>{5gJh*$ngXR67 z65)PyZj30F3h*tzQ 0OR>qTZtGZ$1C&6oU z{3E>!sf4`rbWVJ=q3&C`vPsVGL{T|8IXX)oKYqNeJds~>;AP-w43N=XEpX;MWjS&+XV($`m0j?RXDePD SYy0cy+2%2L^8O9m0$wX3$4PQ(*L zy|A#*R0$&F$V3~%&;?NjS-dCk8w&b>_}WfkhgjwSMNv%m!-0qw {NRI-KG7DD5(MZ9dL)~6g+2!ea%Zw~M cpuyCWx0pXO>l%eG%uNVJjPy)3%LN%LW79MBer*mT)c|-F!Q}IRxh?$OT-DXqJ z!=dkE1+ufV6)OvuW$gM1GWi7BccKJ>9A+Y&|IeB=OA!`sML5Y=9-tlLW-259Md>9L zeX8^AA)sFh@MIC2p6cn*Eyn2*F)89)U>4LeN=N)p^+YT}i`8r=T)%)_taqXit1x3r zJ_1V-`xgRxq#u&gyuYLZXq5n@l|xC+(5(lBtcL28a3)Yn)6k2tCUib9Q^KXV7-#=J z;Ag%X`g4HoVw@H6-hh_#FXGDM<%0A6g$$AJbuh2K0(< 5BT3x>& z|Hqu;a)+%43`<@UV&QgHU$bXgZuhI(XAMg0oYlWi$E?Jb&GM+NDK7MKg{21!OMXvP za_7N|x$3 $4QAr6_i8p1)d`@r_GUy4$C)z72s`Fw!(Y~`+lwb j4D!!6$NKV&n4a;mL}Pi_dboW3!H*uJ-l3rY)K$ct{BjpXYx$F!g}( zi)q~=9mTP2v3SVKyv_TaPtEUXJ?#`BX#c?y-{3K?=Lg94(PGBY6XiaZ4}9#YJd0JY zc!31V5Jcn?8dNt@j(i{XKq3USxn4`gojWG^k`m)^AU$OVK_vx3hkMmc>tdOG?V~$|`|x_8iFyH0O~=e7X7|Z$(vo z-t~R1C_zSu0*L(kyX0bcm+k0$xCl7xjC{hzO+`LdWHG{LktfI?C9p!-#6s23LCIH? z5P(hrFRuSaeSF9<4C~$v1qF%NR1$-ZH;i?>+(5*Klc7-c<(HYc*QB)cmHjY%rgHUj zVaHs~2rkA^=y4^q#3{cAkB{iD?BBdW-L-8i?;D-*A5FgIbNcIPGuvE0=NC;rLAM&p wJ%Eva@h<0=2i qA5I~R95XD0x_J12gw%f6qF1Q)U78^fGwNXN0-NfEgY@`;RfZz4L3O|ih02#Ea9 z;=0Cibt>PU$n2lb3nz>?w55WMibxXYpD=ziToNJ{%js6yjb{IAlCfMzigbDL40lc> z9bYU*3B^pa@9`k0s;DpfRrq+A>=QxEsQo&)-9Vjb-%iDKcJ7m>7Qsf (f)- gvGM%==y^Oz!^Z4tn)mpfNg-h#i1*{0D)s+mW2oM& z1s1*%H=11M-fg_-T1@^tF>c`I;xIfgc6Y4@e;lG|tSCI !Hj#$5w$|DN~tL zl1Q63vKE?_BWjaF{ioKHm*w>S<^t}z-VG{GqU6$v@=kS``d6{s)ze{VD&w;~bV3rB zSaF~{!iQA|8ZI}s_}^Q!G5vtcD!EQloqRFKYt}GksFYF7BsNd3Gj+?ypN$HfGg!`Q zhm{UrJnDyu+1H+O=~V4);awiR*~o(Hya0E5S<|N*D|}GH^A&j-R^TFq`vBixm!@r$ z?|b0VeSL;9ZR`76V>GiIxL8K)h1~BKl#Z0U2y>~-kdZ&fp`Gg=@nY10IkwfI%% z$;+Q6{hgjJVBj@uu1aBN`BdKD-OKi>1M0m_jXL`ibQc{)=ut-iyc+CU5%l|xnEa%9 zNQ6D*a9}?xq}VrmbFw#w`xI*0X_Ls*(qr7#7nm#6NBVN+SBn3(tvoAD{9RhM@#yFT z&tL$}1pPN<4Xb{6`C!mBAt51XYpgxVZ^el`TKdLvDQ%#fF>d-G0B?W!6y57>;EEmq z-Pb#}*ewWo_!j)Gm9S3VIy@{PizA8s*s;ok1hI?W`MVZDRaLZp1qAu}*xhfGNZAx! z=rw<$JzS`zzC8LqKStvAFBI+{_!}#@t(YiyD$!T?^5^FdgtBP-vdG%G@l=l&RNtEf zTz>M(eS
2uW|#-n8orDm=tg!J#HHoDLvZ0(@Oc?5pyMr>?6^hUXlva zcMW9p;`<+jnYc; lFmJj@emPX|B_X}Qc$?)NME&S8-4F*F0A+TQ+q5$OXD(&+ o<+rk_&1=%bm~Du+DDa{iE8QQpRS(+r z_Zku}y}zT*9nNrV$ba*UkkLYJ88Q`>#?@!j4fQX+BS`==gO;djIK-|628KyVrz?(A z$kPm 1{y3Lq|kJ{Elz3pYmqEKe!qTX_z**?G!ZL zTOQYwU`g{S ^>gm_u_BgZ*O^hOFkdr@=m~tTCcQyi;5+qZPm^CkE;!e|1Opjky2~ zu8c8u<_pa4ln1(rkYUuynM_ET!!h4Bmn~!s +>Y!I+8K3Y6{an`43hhvwnzW{?xFaOWuKdG;<%v&fq%{?0^|;sUgt zs4rhItwx}%7AvivLEB%xe5s`fg{u!s_}_7Msj|)NIDD&sODJ6T=w6*2yhIR2cv4T} zUg@n4Az%Wk4F1iA-2Tnk=w91QN0?ca5QE&L8UeFS`8Gt?^3v^7p7dHH;W$i-;;i%h z4dqLpIW0?<$m-cJ(U?4>WazJTPezOB0)EiNsc7&sF}VTx@2Wakv}w8HtK>K5{Tut^ z?Uo#>lkJ)8j~ln5BCyGR6ih)$X}zM&Gw^a{Z+L-7PpmZZcg(Cb*g0x D4ZoT%hQPY(y^ `xE&!oO&GH4)_Z)i&cT8E2^DXj>oZMgn0Fx9R-#=ZD*c}a9L5%GAl zP#nQBJYB5cGhow^T*#pz%;}^+E`YTC!^`iABS1kL&K${{`#-HH{W7V25cdk$O8CuG z$gK31_@Ne>tf!I8Uv;G-3L)vQNQ>oFEzeV7v`wxrhtg|)U!FtOcK2qw2Joem!HJX+ zCKc`4aapSwpbuvId35WYDm#56l}OQ)h;u9I8XL+dU;b>ll;BnaU5*(e;0bffCjDX2 z!nyX)@qj-SV5!{6_JVn7u<7oD`Ok;a$RzAZ#kTK&MWQwKEuS$_4+`-cRv%cm{Kndo zEoE3i+K|Cq)2+LzuRKQRa~H(=`=lj9?wohuj);N&k&TT5w$Cvoi~1=^9f<1O4%x5l z|M@R @)_`TpR?vChf6zn(KFD2 zdX>sxUZMI<$9^-|xv;* f@zC3=QeU nEbuTY`Po*~6ufjP-bi&Yo|nFzVu?Na87r-e8RXg_~)*Izvj|XDCP&@Mtm47L;nu zPxI*Y1iNs82mPD?wab4@u)KMhN76qxPumgVF`y&jGeUIozMo^Il0MVF`F+7FA(7F= zyj?_C7|+m-h_HSF8csASz<(01IN>UlfY-9Z&-aCM`#E4cGZEEj*oGGGVK2|I)ADx_ ze1G0Oi)3c-D&QHwS~-?p{6ya7eah6ro7aojAa4!eFDYdeFzW@NMKV$>1aCEDUbBK{ zD-W;+a1VC=b%Hp48-!{FH(IA@&97$isnaJ@9Oo938Tx|HvAb}=WZD|k QrU?xr$N2BbROuoQgdoYTDb31{EaWx>FTN_+kf%Ce)K z%Ca#meApOgrExPJZamr?A{m?%6}=?b!x;i{_p9mtgN`G*JC2+hjnR6&%;;D`r+NvP zHb6odqqeibK*Sr78#NG|#b^ ddUI0dHm6eR_4jH~|sbw;4VM7MCZ@^V2nY-Ri;(wPY4M$dRk%<-P1#j2NjYAQjIa zX-!Kp1_p7XAYUxNLeDDQ97zl?pZ)(mY;{A3L*IeM+O!IX19Wd9YH{P6zBv>(xwyj! zG7;Omwyts)=wur-QDZ{f_Ws4}) Lp~4Wl!yZWOfjoQdq3q#w(q0VZoA zCD8RSd$ACuna}l1{a1I;M2B^BwuDU$Kv-Y@CwJzOy48h1c8l}<^3=!HDxvcS{oGee z<g*(<%NhJ-)tp&GHO!H>RqtxBpB9FWRK)|Fm6Z-MnFx8cC$q(7BAqZO-A2XaIrA z%T{^ljCo26>k~3jQ)FF&4Of8jo}hGF+bV)&Jc${DT?6&T(x|MK1#=ZOzD%X7`#}5b z_b$NB;hiGtJu4l=8=pZa?07rcIJ<^6aXN*umdU~=_F;@jouB%ZVMx9gR8t%?emWDQ zNKmk0cyyBK@IG|BsiZ-`>-jF{q`JOGf{EDN(uHR|X5lD}n0*`{dlp}|@>iv#RNG&> zhXvJLSou>^+p!lc^UZ3H>a31b p`cmx3v;GN9!0pF)+h8|Z z>EFaYSRNYu&WlHzyTL3$)o#^SiMp`>#O*x`Tb8;l?uj^=;Y0So<&WOOM&K> )!xbgSZ{)ktQdU>l+u9Xr1cXneU?v+#EBS3#if7yl%rJW0(2o}Ij zN~<32%uF5(QE@)NW?%@s3k>P$hrq%s)Xq6#P(A9)#3@->;J#t{7b9V|=aER!_RY6U zO}aR4z|4@2#^<*IDX-6XjjBFQu0&=EqRg%TdX;@Ew=J)^`En3@!2VK~KC7bUhDj&G zNnZFmc}q#~B%jrUkv|i+axxi^Qz<;O9`{NkWTF=pqGjeHN43kT^}p!!CTe87Gbml} z(1`2L-41J~^2AsBj1+f%diCUR1hBMtBCK{v%FvRybHc !`|Tn>`k?xdlRRjY0ja31Wv3LT ztn EW0X}K21*3|> zV&xXms!%^TCjU9R*G$lF;ZfBJd{GVGuMfq){{J;t8fGZ)L%JE!%(D^U`ic2pU-}PO z8M-H#qT4_xhId*JwvII(9Vne4pjCu9)-L53`$a{)ETkKq;@W6Ag=!ma@V8&qcNam$ zO-oV^Zum#sRLfoHZ=}&L#nw@IVc6NhxmYYY3B$#*Uppc9ot*YHEzVzWLG5jutAC9* zV)x;(X;BB9@pq~TL4BpX%kRXZSb_%jk^wC2?B^XqhF}#H95eLzGnZr{cr+^J+r3%} z`N}K9`FB`fQ|JuKZ;-+Sz)bEpo%PZf2*Yt?_1om%i+$m9W&5#sJ*>hO#)#oh=4Ura zj8@tH+l^OH1-@$qzFYpxI}WxB5!uLSwjiEr$7*-?ass=)lOgB~wHEVW_XFi%6GCC* z+`|PqppN||J)Md!i;l*QVUn7<5~I9EFk$;Ro?t+gF -K9ZsI7X!V`vz2)z`7By69_)QiC-Jympif!gtxu{w! z?cF1sg_YwV-S(G-g0<$zWl~#kz&)3uoxV`1)x5uvXY`bc3F{!Vul@|4n)e;9cm3HH z_1fDQ=MKq#5e^v)H{j&?-Qck6chHXuUTZoRt5)VE{<#Pgr;egJk6(@toVQCQ=#!VU z?io~q8`_5>0ns7%xG$nJk_6&;GB$}hp1r8IF(pf_WceEKm7G$E&7)+_`UZrzqctA$ zfmFfW{mRZ6HRFn!$OVpH&W?c={-UmU2g^wVLSna`jTGMbi);gVHQ#pq8SyPmLxCBG zdqf{o<=zyeT?ml1e6)@vp`FqQGx0q4gfo^5h~Y0Iei4 OG3Lp) zPRE>&w1CZjOGhY0>%j#2s`vR8tVa<* rR31yZEV`Wah$|9adtQt^8BGj)Zo1v>G_S*}lt14)GxSv}QAO8=ONsv(M zo5!EWUed0T87U57; V!M>KEm1Fx%dM>UD>WN4c9Zvn4NP~z!Y z;NzLd0Sba07IMWi;ndWPujKQ08x9U-ZS~32kLRVWjP3{D7E)akb(tkrZmKf_+Aieb zSID4*Iy5bJ$a)d~x?AH3EHqDNXye!WmTrq^p2Y9-nOAO#KkEtJMi`ZGDMqm!qVI0* z$8}XZXUZ >uo`V;`9uGPuv 2Mr@D7E6j);yQ>q(2ijs2w+auM+kmDie?b8+S!Q1TN?EX&HZYk0Z z3t~h(&Iri_Fk72?CAK%T?5#Td@h#qHT;+*)BB~d3hmxsc%=I!LjQ1{bL_NK)Kb&zk z!SnI)Igr;4KOLNNj@bg&!H%S~suMX=aspZwJ5G3i`g~Ynf5b^!Io}?KHQ#O<-7c zz4xZj*3zP|7&+gWh~;!{fyp`yIu~-{QCa_Fr*wfS7fSU=sNC-hecW2(eLxJg%ohfh zkVhnm3FG0goAdgtXZe+u5AkI{L>x&l+Ye|rw&cGP$ZL3Tiuy6Lu>4%iE*K=noeG{R zaeDL<9#LdEa{M`EU-bAJ^j>nc+kDaMpITrU*JHv}wFH!mWm7$3##A}_;%yiJfmO|> zMgisv5yAL%_~5BALQ7KELPhokY5uGG2q;+#xTaoyX2tY#+tq`q*Qv$prT^= 8@5j20>p7m->qarWEckFkzZUnOCapTb Qa~U^X+C|-6G{@A{Q((@w!1rjP_?OQ=PSc%o##aGzqW%+rhQ<%4V`LK zRE=IIi}wS}*~>n~!&u`>80Jcj`QmRM;ENICJnVdI=!q+w8njVfS$PN@l$ZAL5s9VZ z#{8{D0TEfHH85#hy4vMq?X>+dxUd8x+MegL0N1Ig7wE A_bquICiPVdgA98i}<6I2bfBkp~{Z}hYX zGuuti-LE$0dLcPhK=9M9(xk!GBpFd*yc!(24|aH H}2RTP*9Sp}-9Gz(GCdcKch<#YD7QDj?&Vyhjo&X&r1mAzoRg-r`1 zBno5U+J5gM*m*l3nA?o?*r^WOvHH+-vI~ CbPvm>S- zzk&RZUjn8t33nV{e{JzNi?eMNgjcIHG;=6?zZlqrn!hC)&lh$AKP;+eUhmsg)chfj zg=}`MT|Aw@V!5vWU%{uP0F!~Uu=j!w9H~%`MLjOyN`Qpw !yoon0em17~nQ%-|(n(p_B!g9CCJ?=)zY3~qMm)MohZ*MJ+Em`joW!rh$K&3R z-#Qd?D?2vBPl$JM4Mno)Zd=-S+#ryeH_c0ioq-yfWVQ~dxnuG;#`(k_lo@umpPC|f z!wv%|C_W2m`C^t2K+Z}9ip yE#>6RHJ5JqH@aTw>g5Kr!e!+^75y&w!}afc7Tiq5Cm(-XHl>5J@{-2HArA z*1N%4r?zh3ni@!*%DbDT2o8kLe-vf;QQPJ0i=UQ}RbFupO|{)jFTDR(ruvFU0oc9s zK82WR601b2#;Cn-mm6 zi#&nT@vYbuk*fG&d53GHJ6Wd0*SRCX)dOM%*0)w=OZ0Sx=Vf=B&ZKD`Vjm!V68ST_ zc8<|^iO)WQV`LuE-=d;VG7a?u%t(T&eLr09{dgw+Q1`|7&~)$8IT~keCug(b)2ObK zk%w^#F;47f*KhR4gc>3 lE*I8NmG0{WE e Oqb9jf5bJs~!om;zb9i8AL?9{z0Ei~I+z1Vi+}Uyo-DIyQ+o&lI z501FJbkiKuT3AvYu~m8p2+zPb>1jD@ebBO&BP?ZgXSvF`R5jIA%2m|qK@=db6yXnW zTJp7(- 2~$D$f6T=GrHTvzY|e_#n{K&2N?+7KT~3$L{ZG|lLM;A zs~Z-Tf5!y0g}B`aWut*meSm2~4x=81^a22c(J%{B*JuKB_DZnyq*Tx5qh{dMAQ1_5 zg1D|}pE56p&tEW^_inm?NKMMUPgS9<_h9E75w{ZnDQTz|Ka5+B={jEcRV_07wg_Lc zP*+yc4#)k#fYJVY{WVqrYdGV`SaZ02K?{obJUyL1Hmp@oq4)yQ!qj4UI^C=Q$tJv~ z1uXs!YJhF%Rr}+k!~KMjEBK!AU8SCo7SuIkkqM)5s?C`RUzUv#)DuB!?v1VidfmJ^ zdQp6i|4xsmkB|BdINT@|i6_q=x~ZzE$-Bqxo$h#jMA8}}f1rt1nFTP4>L+sJc5?<4 zWu?Jj`DvJfg2G!GEiep&`3%8$ZpF5jE(bH~6B)K#AH6IVda@oPS`+|P()9H7JY=)k zRn^OZ(&r^5^YZdkFi}ysCr{4qysAH<7B+^=hRe?6VUK7u+D`~XFLU>N*+w9#{ kdpN^K8`m99Z=ZKfYvBJEU M>9WQ$as~G%kNsBnJ;;>Ls|g39wUT;& zn01NIr|~a^UXuCyto&2P{-3>-IWbwgllW>-!>M&{Y~BymNZBN6sHt5om%o9o`KIO2 z@9~q-MBHN%g*ienhP!)!>RB?<(jrGYe&~?dbE7S-^BQ*tqJ@0Pljw6Q{Ob>Q!+xu& zX(8<>o}VOU8}WlR3_^OIqZvE_vkM3WLVX!5BO}q;+6pu1b!iG)w%SJeP_VPecIb4I zoqOVtOE2zWURYgCaV#2Ldwj6RdYu^8=J%?xPDMrKZBLICbDqcYWn;S1+(qhCBWgaR zo5R?30r(LzRY})Q*gH6YFi$667lnyK@Hku`-Z=sCp@~}f=fwj}lfoWRe7w1(kqDC_ zn1I~rGyqTXzYPIPfNE9q#E&Wdv!Ts5o%ly3%7&BZzqlxPg^0~YnOK+cR1WJzzWJ}j zSOR~kYc*KOPgXkg$zyt&LUdB5GqBq@;)3 kcRP(Ckl~I5q{~c$=E_q0 z5djEZlhf1F`<`&lxkG3MDT~y|y~iDzy X`c2-81dFh+VV%}tm0;NakYrYBa{u)l?v(-6aKv~PC MISF-DRq>GmBO9!k37G?hLQ}MEeVsRxYG`cK-Hl-*Fqnp>sCA$1=72nE z!;m@J+HM~{^ZsbtBavs#1a)s^tON=JS)4x}%F|WSWmy_*Z0X$GYCLrSC;RvnrZ!X| zK_l{PTo$(|QJ}Jr?qwH{jNw{v#T0OiiJ2X_OWo7yn7a?b9_W2hURxUpPGn%ZKU6qm z58EIhv)J!vG4!jj`Xk=a2dAv}*TwnG=$i_g8;e~>GmWU@^ -W_mj8oXc{6AwF*j*MlsQG>r3F zEIpLxed#A|CXDA7MsK07Gpr@ckD9jKHdogv@dx*hE(_ek9ej!jgfDxIBuP0e2gT=@ zdVa2mN|dCWHO79+$PE+gl-L`Y(@m-UxV^o-fQF3|UvPG$Ru2y1H*^Mi$hDQH-uY7Y zcWw 9i+T#k$@{}Owq^XaP*tPflb1Onj*vyyI>5!b2a z=>rQdY}IO;o2MJ0^>K!ZH&L{R8{_iZcs!m;If-{H)5zXWQY)$OCmIZ@s2Ws?(+#$q zKDs@TZ0SdIrggLsKRKjgst(R+Mj010S06?MNao-)4Fn=7imRxBNmAh{#V+|IPP`^f zw6D4*$QVq0E1%TjQ2Hj_D}vl>ut YwoN^`>JDoBO%0WOL4M>T@e`8;To&Q`cFzchk?>cA zr L+)3=4&LQ(I-GhnnUOuJZTZ94Nks+%Zl5AsL8xg@z2dfBMZ z3Y7MZ-pg%zG^GGK5K!H+C8GBU1m8(lHp-az%osnVZL49nEnvmC1*mS)PO@X9vcC47 z_n*hYB?;W1V4Z~6x)bL{Ig37+4l)~9u@|$mELsb7tQ5A-4>fV~6)9qORiW%VruR{# zkvqACb5eA(2T eBEeAORXLGO=;ad$nK+Hj;96JsAcPg?RG uO=B8)qTuc1{5> zZvs>iQ?8zUIeO#G&w@^{uh_mcNWW9T;bZNU;_vQta!kW32NGzD*nVZneE~V;56RJ? zp_+PHrSWkglwHSEh!q)Y-2qDLkI;EJ<5oq>xj+v!dP6MC(vtI9p$EDO4i666K1C)x z{Mt*`c?>m{N0_)4H{NSmtuE;P2v3bHAA=7^@MRnrc^w)QV|@;v=jVg9{hxqwfZ`w9 zMYBI1{;Jc#cCy;|TCt+Tt2{6Us@fPY!;RGzW&z$<(y@Jn!|a^RFBO-$@&P&VFZP_u z2;FWf)guv$J<854mwx*saxE2Ckclw%c6ZvRAgv35nVFgVxDb9{b$Tk%X4ir>8XwMH ze!h6ZcmHBz<>9=}llePT`#w|h0sRHh-1w8`5VY)(zOZ>4hgRL+d^}Sb0buu&SC@&G z)K-&=nB&Z|aHP?VsYf{YUoMpMfh1XESXkKT^QY!DGA%If+s*X$b#;$mQZv-p`>fa> zG<@$mDda-#5-$x!w0h^j5*|WUJZ1BbYPwcU7*IIMyJoKv-@7(QOt=!L;^4+L!E>39 zKk%=&EvC36^8Jq0W0Vku8AO}eOoh3_2tUg&$2z%9;CDWIR;^>sQ4Ql&vLUVyv27Yi zvbFJSY4LWVr=4`?4$f!_SmLaK&F3ttXQ8nLhY{K7)MF&uI3L^`#lA39&HX3 Wsy8Dj$g001gqpXC4m076hqR7JqRzyJUMCMG810tPB7DrRP8b8~Z4 zR8&`2S3*KUPft&_0tFTVyAuMUq5=dbCnr8WJ}fLO8X6ikH8lbP0>Hq)P>#=v00001 zbW%=J06^y0W|1LH2Pi)&za%p`k#$ag>zS70j4Xv`0009_Nkl vDM7~U2+f@XLoiYOI$7h008)pNKiKisS^Dz=;8C@OX|Q7 z?y>?5qjn47$CP;kHksA%moN^Q5r#z{VHoGUXC#w$2Qn?0H?R{u&iVkS{25Gt3~-K_ z16*X@Y@B7OGr%BG8{jp5?f~Pg+}|2GCO%vnqD-~6?MtqKv?p~We&X0AKZZJk+1Iy2 z-#@5Rbtt|*gR(r_XGM7oqcVeIcsy_mNg_}B436O`GsKg2f0uOzpORm&0000000000 z005v1vRMie!hsa6l}VRv?2q_=x%u}s#++KJk{duaD?zeXIIOJI3^M79SjGd%TZx4U z_j$X}Bn*1qTtDB~C!@NEB}_-+%TPAJsQd*4iA6F021=~63i KVQI>P_AdF@ube$sQp2DQpj{bIX`lyA%%rCxw12J;-*1nq% zB|cjRJV(9FKxX_Zj9mKe(tx!~f_aRX-41Hi`rEVw{s-Aj|XI|B^q89b84FR)!= z^0{Z(`yLKqe6f#s8Pi{ciT(k#>Ag&DdxpIyyiC)peZ=dOZi -|P9ao@>nE+iiC$NJjiR zhC#nhYWqKa4y*Un?)Tg7qt^uh002I9>R;MUpZ=u{_32;QP?!FtP4(zs+E$1Dr7d;o zU)ofM`op$5)E~Chq5iO~9`%P!b*Vr6!_2W2=I?y4J`08UJ0Gln0@$+rofEV1L!c~w z=R`DeP-Xc$AIu-Uh50)djQn0{{?3VHe(zG4zjMRLvlZp<0001hly>j`>!acO|N3b7 z{=Y7ozW=X>w(tMzpym7jy7=zz|Eto!({ue{mHwTc>kq5+?{r;%Sfzib>wnwRzq5^V z>kmCRwf@k9Q|k|MJvg`i(1CO75Boc}{?LJQ>kmCRvHsAB^Xd-)00000003aCynm Ox>AL=~O8-vJ^@nx(clxS7 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 zcmcI~cT^K^x9)@@C`eHR6p*TjQWfbXN=KSR1?dtHDFNxt5U|jT6e%Kt(xe6if`AZI zic0S#6s1T9>5!1j9sGUu+_la+_pa~!k!13=DetqNz4x;x!pK1D_^~s`0020yqpfZX z094Q+><9f3=%=rLU>5q56L8DaOWocR>EZa$%hAmh0Q_E6CAS%Tkz~;r`evfO!p;)s zde DUd0je9Vm0}0f{OUGtYotD z3k%_jicPuEjnB6!vx}EwFaEHf{T$`p9>QyI-u>1?B>A^MtW2m5{q()Z?L5;0)yB>y zvzyK2%Qu+28L7urRP7~9^B#VrQDa-=Pk7ELD5Ob05;|m4P{6=q@W4KJz=p-y@rA3U z>!tfI56+|EAC5llDY>Yvp3lE?N{iz&a_{RURMK{7<)<@?N5#2dLU!Y4V8br7O&Ea= zheEanrnvOCF+Z=f2vTh5{a09bM&Aq4{g92JdYL9c9}pFkC#1bct@B=_^5Qo$9`)qY zrv`z9nOfZ}U9#Ffa3yH-a+t~l9e@hrdw6uw4A$HOJm+@LJ-By0<^cZl@&5O$ M-_}uZTJ)VpjGfVzL8*2c#fYMRFcFXV8%DDAAJCho| z-wM4w&&SU9_6#o2yzP02l}bE{dVBqCK5x!xww@)=#$ZEPH`}w~p(L+}v9Rz>NxRoi zX*QP6(O;I{eZwRRyE-bDCd2ej>Uyt<`N NMXjmK zdN)kqTp3OM!S0@Fx(qwEyaS{LMyoCWg@W533~8_F4i2>TVJw1NEIq8Z6@bRFSW)5C zMKAQ#dstmc8=mVYHT-O8ExqKq-%bM7FZxq>&1JuvumFvF+;?TiF{w{pS1%^P0Limj zz06B_q$M-&i*Nk>062#a6H%z~OXq^(95djr@cT)ykS~yWK9hzXpjGhLLzMnHPyuF8 zMO2LiFyL!C0sxG%O6~)=o-I@;01phvfIZ)X*>IbQ0fpI*IF3;@`dO}{f_3`hiM2D> z3qY{@2PJA29el?cwW*1^+;IT-LLdq>dRxODb+=Lvp(pNjzLKxNOrm!?tkBy7&1 k7`tr5vi{+b!Ll2w4XB<|k;{i)075SM#0e3!Mj(bMNeDnw}KaLmyCAt9h z>sAzYyip9n{AF%I%_)fw6 z{QT_A7r9$ark^Qb{TkYB-E(ZNTVknLiPoq}e8f$md2e_D&HvWEF^7AKvUz#jmv4 zpDXNmrxX^8%m^2=eO0?T*Cm0&n+|f)Htoo5KbbI9+Mh`@Spn(LZ$^?H&0ey;D++eI z7oRNGh(_%8BMdtXG8C$Y!L{0@QVqP)##h1Ym6Rv_3bYT6?v-`cicr4XXO=njO?7A? zrM55|l>2R|t3XmEjdb1Loy33_k`;XphFK>_6T6+UJc>U4>^6nu6K$v3d`T M)2Q5hgnuhyz&hAj1j(F%I$u?fuN? z7j_?ux*I$n$8EVT(^xCGDQ#Y+ L1sW=?H@WC#gU@%s)H4z&cD|kc zVJ5Y$8*H%k>X0u*DB-Y8hg@NBaURo7S3iq@#k1v47%uQVPnOj~r;(C7#Zpoa`Y61D zOT*Oy-(s(RQr{r;rZiN}r_W tf7B4)JALvH@I1C{YIVh!uW z%F=r|Ohm$WNOuxMvSplb6rz;J9GK_~QLFPmKbG>r75Sa~Vh8-1JMdXJ8eOAx7Z6?B z dxRis_c`_yscxMH#Dx6|Q zjQb6W1-eFHMm+dgBBWHL1=DOX;v5ePI8%upvi2YtRk ZC#;UwEF-rYAu zPtGqs%6>2a*uoBAsgD2~SpX1BB?16haL6}acz(!XIscia?)W#zg=8 *6V@G2Pq0dZGTz1wo<%H%Po3!QC36~d!7oz?>SY_Ul>=nDB2h!J0bV*mVIQ< zS8rlfsWcJn^lhlnR+6GZZ+sKhs=#RcnImO@X6M6I3%~Z8+7Nl?m6=_9EckXdXq;z_ zOgbHLUTl|B!-W-jv;wd`nBwT5+Hx6~S3TsPMC&y}e&bZ+yR0VGR<8Dv+(Q zV#h*KOVT#xMTx(52yWJ|9!CoB;aW}Uq|_w6To4sbU|hklh?_NkGHJviGXqUtvc`X0 z{s+CiOIExOTZNc$Byf^6(M;jJ0z0&a98&(Mtoud2WaaA91)|4-y UUJ&5xpi!TksRiR|0d2&^+&dJ<8D6eCLKLakgOuE~ z;0rXyKaG3!;8nkmBCJ+RUwj0$JoX`G@!G#$A^B@2Ge>|gXLvdZe)O4HJI&KqJK#-r zAYNU-@z&%Lmm;RPUpo?M_*g%uDO3F24FpAAU##_=Tr+p}G|M;l@6X_(o4a_Be7A~4 zyV=k};`xoqm`@&4%#I*4;_N<_Ydfr57! BK~m$_YPFGG=+WeDBD| zn@yLG aAQwF#);@_YT&$tOl#sk8)Ae zV3b4yC+|+>hq%e Y|0ifWpvaK#e9=SuK?@-QehCemcstGX!Z|fS6<2N3X8pGRF`kC!aPEmc+_yk zjszrqWBl8ul%;8%^|u3mhVeEy4cd%PBb>ocbi8Bug}iij)!iN|p7LdPaHCD4>ulh1 zxdHM_0GW9t$gB&wuxpQQGVuVz7Ad@;6YR#BVWqpEcWcA>R^EKzvLfwsna8uov*Kp1 zgzglf@-o8|=owkRbT45 G7_F#M*P;KlJxRR;_8;_93jfV}oP;3ETsg8d6N|5-=-U!1n$=KiC3&Meb^!$RZ3 zcEE1AJ?+Yq^KowobT)xnGX5KaaZ2z1?7D01Lf*(1X4Q|L!_$`UaHn?Tly`=+1XJmF zA3aoU?rq&LL9a*UJ76fD)+MuV%#sc^Rl#X+Zx^FVvPm2wwL2K7>==Su65#V7RWz}Z z^@`-tDhEKICpS}Y _2ZDJYG&V5PhFu40iQ6YZSt~)SOZBc16=%!ay;A}c=YI84SWqr+ zvG%T;{xwyqw-mjlBXV~b8?OnjZke7r?pw09!(?nJY{{ l#yZR`@(Vm`T|J zeF}GxMm!nS R L@fTm;pre?rZ@n>&_EI61)=}zGVQ1cxQPT@*efFiw)JD4& zfkSgMVS0OEr#)TDVth3fQZUxCQxUCw^kQVZjHd0MMV{N%_PZ{jTx@GN7anfa@6~h? z-2%s%$0_{lUV{ca1C+`8Y4r?%=~C}CdtoMVZ!N`znsqR*oAO@nM++)3wKi!=+ufUg z``WnQsMRjCq)Raw9}_b{3nV!tKDogmnEi%;)fMdizCUj;TCh|W?@n0h_qXC$vYX#2 zDy%qOvkNiiW7s|)pUnjW*uV0>_W$h?{zFY!e}yWH4|e+t$oz!K^e*2}7v8K}5C>$z z53zh0XBuXz)cZ8~3{R#*Pt|W_%QK~ISe;3VN|LFHAy{$kqbJyl+L_OeE7f}+|LAPM z{F^;@ux9S{lF)wB67L`-7gzTnAl?Yc)6~VP7EqknB9n9iR9wOg4iM>V6r4DKl!S>{ z8qeWP@pCPj*Gf+4h#z}?TLYfEH}A#Hmn@cp8$2b5E))-p#71p1H&*sH9Ql#a6!^n) zk^Lw^dj*fMv55DY-rcG$9W`9JHKdk;8n~@bS>NoYJqq~0vjqBeO1&eWqHb$eUpi?K z@Udv8$USG4`^&AsCZm|6z#=pv=jP6}qkCC++1tC`b!TDuQ185|&bP^V-r!o90InbR zj^@S9DB6(*d|ISOlMi6SNnNnv-qaJTskSga=D)@FxLf2Oxgxmg7;amaC<@+;NovF7 z7%*%+nQ!GGH;@R$<2|5B8^0z+7Y3LwdR8X(eZ81(n%)f-&9XT!umNScDq4#2F~uH{ zRY%EqGlTME2m|JqsVv0)ZPYoz#)1EpA-y8$6k*@PE4CKQ;6AAzE9IsOVpEXq=Zpb3 zHJW?g b|4fI^jH3HxawF<+tN(tZPck~ya zJL3)%VFS7! ;9lxb zmo8l$>g1;+ts4j{oH~fDUU;9|1VT}*ejeu;E?U6LrceF(YuViR$@h8Rq=cc_-a`>h zlbQd5ftxiM+%~`;B>(g4f0~U2>qYNJCADyK6^Q_6<^!K}-J^px@4*)q5}1k? zleDb>=QLp5jcUxw{pRNDr_zuU`-$OF=nP@KyOSiOI0@{QGRmaN3en<4dnKT*zCaY0 zm8fXdK^yEDS><&s_z3Y8Y`&r-&m-~_ZeZwv?=k{xdv)w<7*!VR3IIXkl1mX*D8>AG zM~RI{+CLlH7#p2xPKlmF0Ma%`Y^q+_K0~F!OvS1n=h{JQwgbh<(22wjSGZG_qzCH` zJ{=6f gUvq~U#5jqYt|Z-syG0|2l@K)EfxY$3p&PY z8omiVa{CH3jbcqe&oc80fUfMz<3@_dL$}p%!ZH@IDBr@EzK8_7+@&-A;6%EA+hKA} zhG^JMW%Ri8q-7_`sIxrfI;{J#cp?Oqg;&TheXlBTPAQ>Ne#iI%VAi{%2j@1L+V u$fd%u5FVUK>pwq0Tk}|BE{{qRo}6sZhVTnJRnA+JGwI@<}A|MD0TBN5VwHh za$1GUUI38f2odEq>?%Z*Q7Yp$M}l4S7fOt09KNn#W2%R6pUk&5@&G<_l?UOy>Yw!^ zz!18#oT9LNDj{3bSm#Jra-HJN^x&2}G8+JfKeNz2s64GBTbiVbp&S@k=<}`>E>zIJ zYe*Ef4L23Y6XBR?1xXn5G3<@s3+r1SEiM3GldBn|at?FpdR$7vBcbudX*9;jpt9;f zrh%>RmLc88xlTonZ_2K18t{YH6!xyRh-w&>%bTv<)wzv=)by6LK8@fy4)NtR9@U1O z{V*~*x*Y(ZevvilZB-wH%BhE@9$jMlbhJR@*XBwRB$_q+QTyimEmWX%#C)D~26&K8 z1=ujesZ#vhP|Y>lA2ujW5ht_jzlz&NapoWRG#1 rkHewmk8j;wXdyYbzB)(@cQ0I{4J~Xi zgv~rR71VqZ{OAI3CVbNp;Zjs^2>R`-z`LLsSEgPqHfA2WFvuLb=U{yKn@+4n)Ig=+ zPCoYpRjPWiJP%ek4`M28yz8=_d`zL>9XcSd6zdFlq!O)@|H5pyNkW_0n_qXz8fAzd zkMQM_Me JPYbFt5~TN?Z4UE zB~u%&QphU*S| |!b#;g aIOr*-Uqv$P-W3tx-QGd z<#@*OEWQV^$q)$-r*+M#wMvReop~_LZCd+VxOEX<7_%+)!u!+K2#EC>CJrlmJ9XcE zT)(fhv`t7l9h{sSqbzf9KKrrA@&SMHJwiOZ81F^#Jht?Bp#ron_(n0@jb-F%?9b7y z4&WQMQ ^v!Ip~9Xd2B2zY<{I>P}}Q^t8n?#_a#+@n0Y8M9)j3@9 K?-bs4faF~aMn0K? z(p95l-LW6WVXgFgtw3VRe`wqf$;=9SUQxmjto>n#SGkt==$x|e#K?WUD)sc99g^zS zo00xR%!Yx7bxpCG#m5huzb;|fq`0Wyo-t5*(i`!#()Yk`?Wo*nG)^$IfpGSF?Tq#A z8t~kY1Acz-ysriTcwYbj(@O^1EvR|9#qVMh{E+&0x!>V!9ckv9%1cKLgL0W3P4E)b z$QB{)YROKuUMqjTztSo+Hv0x@3r_{`sRafGD!MNTUei*{knK%)Ws7 O-gf?!hBtARCrgqiHNmy^xlP;@47hyn z$bU$*41TFXb^~#fzcv9IZLLryK904T&Ca%O njVT}NV9lAQF26N~ivho3T0_VUS9o8RDf&soOhj2(;h((MKJhnLr#SdS#Ev9kR z)zy3Qr>F>WTWs)v^*j!)Es^F?yJny AH=?qXE~yzomlqbJHW z+tpg7P7!%+0+_^r-Vks#QP@FVC?s6UR$rBw+rUBKQ?B{YN)y^FUtYWXA{8*GSP5v; z_0`wcXK*JRA|@|0|H27^Vdv|NTyv8M@p{+du1W(>qZr>v4Y+l)byZ0z!O^_boj0$m z!GRd-vM~cqW0I1IPr&$1Pc=8cw=(;64f$4efMSUEt?I}ZLZBo#SUnkmS_@V5QpH*k zstN77Bsuhfxo^jV#|)VHuo-4CU7D@Xc1_-xO8c4heD+=uE+xv>_I3LO|M1V4V-<`D zQGhVUThG9E1 6H{{mt!wUwWcmbHVw{&$Pd~ZEM2MgThb-J z7I$4zIGs~4ITji0w9(~G40tiyuvP?S*K;!zRF>xTf&~(zt8q{yYqb 6Yuds~Qw{n|~xYP1gpGLOP)&50q>ESMBgWlqmku zA^*NsS?}uVYS36{ED}-EGA>IC*tLh0x)gwQqep@~c9y3okV#gIv=|qQ_zV*M_#?oD zpNY7@=ezqYvEmRu;-ldtajUu;H7)fKPGDFmE=2pCWxWqaZ-74p4ACi+z_$K-M_wLB zWr6eOhNvA&-Q8>#_=bq|B` &7#+ x-Sv znbpaD^})L;dLb)ex~7uN*MP8svprT8rJ{>HO_u_la`b*5OsW;-i*P*ip)yCy6Ov*I z=T5hX=bOsLCj@PCr(`s^h=}->^W>~J?<-9YYZN=y1}u`ac<1I)q6($j3QSQ18R`&f zhG1?ipr7Y=?t$oy#Tk`6Om>Nd7CWnFB<4Huquiyi6+Wmu(?77><-sMtqE*vOxHS`u zl6a)_TcFX`O0;gq`f4uq_1YhTIs+IJx?pY5n#}8Ii?lZP_AfsCZrnStTAUo)MR27H zYhcJySZvpT5;>&5OcsMk$gfIqL@~mEf(~#nyPAI8$k@eXSxdfyDy0`hu?1JD(DAia z_s&4Hwbe{_$Vrc&@;lq#_xxYv=>N8fi7W#LQs0gv@{f>{ztrzP+Qj}=_LwP5oeUza zlr-!?SuG%VN1wPm5x906gZY)_AP%AvZ5ttP$@xb6z+ExuU{7EjD$nzi#atJ_et$HC z>1ge%>yz%SJQW1jx)La&pKC2K;6E&}#fRr)B>1rbKevaht;d)UXoD&iQ^FmFbt>R^ z?oCj^J2Ke*Ce15FUsudP6$~P8&Ikq$aZy*a5dbvOyO4YuP&NN>a}Yn4LfnY)_4VyG z)EiZAIwJ)Imq7G@<`qDm4F;9fpP8 Z CRjqf%t2Gt>4UalYTwf>~GBWMS zfH?5>ZDfpC-pe}1cM;OZONq|bi(vVs0+94^g8y7b`H~=itOnbog)Nt%wq>>-(gQ&p z@Uc0`&)QPS2{Z}P`a|0-sykE<=Q)YSJhXY#)+vNXm5E>8U9=VDhuw;6MsvWB$!gI^ z<02qD<6>Bb>Nl~8^Su`&dG PC|8MEk9DTYwUQnx)NcF6GGN^7y;wtCmP#J l#z$FAlB~&BuB{$4g)N zk(^&PsNsY`h&GyhTX}rjUF%kGqY`Jj;>`Qh0qVVxG`R1_Wyc==U}&HamrRs>R>x{$@|(k=-*n+Dseu`xgcax| z4&OntRix?aVMW%5a Hq!?8^3^s`Z%d%liKNZ$z#D7W_=l-5*Ai7P|)K^vFMI zoOo^}b_^$A!czrWocN9OeH`UOW8Pa11clF1;(U{pPf;VRgC2ZmY;0_iq-NP25W*{& z6{^VC)0I2{_rA!T1TV%j3LXtTLF&aZZeIY7$RtCd)q6jV|1p<+6^2p$Ei*B@1Q@)M z>uGZs-5oFxw?*d=AU#yUS{7*uqMJ`GeW>juJxE;N?+#O` z~@mL6rRzaL`E2+#c$L8QG|vuUq+G*f!A`U|LNfnbE23V5%T( zmGeDFawYB0Wm>1ZxZ=q>oyY #vuDZj%UBpUYKO6 o#)< zZ>IT~p>URo?c3~TCU_vK*>LanW1YSqQpd=jn1i~V9!Kv8mWxH%eOz4^Kj9TkAz0yL za)T~2z%8M`AK=7Guhfh0YutR;y%2KVcJOB?muo8YQqFQ@>*RK+Z-;BmZ1SbEf!hNn z5?#iXVyECpcBz*@mN+f&@Ezv}@A-@{EAOC>1w+;tw0qQbzWx0!jLKoz@l@A>F`Imf z=CBk)nJVrskd49pL =MTV0vVAP#-0-@nM3`O0k0~htLXXD3^lb@U5GL zL&BA)_6h(QE9USgF|2+w{mwbjuLA(89xWm=BZVsPt7n4u0@(n|yJvsyDpRx6zWn*% ziz0-4h3JVKp FnADRgE+Q zi%!r0BV1`>dtSAPE%4Ri{9-^DDkn ^g2 zG$UAlXY-ODxRb`$f_(SqR1z>7omBu@`u2?`<0*4cJm#zK)S%YmSRVzqoO9_-g#hrL zRVQe?q)QIctIr}t)wDI>26GFo*Z;MQU{};u0B$io86O{aF_6eHUHYg9^}~}3O%{B& zeHv@s3b; 9TMiqAo?Mf< xHgk|yw^v>JmLw)Su kOV g3Q9+M4OliHB1lI{R6wOS=_Q~b zA|MLViJ^B0p(TMN>%PJLefPirIA@IW-+Ruu=QtuOS$(}_&SyUJnJfB+!S%ze$5~-8 z*kNrg4I>zgp#}VZeeeKSvjG=sg~8| rtEEPxz z9=yzto9C++i}2N7xuW&1&N|fAW65dZZ-!9Hw)bX6*T+t0kvBgWqo0hQxw6LiW_V2C z+JmKQQQ|&^2bDy=+`cCC_b&~GUl(ncgr48O_UO}uB`4?M8@M6`ZJD+X;&**vp^W?V zUJS1ej%~ARe)SWM9CwX9s4gBP)aa*`erro@@Y0)U V_PaJN~Pc*)eiFS{yxJn!0! zibq-y!==fjyOz)O?y^1T{ybS^T`=&@bQ@DoW-Cs=k-Ga~?m7%64Aa(7Hx9^L!5H2@ zrTuChx_*@qz^?S#@37-d*`vm)i_A}lKlug@jH%AvlVegn@$E `q0OZlP{Nfs!$%6_l2T51;kl^ABX zAd%W}EZtDUQ5moC?Wtqs889|suo;YO9~g_Yf7-%ywDAg4oaBSUvD7vH)*AGl^^t9k zA;kF-6bEfnOJmqc_{Mt#`OW%|i%TMY>335^j?y;7r)V>oLqp_Bsu*P+L7C)WqM$wD zA!ZNvR&il`3y@)^IQ{+!LYsfE6i`1|YkLxdyM^q-5YaNU^};c#dq-b^9ZVzV zhpPgP+!0w&YaB>NTT@M35wPR#l%{ ^7(_!P@v6Fb^QKq YzPPHS8_!;J<#dGj+o&pW0k zc6Tq=HaGjdD=13(My?zE@#QpF`?`OTaT>4aIh$Ge2#>N>_;{A}IkY85t?c?+;aUV9 zCHMvDH}d0JzX%<5#~;n+V|2WPF#~c8qm*b|T$KJHbBI3A_=ZGspZk}`I(Z4ck0;76 zXBm|A_9~P-hbBGK{LTwr;AhV|3W 8FfsfK4ukr!_wbxnj&4QUJ;vRbAD=RXw+lY-XgwB%s#aE zGVSH4G!&rB{%!W*XipTzPVNYnkY^>MTRN0@yV!Byb&W;NPogXNVn&b8iRAdKEP)3X zj;F6W#a=r#JTju)aI9QOMJ2hoSo%zAmr=3lJtwE@OWQ$?(+T2vMvIkrXsSIX$ujwQ zSC{UYWF2r^p3#}w#zsAGTribfXJuujRcFPUmt WZnU=_4u8PvFMQEi71MWMni%Ad`uVjEpNa zV?33t Gn|a>U$+6CD6GEBs>yyv5awqWihYG#FL%^YJCM| zYh%MmK|$dhf_hOwq3x-}`p%95*ocvb{3n}(gMuU|VTjFXG#1yjxcFdHKi%@ph^v8U zvjrt-&LRsbcT}-**Fmgh)lbRWr1V-2r*Wal8Qz$R`g(~b8(9MWrVdlG&b^1t?e;&T zc{(q2ABQaXnQ!(FU_pO_=6(?ucP}(l#d{ue|H7lfLdn4GrR1WLl5d@z(M83@vq4e| zc&w{J-tA(Y222Xreo0aB>*}TV_Xdds<=*rq-0W-~7 0G(7cdP%&YuejwQf?=JpP&y`8=Huzlh&BL@qJ!y-` zVTP;>_+78>$fJmJXx(i5gvaBJMTxUrsdcLJ7rG0`^$Fw@oxI)xw1u(N> zyW2YPQF^1 Q_PJLgc0GFQc$cNy}wQk*iX2TO{I80&iwRANq4$ZqbMviK)SNy*lc zk@U3aG6QN&O-*sMHLvmosCSd{t7w 4?Df;_N%0jnDi(`Js;IlZb zu*9f_@0jWrLcD?p3kwS$hJ~q;2+Cj1H-^7SoNPo9Dvm;^1@D@(_`_`CpJbjRvkoq6 z9?Cj2PiahTCqf#ihS+Eib45 a&qznrosO_BwadfEB L%ji_l-;MvSAHt zW5vbBwp`Gy%Jdj@;KJuR$PD3yVfghLnumhfA-L?o;_mGx8HR%(bJ93^Z+39|)e*Dg%;N|O!8E~S~f z1G%^3rY>~LaJPTA=-~N9t%Ac3Y@rKrNKeljKiGsPOFP2Wk9}HQAnYYlkEMPnMX<<$ z6P;UK9jkfjnRhlix+ajkKGdhB=5uaqd&pKibm5G)O)%$_haie5i#?#qD0wgBAQKFx zb$pWpRx%}ECkzK3@P-c4X2?g#VG*Sy7 IR``VpNT$URHa;(HVvB0(Fn5FAb2E}b1hQ>(~Z z{f6qdhh7nTd7mNI3vDS9eJ=PKG)0=Y>VeD%BGU=Wet N~Cs~Qe8Dp;qVYR%S N zgdaI41hZ=Ay)O*+5*K?Qu3C$d#QR?wVL6|Osx6J7k`R=wTd(7?u5sy+J?f5vt1-|< z3-4?0cw5SnS+u~W8G6@b5{HBuh|Q?svu97>nPEzJc3PLhT3AF{XiJ!QJdA<1%v7V_ z$5Ed2`+fdDvICoV3+UYipUbTPDI^)GC&ligEMaFh(UvTO$R~WX^V%gp<(g=<6K=-o z)>)+hD_3<}{{#L0B`aLtFb?mV+;ZRu;O9vDkPc>1b%UN}W5Up~a5w-Xz&4rK(N3lI zPC5xD#LxfN@8(d;1;2)e0Rf65tk(I)T95VtTKdOdrRvUAxBGAeaU4V3wNn6Gh_up< z4DTk{r$d{qt?KF;8fSPu-j*g&_i*CSyF|O*O;+8iBl|lYlro_k^bsYJ$stCEO9q@1 zo#lA$(6*?JrWC+j>bayIT9S&5C5)tafps MV1{=4 zhY9Tl{jx!a34~C#hZ51^Ufp}YmbbOJe&7hRU=Eg7btwC9Hu|2JQVshvqiOr01dxM6 z)9zQt=ao1F5_7*}KQ^s)_UId3uY8=I1W^ePRR|)Xp!w}{2wa8-m9z?xQ4kKjh~6AM z0OLE8_h@eo$w6u8>8P1J@9KL0RJ>?h35>8u$ 0zHT&@5K4&gQ5?WL$2$U^=YGHR4Oh8Jd?4T?sQqzvq|&LCN~LCX80j$W z?d@%>j8qPfp6kU=PX*fCK_ZcTe;2jeq97_&wNqB^{dKc&CzJ7nf}r${Fklx?S{*ic zZ1ME@=H)b=-l0-kL(xZYylvc`M9Hp;cKfNtX-r3>n3ouI=TB>1#F9BIsz23zfObpK zeBF>^1Zg5}YPWm$n2dqUR@+8T#zp_IfH&DkmT;8y$*b-!khZ~nYaDZJh&AtQ!fwaU z7a!x0X2BI)P;D;>?0nAf5oxaH1YTKoV_GurkyCGWPvhF$(I@~W!D`OVHR8}}%=9ip z;N5Md77uK*bZ#Bf?!?6F_!(ZS(4ra-EbrQ`w^c{BQv-gi#)Hjkjq!(x-)4ZtGi0CT z>wcXuH_rBLFUs+Z R77_9N zju6i#g!MLRZ=CCZF12O{eF@4o`vIkB@F*5eqn2dX6+>7rz;Z>FQJ+Ylom(=As$1;Y z)XiR#{5)}o2SP~GV2yVL()niL8t){q<(Zqx^Ct>ET^j_CjlLh85dZ7avd(l7qfa(6 zZi)!sY)7mS;-{5+HKqFB6(Nw}iZ5XdYC5iI;c42~tK2^nxynDr390_A)yOjMAd(!v zoa>RjEab$MJ&1P_xGrLek5fA7O}bk4sYClMs>da}+>7r-HbTuxE1XVPR6$Q|j^gvP zR`uzH)oHAM(Z@nH?W$9&tX88PhMVRJA3w`$i;iuYzmrx_Muyh{gQ%vH77l~;wQMrW zRPJ6a1Cta6OXK@v7`sm{Vwtk?uqvT^Cr0nX_XF?nOCl8Z0Mp->&~b;|E`U1+`?v5X z6#0!BTU6y2|1q_4ks^gz3MQs*&XWI}DS~y~RiP@GaX<8&Q)3EH$Qaf6V}`w7(<^7_ zyNUjD`WtlFJ@2X${yFgnSg+$POYLx))w5$a4tJ{j_cfR^B(l ^f~V13Rv2$@#t*n jS+BhP&Bj*E|z96hxiKs8c8bc68y~7-U@doXzSj7Lrz17_?@2bczhQXA1d!Z3m z=fdTpeAw8>3j14@5t>bbn_{UQw^Q`pn0VVak)VrNrJl`0pyLO8jl=1rp72b7LnPyU zEwH DN{mYZSFA5BC>R^ybwCue8*QxeL zAdmT9;FMZnlk^fTl{e|Cng5p@S@w?pkg%oe?PR7S#Uhd|+Wg`=3f0Ge4bO%YUWlF; zTX~zuHIe(s)#0t1Lq jB6VEMY^4KDyeKJydi+v>*$bS{n41oT!d<3mtkh)>aHZm0lW=p%9vu*SoLmU zIqM<5buv1m$BlWe74%6q y#=dah zn!w^kZF4cO+ErQzgC*_Ws_Zo7rrAAC 0qWcG4$f<6MwnI;{hYt$E;a>rAaS)LdqPo(6b}2~Fzp z5X2m)R->5+EmochQGmOV+FJqjeJ)~Xcn$iYSiavvoX |yfc=g3bP7d?zZFYYsiYoB-*L`CYDf(8fYrGi#W@BjM(cDnohnt>&Y ztvV{-e@WQ4d%^%S>uT)^*wHS~GNlC`^NUgoh ^?f~C|i!F`_Xz5Mc z3(*8hL8ZHs(a`>r&S^3QuxN|r>^6-`ArGdwpTO<6 $XRD4N(2 zPQ=2gBiqBoM3^k-VUDLFm!V3hUiu6!oj;SlYgS*~kTDdS`t!aB9FB3nIBVM8)kwM* z*nX= |GdwbWgz||@#n)j z{xOl^6diNpD9E)$M70g6U^XRtt_fy;m7I7RCJ$vewL$J}h|sP!6r&=&msqeu)7}Y3 z?=h!z6N)dmn?69JVcfgc*4!Nvs2B|93Lw-#d@;<>Swx)+q-)b4W6nvEszj;UBCRrV zd*NYg_vESdaKn`xr!R=YZsMuqLEl}*h$w=|QLc%o1?_dvJdaMhH|pe10K{x+imc)g zQvK^~z2Jk4WHS4K$5!HqNoS|ZktEu+QryE{xtmpvWQIsD5$JkUC%7o<%YF^%ambpn zSYNK(y>J&c;mf3+AabG&W2ZOyb7yJPUH6T`MeVYvc*g7Z2OCfp%M6YyRf-P4m!8Cx zszmGcLKUyb&XXeMcbiE A$*=doFpD4t4pg$X9Y~1*zaep;nPJMn(IegxdS? z%t%156(`%}8BaXiP~vCrcmLG)_Hv}>Z0}Rm*QFQ|sm^46De(7QPLXe_D@H F?l7y7@PR#bW=4;^6O)Ska+*!EyB^Wt*(P&Wp) zE9hw(q80A2F|1)O-V9=&jU=+OkZQ %!x=P8X$BxMo5gE$o2->0ej4JFk2K4w=-@{exK_z$yz%;5$h&)V%Bv7|69 zV%EBSxfYkQIHj@hPv| 5zAY(1i?r3rkDghGT4JvCOvDYGrEyrP?*CjjAz8nt#pB z&~)@wjjEj~WqY{%!IVqi>LAM0ve;By+w(846Ne5MNhB8u3BfDpRWFk`%S$=BpM~Zb zy&M=A$oICc77EC|NLshdx;qwP_+#2uHYjSCFIak x^;QC34<8^()Y9W*T{tYAiv z*CzAO$mznN&mpykBR@ZN|4k_7a@ua3&J_}Nad8>UL>o!`h!MKE0y~K8 zNm(wF3SFzt_V~3L_i!Uq^X7|;qUc@Kl+ 2?23PQEiT9~}Lkd#_ zrjq9JU Kv;}eX3KzBIzAAJ1(?+&~M;T_Xno}r-vAXO#&?ZCZsBZ qw zOH0M^HIwxkt$%NdQ1RuH%5L`^{sI}HAB#SjOUPPHGRE->VzpX0unp^WvmN<{5hTHg z%?N<>kKbVcDXYQ(TFMIWFe`ZA626BvevX2qr%=|~Z3s7D5QpX?_c)O?PjMcBXzZQi zcz??zysb0a*8K~&=OFjP-WwUSJmQ$@TJctlyP1Y+JJ#x8r{okunjdNux4ukm#yJIT zU>1Go`KHbuJ=8`B1u3S!JL@H^$Lf4e;$~ z M4==)A{|y&!PfGHDBk+?Nta$2^J8_# z=~79Dl9lcwBx5H2*lTrb$h5gWdVWXmS?b>-QHZx?H|Y5d!Z%b&Ke+8w@I8IN(ybmp zbRgO=+*&(43fjVdVln%@8*U`=!B`@3rUv8gq)J`&vjnY?Ym`4DAqesiMKz!1NFn%3 z)vXQMaiR7&G2WIV$yyREfi|%}JL9s+?=abs3)-IJ+CPdIPkU^!!_JfR8}vEOCQj6f zACM7gb)5AFNw7^k7K6!prk(vXaRPWpfMv`m9F;w{VG))ait{bxXYKH5L0t<)I(Eab zO$EGsBFeA94H)JzaFj@^7n<$Wys8{OdpjZ2CBas|11yiRM@IAO&TNVd?=;)lG}M+l zB)Pf~;Gd#z)LCVVv{n-k