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-31 02:17:31 +00:00
committed by GitHub
co-authored by Burzah DGamerL
parent 247e24ba9f
commit bc0c8344cf
62 changed files with 1326 additions and 148 deletions
@@ -68,6 +68,14 @@
SEND_SIGNAL(U, COMSIG_LIVING_CLEAR_STUNS)
to_chat(user, "<span class='notice'>You instill your body with clean blood and remove any incapacitating effects.</span>")
var/datum/antagonist/vampire/V = U.mind.has_antag_datum(/datum/antagonist/vampire)
for(var/datum/disease/zombie/zombie_infection in U.viruses)
zombie_infection.stage = min(zombie_infection.stage, round(7 - (V.bloodtotal/100))) // 700 max usable blood can cleanse any zombie infection
if(zombie_infection.stage <= 0)
zombie_infection.cure()
to_chat(user, "<span class='notice'>You cleanse the plague from your system.</span>")
else
to_chat(user, "<span class='warning'>You weaken the plague in your system, but you don't have enough blood to completely remove it.</span>")
var/rejuv_bonus = V.get_rejuv_bonus()
if(rejuv_bonus)
INVOKE_ASYNC(src, PROC_REF(heal), U, rejuv_bonus)
@@ -0,0 +1,87 @@
RESTRICT_TYPE(/datum/antagonist/zombie)
/datum/antagonist/zombie
name = "Zombie"
antag_hud_name = "hudzombie"
antag_hud_type = ANTAG_HUD_ZOMBIE
special_role = SPECIAL_ROLE_ZOMBIE
clown_gain_text = "B-Braaaaaains... Honk..."
clown_removal_text = "You feel funnier again."
var/list/old_languages = list() // someone make this better to prevent langs changing if species changes while zombie somehow
var/static/list/zombie_traits = list(TRAIT_LANGUAGE_LOCKED, TRAIT_GOTTAGOSLOW, TRAIT_ABSTRACT_HANDS, TRAIT_SLOW_GRABBER)
var/datum/unarmed_attack/claws/claw_attack
// possibly upgrades for the zombies after eating brains? Better vision (/datum/action/changeling/augmented_eyesight), better weapons (armblade), better infection, more inhereint armor (physiology)
// ability to find nearby brains to eat (like cling/vamp ability to track people around them)
/datum/antagonist/zombie/on_gain()
. = ..()
owner.AddSpell(new /datum/spell/zombie_claws)
claw_attack = new /datum/unarmed_attack/claws()
/datum/antagonist/zombie/Destroy(force, ...)
QDEL_NULL(claw_attack)
return ..()
/datum/antagonist/zombie/detach_from_owner()
owner.RemoveSpell(/datum/spell/zombie_claws)
return ..()
/datum/antagonist/zombie/greet()
var/list/messages = list()
. = messages
if(owner && owner.current)
messages.Add("<span class='userdanger zombie'>We are a [special_role]!</span>")
messages.Add("<span class='zombie'>You can feel your heart stopping, but something isn't right... life has not abandoned your broken form. You can only feel a deep and immutable hunger that not even death can stop.</span>")
/datum/antagonist/zombie/finalize_antag()
var/list/messages = list()
. = messages
if(owner && owner.current)
messages.Add("<br><span class='notice'>You can use your claws to break down doors, and to crack open damaged skulls. Once their head is open, use an empty hand to eat their brains. Alternatively, grab someone aggressively and them harm them to bite and infect them. You heal slowly but you heal faster in the dark, after death you will slowly revive and reawaken.</span>")
/datum/antagonist/zombie/apply_innate_effects(mob/living/mob_override)
var/mob/living/L = ..()
old_languages = L.languages.Copy()
for(var/datum/language/lang as anything in L.languages)
L.remove_language(lang.name)
L.add_language("Zombie")
L.default_language = GLOB.all_languages["Zombie"]
L.extinguish_light() // zombies prefer darkness
for(var/trait in zombie_traits)
ADD_TRAIT(L, trait, ZOMBIE_TRAIT)
if(!L.HasDisease(/datum/disease/zombie))
var/datum/disease/zombie/zomb = new /datum/disease/zombie()
zomb.stage = 7
L.AddDisease(zomb)
if(ishuman(L))
var/mob/living/carbon/human/H = L
H.physiology.stamina_mod *= 0.5
/datum/antagonist/zombie/remove_innate_effects(mob/living/mob_override)
var/mob/living/L = ..()
if(!ishuman(L))
STOP_PROCESSING(SSobj, src) // This is to handle when they transfer into a headslug (simple animal). We shouldn't process in that case.
for(var/trait in zombie_traits)
REMOVE_TRAIT(L, trait, ZOMBIE_TRAIT)
L.remove_language("Zombie")
for(var/datum/language/lang as anything in old_languages)
L.add_language(lang.name)
L.default_language = null
if(ishuman(L))
var/mob/living/carbon/human/H = L
H.physiology.stamina_mod /= 0.5
/datum/antagonist/zombie/on_body_transfer(mob/living/old_body, mob/living/new_body)
if(!new_body.HasDisease(/datum/disease/zombie))
owner.remove_antag_datum(/datum/antagonist/zombie)
return
return ..()
/datum/antagonist/zombie/give_objectives()
add_antag_objective(/datum/objective/zombie)
@@ -0,0 +1,150 @@
/datum/spell/zombie_claws
name = "Zombie Claws"
desc = "Toggle your claws, allowing you to slash and infect other people."
action_icon_state = "vampire_claws"
action_background_icon_state = "bg_vampire"
human_req = TRUE
clothes_req = FALSE
base_cooldown = 0 SECONDS
var/list/our_claws = list()
var/infection_stage = 1 // mostly for adminbus and testing
/datum/spell/zombie_claws/Destroy()
QDEL_LIST_CONTENTS(our_claws)
return ..()
/datum/spell/zombie_claws/cast(mob/user)
if(dispel())
return
var/obj/item/zombie_claw/claws = new /obj/item/zombie_claw(user.loc, src)
claws.infection_stage = infection_stage
if(user.put_in_hands(claws))
our_claws += claws
else
qdel(claws)
to_chat(user, "<span class='warning zombie'>We have no claws...</span>")
/datum/spell/zombie_claws/proc/dispel()
var/mob/living/carbon/human/user = action.owner
var/obj/item/zombie_claw/claw = user.get_active_hand()
if(istype(claw, /obj/item/zombie_claw))
qdel(claw)
return TRUE
/datum/spell/zombie_claws/can_cast(mob/user, charge_check, show_message)
var/mob/living/L = user
if(!L.get_active_hand() || istype(L.get_active_hand(), /obj/item/zombie_claw))
return ..()
/datum/spell/zombie_claws/create_new_targeting()
return new /datum/spell_targeting/self
/obj/item/zombie_claw
name = "claws"
desc = "Claws extending from your rotting hands, perfect for ripping open brain_holders for brains."
icon = 'icons/effects/vampire_effects.dmi'
icon_state = "vamp_claws"
lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons_righthand.dmi'
w_class = WEIGHT_CLASS_BULKY
flags = ABSTRACT | NODROP | DROPDEL
gender = PLURAL
force = 21 // allows them to break down doors aka NOT FUCKING AROUND
armour_penetration_percentage = -20
attack_effect_override = ATTACK_EFFECT_CLAW
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("slashed", "sliced", "torn", "ripped", "mauled", "cut", "savaged", "clawed")
sprite_sheets_inhand = list("Vox" = 'icons/mob/clothing/species/vox/held.dmi', "Drask" = 'icons/mob/clothing/species/drask/held.dmi')
var/datum/spell/zombie_claws/parent_spell
var/force_weak = 10
var/infection_stage = 1
/obj/item/zombie_claw/Initialize(mapload, new_parent_spell)
. = ..()
parent_spell = new_parent_spell
RegisterSignal(parent_spell.action.owner, COMSIG_MOB_WILLINGLY_DROP, PROC_REF(dispel))
/obj/item/zombie_claw/proc/dispel(mob/user)
if(user && user.get_active_hand() == src)
qdel(src)
/obj/item/zombie_claw/Destroy()
UnregisterSignal(parent_spell.action.owner, COMSIG_MOB_WILLINGLY_DROP)
if(parent_spell)
parent_spell.our_claws -= src
parent_spell = null
return ..()
/obj/item/zombie_claw/customised_abstract_text(mob/living/carbon/owner)
return "<span class='warning'>[owner.p_they(TRUE)] [owner.p_have(FALSE)] dull claws extending from [owner.p_their(FALSE)] [owner.l_hand == src ? "left hand" : "right hand"].</span>"
/obj/item/zombie_claw/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(user.reagents.has_reagent("zombiecure2"))
force = force_weak
else
force = initial(force)
/obj/item/zombie_claw/afterattack(atom/atom_target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag)
return
if(!ishuman(atom_target) || ismachineperson(atom_target))
return
var/mob/living/carbon/human/target = atom_target
try_infect(target, user)
var/obj/item/organ/internal/brain/eat_brain = target.get_organ_slot("brain")
if(!eat_brain)
return
var/obj/item/organ/external/brain_holder = target.get_limb_by_name(eat_brain.parent_organ)
if(!brain_holder || brain_holder.open || brain_holder.limb_name != user.zone_selected)
return
// Max damage - 5
if(brain_holder.brute_dam + brain_holder.burn_dam <= brain_holder.max_damage - 5) // Deal more damage
return
if(target.getarmor(brain_holder, MELEE) > 0) // dont count negative armor
to_chat(user, "<span class='warning zombie'>[target]'s brains are blocked.</span>")
return // Armor blocks zombies trying to eat your brains!
to_chat(target, "<span class='userdanger'[user]'s claws dig into your [brain_holder.encased]!</span>")
user.visible_message("<span class='danger'>[user] digs their claws into [target]'s [brain_holder.name]!</span>", "<span class='danger zombie'>We dig into [target]'s [brain_holder.encased ? brain_holder.encased : brain_holder]...</span>")
playsound(user, 'sound/weapons/armblade.ogg', 50, TRUE)
if(!do_mob(user, target, 3 SECONDS))
return FALSE
playsound(user.loc, 'sound/misc/moist_impact.ogg', 50, TRUE)
brain_holder.fracture()
brain_holder.broken_description = "split open"
brain_holder.open = ORGAN_ORGANIC_VIOLENT_OPEN
to_chat(target, "<span class='userdanger'>Your [brain_holder.name] is violently cracked open!</span>")
user.visible_message("<span class='danger'>[user] violently splits apart [target]'s [brain_holder.name]!</span>", "<span class='danger zombie'>We crack apart [target]'s [brain_holder.name]!</span>")
return TRUE
/obj/item/zombie_claw/proc/try_infect(mob/living/carbon/human/target, mob/living/user)
if(!ishuman(target))
return
if(!(user.zone_selected in list(BODY_ZONE_CHEST, BODY_ZONE_HEAD)))
to_chat(user, "<span class='warning zombie'>Our infection cannot spread without their head or chest.</span>")
return
if(HAS_TRAIT(target, TRAIT_PIERCEIMMUNE))
return FALSE
if(target.reagents.has_reagent("zombiecure1") || target.reagents.has_reagent("spaceacillin"))
return
if(prob(3 * target.getarmor(user.zone_selected, MELEE)) || prob(50)) // more than 33.34 melee armor will always protect you! Or just get lucky B)
return // Armor blocks zombies trying to eat your brains!
// already have the disease, or have contracted it. Good for feedback when being attacked while wearing a biosuit
if(target.HasDisease(/datum/disease/zombie) || target.ContractDisease(new /datum/disease/zombie))
playsound(user.loc, 'sound/misc/moist_impact.ogg', 50, TRUE)
target.bleed_rate = max(5, target.bleed_rate + 1) // it transfers via blood, you know. It had to get in somehow.
for(var/datum/disease/zombie/zomb in target.viruses)
zomb.stage = max(zomb.stage, infection_stage)
/obj/item/zombie_claw/attack_self(mob/user)
. = ..()
qdel(src)