diff --git a/code/modules/mob/living/human/death.dm b/code/modules/mob/living/human/death.dm index 83e6c71dcd22..d05fca67b1c2 100644 --- a/code/modules/mob/living/human/death.dm +++ b/code/modules/mob/living/human/death.dm @@ -1,6 +1,8 @@ /mob/living/human/gib(do_gibs = TRUE) var/turf/my_turf = get_turf(src) - . = ..() + if(do_gibs && has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE)) + do_gibs = FALSE + . = ..(do_gibs) if(.) for(var/obj/item/organ/I in get_internal_organs()) remove_organ(I) @@ -16,10 +18,15 @@ E.throw_at(get_edge_target_turf(E, pick(global.alldirs)), rand(1,3), THROWFORCE_GIBS) /mob/living/human/get_death_message(gibbed) + if(has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE)) + return "crumbles and falls apart!" if(get_config_value(/decl/config/toggle/health_show_human_death_message)) return species.get_species_death_message(src) || "seizes up and falls limp..." return ..() +/mob/living/human/get_self_death_message(gibbed) + return has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE) ? "You have crumbled." : ..() + /mob/living/human/death(gibbed) if(!(. = ..())) return @@ -40,6 +47,12 @@ SSticker.mode.check_win() species.handle_death(src) + if(!QDELETED(src) && !gibbed && has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE)) + gib() + +/mob/living/human/get_gibber_type() + return has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE) ? null : ..() + /mob/living/human/physically_destroyed(var/skip_qdel, var/droplimb_type = DISMEMBER_METHOD_BLUNT) for(var/obj/item/organ/external/limb in get_external_organs()) if(!limb.parent_organ) // don't dismember root diff --git a/code/modules/mob/living/human/human.dm b/code/modules/mob/living/human/human.dm index e8e79e0bffd6..31b74d0c690a 100644 --- a/code/modules/mob/living/human/human.dm +++ b/code/modules/mob/living/human/human.dm @@ -1202,6 +1202,16 @@ var/temp_inc = max(min(BODYTEMP_HEATING_MAX*(1-get_heat_protection()), exposed_temperature - bodytemperature), 0) bodytemperature += temp_inc +/mob/living/human/need_breathe() + return has_trait(/decl/trait/undead) ? FALSE : ..() + +// Undead don't get hungry/thirsty (except for brains) +/mob/living/human/get_nutrition() + return has_trait(/decl/trait/undead) ? get_max_nutrition() : ..() + +/mob/living/human/get_hydration() + return has_trait(/decl/trait/undead) ? get_max_hydration() : ..() + /mob/living/human/currently_has_skin() return currently_has_meat() @@ -1213,3 +1223,13 @@ if(istype(limb.material, /decl/material/solid/organic/meat)) return TRUE return FALSE + +/mob/living/human/set_status(condition, amount) + if(has_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE)) + var/static/list/ignore_status_conditions = list( + STAT_BLIND, + STAT_DEAF + ) + if(condition in ignore_status_conditions) + return + . = ..() diff --git a/code/modules/mob/living/human/human_appearance_head.dm b/code/modules/mob/living/human/human_appearance_head.dm index f5ed43182da9..49bd3d2d7557 100644 --- a/code/modules/mob/living/human/human_appearance_head.dm +++ b/code/modules/mob/living/human/human_appearance_head.dm @@ -3,6 +3,9 @@ // Eyes! TODO, make these a marking. /mob/living/human/get_eye_colour() + // Force an evil red glow for undead mobs. + if(has_trait(/decl/trait/undead)) + return COLOR_RED return _eye_colour /mob/living/human/set_eye_colour(var/new_color, var/skip_update = FALSE) diff --git a/code/modules/mob/living/human/human_damage.dm b/code/modules/mob/living/human/human_damage.dm index c1d05b7c6ab5..db5c6936e9c2 100644 --- a/code/modules/mob/living/human/human_damage.dm +++ b/code/modules/mob/living/human/human_damage.dm @@ -1,4 +1,11 @@ /mob/living/human/get_life_damage_types() + if(has_trait(/decl/trait/undead)) + // Undead human mobs use brute and burn damage instead of brain damage, a la simplemobs. + var/static/list/life_damage_types = list( + BURN, + BRUTE + ) + return life_damage_types var/static/list/brain_life_damage_types = list( BRAIN ) @@ -137,9 +144,13 @@ return 0 /mob/living/human/setOxyLoss(var/amount) + if(has_trait(/decl/trait/undead)) + return take_damage(amount - get_damage(OXY), OXY) /mob/living/human/adjustOxyLoss(var/damage, var/do_update_health = TRUE) + if(has_trait(/decl/trait/undead)) + return . = FALSE if(need_breathe()) var/obj/item/organ/internal/lungs/breathe_organ = get_organ(get_bodytype().breathing_organ, /obj/item/organ/internal/lungs) @@ -150,7 +161,7 @@ ..(do_update_health = FALSE) // Oxyloss cannot directly kill humans /mob/living/human/getToxLoss() - if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic()) + if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic() || has_trait(/decl/trait/undead)) return 0 var/amount = 0 for(var/obj/item/organ/internal/I in get_internal_organs()) @@ -158,13 +169,13 @@ return amount /mob/living/human/setToxLoss(var/amount) - if(!(species.species_flags & SPECIES_FLAG_NO_POISON) && !isSynthetic()) + if(!(species.species_flags & SPECIES_FLAG_NO_POISON) && !isSynthetic() || has_trait(/decl/trait/undead)) take_damage(get_damage(TOX)-amount, TOX) // TODO: better internal organ damage procs. /mob/living/human/adjustToxLoss(var/amount, var/do_update_health = TRUE) - if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic()) + if((species.species_flags & SPECIES_FLAG_NO_POISON) || isSynthetic() || has_trait(/decl/trait/undead)) return var/heal = amount < 0 diff --git a/code/modules/mob/living/human/human_organs.dm b/code/modules/mob/living/human/human_organs.dm index 7dbeab31c6ce..5f31bc7793e7 100644 --- a/code/modules/mob/living/human/human_organs.dm +++ b/code/modules/mob/living/human/human_organs.dm @@ -145,12 +145,25 @@ LAZYDISTINCTADD(bad_external_organs, E) /mob/living/human/proc/check_vital_organ_missing() + // Undead don't care about missing internal organs. + if(has_trait(/decl/trait/undead)) + return FALSE return get_bodytype()?.check_vital_organ_missing(src) +/mob/living/human/should_have_organ(organ_to_check) + // It might be nice to have eyes etc. matter for zombies, but as all organs are dead it won't work currently. + return has_trait(/decl/trait/undead) ? FALSE : ..() + /mob/living/human/proc/process_internal_organs() + if(has_trait(/decl/trait/undead)) + return for(var/obj/item/organ/I in internal_organs) I.Process() +/mob/living/human/get_vision_organ_tag() + // Where we're going, we don't need eyes. + return has_trait(/decl/trait/undead) ? null : ..() + // Takes care of organ related updates, such as broken and missing limbs /mob/living/human/proc/handle_organs() diff --git a/code/modules/organs/external/_external.dm b/code/modules/organs/external/_external.dm index 39673c2f03eb..5856f901e691 100644 --- a/code/modules/organs/external/_external.dm +++ b/code/modules/organs/external/_external.dm @@ -733,7 +733,10 @@ This function completely restores a damaged organ to perfect condition. if(length(ailments)) return TRUE - if(status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_MUTATED|ORGAN_DISLOCATED|ORGAN_DEAD)) + if(status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_MUTATED|ORGAN_DISLOCATED)) + return TRUE + + if((status & ORGAN_DEAD) && !owner?.has_trait(/decl/trait/undead)) return TRUE if((brute_dam || burn_dam) && !BP_IS_PROSTHETIC(src)) //Robot limbs don't autoheal and thus don't need to process when damaged diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 6ae0fb2f1ea1..a46cd38be6d3 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -417,7 +417,9 @@ return bodytype && !(bodytype.body_flags & BODY_FLAG_NO_PAIN) && !(status & ORGAN_DEAD) /obj/item/organ/proc/is_usable() - . = !(status & (ORGAN_CUT_AWAY|ORGAN_MUTATED|ORGAN_DEAD)) + . = !(status & (ORGAN_CUT_AWAY|ORGAN_MUTATED)) + if(. && (status & ORGAN_DEAD)) + return owner?.has_trait(/decl/trait/undead) /obj/item/organ/proc/can_recover() return (max_damage > 0) && !(status & ORGAN_DEAD) || death_time >= REALTIMEOFDAY - ORGAN_RECOVERY_THRESHOLD diff --git a/mods/pyrelight/_pyrelight.dme b/mods/pyrelight/_pyrelight.dme index b1b42ba3caea..cd4db6f33b5f 100644 --- a/mods/pyrelight/_pyrelight.dme +++ b/mods/pyrelight/_pyrelight.dme @@ -14,5 +14,8 @@ #include "plants\plants_fruit_template.dm" #include "plants\fruit_subtypes\nightweave.dm" #include "plants\plant_subtypes\nightweave.dm" +#include "undead\_undead.dm" +#include "undead\undead_skeleton.dm" +#include "undead\undead_zombie.dm" #endif // END_INCLUDE diff --git a/mods/pyrelight/undead/_undead.dm b/mods/pyrelight/undead/_undead.dm new file mode 100644 index 000000000000..06d4f34e9572 --- /dev/null +++ b/mods/pyrelight/undead/_undead.dm @@ -0,0 +1,4 @@ +/decl/trait/undead + name = "Undead" + description = "Your body is dead, but remains animated through some supernatural force." + levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MODERATE) // Moderate means skeleton, minor means zombie. diff --git a/mods/pyrelight/undead/undead_skeleton.dm b/mods/pyrelight/undead/undead_skeleton.dm new file mode 100644 index 000000000000..fa6fdfe09975 --- /dev/null +++ b/mods/pyrelight/undead/undead_skeleton.dm @@ -0,0 +1,42 @@ +// SKELETONS +// Immune to blind or deaf, but weak to physical damage. +/mob/living/human/proc/make_skeleton() + set_trait(/decl/trait/metabolically_inert, TRAIT_LEVEL_EXISTS) + set_trait(/decl/trait/undead, TRAIT_LEVEL_MODERATE) + + for(var/obj/item/organ/external/limb in get_external_organs()) + if(!BP_IS_PROSTHETIC(limb)) + limb.skeletonize() + + for(var/obj/item/organ/internal/organ in get_internal_organs()) + remove_organ(organ, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE) + qdel(organ) + + vessel?.clear_reagents() + SET_HAIR_STYLE(src, /decl/sprite_accessory/hair/bald, FALSE) + update_body() + +/mob/living/human/skeleton/post_setup(species_name, datum/mob_snapshot/supplied_appearance) + . = ..() + make_skeleton() + +/mob/living/human/skeleton/Initialize(mapload, species_name, datum/mob_snapshot/supplied_appearance) + if(!species_name) + species_name = SPECIES_HUMAN + . = ..() + +/mob/living/human/skeleton/hnoll/Initialize(mapload, species_name, datum/mob_snapshot/supplied_appearance) + if(!species_name) + species_name = SPECIES_HNOLL + . = ..() + +/mob/living/human/skeleton/kobaloi/Initialize(mapload, species_name, datum/mob_snapshot/supplied_appearance) + if(!species_name) + species_name = SPECIES_KOBALOI + . = ..() + +/mob/living/human/skeleton/meredrake/Initialize(mapload, species_name, datum/mob_snapshot/supplied_appearance) + if(!species_name) + var/decl/species/grafadreka/drakes = GET_DECL(/decl/species/grafadreka) + species_name = drakes.name + . = ..() diff --git a/mods/pyrelight/undead/undead_zombie.dm b/mods/pyrelight/undead/undead_zombie.dm new file mode 100644 index 000000000000..0c65f5cf82a6 --- /dev/null +++ b/mods/pyrelight/undead/undead_zombie.dm @@ -0,0 +1,56 @@ +// ZOMBIES +// Dead and rotting, but still mobile and aggressive. +/mob/living/human/proc/make_zombie() + set_trait(/decl/trait/metabolically_inert, TRAIT_LEVEL_EXISTS) + set_trait(/decl/trait/undead, TRAIT_LEVEL_MINOR) + + for(var/obj/item/organ/organ in get_organs()) + organ.die() + organ.damage = 0 // die() sets to max damage + organ.germ_level = INFECTION_LEVEL_THREE + + // Set this so nonhumans look appropriately gross. + reset_hair() + if(get_bodytype()?.appearance_flags & HAS_SKIN_COLOR) + _skin_colour = pick(COLOR_GRAY, COLOR_GRAY15, COLOR_GRAY20, COLOR_GRAY40, COLOR_GRAY80, COLOR_WHITE) + SET_HAIR_COLOUR(src, _skin_colour, TRUE) + SET_FACIAL_HAIR_COLOUR(src, _skin_colour, TRUE) + + for(var/obj/item/organ/external/limb in get_external_organs()) + if(!BP_IS_PROSTHETIC(limb)) + limb.sync_colour_to_human(src) + if(prob(10)) + limb.skeletonize() + else if(prob(15)) + if(prob(75)) + limb.createwound(CUT, rand(limb.max_damage * 0.25, limb.max_damage * 0.5)) + else + limb.createwound(BURN, rand(limb.max_damage * 0.25, limb.max_damage * 0.5)) + + vessel.remove_any(vessel.total_volume * rand(0.2, 0.5)) + update_body() + +/mob/living/human/zombie/post_setup(species_name, datum/mob_snapshot/supplied_appearance) + . = ..() + make_zombie() + +/mob/living/human/zombie/Initialize(mapload, species_name, datum/mob_snapshot/supplied_appearance) + if(!species_name) + species_name = SPECIES_HUMAN + . = ..() + +/mob/living/human/zombie/hnoll/Initialize(mapload, species_name, datum/mob_snapshot/supplied_appearance) + if(!species_name) + species_name = SPECIES_HNOLL + . = ..() + +/mob/living/human/zombie/kobaloi/Initialize(mapload, species_name, datum/mob_snapshot/supplied_appearance) + if(!species_name) + species_name = SPECIES_KOBALOI + . = ..() + +/mob/living/human/zombie/meredrake/Initialize(mapload, species_name, datum/mob_snapshot/supplied_appearance) + if(!species_name) + var/decl/species/grafadreka/drakes = GET_DECL(/decl/species/grafadreka) + species_name = drakes.name + . = ..()