diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 02ab7276b76..f0318787368 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -109,6 +109,11 @@ /code/modules/mob/living/simple_animal/bot/ @JohnFulpWillard /goon/ @JohnFulpWillard +# Kapu1178 + +/code/modules/surgery/bodyparts @Kapu1178 +/code/modules/mob/living/carbon/carbon_update_icons.dm @Kapu1178 + # MrStonedOne /SQL/database_changelog.txt @MrStonedOne diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index f91b3b518c9..ce088f99880 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -68,30 +68,28 @@ #define NOBLOOD 6 #define NOTRANSSTING 7 #define NOZOMBIE 8 -/// Uses weird leg sprites. Optional for Lizards, required for ashwalkers. Don't give it to other races unless you make sprites for this (see human_parts_greyscale.dmi) -#define DIGITIGRADE 9 -#define NO_UNDERWEAR 10 -#define NOSTOMACH 11 -#define NO_DNA_COPY 12 -#define DRINKSBLOOD 13 +#define NO_UNDERWEAR 9 +#define NOSTOMACH 10 +#define NO_DNA_COPY 11 +#define DRINKSBLOOD 12 /// Use this if you want to change the race's color without the player being able to pick their own color. AKA special color shifting -#define DYNCOLORS 14 -#define AGENDER 15 +#define DYNCOLORS 13 +#define AGENDER 14 /// Do not draw eyes or eyeless overlay -#define NOEYESPRITES 16 +#define NOEYESPRITES 15 /// Used for determining which wounds are applicable to this species. /// if we have flesh (can suffer slash/piercing/burn wounds, requires they don't have NOBLOOD) -#define HAS_FLESH 17 +#define HAS_FLESH 16 /// if we have bones (can suffer bone wounds) -#define HAS_BONE 18 +#define HAS_BONE 17 ///If we have a limb-specific overlay sprite -#define HAS_MARKINGS 19 +#define HAS_MARKINGS 18 /// Do not draw blood overlay -#define NOBLOODOVERLAY 20 +#define NOBLOODOVERLAY 19 ///No augments, for monkeys in specific because they will turn into fucking freakazoids https://cdn.discordapp.com/attachments/326831214667235328/791313258912153640/102707682-fa7cad80-4294-11eb-8f13-8c689468aeb0.png -#define NOAUGMENTS 21 +#define NOAUGMENTS 20 ///will be assigned a universal vampire themed last name shared by their department. this is preferenced! -#define BLOOD_CLANS 22 +#define BLOOD_CLANS 21 //organ slots #define ORGAN_SLOT_ADAMANTINE_RESONATOR "adamantine_resonator" @@ -149,7 +147,7 @@ #define CHROMOSOME_NONE 1 #define CHROMOSOME_USED 2 -//used for mob's genetic gender (mainly just for pronouns, members of sexed species with plural gender refer to their body_type for the actual sprites, which is not genetic) +//used for mob's genetic gender (mainly just for pronouns, members of sexed species with plural gender refer to their physique for the actual sprites, which is not genetic) #define G_MALE 1 #define G_FEMALE 2 #define G_PLURAL 3 @@ -187,42 +185,10 @@ GLOBAL_LIST_INIT(organ_process_order, list( ORGAN_SLOT_XENO_NEUROTOXINGLAND, ORGAN_SLOT_XENO_EGGSAC,)) -//Defines for Species IDs -#define SPECIES_HUMAN "human" -#define SPECIES_FELINE "felinid" -#define SPECIES_MOTH "moth" -#define SPECIES_ETHEREAL "ethereal" -#define SPECIES_PLASMAMAN "plasmaman" -#define SPECIES_FLY "fly" -#define SPECIES_MONKEY "monkey" -#define SPECIES_JELLYPERSON "jelly" -#define SPECIES_SLIMEPERSON "slime" -#define SPECIES_LUMINESCENT "lum" -#define SPECIES_STARGAZER "stargazer" -#define SPECIES_LIZARD "lizard" -#define SPECIES_LIZARD_ASH "ashlizard" -#define SPECIES_LIZARD_SILVER "silverlizard" -#define SPECIES_DULLAHAN "dullahan" -#define SPECIES_SKELETON "skeleton" -#define SPECIES_VAMPIRE "vampire" -#define SPECIES_ZOMBIE "memezombies" -#define SPECIES_ZOMBIE_HALLOWEEN "zombie" -#define SPECIES_ADDICT "goofzombies" - -#define SPECIES_ABDUCTOR "abductor" -#define SPECIES_ANDROID "android" -#define SPECIES_MUSHROOM "mush" -#define SPECIES_PODPERSON "pod" -#define SPECIES_SHADOW "shadow" -#define SPECIES_NIGHTMARE "nightmare" -#define SPECIES_SNAIL "snail" -#define SPECIES_SYNTH "synth" -#define SPECIES_SYNTH_MILITARY "military_synth" - //Defines for Golem Species IDs -#define SPECIES_GOLEM "iron_golem" -#define SPECIES_GOLEM_ADAMANTINE "adamantine_golem" -#define SPECIES_GOLEM_PLASMA "plasma_golem" +#define SPECIES_GOLEM "golem" +#define SPECIES_GOLEM_ADAMANTINE "a_golem" +#define SPECIES_GOLEM_PLASMA "p_golem" #define SPECIES_GOLEM_DIAMOND "diamond_golem" #define SPECIES_GOLEM_GOLD "gold_golem" #define SPECIES_GOLEM_SILVER "silver_golem" @@ -235,16 +201,16 @@ GLOBAL_LIST_INIT(organ_process_order, list( #define SPECIES_GOLEM_SAND "sand_golem" #define SPECIES_GOLEM_GLASS "glass_golem" #define SPECIES_GOLEM_BLUESPACE "bluespace_golem" -#define SPECIES_GOLEM_BANANIUM "bananium_golem" -#define SPECIES_GOLEM_CULT "runic_golem" -#define SPECIES_GOLEM_CLOTH "cloth_golem" +#define SPECIES_GOLEM_BANANIUM "ba_golem" +#define SPECIES_GOLEM_CULT "cultgolem" +#define SPECIES_GOLEM_CLOTH "clothgolem" #define SPECIES_GOLEM_PLASTIC "plastic_golem" #define SPECIES_GOLEM_BRONZE "bronze_golem" -#define SPECIES_GOLEM_CARDBOARD "cardboard_golem" +#define SPECIES_GOLEM_CARDBOARD "c_golem" #define SPECIES_GOLEM_LEATHER "leather_golem" -#define SPECIES_GOLEM_DURATHREAD "durathread_golem" -#define SPECIES_GOLEM_BONE "bone_golem" -#define SPECIES_GOLEM_SNOW "snow_golem" +#define SPECIES_GOLEM_DURATHREAD "d_golem" +#define SPECIES_GOLEM_BONE "b_golem" +#define SPECIES_GOLEM_SNOW "sn_golem" #define SPECIES_GOLEM_HYDROGEN "metallic_hydrogen_golem" // Defines for used in creating "perks" for the species preference pages. diff --git a/code/__DEFINES/bodyparts.dm b/code/__DEFINES/bodyparts.dm new file mode 100644 index 00000000000..5c575184273 --- /dev/null +++ b/code/__DEFINES/bodyparts.dm @@ -0,0 +1,2 @@ +///The standard amount of bodyparts a carbon has. Currently 6, HEAD/L_ARM/R_ARM/CHEST/L_LEG/R_LEG +#define BODYPARTS_DEFAULT_MAXIMUM 6 diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index b3dfa80cb8c..7ad02ab4525 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -125,13 +125,13 @@ #define ALT_STYLE 1 #define DIGITIGRADE_STYLE 2 -//flags for outfits that have mutantrace variants (try not to use this): Currently only needed if you're trying to add tight fitting bootyshorts -#define NO_MUTANTRACE_VARIATION 0 -#define MUTANTRACE_VARIATION 1 - -#define NOT_DIGITIGRADE 0 -#define FULL_DIGITIGRADE 1 -#define SQUISHED_DIGITIGRADE 2 +//Flags (actual flags, fucker ^) for /obj/item/var/supports_variations_flags +///No alternative sprites based on bodytype +#define CLOTHING_NO_VARIATION (1<<0) +///Has a sprite for digitigrade legs specifically. +#define CLOTHING_DIGITIGRADE_VARIATION (1<<1) +///The sprite works fine for digitigrade legs as-is. +#define CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON (1<<2) //flags for covering body parts #define GLASSESCOVERSEYES (1<<0) diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index cf2d69b7059..f712dc487d5 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -49,13 +49,11 @@ #define MOB_SPIRIT (1 << 9) #define MOB_PLANT (1 << 10) + //Organ defines for carbon mobs #define ORGAN_ORGANIC 1 #define ORGAN_ROBOTIC 2 -#define BODYPART_ORGANIC 1 -#define BODYPART_ROBOTIC 2 - #define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi' #define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi' @@ -63,7 +61,62 @@ #define ALIEN_BODYPART "alien" #define LARVA_BODYPART "larva" +//Bodypart change blocking flags +///Bodypart does not get replaced during set_species() +#define BP_BLOCK_CHANGE_SPECIES (1<<0) +//Bodytype defines for how things can be worn, surgery, and other misc things. +///The limb is organic +#define BODYTYPE_ORGANIC (1<<0) +///The limb is robotic +#define BODYTYPE_ROBOTIC (1<<1) +///The limb fits the human mold +#define BODYTYPE_HUMANOID (1<<2) +///The limb is digitigrade +#define BODYTYPE_DIGITIGRADE (1<<3) //Cancer +///The limb fits the monkey mold +#define BODYTYPE_MONKEY (1<<4) +///The limb is snouted +#define BODYTYPE_SNOUTED (1<<5) + +//Defines for Species IDs +#define SPECIES_ABDUCTOR "abductor" +#define SPECIES_ANDROID "android" +#define SPECIES_DULLAHAN "dullahan" +#define SPECIES_ETHEREAL "ethereal" +#define SPECIES_FELINE "felinid" +#define SPECIES_FLYPERSON "fly" +#define SPECIES_HUMAN "human" +#define SPECIES_JELLYPERSON "jelly" +#define SPECIES_SLIMEPERSON "slime" +#define SPECIES_LUMINESCENT "luminescent" +#define SPECIES_STARGAZER "stargazer" +#define SPECIES_LIZARD "lizard" +#define SPECIES_LIZARD_ASH "ashwalker" +#define SPECIES_LIZARD_SILVER "silverscale" +#define SPECIES_NIGHTMARE "nightmare" +#define SPECIES_MONKEY "monkey" +#define SPECIES_MOTH "moth" +#define SPECIES_MUSHROOM "mush" +#define SPECIES_PLASMAMAN "plasmaman" +#define SPECIES_PODPERSON "pod" +#define SPECIES_SHADOW "shadow" +#define SPECIES_SKELETON "skeleton" +#define SPECIES_SNAIL "snail" +#define SPECIES_VAMPIRE "vampire" +#define SPECIES_ZOMBIE "zombie" +#define SPECIES_ZOMBIE_INFECTIOUS "memezombie" +#define SPECIES_ZOMBIE_KROKODIL "krokodil_zombie" + +//See: datum/species/var/digitigrade_customization +///The species does not have digitigrade legs in generation. +#define DIGITIGRADE_NEVER 0 +///The species can have digitigrade legs in generation +#define DIGITIGRADE_OPTIONAL 1 +///The species is forced to have digitigrade legs in generation. +#define DIGITIGRADE_FORCED 2 + +//TODO: Remove entirely in favor of the BODYTYPE system ///Body type bitfields for allowed_animal_origin used to check compatible surgery body types (use NONE for no matching body type) #define HUMAN_BODY (1 << 0) #define MONKEY_BODY (1 << 1) diff --git a/code/__DEFINES/species_clothing_paths.dm b/code/__DEFINES/species_clothing_paths.dm new file mode 100644 index 00000000000..d1fb4f028aa --- /dev/null +++ b/code/__DEFINES/species_clothing_paths.dm @@ -0,0 +1,15 @@ +//HUMAN PATHS +///The dmi for humanoid uniforms +#define DEFAULT_UNIFORM_FILE 'icons/mob/clothing/under/default.dmi' +///The dmi for humanoid shoes +#define DEFAULT_SHOES_FILE 'icons/mob/clothing/feet.dmi' +///The dmi for humanoid oversuits +#define DEFAULT_SUIT_FILE 'icons/mob/clothing/suit.dmi' + +//DIGITIGRADE PATHS +///The dmi containing digitigrade uniforms +#define DIGITIGRADE_UNIFORM_FILE 'icons/mob/species/misc/digitigrade.dmi' +///The dmi containing digitigrade shoes +#define DIGITIGRADE_SHOES_FILE 'icons/mob/species/misc/digitigrade_shoes.dmi' +///The dmi containing digitigrade oversuits +#define DIGITIGRADE_SUIT_FILE 'icons/mob/species/misc/digitigrade_suits.dmi' diff --git a/code/__HELPERS/bodyparts.dm b/code/__HELPERS/bodyparts.dm new file mode 100644 index 00000000000..39df8e37e5f --- /dev/null +++ b/code/__HELPERS/bodyparts.dm @@ -0,0 +1 @@ +#define IS_ORGANIC_LIMB(limb) (limb.bodytype & BODYTYPE_ORGANIC) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 212cda4d758..5f9cef0db4a 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -1321,3 +1321,26 @@ GLOBAL_LIST_EMPTY(transformation_animation_objects) animate(src, pixel_x = pixel_x + shiftx, pixel_y = pixel_y + shifty, time = 0.2, loop = duration) pixel_x = initialpixelx pixel_y = initialpixely + +///Checks if the given iconstate exists in the given file, caching the result. Setting scream to TRUE will print a stack trace ONCE. +/proc/icon_exists(file, state, scream) + var/static/list/icon_states_cache = list() + if(icon_states_cache[file]?[state]) + return TRUE + + if(icon_states_cache[file]?[state] == FALSE) + return FALSE + + var/list/states = icon_states(file) + + if(!icon_states_cache[file]) + icon_states_cache[file] = list() + + if(state in states) + icon_states_cache[file][state] = TRUE + return TRUE + else + icon_states_cache[file][state] = FALSE + if(scream) + stack_trace("Icon Lookup for state: [state] in file [file] failed.") + return FALSE diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 2162eca1b80..1a8c9a6886a 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -153,7 +153,7 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH, return . /// For finding out what body parts a body zone covers, the inverse of the below basically -/proc/zone2body_parts_covered(def_zone) +/proc/body_zone2cover_flags(def_zone) switch(def_zone) if(BODY_ZONE_CHEST) return list(CHEST, GROIN) @@ -169,14 +169,14 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH, return list(LEG_RIGHT, FOOT_RIGHT) //Turns a Body_parts_covered bitfield into a list of organ/limb names. -//(I challenge you to find a use for this) -I found a use for it!! -/proc/body_parts_covered2organ_names(bpc) +//(I challenge you to find a use for this) -I found a use for it!! | So did I!. +/proc/cover_flags2body_zones(bpc) var/list/covered_parts = list() if(!bpc) return 0 - if(bpc & FULL_BODY) + if(bpc == FULL_BODY) covered_parts |= list(BODY_ZONE_L_ARM,BODY_ZONE_R_ARM,BODY_ZONE_HEAD,BODY_ZONE_CHEST,BODY_ZONE_L_LEG,BODY_ZONE_R_LEG) else diff --git a/code/__HELPERS/type_processing.dm b/code/__HELPERS/type_processing.dm index 4df4cece096..98aed39eba1 100644 --- a/code/__HELPERS/type_processing.dm +++ b/code/__HELPERS/type_processing.dm @@ -6,6 +6,7 @@ var/typename = "[type]" var/static/list/TYPES_SHORTCUTS = list( /obj/effect/decal/cleanable = "CLEANABLE", + /obj/item/bodypart = "BODYPART", /obj/item/radio/headset = "HEADSET", /obj/item/clothing/head/helmet/space = "SPESSHELMET", /obj/item/book/manual = "MANUAL", diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index cdd1cc60bcd..0be6e0c82ff 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -355,3 +355,18 @@ DEFINE_BITFIELD(reaction_flags, list( "REACTION_PH_VOL_CONSTANT" = REACTION_PH_VOL_CONSTANT, "REACTION_REAL_TIME_SPLIT" = REACTION_REAL_TIME_SPLIT, )) + +DEFINE_BITFIELD(bodytype, list( + "BODYTYPE_DIGITIGRADE" = BODYTYPE_DIGITIGRADE, + "BODYTYPE_HUMANOID" = BODYTYPE_HUMANOID, + "BODYTYPE_MONKEY" = BODYTYPE_MONKEY, + "BODYTYPE_ORGANIC" = BODYTYPE_ORGANIC, + "BODYTYPE_ROBOTIC" = BODYTYPE_ROBOTIC, + "BODYTYPE_SNOUTED" = BODYTYPE_SNOUTED, +)) + +DEFINE_BITFIELD(supports_variations_flags, list( + "CLOTHING_NO_VARIATION" = CLOTHING_NO_VARIATION, + "CLOTHING_DIGITIGRADE_VARIATION" = CLOTHING_DIGITIGRADE_VARIATION, + "CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON" = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON, +)) diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index 1394b074d33..64afd556a2a 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -493,7 +493,6 @@ GLOBAL_LIST_INIT(phobia_species, list( "conspiracies" = typecacheof(list( /datum/species/abductor, /datum/species/lizard, - /datum/species/synth, )), "insects" = typecacheof(list( /datum/species/fly, diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index 9c4b5053841..16c10c5fd3c 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -52,7 +52,7 @@ freak_out(O) return for(var/mob/living/carbon/human/HU in seen_atoms) //check equipment for trigger items - for(var/X in HU.get_all_slots() | HU.held_items) + for(var/X in HU.get_all_worn_items() | HU.held_items) var/obj/I = X if(!QDELETED(I) && (is_type_in_typecache(I, trigger_objs) || (phobia_type == "blood" && HAS_BLOOD_DNA(I)))) freak_out(I) @@ -213,7 +213,7 @@ /datum/brain_trauma/mild/phobia/guns phobia_type = "guns" random_gain = FALSE - + /datum/brain_trauma/mild/phobia/blood phobia_type = "blood" random_gain = FALSE diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm index 2a8189dc358..83dcdab0207 100644 --- a/code/datums/components/bloodysoles.dm +++ b/code/datums/components/bloodysoles.dm @@ -262,7 +262,7 @@ var/obj/item/bodypart/affecting = X if(affecting.body_part == LEG_RIGHT || affecting.body_part == LEG_LEFT) if(!affecting.bodypart_disabled) - FP.species_types |= affecting.species_id + FP.species_types |= affecting.limb_id break diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm index 590c7e84f7d..bbc1d422c68 100644 --- a/code/datums/components/caltrop.dm +++ b/code/datums/components/caltrop.dm @@ -89,7 +89,7 @@ if(!istype(O)) return - if(O.status == BODYPART_ROBOTIC) + if(!IS_ORGANIC_LIMB(O)) return if (!(flags & CALTROP_BYPASS_SHOES)) diff --git a/code/datums/components/creamed.dm b/code/datums/components/creamed.dm index 12e2f3e1660..53c92ba2513 100644 --- a/code/datums/components/creamed.dm +++ b/code/datums/components/creamed.dm @@ -25,9 +25,9 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list( if(ishuman(parent)) var/mob/living/carbon/human/H = parent - if(H.dna.species.limbs_id == "lizard") + if(H.dna.species.bodytype & BODYTYPE_SNOUTED) creamface.icon_state = "creampie_lizard" - else if(H.dna.species.limbs_id == "monkey") + else if(H.dna.species.bodytype & BODYTYPE_MONKEY) creamface.icon_state = "creampie_monkey" else creamface.icon_state = "creampie_human" diff --git a/code/datums/components/surgery_initiator.dm b/code/datums/components/surgery_initiator.dm index 4e41d6b2f81..4e66f8ab35c 100644 --- a/code/datums/components/surgery_initiator.dm +++ b/code/datums/components/surgery_initiator.dm @@ -89,7 +89,7 @@ if(affecting) if(!surgery.requires_bodypart) continue - if(surgery.requires_bodypart_type && affecting.status != surgery.requires_bodypart_type) + if(surgery.requires_bodypart_type && !(affecting.bodytype & surgery.requires_bodypart_type)) continue if(surgery.requires_real_bodypart && affecting.is_pseudopart) continue @@ -128,7 +128,7 @@ var/required_tool_type = TOOL_CAUTERY var/obj/item/close_tool = user.get_inactive_held_item() - var/is_robotic = the_surgery.requires_bodypart_type == BODYPART_ROBOTIC + var/is_robotic = the_surgery.requires_bodypart_type == BODYTYPE_ROBOTIC if(is_robotic) required_tool_type = TOOL_SCREWDRIVER @@ -300,7 +300,7 @@ return - if (!isnull(affecting_limb) && surgery.requires_bodypart_type && affecting_limb.status != surgery.requires_bodypart_type) + if (!isnull(affecting_limb) && surgery.requires_bodypart_type && !(affecting_limb.bodytype & surgery.requires_bodypart_type)) target.balloon_alert(user, "not the right type of limb!") return diff --git a/code/datums/components/unbreakable.dm b/code/datums/components/unbreakable.dm index 8261dd6d3cb..0d27f7bc39c 100644 --- a/code/datums/components/unbreakable.dm +++ b/code/datums/components/unbreakable.dm @@ -24,7 +24,7 @@ return COOLDOWN_START(src, surge_cooldown, 1 MINUTES) surged.balloon_alert(surged, "you refuse to give up!")//breaks balloon alert conventions by using a "!" for a fail message but that's okay because it's a pretty awesome moment - surged.heal_overall_damage(15, 15, 0, BODYPART_ORGANIC) + surged.heal_overall_damage(15, 15, 0, BODYTYPE_ORGANIC) if(surged.reagents.get_reagent_amount(/datum/reagent/medicine/ephedrine) < 20) surged.reagents.add_reagent(/datum/reagent/medicine/ephedrine, 10) if(surged.reagents.get_reagent_amount(/datum/reagent/medicine/epinephrine) < 20) diff --git a/code/datums/diseases/advance/symptoms/fire.dm b/code/datums/diseases/advance/symptoms/fire.dm index 240abf84603..edb0d6e4aa4 100644 --- a/code/datums/diseases/advance/symptoms/fire.dm +++ b/code/datums/diseases/advance/symptoms/fire.dm @@ -71,14 +71,14 @@ Bonus /datum/symptom/fire/proc/Firestacks_stage_4(mob/living/M, datum/disease/advance/A) M.adjust_fire_stacks(1 * power) - M.take_overall_damage(burn = 3 * power, required_status = BODYPART_ORGANIC) + M.take_overall_damage(burn = 3 * power, required_status = BODYTYPE_ORGANIC) if(infective) A.spread(2) return 1 /datum/symptom/fire/proc/Firestacks_stage_5(mob/living/M, datum/disease/advance/A) M.adjust_fire_stacks(3 * power) - M.take_overall_damage(burn = 5 * power, required_status = BODYPART_ORGANIC) + M.take_overall_damage(burn = 5 * power, required_status = BODYTYPE_ORGANIC) if(infective) A.spread(4) return 1 @@ -164,7 +164,7 @@ Bonus /datum/symptom/alkali/proc/Alkali_fire_stage_4(mob/living/M, datum/disease/advance/A) var/get_stacks = 6 * power M.adjust_fire_stacks(get_stacks) - M.take_overall_damage(burn = get_stacks / 2, required_status = BODYPART_ORGANIC) + M.take_overall_damage(burn = get_stacks / 2, required_status = BODYTYPE_ORGANIC) if(chems) M.reagents.add_reagent(/datum/reagent/clf3, 2 * power) return 1 @@ -172,7 +172,7 @@ Bonus /datum/symptom/alkali/proc/Alkali_fire_stage_5(mob/living/M, datum/disease/advance/A) var/get_stacks = 8 * power M.adjust_fire_stacks(get_stacks) - M.take_overall_damage(burn = get_stacks, required_status = BODYPART_ORGANIC) + M.take_overall_damage(burn = get_stacks, required_status = BODYTYPE_ORGANIC) if(chems) M.reagents.add_reagent_list(list(/datum/reagent/napalm = 4 * power, /datum/reagent/clf3 = 4 * power)) return 1 diff --git a/code/datums/diseases/advance/symptoms/flesh_eating.dm b/code/datums/diseases/advance/symptoms/flesh_eating.dm index 45fedd8947f..65b19657da6 100644 --- a/code/datums/diseases/advance/symptoms/flesh_eating.dm +++ b/code/datums/diseases/advance/symptoms/flesh_eating.dm @@ -59,7 +59,7 @@ Bonus /datum/symptom/flesh_eating/proc/Flesheat(mob/living/M, datum/disease/advance/A) var/get_damage = rand(15,25) * power - M.take_overall_damage(brute = get_damage, required_status = BODYPART_ORGANIC) + M.take_overall_damage(brute = get_damage, required_status = BODYTYPE_ORGANIC) if(pain) M.adjustStaminaLoss(get_damage * 2) if(bleed) @@ -131,7 +131,7 @@ Bonus /datum/symptom/flesh_death/proc/Flesh_death(mob/living/M, datum/disease/advance/A) var/get_damage = rand(6,10) - M.take_overall_damage(brute = get_damage, required_status = BODYPART_ORGANIC) + M.take_overall_damage(brute = get_damage, required_status = BODYTYPE_ORGANIC) if(chems) M.reagents.add_reagent_list(list(/datum/reagent/toxin/heparin = 2, /datum/reagent/toxin/lipolicide = 2)) if(zombie) diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index 973fad09349..b9088b7efb5 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -160,13 +160,13 @@ M.adjustToxLoss(-(4 * heal_amt)) //most effective on toxins - var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYPART_ORGANIC) + var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYTYPE_ORGANIC) if(!parts.len) return for(var/obj/item/bodypart/L in parts) - if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len, null, BODYPART_ORGANIC)) + if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len, null, BODYTYPE_ORGANIC)) M.update_damage_overlays() return 1 @@ -278,7 +278,7 @@ /datum/symptom/heal/darkness/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power) var/heal_amt = 2 * actual_power - var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYPART_ORGANIC) + var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYTYPE_ORGANIC) if(!parts.len) return @@ -287,7 +287,7 @@ to_chat(M, span_notice("The darkness soothes and mends your wounds.")) for(var/obj/item/bodypart/L in parts) - if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len * 0.5, null, BODYPART_ORGANIC)) //more effective on brute + if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len * 0.5, null, BODYTYPE_ORGANIC)) //more effective on brute M.update_damage_overlays() return 1 @@ -381,7 +381,7 @@ return for(var/obj/item/bodypart/L in parts) - if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len, null, BODYPART_ORGANIC)) + if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len, null, BODYTYPE_ORGANIC)) M.update_damage_overlays() if(active_coma && M.getBruteLoss() + M.getFireLoss() == 0) @@ -434,7 +434,7 @@ /datum/symptom/heal/water/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power) var/heal_amt = 2 * actual_power - var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYPART_ORGANIC) //more effective on burns + var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYTYPE_ORGANIC) //more effective on burns if(!parts.len) return @@ -443,7 +443,7 @@ to_chat(M, span_notice("You feel yourself absorbing the water around you to soothe your damaged skin.")) for(var/obj/item/bodypart/L in parts) - if(L.heal_damage(heal_amt/parts.len * 0.5, heal_amt/parts.len, null, BODYPART_ORGANIC)) + if(L.heal_damage(heal_amt/parts.len * 0.5, heal_amt/parts.len, null, BODYTYPE_ORGANIC)) M.update_damage_overlays() return 1 @@ -514,13 +514,13 @@ M.adjustToxLoss(-heal_amt) - var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYPART_ORGANIC) + var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYTYPE_ORGANIC) if(!parts.len) return if(prob(5)) to_chat(M, span_notice("The pain from your wounds fades rapidly.")) for(var/obj/item/bodypart/L in parts) - if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len, null, BODYPART_ORGANIC)) + if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len, null, BODYTYPE_ORGANIC)) M.update_damage_overlays() return 1 @@ -564,7 +564,7 @@ M.adjustToxLoss(-(2 * heal_amt)) - var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYPART_ORGANIC) + var/list/parts = M.get_damaged_bodyparts(1,1, null, BODYTYPE_ORGANIC) if(!parts.len) return @@ -573,6 +573,6 @@ to_chat(M, span_notice("Your skin glows faintly, and you feel your wounds mending themselves.")) for(var/obj/item/bodypart/L in parts) - if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len, null, BODYPART_ORGANIC)) + if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len, null, BODYTYPE_ORGANIC)) M.update_damage_overlays() return 1 diff --git a/code/datums/diseases/advance/symptoms/itching.dm b/code/datums/diseases/advance/symptoms/itching.dm index 98318060f28..6d6c2b843fb 100644 --- a/code/datums/diseases/advance/symptoms/itching.dm +++ b/code/datums/diseases/advance/symptoms/itching.dm @@ -51,7 +51,7 @@ BONUS var/mob/living/carbon/M = A.affected_mob var/picked_bodypart = pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) var/obj/item/bodypart/bodypart = M.get_bodypart(picked_bodypart) - if(bodypart && bodypart.status == BODYPART_ORGANIC && !bodypart.is_pseudopart) //robotic limbs will mean less scratching overall (why are golems able to damage themselves with self-scratching, but not androids? the world may never know) + if(bodypart && IS_ORGANIC_LIMB(bodypart) && !bodypart.is_pseudopart) //robotic limbs will mean less scratching overall (why are golems able to damage themselves with self-scratching, but not androids? the world may never know) var/can_scratch = scratch && !M.incapacitated() M.visible_message("[can_scratch ? span_warning("[M] scratches [M.p_their()] [bodypart.name].") : ""]", span_warning("Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]")) if(can_scratch) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index b7498d257e6..c7566579bea 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -489,9 +489,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) /mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) ..() if(icon_update) - update_body() - update_hair() - update_body_parts() + update_body(is_creating = TRUE) update_mutations_overlay()// no lizard with human hulk overlay please. @@ -533,9 +531,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) domutcheck() if(mrace || newfeatures || ui) - update_body() - update_hair() - update_body_parts() + update_body(is_creating = TRUE) update_mutations_overlay() if(LAZYLEN(mutations)) @@ -615,9 +611,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(icon_update) dna.species.handle_body(src) // We want 'update_body_parts()' to be called only if mutcolor_update is TRUE, so no 'update_body()' here. - update_hair() + update_hair(is_creating = TRUE) if(mutcolor_update) - update_body_parts() + update_body_parts(update_limb_data = TRUE) if(mutations_overlay_update) update_mutations_overlay() diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index dd6753166ef..466c6b328b8 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -506,7 +506,7 @@ if(brain) //so this doesn't instantly kill you. we could delete the brain, but it lets people cure brain issues they /really/ shouldn't be brain.zone = BODY_ZONE_HEAD UnregisterSignal(owner, COMSIG_CARBON_ATTACH_LIMB) - var/successful = owner.regenerate_limb(BODY_ZONE_HEAD, noheal = TRUE) //noheal needs to be TRUE to prevent weird adding and removing mutation healing + var/successful = owner.regenerate_limb(BODY_ZONE_HEAD) if(!successful) stack_trace("HARS mutation head regeneration failed! (usually caused by headless syndrome having a head)") return TRUE diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 0b39d88cc98..16e4b4d5018 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -110,7 +110,7 @@ * * attack_direction: For bloodsplatters, if relevant */ /datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null) - if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || !L.is_organic_limb() || HAS_TRAIT(L.owner, TRAIT_NEVER_WOUNDED)) + if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || !IS_ORGANIC_LIMB(L) || HAS_TRAIT(L.owner, TRAIT_NEVER_WOUNDED)) qdel(src) return diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 5558d9b68b2..c481eb3eba6 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -48,7 +48,7 @@ I = victim.get_inactive_held_item() if(I && victim.dropItemToGround(I)) - victim.visible_message(span_danger("[victim] drops [I] in shock!"), span_warning("The force on your [limb.name] causes you to drop [I]!"), vision_distance=COMBAT_MESSAGE_RANGE) + victim.visible_message(span_danger("[victim] drops [I] in shock!"), span_warning("The force on your [parse_zone(limb.body_zone)] causes you to drop [I]!"), vision_distance=COMBAT_MESSAGE_RANGE) update_inefficiencies() @@ -91,7 +91,7 @@ if(!victim || !limb) qdel(src) return - to_chat(victim, span_green("Your [limb.name] has recovered from its [name]!")) + to_chat(victim, span_green("Your [parse_zone(limb.body_zone)] has recovered from its [name]!")) remove_wound() /// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so @@ -105,11 +105,11 @@ if(prob((severity - 1) * 15)) // And you have a 70% or 50% chance to actually land the blow, respectively if(prob(70 - 20 * (severity - 1))) - to_chat(victim, span_userdanger("The fracture in your [limb.name] shoots with pain as you strike [target]!")) + to_chat(victim, span_userdanger("The fracture in your [parse_zone(limb.body_zone)] shoots with pain as you strike [target]!")) limb.receive_damage(brute=rand(1,5)) else - victim.visible_message(span_danger("[victim] weakly strikes [target] with [victim.p_their()] broken [limb.name], recoiling from pain!"), \ - span_userdanger("You fail to strike [target] as the fracture in your [limb.name] lights up in unbearable pain!"), vision_distance=COMBAT_MESSAGE_RANGE) + victim.visible_message(span_danger("[victim] weakly strikes [target] with [victim.p_their()] broken [parse_zone(limb.body_zone)], recoiling from pain!"), \ + span_userdanger("You fail to strike [target] as the fracture in your [parse_zone(limb.body_zone)] lights up in unbearable pain!"), vision_distance=COMBAT_MESSAGE_RANGE) INVOKE_ASYNC(victim, /mob.proc/emote, "scream") victim.Stun(0.5 SECONDS) limb.receive_damage(brute=rand(3,7)) @@ -149,7 +149,7 @@ var/list/msg = list() if(!limb.current_gauze) - msg += "[victim.p_their(TRUE)] [limb.name] [examine_desc]" + msg += "[victim.p_their(TRUE)] [parse_zone(limb.body_zone)] [examine_desc]" else var/sling_condition = "" // how much life we have left in these bandages @@ -163,7 +163,7 @@ if(4 to INFINITY) sling_condition = "tightly" - msg += "[victim.p_their(TRUE)] [limb.name] is [sling_condition] fastened in a sling of [limb.current_gauze.name]" + msg += "[victim.p_their(TRUE)] [parse_zone(limb.body_zone)] is [sling_condition] fastened in a sling of [limb.current_gauze.name]" if(taped) msg += ", [span_notice("and appears to be reforming itself under some surgical tape!")]" @@ -231,7 +231,7 @@ /datum/wound/blunt/moderate/proc/door_crush() SIGNAL_HANDLER if(prob(40)) - victim.visible_message(span_danger("[victim]'s dislocated [limb.name] pops back into place!"), span_userdanger("Your dislocated [limb.name] pops back into place! Ow!")) + victim.visible_message(span_danger("[victim]'s dislocated [parse_zone(limb.body_zone)] pops back into place!"), span_userdanger("Your dislocated [parse_zone(limb.body_zone)] pops back into place! Ow!")) remove_wound() /datum/wound/blunt/moderate/try_handling(mob/living/carbon/human/user) @@ -243,8 +243,8 @@ return TRUE if(user.grab_state >= GRAB_AGGRESSIVE) - user.visible_message(span_danger("[user] begins twisting and straining [victim]'s dislocated [limb.name]!"), span_notice("You begin twisting and straining [victim]'s dislocated [limb.name]..."), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] begins twisting and straining your dislocated [limb.name]!")) + user.visible_message(span_danger("[user] begins twisting and straining [victim]'s dislocated [parse_zone(limb.body_zone)]!"), span_notice("You begin twisting and straining [victim]'s dislocated [parse_zone(limb.body_zone)]..."), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] begins twisting and straining your dislocated [parse_zone(limb.body_zone)]!")) if(!user.combat_mode) chiropractice(user) else @@ -259,14 +259,14 @@ return if(prob(65)) - user.visible_message(span_danger("[user] snaps [victim]'s dislocated [limb.name] back into place!"), span_notice("You snap [victim]'s dislocated [limb.name] back into place!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] snaps your dislocated [limb.name] back into place!")) + user.visible_message(span_danger("[user] snaps [victim]'s dislocated [parse_zone(limb.body_zone)] back into place!"), span_notice("You snap [victim]'s dislocated [parse_zone(limb.body_zone)] back into place!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] snaps your dislocated [parse_zone(limb.body_zone)] back into place!")) victim.emote("scream") limb.receive_damage(brute=20, wound_bonus=CANT_WOUND) qdel(src) else - user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [limb.name] around painfully!"), span_danger("You wrench [victim]'s dislocated [limb.name] around painfully!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] wrenches your dislocated [limb.name] around painfully!")) + user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), span_danger("You wrench [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] wrenches your dislocated [parse_zone(limb.body_zone)] around painfully!")) limb.receive_damage(brute=10, wound_bonus=CANT_WOUND) chiropractice(user) @@ -278,33 +278,33 @@ return if(prob(65)) - user.visible_message(span_danger("[user] snaps [victim]'s dislocated [limb.name] with a sickening crack!"), span_danger("You snap [victim]'s dislocated [limb.name] with a sickening crack!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] snaps your dislocated [limb.name] with a sickening crack!")) + user.visible_message(span_danger("[user] snaps [victim]'s dislocated [parse_zone(limb.body_zone)] with a sickening crack!"), span_danger("You snap [victim]'s dislocated [parse_zone(limb.body_zone)] with a sickening crack!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] snaps your dislocated [parse_zone(limb.body_zone)] with a sickening crack!")) victim.emote("scream") limb.receive_damage(brute=25, wound_bonus=30) else - user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [limb.name] around painfully!"), span_danger("You wrench [victim]'s dislocated [limb.name] around painfully!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] wrenches your dislocated [limb.name] around painfully!")) + user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), span_danger("You wrench [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] wrenches your dislocated [parse_zone(limb.body_zone)] around painfully!")) limb.receive_damage(brute=10, wound_bonus=CANT_WOUND) malpractice(user) /datum/wound/blunt/moderate/treat(obj/item/I, mob/user) if(victim == user) - victim.visible_message(span_danger("[user] begins resetting [victim.p_their()] [limb.name] with [I]."), span_warning("You begin resetting your [limb.name] with [I]...")) + victim.visible_message(span_danger("[user] begins resetting [victim.p_their()] [parse_zone(limb.body_zone)] with [I]."), span_warning("You begin resetting your [parse_zone(limb.body_zone)] with [I]...")) else - user.visible_message(span_danger("[user] begins resetting [victim]'s [limb.name] with [I]."), span_notice("You begin resetting [victim]'s [limb.name] with [I]...")) + user.visible_message(span_danger("[user] begins resetting [victim]'s [parse_zone(limb.body_zone)] with [I]."), span_notice("You begin resetting [victim]'s [parse_zone(limb.body_zone)] with [I]...")) if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists))) return if(victim == user) limb.receive_damage(brute=15, wound_bonus=CANT_WOUND) - victim.visible_message(span_danger("[user] finishes resetting [victim.p_their()] [limb.name]!"), span_userdanger("You reset your [limb.name]!")) + victim.visible_message(span_danger("[user] finishes resetting [victim.p_their()] [parse_zone(limb.body_zone)]!"), span_userdanger("You reset your [parse_zone(limb.body_zone)]!")) else limb.receive_damage(brute=10, wound_bonus=CANT_WOUND) - user.visible_message(span_danger("[user] finishes resetting [victim]'s [limb.name]!"), span_nicegreen("You finish resetting [victim]'s [limb.name]!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] resets your [limb.name]!")) + user.visible_message(span_danger("[user] finishes resetting [victim]'s [parse_zone(limb.body_zone)]!"), span_nicegreen("You finish resetting [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] resets your [parse_zone(limb.body_zone)]!")) victim.emote("scream") qdel(src) @@ -375,10 +375,10 @@ return if(gelled) - to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.name] is already coated with bone gel!")) + to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] is already coated with bone gel!")) return - user.visible_message(span_danger("[user] begins hastily applying [I] to [victim]'s' [limb.name]..."), span_warning("You begin hastily applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name], disregarding the warning label...")) + user.visible_message(span_danger("[user] begins hastily applying [I] to [victim]'s' [parse_zone(limb.body_zone)]..."), span_warning("You begin hastily applying [I] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)], disregarding the warning label...")) if(!do_after(user, base_treat_time * 1.5 * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists))) return @@ -386,8 +386,8 @@ I.use(1) victim.emote("scream") if(user != victim) - user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [limb.name], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [limb.name]!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] finishes applying [I] to your [limb.name], and you can feel the bones exploding with pain as they begin melting and reforming!")) + user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [parse_zone(limb.body_zone)], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] finishes applying [I] to your [parse_zone(limb.body_zone)], and you can feel the bones exploding with pain as they begin melting and reforming!")) else var/painkiller_bonus = 0 if(victim.drunkenness > 10) @@ -402,10 +402,10 @@ painkiller_bonus += 20 if(prob(25 + (20 * (severity - 2)) - painkiller_bonus)) // 25%/45% chance to fail self-applying with severe and critical wounds, modded by painkillers - victim.visible_message(span_danger("[victim] fails to finish applying [I] to [victim.p_their()] [limb.name], passing out from the pain!"), span_notice("You pass out from the pain of applying [I] to your [limb.name] before you can finish!")) + victim.visible_message(span_danger("[victim] fails to finish applying [I] to [victim.p_their()] [parse_zone(limb.body_zone)], passing out from the pain!"), span_notice("You pass out from the pain of applying [I] to your [parse_zone(limb.body_zone)] before you can finish!")) victim.AdjustUnconscious(5 SECONDS) return - victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [limb.name], grimacing from the pain!"), span_notice("You finish applying [I] to your [limb.name], and your bones explode in pain!")) + victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [parse_zone(limb.body_zone)], grimacing from the pain!"), span_notice("You finish applying [I] to your [parse_zone(limb.body_zone)], and your bones explode in pain!")) limb.receive_damage(25, stamina=100, wound_bonus=CANT_WOUND) gelled = TRUE @@ -416,20 +416,20 @@ return // poser if(gelled) - to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.name] is already coated with bone gel!")) + to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] is already coated with bone gel!")) return - user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [limb.name]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...")) + user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [parse_zone(limb.body_zone)]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]...")) if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists))) return I.use(1) if(user != victim) - user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [limb.name], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [limb.name]!"), ignored_mobs=victim) - to_chat(victim, span_userdanger("[user] finishes applying [I] to your [limb.name], and you feel a funny fizzy tickling as they begin to reform!")) + user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [parse_zone(limb.body_zone)], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim) + to_chat(victim, span_userdanger("[user] finishes applying [I] to your [parse_zone(limb.body_zone)], and you feel a funny fizzy tickling as they begin to reform!")) else - victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [limb.name], emitting a funny fizzing sound!"), span_notice("You finish applying [I] to your [limb.name], and feel a funny fizzy tickling as the bone begins to reform!")) + victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [parse_zone(limb.body_zone)], emitting a funny fizzing sound!"), span_notice("You finish applying [I] to your [parse_zone(limb.body_zone)], and feel a funny fizzy tickling as the bone begins to reform!")) gelled = TRUE processes = TRUE @@ -437,13 +437,13 @@ /// if someone is using surgical tape on our wound /datum/wound/blunt/proc/tape(obj/item/stack/sticky_tape/surgical/I, mob/user) if(!gelled) - to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.name] must be coated with bone gel to perform this emergency operation!")) + to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] must be coated with bone gel to perform this emergency operation!")) return if(taped) - to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.name] is already wrapped in [I.name] and reforming!")) + to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] is already wrapped in [I.name] and reforming!")) return - user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [limb.name]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...")) + user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [parse_zone(limb.body_zone)]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]...")) if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, .proc/still_exists))) return @@ -453,10 +453,10 @@ I.use(1) if(user != victim) - user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [limb.name], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [limb.name]!"), ignored_mobs=victim) - to_chat(victim, span_green("[user] finishes applying [I] to your [limb.name], you immediately begin to feel your bones start to reform!")) + user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [parse_zone(limb.body_zone)], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim) + to_chat(victim, span_green("[user] finishes applying [I] to your [parse_zone(limb.body_zone)], you immediately begin to feel your bones start to reform!")) else - victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [limb.name], !"), span_green("You finish applying [I] to your [limb.name], and you immediately begin to feel your bones start to reform!")) + victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [parse_zone(limb.body_zone)], !"), span_green("You finish applying [I] to your [parse_zone(limb.body_zone)], and you immediately begin to feel your bones start to reform!")) taped = TRUE processes = TRUE diff --git a/code/datums/wounds/scars/_scars.dm b/code/datums/wounds/scars/_scars.dm index 514f99cc687..442923dc322 100644 --- a/code/datums/wounds/scars/_scars.dm +++ b/code/datums/wounds/scars/_scars.dm @@ -87,7 +87,7 @@ /// Used to "load" a persistent scar /datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE, biology=BIO_FLESH_BONE, char_slot) - if(!BP.is_organic_limb()) + if(!IS_ORGANIC_LIMB(BP)) qdel(src) return diff --git a/code/game/atoms.dm b/code/game/atoms.dm index fbfd49acef6..4785b010945 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -672,6 +672,9 @@ * Produces a signal [COMSIG_PARENT_EXAMINE_MORE] */ /atom/proc/examine_more(mob/user) + SHOULD_CALL_PARENT(TRUE) + RETURN_TYPE(/list) + . = list() SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE_MORE, user, .) diff --git a/code/game/machinery/computer/arcade/arcade.dm b/code/game/machinery/computer/arcade/arcade.dm index 69a9b80a75b..1f6e3ecb07d 100644 --- a/code/game/machinery/computer/arcade/arcade.dm +++ b/code/game/machinery/computer/arcade/arcade.dm @@ -602,14 +602,15 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( return ..() //well boys we did it, lists are no more /obj/machinery/computer/arcade/battle/examine_more(mob/user) - var/list/msg = list(span_notice("You notice some writing scribbled on the side of [src]...")) - msg += "\t[span_info("smart -> defend, defend, light attack")]" - msg += "\t[span_info("shotgun -> defend, defend, power attack")]" - msg += "\t[span_info("short temper -> counter, counter, counter")]" - msg += "\t[span_info("poisonous -> light attack, light attack, light attack")]" - msg += "\t[span_info("chonker -> power attack, power attack, power attack")]" - msg += "\t[span_info("magical -> defend until outmagiced")]" - return msg + . = ..() + . += span_notice("You notice some writing scribbled on the side of [src]...") + . += "\t[span_info("smart -> defend, defend, light attack")]" + . += "\t[span_info("shotgun -> defend, defend, power attack")]" + . += "\t[span_info("short temper -> counter, counter, counter")]" + . += "\t[span_info("poisonous -> light attack, light attack, light attack")]" + . += "\t[span_info("chonker -> power attack, power attack, power attack")]" + . += "\t[span_info("magical -> defend until outmagiced")]" + return . /obj/machinery/computer/arcade/battle/emag_act(mob/user) if(obj_flags & EMAGGED) diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 06863d274b7..067c64e6340 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -194,10 +194,10 @@ reagents.remove_reagent(reagent_id, modified_consumed_reagents_list[reagent_id]) var/built_typepath = being_built.build_path - // If we have a bodypart, we need to initialize the limb on its own. Otherwise we can build it here. if(ispath(built_typepath, /obj/item/bodypart)) - build_limb(built_typepath) + build_limb(create_buildpath()) else + //Just build whatever it is new built_typepath(loc) busy = FALSE @@ -214,26 +214,24 @@ */ /obj/machinery/limbgrower/proc/build_limb(buildpath) /// The limb we're making with our buildpath, so we can edit it. - var/obj/item/bodypart/limb = new buildpath(loc) - /// Species with greyscale limbs. - var/list/greyscale_species = list(SPECIES_HUMAN, SPECIES_LIZARD, SPECIES_ETHEREAL) - if(selected_category in greyscale_species) //Species with greyscale parts should be included here - if(selected_category == SPECIES_HUMAN) //humans don't use the full colour spectrum, they use random_skin_tone - limb.skin_tone = random_skin_tone() - else - limb.species_color = "#[random_color()]" - limb.icon = 'icons/mob/human_parts_greyscale.dmi' - limb.should_draw_greyscale = TRUE - else - limb.icon = 'icons/mob/human_parts.dmi' - - // Set this limb up using the species name and body zone - limb.icon_state = "[selected_category]_[limb.body_zone]" - limb.name = "\improper biosynthetic [selected_category] [parse_zone(limb.body_zone)]" - limb.desc = "A synthetically produced [selected_category] limb, grown in a tube. This one is for the [parse_zone(limb.body_zone)]." - limb.species_id = selected_category + //i need to create a body part manually using a set icon (otherwise it doesnt appear) + var/obj/item/bodypart/limb + limb = new buildpath(loc) + limb.name = "\improper synthetic [selected_category] [parse_zone(limb.body_zone)]" + limb.limb_id = selected_category + limb.mutation_color = "#62A262" limb.update_icon_dropped() - limb.original_owner = WEAKREF(src) //prevents updating the icon, so a lizard arm on a human stays a lizard arm etc. + +///Returns a valid limb typepath based on the selected option +/obj/machinery/limbgrower/proc/create_buildpath() + var/part_type = being_built.id //their ids match bodypart typepaths + var/species = selected_category + var/path + if(species == SPECIES_HUMAN) //Humans use the parent type. + path = "/obj/item/bodypart/[part_type]" + else + path = "/obj/item/bodypart/[part_type]/[species]" + return text2path(path) /obj/machinery/limbgrower/RefreshParts() reagents.maximum_volume = 0 diff --git a/code/game/objects/effects/contraband.dm b/code/game/objects/effects/contraband.dm index 142c0b92639..7aa407b2998 100644 --- a/code/game/objects/effects/contraband.dm +++ b/code/game/objects/effects/contraband.dm @@ -468,11 +468,12 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/contraband/random, 32) icon_state = "gas_power" /obj/structure/sign/poster/contraband/donk_co/examine_more(mob/user) - var/list/msg = list(span_notice("You browse some of the poster's information...")) - msg += "\t[span_info("DONK CO. BRAND DONK POCKETS: IRRESISTABLY DONK!")]" - msg += "\t[span_info("AVAILABLE IN OVER 200 DONKTASTIC FLAVOURS: TRY CLASSIC MEAT, HOT AND SPICY, NEW YORK PEPPERONI PIZZA, BREAKFAST SAUSAGE AND EGG, PHILADELPHIA CHEESESTEAK, HAMBURGER DONK-A-RONI, CHEESE-O-RAMA, AND MANY MORE!")]" - msg += "\t[span_info("AVAILABLE FROM ALL GOOD RETAILERS, AND MANY BAD ONES TOO!")]" - return msg + . = ..() + . += span_notice("You browse some of the poster's information...") + . += "\t[span_info("DONK CO. BRAND DONK POCKETS: IRRESISTABLY DONK!")]" + . += "\t[span_info("AVAILABLE IN OVER 200 DONKTASTIC FLAVOURS: TRY CLASSIC MEAT, HOT AND SPICY, NEW YORK PEPPERONI PIZZA, BREAKFAST SAUSAGE AND EGG, PHILADELPHIA CHEESESTEAK, HAMBURGER DONK-A-RONI, CHEESE-O-RAMA, AND MANY MORE!")]" + . += "\t[span_info("AVAILABLE FROM ALL GOOD RETAILERS, AND MANY BAD ONES TOO!")]" + return . /obj/structure/sign/poster/contraband/cybersun_six_hundred name = "Saibāsan: 600 Years Commemorative Poster" @@ -734,15 +735,16 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/poster/official/random, 32) icon_state = "plasma_effects" /obj/structure/sign/poster/official/plasma_effects/examine_more(mob/user) - var/list/msg = list(span_notice("You browse some of the poster's information...")) - msg += "\t[span_info("Plasma (scientific name Amenthium) is classified by TerraGov as a Grade 1 Health Hazard, and has significant risks to health associated with chronic exposure.")]" - msg += "\t[span_info("Plasma is known to cross the blood/brain barrier and bioaccumulate in brain tissue, where it begins to result in degradation of brain function. The mechanism for attack is not yet fully known, and as such no concrete preventative advice is available barring proper use of PPE (gloves + protective jumpsuit + respirator).")]" - msg += "\t[span_info("In small doses, plasma induces confusion, short-term amnesia, and heightened aggression. These effects persist with continual exposure.")]" - msg += "\t[span_info("In individuals with chronic exposure, severe effects have been noted. Further heightened aggression, long-term amnesia, Alzheimer's symptoms, schizophrenia, macular degeneration, aneurysms, heightened risk of stroke, and Parkinsons symptoms have all been noted.")]" - msg += "\t[span_info("It is recommended that all individuals in unprotected contact with raw plasma regularly check with company health officials.")]" - msg += "\t[span_info("For more information, please check with TerraGov's extranet site on Amenthium: www.terra.gov/health_and_safety/amenthium/, or our internal risk-assessment documents (document numbers #47582-b (Plasma safety data sheets) and #64210 through #64225 (PPE regulations for working with Plasma), available via NanoDoc to all employees).")]" - msg += "\t[span_info("Nanotrasen: Always looking after your health.")]" - return msg + . = ..() + . += span_notice("You browse some of the poster's information...") + . += "\t[span_info("Plasma (scientific name Amenthium) is classified by TerraGov as a Grade 1 Health Hazard, and has significant risks to health associated with chronic exposure.")]" + . += "\t[span_info("Plasma is known to cross the blood/brain barrier and bioaccumulate in brain tissue, where it begins to result in degradation of brain function. The mechanism for attack is not yet fully known, and as such no concrete preventative advice is available barring proper use of PPE (gloves + protective jumpsuit + respirator).")]" + . += "\t[span_info("In small doses, plasma induces confusion, short-term amnesia, and heightened aggression. These effects persist with continual exposure.")]" + . += "\t[span_info("In individuals with chronic exposure, severe effects have been noted. Further heightened aggression, long-term amnesia, Alzheimer's symptoms, schizophrenia, macular degeneration, aneurysms, heightened risk of stroke, and Parkinsons symptoms have all been noted.")]" + . += "\t[span_info("It is recommended that all individuals in unprotected contact with raw plasma regularly check with company health officials.")]" + . += "\t[span_info("For more information, please check with TerraGov's extranet site on Amenthium: www.terra.gov/health_and_safety/amenthium/, or our internal risk-assessment documents (document numbers #47582-b (Plasma safety data sheets) and #64210 through #64225 (PPE regulations for working with Plasma), available via NanoDoc to all employees).")]" + . += "\t[span_info("Nanotrasen: Always looking after your health.")]" + return . /obj/structure/sign/poster/official/terragov name = "TerraGov: United for Humanity" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d330ceb0180..e9fb99dd5e8 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -149,6 +149,8 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e var/list/attack_verb_simple ///list() of species types, if a species cannot put items in a certain slot, but species type is in list, it will be able to wear that item var/list/species_exception = null + ///This is a bitfield that defines what variations exist for bodyparts like Digi legs. See: code\_DEFINES\inventory.dm + var/supports_variations_flags = NONE ///A weakref to the mob who threw the item var/datum/weakref/thrownby = null //I cannot verbally describe how much I hate this var diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index ab4d0b6aa90..2f7e99a195e 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -680,31 +680,32 @@ . += span_notice("There's more information below, you can look again to take a closer look...") /obj/item/card/id/examine_more(mob/user) - var/list/msg = list(span_notice("You examine [src] closer, and note the following...")) + . = ..() + . += span_notice("You examine [src] closer, and note the following...") if(registered_age) - msg += "The card indicates that the holder is [registered_age] years old. [(registered_age < AGE_MINOR) ? "There's a holographic stripe that reads [span_danger("'MINOR: DO NOT SERVE ALCOHOL OR TOBACCO'")] along the bottom of the card." : ""]" + . += "The card indicates that the holder is [registered_age] years old. [(registered_age < AGE_MINOR) ? "There's a holographic stripe that reads [span_danger("'MINOR: DO NOT SERVE ALCOHOL OR TOBACCO'")] along the bottom of the card." : ""]" if(mining_points) - msg += "There's [mining_points] mining equipment redemption point\s loaded onto this card." + . += "There's [mining_points] mining equipment redemption point\s loaded onto this card." if(registered_account) - msg += "The account linked to the ID belongs to '[registered_account.account_holder]' and reports a balance of [registered_account.account_balance] cr." + . += "The account linked to the ID belongs to '[registered_account.account_holder]' and reports a balance of [registered_account.account_balance] cr." if(registered_account.account_job) var/datum/bank_account/D = SSeconomy.get_dep_account(registered_account.account_job.paycheck_department) if(D) - msg += "The [D.account_holder] reports a balance of [D.account_balance] cr." - msg += span_info("Alt-Click the ID to pull money from the linked account in the form of holochips.") - msg += span_info("You can insert credits into the linked account by pressing holochips, cash, or coins against the ID.") + . += "The [D.account_holder] reports a balance of [D.account_balance] cr." + . += span_info("Alt-Click the ID to pull money from the linked account in the form of holochips.") + . += span_info("You can insert credits into the linked account by pressing holochips, cash, or coins against the ID.") if(registered_account.civilian_bounty) - msg += "There is an active civilian bounty." - msg += span_info("[registered_account.bounty_text()]") - msg += span_info("Quantity: [registered_account.bounty_num()]") - msg += span_info("Reward: [registered_account.bounty_value()]") + . += "There is an active civilian bounty." + . += span_info("[registered_account.bounty_text()]") + . += span_info("Quantity: [registered_account.bounty_num()]") + . += span_info("Reward: [registered_account.bounty_value()]") if(registered_account.account_holder == user.real_name) - msg += span_boldnotice("If you lose this ID card, you can reclaim your account by Alt-Clicking a blank ID card while holding it and entering your account ID number.") + . += span_boldnotice("If you lose this ID card, you can reclaim your account by Alt-Clicking a blank ID card while holding it and entering your account ID number.") else - msg += span_info("There is no registered account linked to this card. Alt-Click to add one.") + . += span_info("There is no registered account linked to this card. Alt-Click to add one.") - return msg + return . /obj/item/card/id/GetAccess() return access.Copy() diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index a000c331b0f..1fbcda5fcc4 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -786,7 +786,7 @@ if(istype(target, /obj/item/bodypart) && actually_paints) var/obj/item/bodypart/limb = target - if(limb.status == BODYPART_ROBOTIC) + 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') for(var/skin_option in style_list_icons) diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 697ad13e4a7..ded8c0ee892 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -234,7 +234,7 @@ if(mode == SCANNER_VERBOSE) for(var/obj/item/bodypart/limb as anything in damaged) - dmgreport += "[capitalize(limb.name)]:" + dmgreport += "[capitalize(parse_zone(limb.body_zone))]:" dmgreport += "[(limb.brute_dam > 0) ? "[CEILING(limb.brute_dam,1)]" : "0"]" dmgreport += "[(limb.burn_dam > 0) ? "[CEILING(limb.burn_dam,1)]" : "0"]" dmgreport += "" diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index 190c30f3bcd..0b6a0f73457 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -922,11 +922,12 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/food/ready_donk/examine_more(mob/user) - var/list/msg = list(span_notice("You browse the back of the box...")) - msg += "\t[span_info("Ready-Donk: a product of Donk Co.")]" - msg += "\t[span_info("Heating instructions: open box and pierce film, heat in microwave on high for 2 minutes. Allow to stand for 60 seconds prior to eating. Product will be hot.")]" - msg += "\t[span_info("Per 200g serving contains: 8g Sodium; 25g Fat, of which 22g are saturated; 2g Sugar.")]" - return msg + . = ..() + . += span_notice("You browse the back of the box...") + . += "\t[span_info("Ready-Donk: a product of Donk Co.")]" + . += "\t[span_info("Heating instructions: open box and pierce film, heat in microwave on high for 2 minutes. Allow to stand for 60 seconds prior to eating. Product will be hot.")]" + . += "\t[span_info("Per 200g serving contains: 8g Sodium; 25g Fat, of which 22g are saturated; 2g Sugar.")]" + return . /obj/item/food/ready_donk/warm name = "warm Ready-Donk: Bachelor Chow" diff --git a/code/game/objects/items/food/moth.dm b/code/game/objects/items/food/moth.dm index 92981cb7d4f..c5d8b48dbae 100644 --- a/code/game/objects/items/food/moth.dm +++ b/code/game/objects/items/food/moth.dm @@ -369,7 +369,7 @@ foodtypes = VEGETABLES w_class = WEIGHT_CLASS_SMALL -/obj/item/food/soup/moth_bean_stew +/obj/item/food/soup/moth_bean_stew name = "prickeldröndolhaskl" //prickeld = spicy, röndol = bean, haskl = stew desc = "A spicy bean stew with lots of veggies, commonly served aboard the fleet as a filling and satisfying meal with rice or bread." icon = 'icons/obj/food/moth.dmi' @@ -389,7 +389,7 @@ foodtypes = VEGETABLES | GRAIN w_class = WEIGHT_CLASS_SMALL -/obj/item/food/soup/moth_fire_soup +/obj/item/food/soup/moth_fire_soup name = "tömpröttkrakklmæsch" //tömprött = heart (tömp = thump, rött = muscle), krakkl = fire, mæsch = soup desc = "Tömpröttkrakklmæsch, or heartburn soup, is a cold soup dish that originated amongst the jungle moths, and is named for two things- its rosy pink colour, and its scorchingly hot chilli heat." icon = 'icons/obj/food/moth.dmi' @@ -400,7 +400,7 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/food/soup/rice_porridge - name = "rice porridge" + name = "rice porridge" desc = "A plate of rice porridge. It's mostly flavourless, but it does fill a spot. To the Chinese it's congee, and moths call it höllflöfmisklsløsk." //höllflöfmiskl = rice (höllflöf = cloud, miskl = seed), sløsk = porridge icon = 'icons/obj/food/moth.dmi' icon_state = "rice_porridge" @@ -410,7 +410,7 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/food/soup/hua_mulan_congee - name = "\improper Hua Mulan congee" + name = "\improper Hua Mulan congee" desc = "Nobody is quite sure why this smiley bowl of rice porridge with eggs and bacon is named after a mythological Chinese figure- it's just sorta what it's always been called." icon = 'icons/obj/food/moth.dmi' icon_state = "hua_mulan_congee" @@ -420,7 +420,7 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/food/soup/toechtauese_rice_porridge - name = "töchtaüse rice porridge" + name = "töchtaüse rice porridge" desc = "Commonly served aboard the mothic fleet, rice porridge with töchtaüse syrup is more palatable than the regular stuff, if even just because it's spicier than normal." icon = 'icons/obj/food/moth.dmi' icon_state = "toechtauese_rice_porridge" @@ -430,7 +430,7 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/food/soup/cornmeal_porridge - name = "cornmeal porridge" + name = "cornmeal porridge" desc = "A plate of cornmeal porridge. It's more flavourful than most porridges, and makes a good base for other flavours, too." icon = 'icons/obj/food/moth.dmi' icon_state = "cornmeal_porridge" @@ -440,7 +440,7 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/food/soup/cheesy_porridge //milk, polenta, firm cheese, curd cheese, butter - name = "cheesy porridge" + name = "cheesy porridge" desc = "A rich and creamy bowl of cheesy cornmeal porridge." icon = 'icons/obj/food/moth.dmi' icon_state = "cheesy_porridge" @@ -450,7 +450,7 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/food/soup/fried_eggplant_polenta - name = "fried eggplant and polenta" + name = "fried eggplant and polenta" desc = "Polenta loaded with cheese, served with a few discs of fried eggplant and some tomato sauce. Lække!" icon = 'icons/obj/food/moth.dmi' icon_state = "fried_eggplant_polenta" @@ -765,16 +765,17 @@ custom_premium_price = PAYCHECK_EASY * 1.5 /obj/item/storage/box/gum/wake_up/examine_more(mob/user) - var/list/msg = list(span_notice("You read some of the health and safety information...")) - msg += "\t[span_info("For the relief of tiredness and drowsiness while working.")]" - msg += "\t[span_info("Do not chew more than one strip every 12 hours. Do not use as a complete substitute for sleep.")]" - msg += "\t[span_info("Do not give to children under 16. Do not exceed the maximum dosage. Do not ingest. Do not take for more than 3 days consecutively. Do not take in conjunction with other medication. May cause adverse reactions in patients with pre-existing heart conditions.")]" - msg += "\t[span_info("Side effects of Activin use may include twitchy antennae, overactive wings, loss of keratin sheen, loss of setae coverage, arrythmia, blurred vision, and euphoria. Cease taking the medication if side effects occur.")]" - msg += "\t[span_info("Repeated use may cause addiction.")]" - msg += "\t[span_info("If the maximum dosage is exceeded, inform a member of your assigned vessel's medical staff immediately. Do not induce vomiting.")]" - msg += "\t[span_info("Ingredients: each strip contains 500mg of Activin (dextro-methamphetamine). Other ingredients include Green Dye 450 (Verdant Meadow) and artificial herb flavouring.")]" - msg += "\t[span_info("Storage: keep in a cool dry place. Do not use after the use-by date: 32/4/350.")]" - return msg + . = ..() + . += span_notice("You read some of the health and safety information...") + . += "\t[span_info("For the relief of tiredness and drowsiness while working.")]" + . += "\t[span_info("Do not chew more than one strip every 12 hours. Do not use as a complete substitute for sleep.")]" + . += "\t[span_info("Do not give to children under 16. Do not exceed the maximum dosage. Do not ingest. Do not take for more than 3 days consecutively. Do not take in conjunction with other medication. May cause adverse reactions in patients with pre-existing heart conditions.")]" + . += "\t[span_info("Side effects of Activin use may include twitchy antennae, overactive wings, loss of keratin sheen, loss of setae coverage, arrythmia, blurred vision, and euphoria. Cease taking the medication if side effects occur.")]" + . += "\t[span_info("Repeated use may cause addiction.")]" + . += "\t[span_info("If the maximum dosage is exceeded, inform a member of your assigned vessel's medical staff immediately. Do not induce vomiting.")]" + . += "\t[span_info("Ingredients: each strip contains 500mg of Activin (dextro-methamphetamine). Other ingredients include Green Dye 450 (Verdant Meadow) and artificial herb flavouring.")]" + . += "\t[span_info("Storage: keep in a cool dry place. Do not use after the use-by date: 32/4/350.")]" + return . /obj/item/storage/box/gum/wake_up/PopulateContents() for(var/i in 1 to 4) diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index e2351b42da5..d23bce7e6f2 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -127,7 +127,7 @@ return FALSE var/obj/item/bodypart/head/the_head = target.get_bodypart(BODY_ZONE_HEAD) - if((target.get_biological_state() != BIO_FLESH_BONE && target.get_biological_state() != BIO_JUST_FLESH) || !the_head.is_organic_limb()) + if((target.get_biological_state() != BIO_FLESH_BONE && target.get_biological_state() != BIO_JUST_FLESH) || !IS_ORGANIC_LIMB(the_head)) to_chat(user, span_warning("You can't noogie [target], [target.p_they()] [target.p_have()] no skin on [target.p_their()] head!")) return diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index dcbee9ab9eb..1d0e70fec06 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -53,17 +53,17 @@ /obj/item/robot_suit/update_overlays() . = ..() if(l_arm) - . += "[l_arm.icon_state]+o" + . += "[initial(l_arm.icon_state)]+o" if(r_arm) - . += "[r_arm.icon_state]+o" + . += "[initial(r_arm.icon_state)]+o" if(chest) - . += "[chest.icon_state]+o" + . += "[initial(chest.icon_state)]+o" if(l_leg) - . += "[l_leg.icon_state]+o" + . += "[initial(l_leg.icon_state)]+o" if(r_leg) - . += "[r_leg.icon_state]+o" + . += "[initial(r_leg.icon_state)]+o" if(head) - . += "[head.icon_state]+o" + . += "[initial(head.icon_state)]+o" /obj/item/robot_suit/proc/check_completion() if(l_arm && r_arm && l_leg && r_leg && head && head.flash1 && head.flash2 && chest && chest.wired && chest.cell) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 177678675f7..961e3065f3c 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -83,17 +83,20 @@ if(!affecting) //Missing limb? to_chat(user, span_warning("[C] doesn't have \a [parse_zone(user.zone_selected)]!")) return FALSE - if(affecting.status != BODYPART_ORGANIC) //Limb must be organic to be healed - RR + if(!IS_ORGANIC_LIMB(affecting)) //Limb must be organic to be healed - RR to_chat(user, span_warning("[src] won't work on a robotic limb!")) return FALSE if(affecting.brute_dam && brute || affecting.burn_dam && burn) - user.visible_message("[user] applies [src] on [C]'s [affecting.name].", "You apply [src] on [C]'s [affecting.name].") + user.visible_message( + span_infoplain(span_green("[user] applies [src] on [C]'s [parse_zone(affecting.body_zone)].")), + span_infoplain(span_green("You apply [src] on [C]'s [parse_zone(affecting.body_zone)].")) + ) var/previous_damage = affecting.get_damage() if(affecting.heal_damage(brute, burn)) C.update_damage_overlays() post_heal_effects(max(previous_damage - affecting.get_damage(), 0), C, user) return TRUE - to_chat(user, span_warning("[C]'s [affecting.name] can not be healed with [src]!")) + to_chat(user, span_warning("[C]'s [parse_zone(affecting.body_zone)] can not be healed with [src]!")) return FALSE ///Override this proc for special post heal effects. diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm index 02c6b23eae8..acf400b1a9f 100644 --- a/code/game/objects/items/storage/book.dm +++ b/code/game/objects/items/storage/book.dm @@ -132,19 +132,18 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "burning", if(!ishuman(L)) return var/mob/living/carbon/human/H = L - for(var/X in H.bodyparts) - var/obj/item/bodypart/BP = X - if(BP.status == BODYPART_ROBOTIC) + for(var/obj/item/bodypart/bodypart as anything in H.bodyparts) + if(!IS_ORGANIC_LIMB(bodypart)) to_chat(user, span_warning("[src.deity_name] refuses to heal this metallic taint!")) return 0 var/heal_amt = 10 - var/list/hurt_limbs = H.get_damaged_bodyparts(1, 1, null, BODYPART_ORGANIC) + var/list/hurt_limbs = H.get_damaged_bodyparts(1, 1, null, BODYTYPE_ORGANIC) if(hurt_limbs.len) for(var/X in hurt_limbs) var/obj/item/bodypart/affecting = X - if(affecting.heal_damage(heal_amt, heal_amt, null, BODYPART_ORGANIC)) + if(affecting.heal_damage(heal_amt, heal_amt, null, BODYTYPE_ORGANIC)) H.update_damage_overlays() H.visible_message(span_notice("[user] heals [H] with the power of [deity_name]!")) to_chat(H, span_boldnotice("May the power of [deity_name] compel you to be healed!")) diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 8a745b9a005..4d508d05597 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -120,7 +120,7 @@ var/obj/item/bodypart/affecting = attacked_humanoid.get_bodypart(check_zone(user.zone_selected)) - if(affecting && affecting.status == BODYPART_ROBOTIC && !user.combat_mode) + if(affecting && !IS_ORGANIC_LIMB(affecting) && !user.combat_mode) if(src.use_tool(attacked_humanoid, user, 0, volume=50, amount=1)) if(user == attacked_humanoid) user.visible_message(span_notice("[user] starts to fix some of the dents on [attacked_humanoid]'s [affecting.name]."), diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 7d961515105..054e586fbcc 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -49,7 +49,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28) hairdresser.hairstyle = new_style - hairdresser.update_hair() + hairdresser.update_hair(is_creating = TRUE) /obj/structure/mirror/examine_status(mob/user) if(broken) @@ -216,7 +216,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28) if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return TRUE amazed_human.gender = FEMALE - amazed_human.body_type = FEMALE + amazed_human.physique = FEMALE to_chat(amazed_human, span_notice("Man, you feel like a woman!")) else return TRUE @@ -226,7 +226,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28) if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return TRUE amazed_human.gender = MALE - amazed_human.body_type = MALE + amazed_human.physique = MALE to_chat(amazed_human, span_notice("Whoa man, you feel like a man!")) else return TRUE diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index ec74131b52d..539d745b3ee 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -12,7 +12,7 @@ /proc/randomize_human(mob/living/carbon/human/H) H.gender = pick(MALE, FEMALE) - H.body_type = H.gender + H.physique = H.gender H.real_name = random_unique_name(H.gender) H.name = H.real_name H.underwear = random_underwear(H.gender) @@ -38,6 +38,5 @@ H.dna.features["moth_antennae"] = pick(GLOB.moth_antennae_list) H.dna.features["pod_hair"] = pick(GLOB.pod_hair_list) - H.update_body() - H.update_hair() - H.update_body_parts() + H.update_body(is_creating = TRUE) + H.update_hair(is_creating = TRUE) diff --git a/code/modules/antagonists/abductor/equipment/glands/heal.dm b/code/modules/antagonists/abductor/equipment/glands/heal.dm index 7335c4fdb35..ba71d1f174c 100644 --- a/code/modules/antagonists/abductor/equipment/glands/heal.dm +++ b/code/modules/antagonists/abductor/equipment/glands/heal.dm @@ -53,7 +53,7 @@ if(!limb) replace_limb(zone) return - if((limb.get_damage() >= (limb.max_damage / 2)) || (limb.status == BODYPART_ROBOTIC)) + if((limb.get_damage() >= (limb.max_damage / 2)) || (!IS_ORGANIC_LIMB(limb))) replace_limb(zone, limb) return @@ -72,7 +72,7 @@ return var/obj/item/bodypart/chest/chest = owner.get_bodypart(BODY_ZONE_CHEST) - if((chest.get_damage() >= (chest.max_damage / 4)) || (chest.status == BODYPART_ROBOTIC)) + if((chest.get_damage() >= (chest.max_damage / 4)) || (!IS_ORGANIC_LIMB(chest))) replace_chest(chest) return @@ -208,7 +208,7 @@ addtimer(CALLBACK(src, .proc/keep_replacing_blood), 30) /obj/item/organ/heart/gland/heal/proc/replace_chest(obj/item/bodypart/chest/chest) - if(chest.status == BODYPART_ROBOTIC) + if(!IS_ORGANIC_LIMB(chest)) owner.visible_message(span_warning("[owner]'s [chest.name] rapidly expels its mechanical components, replacing them with flesh!"), span_userdanger("Your [chest.name] rapidly expels its mechanical components, replacing them with flesh!")) playsound(owner, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, TRUE) var/list/dirs = GLOB.alldirs.Copy() diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 8f9560c80c0..e23e5bdb476 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -652,9 +652,11 @@ chosen_dna.transfer_identity(user, TRUE) - user.Digitigrade_Leg_Swap(!(DIGITIGRADE in chosen_dna.species?.species_traits)) + for(var/obj/item/bodypart/limb as anything in user.bodyparts) + if(IS_ORGANIC_LIMB(limb)) + limb.update_limb(is_creating = TRUE) + user.updateappearance(mutcolor_update = TRUE) - user.update_body() user.domutcheck() // Get rid of any scars from previous Changeling-ing diff --git a/code/modules/antagonists/changeling/powers/fakedeath.dm b/code/modules/antagonists/changeling/powers/fakedeath.dm index 835e13cfb36..05a58894cd9 100644 --- a/code/modules/antagonists/changeling/powers/fakedeath.dm +++ b/code/modules/antagonists/changeling/powers/fakedeath.dm @@ -43,7 +43,7 @@ "You hear organic matter ripping \ and tearing!") user.emote("scream") - user.regenerate_limbs(0, list(BODY_ZONE_HEAD)) + user.regenerate_limbs(list(BODY_ZONE_HEAD)) user.regenerate_organs() /datum/action/changeling/fakedeath/proc/ready_to_regenerate(mob/user) diff --git a/code/modules/antagonists/changeling/powers/regenerate.dm b/code/modules/antagonists/changeling/powers/regenerate.dm index fffcb731bed..01109161dca 100644 --- a/code/modules/antagonists/changeling/powers/regenerate.dm +++ b/code/modules/antagonists/changeling/powers/regenerate.dm @@ -23,7 +23,7 @@ "You hear organic matter ripping \ and tearing!") C.emote("scream") - C.regenerate_limbs(1) + C.regenerate_limbs() if(!user.getorganslot(ORGAN_SLOT_BRAIN)) var/obj/item/organ/brain/B if(C.has_dna() && C.dna.species.mutantbrain) diff --git a/code/modules/antagonists/fugitive/fugitive_outfits.dm b/code/modules/antagonists/fugitive/fugitive_outfits.dm index 6400324c720..e32e1f2ce25 100644 --- a/code/modules/antagonists/fugitive/fugitive_outfits.dm +++ b/code/modules/antagonists/fugitive/fugitive_outfits.dm @@ -219,18 +219,6 @@ /obj/item/bountytrap = 4 ) -/datum/outfit/bountysynth/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - if(visualsOnly) - return - var/datum/species/synth/synthetic_appearance = new() - H.set_species(synthetic_appearance) - synthetic_appearance.assume_disguise(synthetic_appearance, H) - H.update_hair() - var/obj/item/card/id/W = H.wear_id - W.registered_name = H.real_name - W.update_label() - W.update_icon() - //ids and ert code /obj/item/card/id/advanced/bountyhunter diff --git a/code/modules/antagonists/heretic/structures/mawed_crucible.dm b/code/modules/antagonists/heretic/structures/mawed_crucible.dm index 32311eefada..adb7a64a5a5 100644 --- a/code/modules/antagonists/heretic/structures/mawed_crucible.dm +++ b/code/modules/antagonists/heretic/structures/mawed_crucible.dm @@ -75,7 +75,7 @@ if(istype(weapon, /obj/item/bodypart)) var/obj/item/bodypart/consumed = weapon - if(consumed.status != BODYPART_ORGANIC) + if(!IS_ORGANIC_LIMB(consumed)) balloon_alert(user, "not organic!") return diff --git a/code/modules/antagonists/nightmare/nightmare_species.dm b/code/modules/antagonists/nightmare/nightmare_species.dm index e273780f424..5b448b72187 100644 --- a/code/modules/antagonists/nightmare/nightmare_species.dm +++ b/code/modules/antagonists/nightmare/nightmare_species.dm @@ -4,7 +4,7 @@ /datum/species/shadow/nightmare name = "Nightmare" id = SPECIES_NIGHTMARE - limbs_id = "shadow" + examine_limb_id = "shadow" burnmod = 1.5 no_equip = list(ITEM_SLOT_MASK, ITEM_SLOT_OCLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_FEET, ITEM_SLOT_ICLOTHING, ITEM_SLOT_SUITSTORE) species_traits = list(NOBLOOD,NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYESPRITES) diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm index 86e4d2ce0e8..958626d39ff 100644 --- a/code/modules/antagonists/revenant/revenant_abilities.dm +++ b/code/modules/antagonists/revenant/revenant_abilities.dm @@ -356,8 +356,7 @@ if(iscarbon(mob)) if(ishuman(mob)) var/mob/living/carbon/human/H = mob - if(H.dna && H.dna.species) - H.dna.species.handle_hair(H,"#1d2953") //will be reset when blight is cured + H.set_haircolor("#1d2953", override = TRUE) //will be reset when blight is cured var/blightfound = FALSE for(var/datum/disease/revblight/blight in H.diseases) blightfound = TRUE diff --git a/code/modules/antagonists/revenant/revenant_blight.dm b/code/modules/antagonists/revenant/revenant_blight.dm index defe4a6c851..cd05d88dd9e 100644 --- a/code/modules/antagonists/revenant/revenant_blight.dm +++ b/code/modules/antagonists/revenant/revenant_blight.dm @@ -20,7 +20,7 @@ affected_mob.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#1d2953") if(affected_mob.dna && affected_mob.dna.species) affected_mob.dna.species.handle_mutant_bodyparts(affected_mob) - affected_mob.dna.species.handle_hair(affected_mob) + affected_mob.set_haircolor(null, override = TRUE) to_chat(affected_mob, span_notice("You feel better.")) ..() @@ -64,7 +64,7 @@ new /obj/effect/temp_visual/revenant(affected_mob.loc) if(affected_mob.dna && affected_mob.dna.species) affected_mob.dna.species.handle_mutant_bodyparts(affected_mob,"#1d2953") - affected_mob.dna.species.handle_hair(affected_mob,"#1d2953") + affected_mob.set_haircolor("#1d2953", override = TRUE) affected_mob.visible_message(span_warning("[affected_mob] looks terrifyingly gaunt..."), span_revennotice("You suddenly feel like your skin is wrong...")) affected_mob.add_atom_colour("#1d2953", TEMPORARY_COLOUR_PRIORITY) addtimer(CALLBACK(src, .proc/cure), 10 SECONDS) diff --git a/code/modules/antagonists/thief/thief.dm b/code/modules/antagonists/thief/thief.dm index b2fd7a4ea93..63a7618fb7a 100644 --- a/code/modules/antagonists/thief/thief.dm +++ b/code/modules/antagonists/thief/thief.dm @@ -100,7 +100,7 @@ if(SSatoms.initialized == INITIALIZATION_INSSATOMS) thief.w_uniform?.update_greyscale() thief.update_inv_w_uniform() - thief.body_type = FEMALE //update_body() and gender block or something + thief.physique = FEMALE //update_body() and gender block or something thief.hair_color = "#2A71DC" //hair color dna block thief.skin_tone = "caucasian2" //skin tone dna block thief.hairstyle = "Bun Head 2" //update_hair() diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm index 8c2deb4cbae..a7d07884a71 100644 --- a/code/modules/awaymissions/mission_code/snowdin.dm +++ b/code/modules/awaymissions/mission_code/snowdin.dm @@ -197,15 +197,15 @@ return var/mob/living/carbon/human/burn_human = burn_living var/datum/species/burn_species = burn_human.dna.species - if(istype(burn_species, /datum/species/plasmaman) || istype(burn_species, /datum/species/android) || istype(burn_species, /datum/species/synth)) //ignore plasmamen/robotic species + if(istype(burn_species, /datum/species/plasmaman) || istype(burn_species, /datum/species/android)) //ignore plasmamen/robotic species return var/list/plasma_parts = list()//a list of the organic parts to be turned into plasma limbs var/list/robo_parts = list()//keep a reference of robotic parts so we know if we can turn them into a plasmaman for(var/obj/item/bodypart/burn_limb as anything in burn_human.bodyparts) - if(burn_limb.status == BODYPART_ORGANIC && burn_limb.species_id != SPECIES_PLASMAMAN) //getting every organic, non-plasmaman limb (augments/androids are immune to this) + if(IS_ORGANIC_LIMB(burn_limb) && burn_limb.limb_id != SPECIES_PLASMAMAN) //getting every organic, non-plasmaman limb (augments/androids are immune to this) plasma_parts += burn_limb - if(burn_limb.status == BODYPART_ROBOTIC) + if(!IS_ORGANIC_LIMB(burn_limb)) robo_parts += burn_limb burn_human.adjustToxLoss(15) diff --git a/code/modules/capture_the_flag/ctf_game.dm b/code/modules/capture_the_flag/ctf_game.dm index 1c3272c11b4..140cc4d5fec 100644 --- a/code/modules/capture_the_flag/ctf_game.dm +++ b/code/modules/capture_the_flag/ctf_game.dm @@ -389,7 +389,8 @@ var/mob/living/carbon/human/M = new /mob/living/carbon/human(get_turf(src)) new_team_member.prefs.safe_transfer_prefs_to(M, is_antag = TRUE) - M.set_species(/datum/species/synth) + if(M.dna.species.outfit_important_for_life) + M.set_species(/datum/species/human) M.key = new_team_member.key M.faction += team M.equipOutfit(chosen_class) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 40f8cf8bb9f..0ac9d2b225f 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -492,10 +492,8 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/character_preview_view) character.dna.real_name = character.real_name if(icon_updates) - character.icon_render_key = null //turns out if you don't set this to null update_body_parts does nothing, since it assumes the operation was cached - character.update_body() - character.update_hair() - character.update_body_parts() + character.icon_render_keys = list() + character.update_body(is_creating = TRUE) /// Returns whether the parent mob should have the random hardcore settings enabled. Assumes it has a mind. diff --git a/code/modules/client/preferences/body_type.dm b/code/modules/client/preferences/body_type.dm index 4ef018fc60f..469b564e46f 100644 --- a/code/modules/client/preferences/body_type.dm +++ b/code/modules/client/preferences/body_type.dm @@ -14,9 +14,9 @@ /datum/preference/choiced/body_type/apply_to_human(mob/living/carbon/human/target, value) if (value == USE_GENDER) - target.body_type = target.gender + target.physique = target.gender else - target.body_type = value + target.physique = value /datum/preference/choiced/body_type/is_accessible(datum/preferences/preferences) if (!..(preferences)) diff --git a/code/modules/client/preferences/species.dm b/code/modules/client/preferences/species.dm index 2ad93c3b14b..c90b182f16c 100644 --- a/code/modules/client/preferences/species.dm +++ b/code/modules/client/preferences/species.dm @@ -6,7 +6,7 @@ randomize_by_default = FALSE /datum/preference/choiced/species/deserialize(input, datum/preferences/preferences) - return GLOB.species_list[sanitize_inlist(input, get_choices_serialized(), "human")] + return GLOB.species_list[sanitize_inlist(input, get_choices_serialized(), SPECIES_HUMAN)] /datum/preference/choiced/species/serialize(input) var/datum/species/species = input diff --git a/code/modules/client/preferences/species_features/basic.dm b/code/modules/client/preferences/species_features/basic.dm index bf208f36942..f75e12dd0d1 100644 --- a/code/modules/client/preferences/species_features/basic.dm +++ b/code/modules/client/preferences/species_features/basic.dm @@ -53,6 +53,7 @@ /datum/preference/choiced/facial_hairstyle/apply_to_human(mob/living/carbon/human/target, value) target.facial_hairstyle = value + target.update_hair(is_creating = TRUE) /datum/preference/choiced/facial_hairstyle/compile_constant_data() var/list/data = ..() @@ -69,6 +70,7 @@ /datum/preference/color/facial_hair_color/apply_to_human(mob/living/carbon/human/target, value) target.facial_hair_color = value + target.update_hair(is_creating = TRUE) /datum/preference/choiced/facial_hair_gradient category = PREFERENCE_CATEGORY_SECONDARY_FEATURES @@ -82,7 +84,7 @@ /datum/preference/choiced/facial_hair_gradient/apply_to_human(mob/living/carbon/human/target, value) LAZYSETLEN(target.grad_style, GRADIENTS_LEN) target.grad_style[GRADIENT_FACIAL_HAIR_KEY] = value - target.update_hair() + target.update_hair(is_creating = TRUE) /datum/preference/choiced/facial_hair_gradient/create_default_value() return "None" @@ -96,7 +98,7 @@ /datum/preference/color/facial_hair_gradient/apply_to_human(mob/living/carbon/human/target, value) LAZYSETLEN(target.grad_color, GRADIENTS_LEN) target.grad_color[GRADIENT_FACIAL_HAIR_KEY] = value - target.update_hair() + target.update_hair(is_creating = TRUE) /datum/preference/color/facial_hair_gradient/is_accessible(datum/preferences/preferences) if (!..(preferences)) @@ -145,7 +147,7 @@ /datum/preference/choiced/hair_gradient/apply_to_human(mob/living/carbon/human/target, value) LAZYSETLEN(target.grad_style, GRADIENTS_LEN) target.grad_style[GRADIENT_HAIR_KEY] = value - target.update_hair() + target.update_hair(is_creating = TRUE) /datum/preference/choiced/hair_gradient/create_default_value() return "None" @@ -159,7 +161,7 @@ /datum/preference/color/hair_gradient/apply_to_human(mob/living/carbon/human/target, value) LAZYSETLEN(target.grad_color, GRADIENTS_LEN) target.grad_color[GRADIENT_HAIR_KEY] = value - target.update_hair() + target.update_hair(is_creating = TRUE) /datum/preference/color/hair_gradient/is_accessible(datum/preferences/preferences) if (!..(preferences)) diff --git a/code/modules/client/preferences/species_features/ethereal.dm b/code/modules/client/preferences/species_features/ethereal.dm index dfd7afb06a9..61818aee2d0 100644 --- a/code/modules/client/preferences/species_features/ethereal.dm +++ b/code/modules/client/preferences/species_features/ethereal.dm @@ -8,10 +8,10 @@ /datum/preference/choiced/ethereal_color/init_possible_values() var/list/values = list() - var/icon/ethereal_base = icon('icons/mob/human_parts_greyscale.dmi', "ethereal_head_m") - ethereal_base.Blend(icon('icons/mob/human_parts_greyscale.dmi', "ethereal_chest_m"), ICON_OVERLAY) - ethereal_base.Blend(icon('icons/mob/human_parts_greyscale.dmi', "ethereal_l_arm"), ICON_OVERLAY) - ethereal_base.Blend(icon('icons/mob/human_parts_greyscale.dmi', "ethereal_r_arm"), ICON_OVERLAY) + var/icon/ethereal_base = icon('icons/mob/species/ethereal/bodyparts.dmi', "ethereal_head") + ethereal_base.Blend(icon('icons/mob/species/ethereal/bodyparts.dmi', "ethereal_chest"), ICON_OVERLAY) + ethereal_base.Blend(icon('icons/mob/species/ethereal/bodyparts.dmi', "ethereal_l_arm"), ICON_OVERLAY) + ethereal_base.Blend(icon('icons/mob/species/ethereal/bodyparts.dmi', "ethereal_r_arm"), ICON_OVERLAY) var/icon/eyes = icon('icons/mob/human_face.dmi', "eyes") eyes.Blend(COLOR_BLACK, ICON_MULTIPLY) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 898ec327c43..579fc64ac25 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -173,7 +173,7 @@ /obj/item/clothing/proc/take_damage_zone(def_zone, damage_amount, damage_type, armour_penetration) if(!def_zone || !limb_integrity || (initial(body_parts_covered) in GLOB.bitflags)) // the second check sees if we only cover one bodypart anyway and don't need to bother with this return - var/list/covered_limbs = body_parts_covered2organ_names(body_parts_covered) // what do we actually cover? + var/list/covered_limbs = cover_flags2body_zones(body_parts_covered) // what do we actually cover? if(!(def_zone in covered_limbs)) return @@ -195,7 +195,7 @@ * * damage_type: Only really relevant for the verb for describing the breaking, and maybe atom_destruction() */ /obj/item/clothing/proc/disable_zone(def_zone, damage_type) - var/list/covered_limbs = body_parts_covered2organ_names(body_parts_covered) + var/list/covered_limbs = cover_flags2body_zones(body_parts_covered) if(!(def_zone in covered_limbs)) return @@ -208,7 +208,7 @@ RegisterSignal(C, COMSIG_MOVABLE_MOVED, .proc/bristle, override = TRUE) zones_disabled++ - for(var/i in zone2body_parts_covered(def_zone)) + for(var/i in body_zone2cover_flags(def_zone)) body_parts_covered &= ~i if(body_parts_covered == NONE) // if there are no more parts to break then the whole thing is kaput diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 60fcada6d47..6b26fb6697e 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -20,7 +20,6 @@ var/alt_covers_chest = FALSE // for adjusted/rolled-down jumpsuits, FALSE = exposes chest and arms, TRUE = exposes arms only var/obj/item/clothing/accessory/attached_accessory var/mutable_appearance/accessory_overlay - var/mutantrace_variation = NO_MUTANTRACE_VARIATION //Are there special sprites for specific situations? Don't use this unless you need to. var/freshly_laundered = FALSE /obj/item/clothing/under/Initialize(mapload) @@ -98,9 +97,9 @@ if(!alt_covers_chest) body_parts_covered |= CHEST - if(mutantrace_variation && ishuman(user)) + if((supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && ishuman(user)) var/mob/living/carbon/human/H = user - if(DIGITIGRADE in H.dna.species.species_traits) + if(H.dna.species.bodytype & BODYTYPE_DIGITIGRADE) adjusted = DIGITIGRADE_STYLE H.update_inv_w_uniform() @@ -323,7 +322,7 @@ return adjusted for(var/zone in list(BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) // ugly check to make sure we don't reenable protection on a disabled part if(damage_by_parts[zone] > limb_integrity) - for(var/part in zone2body_parts_covered(zone)) + for(var/part in body_zone2cover_flags(zone)) body_parts_covered &= part return adjusted diff --git a/code/modules/clothing/under/jobs/cargo.dm b/code/modules/clothing/under/jobs/cargo.dm index d68f4b9e141..4c8d6b06f8e 100644 --- a/code/modules/clothing/under/jobs/cargo.dm +++ b/code/modules/clothing/under/jobs/cargo.dm @@ -16,6 +16,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/cargo/tech name = "cargo technician's jumpsuit" @@ -23,16 +24,17 @@ icon_state = "cargotech" inhand_icon_state = "lb_suit" body_parts_covered = CHEST|GROIN|ARMS - mutantrace_variation = MUTANTRACE_VARIATION + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION alt_covers_chest = TRUE + /obj/item/clothing/under/rank/cargo/tech/skirt name = "cargo technician's jumpskirt" desc = "Skiiiiirts! They're comfy and easy to wear!" icon_state = "cargo_skirt" inhand_icon_state = "lb_suit" body_parts_covered = CHEST|GROIN|ARMS - mutantrace_variation = NO_MUTANTRACE_VARIATION + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY diff --git a/code/modules/clothing/under/jobs/civilian/civilian.dm b/code/modules/clothing/under/jobs/civilian/civilian.dm index 66d3a772eb9..044e9587f9b 100644 --- a/code/modules/clothing/under/jobs/civilian/civilian.dm +++ b/code/modules/clothing/under/jobs/civilian/civilian.dm @@ -25,6 +25,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/chaplain desc = "It's a black jumpsuit, often worn by religious folk." @@ -41,6 +42,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/chef name = "cook's suit" @@ -55,6 +57,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/head_of_personnel desc = "It's a jumpsuit worn by someone who works in the position of \"Head of Personnel\"." @@ -70,6 +73,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/head_of_personnel/suit name = "head of personnel's suit" @@ -86,6 +90,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/hydroponics desc = "It's a jumpsuit designed to protect against minor plant-related hazards." @@ -102,6 +107,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/janitor desc = "It's the official uniform of the station's janitor. It has minor protection from biohazards." @@ -116,6 +122,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/janitor/maid name = "maid uniform" @@ -148,6 +155,7 @@ inhand_icon_state = "lawyer_black" dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/lawyer/beige name = "good lawyer's suit" @@ -164,6 +172,7 @@ worn_icon = 'icons/mob/clothing/under/suits.dmi' dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/lawyer/red name = "lawyer red suit" @@ -176,6 +185,7 @@ inhand_icon_state = "lawyer_red" dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/lawyer/blue name = "lawyer blue suit" @@ -188,6 +198,7 @@ inhand_icon_state = "lawyer_blue" dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/lawyer/bluesuit name = "blue suit" @@ -205,6 +216,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/lawyer/purpsuit name = "purple suit" @@ -221,6 +233,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/lawyer/galaxy worn_icon = 'icons/mob/clothing/under/lawyer_galaxy.dmi' diff --git a/code/modules/clothing/under/jobs/civilian/clown_mime.dm b/code/modules/clothing/under/jobs/civilian/clown_mime.dm index 5c8f3c52cd9..b779d7504f0 100644 --- a/code/modules/clothing/under/jobs/civilian/clown_mime.dm +++ b/code/modules/clothing/under/jobs/civilian/clown_mime.dm @@ -13,6 +13,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/mime/sexy name = "sexy mime outfit" diff --git a/code/modules/clothing/under/jobs/civilian/curator.dm b/code/modules/clothing/under/jobs/civilian/curator.dm index 86a8683d56f..f9d822d6130 100644 --- a/code/modules/clothing/under/jobs/civilian/curator.dm +++ b/code/modules/clothing/under/jobs/civilian/curator.dm @@ -18,6 +18,7 @@ can_adjust = FALSE dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/civilian/curator/treasure_hunter name = "treasure hunter uniform" diff --git a/code/modules/clothing/under/jobs/command.dm b/code/modules/clothing/under/jobs/command.dm index dbf33c259fc..42580be448d 100644 --- a/code/modules/clothing/under/jobs/command.dm +++ b/code/modules/clothing/under/jobs/command.dm @@ -33,6 +33,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/captain/parade name = "captain's parade uniform" diff --git a/code/modules/clothing/under/jobs/engineering.dm b/code/modules/clothing/under/jobs/engineering.dm index 3ae5668db3c..bd95efc8830 100644 --- a/code/modules/clothing/under/jobs/engineering.dm +++ b/code/modules/clothing/under/jobs/engineering.dm @@ -21,6 +21,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/engineering/atmospheric_technician desc = "It's a jumpsuit worn by atmospheric technicians. Made from fire resistant materials." @@ -36,6 +37,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/engineering/engineer desc = "It's an orange high visibility jumpsuit worn by engineers. Made from fire resistant materials." @@ -59,3 +61,4 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON diff --git a/code/modules/clothing/under/jobs/medical.dm b/code/modules/clothing/under/jobs/medical.dm index 652634ae053..251ec3d3a69 100644 --- a/code/modules/clothing/under/jobs/medical.dm +++ b/code/modules/clothing/under/jobs/medical.dm @@ -18,6 +18,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/medical/chief_medical_officer desc = "It's a jumpsuit worn by those with the experience to be \"Chief Medical Officer\". It provides minor biological protection." @@ -33,6 +34,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/medical/chief_medical_officer/turtleneck name = "chief medical officer's turtleneck" @@ -51,6 +53,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/medical/virologist desc = "It's made of a special fiber that gives special protection against biohazards. It has a virologist rank stripe on it." @@ -66,6 +69,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/medical/scrubs name = "medical scrubs" @@ -98,6 +102,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/medical/paramedic desc = "It's made of a special fiber that provides minor protection against biohazards. It has a dark blue cross on the chest denoting that the wearer is a trained paramedic." @@ -114,6 +119,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/medical/doctor/nurse desc = "It's a jumpsuit commonly worn by nursing staff in the medical department." diff --git a/code/modules/clothing/under/jobs/rnd.dm b/code/modules/clothing/under/jobs/rnd.dm index ed1a2d3ae78..1d657056b76 100644 --- a/code/modules/clothing/under/jobs/rnd.dm +++ b/code/modules/clothing/under/jobs/rnd.dm @@ -23,6 +23,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/rnd/research_director/alt desc = "Maybe you'll engineer your own half-man, half-pig creature some day. Its fabric provides minor protection from biological contaminants." @@ -40,6 +41,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/rnd/research_director/turtleneck desc = "A dark purple turtleneck and tan khakis, for a director with a superior sense of style." @@ -57,6 +59,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/rnd/scientist desc = "It's made of a special fiber that provides minor protection against explosives. It has markings that denote the wearer as a scientist." @@ -73,6 +76,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/rnd/roboticist desc = "It's a slimming black with reinforced seams; great for industrial work." @@ -89,6 +93,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/rnd/geneticist desc = "It's made of a special fiber that gives special protection against biohazards. It has a genetics rank stripe on it." @@ -106,3 +111,4 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm index 661603703ce..b946e27e55f 100644 --- a/code/modules/clothing/under/jobs/security.dm +++ b/code/modules/clothing/under/jobs/security.dm @@ -37,6 +37,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/security/officer/blueshirt name = "blue shirt and tie" @@ -81,6 +82,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/security/warden/formal desc = "The insignia on this uniform tells you that this uniform belongs to the Warden." @@ -108,6 +110,7 @@ dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY alt_covers_chest = TRUE + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/security/detective/noir name = "noir suit" @@ -125,6 +128,7 @@ dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY alt_covers_chest = TRUE + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /* * Head of Security @@ -145,6 +149,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/security/head_of_security/grey name = "head of security's grey jumpsuit" @@ -168,6 +173,7 @@ dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY alt_covers_chest = TRUE + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/security/head_of_security/parade name = "head of security's parade uniform" @@ -228,6 +234,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/rank/security/officer/beatcop name = "space police uniform" diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm index d523b63b014..6c409b98ca1 100644 --- a/code/modules/clothing/under/shorts.dm +++ b/code/modules/clothing/under/shorts.dm @@ -4,7 +4,7 @@ gender = PLURAL body_parts_covered = GROIN female_sprite_flags = NO_FEMALE_UNIFORM - mutantrace_variation = MUTANTRACE_VARIATION + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION can_adjust = FALSE icon = 'icons/obj/clothing/under/shorts_pants.dmi' worn_icon = 'icons/mob/clothing/under/shorts_pants.dmi' diff --git a/code/modules/clothing/under/skirt_dress.dm b/code/modules/clothing/under/skirt_dress.dm index f3a7521b804..e5b964ca2f7 100644 --- a/code/modules/clothing/under/skirt_dress.dm +++ b/code/modules/clothing/under/skirt_dress.dm @@ -2,6 +2,7 @@ female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY can_adjust = FALSE body_parts_covered = CHEST|GROIN + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON icon = 'icons/obj/clothing/under/dress.dmi' worn_icon = 'icons/mob/clothing/under/dress.dmi' diff --git a/code/modules/clothing/under/suits.dm b/code/modules/clothing/under/suits.dm index a9cbc662580..f148cc16683 100644 --- a/code/modules/clothing/under/suits.dm +++ b/code/modules/clothing/under/suits.dm @@ -18,6 +18,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY|FEMALE_UNIFORM_NO_BREASTS + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/suit/sl desc = "It's a very amish looking suit." @@ -53,6 +54,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY|FEMALE_UNIFORM_NO_BREASTS + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/suit/black_really name = "executive suit" @@ -68,6 +70,7 @@ body_parts_covered = CHEST|GROIN|ARMS dying_key = DYE_REGISTRY_JUMPSKIRT female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY|FEMALE_UNIFORM_NO_BREASTS + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/suit/green name = "green suit" diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm index 426d992c538..5ed37be56b8 100644 --- a/code/modules/clothing/under/syndicate.dm +++ b/code/modules/clothing/under/syndicate.dm @@ -19,6 +19,7 @@ alt_covers_chest = TRUE female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY dying_key = DYE_REGISTRY_JUMPSKIRT + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/syndicate/bloodred name = "blood-red sneaksuit" @@ -51,6 +52,7 @@ armor = list(MELEE = 0, BULLET = 0, LASER = 0,ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 50, ACID = 40) female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY dying_key = DYE_REGISTRY_JUMPSKIRT + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON /obj/item/clothing/under/syndicate/sniper name = "tactical turtleneck suit" diff --git a/code/modules/games/wizoff.dm b/code/modules/games/wizoff.dm index 05044ea392d..73be649593a 100644 --- a/code/modules/games/wizoff.dm +++ b/code/modules/games/wizoff.dm @@ -13,13 +13,14 @@ cards += generate_card("[card]") /obj/item/toy/cards/deck/wizoff/examine_more(mob/user) - var/list/msg = list(span_notice("Remember the rules of Wiz-Off!")) - msg += "\t[span_info("Each player draws 5 cards.")]" - msg += "\t[span_info("There are five rounds. Each round, a player selects a card to play, and the winner is selected based on the following rules:")]" - msg += "\t[span_info("Defensive beats Offensive!")]" - msg += "\t[span_info("Offensive beats Utility!")]" - msg += "\t[span_info("Utility beats Defensive!")]" - msg += "\t[span_info("If both players play the same type of spell, the higher number wins!")]" - msg += "\t[span_info("The player who wins the most of the 5 rounds wins the game!")]" - msg += "\t[span_notice("Now get ready to battle for the fate of the universe: Wiz-Off!")]" - return msg + . = ..() + . += span_notice("Remember the rules of Wiz-Off!") + . += "\t[span_info("Each player draws 5 cards.")]" + . += "\t[span_info("There are five rounds. Each round, a player selects a card to play, and the winner is selected based on the following rules:")]" + . += "\t[span_info("Defensive beats Offensive!")]" + . += "\t[span_info("Offensive beats Utility!")]" + . += "\t[span_info("Utility beats Defensive!")]" + . += "\t[span_info("If both players play the same type of spell, the higher number wins!")]" + . += "\t[span_info("The player who wins the most of the 5 rounds wins the game!")]" + . += "\t[span_notice("Now get ready to battle for the fate of the universe: Wiz-Off!")]" + return . diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index df2e891e04c..9d187a823f2 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -445,7 +445,7 @@ if(require_human) player_client.prefs.randomise["species"] = FALSE player_client.prefs.safe_transfer_prefs_to(src, TRUE, is_antag) - if (require_human && !ishumanbasic(src)) + if(require_human && !ishumanbasic(src)) set_species(/datum/species/human) dna.species.roundstart_changed = TRUE apply_pref_name(/datum/preference/name/backup_human, player_client) diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 6fb0f9e3043..2f6eb869f3b 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -202,7 +202,7 @@ worn_icon_state = "[base_icon_state]_impregnated" var/obj/item/bodypart/chest/LC = target.get_bodypart(BODY_ZONE_CHEST) - if((!LC || LC.status != BODYPART_ROBOTIC) && !target.getorgan(/obj/item/organ/body_egg/alien_embryo)) + if((!LC || IS_ORGANIC_LIMB(LC)) && !target.getorgan(/obj/item/organ/body_egg/alien_embryo)) new /obj/item/organ/body_egg/alien_embryo(target) var/turf/T = get_turf(target) log_game("[key_name(target)] was impregnated by a facehugger at [loc_name(T)]") diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index c13b54af5e3..f4801021327 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1,7 +1,6 @@ /mob/living/carbon/Initialize(mapload) . = ..() create_reagents(1000, REAGENT_HOLDER_ALIVE) - assign_bodypart_ownership() update_body_parts() //to update the carbon's new bodyparts appearance register_context() @@ -348,7 +347,7 @@ return FALSE visible_message(span_danger("[src] manages to [cuff_break ? "break" : "remove"] [I]!")) to_chat(src, span_notice("You successfully [cuff_break ? "break" : "remove"] [I].")) - + if(cuff_break) . = !((I == handcuffed) || (I == legcuffed)) qdel(I) @@ -1000,6 +999,7 @@ ///Proc to hook behavior on bodypart additions. /mob/living/carbon/proc/add_bodypart(obj/item/bodypart/new_bodypart) bodyparts += new_bodypart + new_bodypart.owner = src switch(new_bodypart.body_part) if(LEG_LEFT, LEG_RIGHT) @@ -1015,7 +1015,6 @@ ///Proc to hook behavior on bodypart removals. /mob/living/carbon/proc/remove_bodypart(obj/item/bodypart/old_bodypart) bodyparts -= old_bodypart - switch(old_bodypart.body_part) if(LEG_LEFT, LEG_RIGHT) set_num_legs(num_legs - 1) @@ -1049,43 +1048,52 @@ if(href_list[VV_HK_MODIFY_BODYPART]) if(!check_rights(R_SPAWN)) return - var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment") + var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("replace","remove") if(!edit_action) return var/list/limb_list = list() - if(edit_action == "remove" || edit_action == "augment") - for(var/obj/item/bodypart/B in bodyparts) + if(edit_action == "remove") + for(var/obj/item/bodypart/B as anything in bodyparts) limb_list += B.body_zone - if(edit_action == "remove") limb_list -= BODY_ZONE_CHEST else - limb_list = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - for(var/obj/item/bodypart/B in bodyparts) - limb_list -= B.body_zone - var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in sort_list(limb_list) + limb_list = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_CHEST) + var/result = input(usr, "Please choose which bodypart to [edit_action]","[capitalize(edit_action)] Bodypart") as null|anything in sort_list(limb_list) if(result) var/obj/item/bodypart/BP = get_bodypart(result) + var/list/limbtypes = list() + switch(result) + if(BODY_ZONE_CHEST) + limbtypes = typesof(/obj/item/bodypart/chest) + if(BODY_ZONE_R_ARM) + limbtypes = typesof(/obj/item/bodypart/r_arm) + if(BODY_ZONE_L_ARM) + limbtypes = typesof(/obj/item/bodypart/l_arm) + if(BODY_ZONE_HEAD) + limbtypes = typesof(/obj/item/bodypart/head) + if(BODY_ZONE_L_LEG) + limbtypes = typesof(/obj/item/bodypart/l_leg) + if(BODY_ZONE_R_LEG) + limbtypes = typesof(/obj/item/bodypart/r_leg) switch(edit_action) if("remove") if(BP) - BP.drop_limb() + BP.drop_limb(special = TRUE) + admin_ticket_log("[key_name_admin(usr)] has removed [src]'s [parse_zone(BP.body_zone)]") else to_chat(usr, span_boldwarning("[src] doesn't have such bodypart.")) - if("add") - if(BP) - to_chat(usr, span_boldwarning("[src] already has such bodypart.")) + admin_ticket_log("[key_name_admin(usr)] has attempted to modify the bodyparts of [src]") + if("replace") + var/limb2add = input(usr, "Select a bodypart type to add", "Add/Replace Bodypart") as null|anything in sort_list(limbtypes) + var/obj/item/bodypart/new_bp = new limb2add() + + if(new_bp.replace_limb(src, special = TRUE)) + admin_ticket_log("key_name_admin(usr)] has replaced [src]'s [BP.type] with [new_bp.type]") + qdel(BP) else - if(!regenerate_limb(result)) - to_chat(usr, span_boldwarning("[src] cannot have such bodypart.")) - if("augment") - if(ishuman(src)) - if(BP) - BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE) - else - to_chat(usr, span_boldwarning("[src] doesn't have such bodypart.")) - else - to_chat(usr, span_boldwarning("Only humans can be augmented.")) - admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src]") + to_chat(usr, "Failed to replace bodypart! They might be incompatible.") + admin_ticket_log("[key_name_admin(usr)] has attempted to modify the bodyparts of [src]") + if(href_list[VV_HK_MAKE_AI]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index f4962699cc3..6f2abf2eda5 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -82,11 +82,11 @@ if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest) affecting = bodyparts[1] SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting) - send_item_attack_message(I, user, affecting.name, affecting) + send_item_attack_message(I, user, parse_zone(affecting.body_zone), affecting) if(I.force) var/attack_direction = get_dir(user, src) apply_damage(I.force, I.damtype, affecting, wound_bonus = I.wound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness(), attack_direction = attack_direction) - if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC) + if(I.damtype == BRUTE && IS_ORGANIC_LIMB(affecting)) if(prob(33)) I.add_mob_blood(src) var/turf/location = get_turf(src) @@ -643,7 +643,7 @@ . = health for (var/_limb in bodyparts) var/obj/item/bodypart/limb = _limb - if (limb.status != BODYPART_ORGANIC) + if (IS_ORGANIC_LIMB(limb)) . += (limb.brute_dam * limb.body_damage_coeff) + (limb.burn_dam * limb.body_damage_coeff) /mob/living/carbon/grabbedby(mob/living/carbon/user, supress_message = FALSE) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 6c0bab0bed7..6426cdb8f7f 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -74,7 +74,8 @@ /// A collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems) var/list/hand_bodyparts = list() - var/icon_render_key = "" + ///A cache of bodypart = icon to prevent excessive icon creation. + var/list/icon_render_keys = list() var/static/list/limb_icon_cache = list() //halucination vars diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index 4bd940c9e9f..483582ed7af 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -40,10 +40,12 @@ /mob/living/carbon/regenerate_icons() if(notransform) return 1 + icon_render_keys = list() //Clear this bad larry out update_inv_hands() update_inv_handcuffed() update_inv_legcuffed() update_fire() + update_body_parts() /mob/living/carbon/update_inv_hands() @@ -226,85 +228,110 @@ . += emissive_blocker(standing.icon, standing.icon_state, alpha = standing.alpha) -/mob/living/carbon/update_body() - update_body_parts() +/mob/living/carbon/update_body(is_creating) + update_body_parts(is_creating) -/mob/living/carbon/proc/assign_bodypart_ownership() - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - BP.original_owner = WEAKREF(src) +///Checks to see if any bodyparts need to be redrawn, then does so. update_limb_data = TRUE redraws the limbs to conform to the owner. +/mob/living/carbon/proc/update_body_parts(update_limb_data) + update_damage_overlays() + update_wound_overlays() + var/list/needs_update = list() + var/limb_count_update = FALSE + for(var/obj/item/bodypart/limb as anything in bodyparts) + limb.update_limb(is_creating = update_limb_data) //Update limb actually doesn't do much, get_limb_icon is the cpu eater. + var/old_key = icon_render_keys?[limb.body_zone] //Checks the mob's icon render key list for the bodypart + icon_render_keys[limb.body_zone] = (limb.is_husked) ? limb.generate_husk_key().Join() : limb.generate_icon_key().Join() //Generates a key for the current bodypart + if(!(icon_render_keys[limb.body_zone] == old_key)) //If the keys match, that means the limb doesn't need to be redrawn + needs_update += limb -/mob/living/carbon/proc/update_body_parts() - //CHECK FOR UPDATE - var/oldkey = icon_render_key - icon_render_key = generate_icon_render_key() - if(oldkey == icon_render_key) + + var/list/missing_bodyparts = get_missing_limbs() + if(((dna ? dna.species.max_bodypart_count : BODYPARTS_DEFAULT_MAXIMUM) - icon_render_keys.len) != missing_bodyparts.len) //Checks to see if the target gained or lost any limbs. + limb_count_update = TRUE + for(var/missing_limb in missing_bodyparts) + icon_render_keys -= missing_limb //Removes dismembered limbs from the key list + + if(!needs_update.len && !limb_count_update) return remove_overlay(BODYPARTS_LAYER) - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - BP.update_limb() - - //LOAD ICONS - if(limb_icon_cache[icon_render_key]) - load_limb_from_cache() - return - //GENERATE NEW LIMBS var/list/new_limbs = list() - var/draw_features = !HAS_TRAIT(src, TRAIT_INVISIBLE_MAN) - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - new_limbs += BP.get_limb_icon(draw_external_organs = draw_features) + for(var/obj/item/bodypart/limb as anything in bodyparts) + if(limb in needs_update) //Checks to see if the limb needs to be redrawn + var/bodypart_icon = limb.get_limb_icon() + new_limbs += bodypart_icon + limb_icon_cache[icon_render_keys[limb.body_zone]] = bodypart_icon //Caches the icon with the bodypart key, as it is new + else + new_limbs += limb_icon_cache[icon_render_keys[limb.body_zone]] //Pulls existing sprites from the cache + if(new_limbs.len) overlays_standing[BODYPARTS_LAYER] = new_limbs - limb_icon_cache[icon_render_key] = new_limbs apply_overlay(BODYPARTS_LAYER) - update_damage_overlays() - update_wound_overlays() -///////////////////// -// Limb Icon Cache // -///////////////////// -/* - Called from update_body_parts() these procs handle the limb icon cache. - the limb icon cache adds an icon_render_key to a human mob, it represents: - - skin_tone (if applicable) - - gender - - limbs (stores as the limb name and whether it is removed/fine, organic/robotic) - These procs only store limbs as to increase the number of matching icon_render_keys - This cache exists because drawing 6/7 icons for humans constantly is quite a waste - See RemieRichards on irc.rizon.net #coderbus (RIP remie :sob:) -*/ +///////////////////////// +// Limb Icon Cache 2.0 // +///////////////////////// +/** + * Called from update_body_parts() these procs handle the limb icon cache. + * the limb icon cache adds an icon_render_key to a human mob, it represents: + * - Gender, if applicable + * - The ID of the limb + * - Draw color, if applicable + * These procs only store limbs as to increase the number of matching icon_render_keys + * This cache exists because drawing 6/7 icons for humans constantly is quite a waste + * See RemieRichards on irc.rizon.net #coderbus (RIP remie :sob:) +**/ +/obj/item/bodypart/proc/generate_icon_key() + RETURN_TYPE(/list) + . = list() + if(is_dimorphic) + . += "[limb_gender]-" + . += "[limb_id]" + . += "-[body_zone]" + if(should_draw_greyscale && draw_color) + . += "-[draw_color]" + for(var/obj/item/organ/external/external_organ as anything in external_organs) + if(!external_organ.can_draw_on_bodypart(owner)) + continue + . += "-[external_organ.generate_icon_cache()]" -//produces a key based on the mob's limbs + return . -/mob/living/carbon/proc/generate_icon_render_key() - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - . += "-[BP.body_zone]" - if(BP.use_digitigrade) - . += "-digitigrade[BP.use_digitigrade]" - if(BP.animal_origin) - . += "-[BP.animal_origin]" - if(BP.status == BODYPART_ORGANIC) - . += "-organic" - else - . += "-robotic" +///Generates a cache key specifically for husks +/obj/item/bodypart/proc/generate_husk_key() + RETURN_TYPE(/list) + . = list() + . += "[husk_type]" + . += "-husk" + . += "-[body_zone]" + return . - if(HAS_TRAIT(src, TRAIT_HUSK)) - . += "-husk" +/obj/item/bodypart/head/generate_icon_key() + . = ..() + . += "-[facial_hairstyle]" + . += "-[facial_hair_color]" + if(facial_hair_gradient_style) + . += "-[facial_hair_gradient_style]" + if(hair_gradient_color) + . += "-[facial_hair_gradient_color]" + if(facial_hair_hidden) + . += "-FACIAL_HAIR_HIDDEN" + if(show_debrained) + . += "-SHOW_DEBRAINED" + return . + . += "-[hair_style]" + . += "-[fixed_hair_color || override_hair_color || hair_color]" + if(hair_gradient_style) + . += "-[hair_gradient_style]" + if(hair_gradient_color) + . += "-[hair_gradient_color]" + if(hair_hidden) + . += "-HAIR_HIDDEN" -//change the mob's icon to the one matching its key -/mob/living/carbon/proc/load_limb_from_cache() - if(limb_icon_cache[icon_render_key]) - remove_overlay(BODYPARTS_LAYER) - overlays_standing[BODYPARTS_LAYER] = limb_icon_cache[icon_render_key] - apply_overlay(BODYPARTS_LAYER) - update_damage_overlays() + return . diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm index 65d410c314c..bac5a8dcc38 100644 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -68,7 +68,7 @@ if(amount > 0) take_overall_damage(amount, 0, 0, updating_health, required_status) else - heal_overall_damage(abs(amount), 0, 0, required_status ? required_status : BODYPART_ORGANIC, updating_health) + heal_overall_damage(abs(amount), 0, 0, required_status ? required_status : BODYTYPE_ORGANIC, updating_health) return amount /mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, required_status) @@ -77,7 +77,7 @@ if(amount > 0) take_overall_damage(0, amount, 0, updating_health, required_status) else - heal_overall_damage(0, abs(amount), 0, required_status ? required_status : BODYPART_ORGANIC, updating_health) + heal_overall_damage(0, abs(amount), 0, required_status ? required_status : BODYTYPE_ORGANIC, updating_health) return amount /mob/living/carbon/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE) @@ -159,7 +159,7 @@ var/list/obj/item/bodypart/parts = list() for(var/X in bodyparts) var/obj/item/bodypart/BP = X - if(status && (BP.status != status)) + if(status && !(BP.bodytype & status)) continue if((brute && BP.brute_dam) || (burn && BP.burn_dam) || (stamina && BP.stamina_dam)) parts += BP @@ -170,7 +170,7 @@ var/list/obj/item/bodypart/parts = list() for(var/X in bodyparts) var/obj/item/bodypart/BP = X - if(status && (BP.status != status)) + if(status && !(BP.bodytype & status)) continue if(BP.brute_dam + BP.burn_dam < BP.max_damage) parts += BP diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 2b8d710bb60..c12be3b336f 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -155,8 +155,16 @@ SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .) /mob/living/carbon/examine_more(mob/user) - if(!all_scars) - return ..() + . = ..() + . += span_notice("You examine [src] closer, and note the following...") + + //On closer inspection, this man isnt a man at all! + var/list/covered_zones = get_covered_body_zones() + for(var/obj/item/bodypart/part as anything in bodyparts) + if(part.body_zone in covered_zones) + continue + if(part.limb_id != (dna.species.examine_limb_id ? dna.species.examine_limb_id : dna.species.id)) + . += "[span_info("[p_they(TRUE)] [p_have()] \an [part.name].")]" var/list/visible_scars for(var/i in all_scars) @@ -164,14 +172,10 @@ if(S.is_visible(user)) LAZYADD(visible_scars, S) - if(!visible_scars) - return ..() - - var/msg = list(span_notice("You examine [src] closer, and note the following...")) for(var/i in visible_scars) var/datum/scar/S = i var/scar_text = S.get_examine_description(user) if(scar_text) - msg += "[scar_text]" + . += "[scar_text]" - return msg + return . diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 7d26e1384ee..4b13f71cf3a 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -46,7 +46,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) //Instead of just deleting our equipment, we save what we can and reinsert it into SSwardrobe's store //Hopefully this makes preference reloading not the worst thing ever /mob/living/carbon/human/dummy/delete_equipment() - var/list/items_to_check = get_all_slots() + held_items + var/list/items_to_check = get_all_worn_items() + held_items var/list/to_nuke = list() //List of items queued for deletion, can't qdel them before iterating their contents in case they hold something ///Travel to the bottom of the contents chain, expanding it out for(var/i = 1; i <= length(items_to_check); i++) //Needs to be a c style loop since it can expand diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index d2143b6f4e1..77dda59a920 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -9,15 +9,18 @@ var/t_es = p_es() var/obscure_name + var/obscured = check_obscured_slots() + var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE)) + if(isliving(user)) var/mob/living/L = user if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA) || HAS_TRAIT(L, TRAIT_INVISIBLE_MAN)) obscure_name = TRUE - . = list("*---------*\nThis is [!obscure_name ? name : "Unknown"]!") - - var/obscured = check_obscured_slots() - var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE)) + var/apparent_species + if(dna?.species && !skipface) + apparent_species = ", \an [dna.species.name]" + . = list("*---------*\nThis is [!obscure_name ? name : "Unknown"][apparent_species]!") //uniform if(w_uniform && !(obscured & ITEM_SLOT_ICLOTHING) && !(w_uniform.item_flags & EXAMINE_SKIP)) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 0bf5ae9fe6f..1868c8cff46 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -8,6 +8,7 @@ create_bodyparts() setup_human_dna() + prepare_huds() //Prevents a nasty runtime on human init if(dna.species) INVOKE_ASYNC(src, .proc/set_species, dna.species.type) @@ -473,8 +474,7 @@ facial_hairstyle = "Shaved" hairstyle = pick("Bedhead", "Bedhead 2", "Bedhead 3") underwear = "Nude" - update_body() - update_hair() + update_body(is_creating = TRUE) /mob/living/carbon/human/singularity_pull(S, current_size) ..() @@ -1147,12 +1147,6 @@ /mob/living/carbon/human/species/snail race = /datum/species/snail -/mob/living/carbon/human/species/synth - race = /datum/species/synth - -/mob/living/carbon/human/species/synth/military - race = /datum/species/synth/military - /mob/living/carbon/human/species/vampire race = /datum/species/vampire @@ -1161,6 +1155,3 @@ /mob/living/carbon/human/species/zombie/infectious race = /datum/species/zombie/infectious - -/mob/living/carbon/human/species/zombie/krokodil_addict - race = /datum/species/krokodil_addict diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index e6ab4dd5796..3ee611c243c 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -478,7 +478,7 @@ for(var/X in bodyparts) var/obj/item/bodypart/BP = X if(prob(probability) && !prob(getarmor(BP, BOMB)) && BP.body_zone != BODY_ZONE_HEAD && BP.body_zone != BODY_ZONE_CHEST) - BP.brute_dam = BP.max_damage + BP.receive_damage(INFINITY, wound_bonus = CANT_WOUND) //Capped by proc BP.dismember() max_limb_loss-- if(!max_limb_loss) @@ -529,8 +529,8 @@ if(. & EMP_PROTECT_CONTENTS) return var/informed = FALSE - for(var/obj/item/bodypart/L in src.bodyparts) - if(L.status == BODYPART_ROBOTIC) + 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 diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index e2d6e85bcb2..102d3475e36 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -69,7 +69,7 @@ var/hardcore_survival_score = 0 /// Which body type to use - var/body_type = MALE + var/physique = MALE /// How many "units of blood" we have on our hands var/blood_in_hands = 0 diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index e42da6b6bc9..f07c313a37b 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -1,3 +1,5 @@ +#define RESOLVE_ICON_STATE(worn_item) (worn_item.worn_icon_state || worn_item.icon_state) + /////////////////////// //UPDATE_ICONS SYSTEM// /////////////////////// @@ -6,7 +8,7 @@ This system allows you to update individual mob-overlays, without regenerating t When we generate overlays we generate the standing version and then rotate the mob as necessary.. As of the time of writing there are 20 layers within this list. Please try to keep this from increasing. //22 and counting, good job guys - var/overlays_standing[20] //For the standing stance + var/overlays_standing[20] //For the standing stance Most of the time we only wish to update one overlay: e.g. - we dropped the fireaxe out of our left hand and need to remove its icon from our mob @@ -28,7 +30,7 @@ Note: The defines for layer numbers is now kept exclusvely in __DEFINES/misc.dm All of this means that this code is more maintainable, faster and still fairly easy to use. There are several things that need to be remembered: -> Whenever we do something that should cause an overlay to update (which doesn't use standard procs +> Whenever we do something that should cause an overlay to update (which doesn't use standard procs ( i.e. you do something like l_hand = /obj/item/something new(src), rather than using the helper procs) You will need to call the relevant update_inv_* proc @@ -37,33 +39,38 @@ There are several things that need to be remembered: slime etc. Instead, it'll just return without doing any work. So no harm in calling it for slimes and such. -> There are also these special cases: - update_damage_overlays() //handles damage overlays for brute/burn damage - update_body() //Handles updating your mob's body layer and mutant bodyparts +> There are also these special cases: + update_damage_overlays() //handles damage overlays for brute/burn damage + update_body() //Handles updating your mob's body layer and mutant bodyparts as well as sprite-accessories that didn't really fit elsewhere (underwear, undershirts, socks, lips, eyes) //NOTE: update_mutantrace() is now merged into this! - update_hair() //Handles updating your hair overlay (used to be update_face, but mouth and + update_hair() //Handles updating your hair overlay (used to be update_face, but mouth and eyes were merged into update_body()) */ //HAIR OVERLAY -/mob/living/carbon/human/update_hair() - dna.species.handle_hair(src) +/mob/living/carbon/human/update_hair(is_creating) + var/obj/item/bodypart/head/my_head = get_bodypart(BODY_ZONE_HEAD) + if(!my_head) + return + my_head.update_limb(FALSE, is_creating) + update_body_parts() + //used when putting/removing clothes that hide certain mutant body parts to just update those and not update the whole body. /mob/living/carbon/human/proc/update_mutant_bodyparts() dna.species.handle_mutant_bodyparts(src) - update_body_parts() // basically a better and cooler handle_mutant_bodyparts (at least until handle_mutant_bodyparts is annihilated) + update_body_parts() -/mob/living/carbon/human/update_body() +/mob/living/carbon/human/update_body(is_creating = FALSE) dna.species.handle_body(src) ..() /mob/living/carbon/human/update_fire() - ..((fire_stacks > HUMAN_FIRE_STACK_ICON_NUM) ? dna.species.fire_overlay : "Generic_mob_burning") + ..((fire_stacks > HUMAN_FIRE_STACK_ICON_NUM) ? "Standing" : "Generic_mob_burning") /* --------------------------------------- */ @@ -71,7 +78,6 @@ There are several things that need to be remembered: /mob/living/carbon/human/regenerate_icons() if(!..()) - icon_render_key = null //invalidate bodyparts cache update_body() update_hair() update_inv_w_uniform() @@ -102,15 +108,11 @@ There are several things that need to be remembered: if(client && hud_used) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_ICLOTHING) + 1] - inv.update_appearance() + inv.update_icon() if(istype(w_uniform, /obj/item/clothing/under)) var/obj/item/clothing/under/U = w_uniform - U.screen_loc = ui_iclothing - if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) - client.screen += w_uniform - update_observer_view(w_uniform,1) + update_hud_uniform(U) if(wear_suit && (wear_suit.flags_inv & HIDEJUMPSUIT)) return @@ -119,95 +121,114 @@ There are several things that need to be remembered: var/target_overlay = U.icon_state if(U.adjusted == ALT_STYLE) target_overlay = "[target_overlay]_d" - else if(U.adjusted == DIGITIGRADE_STYLE) - target_overlay = "[target_overlay]_l" - var/mutable_appearance/uniform_overlay - if(dna?.species.sexes) - if(body_type == FEMALE && U.female_sprite_flags != NO_FEMALE_UNIFORM) - uniform_overlay = U.build_worn_icon(default_layer = UNIFORM_LAYER, default_icon_file = 'icons/mob/clothing/under/default.dmi', isinhands = FALSE, femaleuniform = U.female_sprite_flags, override_state = target_overlay) - + //Change check_adjustable_clothing.dm if you change this + var/handled_by_bodytype = TRUE + var/icon_file + var/woman if(!uniform_overlay) - uniform_overlay = U.build_worn_icon(default_layer = UNIFORM_LAYER, default_icon_file = 'icons/mob/clothing/under/default.dmi', isinhands = FALSE, override_state = target_overlay) + //BEGIN SPECIES HANDLING + if((dna?.species.bodytype & BODYTYPE_DIGITIGRADE) && (U.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) + icon_file = DIGITIGRADE_UNIFORM_FILE - if(OFFSET_UNIFORM in dna.species.offset_features) - uniform_overlay.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1] - uniform_overlay.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2] + //Female sprites have lower priority than digitigrade sprites + else if(dna.species.sexes && (dna.species.bodytype & BODYTYPE_HUMANOID) && physique == FEMALE && U.adjusted != NO_FEMALE_UNIFORM) //Agggggggghhhhh + woman = TRUE + + if(!icon_exists(icon_file, RESOLVE_ICON_STATE(U))) + icon_file = DEFAULT_UNIFORM_FILE + handled_by_bodytype = FALSE + //END SPECIES HANDLING + uniform_overlay = U.build_worn_icon( + default_layer = UNIFORM_LAYER, + default_icon_file = icon_file, + isinhands = FALSE, + femaleuniform = woman ? U.adjusted : null, + override_state = target_overlay, + override_file = handled_by_bodytype ? icon_file : null + ) + + if(OFFSET_UNIFORM in dna.species.offset_features && !handled_by_bodytype) + uniform_overlay?.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1] + uniform_overlay?.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2] overlays_standing[UNIFORM_LAYER] = uniform_overlay + apply_overlay(UNIFORM_LAYER) - apply_overlay(UNIFORM_LAYER) update_mutant_bodyparts() - /mob/living/carbon/human/update_inv_wear_id() remove_overlay(ID_LAYER) - remove_overlay(ID_CARD_LAYER) if(client && hud_used) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_ID) + 1] - inv.update_appearance() + inv.update_icon() var/mutable_appearance/id_overlay = overlays_standing[ID_LAYER] if(wear_id) - wear_id.screen_loc = ui_id - if(client && hud_used?.hud_shown) - client.screen += wear_id - update_observer_view(wear_id) + var/obj/item/worn_item = wear_id + update_hud_id(worn_item) + var/handled_by_bodytype + var/icon_file - //TODO: add an icon file for ID slot stuff, so it's less snowflakey - id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = 'icons/mob/clothing/id.dmi') - if(OFFSET_ID in dna.species.offset_features) + if(!icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item))) + icon_file = 'icons/mob/mob.dmi' + handled_by_bodytype = FALSE + + id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = icon_file) + + if(!id_overlay) + return + if(OFFSET_ID in dna.species.offset_features && !handled_by_bodytype) id_overlay.pixel_x += dna.species.offset_features[OFFSET_ID][1] id_overlay.pixel_y += dna.species.offset_features[OFFSET_ID][2] overlays_standing[ID_LAYER] = id_overlay - var/obj/item/card/id/shown_id = wear_id.GetID() - if(shown_id) - var/mutable_appearance/id_card_overlay = overlays_standing[ID_CARD_LAYER] - id_card_overlay = shown_id.build_worn_icon(default_layer = ID_CARD_LAYER, default_icon_file = 'icons/mob/clothing/id_card.dmi') - if(OFFSET_ID in dna.species.offset_features) - id_card_overlay.pixel_x += dna.species.offset_features[OFFSET_ID][1] - id_card_overlay.pixel_y += dna.species.offset_features[OFFSET_ID][2] - - overlays_standing[ID_CARD_LAYER] = id_card_overlay - apply_overlay(ID_LAYER) - apply_overlay(ID_CARD_LAYER) /mob/living/carbon/human/update_inv_gloves() remove_overlay(GLOVES_LAYER) - if(client && hud_used?.inv_slots[TOBITSHIFT(ITEM_SLOT_GLOVES) + 1]) + if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_GLOVES) + 1]) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_GLOVES) + 1] - inv.update_appearance() + inv.update_icon() - if(!gloves && blood_in_hands && (num_hands > 0) && !(NOBLOODOVERLAY in dna.species.species_traits)) - var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER) + //Bloody hands begin + var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER) + cut_overlay(bloody_overlay) + if(!gloves && blood_in_hands && (num_hands > 0)) + bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER) if(num_hands < 2) if(has_left_hand(FALSE)) bloody_overlay.icon_state = "bloodyhands_left" else if(has_right_hand(FALSE)) bloody_overlay.icon_state = "bloodyhands_right" - overlays_standing[GLOVES_LAYER] = bloody_overlay + add_overlay(bloody_overlay) + //Bloody hands end - var/mutable_appearance/gloves_overlay = overlays_standing[GLOVES_LAYER] + var/mutable_appearance/gloves_overlay if(gloves) - gloves.screen_loc = ui_gloves - if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) - client.screen += gloves - update_observer_view(gloves,1) - overlays_standing[GLOVES_LAYER] = gloves.build_worn_icon(default_layer = GLOVES_LAYER, default_icon_file = 'icons/mob/clothing/hands.dmi') - gloves_overlay = overlays_standing[GLOVES_LAYER] - if(OFFSET_GLOVES in dna.species.offset_features) + var/obj/item/worn_item = gloves + update_hud_gloves(worn_item) + var/icon_file + var/handled_by_bodytype + + if(!icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item))) + icon_file = 'icons/mob/clothing/hands.dmi' + handled_by_bodytype = FALSE + + gloves_overlay = gloves.build_worn_icon(default_layer = GLOVES_LAYER, default_icon_file = icon_file) + + if(!gloves_overlay) + return + if(OFFSET_GLOVES in dna.species.offset_features && !handled_by_bodytype) gloves_overlay.pixel_x += dna.species.offset_features[OFFSET_GLOVES][1] gloves_overlay.pixel_y += dna.species.offset_features[OFFSET_GLOVES][2] - overlays_standing[GLOVES_LAYER] = gloves_overlay + overlays_standing[GLOVES_LAYER] = gloves_overlay apply_overlay(GLOVES_LAYER) @@ -219,24 +240,29 @@ There are several things that need to be remembered: if(client && hud_used) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_EYES) + 1] - inv.update_appearance() + inv.update_icon() if(glasses) - glasses.screen_loc = ui_glasses //...draw the item in the inventory screen - if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) //if the inventory is open ... - client.screen += glasses //Either way, add the item to the HUD - update_observer_view(glasses,1) - //This is in case the glasses would be going above the hair, like welding goggles that were lifted up - if(!(head && (head.flags_inv & HIDEEYES)) && !(wear_mask && (wear_mask.flags_inv & HIDEEYES))) - overlays_standing[GLASSES_LAYER] = glasses.build_worn_icon(default_layer = GLASSES_LAYER, default_icon_file = 'icons/mob/clothing/eyes.dmi') + var/obj/item/worn_item = glasses + var/mutable_appearance/glasses_overlay + update_hud_glasses(worn_item) - var/mutable_appearance/glasses_overlay = overlays_standing[GLASSES_LAYER] - if(glasses_overlay) - if(OFFSET_GLASSES in dna.species.offset_features) - glasses_overlay.pixel_x += dna.species.offset_features[OFFSET_GLASSES][1] - glasses_overlay.pixel_y += dna.species.offset_features[OFFSET_GLASSES][2] - overlays_standing[GLASSES_LAYER] = glasses_overlay + var/handled_by_bodytype + var/icon_file + if(!(head?.flags_inv & HIDEEYES) && !(wear_mask?.flags_inv & HIDEEYES)) + + if(!icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item))) + icon_file = 'icons/mob/clothing/eyes.dmi' + handled_by_bodytype = FALSE + + glasses_overlay = glasses.build_worn_icon(default_layer = GLASSES_LAYER, default_icon_file = icon_file) + + if(!glasses_overlay) + return + if(OFFSET_GLASSES in dna.species.offset_features && !handled_by_bodytype) + glasses_overlay.pixel_x += dna.species.offset_features[OFFSET_GLASSES][1] + glasses_overlay.pixel_y += dna.species.offset_features[OFFSET_GLASSES][2] + overlays_standing[GLASSES_LAYER] = glasses_overlay apply_overlay(GLASSES_LAYER) @@ -248,22 +274,60 @@ There are several things that need to be remembered: if(client && hud_used) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_EARS) + 1] - inv.update_appearance() + inv.update_icon() if(ears) - ears.screen_loc = ui_ears //move the item to the appropriate screen loc - if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) //if the inventory is open - client.screen += ears //add it to the client's screen - update_observer_view(ears,1) - overlays_standing[EARS_LAYER] = ears.build_worn_icon(default_layer = EARS_LAYER, default_icon_file = 'icons/mob/clothing/ears.dmi') - var/mutable_appearance/ears_overlay = overlays_standing[EARS_LAYER] - if(OFFSET_EARS in dna.species.offset_features) + var/obj/item/worn_item = ears + var/mutable_appearance/ears_overlay + update_hud_ears(worn_item) + + var/handled_by_bodytype = TRUE + var/icon_file + + if(!(icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item)))) + handled_by_bodytype = FALSE + icon_file = 'icons/mob/clothing/ears.dmi' + + ears_overlay = ears.build_worn_icon(default_layer = EARS_LAYER, default_icon_file = icon_file) + + if(!ears_overlay) + return + if(OFFSET_EARS in dna.species.offset_features && !handled_by_bodytype) ears_overlay.pixel_x += dna.species.offset_features[OFFSET_EARS][1] ears_overlay.pixel_y += dna.species.offset_features[OFFSET_EARS][2] overlays_standing[EARS_LAYER] = ears_overlay apply_overlay(EARS_LAYER) +/mob/living/carbon/human/update_inv_neck() + remove_overlay(NECK_LAYER) + + if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_NECK) + 1]) + var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_NECK) + 1] + inv.update_icon() + + if(wear_neck) + var/obj/item/worn_item = wear_neck + + if(!(ITEM_SLOT_NECK in check_obscured_slots())) + var/mutable_appearance/neck_overlay + var/icon_file + var/handled_by_bodytype = TRUE + + if(!(icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item)))) + handled_by_bodytype = FALSE + icon_file = 'icons/mob/clothing/neck.dmi' + + neck_overlay = worn_item.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = icon_file) + + if(!neck_overlay) + return + if(OFFSET_NECK in dna.species.offset_features && !handled_by_bodytype) + neck_overlay.pixel_x += dna.species.offset_features[OFFSET_NECK][1] + neck_overlay.pixel_y += dna.species.offset_features[OFFSET_NECK][2] + overlays_standing[NECK_LAYER] = neck_overlay + update_hud_neck(wear_neck) + + apply_overlay(NECK_LAYER) /mob/living/carbon/human/update_inv_shoes() remove_overlay(SHOES_LAYER) @@ -273,17 +337,30 @@ There are several things that need to be remembered: if(client && hud_used) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_FEET) + 1] - inv.update_appearance() + inv.update_icon() if(shoes) - shoes.screen_loc = ui_shoes //move the item to the appropriate screen loc - if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) //if the inventory is open - client.screen += shoes //add it to client's screen - update_observer_view(shoes,1) - overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(default_layer = SHOES_LAYER, default_icon_file = 'icons/mob/clothing/feet.dmi') - var/mutable_appearance/shoes_overlay = overlays_standing[SHOES_LAYER] - if(OFFSET_SHOES in dna.species.offset_features) + var/obj/item/worn_item = shoes + var/mutable_appearance/shoes_overlay + var/icon_file + update_hud_shoes(worn_item) + var/handled_by_bodytype = TRUE + + //(Currently) unused digitigrade handling + /*if((dna.species.bodytype & BODYTYPE_DIGITIGRADE) && (worn_item.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) + var/obj/item/bodypart/leg = src.get_bodypart(BODY_ZONE_L_LEG) + if(leg.limb_id == "digitigrade")//Snowflakey and bad. But it makes it look consistent. + icon_file = DIGITIGRADE_SHOES_FILE*/ + + if(!(icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item)))) + handled_by_bodytype = FALSE + icon_file = DEFAULT_SHOES_FILE + + shoes_overlay = shoes.build_worn_icon(default_layer = SHOES_LAYER, default_icon_file = icon_file) + + if(!shoes_overlay) + return + if(!(handled_by_bodytype) && (OFFSET_SHOES in dna.species.offset_features)) shoes_overlay.pixel_x += dna.species.offset_features[OFFSET_SHOES][1] shoes_overlay.pixel_y += dna.species.offset_features[OFFSET_SHOES][2] overlays_standing[SHOES_LAYER] = shoes_overlay @@ -296,32 +373,50 @@ There are several things that need to be remembered: if(client && hud_used) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_SUITSTORE) + 1] - inv.update_appearance() + inv.update_icon() if(s_store) - s_store.screen_loc = ui_sstore1 - if(client && hud_used?.hud_shown) - client.screen += s_store - update_observer_view(s_store) - overlays_standing[SUIT_STORE_LAYER] = s_store.build_worn_icon(default_layer = SUIT_STORE_LAYER, default_icon_file = 'icons/mob/clothing/belt_mirror.dmi') - var/mutable_appearance/s_store_overlay = overlays_standing[SUIT_STORE_LAYER] + var/obj/item/worn_item = s_store + var/mutable_appearance/s_store_overlay + update_hud_s_store(worn_item) + + s_store_overlay = worn_item.build_worn_icon(default_layer = SUIT_STORE_LAYER, default_icon_file = 'icons/mob/clothing/belt_mirror.dmi') + + if(!s_store_overlay) + return if(OFFSET_S_STORE in dna.species.offset_features) s_store_overlay.pixel_x += dna.species.offset_features[OFFSET_S_STORE][1] s_store_overlay.pixel_y += dna.species.offset_features[OFFSET_S_STORE][2] overlays_standing[SUIT_STORE_LAYER] = s_store_overlay apply_overlay(SUIT_STORE_LAYER) - /mob/living/carbon/human/update_inv_head() - ..() - update_mutant_bodyparts() - var/mutable_appearance/head_overlay = overlays_standing[HEAD_LAYER] - if(head_overlay) - remove_overlay(HEAD_LAYER) - if(OFFSET_HEAD in dna.species.offset_features) + remove_overlay(HEAD_LAYER) + if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_BACK) + 1]) + var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_HEAD) + 1] + inv.update_icon() + + if(head) + var/obj/item/worn_item = head + var/mutable_appearance/head_overlay + update_hud_head(worn_item) + var/handled_by_bodytype = FALSE + var/icon_file + + if(!(icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item)))) + handled_by_bodytype = FALSE + icon_file = 'icons/mob/clothing/head.dmi' + + head_overlay = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = icon_file) + + if(!head_overlay) + return + if(!(handled_by_bodytype) && (OFFSET_HEAD in dna.species.offset_features)) head_overlay.pixel_x += dna.species.offset_features[OFFSET_HEAD][1] head_overlay.pixel_y += dna.species.offset_features[OFFSET_HEAD][2] - overlays_standing[HEAD_LAYER] = head_overlay + overlays_standing[HEAD_LAYER] = head_overlay + + update_mutant_bodyparts() apply_overlay(HEAD_LAYER) /mob/living/carbon/human/update_inv_belt() @@ -329,40 +424,59 @@ There are several things that need to be remembered: if(client && hud_used) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_BELT) + 1] - inv.update_appearance() + inv.update_icon() if(belt) - belt.screen_loc = ui_belt - if(client && hud_used?.hud_shown) - client.screen += belt - update_observer_view(belt) - overlays_standing[BELT_LAYER] = belt.build_worn_icon(default_layer = BELT_LAYER, default_icon_file = 'icons/mob/clothing/belt.dmi') - var/mutable_appearance/belt_overlay = overlays_standing[BELT_LAYER] - if(OFFSET_BELT in dna.species.offset_features) + var/obj/item/worn_item = belt + var/mutable_appearance/belt_overlay + update_hud_belt(worn_item) + var/handled_by_bodytype = TRUE + var/icon_file + + if(!(icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item)))) + handled_by_bodytype = FALSE + icon_file = 'icons/mob/clothing/belt.dmi' + + belt_overlay = belt.build_worn_icon(default_layer = BELT_LAYER, default_icon_file = icon_file) + + if(!belt_overlay) + return + if(OFFSET_BELT in dna.species.offset_features && !handled_by_bodytype) belt_overlay.pixel_x += dna.species.offset_features[OFFSET_BELT][1] belt_overlay.pixel_y += dna.species.offset_features[OFFSET_BELT][2] overlays_standing[BELT_LAYER] = belt_overlay apply_overlay(BELT_LAYER) - - /mob/living/carbon/human/update_inv_wear_suit() remove_overlay(SUIT_LAYER) if(client && hud_used) var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_OCLOTHING) + 1] - inv.update_appearance() + inv.update_icon() - if(istype(wear_suit, /obj/item/clothing/suit)) - wear_suit.screen_loc = ui_oclothing - if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) - client.screen += wear_suit - update_observer_view(wear_suit,1) - overlays_standing[SUIT_LAYER] = wear_suit.build_worn_icon(default_layer = SUIT_LAYER, default_icon_file = 'icons/mob/clothing/suit.dmi') - var/mutable_appearance/suit_overlay = overlays_standing[SUIT_LAYER] - if(OFFSET_SUIT in dna.species.offset_features) + if(wear_suit) + var/obj/item/worn_item = wear_suit + var/mutable_appearance/suit_overlay + update_hud_wear_suit(worn_item) + var/icon_file + + var/handled_by_bodytype = TRUE + + //More currently unused digitigrade handling + /*if(dna.species.bodytype & BODYTYPE_DIGITIGRADE) + if(worn_item.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) + icon_file = DIGITIGRADE_SUIT_FILE*/ + + if(!(icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item)))) + handled_by_bodytype = FALSE + icon_file = DEFAULT_SUIT_FILE + + suit_overlay = wear_suit.build_worn_icon(default_layer = SUIT_LAYER, default_icon_file = icon_file) + + if(!suit_overlay) + return + if((!handled_by_bodytype) && (OFFSET_SUIT in dna.species.offset_features)) suit_overlay.pixel_x += dna.species.offset_features[OFFSET_SUIT][1] suit_overlay.pixel_y += dna.species.offset_features[OFFSET_SUIT][2] overlays_standing[SUIT_LAYER] = suit_overlay @@ -377,10 +491,9 @@ There are several things that need to be remembered: var/atom/movable/screen/inventory/inv inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_LPOCKET) + 1] - inv.update_appearance() - inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_RPOCKET) + 1] - inv.update_appearance() + + inv.update_icon() if(l_store) l_store.screen_loc = ui_storage1 @@ -394,46 +507,120 @@ There are several things that need to be remembered: client.screen += r_store update_observer_view(r_store) - /mob/living/carbon/human/update_inv_wear_mask() - ..() - var/mutable_appearance/mask_overlay = overlays_standing[FACEMASK_LAYER] - if(mask_overlay) - remove_overlay(FACEMASK_LAYER) - if(OFFSET_FACEMASK in dna.species.offset_features) + remove_overlay(FACEMASK_LAYER) + + if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated + return + + if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_MASK) + 1]) + var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_MASK) + 1] + inv.update_icon() + + if(wear_mask) + var/obj/item/worn_item = wear_mask + update_hud_wear_mask(worn_item) + var/mutable_appearance/mask_overlay + var/icon_file = 'icons/mob/clothing/mask.dmi' + var/handled_by_bodytype = TRUE + + if(!(ITEM_SLOT_MASK in check_obscured_slots())) + + if(!(icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item)))) + icon_file = 'icons/mob/clothing/mask.dmi' + handled_by_bodytype = FALSE + + mask_overlay = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = icon_file) + + if(!mask_overlay) + return + if((!handled_by_bodytype) && (OFFSET_FACEMASK in dna.species.offset_features)) mask_overlay.pixel_x += dna.species.offset_features[OFFSET_FACEMASK][1] mask_overlay.pixel_y += dna.species.offset_features[OFFSET_FACEMASK][2] - overlays_standing[FACEMASK_LAYER] = mask_overlay - apply_overlay(FACEMASK_LAYER) + + overlays_standing[FACEMASK_LAYER] = mask_overlay + + apply_overlay(FACEMASK_LAYER) update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout /mob/living/carbon/human/update_inv_back() - ..() - var/mutable_appearance/back_overlay = overlays_standing[BACK_LAYER] - if(back_overlay) - remove_overlay(BACK_LAYER) - if(OFFSET_BACK in dna.species.offset_features) + remove_overlay(BACK_LAYER) + + if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_BACK) + 1]) + var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_BACK) + 1] + inv.update_icon() + + if(back) + var/obj/item/worn_item = back + var/mutable_appearance/back_overlay + update_hud_back(worn_item) + var/icon_file = 'icons/mob/clothing/back.dmi' + var/handled_by_bodytype = TRUE + + if(!icon_exists(icon_file, RESOLVE_ICON_STATE(worn_item))) + icon_file = 'icons/mob/clothing/back.dmi' + handled_by_bodytype = FALSE + + back_overlay = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = icon_file) + + if(!back_overlay) + return + if((!handled_by_bodytype) && (OFFSET_BACK in dna.species.offset_features)) back_overlay.pixel_x += dna.species.offset_features[OFFSET_BACK][1] back_overlay.pixel_y += dna.species.offset_features[OFFSET_BACK][2] - overlays_standing[BACK_LAYER] = back_overlay - apply_overlay(BACK_LAYER) + overlays_standing[BACK_LAYER] = back_overlay + apply_overlay(BACK_LAYER) /mob/living/carbon/human/update_inv_legcuffed() remove_overlay(LEGCUFF_LAYER) - clear_alert(ALERT_LEGCUFFED) + clear_alert("legcuffed") if(legcuffed) - var/mutable_appearance/legcuff_overlay = mutable_appearance('icons/mob/mob.dmi', "legcuff1", -LEGCUFF_LAYER) - if(legcuffed.blocks_emissive) - legcuff_overlay.overlays += emissive_blocker(legcuff_overlay.icon, legcuff_overlay.icon_state, alpha = legcuff_overlay.alpha) - - overlays_standing[LEGCUFF_LAYER] = legcuff_overlay + overlays_standing[LEGCUFF_LAYER] = mutable_appearance('icons/mob/mob.dmi', "legcuff1", -LEGCUFF_LAYER) apply_overlay(LEGCUFF_LAYER) - throw_alert(ALERT_LEGCUFFED, /atom/movable/screen/alert/restrained/legcuffed, new_master = src.legcuffed) + throw_alert("legcuffed", /atom/movable/screen/alert/restrained/legcuffed, new_master = src.legcuffed) + +/mob/living/carbon/human/update_inv_hands() + remove_overlay(HANDS_LAYER) + if (handcuffed) + drop_all_held_items() + return + + var/list/hands = list() + for(var/obj/item/worn_item in held_items) + if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) + worn_item.screen_loc = ui_hand_position(get_held_index_of_item(worn_item)) + client.screen += worn_item + if(observers?.len) + for(var/M in observers) + var/mob/dead/observe = M + if(observe.client && observe.client.eye == src) + observe.client.screen += worn_item + else + observers -= observe + if(!observers.len) + observers = null + break + + var/t_state = worn_item.inhand_icon_state + if(!t_state) + t_state = worn_item.icon_state + + var/icon_file = worn_item.lefthand_file + var/mutable_appearance/hand_overlay + if(get_held_index_of_item(worn_item) % 2 == 0) + icon_file = worn_item.righthand_file + hand_overlay = worn_item.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE) + else + hand_overlay = worn_item.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE) + + hands += hand_overlay + overlays_standing[HANDS_LAYER] = hands + apply_overlay(HANDS_LAYER) /proc/wear_female_version(t_color, icon, layer, type, greyscale_colors) var/index = "[t_color]-[greyscale_colors]" var/icon/female_clothing_icon = GLOB.female_clothing_icons[index] - if(!female_clothing_icon) //Create standing/laying icons if they don't exist + if(!female_clothing_icon) //Create standing/laying icons if they don't exist generate_female_clothing(index, t_color, icon, type) return mutable_appearance(GLOB.female_clothing_icons[index], layer = -layer) @@ -449,36 +636,86 @@ There are several things that need to be remembered: //human HUD updates for items in our inventory -//update whether our head item appears on our hud. -/mob/living/carbon/human/update_hud_head(obj/item/I) - I.screen_loc = ui_head +/mob/living/carbon/human/proc/update_hud_uniform(obj/item/worn_item) + worn_item.screen_loc = ui_iclothing + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) + +/mob/living/carbon/human/proc/update_hud_id(obj/item/worn_item) + worn_item.screen_loc = ui_id + if((client && hud_used?.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item) + +/mob/living/carbon/human/proc/update_hud_gloves(obj/item/worn_item) + worn_item.screen_loc = ui_gloves + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) + +/mob/living/carbon/human/proc/update_hud_glasses(obj/item/worn_item) + worn_item.screen_loc = ui_glasses + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) + +/mob/living/carbon/human/proc/update_hud_ears(obj/item/worn_item) + worn_item.screen_loc = ui_ears + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) + +/mob/living/carbon/human/proc/update_hud_shoes(obj/item/worn_item) + worn_item.screen_loc = ui_shoes + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) + +/mob/living/carbon/human/proc/update_hud_s_store(obj/item/worn_item) + worn_item.screen_loc = ui_sstore1 + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) + +/mob/living/carbon/human/proc/update_hud_wear_suit(obj/item/worn_item) + worn_item.screen_loc = ui_oclothing + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) + +/mob/living/carbon/human/proc/update_hud_belt(obj/item/worn_item) + belt.screen_loc = ui_belt if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) - client.screen += I - update_observer_view(I,1) + client.screen += worn_item + update_observer_view(worn_item,TRUE) + +/mob/living/carbon/human/update_hud_head(obj/item/worn_item) + worn_item.screen_loc = ui_head + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) //update whether our mask item appears on our hud. -/mob/living/carbon/human/update_hud_wear_mask(obj/item/I) - I.screen_loc = ui_mask - if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) - client.screen += I - update_observer_view(I,1) +/mob/living/carbon/human/update_hud_wear_mask(obj/item/worn_item) + worn_item.screen_loc = ui_mask + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) //update whether our neck item appears on our hud. -/mob/living/carbon/human/update_hud_neck(obj/item/I) - I.screen_loc = ui_neck - if(client && hud_used?.hud_shown) - if(hud_used.inventory_shown) - client.screen += I - update_observer_view(I,1) +/mob/living/carbon/human/update_hud_neck(obj/item/worn_item) + worn_item.screen_loc = ui_neck + if((client && hud_used) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item,TRUE) //update whether our back item appears on our hud. -/mob/living/carbon/human/update_hud_back(obj/item/I) - I.screen_loc = ui_back +/mob/living/carbon/human/update_hud_back(obj/item/worn_item) + worn_item.screen_loc = ui_back if(client && hud_used?.hud_shown) - client.screen += I - update_observer_view(I) + client.screen += worn_item + update_observer_view(worn_item, inventory = TRUE) /* Does everything in relation to building the /mutable_appearance used in the mob's overlays list @@ -505,7 +742,7 @@ generate/load female uniform sprites matching all previously decided variables */ -/obj/item/proc/build_worn_icon(default_layer = 0, default_icon_file = null, isinhands = FALSE, femaleuniform = NO_FEMALE_UNIFORM, override_state = null) +/obj/item/proc/build_worn_icon(default_layer = 0, default_icon_file = null, isinhands = FALSE, femaleuniform = NO_FEMALE_UNIFORM, override_state = null, override_file = null) //Find a valid icon_state from variables+arguments var/t_state @@ -515,8 +752,11 @@ generate/load female uniform sprites matching all previously decided variables t_state = !isinhands ? (worn_icon_state ? worn_icon_state : icon_state) : (inhand_icon_state ? inhand_icon_state : icon_state) //Find a valid icon file from variables+arguments - var/file2use = !isinhands ? (worn_icon ? worn_icon : default_icon_file) : default_icon_file - + var/file2use + if(override_file) + file2use = override_file + else + file2use = !isinhands ? (worn_icon ? worn_icon : default_icon_file) : default_icon_file //Find a valid layer from variables+arguments var/layer2use = alternate_worn_layer ? alternate_worn_layer : default_layer @@ -568,56 +808,7 @@ generate/load female uniform sprites matching all previously decided variables else //No offsets or Unwritten number of hands return list("x" = 0, "y" = 0)//Handle held offsets -//produces a key based on the human's limbs -/mob/living/carbon/human/generate_icon_render_key() - . = "[dna.species.limbs_id]" - - if(dna.check_mutation(/datum/mutation/human/hulk)) - . += "-coloured-hulk" - else if(dna.species.use_skintones) - . += "-coloured-[skin_tone]" - else if(dna.species.fixed_mut_color) - . += "-coloured-[dna.species.fixed_mut_color]" - else if(dna.features["mcolor"]) - . += "-coloured-[dna.features["mcolor"]]" - else - . += "-not_coloured" - - . += "-[body_type]" - - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - . += "-[BP.body_zone]" - - if(!HAS_TRAIT(src, TRAIT_INVISIBLE_MAN)) - for(var/obj/item/organ/external/organ as anything in BP.external_organs) - if(organ.can_draw_on_bodypart(src)) //make sure we're drawn before generating a key - . += "([organ.cache_key])" - - if(BP.status == BODYPART_ORGANIC) - . += "-organic" - else - . += "-robotic" - if(BP.use_digitigrade) - . += "-digitigrade[BP.use_digitigrade]" - if(BP.dmg_overlay_type) - . += "-[BP.dmg_overlay_type]" - if(HAS_TRAIT(BP, TRAIT_PLASMABURNT)) - . += "-plasmaburnt" - - if(HAS_TRAIT(src, TRAIT_HUSK)) - . += "-husk" - - if(HAS_TRAIT(src, TRAIT_INVISIBLE_MAN)) - . += "-invisible" - -/mob/living/carbon/human/load_limb_from_cache() - ..() - update_hair() - - - -/mob/living/carbon/human/proc/update_observer_view(obj/item/I, inventory) +/mob/living/carbon/human/proc/update_observer_view(obj/item/worn_item, inventory) if(observers?.len) for(var/M in observers) var/mob/dead/observe = M @@ -625,7 +816,7 @@ generate/load female uniform sprites matching all previously decided variables if(observe.hud_used) if(inventory && !observe.hud_used.inventory_shown) continue - observe.client.screen += I + observe.client.screen += worn_item else observers -= observe if(!observers.len) @@ -633,11 +824,8 @@ generate/load female uniform sprites matching all previously decided variables break // Only renders the head of the human -/mob/living/carbon/human/proc/update_body_parts_head_only() - if (!dna) - return - - if (!dna.species) +/mob/living/carbon/human/proc/update_body_parts_head_only(update_limb_data) + if(!dna?.species) return var/obj/item/bodypart/HD = get_bodypart("head") @@ -645,7 +833,7 @@ generate/load female uniform sprites matching all previously decided variables if (!istype(HD)) return - HD.update_limb() + HD.update_limb(is_creating = update_limb_data) add_overlay(HD.get_limb_icon()) update_damage_overlays() @@ -669,13 +857,14 @@ generate/load female uniform sprites matching all previously decided variables else eye_overlay = mutable_appearance('icons/mob/human_face.dmi', E.eye_icon_state, -BODY_LAYER) if((EYECOLOR in dna.species.species_traits) && E) - eye_overlay.color = eye_color + eye_overlay.color = "#" + eye_color if(OFFSET_FACE in dna.species.offset_features) eye_overlay.pixel_x += dna.species.offset_features[OFFSET_FACE][1] eye_overlay.pixel_y += dna.species.offset_features[OFFSET_FACE][2] add_overlay(eye_overlay) - dna.species.handle_hair(src) update_inv_head() update_inv_wear_mask() + +#undef RESOLVE_ICON_STATE diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index be66c441eed..36765de0ba2 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -40,7 +40,7 @@ return s_store return null -/mob/living/carbon/human/proc/get_all_slots() +/mob/living/carbon/human/get_all_worn_items() . = get_head_slots() | get_body_slots() /mob/living/carbon/human/proc/get_body_slots() @@ -170,7 +170,7 @@ /mob/living/carbon/human/equipped_speed_mods() . = ..() - for(var/sloties in get_all_slots() - list(l_store, r_store, s_store)) + for(var/sloties in get_all_worn_items() - list(l_store, r_store, s_store)) var/obj/item/thing = sloties . += thing?.slowdown @@ -298,7 +298,7 @@ //delete all equipment without dropping anything /mob/living/carbon/human/proc/delete_equipment() - for(var/slot in get_all_slots())//order matters, dependant slots go first + for(var/slot in get_all_worn_items())//order matters, dependant slots go first qdel(slot) for(var/obj/item/I in held_items) qdel(I) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 45d6d85305f..c3f9e1de95c 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -15,8 +15,6 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species ///If the game needs to manually check your race to do something not included in a proc here, it will use this. var/id - //This is used if you want to use a different species' limb sprites. - var/limbs_id ///This is the fluff name. They are displayed on health analyzers and in the character setup menu. Leave them generic for other servers to customize. var/name /// The formatting of the name of the species in plural context. Defaults to "[name]\s" if unset. @@ -27,15 +25,22 @@ GLOBAL_LIST_EMPTY(features_by_species) ///Whether or not the race has sexual characteristics (biological genders). At the moment this is only FALSE for skeletons and shadows var/sexes = TRUE - + ///A bitfield of "bodytypes", updated by /datum/obj/item/bodypart/proc/synchronize_bodytypes() + var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC ///Clothing offsets. If a species has a different body than other species, you can offset clothing so they look less weird. var/list/offset_features = list(OFFSET_UNIFORM = list(0,0), OFFSET_ID = list(0,0), OFFSET_GLOVES = list(0,0), OFFSET_GLASSES = list(0,0), OFFSET_EARS = list(0,0), OFFSET_SHOES = list(0,0), OFFSET_S_STORE = list(0,0), OFFSET_FACEMASK = list(0,0), OFFSET_HEAD = list(0,0), OFFSET_FACE = list(0,0), OFFSET_BELT = list(0,0), OFFSET_BACK = list(0,0), OFFSET_SUIT = list(0,0), OFFSET_NECK = list(0,0)) + ///The maximum number of bodyparts this species can have. + var/max_bodypart_count = 6 ///This allows races to have specific hair colors. If null, it uses the H's hair/facial hair colors. If "mutcolor", it uses the H's mutant_color. If "fixedmutcolor", it uses fixedmutcolor var/hair_color ///The alpha used by the hair. 255 is completely solid, 0 is invisible. var/hair_alpha = 255 + ///This is used for children, it will determine their default limb ID for use of examine. See [/mob/living/carbon/human/proc/examine]. + var/examine_limb_id + ///Never, Optional, or Forced digi legs? + var/digitigrade_customization = DIGITIGRADE_NEVER ///Does the species use skintones or not? As of now only used by humans. var/use_skintones = FALSE ///If your race bleeds something other than bog standard blood, change this to reagent id. For example, ethereals bleed liquid electricity. @@ -73,13 +78,14 @@ GLOBAL_LIST_EMPTY(features_by_species) ///Internal organs that are unique to this race, like a tail. var/list/mutant_organs = list() ///The bodyparts this species uses. assoc of bodypart string - bodypart type. Make sure all the fucking entries are in or I'll skin you alive. - var/list/bodypart_overides = list( - BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm,\ - BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm,\ - BODY_ZONE_HEAD = /obj/item/bodypart/head,\ - BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg,\ - BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg,\ - BODY_ZONE_CHEST = /obj/item/bodypart/chest) + var/list/bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm, + BODY_ZONE_HEAD = /obj/item/bodypart/head, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg, + BODY_ZONE_CHEST = /obj/item/bodypart/chest, + ) ///List of external organs to generate like horns, frills, wings, etc. list(typepath of organ = "Round Beautiful BDSM Snout"). Still WIP var/list/external_organs = list() @@ -232,8 +238,6 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/New() - if(!limbs_id) //if we havent set a limbs id to use, just use our own id - limbs_id = id wings_icons = string_list(wings_icons) if(!plural_form) @@ -415,16 +419,10 @@ GLOBAL_LIST_EMPTY(features_by_species) if(C.hud_used) C.hud_used.update_locked_slots() - fix_non_native_limbs(C) - - // this needs to be FIRST because qdel calls update_body which checks if we have DIGITIGRADE legs or not and if not then removes DIGITIGRADE from species_traits - if(C.dna.species.mutant_bodyparts["legs"] && C.dna.features["legs"] == "Digitigrade Legs") - species_traits += DIGITIGRADE - if(DIGITIGRADE in species_traits) - C.Digitigrade_Leg_Swap(FALSE) C.mob_biotypes = inherent_biotypes + replace_body(C, src) regenerate_organs(C, old_species, visual_only = C.visual_only_organs) if(exotic_bloodtype && C.dna.blood_type != exotic_bloodtype) @@ -497,8 +495,6 @@ GLOBAL_LIST_EMPTY(features_by_species) SHOULD_CALL_PARENT(TRUE) if(C.dna.species.exotic_bloodtype) C.dna.blood_type = random_blood_type() - if(DIGITIGRADE in species_traits) - C.Digitigrade_Leg_Swap(TRUE) for(var/X in inherent_traits) REMOVE_TRAIT(C, X, SPECIES_TRAIT) for(var/obj/item/organ/external/organ in C.internal_organs) @@ -526,151 +522,6 @@ GLOBAL_LIST_EMPTY(features_by_species) SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src) -/** - * Handles hair icons and dynamic hair. - * - * Handles hiding hair with clothing, hair layers, losing hair due to husking or augmented heads, facial hair, head hair, and hair styles. - * Arguments: - * * H - Human, whoever we're handling the hair for - * * forced_colour - The colour of hair we're forcing on this human. Leave null to not change. Mind the british spelling! - */ -/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour) - H.remove_overlay(HAIR_LAYER) - var/obj/item/bodypart/head/noggin = H.get_bodypart(BODY_ZONE_HEAD) - if(!noggin) //Decapitated - return - - if(HAS_TRAIT(H, TRAIT_HUSK) || HAS_TRAIT(H, TRAIT_INVISIBLE_MAN)) - return - var/datum/sprite_accessory/S - var/list/standing = list() - - var/hair_hidden = FALSE //ignored if the matching dynamic_X_suffix is non-empty - var/facialhair_hidden = FALSE // ^ - - //for augmented heads - if(noggin.status == BODYPART_ROBOTIC) - return - - //we check if our hat or helmet hides our facial hair. - if(H.head) - var/obj/item/I = H.head - if(I.flags_inv & HIDEFACIALHAIR) - facialhair_hidden = TRUE - - if(H.wear_mask) - var/obj/item/I = H.wear_mask - if(I.flags_inv & HIDEFACIALHAIR) - facialhair_hidden = TRUE - - if(H.facial_hairstyle && (FACEHAIR in species_traits) && !facialhair_hidden) - S = GLOB.facial_hairstyles_list[H.facial_hairstyle] - if(S) - - var/mutable_appearance/facial_overlay = mutable_appearance(S.icon, S.icon_state, -HAIR_LAYER) - var/mutable_appearance/gradient_overlay - - if(!forced_colour) - if(hair_color) - if(hair_color == "mutcolor") - facial_overlay.color = H.dna.features["mcolor"] - else if(hair_color == "fixedmutcolor") - facial_overlay.color = fixed_mut_color - else - facial_overlay.color = hair_color - else - facial_overlay.color = H.facial_hair_color - //Gradients - var/grad_style = LAZYACCESS(H.grad_style, GRADIENT_FACIAL_HAIR_KEY) - if(grad_style) - var/grad_color = LAZYACCESS(H.grad_color, GRADIENT_FACIAL_HAIR_KEY) - gradient_overlay = make_gradient_overlay(S.icon, S.icon_state, HAIR_LAYER, GLOB.facial_hair_gradients_list[grad_style], grad_color) - else - facial_overlay.color = forced_colour - - facial_overlay.alpha = hair_alpha - facial_overlay.overlays += emissive_blocker(S.icon, S.icon_state, alpha = hair_alpha) - - standing += facial_overlay - if(gradient_overlay) - standing += gradient_overlay - - if(H.head) - var/obj/item/I = H.head - if(I.flags_inv & HIDEHAIR) - hair_hidden = TRUE - - if(H.w_uniform) - var/obj/item/item_uniform = H.w_uniform - if(item_uniform.flags_inv & HIDEHAIR) - hair_hidden = TRUE - - if(H.wear_mask) - var/obj/item/I = H.wear_mask - if(I.flags_inv & HIDEHAIR) - hair_hidden = TRUE - - if(!hair_hidden) - var/mutable_appearance/hair_overlay = mutable_appearance(layer = -HAIR_LAYER) - var/mutable_appearance/gradient_overlay - if(!hair_hidden && !H.getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain - if(!(NOBLOOD in species_traits)) - hair_overlay.icon = 'icons/mob/human_face.dmi' - hair_overlay.icon_state = "debrained" - - else if(H.hairstyle && (HAIR in species_traits)) - S = GLOB.hairstyles_list[H.hairstyle] - if(S) - var/hair_state = S.icon_state - var/hair_file = S.icon - - hair_overlay.icon = hair_file - hair_overlay.icon_state = hair_state - - if(!forced_colour) - if(hair_color) - if(hair_color == "mutcolor") - hair_overlay.color = H.dna.features["mcolor"] - else if(hair_color == "fixedmutcolor") - hair_overlay.color = fixed_mut_color - else - hair_overlay.color = hair_color - else - hair_overlay.color = H.hair_color - - //Gradients - var/grad_style = LAZYACCESS(H.grad_style, GRADIENT_HAIR_KEY) - if(grad_style) - var/grad_color = LAZYACCESS(H.grad_color, GRADIENT_HAIR_KEY) - gradient_overlay = make_gradient_overlay(hair_file, hair_state, HAIR_LAYER, GLOB.hair_gradients_list[grad_style], grad_color) - else - hair_overlay.color = forced_colour - - hair_overlay.alpha = hair_alpha - if(OFFSET_FACE in H.dna.species.offset_features) - hair_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1] - hair_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2] - - if(hair_overlay.icon) - hair_overlay.overlays += emissive_blocker(hair_overlay.icon, hair_overlay.icon_state, alpha = hair_alpha) - standing += hair_overlay - if(gradient_overlay) - standing += gradient_overlay - - if(standing.len) - H.overlays_standing[HAIR_LAYER] = standing - - H.apply_overlay(HAIR_LAYER) - -/datum/species/proc/make_gradient_overlay(file, icon, layer, datum/sprite_accessory/gradient, grad_color) - var/mutable_appearance/gradient_overlay = mutable_appearance(layer = -layer) - var/icon/temp = icon(gradient.icon, gradient.icon_state) - var/icon/temp_hair = icon(file, icon) - temp.Blend(temp_hair, ICON_ADD) - gradient_overlay.icon = temp - gradient_overlay.color = grad_color - return gradient_overlay - /** * Handles the body of a human * @@ -737,27 +588,27 @@ GLOBAL_LIST_EMPTY(features_by_species) var/datum/sprite_accessory/markings = GLOB.moth_markings_list[species_human.dna.features["moth_markings"]] if(!HAS_TRAIT(species_human, TRAIT_HUSK)) - if(noggin && (noggin.status != BODYPART_ROBOTIC)) + if(noggin && (IS_ORGANIC_LIMB(noggin))) var/mutable_appearance/markings_head_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_head", -BODY_LAYER) standing += markings_head_overlay - if(chest && (chest.status != BODYPART_ROBOTIC)) + if(chest && (IS_ORGANIC_LIMB(chest))) var/mutable_appearance/markings_chest_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_chest", -BODY_LAYER) standing += markings_chest_overlay - if(right_arm && (right_arm.status != BODYPART_ROBOTIC)) + if(right_arm && (IS_ORGANIC_LIMB(right_arm))) var/mutable_appearance/markings_r_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_arm", -BODY_LAYER) standing += markings_r_arm_overlay - if(left_arm && (left_arm.status != BODYPART_ROBOTIC)) + if(left_arm && (IS_ORGANIC_LIMB(left_arm))) var/mutable_appearance/markings_l_arm_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_arm", -BODY_LAYER) standing += markings_l_arm_overlay - if(right_leg && (right_leg.status != BODYPART_ROBOTIC)) + if(right_leg && (IS_ORGANIC_LIMB(right_leg))) var/mutable_appearance/markings_r_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_r_leg", -BODY_LAYER) standing += markings_r_leg_overlay - if(left_leg && (left_leg.status != BODYPART_ROBOTIC)) + if(left_leg && (IS_ORGANIC_LIMB(left_leg))) var/mutable_appearance/markings_l_leg_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_l_leg", -BODY_LAYER) standing += markings_l_leg_overlay @@ -767,7 +618,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[species_human.underwear] var/mutable_appearance/underwear_overlay if(underwear) - if(species_human.dna.species.sexes && species_human.body_type == FEMALE && (underwear.gender == MALE)) + if(species_human.dna.species.sexes && species_human.physique == FEMALE && (underwear.gender == MALE)) underwear_overlay = wear_female_version(underwear.icon_state, underwear.icon, BODY_LAYER, FEMALE_UNIFORM_FULL) else underwear_overlay = mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) @@ -778,12 +629,12 @@ GLOBAL_LIST_EMPTY(features_by_species) if(species_human.undershirt) var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[species_human.undershirt] if(undershirt) - if(species_human.dna.species.sexes && species_human.body_type == FEMALE) + if(species_human.dna.species.sexes && species_human.physique == FEMALE) standing += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) else standing += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) - if(species_human.socks && species_human.num_legs >= 2 && !(DIGITIGRADE in species_traits)) + if(species_human.socks && species_human.num_legs >= 2 && !(src.bodytype & BODYTYPE_DIGITIGRADE)) var/datum/sprite_accessory/socks/socks = GLOB.socks_list[species_human.socks] if(socks) standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) @@ -852,36 +703,13 @@ GLOBAL_LIST_EMPTY(features_by_species) bodyparts_to_add -= "waggingspines" 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 || noggin.status == BODYPART_ROBOTIC) + 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" - //Digitigrade legs are stuck in the phantom zone between true limbs and mutant bodyparts. Mainly it just needs more aggressive updating than most limbs. - var/update_needed = FALSE - var/not_digitigrade = TRUE - for(var/obj/item/bodypart/bodypart as anything in source.bodyparts) - if(!bodypart.use_digitigrade) - continue - not_digitigrade = FALSE - if(!(DIGITIGRADE in species_traits)) //Someone cut off a digitigrade leg and tacked it on - species_traits += DIGITIGRADE - var/should_be_squished = FALSE - if(source.wear_suit && ((source.wear_suit.flags_inv & HIDEJUMPSUIT) || (source.wear_suit.body_parts_covered & LEGS)) || (source.w_uniform && (source.w_uniform.body_parts_covered & LEGS))) - should_be_squished = TRUE - if(bodypart.use_digitigrade == FULL_DIGITIGRADE && should_be_squished) - bodypart.use_digitigrade = SQUISHED_DIGITIGRADE - update_needed = TRUE - else if(bodypart.use_digitigrade == SQUISHED_DIGITIGRADE && !should_be_squished) - bodypart.use_digitigrade = FULL_DIGITIGRADE - update_needed = TRUE - if(update_needed) - source.update_body_parts() - if(not_digitigrade && (DIGITIGRADE in species_traits)) //Curse is lifted - species_traits -= DIGITIGRADE - if(!bodyparts_to_add) return - var/g = (source.body_type == FEMALE) ? "f" : "m" + var/g = (source.physique == FEMALE) ? "f" : "m" for(var/layer in relevent_layers) var/layertext = mutant_bodyparts_layertext(layer) @@ -1054,15 +882,16 @@ GLOBAL_LIST_EMPTY(features_by_species) if(ITEM_SLOT_FEET) if(H.num_legs < 2) return FALSE - if((DIGITIGRADE in species_traits) && !(I.item_flags & IGNORE_DIGITIGRADE)) - if(!disable_warning) - to_chat(H, span_warning("The footwear around here isn't compatible with your feet!")) - return FALSE + if((bodytype & BODYTYPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE)) + if(!(I.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) + if(!disable_warning) + to_chat(H, span_warning("The footwear around here isn't compatible with your feet!")) + return FALSE return equip_delay_self_check(I, H, bypass_equip_delay_self) if(ITEM_SLOT_BELT) var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST) - if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC)) + if(!H.w_uniform && !nojumpsuit && (!O || IS_ORGANIC_LIMB(O))) if(!disable_warning) to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!")) return FALSE @@ -1086,7 +915,7 @@ GLOBAL_LIST_EMPTY(features_by_species) return equip_delay_self_check(I, H, bypass_equip_delay_self) if(ITEM_SLOT_ID) var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST) - if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC)) + if(!H.w_uniform && !nojumpsuit && (!O || IS_ORGANIC_LIMB(O))) if(!disable_warning) to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!")) return FALSE @@ -1099,7 +928,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_L_LEG) - if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC)) + if(!H.w_uniform && !nojumpsuit && (!O || IS_ORGANIC_LIMB(O))) if(!disable_warning) to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!")) return FALSE @@ -1112,7 +941,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_R_LEG) - if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC)) + if(!H.w_uniform && !nojumpsuit && (!O || IS_ORGANIC_LIMB(O))) if(!disable_warning) to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!")) return FALSE @@ -1431,7 +1260,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/bloody = FALSE if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2)))) - if(affecting.status == BODYPART_ORGANIC) + if(IS_ORGANIC_LIMB(affecting)) I.add_mob_blood(H) //Make the weapon bloody, not the person. if(prob(I.force * 2)) //blood spatter! bloody = TRUE @@ -2050,7 +1879,7 @@ GLOBAL_LIST_EMPTY(features_by_species) else wings_icon = wings_icons[1] - var/obj/item/organ/external/wings/functional/wings = new(null, wings_icon, H.body_type) + var/obj/item/organ/external/wings/functional/wings = new(null, wings_icon, H.physique) wings.Insert(H) handle_mutant_bodyparts(H) @@ -2068,18 +1897,6 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/spec_unarmedattack(mob/living/carbon/human/user, atom/target, modifiers) return FALSE - -///Removes any non-native limbs from the mob -/datum/species/proc/fix_non_native_limbs(mob/living/carbon/human/H) - for(var/X in H.bodyparts) - var/obj/item/bodypart/current_part = X - var/obj/item/bodypart/species_part = bodypart_overides[current_part.body_zone] - - if(current_part.type == species_part) - continue - - current_part.change_bodypart(species_part) - /// Returns a list of strings representing features this species has. /// Used by the preferences UI to know what buttons to show. /datum/species/proc/get_features() @@ -2514,3 +2331,24 @@ GLOBAL_LIST_EMPTY(features_by_species) qdel(temp_holder) return to_add + +///Handles replacing all of the bodyparts with their species version during set_species() +/datum/species/proc/replace_body(mob/living/carbon/target, datum/species/new_species) + new_species ||= target.dna.species //If no new species is provided, assume its src. + //Note for future: Potentionally add a new C.dna.species() to build a template species for more accurate limb replacement + + if((new_species.digitigrade_customization == DIGITIGRADE_OPTIONAL && target.dna.features["legs"] == "Digitigrade Legs") || new_species.digitigrade_customization == DIGITIGRADE_FORCED) + new_species.bodypart_overrides[BODY_ZONE_R_LEG] = /obj/item/bodypart/r_leg/digitigrade + new_species.bodypart_overrides[BODY_ZONE_L_LEG] = /obj/item/bodypart/l_leg/digitigrade + + for(var/obj/item/bodypart/old_part as anything in target.bodyparts) + if(old_part.change_exempt_flags & BP_BLOCK_CHANGE_SPECIES) + continue + + var/path = new_species.bodypart_overrides?[old_part.body_zone] + var/obj/item/bodypart/new_part + if(path) + new_part = new path() + new_part.replace_limb(target, TRUE) + new_part.update_limb(is_creating = TRUE) + qdel(old_part) diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm index aa148fc3e07..a248ce1e338 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm @@ -16,6 +16,15 @@ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT ass_image = 'icons/ass/assgrey.png' + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/abductor, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/abductor, + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/abductor, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/abductor, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/abductor, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/abductor, + ) + /datum/species/abductor/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR] diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index 9398d1c09c4..e882a4fa514 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -27,25 +27,38 @@ damage_overlay_type = "synth" mutanttongue = /obj/item/organ/tongue/robot species_language_holder = /datum/language_holder/synthetic - limbs_id = "synth" wings_icons = list("Robotic") changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/robot, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/robot, + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/robot, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/robot, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/robot, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/robot, + ) + examine_limb_id = SPECIES_HUMAN + /datum/species/android/on_species_gain(mob/living/carbon/C) . = ..() - for(var/X in C.bodyparts) - var/obj/item/bodypart/O = X - O.change_bodypart_status(BODYPART_ROBOTIC, FALSE, TRUE) - O.brute_reduction = 5 - O.burn_reduction = 4 - // Androids don't eat, hunger or metabolise foods. Let's do some cleanup. C.set_safe_hunger_level() -/datum/species/android/on_species_loss(mob/living/carbon/C) +/datum/species/human/android/replace_body(mob/living/carbon/target, datum/species/new_species) . = ..() - for(var/X in C.bodyparts) - var/obj/item/bodypart/O = X - O.change_bodypart_status(BODYPART_ORGANIC,FALSE, TRUE) - O.brute_reduction = initial(O.brute_reduction) - O.burn_reduction = initial(O.burn_reduction) + var/skintone + if(ishuman(target)) + var/mob/living/carbon/human/human_target = target + skintone = human_target.skin_tone + + for(var/obj/item/bodypart/limb as anything in target.bodyparts) + if(limb.body_zone == BODY_ZONE_HEAD || limb.body_zone == BODY_ZONE_CHEST) + limb.is_dimorphic = TRUE + limb.skin_tone ||= skintone + limb.limb_id = SPECIES_HUMAN + limb.should_draw_greyscale = TRUE + limb.name = "human [parse_zone(limb.body_zone)]" + limb.update_limb() + limb.brute_reduction = 5 + limb.burn_reduction = 4 diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index a9441bf52ae..306a3c02a2d 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -16,7 +16,7 @@ mutanteyes = /obj/item/organ/eyes/dullahan mutanttongue = /obj/item/organ/tongue/dullahan mutantears = /obj/item/organ/ears/dullahan - limbs_id = "human" + examine_limb_id = SPECIES_HUMAN skinned_type = /obj/item/stack/sheet/animalhide/human changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN @@ -38,7 +38,6 @@ var/obj/item/bodypart/head/head = human.get_bodypart(BODY_ZONE_HEAD) if(head) - head.no_update = TRUE head.drop_limb() if(!QDELETED(head)) //drop_limb() deletes the limb if no drop location exists and character setup dummies are located in nullspace. diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index add9c4ed0ce..e4a97328772 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -1,5 +1,5 @@ /datum/species/ethereal - name = "Ethereal" + name = "\improper Ethereal" id = SPECIES_ETHEREAL attack_verb = "burn" attack_sound = 'sound/weapons/etherealhit.ogg' @@ -28,6 +28,15 @@ hair_color = "fixedmutcolor" hair_alpha = 140 + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/ethereal, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/ethereal, + BODY_ZONE_HEAD = /obj/item/bodypart/head/ethereal, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/ethereal, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/ethereal, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/ethereal, + ) + var/current_color var/EMPeffect = FALSE var/emageffect = FALSE @@ -66,6 +75,12 @@ var/obj/item/organ/heart/ethereal/ethereal_heart = C.getorganslot(ORGAN_SLOT_HEART) ethereal_heart.ethereal_color = default_color + //The following code is literally only to make admin-spawned ethereals not be black. + C.dna.features["mcolor"] = C.dna.features["ethcolor"] //Ethcolor and Mut color are both dogshit and i hate them + for(var/obj/item/bodypart/limb as anything in C.bodyparts) + if(limb.limb_id == SPECIES_ETHEREAL) + limb.update_limb(is_creating = TRUE) + /datum/species/ethereal/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) UnregisterSignal(C, COMSIG_ATOM_EMAG_ACT) UnregisterSignal(C, COMSIG_ATOM_EMP_ACT) @@ -85,6 +100,9 @@ /datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/H) . = ..() + if(!ethereal_light) + return + if(H.stat != DEAD && !EMPeffect) var/healthpercent = max(H.health, 0) / 100 if(!emageffect) @@ -95,8 +113,7 @@ else ethereal_light.set_light_on(FALSE) fixed_mut_color = rgb(128,128,128) - H.update_body() - H.update_hair() // This should fix the ethereal hair not changing with body, no clue as to why hair is not in update_body but okay + H.update_body(is_creating = TRUE) /datum/species/ethereal/proc/on_emp_act(mob/living/carbon/human/H, severity) SIGNAL_HANDLER diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 632c424ecd2..5f67636bf5c 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -3,7 +3,6 @@ name = "Felinid" id = SPECIES_FELINE say_mod = "meows" - limbs_id = "human" mutant_bodyparts = list("tail_human" = "Cat", "ears" = "Cat", "wings" = "None") @@ -17,6 +16,7 @@ payday_modifier = 0.75 ass_image = 'icons/ass/asscat.png' family_heirlooms = list(/obj/item/toy/cattoy) + examine_limb_id = SPECIES_HUMAN //Curiosity killed the cat's wagging tail. /datum/species/human/felinid/spec_death(gibbed, mob/living/carbon/human/H) diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm index d7bd542c795..7a781dedddd 100644 --- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm @@ -1,7 +1,7 @@ /datum/species/fly name = "Flyperson" plural_form = "Flypeople" - id = SPECIES_FLY + id = SPECIES_FLYPERSON say_mod = "buzzes" species_traits = list(HAS_FLESH, HAS_BONE, TRAIT_ANTENNAE) inherent_traits = list( @@ -27,6 +27,15 @@ mutantappendix = /obj/item/organ/appendix/fly mutant_organs = list(/obj/item/organ/fly, /obj/item/organ/fly/groin) + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/fly, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/fly, + BODY_ZONE_HEAD = /obj/item/bodypart/head/fly, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/fly, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/fly, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/fly, + ) + /datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, delta_time, times_fired) if(chem.type == /datum/reagent/toxin/pestkiller) H.adjustToxLoss(3 * REAGENTS_EFFECT_MULTIPLIER * delta_time) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 0f4d4629cb5..05518cee211 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -36,8 +36,17 @@ species_language_holder = /datum/language_holder/golem // To prevent golem subtypes from overwhelming the odds when random species // changes, only the Random Golem type can be chosen - limbs_id = "golem" fixed_mut_color = "#aaaaaa" + + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/golem, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/golem, + BODY_ZONE_HEAD = /obj/item/bodypart/head/golem, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/golem, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/golem, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem, + ) + var/info_text = "As an Iron Golem, you don't have any special traits." var/random_eligible = TRUE //If false, the golem subtype can't be made through golem mutation toxin @@ -101,6 +110,7 @@ info_text = "As an Adamantine Golem, you possess special vocal cords allowing you to \"resonate\" messages to all golems. Your unique mineral makeup makes you immune to most types of magic." prefix = "Adamantine" special_names = null + examine_limb_id = SPECIES_GOLEM /datum/species/golem/adamantine/on_species_gain(mob/living/carbon/C, datum/species/old_species) ..() @@ -135,6 +145,7 @@ heatmod = 0 //fine until they blow up prefix = "Plasma" special_names = list("Flood","Fire","Bar","Man") + examine_limb_id = SPECIES_GOLEM var/boom_warning = FALSE var/datum/action/innate/ignite/ignite @@ -192,6 +203,7 @@ info_text = "As a Diamond Golem, you are more resistant than the average golem." prefix = "Diamond" special_names = list("Back","Grill") + examine_limb_id = SPECIES_GOLEM //Faster but softer and less armoured /datum/species/golem/gold @@ -204,6 +216,7 @@ info_text = "As a Gold Golem, you are faster but less resistant than the average golem." prefix = "Golden" special_names = list("Boy") + examine_limb_id = SPECIES_GOLEM //Heavier, thus higher chance of stunning when punching /datum/species/golem/silver @@ -215,6 +228,7 @@ info_text = "As a Silver Golem, your attacks have a higher chance of stunning. Being made of silver, your body is immune to most types of magic." prefix = "Silver" special_names = list("Surfer", "Chariot", "Lining") + examine_limb_id = SPECIES_GOLEM /datum/species/golem/silver/on_species_gain(mob/living/carbon/C, datum/species/old_species) ..() @@ -241,6 +255,7 @@ attack_sound = 'sound/effects/meteorimpact.ogg' //hits pretty hard prefix = "Plasteel" special_names = null + examine_limb_id = SPECIES_GOLEM /datum/species/golem/plasteel/negates_gravity(mob/living/carbon/human/H) return TRUE @@ -263,6 +278,7 @@ burnmod = 0.9 prefix = "Titanium" special_names = list("Dioxide") + examine_limb_id = SPECIES_GOLEM /datum/species/golem/titanium/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() @@ -282,6 +298,7 @@ burnmod = 0.8 prefix = "Plastitanium" special_names = null + examine_limb_id = SPECIES_GOLEM /datum/species/golem/plastitanium/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() @@ -304,12 +321,13 @@ info_text = "As an Alloy Golem, you are made of advanced alien materials: you are faster and regenerate over time. You are, however, only able to be heard by other alloy golems." prefix = "Alien" special_names = list("Outsider", "Technology", "Watcher", "Stranger") //ominous and unknown + examine_limb_id = SPECIES_GOLEM //Regenerates because self-repairing super-advanced alien tech /datum/species/golem/alloy/spec_life(mob/living/carbon/human/H, delta_time, times_fired) if(H.stat == DEAD) return - H.heal_overall_damage(1 * delta_time, 1 * delta_time, 0, BODYPART_ORGANIC) + H.heal_overall_damage(1 * delta_time, 1 * delta_time, 0, BODYTYPE_ORGANIC) H.adjustToxLoss(-1 * delta_time) H.adjustOxyLoss(-1 * delta_time) @@ -343,6 +361,7 @@ human_surname_chance = 0 special_name_chance = 100 inherent_factions = list("plants", "vines") + examine_limb_id = SPECIES_GOLEM /datum/species/golem/wood/spec_life(mob/living/carbon/human/H, delta_time, times_fired) if(H.stat == DEAD) @@ -355,7 +374,7 @@ if(H.nutrition > NUTRITION_LEVEL_ALMOST_FULL) H.set_nutrition(NUTRITION_LEVEL_ALMOST_FULL) if(light_amount > 0.2) //if there's enough light, heal - H.heal_overall_damage(0.5 * delta_time, 0.5 * delta_time, 0, BODYPART_ORGANIC) + H.heal_overall_damage(0.5 * delta_time, 0.5 * delta_time, 0, BODYTYPE_ORGANIC) H.adjustToxLoss(-0.5 * delta_time) H.adjustOxyLoss(-0.5 * delta_time) @@ -388,6 +407,7 @@ prefix = "Uranium" special_names = list("Oxide", "Rod", "Meltdown", "235") COOLDOWN_DECLARE(radiation_emission_cooldown) + examine_limb_id = SPECIES_GOLEM /datum/species/golem/uranium/proc/radiation_emission(mob/living/carbon/human/H) if(!COOLDOWN_FINISHED(src, radiation_emission_cooldown)) @@ -424,6 +444,7 @@ attack_sound = 'sound/effects/shovel_dig.ogg' prefix = "Sand" special_names = list("Castle", "Bag", "Dune", "Worm", "Storm") + examine_limb_id = SPECIES_GOLEM /datum/species/golem/sand/spec_death(gibbed, mob/living/carbon/human/H) H.visible_message(span_danger("[H] turns into a pile of sand!")) @@ -455,6 +476,7 @@ attack_sound = 'sound/effects/glassbr2.ogg' prefix = "Glass" special_names = list("Lens", "Prism", "Fiber", "Bead") + examine_limb_id = SPECIES_GOLEM /datum/species/golem/glass/spec_death(gibbed, mob/living/carbon/human/H) playsound(H, SFX_SHATTER, 70, TRUE) @@ -490,6 +512,7 @@ attack_sound = 'sound/effects/phasein.ogg' prefix = "Bluespace" special_names = list("Crystal", "Polycrystal") + examine_limb_id = SPECIES_GOLEM var/datum/action/innate/unstable_teleport/unstable_teleport var/teleport_cooldown = 100 @@ -605,6 +628,7 @@ attack_sound = 'sound/items/airhorn2.ogg' prefix = "Bananium" special_names = null + examine_limb_id = SPECIES_GOLEM /// Cooldown for producing honks COOLDOWN_DECLARE(honkooldown) @@ -684,7 +708,6 @@ /datum/species/golem/runic name = "Runic Golem" id = SPECIES_GOLEM_CULT - limbs_id = "cultgolem" sexes = FALSE info_text = "As a Runic Golem, you possess eldritch powers granted by the Elder Goddess Nar'Sie." species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYESPRITES) //no mutcolors @@ -709,6 +732,15 @@ special_names = null inherent_factions = list("cult") species_language_holder = /datum/language_holder/golem/runic + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/golem/cult, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/golem/cult, + BODY_ZONE_HEAD = /obj/item/bodypart/head/golem/cult, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/golem/cult, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/golem/cult, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem/cult, + ) + var/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/golem/phase_shift var/obj/effect/proc_holder/spell/pointed/abyssal_gaze/abyssal_gaze var/obj/effect/proc_holder/spell/pointed/dominate/dominate @@ -753,7 +785,6 @@ /datum/species/golem/cloth name = "Cloth Golem" id = SPECIES_GOLEM_CLOTH - limbs_id = "clothgolem" sexes = FALSE info_text = "As a Cloth Golem, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \ Being made of cloth, your body is magic resistant and faster than that of other golems, but weaker and less resilient." @@ -780,6 +811,14 @@ punchdamagehigh = 8 // not as heavy as stone prefix = "Cloth" special_names = null + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/golem/cloth, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/golem/cloth, + BODY_ZONE_HEAD = /obj/item/bodypart/head/golem/cloth, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/golem/cloth, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/golem/cloth, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem/cloth, + ) /datum/species/golem/cloth/on_species_gain(mob/living/carbon/C, datum/species/old_species) ..() @@ -942,6 +981,7 @@ special_names = list("Sheet", "Bag", "Bottle") fixed_mut_color = "fffa" info_text = "As a Plastic Golem, you are capable of ventcrawling and passing through plastic flaps as long as you are naked." + examine_limb_id = SPECIES_GOLEM /datum/species/golem/bronze name = "Bronze Golem" @@ -952,6 +992,7 @@ info_text = "As a Bronze Golem, you are very resistant to loud noises, and make loud noises if something hard hits you, however this ability does hurt your hearing." special_step_sounds = list('sound/machines/clockcult/integration_cog_install.ogg', 'sound/magic/clockwork/fellowship_armory.ogg' ) mutantears = /obj/item/organ/ears/bronze + examine_limb_id = SPECIES_GOLEM var/last_gong_time = 0 var/gong_cooldown = 150 @@ -1033,7 +1074,6 @@ TRAIT_NODISMEMBER, TRAIT_NOFLASH, ) - limbs_id = "c_golem" //special sprites attack_verb = "whips" attack_sound = 'sound/weapons/whip.ogg' miss_sound = 'sound/weapons/etherealmiss.ogg' @@ -1045,6 +1085,14 @@ punchdamagelow = 4 punchstunthreshold = 7 punchdamagehigh = 8 + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/golem/cardboard, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/golem/cardboard, + BODY_ZONE_HEAD = /obj/item/bodypart/head/golem/cardboard, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/golem/cardboard, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/golem/cardboard, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem/cardboard, + ) var/last_creation = 0 var/brother_creation_cooldown = 300 @@ -1096,12 +1144,11 @@ info_text = "As a Leather Golem, you are flammable, but you can grab things with incredible ease, allowing all your grabs to start at a strong level." grab_sound = 'sound/weapons/whipgrab.ogg' attack_sound = 'sound/weapons/whip.ogg' - + examine_limb_id = SPECIES_GOLEM /datum/species/golem/durathread name = "Durathread Golem" id = SPECIES_GOLEM_DURATHREAD prefix = "Durathread" - limbs_id = "d_golem" special_names = list("Boll","Weave") species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYESPRITES) fixed_mut_color = null @@ -1120,6 +1167,14 @@ TRAIT_NOFLASH, ) info_text = "As a Durathread Golem, your strikes will cause those your targets to start choking, but your woven body won't withstand fire as well." + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/golem/durathread, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/golem/durathread, + BODY_ZONE_HEAD = /obj/item/bodypart/head/golem/durathread, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/golem/durathread, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/golem/durathread, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem/durathread, + ) /datum/species/golem/durathread/spec_unarmedattacked(mob/living/carbon/human/user, mob/living/carbon/human/target) . = ..() @@ -1130,7 +1185,6 @@ id = SPECIES_GOLEM_BONE say_mod = "rattles" prefix = "Bone" - limbs_id = "b_golem" special_names = list("Head", "Broth", "Fracture", "Rattler", "Appetit") liked_food = GROSS | MEAT | RAW toxic_food = null @@ -1159,6 +1213,14 @@ ) species_language_holder = /datum/language_holder/golem/bone info_text = "As a Bone Golem, You have a powerful spell that lets you chill your enemies with fear, and milk heals you! Just make sure to watch our for bone-hurting juice." + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/golem/bone, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/golem/bone, + BODY_ZONE_HEAD = /obj/item/bodypart/head/golem/bone, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/golem/bone, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/golem/bone, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem/bone, + ) var/datum/action/innate/bonechill/bonechill /datum/species/golem/bone/on_species_gain(mob/living/carbon/C, datum/species/old_species) @@ -1238,7 +1300,6 @@ /datum/species/golem/snow name = "Snow Golem" id = SPECIES_GOLEM_SNOW - limbs_id = "sn_golem" fixed_mut_color = null //custom sprites armor = 45 //down from 55 burnmod = 3 //melts easily @@ -1259,7 +1320,14 @@ TRAIT_PIERCEIMMUNE, TRAIT_NODISMEMBER, ) - + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/golem/snow, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/golem/snow, + BODY_ZONE_HEAD = /obj/item/bodypart/head/golem/snow, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/golem/snow, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/golem/snow, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem/snow, + ) var/obj/effect/proc_holder/spell/targeted/conjure_item/snowball/ball var/obj/effect/proc_holder/spell/aimed/cryo/cryo @@ -1318,6 +1386,7 @@ TRAIT_NODISMEMBER, TRAIT_CHUNKYFINGERS, ) + examine_limb_id = SPECIES_GOLEM /datum/species/golem/mhydrogen/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index 271bd95c5c6..85f66b89c6f 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -1,5 +1,5 @@ /datum/species/human - name = "Human" + name = "\improper Human" id = SPECIES_HUMAN default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE) diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 1988641a375..e2ef3f14a6c 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -1,6 +1,6 @@ /datum/species/jelly // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them. - name = "Jellyperson" + name = "\improper Jellyperson" plural_form = "Jellypeople" id = SPECIES_JELLYPERSON default_color = "00FF90" @@ -27,6 +27,15 @@ species_language_holder = /datum/language_holder/jelly ass_image = 'icons/ass/assslime.png' + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/jelly, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/jelly, + BODY_ZONE_HEAD = /obj/item/bodypart/head/jelly, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/jelly, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/jelly, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/jelly, + ) + /datum/species/jelly/on_species_loss(mob/living/carbon/C) if(regenerate_limbs) regenerate_limbs.Remove(C) @@ -136,7 +145,7 @@ //Slime people are able to split like slimes, retaining a single mind that can swap between bodies at will, even after death. /datum/species/jelly/slime - name = "Slimeperson" + name = "\improper Slimeperson" plural_form = "Slimepeople" id = SPECIES_SLIMEPERSON default_color = "00FFFF" @@ -148,6 +157,15 @@ var/list/mob/living/carbon/bodies var/datum/action/innate/swap_body/swap_body + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/slime, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/slime, + BODY_ZONE_HEAD = /obj/item/bodypart/head/slime, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/slime, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/slime, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/slime, + ) + /datum/species/jelly/slime/on_species_loss(mob/living/carbon/C) if(slime_split) slime_split.Remove(C) @@ -425,6 +443,7 @@ name = "Luminescent" plural_form = null id = SPECIES_LUMINESCENT + examine_limb_id = SPECIES_JELLYPERSON var/glow_intensity = LUMINESCENT_DEFAULT_GLOW var/obj/effect/dummy/luminescent_glow/glow var/obj/item/slime_extract/current_extract @@ -433,6 +452,7 @@ var/datum/action/innate/use_extract/major/extract_major var/extract_cooldown = 0 + //Species datums don't normally implement destroy, but JELLIES SUCK ASS OUT OF A STEEL STRAW /datum/species/jelly/luminescent/Destroy(force, ...) current_extract = null @@ -605,9 +625,10 @@ //Stargazers are the telepathic branch of jellypeople, able to project psychic messages and to link minds with willing participants. /datum/species/jelly/stargazer - name = "Stargazer" + name = "\improper Stargazer" plural_form = null id = SPECIES_STARGAZER + examine_limb_id = SPECIES_JELLYPERSON /// Special "project thought" telepathy action for stargazers. var/datum/action/innate/project_thought/project_action diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 24981dd9fc2..2e695aa2e84 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -1,6 +1,6 @@ /datum/species/lizard // Reptilian humanoids with scaled skin and tails. - name = "Lizardperson" + name = "\improper Lizardperson" plural_form = "Lizardfolk" id = SPECIES_LIZARD say_mod = "hisses" @@ -35,12 +35,23 @@ deathsound = 'sound/voice/lizard/deathsound.ogg' wings_icons = list("Dragon") species_language_holder = /datum/language_holder/lizard + digitigrade_customization = DIGITIGRADE_OPTIONAL + // Lizards are coldblooded and can stand a greater temperature range than humans bodytemp_heat_damage_limit = (BODYTEMP_HEAT_DAMAGE_LIMIT + 20) // This puts lizards 10 above lavaland max heat for ash lizards. bodytemp_cold_damage_limit = (BODYTEMP_COLD_DAMAGE_LIMIT - 10) ass_image = 'icons/ass/asslizard.png' + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/lizard, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/lizard, + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/lizard, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/lizard, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/lizard, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/lizard, + ) + /// Lizards are cold blooded and do not stabilize body temperature naturally /datum/species/lizard/body_temperature_core(mob/living/carbon/human/humi, delta_time, times_fired) return @@ -169,8 +180,7 @@ Lizard subspecies: ASHWALKERS /datum/species/lizard/ashwalker name = "Ash Walker" id = SPECIES_LIZARD_ASH - limbs_id = "lizard" - species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE,HAS_FLESH,HAS_BONE) + species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAS_FLESH,HAS_BONE) mutantlungs = /obj/item/organ/lungs/ashwalker inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, @@ -179,14 +189,14 @@ Lizard subspecies: ASHWALKERS TRAIT_VIRUSIMMUNE, ) species_language_holder = /datum/language_holder/lizard/ash - + digitigrade_customization = DIGITIGRADE_FORCED + examine_limb_id = SPECIES_LIZARD /* Lizard subspecies: SILVER SCALED */ /datum/species/lizard/silverscale name = "Silver Scale" id = SPECIES_LIZARD_SILVER - limbs_id = "lizard" inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, @@ -203,6 +213,7 @@ Lizard subspecies: SILVER SCALED mutanttongue = /obj/item/organ/tongue/lizard/silver armor = 10 //very light silvery scales soften blows changesource_flags = MIRROR_BADMIN | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN + examine_limb_id = SPECIES_LIZARD ///stored mutcolor for when we turn back off of a silverscale. var/old_mutcolor ///stored eye color for when we turn back off of a silverscale. diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index 9e835ba3d80..18bd734f952 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -2,6 +2,7 @@ name = "Monkey" id = SPECIES_MONKEY say_mod = "chimpers" + bodytype = BODYTYPE_ORGANIC | BODYTYPE_MONKEY attack_verb = "bite" attack_effect = ATTACK_EFFECT_BITE attack_sound = 'sound/weapons/bite.ogg' @@ -10,7 +11,6 @@ mutant_bodyparts = list("tail_monkey" = "Monkey") skinned_type = /obj/item/stack/sheet/animalhide/monkey meat = /obj/item/food/meat/slab/monkey - allowed_animal_origin = MONKEY_BODY knife_butcher_results = list(/obj/item/food/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1) species_traits = list( HAS_FLESH, @@ -41,14 +41,14 @@ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN | SLIME_EXTRACT liked_food = MEAT | FRUIT disliked_food = CLOTH - limbs_id = "monkey" damage_overlay_type = "monkey" sexes = FALSE punchdamagelow = 1 punchdamagehigh = 3 punchstunthreshold = 4 // no stun punches species_language_holder = /datum/language_holder/monkey - bodypart_overides = list( + + bodypart_overrides = list( BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/monkey, BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/monkey, BODY_ZONE_HEAD = /obj/item/bodypart/head/monkey, diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index 5e06277ac7e..6a805be1f0f 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -1,5 +1,5 @@ /datum/species/moth - name = "Mothman" + name = "\improper Mothman" plural_form = "Mothmen" id = SPECIES_MOTH say_mod = "flutters" @@ -29,6 +29,15 @@ payday_modifier = 0.75 family_heirlooms = list(/obj/item/flashlight/lantern/heirloom_moth) + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/moth, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/moth, + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/moth, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/moth, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/moth, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/moth, + ) + /datum/species/moth/regenerate_organs(mob/living/carbon/C, datum/species/old_species, replace_current= TRUE, list/excluded_zones, visual_only) . = ..() if(ishuman(C)) diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index 08f15068520..db340e41898 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -34,6 +34,15 @@ var/datum/martial_art/mushpunch/mush species_language_holder = /datum/language_holder/mushroom + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/mushroom, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/mushroom, + BODY_ZONE_HEAD = /obj/item/bodypart/head/mushroom, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/mushroom, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/mushroom, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/mushroom, + ) + /datum/species/mush/check_roundstart_eligible() return FALSE //hard locked out of roundstart on the order of design lead kor, this can be removed in the future when planetstation is here OR SOMETHING but right now we have a problem with races. diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index f7d2c974b7a..5d34c91b2b3 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -1,5 +1,5 @@ /datum/species/plasmaman - name = "Plasmaman" + name = "\improper Plasmaman" plural_form = "Plasmamen" id = SPECIES_PLASMAMAN say_mod = "rattles" @@ -34,6 +34,15 @@ outfit_important_for_life = /datum/outfit/plasmaman species_language_holder = /datum/language_holder/skeleton + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/plasmaman, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/plasmaman, + BODY_ZONE_HEAD = /obj/item/bodypart/head/plasmaman, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/plasmaman, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/plasmaman, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/plasmaman, + ) + // Body temperature for Plasmen is much lower human as they can handle colder environments bodytemp_normal = (BODYTEMP_NORMAL - 40) // The minimum amount they stabilize per tick is reduced making hot areas harder to deal with @@ -56,7 +65,7 @@ var/atmos_sealed = CanIgniteMob(H) && (isclothing(H.wear_suit) && H.wear_suit.clothing_flags & STOPSPRESSUREDAMAGE) && (isclothing(H.head) && H.head.clothing_flags & STOPSPRESSUREDAMAGE) var/flammable_limb = FALSE for(var/obj/item/bodypart/found_bodypart as anything in H.bodyparts)//If any plasma based limb is found the plasmaman will attempt to autoignite - if(found_bodypart.status == BODYPART_ORGANIC && (found_bodypart.species_id == SPECIES_PLASMAMAN || HAS_TRAIT(found_bodypart, TRAIT_PLASMABURNT))) //Allows for "donated" limbs and augmented limbs to prevent autoignition + if(IS_ORGANIC_LIMB(found_bodypart) && (found_bodypart.limb_id == SPECIES_PLASMAMAN || HAS_TRAIT(found_bodypart, TRAIT_PLASMABURNT))) //Allows for "donated" limbs and augmented limbs to prevent autoignition flammable_limb = TRUE break if(!flammable_limb && !H.on_fire) //Allows their suit to attempt to autoextinguish if augged and on fire diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index ee51875bbac..798629a30cf 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -1,6 +1,6 @@ /datum/species/pod // A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness. - name = "Podperson" + name = "\improper Podperson" plural_form = "Podpeople" id = SPECIES_PODPERSON default_color = "59CE00" @@ -29,6 +29,15 @@ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT species_language_holder = /datum/language_holder/plant + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/pod, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/pod, + BODY_ZONE_HEAD = /obj/item/bodypart/head/pod, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/pod, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/pod, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/pod, + ) + /datum/species/pod/spec_life(mob/living/carbon/human/H, delta_time, times_fired) if(H.stat == DEAD) return @@ -41,7 +50,7 @@ if(H.nutrition > NUTRITION_LEVEL_ALMOST_FULL) H.set_nutrition(NUTRITION_LEVEL_ALMOST_FULL) if(light_amount > 0.2) //if there's enough light, heal - H.heal_overall_damage(0.5 * delta_time, 0.5 * delta_time, 0, BODYPART_ORGANIC) + H.heal_overall_damage(0.5 * delta_time, 0.5 * delta_time, 0, BODYTYPE_ORGANIC) H.adjustToxLoss(-0.5 * delta_time) H.adjustOxyLoss(-0.5 * delta_time) diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index e1013f5c658..4b905f35aa0 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -18,6 +18,15 @@ mutanteyes = /obj/item/organ/eyes/night_vision species_language_holder = /datum/language_holder/shadowpeople + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/shadow, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/shadow, + BODY_ZONE_HEAD = /obj/item/bodypart/head/shadow, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/shadow, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/shadow, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/shadow, + ) + /datum/species/shadow/spec_life(mob/living/carbon/human/H, delta_time, times_fired) var/turf/T = H.loc @@ -25,9 +34,9 @@ var/light_amount = T.get_lumcount() if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) //if there's enough light, start dying - H.take_overall_damage(0.5 * delta_time, 0.5 * delta_time, 0, BODYPART_ORGANIC) + H.take_overall_damage(0.5 * delta_time, 0.5 * delta_time, 0, BODYTYPE_ORGANIC) else if (light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD) //heal in the dark - H.heal_overall_damage(0.5 * delta_time, 0.5 * delta_time, 0, BODYPART_ORGANIC) + H.heal_overall_damage(0.5 * delta_time, 0.5 * delta_time, 0, BODYTYPE_ORGANIC) /datum/species/shadow/check_roundstart_eligible() if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 4e3726d80c3..302f06f052b 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -38,6 +38,15 @@ changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN species_language_holder = /datum/language_holder/skeleton + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/skeleton, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/skeleton, + BODY_ZONE_HEAD = /obj/item/bodypart/head/skeleton, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/skeleton, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/skeleton, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/skeleton, + ) + /datum/species/skeleton/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) . = ..() C.set_safe_hunger_level() diff --git a/code/modules/mob/living/carbon/human/species_types/snail.dm b/code/modules/mob/living/carbon/human/species_types/snail.dm index d8c073a5da2..46ff16c832f 100644 --- a/code/modules/mob/living/carbon/human/species_types/snail.dm +++ b/code/modules/mob/living/carbon/human/species_types/snail.dm @@ -24,6 +24,15 @@ mutanttongue = /obj/item/organ/tongue/snail exotic_blood = /datum/reagent/lube + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/snail, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/snail, + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/snail, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/snail, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/snail, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/snail + ) + /datum/species/snail/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, delta_time, times_fired) if(istype(chem,/datum/reagent/consumable/salt)) H.adjustFireLoss(2 * REAGENTS_EFFECT_MULTIPLIER * delta_time) diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm deleted file mode 100644 index 5e0f37de8cf..00000000000 --- a/code/modules/mob/living/carbon/human/species_types/synths.dm +++ /dev/null @@ -1,142 +0,0 @@ -/datum/species/synth - name = "Synth" //inherited from the real species, for health scanners and things - id = SPECIES_SYNTH - say_mod = "beep boops" //inherited from a user's real species - sexes = 0 - species_traits = list(NOTRANSSTING, NO_DNA_COPY) //all of these + whatever we inherit from the real species - inherent_traits = list( - TRAIT_ADVANCEDTOOLUSER, - TRAIT_CAN_STRIP, - TRAIT_VIRUSIMMUNE, - TRAIT_NODISMEMBER, - TRAIT_NOLIMBDISABLE, - TRAIT_NOHUNGER, - TRAIT_NOBREATH, - ) - inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID - meat = null - damage_overlay_type = "synth" - limbs_id = "synth" - ///If your health becomes equal to or less than this value, your disguise is supposed to break. Unfortunately, that feature currently isn't implemented, so currently, all this threshold is used for is (I kid you not) determining whether or not your speech uses SPAN_CLOWN while you're disguised as a bananium golem. See the handle_speech() proc further down in this file for more information on that check. - var/disguise_fail_health = 75 - var/datum/species/fake_species //a species to do most of our work for us, unless we're damaged - var/list/initial_species_traits //for getting these values back for assume_disguise() - var/list/initial_inherent_traits - wings_icons = list("Robotic") - changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC - species_language_holder = /datum/language_holder/synthetic - -/datum/species/synth/New() - initial_species_traits = species_traits.Copy() - initial_inherent_traits = inherent_traits.Copy() - ..() - -/datum/species/synth/military - name = "Military Synth" - id = SPECIES_SYNTH_MILITARY - armor = 25 - punchdamagelow = 10 - punchdamagehigh = 19 - punchstunthreshold = 14 //about 50% chance to stun - disguise_fail_health = 50 - changesource_flags = MIRROR_BADMIN | WABBAJACK - -/datum/species/synth/on_species_gain(mob/living/carbon/human/H, datum/species/old_species) - ..() - assume_disguise(old_species, H) - RegisterSignal(H, COMSIG_MOB_SAY, .proc/handle_speech) - H.set_safe_hunger_level() - -/datum/species/synth/on_species_loss(mob/living/carbon/human/H) - . = ..() - UnregisterSignal(H, COMSIG_MOB_SAY) - -/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, delta_time, times_fired) - if(chem.type == /datum/reagent/medicine/c2/synthflesh) - chem.expose_mob(H, TOUCH, 2 * REAGENTS_EFFECT_MULTIPLIER * delta_time,0) //heal a little - H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * delta_time) - return TRUE - return ..() - - -/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H) - if(S && !istype(S, type)) - name = S.name - say_mod = S.say_mod - sexes = S.sexes - species_traits = initial_species_traits.Copy() - inherent_traits = initial_inherent_traits.Copy() - species_traits |= S.species_traits - inherent_traits |= S.inherent_traits - attack_verb = S.attack_verb - attack_effect = S.attack_effect - attack_sound = S.attack_sound - miss_sound = S.miss_sound - meat = S.meat - mutant_bodyparts = S.mutant_bodyparts.Copy() - mutant_organs = S.mutant_organs.Copy() - nojumpsuit = S.nojumpsuit - no_equip = S.no_equip.Copy() - limbs_id = S.limbs_id - use_skintones = S.use_skintones - fixed_mut_color = S.fixed_mut_color - hair_color = S.hair_color - fake_species = new S.type - else - name = initial(name) - say_mod = initial(say_mod) - species_traits = initial_species_traits.Copy() - inherent_traits = initial_inherent_traits.Copy() - attack_verb = initial(attack_verb) - attack_effect = initial(attack_verb) - attack_sound = initial(attack_sound) - miss_sound = initial(miss_sound) - mutant_bodyparts = list() - nojumpsuit = initial(nojumpsuit) - no_equip = list() - qdel(fake_species) - fake_species = null - meat = initial(meat) - limbs_id = "synth" - use_skintones = 0 - sexes = 0 - fixed_mut_color = "" - hair_color = "" - - for(var/X in H.bodyparts) //propagates the damage_overlay changes - var/obj/item/bodypart/BP = X - BP.update_limb() - H.update_body_parts() //to update limb icon cache with the new damage overlays - -//Proc redirects: -//Passing procs onto the fake_species, to ensure we look as much like them as possible - -/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour) - if(fake_species) - fake_species.handle_hair(H, forced_colour) - else - return ..() - - -/datum/species/synth/handle_body(mob/living/carbon/human/H) - if(fake_species) - fake_species.handle_body(H) - else - return ..() - - -/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour) - if(fake_species) - fake_species.handle_mutant_bodyparts(H,forced_colour) - else - return ..() - - -/datum/species/synth/proc/handle_speech(datum/source, list/speech_args) - SIGNAL_HANDLER - if (isliving(source)) // yeah it's gonna be living but just to be clean - var/mob/living/L = source - if(fake_species && L.health > disguise_fail_health) - switch(fake_species.type) - if (/datum/species/golem/bananium) - speech_args[SPEECH_SPANS] |= SPAN_CLOWN diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 88ddce6b7d1..608c8436f41 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -31,7 +31,7 @@ use_skintones = TRUE mutantheart = /obj/item/organ/heart/vampire mutanttongue = /obj/item/organ/tongue/vampire - limbs_id = "human" + examine_limb_id = SPECIES_HUMAN skinned_type = /obj/item/stack/sheet/animalhide/human ///some starter text sent to the vampire initially, because vampires have shit to do to stay alive var/info_text = "You are a Vampire. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability." @@ -51,7 +51,7 @@ /datum/species/vampire/spec_life(mob/living/carbon/human/vampire, delta_time, times_fired) . = ..() if(istype(vampire.loc, /obj/structure/closet/crate/coffin)) - vampire.heal_overall_damage(2 * delta_time, 2 * delta_time, 0, BODYPART_ORGANIC) + vampire.heal_overall_damage(2 * delta_time, 2 * delta_time, 0, BODYTYPE_ORGANIC) vampire.adjustToxLoss(-2 * delta_time) vampire.adjustOxyLoss(-2 * delta_time) vampire.adjustCloneLoss(-2 * delta_time) diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index f428a46509e..fd624b40ddc 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -3,7 +3,7 @@ /datum/species/zombie // 1spooky name = "High-Functioning Zombie" - id = SPECIES_ZOMBIE_HALLOWEEN + id = SPECIES_ZOMBIE say_mod = "moans" sexes = 0 meat = /obj/item/food/meat/slab/human/mutant/zombie @@ -36,6 +36,15 @@ bodytemp_heat_damage_limit = FIRE_MINIMUM_TEMPERATURE_TO_EXIST // Take damage at fire temp bodytemp_cold_damage_limit = MINIMUM_TEMPERATURE_TO_MOVE // take damage below minimum movement temp + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/zombie, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/zombie, + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/zombie, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/zombie, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/zombie, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/zombie + ) + /// Zombies do not stabilize body temperature they are the walking dead and are cold blooded /datum/species/zombie/body_temperature_core(mob/living/carbon/human/humi, delta_time, times_fired) return @@ -69,8 +78,8 @@ /datum/species/zombie/infectious name = "Infectious Zombie" - id = SPECIES_ZOMBIE - limbs_id = "zombie" + id = SPECIES_ZOMBIE_INFECTIOUS + examine_limb_id = SPECIES_ZOMBIE mutanthands = /obj/item/zombie_hand armor = 20 // 120 damage to KO a zombie, which kills it speedmod = 1.6 @@ -132,19 +141,38 @@ infection.Insert(C) // Your skin falls off -/datum/species/krokodil_addict - name = "Human" - id = SPECIES_ADDICT - limbs_id = "zombie" //They look like zombies +/datum/species/human/krokodil_addict + name = "\improper Human" + id = SPECIES_ZOMBIE_KROKODIL + examine_limb_id = SPECIES_HUMAN sexes = 0 - meat = /obj/item/food/meat/slab/human/mutant/zombie mutanttongue = /obj/item/organ/tongue/zombie changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN - species_traits = list(HAS_FLESH, HAS_BONE) - inherent_traits = list( - TRAIT_ADVANCEDTOOLUSER, - TRAIT_CAN_STRIP, - TRAIT_EASILY_WOUNDED, + + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/zombie, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/zombie, + BODY_ZONE_L_ARM = /obj/item/bodypart/l_arm/zombie, + BODY_ZONE_R_ARM = /obj/item/bodypart/r_arm/zombie, + BODY_ZONE_L_LEG = /obj/item/bodypart/l_leg/zombie, + BODY_ZONE_R_LEG = /obj/item/bodypart/r_leg/zombie ) +/datum/species/human/krokodil_addict/replace_body(mob/living/carbon/target, datum/species/new_species) + ..() + var/skintone + if(ishuman(target)) + var/mob/living/carbon/human/human_target = target + skintone = human_target.skin_tone + + for(var/obj/item/bodypart/limb as anything in target.bodyparts) + if(IS_ORGANIC_LIMB(limb)) + if(limb.body_zone == BODY_ZONE_HEAD || limb.body_zone == BODY_ZONE_CHEST) + limb.is_dimorphic = TRUE + limb.skin_tone ||= skintone + limb.limb_id = SPECIES_HUMAN + limb.should_draw_greyscale = TRUE + limb.name = "human [parse_zone(limb.body_zone)]" + limb.update_limb() + #undef REGENERATION_DELAY diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 5273d0dd930..9fe7e1ddcc3 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -14,6 +14,16 @@ return legcuffed return null +/mob/living/carbon/proc/get_all_worn_items() + return list( + back, + wear_mask, + wear_neck, + head, + handcuffed, + legcuffed, + ) + /mob/living/carbon/proc/equip_in_one_of_slots(obj/item/I, list/slots, qdel_on_fail = 1) for(var/slot in slots) if(equip_to_slot_if_possible(I, slots[slot], qdel_on_fail = 0, disable_warning = TRUE)) @@ -242,3 +252,26 @@ visible_message(span_notice("[src] takes [I] from [offerer]."), \ span_notice("You take [I] from [offerer].")) put_in_hands(I) + +///Returns a list of all body_zones covered by clothing +/mob/living/carbon/proc/get_covered_body_zones() + RETURN_TYPE(/list) + SHOULD_NOT_OVERRIDE(TRUE) + + var/covered_flags = NONE + var/list/all_worn_items = get_all_worn_items() + for(var/obj/item/worn_item in all_worn_items) + covered_flags |= worn_item.body_parts_covered + + return cover_flags2body_zones(covered_flags) + +///Returns a bitfield of all zones covered by clothing +/mob/living/carbon/proc/get_all_covered_flags() + SHOULD_NOT_OVERRIDE(TRUE) + + var/covered_flags = NONE + var/list/all_worn_items = get_all_worn_items() + for(var/obj/item/worn_item in all_worn_items) + covered_flags |= worn_item.body_parts_covered + + return covered_flags diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index f5ff872ee45..3b013b98a97 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -324,15 +324,11 @@ return /mob/living/carbon/proc/handle_bodyparts(delta_time, times_fired) - var/stam_regen = FALSE if(stam_regen_start_time <= world.time) - stam_regen = TRUE if(HAS_TRAIT_FROM(src, TRAIT_INCAPACITATED, STAMINA)) . |= BODYPART_LIFE_UPDATE_HEALTH //make sure we remove the stamcrit - for(var/I in bodyparts) - var/obj/item/bodypart/BP = I - if(BP.needs_processing) - . |= BP.on_life(delta_time, times_fired, stam_regen) + for(var/obj/item/bodypart/limb as anything in bodyparts) + . |= limb.on_life(delta_time, times_fired) /mob/living/carbon/proc/handle_organs(delta_time, times_fired) if(stat != DEAD) @@ -758,7 +754,7 @@ All effects don't start immediately, but rather get worse over time; the rate is if(limb.get_damage() >= limb.max_damage) limb.cremation_progress += rand(1 * delta_time, 2.5 * delta_time) if(limb.cremation_progress >= 100) - if(limb.status == BODYPART_ORGANIC) //Non-organic limbs don't burn + if(IS_ORGANIC_LIMB(limb)) //Non-organic limbs don't burn limb.drop_limb() limb.visible_message(span_warning("[src]'s [limb.name] crumbles into ash!")) qdel(limb) @@ -774,7 +770,7 @@ All effects don't start immediately, but rather get worse over time; the rate is if(head.get_damage() >= head.max_damage) head.cremation_progress += rand(1 * delta_time, 2.5 * delta_time) if(head.cremation_progress >= 100) - if(head.status == BODYPART_ORGANIC) //Non-organic limbs don't burn + if(IS_ORGANIC_LIMB(head)) //Non-organic limbs don't burn head.drop_limb() head.visible_message(span_warning("[src]'s head crumbles into ash!")) qdel(head) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 234e4eb8c02..36c2f1f3b7d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1340,9 +1340,7 @@ // Randomize everything but the species, which was already handled above. new_human.randomize_human_appearance(~RANDOMIZE_SPECIES) - new_human.update_body() - new_human.update_hair() - new_human.update_body_parts() + new_human.update_body(is_creating = TRUE) new_human.dna.update_dna_identity() new_mob = new_human diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 1100627ba53..4cef7a260d6 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -372,14 +372,14 @@ */ /proc/item_heal_robotic(mob/living/carbon/human/H, mob/user, brute_heal, burn_heal) var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - if(affecting && affecting.status == BODYPART_ROBOTIC) + if(affecting && !IS_ORGANIC_LIMB(affecting)) var/dam //changes repair text based on how much brute/burn was supplied if(brute_heal > burn_heal) dam = 1 else dam = 0 if((brute_heal > 0 && affecting.brute_dam > 0) || (burn_heal > 0 && affecting.burn_dam > 0)) - if(affecting.heal_damage(brute_heal, burn_heal, 0, BODYPART_ROBOTIC)) + if(affecting.heal_damage(brute_heal, burn_heal, 0, BODYTYPE_ROBOTIC)) H.update_damage_overlays() user.visible_message(span_notice("[user] fixes some of the [dam ? "dents on" : "burnt wires in"] [H]'s [affecting.name]."), \ span_notice("You fix some of the [dam ? "dents on" : "burnt wires in"] [H == user ? "your" : "[H]'s"] [affecting.name].")) diff --git a/code/modules/mob_spawn/corpses/mining_corpses.dm b/code/modules/mob_spawn/corpses/mining_corpses.dm index 2d882c1f58b..ecbbc2001f3 100644 --- a/code/modules/mob_spawn/corpses/mining_corpses.dm +++ b/code/modules/mob_spawn/corpses/mining_corpses.dm @@ -187,7 +187,7 @@ /datum/outfit/consumed_dame/pre_equip(mob/living/carbon/human/dame, visualsOnly = FALSE) if(!visualsOnly) dame.gender = FEMALE - dame.body_type = FEMALE + dame.physique = FEMALE dame.update_body() if(prob(30)) back = /obj/item/nullrod/scythe/talking diff --git a/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm b/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm index 2d390a1b560..ab05eb6230b 100644 --- a/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm +++ b/code/modules/ninja/suit/ninja_equipment_actions/energy_net_nets.dm @@ -24,16 +24,16 @@ buckle_lying = 0 buckle_prevents_pull = TRUE ///The creature currently caught in the net - var/mob/living/affecting + var/mob/living/affected_mob /obj/structure/energy_net/play_attack_sound(damage, damage_type = BRUTE, damage_flag = 0) if(damage_type == BRUTE || damage_type == BURN) playsound(src, 'sound/weapons/slash.ogg', 80, TRUE) /obj/structure/energy_net/Destroy() - if(!QDELETED(affecting)) - affecting.visible_message(span_notice("[affecting.name] is recovered from the energy net!"), span_notice("You are recovered from the energy net!"), span_hear("You hear a grunt.")) - affecting = null + if(!QDELETED(affected_mob)) + affected_mob.visible_message(span_notice("[affected_mob.name] is recovered from the energy net!"), span_notice("You are recovered from the energy net!"), span_hear("You hear a grunt.")) + affected_mob = null return ..() /obj/structure/energy_net/attack_paw(mob/user, list/modifiers) diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm index 29ffe4a5af0..66eb50438fe 100644 --- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm +++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm @@ -34,7 +34,7 @@ ninja.Beam(net_target, "n_beam", time = 15) ninja.say("Get over here!", forced = "ninja net") var/obj/structure/energy_net/net = new /obj/structure/energy_net(net_target.drop_location()) - net.affecting = net_target + net.affected_mob = net_target ninja.visible_message(span_danger("[ninja] caught [net_target] with an energy net!"),span_notice("You caught [net_target] with an energy net!")) if(net_target.buckled) diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm index a04ac4a7dd7..20b604afa1c 100644 --- a/code/modules/ninja/suit/suit.dm +++ b/code/modules/ninja/suit/suit.dm @@ -167,7 +167,7 @@ var/design_choice = tgui_alert(ninja, "Please choose your desired suit design.",,list("Original","New Age")) switch(design_choice) if("Original") - icon_state = ninja.body_type == "female" ? "s-ninjanf" : "s-ninjan" + icon_state = ninja.physique == "female" ? "s-ninjanf" : "s-ninjan" ninja.gloves.icon_state = "s-ninjan" ninja.gloves.inhand_icon_state = "s-ninjan" if("New Age") diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 8610cbb8aab..3ae225e4b46 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -546,7 +546,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri return ..() var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - if(affecting && affecting.status == BODYPART_ROBOTIC) + if(affecting && !IS_ORGANIC_LIMB(affecting)) if(user == H) user.visible_message(span_notice("[user] starts to fix some of the wires in [H]'s [affecting.name]."), span_notice("You start fixing some of the wires in [H == user ? "your" : "[H]'s"] [affecting.name].")) if(!do_mob(user, H, 50)) diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 71686778ae6..3e593b513ec 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -116,10 +116,10 @@ to_chat(M, span_notice("[high_message]")) SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "smacked out", /datum/mood_event/narcotic_heavy, name) if(current_cycle == 35 && creation_purity <= 0.6) - if(!istype(M.dna.species, /datum/species/krokodil_addict)) + if(!istype(M.dna.species, /datum/species/human/krokodil_addict)) to_chat(M, span_userdanger("Your skin falls off easily!")) M.adjustBruteLoss(50*REM, 0) // holy shit your skin just FELL THE FUCK OFF - M.set_species(/datum/species/krokodil_addict) + M.set_species(/datum/species/human/krokodil_addict) ..() /datum/reagent/drug/krokodil/overdose_process(mob/living/M, delta_time, times_fired) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index cb58051ce77..0d5d2011b2c 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -296,7 +296,7 @@ /datum/reagent/medicine/oxandrolone/overdose_process(mob/living/M, delta_time, times_fired) if(M.getFireLoss()) //It only makes existing burns worse - M.adjustFireLoss(4.5 * REM * delta_time, FALSE, FALSE, BODYPART_ORGANIC) // it's going to be healing either 4 or 0.5 + M.adjustFireLoss(4.5 * REM * delta_time, FALSE, FALSE, BODYTYPE_ORGANIC) // it's going to be healing either 4 or 0.5 . = TRUE ..() @@ -339,8 +339,8 @@ holder.add_reagent(/datum/reagent/consumable/sugar, 1) holder.remove_reagent(/datum/reagent/medicine/salglu_solution, 0.5) if(DT_PROB(18, delta_time)) - M.adjustBruteLoss(0.5, FALSE, FALSE, BODYPART_ORGANIC) - M.adjustFireLoss(0.5, FALSE, FALSE, BODYPART_ORGANIC) + M.adjustBruteLoss(0.5, FALSE, FALSE, BODYTYPE_ORGANIC) + M.adjustFireLoss(0.5, FALSE, FALSE, BODYTYPE_ORGANIC) . = TRUE ..() @@ -407,8 +407,8 @@ /datum/reagent/medicine/omnizine/overdose_process(mob/living/M, delta_time, times_fired) M.adjustToxLoss(1.5 * REM * delta_time, FALSE) M.adjustOxyLoss(1.5 * REM * delta_time, FALSE) - M.adjustBruteLoss(1.5 * REM * delta_time, FALSE, FALSE, BODYPART_ORGANIC) - M.adjustFireLoss(1.5 * REM * delta_time, FALSE, FALSE, BODYPART_ORGANIC) + M.adjustBruteLoss(1.5 * REM * delta_time, FALSE, FALSE, BODYTYPE_ORGANIC) + M.adjustFireLoss(1.5 * REM * delta_time, FALSE, FALSE, BODYTYPE_ORGANIC) ..() . = TRUE @@ -505,7 +505,7 @@ /datum/reagent/medicine/sal_acid/overdose_process(mob/living/M, delta_time, times_fired) if(M.getBruteLoss()) //It only makes existing bruises worse - M.adjustBruteLoss(4.5 * REM * delta_time, FALSE, FALSE, BODYPART_ORGANIC) // it's going to be healing either 4 or 0.5 + M.adjustBruteLoss(4.5 * REM * delta_time, FALSE, FALSE, BODYTYPE_ORGANIC) // it's going to be healing either 4 or 0.5 . = TRUE ..() diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 7811a7d9567..a9804349945 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -583,7 +583,7 @@ /datum/reagent/toxin/histamine/overdose_process(mob/living/M, delta_time, times_fired) M.adjustOxyLoss(2 * REM * delta_time, FALSE) - M.adjustBruteLoss(2 * REM * delta_time, FALSE, FALSE, BODYPART_ORGANIC) + M.adjustBruteLoss(2 * REM * delta_time, FALSE, FALSE, BODYTYPE_ORGANIC) M.adjustToxLoss(2 * REM * delta_time, FALSE) ..() . = TRUE diff --git a/code/modules/reagents/reagent_containers/patch.dm b/code/modules/reagents/reagent_containers/patch.dm index 4bb98269ae9..722da9e3b1a 100644 --- a/code/modules/reagents/reagent_containers/patch.dm +++ b/code/modules/reagents/reagent_containers/patch.dm @@ -17,7 +17,7 @@ if(!affecting) to_chat(user, span_warning("The limb is missing!")) return - if(affecting.status != BODYPART_ORGANIC) + if(!IS_ORGANIC_LIMB(affecting)) to_chat(user, span_notice("Medicine won't work on a robotic limb!")) return ..() diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index 807f79f6e48..88f299227a5 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -97,19 +97,18 @@ if(!ishuman(target)) return FALSE var/mob/living/carbon/human/blessed = target - for(var/X in blessed.bodyparts) - var/obj/item/bodypart/bodypart = X - if(bodypart.status == BODYPART_ROBOTIC) + for(var/obj/item/bodypart/bodypart as anything in blessed.bodyparts) + if(!IS_ORGANIC_LIMB(bodypart)) to_chat(chap, span_warning("[GLOB.deity] refuses to heal this metallic taint!")) return TRUE var/heal_amt = 10 - var/list/hurt_limbs = blessed.get_damaged_bodyparts(1, 1, null, BODYPART_ORGANIC) + var/list/hurt_limbs = blessed.get_damaged_bodyparts(1, 1, null, BODYTYPE_ORGANIC) if(hurt_limbs.len) for(var/X in hurt_limbs) var/obj/item/bodypart/affecting = X - if(affecting.heal_damage(heal_amt, heal_amt, null, BODYPART_ORGANIC)) + if(affecting.heal_damage(heal_amt, heal_amt, null, BODYTYPE_ORGANIC)) blessed.update_damage_overlays() blessed.visible_message(span_notice("[chap] heals [blessed] with the power of [GLOB.deity]!")) to_chat(blessed, span_boldnotice("May the power of [GLOB.deity] compel you to be healed!")) @@ -164,7 +163,7 @@ //if we're not targetting a robot part we stop early var/obj/item/bodypart/bodypart = blessed.get_bodypart(chap.zone_selected) - if(bodypart.status != BODYPART_ROBOTIC) + if(!IS_ORGANIC_LIMB(bodypart)) if(!did_we_charge) to_chat(chap, span_warning("[GLOB.deity] scoffs at the idea of healing such fleshy matter!")) else @@ -175,7 +174,7 @@ return TRUE //charge(?) and go - if(bodypart.heal_damage(5,5,null,BODYPART_ROBOTIC)) + if(bodypart.heal_damage(5,5,null,BODYTYPE_ROBOTIC)) blessed.update_damage_overlays() blessed.visible_message(span_notice("[chap] [did_we_charge ? "repairs" : "repairs and charges"] [blessed] with the power of [GLOB.deity]!")) @@ -251,16 +250,16 @@ return FALSE var/mob/living/carbon/human/blessed = blessed_living for(var/obj/item/bodypart/robolimb as anything in blessed.bodyparts) - if(robolimb.status == BODYPART_ROBOTIC) + if(!IS_ORGANIC_LIMB(robolimb)) to_chat(chap, span_warning("[GLOB.deity] refuses to heal this metallic taint!")) return TRUE account.adjust_money(-GREEDY_HEAL_COST) var/heal_amt = 30 - var/list/hurt_limbs = blessed.get_damaged_bodyparts(1, 1, null, BODYPART_ORGANIC) + var/list/hurt_limbs = blessed.get_damaged_bodyparts(1, 1, null, BODYTYPE_ORGANIC) if(hurt_limbs.len) for(var/obj/item/bodypart/affecting as anything in hurt_limbs) - if(affecting.heal_damage(heal_amt, heal_amt, null, BODYPART_ORGANIC)) + if(affecting.heal_damage(heal_amt, heal_amt, null, BODYTYPE_ORGANIC)) blessed.update_damage_overlays() blessed.visible_message(span_notice("[chap] barters a heal for [blessed] from [GLOB.deity]!")) to_chat(blessed, span_boldnotice("May the power of [GLOB.deity] compel you to be healed! Thank you for choosing [GLOB.deity]!")) diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm index f648d829134..2738fc89d5c 100644 --- a/code/modules/research/designs/limbgrower_designs.dm +++ b/code/modules/research/designs/limbgrower_designs.dm @@ -4,7 +4,7 @@ /datum/design/leftarm name = "Left Arm" - id = "leftarm" + id = "l_arm" build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 25) build_path = /obj/item/bodypart/l_arm @@ -12,7 +12,7 @@ /datum/design/rightarm name = "Right Arm" - id = "rightarm" + id = "r_arm" build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 25) build_path = /obj/item/bodypart/r_arm @@ -20,35 +20,19 @@ /datum/design/leftleg name = "Left Leg" - id = "leftleg" + id = "l_leg" build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 25) build_path = /obj/item/bodypart/l_leg - category = list("initial",SPECIES_HUMAN,SPECIES_LIZARD,SPECIES_MOTH,SPECIES_PLASMAMAN,SPECIES_ETHEREAL) + category = list("initial",SPECIES_HUMAN,SPECIES_LIZARD,SPECIES_MOTH,SPECIES_PLASMAMAN,SPECIES_ETHEREAL, "digitigrade") /datum/design/rightleg name = "Right Leg" - id = "rightleg" + id = "r_leg" build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 25) build_path = /obj/item/bodypart/r_leg - category = list("initial",SPECIES_HUMAN,SPECIES_LIZARD,SPECIES_MOTH,SPECIES_PLASMAMAN,SPECIES_ETHEREAL) - -/datum/design/digi_leftleg - name = "Digitigrade Left Leg" - id = "digi_leftleg" - build_type = LIMBGROWER - reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 30) - build_path = /obj/item/bodypart/l_leg/digitigrade - category = list(SPECIES_LIZARD) - -/datum/design/digi_rightleg - name = "Digitigrade Right Leg" - id = "digi_rightleg" - build_type = LIMBGROWER - reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 30) - build_path = /obj/item/bodypart/r_leg/digitigrade - category = list(SPECIES_LIZARD) + category = list("initial",SPECIES_HUMAN,SPECIES_LIZARD,SPECIES_MOTH,SPECIES_PLASMAMAN,SPECIES_ETHEREAL, "digitigrade") //Non-limb limb designs @@ -256,41 +240,41 @@ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL /obj/item/disk/design_disk/limbs/felinid - name = "Felinid Limb Design Disk" + name = "Felinid Organ Design Disk" limb_designs = list(/datum/design/cat_tail, /datum/design/cat_ears) /datum/design/limb_disk/felinid - name = "Felinid Limb Design Disk" - desc = "Contains designs for felinid bodyparts for the limbgrower - Felinid ears and tail." + name = "Felinid Organ Design Disk" + desc = "Contains designs for felinid organs for the limbgrower - Felinid ears and tail." id = "limbdesign_felinid" build_path = /obj/item/disk/design_disk/limbs/felinid /obj/item/disk/design_disk/limbs/lizard - name = "Lizard Limb Design Disk" - limb_designs = list(/datum/design/lizard_tail, /datum/design/lizard_tongue, /datum/design/digi_leftleg, /datum/design/digi_rightleg) + name = "Lizard Organ Design Disk" + limb_designs = list(/datum/design/lizard_tail, /datum/design/lizard_tongue) /datum/design/limb_disk/lizard - name = "Lizard Limb Design Disk" - desc = "Contains designs for lizard bodyparts for the limbgrower - Lizard tongue, tail, and digitigrade legs." + name = "Lizard Organ Design Disk" + desc = "Contains designs for lizard organs for the limbgrower - Lizard tongue, and tail" id = "limbdesign_lizard" build_path = /obj/item/disk/design_disk/limbs/lizard /obj/item/disk/design_disk/limbs/plasmaman - name = "Plasmaman Limb Design Disk" + name = "Plasmaman Organ Design Disk" limb_designs = list(/datum/design/plasmaman_stomach, /datum/design/plasmaman_liver, /datum/design/plasmaman_lungs, /datum/design/plasmaman_tongue) /datum/design/limb_disk/plasmaman - name = "Plasmaman Limb Design Disk" + name = "Plasmaman Organ Design Disk" desc = "Contains designs for plasmaman organs for the limbgrower - Plasmaman tongue, liver, stomach, and lungs." id = "limbdesign_plasmaman" build_path = /obj/item/disk/design_disk/limbs/plasmaman /obj/item/disk/design_disk/limbs/ethereal - name = "Ethereal Limb Design Disk" + name = "Ethereal Organ Design Disk" limb_designs = list(/datum/design/ethereal_stomach, /datum/design/ethereal_tongue, /datum/design/ethereal_lungs) /datum/design/limb_disk/ethereal - name = "Ethereal Limb Design Disk" + name = "Ethereal Organ Design Disk" desc = "Contains designs for ethereal organs for the limbgrower - Ethereal tongue and stomach." id = "limbdesign_ethereal" build_path = /obj/item/disk/design_disk/limbs/ethereal diff --git a/code/modules/spells/spell_types/shadow_walk.dm b/code/modules/spells/spell_types/shadow_walk.dm index 181dc23ff20..2146fcc45e4 100644 --- a/code/modules/spells/spell_types/shadow_walk.dm +++ b/code/modules/spells/spell_types/shadow_walk.dm @@ -63,7 +63,7 @@ if(!jaunter || jaunter.loc != src) qdel(src) if (light_amount < 0.2 && (!QDELETED(jaunter))) //heal in the dark - jaunter.heal_overall_damage((SHADOW_REGEN_RATE * delta_time), (SHADOW_REGEN_RATE * delta_time), 0, BODYPART_ORGANIC) + jaunter.heal_overall_damage((SHADOW_REGEN_RATE * delta_time), (SHADOW_REGEN_RATE * delta_time), 0, BODYTYPE_ORGANIC) check_light_level() diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 71f39a0b81d..a67eb69a581 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -5,17 +5,35 @@ throwforce = 3 w_class = WEIGHT_CLASS_SMALL icon = 'icons/mob/human_parts.dmi' - icon_state = "" + icon_state = "" //Leave this blank! Bodyparts are built using overlays /// The icon for Organic limbs using greyscale - var/icon_greyscale = DEFAULT_BODYPART_ICON_ORGANIC - /// The icon for Robotic limbs - var/icon_robotic = DEFAULT_BODYPART_ICON_ROBOTIC + VAR_PROTECTED/icon_greyscale = DEFAULT_BODYPART_ICON_ORGANIC + ///The icon for non-greyscale limbs + VAR_PROTECTED/icon_static = 'icons/mob/human_parts.dmi' + ///The icon for husked limbs + VAR_PROTECTED/icon_husk = 'icons/mob/human_parts.dmi' + ///The type of husk for building an iconstate + var/husk_type = "humanoid" layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor grind_results = list(/datum/reagent/bone_dust = 10, /datum/reagent/liquidgibs = 5) // robotic bodyparts and chests/heads cannot be ground var/mob/living/carbon/owner - var/datum/weakref/original_owner - var/status = BODYPART_ORGANIC - var/needs_processing = FALSE + + ///A bitfield of bodytypes for clothing, surgery, and misc information + var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC + ///Defines when a bodypart should not be changed. Example: BP_BLOCK_CHANGE_SPECIES prevents the limb from being overwritten on species gain + var/change_exempt_flags + + var/is_husked = FALSE + ///The ID of a species used to generate the icon. Needs to match the icon_state portion in the limbs file! + var/limb_id = SPECIES_HUMAN + //Defines what sprite the limb should use if it is also sexually dimorphic. + VAR_PROTECTED/limb_gender = "m" + ///Does this limb have a greyscale version? + var/uses_mutcolor = TRUE + ///Is there a sprite difference between male and female? + var/is_dimorphic = FALSE + ///The actual color a limb is drawn as, set by /proc/update_limb() + VAR_PROTECTED/draw_color /// BODY_ZONE_CHEST, BODY_ZONE_L_ARM, etc , used for def_zone var/body_zone @@ -23,8 +41,6 @@ var/aux_layer /// bitflag used to check which clothes cover this bodypart var/body_part - /// Used for alternate legs, useless elsewhere - var/use_digitigrade = NOT_DIGITIGRADE var/list/embedded_objects = list() /// are we a hand? if so, which one! var/held_index = 0 @@ -39,13 +55,19 @@ var/can_be_disabled = FALSE ///Multiplier of the limb's damage that gets applied to the mob var/body_damage_coeff = 1 + ///Multiplier of the limb's stamina damage that gets applied to the mob. Why is this 0.75 by default? Good question! var/stam_damage_coeff = 0.75 var/brutestate = 0 var/burnstate = 0 + ///The current amount of brute damage the limb has var/brute_dam = 0 + ///The current amount of burn damage the limb has var/burn_dam = 0 + ///The current amount of stamina damage the limb has var/stamina_dam = 0 + ///The maximum stamina damage a bodypart can take var/max_stamina_damage = 0 + ///The maximum "physical" damage a bodypart can take. Set by children var/max_damage = 0 ///Gradually increases while burning when at full damage, destroys the limb when at 100 var/cremation_progress = 0 @@ -53,20 +75,17 @@ var/brute_reduction = 0 ///Subtracted to burn damage taken var/burn_reduction = 0 + //Coloring and proper item icon update var/skin_tone = "" - var/body_gender = "" - var/species_id = "" - var/should_draw_gender = FALSE - var/should_draw_greyscale = FALSE var/species_color = "" + ///Limbs need this information as a back-up incase they are generated outside of a carbon (limbgrower) + var/should_draw_greyscale = TRUE + ///An "override" color that can be applied to ANY limb, greyscale or not. var/mutation_color = "" - var/no_update = 0 ///for nonhuman bodypart (e.g. monkey) var/animal_origin - //for all bodyparts - var/part_origin = HUMAN_BODY ///whether it can be dismembered with a weapon. var/dismemberable = 1 @@ -115,15 +134,17 @@ ///A list of all the external 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/external/external_organs = list() - /obj/item/bodypart/Initialize(mapload) . = ..() if(can_be_disabled) RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS), .proc/on_paralysis_trait_gain) RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS), .proc/on_paralysis_trait_loss) - if(status != BODYPART_ORGANIC) + if(!IS_ORGANIC_LIMB(src)) grind_results = null + name = "[limb_id] [parse_zone(body_zone)]" + update_icon_dropped() + /obj/item/bodypart/Destroy() if(owner) owner.remove_bodypart(src) @@ -135,8 +156,16 @@ wounds.Cut() return ..() +/obj/item/bodypart/forceMove(atom/destination) //Please. Never forcemove a limb if its's actually in use. This is only for borgs. + SHOULD_CALL_PARENT(TRUE) + + . = ..() + if(isturf(destination)) + update_icon_dropped() /obj/item/bodypart/examine(mob/user) + SHOULD_CALL_PARENT(TRUE) + . = ..() if(brute_dam > DAMAGE_PRECISION) . += span_warning("This limb has [brute_dam > 30 ? "severe" : "minor"] bruising.") @@ -153,10 +182,11 @@ . += span_warning("The flesh on this limb appears badly cooked.") /obj/item/bodypart/blob_act() - take_damage(max_damage) - + receive_damage(max_damage, wound_bonus = CANT_WOUND) /obj/item/bodypart/attack(mob/living/carbon/victim, mob/user) + SHOULD_CALL_PARENT(TRUE) + if(ishuman(victim)) var/mob/living/carbon/human/human_victim = victim if(HAS_TRAIT(victim, TRAIT_LIMBATTACHMENT)) @@ -175,6 +205,8 @@ ..() /obj/item/bodypart/attackby(obj/item/weapon, mob/user, params) + SHOULD_CALL_PARENT(TRUE) + if(weapon.get_sharpness()) add_fingerprint(user) if(!contents.len) @@ -189,16 +221,20 @@ return ..() /obj/item/bodypart/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + SHOULD_CALL_PARENT(TRUE) + ..() - if(status != BODYPART_ROBOTIC) + if(IS_ORGANIC_LIMB(src)) playsound(get_turf(src), 'sound/misc/splort.ogg', 50, TRUE, -1) pixel_x = rand(-3, 3) pixel_y = rand(-3, 3) //empties the bodypart from its organs and other things inside it /obj/item/bodypart/proc/drop_organs(mob/user, violent_removal) + SHOULD_CALL_PARENT(TRUE) + var/turf/bodypart_turf = get_turf(src) - if(status != BODYPART_ROBOTIC) + if(IS_ORGANIC_LIMB(src)) 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()) @@ -208,6 +244,9 @@ ///since organs aren't actually stored in the bodypart themselves while attached to a person, we have to query the owner for what we should have /obj/item/bodypart/proc/get_organs() + SHOULD_CALL_PARENT(TRUE) + RETURN_TYPE(/list) + if(!owner) return FALSE @@ -218,10 +257,11 @@ return bodypart_organs - //Return TRUE to get whatever mob this is in to update health. -/obj/item/bodypart/proc/on_life(delta_time, times_fired, stam_regen) - if(stamina_dam > DAMAGE_PRECISION && stam_regen) //DO NOT update health here, it'll be done in the carbon's life. +/obj/item/bodypart/proc/on_life(delta_time, times_fired) + SHOULD_CALL_PARENT(TRUE) + //DO NOT update health here, it'll be done in the carbon's life. + if(stamina_dam > DAMAGE_PRECISION && owner.stam_regen_start_time <= world.time) heal_damage(0, 0, INFINITY, null, FALSE) . |= BODYPART_LIFE_UPDATE_HEALTH @@ -229,13 +269,14 @@ //Damage will not exceed max_damage using this proc //Cannot apply negative damage /obj/item/bodypart/proc/receive_damage(brute = 0, burn = 0, stamina = 0, blocked = 0, updating_health = TRUE, required_status = null, wound_bonus = 0, bare_wound_bonus = 0, sharpness = NONE, attack_direction = null) + SHOULD_CALL_PARENT(TRUE) + var/hit_percent = (100-blocked)/100 if((!brute && !burn && !stamina) || hit_percent <= 0) return FALSE if(owner && (owner.status_flags & GODMODE)) - return FALSE //godmode - - if(required_status && (status != required_status)) + return FALSE //godmode + if(required_status && !(bodytype & required_status)) return FALSE var/dmg_multi = CONFIG_GET(number/damage_multiplier) * hit_percent @@ -341,178 +382,13 @@ . = TRUE return update_bodypart_damage_state() || . -/// Allows us to roll for and apply a wound without actually dealing damage. Used for aggregate wounding power with pellet clouds -/obj/item/bodypart/proc/painless_wound_roll(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus, sharpness=NONE) - if(!owner || phantom_wounding_dmg <= WOUND_MINIMUM_DAMAGE || wound_bonus == CANT_WOUND) - return - - var/mangled_state = get_mangled_state() - var/bio_state = owner.get_biological_state() - var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%) - - if(wounding_type == WOUND_BLUNT && sharpness) - if(sharpness & SHARP_EDGED) - wounding_type = WOUND_SLASH - else if (sharpness & SHARP_POINTY) - wounding_type = WOUND_PIERCE - - //Handling for bone only/flesh only(none right now)/flesh and bone targets - switch(bio_state) - // if we're bone only, all cutting attacks go straight to the bone - if(BIO_JUST_BONE) - if(wounding_type == WOUND_SLASH) - wounding_type = WOUND_BLUNT - phantom_wounding_dmg *= (easy_dismember ? 1 : 0.6) - else if(wounding_type == WOUND_PIERCE) - wounding_type = WOUND_BLUNT - phantom_wounding_dmg *= (easy_dismember ? 1 : 0.75) - if((mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)) - return - // note that there's no handling for BIO_JUST_FLESH since we don't have any that are that right now (slimepeople maybe someday) - // standard humanoids - if(BIO_FLESH_BONE) - // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate - // So a big sharp weapon is still all you need to destroy a limb - if(mangled_state == BODYPART_MANGLED_FLESH && sharpness) - playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100) - if(wounding_type == WOUND_SLASH && !easy_dismember) - phantom_wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area - if(wounding_type == WOUND_PIERCE && !easy_dismember) - phantom_wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated - wounding_type = WOUND_BLUNT - else if(mangled_state == BODYPART_MANGLED_BOTH && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)) - return - - check_wounding(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus) - -/** - * check_wounding() is where we handle rolling for, selecting, and applying a wound if we meet the criteria - * - * We generate a "score" for how woundable the attack was based on the damage and other factors discussed in [/obj/item/bodypart/proc/check_woundings_mods], then go down the list from most severe to least severe wounds in that category. - * We can promote a wound from a lesser to a higher severity this way, but we give up if we have a wound of the given type and fail to roll a higher severity, so no sidegrades/downgrades - * - * Arguments: - * * woundtype- Either WOUND_BLUNT, WOUND_SLASH, WOUND_PIERCE, or WOUND_BURN based on the attack type. - * * damage- How much damage is tied to this attack, since wounding potential scales with damage in an attack (see: WOUND_DAMAGE_EXPONENT) - * * wound_bonus- The wound_bonus of an attack - * * bare_wound_bonus- The bare_wound_bonus of an attack - */ -/obj/item/bodypart/proc/check_wounding(woundtype, damage, wound_bonus, bare_wound_bonus, attack_direction) - if(HAS_TRAIT(owner, TRAIT_NEVER_WOUNDED)) - return - - // note that these are fed into an exponent, so these are magnified - if(HAS_TRAIT(owner, TRAIT_EASILY_WOUNDED)) - damage *= 1.5 - else - damage = min(damage, WOUND_MAX_CONSIDERED_DAMAGE) - - if(HAS_TRAIT(owner,TRAIT_HARDLY_WOUNDED)) - damage *= 0.85 - - if(HAS_TRAIT(owner, TRAIT_EASYDISMEMBER)) - damage *= 1.1 - - var/base_roll = rand(1, round(damage ** WOUND_DAMAGE_EXPONENT)) - var/injury_roll = base_roll - injury_roll += check_woundings_mods(woundtype, damage, wound_bonus, bare_wound_bonus) - var/list/wounds_checking = GLOB.global_wound_types[woundtype] - - if(injury_roll > WOUND_DISMEMBER_OUTRIGHT_THRESH && prob(get_damage() / max_damage * 100)) - var/datum/wound/loss/dismembering = new - dismembering.apply_dismember(src, woundtype, outright = TRUE, attack_direction = attack_direction) - return - - // quick re-check to see if bare_wound_bonus applies, for the benefit of log_wound(), see about getting the check from check_woundings_mods() somehow - if(ishuman(owner)) - var/mob/living/carbon/human/human_wearer = owner - var/list/clothing = human_wearer.clothingonpart(src) - for(var/obj/item/clothing/clothes_check as anything in clothing) - // unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary - if(clothes_check.armor.getRating(WOUND)) - bare_wound_bonus = 0 - break - - //cycle through the wounds of the relevant category from the most severe down - for(var/datum/wound/possible_wound as anything in wounds_checking) - var/datum/wound/replaced_wound - for(var/datum/wound/existing_wound as anything in wounds) - if(existing_wound.type in wounds_checking) - if(existing_wound.severity >= initial(possible_wound.severity)) - return - else - replaced_wound = existing_wound - - if(initial(possible_wound.threshold_minimum) < injury_roll) - var/datum/wound/new_wound - if(replaced_wound) - new_wound = replaced_wound.replace_wound(possible_wound, attack_direction = attack_direction) - else - new_wound = new possible_wound - new_wound.apply_wound(src, attack_direction = attack_direction) - log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned - return new_wound - -// try forcing a specific wound, but only if there isn't already a wound of that severity or greater for that type on this bodypart -/obj/item/bodypart/proc/force_wound_upwards(specific_woundtype, smited = FALSE) - var/datum/wound/potential_wound = specific_woundtype - for(var/datum/wound/existing_wound as anything in wounds) - if(existing_wound.wound_type == initial(potential_wound.wound_type)) - if(existing_wound.severity < initial(potential_wound.severity)) // we only try if the existing one is inferior to the one we're trying to force - existing_wound.replace_wound(potential_wound, smited) - return - - var/datum/wound/new_wound = new potential_wound - new_wound.apply_wound(src, smited = smited) - -/** - * check_wounding_mods() is where we handle the various modifiers of a wound roll - * - * A short list of things we consider: any armor a human target may be wearing, and if they have no wound armor on the limb, if we have a bare_wound_bonus to apply, plus the plain wound_bonus - * We also flick through all of the wounds we currently have on this limb and add their threshold penalties, so that having lots of bad wounds makes you more liable to get hurt worse - * Lastly, we add the inherent wound_resistance variable the bodypart has (heads and chests are slightly harder to wound), and a small bonus if the limb is already disabled - * - * Arguments: - * * It's the same ones on [/obj/item/bodypart/proc/receive_damage] - */ -/obj/item/bodypart/proc/check_woundings_mods(wounding_type, damage, wound_bonus, bare_wound_bonus) - var/armor_ablation = 0 - var/injury_mod = 0 - - if(owner && ishuman(owner)) - var/mob/living/carbon/human/human_owner = owner - var/list/clothing = human_owner.clothingonpart(src) - for(var/obj/item/clothing/clothes as anything in clothing) - // unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary - armor_ablation += clothes.armor.getRating(WOUND) - if(wounding_type == WOUND_SLASH) - clothes.take_damage_zone(body_zone, damage, BRUTE) - else if(wounding_type == WOUND_BURN && damage >= 10) // lazy way to block freezing from shredding clothes without adding another var onto apply_damage() - clothes.take_damage_zone(body_zone, damage, BURN) - - if(!armor_ablation) - injury_mod += bare_wound_bonus - - injury_mod -= armor_ablation - injury_mod += wound_bonus - - for(var/datum/wound/wound as anything in wounds) - injury_mod += wound.threshold_penalty - - var/part_mod = -wound_resistance - if(get_damage(TRUE) >= max_damage) - part_mod += disabled_wound_penalty - - injury_mod += part_mod - - return injury_mod - //Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all. //Damage cannot go below zero. //Cannot remove negative damage (i.e. apply damage) /obj/item/bodypart/proc/heal_damage(brute, burn, stamina, required_status, updating_health = TRUE) + SHOULD_CALL_PARENT(TRUE) - if(required_status && status != required_status) //So we can only heal certain kinds of limbs, ie robotic vs organic. + if(required_status && !(bodytype & required_status)) //So we can only heal certain kinds of limbs, ie robotic vs organic. return if(brute) @@ -533,6 +409,8 @@ ///Proc to hook behavior associated to the change of the brute_dam variable's value. /obj/item/bodypart/proc/set_brute_dam(new_value) + PROTECTED_PROC(TRUE) + if(brute_dam == new_value) return . = brute_dam @@ -541,6 +419,8 @@ ///Proc to hook behavior associated to the change of the burn_dam variable's value. /obj/item/bodypart/proc/set_burn_dam(new_value) + PROTECTED_PROC(TRUE) + if(burn_dam == new_value) return . = burn_dam @@ -549,15 +429,12 @@ ///Proc to hook behavior associated to the change of the stamina_dam variable's value. /obj/item/bodypart/proc/set_stamina_dam(new_value) + PROTECTED_PROC(TRUE) + if(stamina_dam == new_value) return . = stamina_dam stamina_dam = new_value - if(stamina_dam > DAMAGE_PRECISION) - needs_processing = TRUE - else - needs_processing = FALSE - //Returns total damage. /obj/item/bodypart/proc/get_damage(include_stamina = FALSE) @@ -566,9 +443,10 @@ total = max(total, stamina_dam) return total - //Checks disabled status thresholds /obj/item/bodypart/proc/update_disabled() + SHOULD_CALL_PARENT(TRUE) + if(!owner) return @@ -609,6 +487,9 @@ ///Proc to change the value of the `disabled` variable and react to the event of its change. /obj/item/bodypart/proc/set_disabled(new_disabled) + SHOULD_CALL_PARENT(TRUE) + PROTECTED_PROC(TRUE) + if(bodypart_disabled == new_disabled) return . = bodypart_disabled @@ -622,6 +503,8 @@ ///Proc to change the value of the `owner` variable and react to the event of its change. /obj/item/bodypart/proc/set_owner(new_owner) + SHOULD_CALL_PARENT(TRUE) + if(owner == new_owner) return FALSE //`null` is a valid option, so we need to use a num var to make it clear no change was made. . = owner @@ -651,6 +534,9 @@ ///Proc to change the value of the `can_be_disabled` variable and react to the event of its change. /obj/item/bodypart/proc/set_can_be_disabled(new_can_be_disabled) + PROTECTED_PROC(TRUE) + SHOULD_CALL_PARENT(TRUE) + if(can_be_disabled == new_can_be_disabled) return . = can_be_disabled @@ -673,32 +559,42 @@ ///Called when TRAIT_PARALYSIS is added to the limb. /obj/item/bodypart/proc/on_paralysis_trait_gain(obj/item/bodypart/source) + PROTECTED_PROC(TRUE) SIGNAL_HANDLER + if(can_be_disabled) set_disabled(TRUE) ///Called when TRAIT_PARALYSIS is removed from the limb. /obj/item/bodypart/proc/on_paralysis_trait_loss(obj/item/bodypart/source) + PROTECTED_PROC(TRUE) SIGNAL_HANDLER + if(can_be_disabled) update_disabled() ///Called when TRAIT_NOLIMBDISABLE is added to the owner. /obj/item/bodypart/proc/on_owner_nolimbdisable_trait_gain(mob/living/carbon/source) + PROTECTED_PROC(TRUE) SIGNAL_HANDLER + set_can_be_disabled(FALSE) ///Called when TRAIT_NOLIMBDISABLE is removed from the owner. /obj/item/bodypart/proc/on_owner_nolimbdisable_trait_loss(mob/living/carbon/source) + PROTECTED_PROC(TRUE) SIGNAL_HANDLER + set_can_be_disabled(initial(can_be_disabled)) //Updates an organ's brute/burn states for use by update_damage_overlays() //Returns 1 if we need to update overlays. 0 otherwise. /obj/item/bodypart/proc/update_bodypart_damage_state() + SHOULD_CALL_PARENT(TRUE) + var/tbrute = round( (brute_dam/max_damage)*3, 1 ) var/tburn = round( (burn_dam/max_damage)*3, 1 ) if((tbrute != brutestate) || (tburn != burnstate)) @@ -707,124 +603,86 @@ return TRUE return FALSE -//Change organ status -/obj/item/bodypart/proc/change_bodypart_status(new_limb_status, heal_limb, change_icon_to_default) - status = new_limb_status - if(heal_limb) - burn_dam = 0 - brute_dam = 0 - brutestate = 0 - burnstate = 0 - - if(change_icon_to_default) - if(status == BODYPART_ORGANIC) - icon = icon_greyscale - else if(status == BODYPART_ROBOTIC) - icon = icon_robotic - - if(owner) - owner.updatehealth() - owner.update_body() //if our head becomes robotic, we remove the lizard horns and human hair. - owner.update_hair() - owner.update_damage_overlays() - -/obj/item/bodypart/proc/is_organic_limb() - return (status == BODYPART_ORGANIC) - //we inform the bodypart of the changes that happened to the owner, or give it the informations from a source mob. -/obj/item/bodypart/proc/update_limb(dropping_limb, mob/living/carbon/source) - var/mob/living/carbon/limb_owner - if(source) - limb_owner = source - if(!original_owner) - original_owner = WEAKREF(source) - else - limb_owner = owner - if(original_owner && !IS_WEAKREF_OF(owner, original_owner)) //Foreign limb - no_update = TRUE - else - no_update = FALSE +//set is_creating to true if you want to change the appearance of the limb outside of mutation changes or forced changes. +/obj/item/bodypart/proc/update_limb(dropping_limb = FALSE, is_creating = FALSE) + SHOULD_CALL_PARENT(TRUE) - if(HAS_TRAIT(limb_owner, TRAIT_HUSK) && is_organic_limb()) - species_id = "husk" //overrides species_id + if(HAS_TRAIT(owner, TRAIT_HUSK) && IS_ORGANIC_LIMB(src)) dmg_overlay_type = "" //no damage overlay shown when husked - should_draw_gender = FALSE - should_draw_greyscale = FALSE - no_update = TRUE + is_husked = TRUE + else + dmg_overlay_type = initial(dmg_overlay_type) + is_husked = FALSE - if(HAS_TRAIT(src, TRAIT_PLASMABURNT) && is_organic_limb()) - species_id = SPECIES_PLASMAMAN - dmg_overlay_type = "" - should_draw_gender = FALSE - should_draw_greyscale = FALSE - no_update = TRUE + if(!dropping_limb && owner.dna?.check_mutation(/datum/mutation/human/hulk)) //Please remove hulk from the game. I beg you. + mutation_color = "#00aa00" + else + mutation_color = null - if(HAS_TRAIT(limb_owner, TRAIT_INVISIBLE_MAN) && is_organic_limb()) - species_id = "invisible" //overrides species_id - dmg_overlay_type = "" //no damage overlay shown when invisible since the wounds themselves are invisible. - should_draw_gender = FALSE - should_draw_greyscale = FALSE - no_update = TRUE + if(mutation_color) + draw_color = mutation_color + else if(should_draw_greyscale) + draw_color = (species_color) || (skin_tone && skintone2hex(skin_tone)) + else + draw_color = null - if(no_update) + if(!is_creating) return - if(!animal_origin) - var/mob/living/carbon/human/human_owner = limb_owner - should_draw_greyscale = FALSE + if(!animal_origin && ishuman(owner)) + var/mob/living/carbon/human/human_owner = owner var/datum/species/owner_species = human_owner.dna.species - species_id = owner_species.limbs_id species_flags_list = human_owner.dna.species.species_traits + limb_gender = (human_owner.physique == MALE) ? "m" : "f" if(owner_species.use_skintones) skin_tone = human_owner.skin_tone - should_draw_greyscale = TRUE else skin_tone = "" - body_gender = human_owner.body_type - should_draw_gender = owner_species.sexes - - if((MUTCOLORS in owner_species.species_traits) || (DYNCOLORS in owner_species.species_traits)) + if(((MUTCOLORS in owner_species.species_traits) || (DYNCOLORS in owner_species.species_traits)) && uses_mutcolor) //Ethereal code. Motherfuckers. if(owner_species.fixed_mut_color) species_color = owner_species.fixed_mut_color else species_color = human_owner.dna.features["mcolor"] - should_draw_greyscale = TRUE else - species_color = "" + species_color = null - if(!dropping_limb && human_owner.dna.check_mutation(/datum/mutation/human/hulk)) - mutation_color = "#00aa00" - else - mutation_color = "" + draw_color = mutation_color + if(should_draw_greyscale) //Should the limb be colored? + draw_color ||= (species_color) || (skin_tone && skintone2hex(skin_tone)) dmg_overlay_type = owner_species.damage_overlay_type else if(animal_origin == MONKEY_BODYPART) //currently monkeys are the only non human mob to have damage overlays. dmg_overlay_type = animal_origin - if(status == BODYPART_ROBOTIC) + if(!IS_ORGANIC_LIMB(src)) dmg_overlay_type = "robotic" - if(dropping_limb) - no_update = TRUE //when attached, the limb won't be affected by the appearance changes of its mob owner. + return TRUE //to update the bodypart's icon when not attached to a mob /obj/item/bodypart/proc/update_icon_dropped() + SHOULD_CALL_PARENT(TRUE) + cut_overlays() var/list/standing = get_limb_icon(TRUE) if(!standing.len) icon_state = initial(icon_state)//no overlays found, we default back to initial icon. return - for(var/image/img in standing) + for(var/image/img as anything in standing) img.pixel_x = px_x img.pixel_y = px_y add_overlay(standing) -//Gives you a proper icon appearance for the dismembered limb -/obj/item/bodypart/proc/get_limb_icon(dropped, draw_external_organs) +///Generates an /image for the limb to be used as an overlay +/obj/item/bodypart/proc/get_limb_icon(dropped) + SHOULD_CALL_PARENT(TRUE) + RETURN_TYPE(/list) + icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone. . = list() @@ -843,9 +701,9 @@ . += limb if(animal_origin) - if(is_organic_limb()) + if(IS_ORGANIC_LIMB(src)) limb.icon = 'icons/mob/animal_parts.dmi' - if(species_id == "husk") + if(limb_id == "husk") limb.icon_state = "[animal_origin]_husk_[body_zone]" else limb.icon_state = "[animal_origin]_[body_zone]" @@ -859,71 +717,43 @@ limb.overlays += limb_em_block return - var/icon_gender = (body_gender == FEMALE) ? "f" : "m" //gender of the icon, if applicable - - if((body_zone != BODY_ZONE_HEAD && body_zone != BODY_ZONE_CHEST)) - should_draw_gender = FALSE - - var/draw_color - - if(!is_organic_limb()) - limb.icon = icon - limb.icon_state = "[body_zone]" //Inorganic limbs are agender - - if(blocks_emissive) - var/mutable_appearance/limb_em_block = emissive_blocker(limb.icon, limb.icon_state, alpha = limb.alpha) - limb_em_block.dir = image_dir - limb.overlays += limb_em_block - - if(aux_zone) - aux = image(limb.icon, "[aux_zone]", -aux_layer, image_dir) - . += aux - - if(blocks_emissive) - var/mutable_appearance/aux_em_block = emissive_blocker(aux.icon, aux.icon_state, alpha = aux.alpha) - aux_em_block.dir = image_dir - aux.overlays += aux_em_block + ////This is the MEAT of limb icon code + limb.icon = icon_greyscale + if(!should_draw_greyscale || !icon_greyscale) + limb.icon = icon_static + if(is_dimorphic) //Does this type of limb have sexual dimorphism? + limb.icon_state = "[limb_id]_[body_zone]_[limb_gender]" else - if(should_draw_greyscale) - limb.icon = icon_greyscale - if(should_draw_gender) - limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" - else if(use_digitigrade) - limb.icon_state = "digitigrade_[use_digitigrade]_[body_zone]" - else - limb.icon_state = "[species_id]_[body_zone]" - else - limb.icon = 'icons/mob/human_parts.dmi' - if(should_draw_gender) - limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" - else - limb.icon_state = "[species_id]_[body_zone]" + limb.icon_state = "[limb_id]_[body_zone]" + + icon_exists(limb.icon, limb.icon_state, TRUE) //Prints a stack trace on the first failure of a given iconstate. + + if(aux_zone) //Hand shit + aux = image(limb.icon, "[limb_id]_[aux_zone]", -aux_layer, image_dir) + . += aux + + draw_color = mutation_color + if(should_draw_greyscale) //Should the limb be colored outside of a forced color? + draw_color ||= (species_color) || (skin_tone && skintone2hex(skin_tone)) + + if(draw_color) + limb.color = "[draw_color]" + if(aux_zone) + aux.color = "[draw_color]" + + //EMISSIVE CODE START + if(blocks_emissive) + var/mutable_appearance/limb_em_block = emissive_blocker(limb.icon, limb.icon_state, alpha = limb.alpha) + limb_em_block.dir = image_dir + limb.overlays += limb_em_block if(aux_zone) - aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir) - . += aux - - if(should_draw_greyscale) - draw_color = mutation_color || species_color || (skin_tone && skintone2hex(skin_tone)) - if(draw_color) - limb.color = draw_color - if(aux_zone) - aux.color = draw_color - - if(blocks_emissive) - var/mutable_appearance/limb_em_block = emissive_blocker(limb.icon, limb.icon_state, alpha = limb.alpha) - limb_em_block.dir = image_dir - limb.overlays += limb_em_block - - if(aux_zone) - var/mutable_appearance/aux_em_block = emissive_blocker(aux.icon, aux.icon_state, alpha = aux.alpha) - aux_em_block.dir = image_dir - aux.overlays += aux_em_block - - if(!draw_external_organs) - return + var/mutable_appearance/aux_em_block = emissive_blocker(aux.icon, aux.icon_state, alpha = aux.alpha) + aux_em_block.dir = image_dir + aux.overlays += aux_em_block + //EMISSIVE CODE END //Draw external organs like horns and frills for(var/obj/item/organ/external/external_organ in external_organs) if(!dropped && !external_organ.can_draw_on_bodypart(owner)) @@ -935,41 +765,13 @@ // Invert the colour of the pod hair's flower draw_color = rgb(255 - rgb_list[1], 255 - rgb_list[2], 255 - rgb_list[3]) if(external_organ.layers & external_layer) - external_organ.get_overlays(., image_dir, external_organ.bitflag_to_layer(external_layer), icon_gender, draw_color) + external_organ.get_overlays(., image_dir, external_organ.bitflag_to_layer(external_layer), limb_gender, draw_color) /obj/item/bodypart/deconstruct(disassembled = TRUE) + SHOULD_CALL_PARENT(TRUE) + drop_organs() - qdel(src) - -/// Get whatever wound of the given type is currently attached to this limb, if any -/obj/item/bodypart/proc/get_wound_type(checking_type) - if(isnull(wounds)) - return - - for(var/wound in wounds) - if(istype(wound, checking_type)) - return wound - -/** - * update_wounds() is called whenever a wound is gained or lost on this bodypart, as well as if there's a change of some kind on a bone wound possibly changing disabled status - * - * Covers tabulating the damage multipliers we have from wounds (burn specifically), as well as deleting our gauze wrapping if we don't have any wounds that can use bandaging - * - * Arguments: - * * replaced- If true, this is being called from the remove_wound() of a wound that's being replaced, so the bandage that already existed is still relevant, but the new wound hasn't been added yet - */ -/obj/item/bodypart/proc/update_wounds(replaced = FALSE) - var/dam_mul = 1 //initial(wound_damage_multiplier) - - // we can (normally) only have one wound per type, but remember there's multiple types (smites like :B:loodless can generate multiple cuts on a limb) - for(var/datum/wound/iter_wound as anything in wounds) - dam_mul *= iter_wound.damage_mulitplier_penalty - - if(!LAZYLEN(wounds) && current_gauze && !replaced) // no more wounds = no need for the gauze anymore - owner.visible_message(span_notice("\The [current_gauze.name] on [owner]'s [name] falls away."), span_notice("The [current_gauze.name] on your [name] falls away.")) - QDEL_NULL(current_gauze) - - wound_damage_multiplier = dam_mul + return ..() /** * Calculates how much blood this limb is losing per life tick @@ -978,9 +780,11 @@ * * ignore_modifiers - If TRUE, ignore the bleed reduction for laying down and grabbing your limb */ /obj/item/bodypart/proc/get_part_bleed_rate(ignore_modifiers = FALSE) + SHOULD_NOT_OVERRIDE(TRUE) + if(HAS_TRAIT(owner, TRAIT_NOBLEED)) return - if(status != BODYPART_ORGANIC) // maybe in the future we can bleed oil from aug parts, but not now + if(!IS_ORGANIC_LIMB(src))// maybe in the future we can bleed oil from aug parts, but not now return var/bleed_rate = 0 @@ -1015,7 +819,7 @@ /obj/item/bodypart/proc/update_part_wound_overlay() if(!owner) return FALSE - if(HAS_TRAIT(owner, TRAIT_NOBLEED) || status != BODYPART_ORGANIC) + if(HAS_TRAIT(owner, TRAIT_NOBLEED) || !IS_ORGANIC_LIMB(src) || (NOBLOOD in species_flags_list)) if(bleed_overlay_icon) bleed_overlay_icon = null owner.update_wound_overlays() @@ -1091,8 +895,8 @@ ///Proc to turn bodypart into another. /obj/item/bodypart/proc/change_bodypart(obj/item/bodypart/new_type) + RETURN_TYPE(/obj/item/bodypart) + var/mob/living/carbon/our_owner = owner //dropping nulls the limb - drop_limb(TRUE) var/obj/item/bodypart/new_part = new new_type() - new_part.attach_limb(our_owner, TRUE) - qdel(src) + new_part.replace_limb(our_owner, TRUE) diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 0b18f8de895..4671c9b8d22 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -129,6 +129,7 @@ organ.transfer_to_limb(src, phantom_owner) update_icon_dropped() + synchronize_bodytypes(phantom_owner) phantom_owner.update_health_hud() //update the healthdoll phantom_owner.update_body() phantom_owner.update_hair() @@ -292,11 +293,6 @@ if(pill) pill.forceMove(src) - //Make sure de-zombification happens before organ removal instead of during it - var/obj/item/organ/zombie_infection/ooze = owner.getorganslot(ORGAN_SLOT_ZOMBIE) - if(istype(ooze)) - ooze.transfer_to_limb(src, owner) - name = "[owner.real_name]'s head" ..() @@ -304,11 +300,13 @@ /obj/item/bodypart/proc/replace_limb(mob/living/carbon/limb_owner, special) if(!istype(limb_owner)) return - var/obj/item/bodypart/limb = limb_owner.get_bodypart(body_zone) //needs to happen before attach because multiple limbs in same zone breaks helpers - if(!attach_limb(limb_owner, special))//we can attach this limb and drop the old after because of our robust bodyparts system. you know, just for a sec. - return - if(limb) - limb.drop_limb(1) + var/obj/item/bodypart/old_limb = limb_owner.get_bodypart(body_zone) + if(old_limb) + old_limb.drop_limb(TRUE) + + . = attach_limb(limb_owner, special) + if(!.) //If it failed to replace, re-attach their old limb as if nothing happened. + old_limb.attach_limb(limb_owner, TRUE) /obj/item/bodypart/head/replace_limb(mob/living/carbon/head_owner, special) if(!istype(head_owner)) @@ -322,7 +320,11 @@ /obj/item/bodypart/proc/attach_limb(mob/living/carbon/new_limb_owner, special) if(SEND_SIGNAL(new_limb_owner, COMSIG_CARBON_ATTACH_LIMB, src, special) & COMPONENT_NO_ATTACH) return FALSE - . = TRUE + + var/obj/item/bodypart/chest/mob_chest = new_limb_owner.get_bodypart(BODY_ZONE_CHEST) + if(mob_chest && !(mob_chest.acceptable_bodytype & bodytype) && !special) + return FALSE + moveToNullspace() set_owner(new_limb_owner) new_limb_owner.add_bodypart(src) @@ -365,20 +367,14 @@ if(can_be_disabled) update_disabled() + synchronize_bodytypes(new_limb_owner) new_limb_owner.updatehealth() new_limb_owner.update_body() - new_limb_owner.update_hair() new_limb_owner.update_damage_overlays() - + return TRUE /obj/item/bodypart/head/attach_limb(mob/living/carbon/new_head_owner, special = FALSE, abort = FALSE) // These are stored before calling super. This is so that if the head is from a different body, it persists its appearance. - var/hair_color = src.hair_color - var/hairstyle = src.hairstyle - var/facial_hair_color = src.facial_hair_color - var/facial_hairstyle = src.facial_hairstyle - var/lip_style = src.lip_style - var/lip_color = src.lip_color var/real_name = src.real_name . = ..() @@ -401,17 +397,9 @@ if(eyes) eyes = null - if(ishuman(new_head_owner)) - var/mob/living/carbon/human/human_head_owner = new_head_owner - human_head_owner.hair_color = hair_color - human_head_owner.hairstyle = hairstyle - human_head_owner.facial_hair_color = facial_hair_color - human_head_owner.facial_hairstyle = facial_hairstyle - human_head_owner.update_lips(lip_style, lip_color, stored_lipstick_trait) if(real_name) new_head_owner.real_name = real_name real_name = "" - name = initial(name) //Handle dental implants for(var/obj/item/reagent_containers/pill/pill in src) @@ -422,41 +410,57 @@ new_head_owner.updatehealth() new_head_owner.update_body() - new_head_owner.update_hair() new_head_owner.update_damage_overlays() +///Makes sure that the owner's bodytype flags match the flags of all of it's parts. +/obj/item/bodypart/proc/synchronize_bodytypes(mob/living/carbon/carbon_owner) + if(!carbon_owner.dna.species) + return + var/all_limb_flags + for(var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts) + all_limb_flags = all_limb_flags | limb.bodytype + + carbon_owner.dna.species.bodytype = all_limb_flags //Regenerates all limbs. Returns amount of limbs regenerated -/mob/living/proc/regenerate_limbs(noheal = FALSE, list/excluded_zones = list()) - SEND_SIGNAL(src, COMSIG_LIVING_REGENERATE_LIMBS, noheal, excluded_zones) +/mob/living/proc/regenerate_limbs(list/excluded_zones = list()) + SEND_SIGNAL(src, COMSIG_LIVING_REGENERATE_LIMBS, excluded_zones) -/mob/living/carbon/regenerate_limbs(noheal = FALSE, list/excluded_zones = list()) - . = ..() +/mob/living/carbon/regenerate_limbs(list/excluded_zones = list()) + SEND_SIGNAL(src, COMSIG_LIVING_REGENERATE_LIMBS, excluded_zones) var/list/zone_list = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) if(length(excluded_zones)) zone_list -= excluded_zones for(var/limb_zone in zone_list) - . += regenerate_limb(limb_zone, noheal) + regenerate_limb(limb_zone) -/mob/living/proc/regenerate_limb(limb_zone, noheal) +/mob/living/proc/regenerate_limb(limb_zone) return -/mob/living/carbon/regenerate_limb(limb_zone, noheal) +/mob/living/carbon/regenerate_limb(limb_zone) var/obj/item/bodypart/limb if(get_bodypart(limb_zone)) return FALSE limb = newBodyPart(limb_zone, 0, 0) if(limb) - if(!noheal) - limb.set_brute_dam(0) - limb.set_burn_dam(0) - limb.brutestate = 0 - limb.burnstate = 0 - if(!limb.attach_limb(src, 1)) qdel(limb) return FALSE + limb.update_limb(is_creating = TRUE) var/datum/scar/scaries = new var/datum/wound/loss/phantom_loss = new // stolen valor, really scaries.generate(limb, phantom_loss) + + //Copied from /datum/species/proc/on_species_gain() + for(var/obj/item/organ/external/organ_path as anything in dna.species.external_organs) + //Load a persons preferences from DNA + var/zone = initial(organ_path.zone) + if(zone != limb_zone) + continue + var/feature_key_name = dna.features[initial(organ_path.feature_key)] + var/obj/item/organ/external/new_organ = SSwardrobe.provide_type(organ_path) + new_organ.set_sprite(feature_key_name) + new_organ.Insert(src) + + update_body_parts() return TRUE diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 24ea1fd7f40..b2f5dfd7018 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -17,6 +17,7 @@ disabled_wound_penalty = 25 scars_covered_by_clothes = FALSE grind_results = null + is_dimorphic = TRUE var/mob/living/brain/brainmob //The current occupant. var/obj/item/organ/brain/brain //The brain organ @@ -29,19 +30,47 @@ //Limb appearance info: var/real_name = "" //Replacement name - //Hair colour and style + ///Hair color source + var/hair_color_source = null + ///Hair colour and style var/hair_color = "#000000" - var/hairstyle = "Bald" + ///An override color that can be cleared later. + var/override_hair_color = null + ///An override that cannot be cleared under any circumstances + var/fixed_hair_color = null + + var/hair_style = "Bald" var/hair_alpha = 255 + var/hair_gradient_style = null + var/hair_gradient_color = null //Facial hair colour and style var/facial_hair_color = "#000000" var/facial_hairstyle = "Shaved" - //Eye Colouring + var/facial_hair_gradient_style = null + var/facial_hair_gradient_color = null + ///Is the hair currently hidden by something? + var/hair_hidden + ///Is the facial hair currently hidden by something? + var/facial_hair_hidden + ///Draw this head as "debrained" + VAR_PROTECTED/show_debrained = FALSE + + var/lip_style var/lip_color = "white" var/stored_lipstick_trait + ///The image for hair + var/mutable_appearance/hair_overlay + ///The image for hair gradient + var/mutable_appearance/hair_gradient_overlay + ///The image for face hair + var/mutable_appearance/facial_overlay + ///The image for facial hair gradient + var/mutable_appearance/facial_gradient_overlay + + /obj/item/bodypart/head/Destroy() @@ -72,7 +101,7 @@ /obj/item/bodypart/head/examine(mob/user) . = ..() - if(status == BODYPART_ORGANIC && show_organs_on_examine) + if(IS_ORGANIC_LIMB(src) && show_organs_on_examine) if(!brain) . += span_info("The brain has been removed from [src].") else if(brain.suicided || brainmob?.suiciding) @@ -106,8 +135,6 @@ /obj/item/bodypart/head/drop_organs(mob/user, violent_removal) var/turf/head_turf = get_turf(src) - if(status != BODYPART_ROBOTIC) - playsound(head_turf, 'sound/misc/splort.ogg', 50, TRUE, -1) for(var/obj/item/head_item in src) if(head_item == brain) if(user) @@ -136,86 +163,139 @@ ears = null tongue = null -/obj/item/bodypart/head/update_limb(dropping_limb, mob/living/carbon/source) - var/mob/living/carbon/head_owner - if(source) - head_owner = source - else - head_owner = owner + return ..() - real_name = head_owner.real_name - if(HAS_TRAIT(head_owner, TRAIT_HUSK)) +#define SET_OVERLAY_VALUE(X,Y,Z) if(X) X.Y = Z +/obj/item/bodypart/head/update_limb(dropping_limb, is_creating) + . = ..() + + real_name = owner.real_name + if(HAS_TRAIT(owner, TRAIT_HUSK)) real_name = "Unknown" - hairstyle = "Bald" + hair_style = "Bald" facial_hairstyle = "Shaved" lip_style = null stored_lipstick_trait = null - else if(!animal_origin) - var/mob/living/carbon/human/human_head_owner = head_owner + else if(!animal_origin && ishuman(owner)) + + var/mob/living/carbon/human/human_head_owner = owner var/datum/species/owner_species = human_head_owner.dna.species - //Facial hair - if(human_head_owner.facial_hairstyle && (FACEHAIR in owner_species.species_traits)) - facial_hairstyle = human_head_owner.facial_hairstyle - if(owner_species.hair_color) - if(owner_species.hair_color == "mutcolor") - facial_hair_color = human_head_owner.dna.features["mcolor"] - else if(hair_color == "fixedmutcolor") - facial_hair_color = owner_species.fixed_mut_color - else - facial_hair_color = owner_species.hair_color - else - facial_hair_color = human_head_owner.facial_hair_color - hair_alpha = owner_species.hair_alpha - else - facial_hairstyle = "Shaved" - facial_hair_color = "#000000" - hair_alpha = 255 - //Hair - if(human_head_owner.hairstyle && (HAIR in owner_species.species_traits)) - hairstyle = human_head_owner.hairstyle - if(owner_species.hair_color) - if(owner_species.hair_color == "mutcolor") - hair_color = human_head_owner.dna.features["mcolor"] - else if(hair_color == "fixedmutcolor") - hair_color = owner_species.fixed_mut_color - else - hair_color = owner_species.hair_color - else - hair_color = human_head_owner.hair_color - hair_alpha = owner_species.hair_alpha - else - hairstyle = "Bald" - hair_color = "#000000" - hair_alpha = initial(hair_alpha) - // lipstick if(human_head_owner.lip_style && (LIPS in owner_species.species_traits)) lip_style = human_head_owner.lip_style lip_color = human_head_owner.lip_color else lip_style = null lip_color = "white" - ..() -/obj/item/bodypart/head/update_icon_dropped() - var/list/standing = get_limb_icon(TRUE) - if(!standing.len) - icon_state = initial(icon_state)//no overlays found, we default back to initial icon. - return - for(var/image/img in standing) - img.pixel_x = px_x - img.pixel_y = px_y - add_overlay(standing) + ///FACIAL HAIR CHECKS START + //we check if our hat or helmet hides our facial hair. + facial_hair_hidden = FALSE + if(human_head_owner.head) + var/obj/item/hat = human_head_owner.head + if(hat.flags_inv & HIDEFACIALHAIR) + facial_hair_hidden = TRUE + + if(human_head_owner.wear_mask) + var/obj/item/mask = human_head_owner.wear_mask + if(mask.flags_inv & HIDEFACIALHAIR) + facial_hair_hidden = TRUE + ///FACIAL HAIR CHECKS END + ///HAIR CHECKS START + hair_hidden = FALSE + if(human_head_owner.head) + var/obj/item/hat = human_head_owner.head + if(hat.flags_inv & HIDEHAIR) + hair_hidden = TRUE + + if(human_head_owner.w_uniform) + var/obj/item/item_uniform = human_head_owner.w_uniform + if(item_uniform.flags_inv & HIDEHAIR) + hair_hidden = TRUE + + if(human_head_owner.wear_mask) + var/obj/item/mask = human_head_owner.wear_mask + if(mask.flags_inv & HIDEHAIR) + hair_hidden = TRUE + ///HAIR CHECKS END + + if(!hair_hidden && !owner.getorgan(/obj/item/organ/brain) && !(NOBLOOD in species_flags_list)) + show_debrained = TRUE + else + show_debrained = FALSE + + //CREATION-ONLY START + if(is_creating) + var/datum/sprite_accessory/sprite_accessory + + facial_overlay = null + facial_gradient_overlay = null + hair_overlay = null + hair_gradient_overlay = null + + hair_alpha = owner_species.hair_alpha + hair_color = human_head_owner.hair_color + facial_hair_color = human_head_owner.hair_color + fixed_hair_color = owner_species.fixed_mut_color //Can be null + hair_style = human_head_owner.hairstyle + facial_hairstyle = human_head_owner.facial_hairstyle + + + if(facial_hairstyle && !facial_hair_hidden && (FACEHAIR in species_flags_list)) + sprite_accessory = GLOB.facial_hairstyles_list[facial_hairstyle] + if(sprite_accessory) + //Create the overlay + facial_overlay = mutable_appearance(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER) + //Gradients + facial_hair_gradient_style = LAZYACCESS(human_head_owner.grad_style, GRADIENT_FACIAL_HAIR_KEY) + if(facial_hair_gradient_style) + facial_hair_gradient_color = LAZYACCESS(human_head_owner.grad_color, GRADIENT_FACIAL_HAIR_KEY) + facial_gradient_overlay = make_gradient_overlay(sprite_accessory.icon, sprite_accessory.icon_state, HAIR_LAYER, GLOB.facial_hair_gradients_list[facial_hair_gradient_style], facial_hair_gradient_color) + + facial_overlay.overlays += emissive_blocker(sprite_accessory.icon, sprite_accessory.icon_state, alpha = hair_alpha) + + if(!hair_hidden && !show_debrained && (HAIR in species_flags_list)) + sprite_accessory = GLOB.hairstyles_list[hair_style] + if(sprite_accessory) + hair_overlay = mutable_appearance(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER) + hair_gradient_style = LAZYACCESS(human_head_owner.grad_style, GRADIENT_HAIR_KEY) + if(hair_gradient_style) + hair_gradient_color = LAZYACCESS(human_head_owner.grad_color, GRADIENT_HAIR_KEY) + hair_gradient_overlay = make_gradient_overlay(sprite_accessory.icon, sprite_accessory.icon_state, HAIR_LAYER, GLOB.hair_gradients_list[hair_gradient_style], hair_gradient_color) + + //CREATION-ONLY END + //HAIR COLOR START + if(!override_hair_color) + if(hair_color_source) + if(hair_color_source == "fixedmutcolor") + SET_OVERLAY_VALUE(facial_overlay, color, fixed_hair_color) + SET_OVERLAY_VALUE(hair_overlay, color, fixed_hair_color) + else if(hair_color_source == "mutcolor") + SET_OVERLAY_VALUE(facial_overlay, color, facial_hair_color) + SET_OVERLAY_VALUE(hair_overlay, color, hair_color) + else + SET_OVERLAY_VALUE(facial_overlay, color, hair_color_source) + SET_OVERLAY_VALUE(hair_overlay, color, hair_color_source) + else + SET_OVERLAY_VALUE(facial_overlay, color, hair_color) + SET_OVERLAY_VALUE(hair_overlay, color, hair_color) + else + SET_OVERLAY_VALUE(facial_overlay, color, override_hair_color) + SET_OVERLAY_VALUE(hair_overlay, color, override_hair_color) + //HAIR COLOR END + +#undef SET_OVERLAY_VALUE +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// /obj/item/bodypart/head/get_limb_icon(dropped, draw_external_organs) cut_overlays() . = ..() if(dropped) //certain overlays only appear when the limb is being detached from its owner. - if(status != BODYPART_ROBOTIC) //having a robotic head hides certain features. + if(IS_ORGANIC_LIMB(src)) //having a robotic head hides certain features. //facial hair - if(facial_hairstyle) + if(facial_hairstyle && (FACEHAIR in species_flags_list)) var/datum/sprite_accessory/sprite = GLOB.facial_hairstyles_list[facial_hairstyle] if(sprite) var/image/facial_overlay = image(sprite.icon, "[sprite.icon_state]", -HAIR_LAYER, SOUTH) @@ -237,8 +317,8 @@ debrain_overlay.icon_state = "debrained" . += debrain_overlay else - var/datum/sprite_accessory/sprite2 = GLOB.hairstyles_list[hairstyle] - if(sprite2) + var/datum/sprite_accessory/sprite2 = GLOB.hairstyles_list[hair_style] + if(sprite2 && (HAIR in species_flags_list)) var/image/hair_overlay = image(sprite2.icon, "[sprite2.icon_state]", -HAIR_LAYER, SOUTH) hair_overlay.color = hair_color hair_overlay.alpha = hair_alpha @@ -260,6 +340,47 @@ if(eyes.eye_color) eyes_overlay.color = eyes.eye_color + else + if(!facial_hair_hidden && facial_overlay && (FACEHAIR in species_flags_list)) + facial_overlay.alpha = hair_alpha + . += facial_overlay + if(facial_gradient_overlay) + . += facial_gradient_overlay + + if(show_debrained) + . += mutable_appearance('icons/mob/human_face.dmi', "debrained", HAIR_LAYER) + + else if(!hair_hidden && hair_overlay && (HAIR in species_flags_list)) + hair_overlay.alpha = hair_alpha + . += hair_overlay + if(hair_gradient_overlay) + . += hair_gradient_overlay +///Set the haircolor of a human. Override instead sets the override value, it will not be changed away from the override value until override is set to null. +/mob/proc/set_haircolor(hex_string, override) + return + +/mob/living/carbon/human/set_haircolor(hex_string, override) + var/obj/item/bodypart/head/my_head = get_bodypart(BODY_ZONE_HEAD) + if(!my_head) + return + + if(override) + my_head.override_hair_color = hex_string + else + my_head.hair_color = hex_string + update_hair(is_creating = TRUE) + +/obj/item/bodypart/head/proc/make_gradient_overlay(file, icon, layer, datum/sprite_accessory/gradient, grad_color) + RETURN_TYPE(/mutable_appearance) + + var/mutable_appearance/gradient_overlay = mutable_appearance(layer = -layer) + var/icon/temp = icon(gradient.icon, gradient.icon_state) + var/icon/temp_hair = icon(file, icon) + temp.Blend(temp_hair, ICON_ADD) + gradient_overlay.icon = temp + gradient_overlay.color = grad_color + return gradient_overlay + /obj/item/bodypart/head/talk_into(mob/holder, message, channel, spans, datum/language/language, list/message_mods) var/mob/headholder = holder if(istype(headholder)) @@ -274,7 +395,9 @@ /obj/item/bodypart/head/monkey icon = 'icons/mob/animal_parts.dmi' icon_state = "default_monkey_head" + limb_id = SPECIES_MONKEY animal_origin = MONKEY_BODYPART + bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC /obj/item/bodypart/head/alien icon = 'icons/mob/animal_parts.dmi' diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 858fdd2d3c8..60be92d76d0 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -121,52 +121,23 @@ return TRUE //Helper for quickly creating a new limb - used by augment code in species.dm spec_attacked_by -/mob/living/carbon/proc/newBodyPart(zone, robotic, fixed_icon) - var/obj/item/bodypart/new_bodypart - switch(zone) - if(BODY_ZONE_L_ARM) - new_bodypart = new /obj/item/bodypart/l_arm() - if(BODY_ZONE_R_ARM) - new_bodypart = new /obj/item/bodypart/r_arm() - if(BODY_ZONE_HEAD) - new_bodypart = new /obj/item/bodypart/head() - if(BODY_ZONE_L_LEG) - new_bodypart = new /obj/item/bodypart/l_leg() - if(BODY_ZONE_R_LEG) - new_bodypart = new /obj/item/bodypart/r_leg() - if(BODY_ZONE_CHEST) - new_bodypart = new /obj/item/bodypart/chest() - if(new_bodypart) - new_bodypart.update_limb(fixed_icon, src) - if(robotic) - new_bodypart.change_bodypart_status(BODYPART_ROBOTIC) - . = new_bodypart +// +// FUCK YOU AUGMENT CODE - With love, Kapu +/mob/living/carbon/proc/newBodyPart(zone) + var/path = dna.species.bodypart_overrides[zone] + var/obj/item/bodypart/new_bodypart = new path() + return new_bodypart -/mob/living/carbon/human/newBodyPart(zone, robotic, fixed_icon) - var/obj/item/bodypart/bodypart - var/datum/species/species = dna.species - var/obj/item/bodypart/selected_type = species.bodypart_overides[zone] - bodypart = new selected_type() - if(bodypart) - bodypart.update_limb(fixed_icon, src) - if(robotic) - bodypart.change_bodypart_status(BODYPART_ROBOTIC) - . = bodypart - -/mob/living/carbon/alien/larva/newBodyPart(zone, robotic, fixed_icon) +/mob/living/carbon/alien/larva/newBodyPart(zone) var/obj/item/bodypart/new_bodypart switch(zone) if(BODY_ZONE_HEAD) new_bodypart = new /obj/item/bodypart/head/larva() if(BODY_ZONE_CHEST) new_bodypart = new /obj/item/bodypart/chest/larva() - if(new_bodypart) - new_bodypart.update_limb(fixed_icon, src) - if(robotic) - new_bodypart.change_bodypart_status(BODYPART_ROBOTIC) . = new_bodypart -/mob/living/carbon/alien/humanoid/newBodyPart(zone, robotic, fixed_icon) +/mob/living/carbon/alien/humanoid/newBodyPart(zone) var/obj/item/bodypart/new_bodypart switch(zone) if(BODY_ZONE_L_ARM) @@ -182,10 +153,8 @@ if(BODY_ZONE_CHEST) new_bodypart = new /obj/item/bodypart/chest/alien() if(new_bodypart) - new_bodypart.update_limb(fixed_icon, src) - if(robotic) - new_bodypart.change_bodypart_status(BODYPART_ROBOTIC) - . = new_bodypart + new_bodypart.update_limb(src) + /proc/skintone2hex(skin_tone) @@ -217,37 +186,3 @@ . = "#fff4e6" if("orange") . = "#ffc905" - -/mob/living/carbon/proc/Digitigrade_Leg_Swap(swap_back) - var/body_plan_changed = FALSE - for(var/obj/item/bodypart/existing_bodypart as anything in bodyparts) - var/obj/item/bodypart/new_bodypart - if((!existing_bodypart.use_digitigrade && swap_back == FALSE) || (existing_bodypart.use_digitigrade && swap_back == TRUE)) - if(existing_bodypart.body_part == LEG_LEFT) - if(swap_back == TRUE) - new_bodypart = new /obj/item/bodypart/l_leg - else - new_bodypart = new /obj/item/bodypart/l_leg/digitigrade - else if(existing_bodypart.body_part == LEG_RIGHT) - if(swap_back == TRUE) - new_bodypart = new /obj/item/bodypart/r_leg - else - new_bodypart = new /obj/item/bodypart/r_leg/digitigrade - if(!new_bodypart) - continue - body_plan_changed = TRUE - existing_bodypart.drop_limb(1) - qdel(existing_bodypart) - new_bodypart.attach_limb(src) //no sanity for if this fails here because we just dropped out a limb of the same zone, SHOULD be okay - if(body_plan_changed && ishuman(src)) - var/mob/living/carbon/human/leg_owner = src - if(leg_owner.w_uniform) - var/obj/item/clothing/under/uniform = leg_owner.w_uniform - if(uniform.mutantrace_variation) - if(swap_back) - uniform.adjusted = NORMAL_STYLE - else - uniform.adjusted = DIGITIGRADE_STYLE - leg_owner.update_inv_w_uniform() - if(leg_owner.shoes && !(leg_owner.shoes.item_flags & IGNORE_DIGITIGRADE) && !swap_back) - leg_owner.dropItemToGround(leg_owner.shoes) diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index f113f7efa4f..aff8b229975 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -6,12 +6,16 @@ max_damage = 200 body_zone = BODY_ZONE_CHEST body_part = CHEST + is_dimorphic = TRUE px_x = 0 px_y = 0 stam_damage_coeff = 1 max_stamina_damage = 120 grind_results = null wound_resistance = 10 + ///The bodytype required to attach to this chest + var/acceptable_bodytype = BODYTYPE_HUMANOID + var/obj/item/cavity_item /obj/item/bodypart/chest/can_dismember(obj/item/item) @@ -30,11 +34,14 @@ ..() /obj/item/bodypart/chest/monkey - icon = 'icons/mob/animal_parts.dmi' + icon_static = 'icons/mob/animal_parts.dmi' icon_state = "default_monkey_chest" + limb_id = SPECIES_MONKEY + should_draw_greyscale = FALSE animal_origin = MONKEY_BODYPART - part_origin = MONKEY_BODY wound_resistance = -10 + bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + acceptable_bodytype = BODYTYPE_MONKEY /obj/item/bodypart/chest/alien icon = 'icons/mob/animal_parts.dmi' @@ -42,7 +49,6 @@ dismemberable = 0 max_damage = 500 animal_origin = ALIEN_BODYPART - part_origin = ALIEN_BODY /obj/item/bodypart/chest/larva icon = 'icons/mob/animal_parts.dmi' @@ -50,7 +56,6 @@ dismemberable = 0 max_damage = 50 animal_origin = LARVA_BODYPART - part_origin = LARVA_BODY /obj/item/bodypart/l_arm name = "left arm" @@ -132,10 +137,12 @@ /obj/item/bodypart/l_arm/monkey - icon = 'icons/mob/animal_parts.dmi' + icon_static = 'icons/mob/animal_parts.dmi' icon_state = "default_monkey_l_arm" + limb_id = SPECIES_MONKEY + should_draw_greyscale = FALSE animal_origin = MONKEY_BODYPART - part_origin = MONKEY_BODY + bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC wound_resistance = -10 px_x = -5 px_y = -3 @@ -149,7 +156,6 @@ can_be_disabled = FALSE max_damage = 100 animal_origin = ALIEN_BODYPART - part_origin = ALIEN_BODY /obj/item/bodypart/r_arm name = "right arm" @@ -229,10 +235,11 @@ /obj/item/bodypart/r_arm/monkey - icon = 'icons/mob/animal_parts.dmi' + icon_static = 'icons/mob/animal_parts.dmi' icon_state = "default_monkey_r_arm" + limb_id = SPECIES_MONKEY + bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC animal_origin = MONKEY_BODYPART - part_origin = MONKEY_BODY wound_resistance = -10 px_x = 5 px_y = -3 @@ -246,7 +253,6 @@ can_be_disabled = FALSE max_damage = 100 animal_origin = ALIEN_BODYPART - part_origin = ALIEN_BODY /obj/item/bodypart/l_leg @@ -316,16 +322,13 @@ else if(!bodypart_disabled) owner.set_usable_legs(owner.usable_legs + 1) - -/obj/item/bodypart/l_leg/digitigrade - name = "left digitigrade leg" - use_digitigrade = FULL_DIGITIGRADE - /obj/item/bodypart/l_leg/monkey - icon = 'icons/mob/animal_parts.dmi' + icon_static = 'icons/mob/animal_parts.dmi' icon_state = "default_monkey_l_leg" + limb_id = SPECIES_MONKEY + should_draw_greyscale = FALSE animal_origin = MONKEY_BODYPART - part_origin = MONKEY_BODY + bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC wound_resistance = -10 px_y = 4 @@ -338,7 +341,6 @@ can_be_disabled = FALSE max_damage = 100 animal_origin = ALIEN_BODYPART - part_origin = ALIEN_BODY /obj/item/bodypart/r_leg name = "right leg" @@ -409,16 +411,13 @@ else if(!bodypart_disabled) owner.set_usable_legs(owner.usable_legs + 1) - -/obj/item/bodypart/r_leg/digitigrade - name = "right digitigrade leg" - use_digitigrade = FULL_DIGITIGRADE - /obj/item/bodypart/r_leg/monkey icon = 'icons/mob/animal_parts.dmi' icon_state = "default_monkey_r_leg" + limb_id = SPECIES_MONKEY + should_draw_greyscale = FALSE animal_origin = MONKEY_BODYPART - part_origin = MONKEY_BODY + bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC wound_resistance = -10 px_y = 4 @@ -431,4 +430,3 @@ can_be_disabled = FALSE max_damage = 100 animal_origin = ALIEN_BODYPART - part_origin = ALIEN_BODY diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 21384097bd0..65b466d2e62 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -13,14 +13,17 @@ /obj/item/bodypart/l_arm/robot name = "cyborg left arm" desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - attack_verb_continuous = list("slaps", "punches") - attack_verb_simple = list("slap", "punch") + limb_id = "robotic" + attack_verb_simple = list("slapped", "punched") inhand_icon_state = "buildpipe" - icon = 'icons/mob/augmentation/augments.dmi' + icon_static = 'icons/mob/augmentation/augments.dmi' + icon = null flags_1 = CONDUCT_1 icon_state = "borg_l_arm" - status = BODYPART_ROBOTIC - disable_threshold = 1 + is_dimorphic = FALSE + should_draw_greyscale = FALSE + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + change_exempt_flags = BP_BLOCK_CHANGE_SPECIES brute_reduction = 5 burn_reduction = 4 @@ -36,14 +39,17 @@ /obj/item/bodypart/r_arm/robot name = "cyborg right arm" desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - attack_verb_continuous = list("slaps", "punches") - attack_verb_simple = list("slap", "punch") + attack_verb_simple = list("slapped", "punched") inhand_icon_state = "buildpipe" - icon = 'icons/mob/augmentation/augments.dmi' + icon_static = 'icons/mob/augmentation/augments.dmi' + icon = null + limb_id = "robotic" flags_1 = CONDUCT_1 icon_state = "borg_r_arm" - status = BODYPART_ROBOTIC - disable_threshold = 1 + is_dimorphic = FALSE + should_draw_greyscale = FALSE + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + change_exempt_flags = BP_BLOCK_CHANGE_SPECIES brute_reduction = 5 burn_reduction = 4 @@ -59,14 +65,17 @@ /obj/item/bodypart/l_leg/robot name = "cyborg left leg" desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - attack_verb_continuous = list("kicks", "stomps") - attack_verb_simple = list("kick", "stomp") + attack_verb_simple = list("kicked", "stomped") inhand_icon_state = "buildpipe" - icon = 'icons/mob/augmentation/augments.dmi' + icon_static = 'icons/mob/augmentation/augments.dmi' + icon = null + limb_id = "robotic" flags_1 = CONDUCT_1 icon_state = "borg_l_leg" - status = BODYPART_ROBOTIC - disable_threshold = 1 + is_dimorphic = FALSE + should_draw_greyscale = FALSE + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + change_exempt_flags = BP_BLOCK_CHANGE_SPECIES brute_reduction = 5 burn_reduction = 4 @@ -82,14 +91,17 @@ /obj/item/bodypart/r_leg/robot name = "cyborg right leg" desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - attack_verb_continuous = list("kicks", "stomps") - attack_verb_simple = list("kick", "stomp") + attack_verb_simple = list("kicked", "stomped") inhand_icon_state = "buildpipe" - icon = 'icons/mob/augmentation/augments.dmi' + icon_static = 'icons/mob/augmentation/augments.dmi' + icon = null + limb_id = "robotic" flags_1 = CONDUCT_1 icon_state = "borg_r_leg" - status = BODYPART_ROBOTIC - disable_threshold = 1 + is_dimorphic = FALSE + should_draw_greyscale = FALSE + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + change_exempt_flags = BP_BLOCK_CHANGE_SPECIES brute_reduction = 5 burn_reduction = 4 @@ -106,10 +118,15 @@ name = "cyborg torso" desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." inhand_icon_state = "buildpipe" - icon = 'icons/mob/augmentation/augments.dmi' + icon_static = 'icons/mob/augmentation/augments.dmi' + icon = null + limb_id = "robotic" flags_1 = CONDUCT_1 icon_state = "borg_chest" - status = BODYPART_ROBOTIC + is_dimorphic = FALSE + should_draw_greyscale = FALSE + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + change_exempt_flags = BP_BLOCK_CHANGE_SPECIES brute_reduction = 5 burn_reduction = 4 @@ -209,10 +226,15 @@ name = "cyborg head" desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." inhand_icon_state = "buildpipe" - icon = 'icons/mob/augmentation/augments.dmi' + icon_static = 'icons/mob/augmentation/augments.dmi' + limb_id = "robotic" + icon = null flags_1 = CONDUCT_1 icon_state = "borg_head" - status = BODYPART_ROBOTIC + is_dimorphic = FALSE + should_draw_greyscale = FALSE + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + change_exempt_flags = BP_BLOCK_CHANGE_SPECIES brute_reduction = 5 burn_reduction = 4 diff --git a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm new file mode 100644 index 00000000000..a581790b31f --- /dev/null +++ b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm @@ -0,0 +1,31 @@ +/obj/item/bodypart/head/ethereal + icon_greyscale = 'icons/mob/species/ethereal/bodyparts.dmi' + limb_id = SPECIES_ETHEREAL + is_dimorphic = FALSE + uses_mutcolor = TRUE + +/obj/item/bodypart/chest/ethereal + icon_greyscale = 'icons/mob/species/ethereal/bodyparts.dmi' + limb_id = SPECIES_ETHEREAL + is_dimorphic = FALSE + uses_mutcolor = TRUE + +/obj/item/bodypart/l_arm/ethereal + icon_greyscale = 'icons/mob/species/ethereal/bodyparts.dmi' + limb_id = SPECIES_ETHEREAL + uses_mutcolor = TRUE + +/obj/item/bodypart/r_arm/ethereal + icon_greyscale = 'icons/mob/species/ethereal/bodyparts.dmi' + limb_id = SPECIES_ETHEREAL + uses_mutcolor = TRUE + +/obj/item/bodypart/l_leg/ethereal + icon_greyscale = 'icons/mob/species/ethereal/bodyparts.dmi' + limb_id = SPECIES_ETHEREAL + uses_mutcolor = TRUE + +/obj/item/bodypart/r_leg/ethereal + icon_greyscale = 'icons/mob/species/ethereal/bodyparts.dmi' + limb_id = SPECIES_ETHEREAL + uses_mutcolor = TRUE diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm new file mode 100644 index 00000000000..7821c3a155c --- /dev/null +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -0,0 +1,77 @@ +/obj/item/bodypart/head/lizard + icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' + limb_id = SPECIES_LIZARD + uses_mutcolor = TRUE + is_dimorphic = FALSE + +/obj/item/bodypart/chest/lizard + icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' + uses_mutcolor = TRUE + limb_id = SPECIES_LIZARD + is_dimorphic = TRUE + +/obj/item/bodypart/l_arm/lizard + icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' + uses_mutcolor = TRUE + limb_id = SPECIES_LIZARD + +/obj/item/bodypart/r_arm/lizard + icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' + uses_mutcolor = TRUE + limb_id = SPECIES_LIZARD + +/obj/item/bodypart/l_leg/lizard + icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' + uses_mutcolor = TRUE + limb_id = SPECIES_LIZARD + +/obj/item/bodypart/r_leg/lizard + icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' + uses_mutcolor = TRUE + limb_id = SPECIES_LIZARD + +/obj/item/bodypart/l_leg/digitigrade + icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' + uses_mutcolor = TRUE + limb_id = "digitigrade" + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + +/obj/item/bodypart/l_leg/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/human_owner = owner + var/uniform_compatible = FALSE + var/suit_compatible = FALSE + if(!(human_owner.w_uniform) || (human_owner.w_uniform.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) //Checks uniform compatibility + uniform_compatible = TRUE + if((!human_owner.wear_suit) || (human_owner.wear_suit.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)) || !(human_owner.wear_suit.body_parts_covered & LEGS)) //Checks suit compatability + suit_compatible = TRUE + + if((uniform_compatible && suit_compatible) || (suit_compatible && human_owner.wear_suit?.flags_inv & HIDEJUMPSUIT)) //If the uniform is hidden, it doesnt matter if its compatible + limb_id = "digitigrade" + + else + limb_id = "lizard" + +/obj/item/bodypart/r_leg/digitigrade + icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' + uses_mutcolor = TRUE + limb_id = "digitigrade" + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + +/obj/item/bodypart/r_leg/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/human_owner = owner + var/uniform_compatible = FALSE + var/suit_compatible = FALSE + if(!(human_owner.w_uniform) || (human_owner.w_uniform.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) //Checks uniform compatibility + uniform_compatible = TRUE + if((!human_owner.wear_suit) || (human_owner.wear_suit.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)) || !(human_owner.wear_suit.body_parts_covered & LEGS)) //Checks suit compatability + suit_compatible = TRUE + + if((uniform_compatible && suit_compatible) || (suit_compatible && human_owner.wear_suit?.flags_inv & HIDEJUMPSUIT)) //If the uniform is hidden, it doesnt matter if its compatible + limb_id = "digitigrade" + + else + limb_id = "lizard" diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm new file mode 100644 index 00000000000..247706becd1 --- /dev/null +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -0,0 +1,422 @@ +///SNAIL +/obj/item/bodypart/head/snail + limb_id = SPECIES_SNAIL + is_dimorphic = FALSE + +/obj/item/bodypart/chest/snail + limb_id = SPECIES_SNAIL + is_dimorphic = FALSE + +/obj/item/bodypart/l_arm/snail + limb_id = SPECIES_SNAIL + +/obj/item/bodypart/r_arm/snail + limb_id = SPECIES_SNAIL + +/obj/item/bodypart/l_leg/snail + limb_id = SPECIES_SNAIL + +/obj/item/bodypart/r_leg/snail + limb_id = SPECIES_SNAIL + +///ABDUCTOR +/obj/item/bodypart/head/abductor + limb_id = SPECIES_ABDUCTOR + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/abductor + limb_id = SPECIES_ABDUCTOR + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/abductor + limb_id = SPECIES_ABDUCTOR + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/abductor + limb_id = SPECIES_ABDUCTOR + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/abductor + limb_id = SPECIES_ABDUCTOR + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/abductor + limb_id = SPECIES_ABDUCTOR + should_draw_greyscale = FALSE + +///JELLY +/obj/item/bodypart/head/jelly + limb_id = SPECIES_JELLYPERSON + is_dimorphic = TRUE + +/obj/item/bodypart/chest/jelly + limb_id = SPECIES_JELLYPERSON + is_dimorphic = TRUE + +/obj/item/bodypart/l_arm/jelly + limb_id = SPECIES_JELLYPERSON + +/obj/item/bodypart/r_arm/jelly + limb_id = SPECIES_JELLYPERSON + +/obj/item/bodypart/l_leg/jelly + limb_id = SPECIES_JELLYPERSON + +/obj/item/bodypart/r_leg/jelly + limb_id = SPECIES_JELLYPERSON + +///SLIME +/obj/item/bodypart/head/slime + limb_id = SPECIES_SLIMEPERSON + is_dimorphic = FALSE + +/obj/item/bodypart/chest/slime + limb_id = SPECIES_SLIMEPERSON + is_dimorphic = TRUE + +/obj/item/bodypart/l_arm/slime + limb_id = SPECIES_SLIMEPERSON + +/obj/item/bodypart/r_arm/slime + limb_id = SPECIES_SLIMEPERSON + +/obj/item/bodypart/l_leg/slime + limb_id = SPECIES_SLIMEPERSON + +/obj/item/bodypart/r_leg/slime + limb_id = SPECIES_SLIMEPERSON + +///ZOMBIE +/obj/item/bodypart/head/zombie + limb_id = SPECIES_ZOMBIE + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/zombie + limb_id = SPECIES_ZOMBIE + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/zombie + limb_id = SPECIES_ZOMBIE + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/zombie + limb_id = SPECIES_ZOMBIE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/zombie + limb_id = SPECIES_ZOMBIE + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/zombie + limb_id = SPECIES_ZOMBIE + should_draw_greyscale = FALSE + +///PODPEOPLE +/obj/item/bodypart/head/pod + limb_id = SPECIES_PODPERSON + is_dimorphic = TRUE + +/obj/item/bodypart/chest/pod + limb_id = SPECIES_PODPERSON + is_dimorphic = TRUE + +/obj/item/bodypart/l_arm/pod + limb_id = SPECIES_PODPERSON + +/obj/item/bodypart/r_arm/pod + limb_id = SPECIES_PODPERSON + +/obj/item/bodypart/l_leg/pod + limb_id = SPECIES_PODPERSON + +/obj/item/bodypart/r_leg/pod + limb_id = SPECIES_PODPERSON + +///FLY +/obj/item/bodypart/head/fly + limb_id = SPECIES_FLYPERSON + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/fly + limb_id = SPECIES_FLYPERSON + is_dimorphic = TRUE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/fly + limb_id = SPECIES_FLYPERSON + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/fly + limb_id = SPECIES_FLYPERSON + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/fly + limb_id = SPECIES_FLYPERSON + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/fly + limb_id = SPECIES_FLYPERSON + should_draw_greyscale = FALSE + +///SHADOW +/obj/item/bodypart/head/shadow + limb_id = SPECIES_SHADOW + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/shadow + limb_id = SPECIES_SHADOW + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/shadow + limb_id = SPECIES_SHADOW + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/shadow + limb_id = SPECIES_SHADOW + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/shadow + limb_id = SPECIES_SHADOW + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/shadow + limb_id = SPECIES_SHADOW + should_draw_greyscale = FALSE + +///SKELETON +/obj/item/bodypart/head/skeleton + limb_id = SPECIES_SKELETON + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/skeleton + limb_id = SPECIES_SKELETON + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/skeleton + limb_id = SPECIES_SKELETON + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/skeleton + limb_id = SPECIES_SKELETON + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/skeleton + limb_id = SPECIES_SKELETON + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/skeleton + limb_id = SPECIES_SKELETON + should_draw_greyscale = FALSE + +///MUSHROOM +/obj/item/bodypart/head/mushroom + limb_id = SPECIES_MUSHROOM + is_dimorphic = TRUE + +/obj/item/bodypart/chest/mushroom + limb_id = SPECIES_MUSHROOM + is_dimorphic = TRUE + +/obj/item/bodypart/l_arm/mushroom + limb_id = SPECIES_MUSHROOM + +/obj/item/bodypart/r_arm/mushroom + limb_id = SPECIES_MUSHROOM + +/obj/item/bodypart/l_leg/mushroom + limb_id = SPECIES_MUSHROOM + +/obj/item/bodypart/r_leg/mushroom + limb_id = SPECIES_MUSHROOM + +///GOLEMS (i hate xenobio SO FUCKING MUCH) +/obj/item/bodypart/head/golem + limb_id = SPECIES_GOLEM + is_dimorphic = FALSE + +/obj/item/bodypart/chest/golem + limb_id = SPECIES_GOLEM + is_dimorphic = TRUE + +/obj/item/bodypart/l_arm/golem + limb_id = SPECIES_GOLEM + +/obj/item/bodypart/r_arm/golem + limb_id = SPECIES_GOLEM + +/obj/item/bodypart/l_leg/golem + limb_id = SPECIES_GOLEM + +/obj/item/bodypart/r_leg/golem + limb_id = SPECIES_GOLEM + +/// +/obj/item/bodypart/head/golem/cult + limb_id = SPECIES_GOLEM_CULT + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/golem/cult + limb_id = SPECIES_GOLEM_CULT + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/golem/cult + limb_id = SPECIES_GOLEM_CULT + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/golem/cult + limb_id = SPECIES_GOLEM_CULT + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/golem/cult + limb_id = SPECIES_GOLEM_CULT + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/golem/cult + limb_id = SPECIES_GOLEM_CULT + should_draw_greyscale = FALSE + +/// +/obj/item/bodypart/head/golem/cloth + limb_id = SPECIES_GOLEM_CLOTH + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/golem/cloth + limb_id = SPECIES_GOLEM_CLOTH + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/golem/cloth + limb_id = SPECIES_GOLEM_CLOTH + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/golem/cloth + limb_id = SPECIES_GOLEM_CLOTH + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/golem/cloth + limb_id = SPECIES_GOLEM_CLOTH + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/golem/cloth + limb_id = SPECIES_GOLEM_CLOTH + should_draw_greyscale = FALSE + +/// +/obj/item/bodypart/head/golem/cardboard + limb_id = SPECIES_GOLEM_CARDBOARD + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/golem/cardboard + limb_id = SPECIES_GOLEM_CARDBOARD + is_dimorphic = TRUE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/golem/cardboard + limb_id = SPECIES_GOLEM_CARDBOARD + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/golem/cardboard + limb_id = SPECIES_GOLEM_CARDBOARD + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/golem/cardboard + limb_id = SPECIES_GOLEM_CARDBOARD + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/golem/cardboard + limb_id = SPECIES_GOLEM_CARDBOARD + should_draw_greyscale = FALSE + +/// +/obj/item/bodypart/head/golem/durathread + limb_id = SPECIES_GOLEM_DURATHREAD + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/golem/durathread + limb_id = SPECIES_GOLEM_DURATHREAD + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/golem/durathread + limb_id = SPECIES_GOLEM_DURATHREAD + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/golem/durathread + limb_id = SPECIES_GOLEM_DURATHREAD + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/golem/durathread + limb_id = SPECIES_GOLEM_DURATHREAD + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/golem/durathread + limb_id = SPECIES_GOLEM_DURATHREAD + should_draw_greyscale = FALSE + +/// +/obj/item/bodypart/head/golem/bone + limb_id = SPECIES_GOLEM_BONE + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/golem/bone + limb_id = SPECIES_GOLEM_BONE + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/golem/bone + limb_id = SPECIES_GOLEM_BONE + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/golem/bone + limb_id = SPECIES_GOLEM_BONE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/golem/bone + limb_id = SPECIES_GOLEM_BONE + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/golem/bone + limb_id = SPECIES_GOLEM_BONE + should_draw_greyscale = FALSE + +/// +/obj/item/bodypart/head/golem/snow + limb_id = SPECIES_GOLEM_SNOW + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/golem/snow + limb_id = SPECIES_GOLEM_SNOW + is_dimorphic = TRUE //WHO MADE SNOW BREASTS? + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/golem/snow + limb_id = SPECIES_GOLEM_SNOW + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/golem/snow + limb_id = SPECIES_GOLEM_SNOW + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/golem/snow + limb_id = SPECIES_GOLEM_SNOW + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/golem/snow + limb_id = SPECIES_GOLEM_SNOW + should_draw_greyscale = FALSE diff --git a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm new file mode 100644 index 00000000000..6d8bb3fd27a --- /dev/null +++ b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm @@ -0,0 +1,30 @@ +/obj/item/bodypart/head/moth + icon_static = 'icons/mob/species/moth/bodyparts.dmi' + limb_id = SPECIES_MOTH + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/moth + icon_static = 'icons/mob/species/moth/bodyparts.dmi' + limb_id = SPECIES_MOTH + is_dimorphic = TRUE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/moth + icon_static = 'icons/mob/species/moth/bodyparts.dmi' + limb_id = SPECIES_MOTH + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/moth + icon_static = 'icons/mob/species/moth/bodyparts.dmi' + limb_id = SPECIES_MOTH + should_draw_greyscale = FALSE +/obj/item/bodypart/l_leg/moth + icon_static = 'icons/mob/species/moth/bodyparts.dmi' + limb_id = SPECIES_MOTH + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/moth + icon_static = 'icons/mob/species/moth/bodyparts.dmi' + limb_id = SPECIES_MOTH + should_draw_greyscale = FALSE diff --git a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm new file mode 100644 index 00000000000..d711bd43001 --- /dev/null +++ b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm @@ -0,0 +1,31 @@ +/obj/item/bodypart/head/plasmaman + icon_static = 'icons/mob/species/plasmaman/bodyparts.dmi' + limb_id = SPECIES_PLASMAMAN + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/chest/plasmaman + icon_static = 'icons/mob/species/plasmaman/bodyparts.dmi' + limb_id = SPECIES_PLASMAMAN + is_dimorphic = FALSE + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_arm/plasmaman + icon_static = 'icons/mob/species/plasmaman/bodyparts.dmi' + limb_id = SPECIES_PLASMAMAN + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_arm/plasmaman + icon_static = 'icons/mob/species/plasmaman/bodyparts.dmi' + limb_id = SPECIES_PLASMAMAN + should_draw_greyscale = FALSE + +/obj/item/bodypart/l_leg/plasmaman + icon_static = 'icons/mob/species/plasmaman/bodyparts.dmi' + limb_id = SPECIES_PLASMAMAN + should_draw_greyscale = FALSE + +/obj/item/bodypart/r_leg/plasmaman + icon_static = 'icons/mob/species/plasmaman/bodyparts.dmi' + limb_id = SPECIES_PLASMAMAN + should_draw_greyscale = FALSE diff --git a/code/modules/surgery/bodyparts/wounds.dm b/code/modules/surgery/bodyparts/wounds.dm new file mode 100644 index 00000000000..be4d5072316 --- /dev/null +++ b/code/modules/surgery/bodyparts/wounds.dm @@ -0,0 +1,209 @@ +/// Allows us to roll for and apply a wound without actually dealing damage. Used for aggregate wounding power with pellet clouds +/obj/item/bodypart/proc/painless_wound_roll(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus, sharpness=NONE) + SHOULD_CALL_PARENT(TRUE) + + if(!owner || phantom_wounding_dmg <= WOUND_MINIMUM_DAMAGE || wound_bonus == CANT_WOUND) + return + + var/mangled_state = get_mangled_state() + var/bio_state = owner.get_biological_state() + var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%) + + if(wounding_type == WOUND_BLUNT && sharpness) + if(sharpness & SHARP_EDGED) + wounding_type = WOUND_SLASH + else if (sharpness & SHARP_POINTY) + wounding_type = WOUND_PIERCE + + //Handling for bone only/flesh only(none right now)/flesh and bone targets + switch(bio_state) + // if we're bone only, all cutting attacks go straight to the bone + if(BIO_JUST_BONE) + if(wounding_type == WOUND_SLASH) + wounding_type = WOUND_BLUNT + phantom_wounding_dmg *= (easy_dismember ? 1 : 0.6) + else if(wounding_type == WOUND_PIERCE) + wounding_type = WOUND_BLUNT + phantom_wounding_dmg *= (easy_dismember ? 1 : 0.75) + if((mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)) + return + // note that there's no handling for BIO_JUST_FLESH since we don't have any that are that right now (slimepeople maybe someday) + // standard humanoids + if(BIO_FLESH_BONE) + // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate + // So a big sharp weapon is still all you need to destroy a limb + if(mangled_state == BODYPART_MANGLED_FLESH && sharpness) + playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100) + if(wounding_type == WOUND_SLASH && !easy_dismember) + phantom_wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area + if(wounding_type == WOUND_PIERCE && !easy_dismember) + phantom_wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated + wounding_type = WOUND_BLUNT + else if(mangled_state == BODYPART_MANGLED_BOTH && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)) + return + + check_wounding(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus) + +/** + * check_wounding() is where we handle rolling for, selecting, and applying a wound if we meet the criteria + * + * We generate a "score" for how woundable the attack was based on the damage and other factors discussed in [/obj/item/bodypart/proc/check_woundings_mods], then go down the list from most severe to least severe wounds in that category. + * We can promote a wound from a lesser to a higher severity this way, but we give up if we have a wound of the given type and fail to roll a higher severity, so no sidegrades/downgrades + * + * Arguments: + * * woundtype- Either WOUND_BLUNT, WOUND_SLASH, WOUND_PIERCE, or WOUND_BURN based on the attack type. + * * damage- How much damage is tied to this attack, since wounding potential scales with damage in an attack (see: WOUND_DAMAGE_EXPONENT) + * * wound_bonus- The wound_bonus of an attack + * * bare_wound_bonus- The bare_wound_bonus of an attack + */ +/obj/item/bodypart/proc/check_wounding(woundtype, damage, wound_bonus, bare_wound_bonus, attack_direction) + SHOULD_CALL_PARENT(TRUE) + RETURN_TYPE(/datum/wound) + + if(HAS_TRAIT(owner, TRAIT_NEVER_WOUNDED)) + return + + // note that these are fed into an exponent, so these are magnified + if(HAS_TRAIT(owner, TRAIT_EASILY_WOUNDED)) + damage *= 1.5 + else + damage = min(damage, WOUND_MAX_CONSIDERED_DAMAGE) + + if(HAS_TRAIT(owner,TRAIT_HARDLY_WOUNDED)) + damage *= 0.85 + + if(HAS_TRAIT(owner, TRAIT_EASYDISMEMBER)) + damage *= 1.1 + + var/base_roll = rand(1, round(damage ** WOUND_DAMAGE_EXPONENT)) + var/injury_roll = base_roll + injury_roll += check_woundings_mods(woundtype, damage, wound_bonus, bare_wound_bonus) + var/list/wounds_checking = GLOB.global_wound_types[woundtype] + + if(injury_roll > WOUND_DISMEMBER_OUTRIGHT_THRESH && prob(get_damage() / max_damage * 100)) + var/datum/wound/loss/dismembering = new + dismembering.apply_dismember(src, woundtype, outright = TRUE, attack_direction = attack_direction) + return + + // quick re-check to see if bare_wound_bonus applies, for the benefit of log_wound(), see about getting the check from check_woundings_mods() somehow + if(ishuman(owner)) + var/mob/living/carbon/human/human_wearer = owner + var/list/clothing = human_wearer.clothingonpart(src) + for(var/obj/item/clothing/clothes_check as anything in clothing) + // unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary + if(clothes_check.armor.getRating(WOUND)) + bare_wound_bonus = 0 + break + + //cycle through the wounds of the relevant category from the most severe down + for(var/datum/wound/possible_wound as anything in wounds_checking) + var/datum/wound/replaced_wound + for(var/datum/wound/existing_wound as anything in wounds) + if(existing_wound.type in wounds_checking) + if(existing_wound.severity >= initial(possible_wound.severity)) + return + else + replaced_wound = existing_wound + + if(initial(possible_wound.threshold_minimum) < injury_roll) + var/datum/wound/new_wound + if(replaced_wound) + new_wound = replaced_wound.replace_wound(possible_wound, attack_direction = attack_direction) + else + new_wound = new possible_wound + new_wound.apply_wound(src, attack_direction = attack_direction) + log_wound(owner, new_wound, damage, wound_bonus, bare_wound_bonus, base_roll) // dismembering wounds are logged in the apply_wound() for loss wounds since they delete themselves immediately, these will be immediately returned + return new_wound + +// try forcing a specific wound, but only if there isn't already a wound of that severity or greater for that type on this bodypart +/obj/item/bodypart/proc/force_wound_upwards(specific_woundtype, smited = FALSE) + SHOULD_NOT_OVERRIDE(TRUE) + + var/datum/wound/potential_wound = specific_woundtype + for(var/datum/wound/existing_wound as anything in wounds) + if(existing_wound.wound_type == initial(potential_wound.wound_type)) + if(existing_wound.severity < initial(potential_wound.severity)) // we only try if the existing one is inferior to the one we're trying to force + existing_wound.replace_wound(potential_wound, smited) + return + + var/datum/wound/new_wound = new potential_wound + new_wound.apply_wound(src, smited = smited) + +/** + * check_wounding_mods() is where we handle the various modifiers of a wound roll + * + * A short list of things we consider: any armor a human target may be wearing, and if they have no wound armor on the limb, if we have a bare_wound_bonus to apply, plus the plain wound_bonus + * We also flick through all of the wounds we currently have on this limb and add their threshold penalties, so that having lots of bad wounds makes you more liable to get hurt worse + * Lastly, we add the inherent wound_resistance variable the bodypart has (heads and chests are slightly harder to wound), and a small bonus if the limb is already disabled + * + * Arguments: + * * It's the same ones on [/obj/item/bodypart/proc/receive_damage] + */ +/obj/item/bodypart/proc/check_woundings_mods(wounding_type, damage, wound_bonus, bare_wound_bonus) + SHOULD_CALL_PARENT(TRUE) + + var/armor_ablation = 0 + var/injury_mod = 0 + + if(owner && ishuman(owner)) + var/mob/living/carbon/human/human_owner = owner + var/list/clothing = human_owner.clothingonpart(src) + for(var/obj/item/clothing/clothes as anything in clothing) + // unlike normal armor checks, we tabluate these piece-by-piece manually so we can also pass on appropriate damage the clothing's limbs if necessary + armor_ablation += clothes.armor.getRating(WOUND) + if(wounding_type == WOUND_SLASH) + clothes.take_damage_zone(body_zone, damage, BRUTE) + else if(wounding_type == WOUND_BURN && damage >= 10) // lazy way to block freezing from shredding clothes without adding another var onto apply_damage() + clothes.take_damage_zone(body_zone, damage, BURN) + + if(!armor_ablation) + injury_mod += bare_wound_bonus + + injury_mod -= armor_ablation + injury_mod += wound_bonus + + for(var/datum/wound/wound as anything in wounds) + injury_mod += wound.threshold_penalty + + var/part_mod = -wound_resistance + if(get_damage(TRUE) >= max_damage) + part_mod += disabled_wound_penalty + + injury_mod += part_mod + + return injury_mod + + /// Get whatever wound of the given type is currently attached to this limb, if any +/obj/item/bodypart/proc/get_wound_type(checking_type) + RETURN_TYPE(checking_type) + SHOULD_NOT_OVERRIDE(TRUE) + + if(isnull(wounds)) + return + + for(var/wound in wounds) + if(istype(wound, checking_type)) + return wound + +/** + * update_wounds() is called whenever a wound is gained or lost on this bodypart, as well as if there's a change of some kind on a bone wound possibly changing disabled status + * + * Covers tabulating the damage multipliers we have from wounds (burn specifically), as well as deleting our gauze wrapping if we don't have any wounds that can use bandaging + * + * Arguments: + * * replaced- If true, this is being called from the remove_wound() of a wound that's being replaced, so the bandage that already existed is still relevant, but the new wound hasn't been added yet + */ +/obj/item/bodypart/proc/update_wounds(replaced = FALSE) + SHOULD_CALL_PARENT(TRUE) + + var/dam_mul = 1 //initial(wound_damage_multiplier) + + // we can (normally) only have one wound per type, but remember there's multiple types (smites like :B:loodless can generate multiple cuts on a limb) + for(var/datum/wound/iter_wound as anything in wounds) + dam_mul *= iter_wound.damage_mulitplier_penalty + + if(!LAZYLEN(wounds) && current_gauze && !replaced) // no more wounds = no need for the gauze anymore + owner.visible_message(span_notice("\The [current_gauze.name] on [owner]'s [name] falls away."), span_notice("The [current_gauze.name] on your [parse_zone(body_zone)] falls away.")) + QDEL_NULL(current_gauze) + + wound_damage_multiplier = dam_mul diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm index e202820df2e..f0860fac8f6 100644 --- a/code/modules/surgery/implant_removal.dm +++ b/code/modules/surgery/implant_removal.dm @@ -65,7 +65,7 @@ /datum/surgery/implant_removal/mechanic name = "implant removal" - requires_bodypart_type = BODYPART_ROBOTIC + requires_bodypart_type = BODYTYPE_ROBOTIC steps = list( /datum/surgery_step/mechanic_open, /datum/surgery_step/open_hatch, diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 2348e8f920d..cfd3e471c47 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -20,7 +20,7 @@ if(istype(tool, /obj/item/borg/apparatus/organ_storage) && istype(tool.contents[1], /obj/item/bodypart)) tool = tool.contents[1] var/obj/item/bodypart/aug = tool - if(aug.status != BODYPART_ROBOTIC) + if(IS_ORGANIC_LIMB(aug)) to_chat(user, span_warning("That's not an augment, silly!")) return -1 if(aug.body_zone != target_zone) @@ -59,7 +59,12 @@ tool.cut_overlays() tool = tool.contents[1] if(istype(tool) && user.temporarilyRemoveItemFromInventory(tool)) - tool.replace_limb(target, TRUE) + if(!tool.replace_limb(target)) + display_results(user, target, span_warning("You fail in replacing [target]'s [parse_zone(target_zone)]! Their body has rejected [tool]!"), + span_warning("[user] fails to replace [target]'s [parse_zone(target_zone)]!"), + span_warning("[user] fails to replaces [target]'s [parse_zone(target_zone)]!")) + tool.forceMove(target.loc) + return display_results(user, target, span_notice("You successfully augment [target]'s [parse_zone(target_zone)]."), span_notice("[user] successfully augments [target]'s [parse_zone(target_zone)] with [tool]!"), span_notice("[user] successfully augments [target]'s [parse_zone(target_zone)]!")) diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index 1921bf6dff3..676c8c74012 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -37,7 +37,7 @@ /datum/surgery/organ_manipulation/mechanic name = "Prosthesis organ manipulation" possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD) - requires_bodypart_type = BODYPART_ROBOTIC + requires_bodypart_type = BODYTYPE_ROBOTIC lying_required = FALSE self_operable = TRUE steps = list( diff --git a/code/modules/surgery/organs/external/_external_organs.dm b/code/modules/surgery/organs/external/_external_organs.dm index cb3607afc5d..63c97c21a16 100644 --- a/code/modules/surgery/organs/external/_external_organs.dm +++ b/code/modules/surgery/organs/external/_external_organs.dm @@ -74,11 +74,11 @@ bodypart.contents.Add(src) ///Add the overlays we need to draw on a person. Called from _bodyparts.dm -/obj/item/organ/external/proc/get_overlays(list/overlay_list, image_dir, image_layer, body_type, image_color) +/obj/item/organ/external/proc/get_overlays(list/overlay_list, image_dir, image_layer, physique, image_color) if(!sprite_datum) return - var/gender = (body_type == FEMALE) ? "f" : "m" + var/gender = (physique == FEMALE) ? "f" : "m" var/finished_icon_state = (sprite_datum.gender_specific ? gender : "m") + "_" + feature_key + "_" + sprite_datum.icon_state + mutant_bodyparts_layertext(image_layer) var/mutable_appearance/appearance = mutable_appearance(sprite_datum.icon, finished_icon_state, layer = -image_layer) appearance.dir = image_dir diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index ef98d9c876a..3b71ac866b2 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -250,7 +250,7 @@ if(owner.health < 5 && COOLDOWN_FINISHED(src, adrenaline_cooldown)) COOLDOWN_START(src, adrenaline_cooldown, rand(25 SECONDS, 1 MINUTES)) to_chat(owner, span_userdanger("You feel yourself dying, but you refuse to give up!")) - owner.heal_overall_damage(15, 15, 0, BODYPART_ORGANIC) + owner.heal_overall_damage(15, 15, 0, BODYTYPE_ORGANIC) if(owner.reagents.get_reagent_amount(/datum/reagent/medicine/ephedrine) < 20) owner.reagents.add_reagent(/datum/reagent/medicine/ephedrine, 10) diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm index a26c586541e..fb0f462d010 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/prosthetic_replacement.dm @@ -42,14 +42,15 @@ tool = organ_storage_contents if(istype(tool, /obj/item/bodypart)) var/obj/item/bodypart/bodypart_to_attach = tool - if(bodypart_to_attach.status != BODYPART_ROBOTIC) + if(IS_ORGANIC_LIMB(bodypart_to_attach)) organ_rejection_dam = 10 if(ishuman(target)) var/mob/living/carbon/human/human_target = target - if(!(bodypart_to_attach.part_origin & human_target.dna.species.allowed_animal_origin)) + var/obj/item/bodypart/chest/target_chest = human_target.get_bodypart(BODY_ZONE_CHEST) + if(!(bodypart_to_attach.bodytype & target_chest.acceptable_bodytype)) to_chat(user, span_warning("[bodypart_to_attach] doesn't match the patient's morphology.")) return -1 - if(human_target.dna.species.id != bodypart_to_attach.species_id) + if(human_target.dna.species.id != bodypart_to_attach.limb_id) organ_rejection_dam = 30 if(target_zone == bodypart_to_attach.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm. diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index eaec3c8b652..ca778dab316 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -7,7 +7,7 @@ var/can_cancel = TRUE //Can cancel this surgery after step 1 with cautery var/list/target_mobtypes = list(/mob/living/carbon/human) //Acceptable Species var/location = BODY_ZONE_CHEST //Surgery location - var/requires_bodypart_type = BODYPART_ORGANIC //Prevents you from performing an operation on incorrect limbs. 0 for any limb type + var/requires_bodypart_type = BODYTYPE_ORGANIC //Prevents you from performing an operation on incorrect limbs. 0 for any limb type var/list/possible_locs = list() //Multiple locations var/ignore_clothes = FALSE //This surgery ignores clothes var/mob/living/carbon/target //Operation target mob diff --git a/code/modules/unit_tests/create_and_destroy.dm b/code/modules/unit_tests/create_and_destroy.dm index cad988d6c63..2e9dd6b43a3 100644 --- a/code/modules/unit_tests/create_and_destroy.dm +++ b/code/modules/unit_tests/create_and_destroy.dm @@ -25,6 +25,8 @@ /mob/dview, //Requires a circuit url /obj/effect/mapping_helpers/circuit_spawner, + //Template type + /obj/item/bodypart, ) //Say it with me now, type template ignore += typesof(/obj/effect/mapping_helpers/atom_injector) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 16918e08ab4..61739757cb3 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -599,7 +599,7 @@ GLOBAL_LIST_EMPTY(vending_products) if(5) // limb squish! for(var/i in C.bodyparts) var/obj/item/bodypart/squish_part = i - if(squish_part.is_organic_limb()) + if(IS_ORGANIC_LIMB(squish_part)) var/type_wound = pick(list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate)) squish_part.force_wound_upwards(type_wound) else diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index 42cec530da3..ac629053477 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -4,7 +4,6 @@ zone = BODY_ZONE_HEAD slot = ORGAN_SLOT_ZOMBIE icon_state = "blacktumor" - visual = FALSE var/causes_damage = TRUE var/datum/species/old_species = /datum/species/human var/living_transformation_time = 30 @@ -31,7 +30,7 @@ /obj/item/organ/zombie_infection/Remove(mob/living/carbon/M, special = 0) . = ..() STOP_PROCESSING(SSobj, src) - if(iszombie(M) && old_species && !QDELETED(M)) + if(iszombie(M) && old_species && !special && !QDELETED(src)) M.set_species(old_species) if(timer_id) deltimer(timer_id) @@ -41,7 +40,7 @@ web of pus and viscera, bound tightly around the brain like some \ biological harness.") -/obj/item/organ/zombie_infection/process(delta_time) +/obj/item/organ/zombie_infection/process(delta_time, times_fired) if(!owner) return if(!(src in owner.internal_organs)) @@ -50,7 +49,7 @@ return if (causes_damage && !iszombie(owner) && owner.stat != DEAD) owner.adjustToxLoss(0.5 * delta_time) - if(DT_PROB(5, delta_time)) + if (DT_PROB(5, delta_time)) to_chat(owner, span_danger("You feel sick...")) if(timer_id) return @@ -66,9 +65,9 @@ not even death can stop, you will rise again!") var/revive_time = rand(revive_time_min, revive_time_max) var/flags = TIMER_STOPPABLE - timer_id = addtimer(CALLBACK(src, .proc/zombify), revive_time, flags) + timer_id = addtimer(CALLBACK(src, .proc/zombify, owner), revive_time, flags) -/obj/item/organ/zombie_infection/proc/zombify() +/obj/item/organ/zombie_infection/proc/zombify(mob/living/carbon/target) timer_id = null if(!converts_living && owner.stat != DEAD) @@ -76,24 +75,24 @@ if(!iszombie(owner)) old_species = owner.dna.species.type - owner.set_species(/datum/species/zombie/infectious) + target.set_species(/datum/species/zombie/infectious) - var/stand_up = (owner.stat == DEAD) || (owner.stat == UNCONSCIOUS) + var/stand_up = (target.stat == DEAD) || (target.stat == UNCONSCIOUS) //Fully heal the zombie's damage the first time they rise - owner.setToxLoss(0, 0) - owner.setOxyLoss(0, 0) - owner.heal_overall_damage(INFINITY, INFINITY, INFINITY, null, TRUE) + target.setToxLoss(0, 0) + target.setOxyLoss(0, 0) + target.heal_overall_damage(INFINITY, INFINITY, INFINITY, null, TRUE) - if(!owner.revive(full_heal = FALSE, admin_revive = FALSE)) + if(!target.revive()) return - owner.grab_ghost() - owner.visible_message(span_danger("[owner] suddenly convulses, as [owner.p_they()][stand_up ? " stagger to [owner.p_their()] feet and" : ""] gain a ravenous hunger in [owner.p_their()] eyes!"), span_alien("You HUNGER!")) - playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, TRUE) - owner.do_jitter_animation(living_transformation_time) - owner.Stun(living_transformation_time) - to_chat(owner, span_alertalien("You are now a zombie! Do not seek to be cured, do not help any non-zombies in any way, do not harm your zombie brethren and spread the disease by killing others. You are a creature of hunger and violence.")) + target.grab_ghost() + target.visible_message(span_danger("[owner] suddenly convulses, as [owner.p_they()][stand_up ? " stagger to [owner.p_their()] feet and" : ""] gain a ravenous hunger in [owner.p_their()] eyes!"), span_alien("You HUNGER!")) + playsound(target.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) + target.do_jitter_animation(living_transformation_time) + target.Stun(living_transformation_time) + to_chat(target, span_alertalien("You are now a zombie! Do not seek to be cured, do not help any non-zombies in any way, do not harm your zombie brethren and spread the disease by killing others. You are a creature of hunger and violence.")) /obj/item/organ/zombie_infection/nodamage causes_damage = FALSE diff --git a/icons/mob/augmentation/augments.dmi b/icons/mob/augmentation/augments.dmi index 4449da22d58..21e55386d3a 100644 Binary files a/icons/mob/augmentation/augments.dmi and b/icons/mob/augmentation/augments.dmi differ diff --git a/icons/mob/augmentation/augments_engineer.dmi b/icons/mob/augmentation/augments_engineer.dmi index 0e7fed2873c..45a3142de24 100644 Binary files a/icons/mob/augmentation/augments_engineer.dmi and b/icons/mob/augmentation/augments_engineer.dmi differ diff --git a/icons/mob/augmentation/augments_mining.dmi b/icons/mob/augmentation/augments_mining.dmi index 3942dc0c851..39df4823fd1 100644 Binary files a/icons/mob/augmentation/augments_mining.dmi and b/icons/mob/augmentation/augments_mining.dmi differ diff --git a/icons/mob/augmentation/augments_security.dmi b/icons/mob/augmentation/augments_security.dmi index 20c25f52332..97a561ed010 100644 Binary files a/icons/mob/augmentation/augments_security.dmi and b/icons/mob/augmentation/augments_security.dmi differ diff --git a/icons/mob/augmentation/surplus_augments.dmi b/icons/mob/augmentation/surplus_augments.dmi index bc3e4bd73ca..0fafab05336 100644 Binary files a/icons/mob/augmentation/surplus_augments.dmi and b/icons/mob/augmentation/surplus_augments.dmi differ diff --git a/icons/mob/clothing/under/cargo.dmi b/icons/mob/clothing/under/cargo.dmi index 105b6ac2fd4..05220dff1db 100644 Binary files a/icons/mob/clothing/under/cargo.dmi and b/icons/mob/clothing/under/cargo.dmi differ diff --git a/icons/mob/clothing/under/shorts_pants.dmi b/icons/mob/clothing/under/shorts_pants.dmi index 24c684c150b..3baa75d7d84 100644 Binary files a/icons/mob/clothing/under/shorts_pants.dmi and b/icons/mob/clothing/under/shorts_pants.dmi differ diff --git a/icons/mob/human_parts.dmi b/icons/mob/human_parts.dmi index c9ec0084b19..625e588d3a4 100644 Binary files a/icons/mob/human_parts.dmi and b/icons/mob/human_parts.dmi differ diff --git a/icons/mob/human_parts_greyscale.dmi b/icons/mob/human_parts_greyscale.dmi index 647c263c407..e2a7b330cb1 100644 Binary files a/icons/mob/human_parts_greyscale.dmi and b/icons/mob/human_parts_greyscale.dmi differ diff --git a/icons/mob/species/ethereal/bodyparts.dmi b/icons/mob/species/ethereal/bodyparts.dmi new file mode 100644 index 00000000000..d063c92b746 Binary files /dev/null and b/icons/mob/species/ethereal/bodyparts.dmi differ diff --git a/icons/mob/species/lizard/bodyparts.dmi b/icons/mob/species/lizard/bodyparts.dmi new file mode 100644 index 00000000000..c3961ade3c6 Binary files /dev/null and b/icons/mob/species/lizard/bodyparts.dmi differ diff --git a/icons/mob/species/misc/digitigrade.dmi b/icons/mob/species/misc/digitigrade.dmi new file mode 100644 index 00000000000..9d40540c14c Binary files /dev/null and b/icons/mob/species/misc/digitigrade.dmi differ diff --git a/icons/mob/species/moth/bodyparts.dmi b/icons/mob/species/moth/bodyparts.dmi new file mode 100644 index 00000000000..6324ad386e4 Binary files /dev/null and b/icons/mob/species/moth/bodyparts.dmi differ diff --git a/icons/mob/species/plasmaman/bodyparts.dmi b/icons/mob/species/plasmaman/bodyparts.dmi new file mode 100644 index 00000000000..c8ee2763615 Binary files /dev/null and b/icons/mob/species/plasmaman/bodyparts.dmi differ diff --git a/tgstation.dme b/tgstation.dme index e4f561d5a8b..570afc6e563 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -42,6 +42,7 @@ #include "code\__DEFINES\blackmarket.dm" #include "code\__DEFINES\blob_defines.dm" #include "code\__DEFINES\blood.dm" +#include "code\__DEFINES\bodyparts.dm" #include "code\__DEFINES\botany.dm" #include "code\__DEFINES\callbacks.dm" #include "code\__DEFINES\cargo.dm" @@ -156,6 +157,7 @@ #include "code\__DEFINES\spaceman_dmm.dm" #include "code\__DEFINES\span.dm" #include "code\__DEFINES\spatial_gridmap.dm" +#include "code\__DEFINES\species_clothing_paths.dm" #include "code\__DEFINES\speech_controller.dm" #include "code\__DEFINES\stat.dm" #include "code\__DEFINES\stat_tracking.dm" @@ -271,6 +273,7 @@ #include "code\__HELPERS\atmospherics.dm" #include "code\__HELPERS\atoms.dm" #include "code\__HELPERS\bitflag_lists.dm" +#include "code\__HELPERS\bodyparts.dm" #include "code\__HELPERS\chat.dm" #include "code\__HELPERS\chat_filter.dm" #include "code\__HELPERS\clients.dm" @@ -3240,7 +3243,6 @@ #include "code\modules\mob\living\carbon\human\species_types\shadowpeople.dm" #include "code\modules\mob\living\carbon\human\species_types\skeletons.dm" #include "code\modules\mob\living\carbon\human\species_types\snail.dm" -#include "code\modules\mob\living\carbon\human\species_types\synths.dm" #include "code\modules\mob\living\carbon\human\species_types\vampire.dm" #include "code\modules\mob\living\carbon\human\species_types\zombies.dm" #include "code\modules\mob\living\silicon\damage_procs.dm" @@ -4085,6 +4087,12 @@ #include "code\modules\surgery\bodyparts\helpers.dm" #include "code\modules\surgery\bodyparts\parts.dm" #include "code\modules\surgery\bodyparts\robot_bodyparts.dm" +#include "code\modules\surgery\bodyparts\wounds.dm" +#include "code\modules\surgery\bodyparts\species_parts\ethereal_bodyparts.dm" +#include "code\modules\surgery\bodyparts\species_parts\lizard_bodyparts.dm" +#include "code\modules\surgery\bodyparts\species_parts\misc_bodyparts.dm" +#include "code\modules\surgery\bodyparts\species_parts\moth_bodyparts.dm" +#include "code\modules\surgery\bodyparts\species_parts\plasmaman_bodyparts.dm" #include "code\modules\surgery\organs\appendix.dm" #include "code\modules\surgery\organs\augments_arms.dm" #include "code\modules\surgery\organs\augments_chest.dm"