mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-18 18:44:48 +01:00
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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user