Adds Zombies (Admin-spawn) (#25381)

* fuck it good enough

* Apply suggestions from code review

Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Signed-off-by: Contrabang <91113370+Contrabang@users.noreply.github.com>

* TRIPLE-REVIEW

* this should do it

* wow

* bruh

* FIX

* fix

* yeah

* sirryan review

* aaaaa

* Apply suggestions from code review

Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Signed-off-by: Contrabang <91113370+Contrabang@users.noreply.github.com>

---------

Signed-off-by: Contrabang <91113370+Contrabang@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
This commit is contained in:
Contrabang
2024-05-30 22:17:31 -04:00
committed by GitHub
parent 247e24ba9f
commit bc0c8344cf
62 changed files with 1326 additions and 148 deletions
+2
View File
@@ -94,6 +94,8 @@
/mob/proc/put_in_hand_check(obj/item/W, skip_blocked_hands_check)
if(!istype(W) || QDELETED(W))
return FALSE
if(HAS_TRAIT(src, TRAIT_ABSTRACT_HANDS) && !(W.flags & ABSTRACT))
return FALSE
return TRUE
/mob/living/put_in_hand_check(obj/item/W, skip_blocked_hands_check)
+35 -3
View File
@@ -667,25 +667,32 @@
syllables = list ("beep", "boop")
// Language handling.
/mob/proc/add_language(language)
/mob/proc/add_language(language, force)
var/datum/language/new_language = GLOB.all_languages[language]
if(!istype(new_language) || (new_language in languages))
return FALSE
if(HAS_TRAIT(src, TRAIT_LANGUAGE_LOCKED) && !force)
return FALSE
languages |= new_language
return TRUE
/mob/proc/remove_language(rem_language)
/mob/proc/remove_language(rem_language, force)
if(HAS_TRAIT(src, TRAIT_LANGUAGE_LOCKED) && !force)
return FALSE
var/datum/language/L = GLOB.all_languages[rem_language]
. = (L in languages)
languages.Remove(L)
/mob/living/remove_language(rem_language)
. = ..()
if(!.)
return
var/datum/language/L = GLOB.all_languages[rem_language]
if(default_language == L)
default_language = null
return ..()
// Can we speak this language, as opposed to just understanding it?
/mob/proc/can_speak_language(datum/language/speaking)
@@ -768,4 +775,29 @@
continue
languages |= new_language
/datum/language/zombie
name = "Zombie"
desc = "Flesh... Brains... We hunger..."
speech_verb = "groans"
ask_verb = "groans"
exclaim_verbs = list("yells")
colour = "zombie"
key = "zz" //doesn't matter, this is their default and only language
flags = RESTRICTED | NOLIBRARIAN
syllables = list("Brains", "Brainssss", "Flesh", "Grrr", "Hnng", "Braaaains", "Braaiiiins")
english_names = TRUE
/datum/language/zombie/scramble(input)
var/terminator = "..."
if(!length(input))
return "[pick(syllables)][terminator]"
var/last_letter = copytext(input, length(input))
if(last_letter in list("?", "!"))
terminator = last_letter
if(prob(90) || !length(input))
return "[pick(syllables)][terminator]"
return "[copytext_char(input, 1, min(7, length(input)))][terminator]"
#undef SCRAMBLE_CACHE_LEN
@@ -115,6 +115,7 @@
var/obj/item/organ/external/chest = owner.get_organ(BODY_ZONE_CHEST)
chest.fracture()
chest.droplimb()
chest.open = ORGAN_ORGANIC_VIOLENT_OPEN
else //If we are discovered mid-surgery
owner.adjustBruteLoss(40)
SSblackbox.record_feedback("tally", "alien_growth", 1, "hatched_eggs")
@@ -209,7 +209,7 @@
if(prob(D.infectivity))
D.spread()
if(stat != DEAD)
if(stat != DEAD || D.allow_dead)
D.stage_act()
//remember to remove the "proc" of the child procs of these.
@@ -115,6 +115,8 @@
skipeyes |= wear_mask.flags_inv & HIDEEYES
var/msg = "<span class='info'>This is "
if(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
msg = "<span class='info'>This is the <span class='warning'>shambling corpse</span> of "
msg += "<em>[name]</em>"
@@ -58,7 +58,7 @@
if(sponge)
return min(sponge.damage,maxHealth*2)
else
if(IS_CHANGELING(src))
if(IS_CHANGELING(src) || HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
// if a changeling has no brain, they have no brain damage.
return 0
@@ -641,7 +641,8 @@ emp_act
if(check_shields(user, 15, "the [hulk_verb]ing"))
return
..(user, TRUE)
playsound(loc, user.dna.species.unarmed.attack_sound, 25, 1, -1)
var/datum/unarmed_attack/unarmed = user.get_unarmed_attack()
playsound(loc, unarmed.attack_sound, 25, TRUE, -1)
var/message = "[user] has [hulk_verb]ed [src]!"
visible_message("<span class='danger'>[message]</span>", "<span class='userdanger'>[message]</span>")
adjustBruteLoss(15)
@@ -185,6 +185,8 @@
var/mob/living/carbon/human/human = user
if(human.mind?.miming || !istype(human))
return
if(HAS_TRAIT(human, TRAIT_I_WANT_BRAINS))
return 'sound/voice/zombie_scream.ogg'
if(human.gender == FEMALE)
return human.dna.species.female_scream_sound
else
@@ -234,7 +236,7 @@
volume_decrease = 95
sound_volume -= volume_decrease
// special handling here: we don't want monkeys' gasps to sound through walls so you can actually walk past xenobio
playsound(user.loc, sound_path, sound_volume, TRUE, -10, frequency = H.get_age_pitch(H.dna.species.max_age), ignore_walls = !isnull(user.mind))
playsound(user.loc, sound_path, sound_volume, TRUE, -10, frequency = H.get_age_pitch(H.dna.species.max_age) * alter_emote_pitch(user), ignore_walls = !isnull(user.mind))
/datum/emote/living/carbon/human/shake
key = "shake"
@@ -137,7 +137,7 @@
if(E.is_robotic())
msg += "<b>The maintenance hatch on [p_their()] [ignore_limb_branding(E.limb_name)] is open!</b>\n"
else
msg += "<b>[p_their(TRUE)] [ignore_limb_branding(E.limb_name)] has an open incision!</b>\n"
msg += "<b>[p_their(TRUE)] [ignore_limb_branding(E.limb_name)] [E.open != ORGAN_ORGANIC_VIOLENT_OPEN ? "has an open incision" : "has been violently split open"]!</b>\n"
for(var/obj/item/I in E.embedded_objects)
// we cant just use \a here, as we want it to appear before the bicon
@@ -1270,6 +1270,9 @@
if(default_language)
return default_language
if(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS)) // you're not allowed to speak common
return GLOB.all_languages["Zombie"]
if(!dna.species)
return null
return dna.species.default_language ? GLOB.all_languages[dna.species.default_language] : null
@@ -2036,3 +2039,10 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
message += "\tI could make [result.gender == PLURAL ? "some" : "a"] [bicon(result)] <b>[result.name]</b> by using \a [possible_recipes[recipe]] with [english_list(ingredient_list)][length(required_reagents) ? ", along with [english_list(required_reagents)]" : ""]."
qdel(recipe)
to_chat(src, chat_box_examine(message.Join("<br>")))
/mob/living/carbon/human/proc/get_unarmed_attack()
var/datum/antagonist/zombie/zombie = mind?.has_antag_datum(/datum/antagonist/zombie)
if(!istype(zombie))
return dna.species.unarmed
return zombie.claw_attack
@@ -48,6 +48,8 @@
for(var/limb_tag in list("l_leg","r_leg","l_foot","r_foot"))
var/obj/item/organ/external/E = bodyparts_by_name[limb_tag]
if(!E || (E.status & ORGAN_DEAD) || E.is_malfunctioning() || !E.properly_attached)
if(E?.status & ORGAN_DEAD && HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
continue
if(E && !E.properly_attached && life_tick % 24 == 0)
to_chat(src, "<span class='danger'>Your [E] is hanging on by a thread! You need someone to surgically attach it for you!</span>")
// let it fail even if just foot&leg. Also malfunctioning happens sporadically so it should impact more when it procs.
@@ -338,6 +338,9 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
var/icon/head_accessory_s = new/icon("icon" = head_accessory_style.icon, "icon_state" = "[head_accessory_style.icon_state]_s")
if(head_accessory_style.do_colouration)
head_accessory_s.Blend(head_organ.headacc_colour, ICON_ADD)
if(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
head_accessory_s.ColorTone(COLORTONE_DEAD_EXT_ORGAN)
head_accessory_s.SetIntensity(0.7)
head_accessory_standing = head_accessory_s //head_accessory_standing.Blend(head_accessory_s, ICON_OVERLAY)
//Having it this way preserves animations. Useful for animated antennae.
@@ -368,11 +371,17 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
var/datum/sprite_accessory/hair/hair = GLOB.hair_styles_full_list[O.h_style]
if(hair?.species_allowed && ((O.dna.species.name in hair.species_allowed) || (O.dna.species.bodyflags & ALL_RPARTS)))
// Base hair
var/mutable_appearance/img_hair = mutable_appearance(hair.icon, "[hair.icon_state]_s")
if(istype(O.dna.species, /datum/species/slime))
img_hair.color = COLOR_MATRIX_OVERLAY("[skin_colour]A0")
else if(hair.do_colouration)
img_hair.color = COLOR_MATRIX_ADD(O.hair_colour)
var/icon/hair_icon = new /icon(hair.icon, "[hair.icon_state]_s")
if(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
hair_icon.ColorTone(COLORTONE_DEAD_EXT_ORGAN)
hair_icon.SetIntensity(0.7)
var/mutable_appearance/img_hair = mutable_appearance(hair_icon)
// Zombie skrells and slimes do not have colored hair
if(!(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS) && (istype(O.dna.species, /datum/species/slime) || istype(O.dna.species, /datum/species/skrell))))
if(istype(O.dna.species, /datum/species/slime))
img_hair.color = COLOR_MATRIX_OVERLAY("[skin_colour]A0")
else if(hair.do_colouration)
img_hair.color = COLOR_MATRIX_ADD(O.hair_colour)
MA.overlays += img_hair
// Gradient
@@ -1204,13 +1213,21 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
if(!body_accessory.try_restrictions(src))
return
var/mutable_appearance/wings = mutable_appearance(body_accessory.icon, body_accessory.icon_state, layer = -WING_LAYER)
var/icon/wings_icon = new /icon(body_accessory.icon, body_accessory.icon_state)
if(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
wings_icon.ColorTone(COLORTONE_DEAD_EXT_ORGAN)
wings_icon.SetIntensity(0.7)
var/mutable_appearance/wings = mutable_appearance(wings_icon, layer = -WING_LAYER)
wings.pixel_x = body_accessory.pixel_x_offset
wings.pixel_y = body_accessory.pixel_y_offset
overlays_standing[WING_LAYER] = wings
if(body_accessory.has_behind)
var/mutable_appearance/under_wing = mutable_appearance(body_accessory.icon, "[body_accessory.icon_state]_BEHIND", layer = -WING_UNDERLIMBS_LAYER)
var/icon/under_wing_icon = new /icon(body_accessory.icon, "[body_accessory.icon_state]_BEHIND")
if(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
under_wing_icon.ColorTone(COLORTONE_DEAD_EXT_ORGAN)
under_wing_icon.SetIntensity(0.7)
var/mutable_appearance/under_wing = mutable_appearance(under_wing_icon, layer = -WING_UNDERLIMBS_LAYER)
under_wing.pixel_x = body_accessory.pixel_x_offset
under_wing.pixel_y = body_accessory.pixel_y_offset
overlays_standing[WING_UNDERLIMBS_LAYER] = under_wing
@@ -1236,10 +1253,14 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
if(body_accessory)
if(body_accessory.try_restrictions(src))
var/icon/accessory_s = new/icon("icon" = body_accessory.icon, "icon_state" = body_accessory.icon_state)
if(dna.species.bodyflags & HAS_SKIN_COLOR)
accessory_s.Blend(skin_colour, body_accessory.blend_mode)
if(tail_marking_icon && (body_accessory.name in tail_marking_style.tails_allowed))
accessory_s.Blend(tail_marking_icon, ICON_OVERLAY)
if(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
accessory_s.ColorTone(COLORTONE_DEAD_EXT_ORGAN)
accessory_s.SetIntensity(0.7)
else
if(dna.species.bodyflags & HAS_SKIN_COLOR)
accessory_s.Blend(skin_colour, body_accessory.blend_mode)
if(tail_marking_icon && (body_accessory.name in tail_marking_style.tails_allowed))
accessory_s.Blend(tail_marking_icon, ICON_OVERLAY)
if((!body_accessory || istype(body_accessory, /datum/body_accessory/tail)) && dna.species.bodyflags & TAIL_OVERLAPPED) // If the player has a species whose tail is overlapped by limbs... (having a non-tail body accessory like the snake body will override this)
// Gives the underlimbs layer SEW direction icons since it's overlayed by limbs and just about everything else anyway.
var/icon/under = new/icon("icon" = 'icons/mob/body_accessory.dmi', "icon_state" = "accessory_none_s")
@@ -1270,10 +1291,14 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
else if(tail && dna.species.bodyflags & HAS_TAIL) //no tailless tajaran
if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL))
var/icon/tail_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[tail]_s")
if(dna.species.bodyflags & HAS_SKIN_COLOR)
tail_s.Blend(skin_colour, ICON_ADD)
if(tail_marking_icon && !tail_marking_style.tails_allowed)
tail_s.Blend(tail_marking_icon, ICON_OVERLAY)
if(HAS_TRAIT(src, TRAIT_I_WANT_BRAINS))
tail_s.ColorTone(COLORTONE_DEAD_EXT_ORGAN)
tail_s.SetIntensity(0.7)
else
if(dna.species.bodyflags & HAS_SKIN_COLOR)
tail_s.Blend(skin_colour, ICON_ADD)
if(tail_marking_icon && !tail_marking_style.tails_allowed)
tail_s.Blend(tail_marking_icon, ICON_OVERLAY)
if((!body_accessory || istype(body_accessory, /datum/body_accessory/tail)) && dna.species.bodyflags & TAIL_OVERLAPPED) // If the player has a species whose tail is overlapped by limbs... (having a non-tail body accessory like the snake body will override this)
// Gives the underlimbs layer SEW direction icons since it's overlayed by limbs and just about everything else anyway.
var/icon/under = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "blank")
@@ -319,6 +319,10 @@
if(ignoreslow)
return // Only malusses after here
if(!IS_HORIZONTAL(H) || (HAS_TRAIT(H, TRAIT_NOKNOCKDOWNSLOWDOWN) && !H.resting))
if(HAS_TRAIT(H, TRAIT_GOTTAGOSLOW))
. += 1
if(H.dna.species.spec_movement_delay()) //Species overrides for slowdown due to feet/legs
. += 2 * H.stance_damage //damaged/missing feet or legs is slow
@@ -512,23 +516,8 @@
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm [target]!</span>")
return FALSE
//Vampire code
var/datum/antagonist/vampire/V = user?.mind?.has_antag_datum(/datum/antagonist/vampire)
if(V && !V.draining && user.zone_selected == "head" && target != user)
if((NO_BLOOD in target.dna.species.species_traits) || !target.blood_volume)
to_chat(user, "<span class='warning'>They have no blood!</span>")
return
if(target.mind && (target.mind.has_antag_datum(/datum/antagonist/vampire) || target.mind.has_antag_datum(/datum/antagonist/mindslave/thrall)))
to_chat(user, "<span class='warning'>Your fangs fail to pierce [target.name]'s cold flesh</span>")
return
if(HAS_TRAIT(target, TRAIT_SKELETONIZED))
to_chat(user, "<span class='warning'>There is no blood in a skeleton!</span>")
return
//we're good to suck the blood, blaah
V.handle_bloodsucking(target)
add_attack_logs(user, target, "vampirebit")
return
//end vampire codes
if(target != user && handle_harm_antag(user, target))
return FALSE
if(target.check_block())
target.visible_message("<span class='warning'>[target] blocks [user]'s attack!</span>")
return FALSE
@@ -536,45 +525,45 @@
return FALSE
if(attacker_style && attacker_style.harm_act(user, target) == MARTIAL_ARTS_ACT_SUCCESS)
return TRUE
else
var/datum/unarmed_attack/attack = user.dna.species.unarmed
user.do_attack_animation(target, attack.animation_type)
if(attack.harmless)
playsound(target.loc, attack.attack_sound, 25, 1, -1)
target.visible_message("<span class='danger'>[user] [pick(attack.attack_verb)]ed [target]!</span>")
return FALSE
add_attack_logs(user, target, "Melee attacked with fists", target.ckey ? null : ATKLOG_ALL)
if(!iscarbon(user))
target.LAssailant = null
else
target.LAssailant = user
target.lastattacker = user.real_name
target.lastattackerckey = user.ckey
var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh)
damage += attack.damage
damage += user.physiology.melee_bonus
if(!damage)
playsound(target.loc, attack.miss_sound, 25, 1, -1)
target.visible_message("<span class='danger'>[user] tried to [pick(attack.attack_verb)] [target]!</span>")
return FALSE
var/obj/item/organ/external/affecting = target.get_organ(ran_zone(user.zone_selected))
var/armor_block = target.run_armor_check(affecting, MELEE)
playsound(target.loc, attack.attack_sound, 25, 1, -1)
var/datum/unarmed_attack/attack = user.get_unarmed_attack()
user.do_attack_animation(target, attack.animation_type)
if(attack.harmless)
playsound(target.loc, attack.attack_sound, 25, TRUE, -1)
target.visible_message("<span class='danger'>[user] [pick(attack.attack_verb)]ed [target]!</span>")
target.apply_damage(damage, BRUTE, affecting, armor_block, sharp = attack.sharp)
if((target.stat != DEAD) && damage >= user.dna.species.punchstunthreshold)
target.visible_message("<span class='danger'>[user] has knocked down [target]!</span>", \
"<span class='userdanger'>[user] has knocked down [target]!</span>")
target.KnockDown(4 SECONDS)
SEND_SIGNAL(target, COMSIG_PARENT_ATTACKBY)
return FALSE
add_attack_logs(user, target, "Melee attacked with fists", target.ckey ? null : ATKLOG_ALL)
if(!iscarbon(user))
target.LAssailant = null
else
target.LAssailant = user
target.lastattacker = user.real_name
target.lastattackerckey = user.ckey
var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh)
damage += attack.damage
damage += user.physiology.melee_bonus
if(!damage)
playsound(target.loc, attack.miss_sound, 25, TRUE, -1)
target.visible_message("<span class='danger'>[user] tried to [pick(attack.attack_verb)] [target]!</span>")
return FALSE
var/obj/item/organ/external/affecting = target.get_organ(ran_zone(user.zone_selected))
var/armor_block = target.run_armor_check(affecting, MELEE)
playsound(target.loc, attack.attack_sound, 25, TRUE, -1)
target.visible_message("<span class='danger'>[user] [pick(attack.attack_verb)]ed [target]!</span>")
target.apply_damage(damage, BRUTE, affecting, armor_block, sharp = attack.sharp)
if((target.stat != DEAD) && damage >= user.dna.species.punchstunthreshold)
target.visible_message("<span class='danger'>[user] has knocked down [target]!</span>", \
"<span class='userdanger'>[user] has knocked down [target]!</span>")
target.KnockDown(4 SECONDS)
SEND_SIGNAL(target, COMSIG_PARENT_ATTACKBY)
/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(user == target)
@@ -1077,3 +1066,105 @@ It'll return null if the organ doesn't correspond, so include null checks when u
else
var/obj/item/organ/external/head/HD = H.get_organ("head")
return HD?.hair_colour
/datum/species/proc/handle_harm_antag(mob/living/carbon/human/user, mob/living/carbon/human/target)
if(!istype(target))
return
if(HAS_TRAIT(user, TRAIT_I_WANT_BRAINS))
var/obj/item/grab/grabby = user.get_inactive_hand()
if(istype(grabby))
if(ismachineperson(target))
to_chat(user, "<span class='warning zombie'>We can't smell any brains in [target].</span>")
return FALSE
if(grabby.state < GRAB_AGGRESSIVE)
to_chat(user, "<span class='warning zombie'>We need a better grip on [target] to bite them!</span>")
return TRUE
if(HAS_TRAIT(target, TRAIT_PIERCEIMMUNE))
to_chat(user, "<span class='warning zombie'>Our bite fails to pierce [target]!</span>")
return FALSE
user.visible_message("<span class='danger'>[user] violently bites [target]!</span>")
playsound(user.loc, 'sound/weapons/bite.ogg', 20, TRUE)
playsound(user.loc, 'sound/misc/moist_impact.ogg', 50, TRUE)
user.do_attack_animation(target, ATTACK_EFFECT_BITE)
target.apply_damage(20, BRUTE, user.zone_selected)
if(!target.HasDisease(/datum/disease/zombie))
var/datum/disease/zombie/zomb = new /datum/disease/zombie
if(target.CanContractDisease(zomb)) // biosuit aint going to protect you buddy
target.ForceContractDisease(zomb)
target.Dizzy(10 SECONDS)
target.Confused(10 SECONDS)
else
qdel(zomb)
for(var/datum/disease/zombie/zomb in target.viruses)
zomb.stage = max(rand(3, 4), zomb.stage)
qdel(grabby)
return TRUE
if(HAS_TRAIT(target, TRAIT_I_WANT_BRAINS))
to_chat(user, "<span class='warning zombie'>We can't smell any fresh brains in [target].</span>")
return
var/obj/item/organ/internal/brain/eat_brain = target.get_organ_slot("brain")
if(!eat_brain || ismachineperson(target))
to_chat(user, "<span class='warning zombie'>We can't smell any brains in [target].</span>")
return FALSE
var/obj/item/organ/external/brain_house = target.get_limb_by_name(eat_brain.parent_organ)
if(!brain_house)
to_chat(user, "<span class='warning zombie'>We can't smell any brains in [target].</span>")
return FALSE
if(brain_house.limb_name != user.zone_selected || !brain_house.open)
return FALSE
if(target.getarmor(brain_house, MELEE) > 0) // dont count negative armor
to_chat(user, "<span class='warning zombie'>[target]'s brains are blocked.</span>")
return FALSE // Armor blocks zombies trying to eat your brains!
if(target.getBrainLoss() >= 120)
to_chat(user, "<span class='warning zombie'>No more brains left...</span>")
return TRUE
eat_brain.custom_pain("OH GOD!!! THEY'RE EATING MY [uppertext(eat_brain.name)]!!") // gnarly
user.visible_message("<span class='danger'>[user] digs their claws into [target]'s [brain_house.name], eating their [eat_brain]!</span>", "<span class='danger zombie'>We feast on [target]'s brains.</span>")
if(!target.HasDisease(/datum/disease/zombie))
var/datum/disease/zombie/zomb = new /datum/disease/zombie
target.ContractDisease(zomb)
for(var/datum/disease/zombie/zomb in target.viruses)
zomb.stage = max(5, zomb.stage)
if(!do_mob(user, target, 1 SECONDS))
return
playsound(user.loc, 'sound/items/eatfood.ogg', 20, TRUE)
playsound(user.loc, 'sound/misc/moist_impact.ogg', 50, TRUE)
user.do_attack_animation(target, ATTACK_EFFECT_BITE)
target.adjustBrainLoss(5)
if(target.stat == CONSCIOUS && prob(33))
// Ouch, eaten alive.
target.emote("scream")
if(user.nutrition < NUTRITION_LEVEL_FULL - 10) // no fat zombies
user.set_nutrition(user.nutrition + 10)
user.heal_overall_damage(2, 2)
return TRUE
//Vampire code
var/datum/antagonist/vampire/V = user?.mind?.has_antag_datum(/datum/antagonist/vampire)
if(V && !V.draining && user.zone_selected == BODY_ZONE_HEAD)
if((NO_BLOOD in target.dna.species.species_traits) || !target.blood_volume)
to_chat(user, "<span class='warning'>They have no blood!</span>")
return TRUE
if(target.mind && (target.mind.has_antag_datum(/datum/antagonist/vampire) || target.mind.has_antag_datum(/datum/antagonist/mindslave/thrall)))
to_chat(user, "<span class='warning'>Your fangs fail to pierce [target.name]'s cold flesh!</span>")
return TRUE
if(HAS_TRAIT(target, TRAIT_SKELETONIZED))
to_chat(user, "<span class='warning'>There is no blood in a skeleton!</span>")
return TRUE
//we're good to suck the blood, blaah
V.handle_bloodsucking(target)
add_attack_logs(user, target, "vampirebit")
return TRUE
//end vampire codes
+1 -1
View File
@@ -119,7 +119,7 @@
if(!istype(H))
return ..()
// special handling here: we don't want monkeys' gasps to sound through walls so you can actually walk past xenobio
playsound(user.loc, sound_path, sound_volume, TRUE, -8, frequency = H.get_age_pitch(H.dna.species.max_age), ignore_walls = !isnull(user.mind))
playsound(user.loc, sound_path, sound_volume, TRUE, -8, frequency = H.get_age_pitch(H.dna.species.max_age) * alter_emote_pitch(user), ignore_walls = !isnull(user.mind))
/datum/emote/living/drool
key = "drool"
+3
View File
@@ -64,6 +64,9 @@
clean_grabbed_by(assailant, affecting)
adjust_position()
if(HAS_TRAIT(assailant, TRAIT_SLOW_GRABBER))
assailant.changeNext_move(1.5 * CLICK_CD_MELEE)
/obj/item/grab/Destroy()
if(affecting)
UnregisterSignal(affecting, COMSIG_MOVABLE_MOVED)