Skip to content

Commit

Permalink
Merge pull request #1062 from crix870/zombies
Browse files Browse the repository at this point in the history
Deadite changes: gags, gear, and undead eyes
  • Loading branch information
Lutowski authored Jan 3, 2025
2 parents 189341e + 5e235fb commit 2abdf40
Show file tree
Hide file tree
Showing 23 changed files with 522 additions and 256 deletions.
28 changes: 22 additions & 6 deletions code/_onclick/other_mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,12 @@
/mob/living/onbite(mob/living/carbon/human/user)
return

///Initial bite on target
/mob/living/carbon/onbite(mob/living/carbon/human/user)
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, span_warning("I don't want to harm [src]!"))
return FALSE
if(user.mouth)
if(!user.can_bite())
to_chat(user, span_warning("My mouth has something in it."))
return FALSE

Expand Down Expand Up @@ -198,19 +199,34 @@

next_attack_msg.Cut()

//nodmg if they don't have an open wound
//nodmg if we don't have strongbite
//nodmg if our teeth can't break through their armour

if(!nodmg)
playsound(src, "smallslash", 100, TRUE, -1)
if(ishuman(src) && user.mind)
var/mob/living/carbon/human/bite_victim = src
/*
WEREWOLF INFECTION VIA BITE
*/
if(istype(user.dna.species, /datum/species/werewolf))
if(HAS_TRAIT(src, TRAIT_SILVER_BLESSED))
to_chat(user, span_warning("BLEH! [src] tastes of SILVER! My gift cannot take hold."))
to_chat(user, span_warning("BLEH! [bite_victim] tastes of SILVER! My gift cannot take hold."))
else
caused_wound?.werewolf_infect_attempt()
if(prob(30))
user.werewolf_feed(src, 10)
if(user.mind.has_antag_datum(/datum/antagonist/zombie) && !src.mind.has_antag_datum(/datum/antagonist/zombie))
INVOKE_ASYNC(TYPE_PROC_REF(/mob/living/carbon/human, zombie_infect_attempt))

user.werewolf_feed(bite_victim, 10)

/*
ZOMBIE INFECTION VIA BITE
*/
var/datum/antagonist/zombie/zombie_antag = user.mind.has_antag_datum(/datum/antagonist/zombie)
if(zombie_antag && zombie_antag.has_turned)
zombie_antag.last_bite = world.time
if(bite_victim.zombie_infect_attempt()) // infect_attempt on bite
to_chat(user, span_danger("You feel your gift trickling from your mouth into [bite_victim]'s wound..."))

var/obj/item/grabbing/bite/B = new()
user.equip_to_slot_or_del(B, SLOT_MOUTH)
if(user.mouth == B)
Expand Down
34 changes: 23 additions & 11 deletions code/datums/components/rotting.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#define DEAD_TO_ZOMBIE_TIME 3 MINUTES ///Time before death -> raised as zombie (when outside of the city)

/datum/component/rot
var/amount = 0
var/last_process = 0
Expand All @@ -21,18 +23,26 @@
. = ..()

/datum/component/rot/process()
var/amt2add = 10 //1 second
if(last_process)
amt2add = ((world.time - last_process)/10) * amt2add
last_process = world.time
amount += amt2add

var/amt2add = 10 // 1 Second. Base increment.
var/current_time = world.time

// time elapsed since the last rot/process
var/elapsed_time = last_process ? (current_time - last_process) : 0
last_process = current_time

// Add amount based on the time elapsed. This is used to calculate when to wake/decompose
amount += (elapsed_time / 10) * amt2add

return

/datum/component/rot/corpse/Initialize()
if(!iscarbon(parent))
return COMPONENT_INCOMPATIBLE
. = ..()

/*
ZOMBIFICATION
*/
/datum/component/rot/corpse/process()
..()
var/mob/living/carbon/C = parent
Expand All @@ -50,25 +60,25 @@
qdel(src)
return

if(amount > 4 MINUTES)
if(amount > DEAD_TO_ZOMBIE_TIME)
if(is_zombie)
var/datum/antagonist/zombie/Z = C.mind.has_antag_datum(/datum/antagonist/zombie)
if(Z && !Z.has_turned && !Z.revived && C.stat == DEAD)
Z.wake_zombie()
wake_zombie(C, infected_wake = TRUE, converted = FALSE)

var/findonerotten = FALSE
var/shouldupdate = FALSE
var/dustme = FALSE
for(var/obj/item/bodypart/B in C.bodyparts)
if(!B.skeletonized && B.is_organic_limb())
if(!B.rotted)
if(amount > 10 MINUTES)
if(amount > 20 MINUTES)
B.rotted = TRUE
findonerotten = TRUE
shouldupdate = TRUE
C.change_stat("constitution", -8, "rottenlimbs")
else
if(amount > 25 MINUTES)
if(amount > 40 MINUTES)
if(!is_zombie)
B.skeletonize()
if(C.dna && C.dna.species)
Expand All @@ -77,7 +87,7 @@
shouldupdate = TRUE
else
findonerotten = TRUE
if(amount > 35 MINUTES)
if(amount > 35 MINUTES) // Code to delete a corpse after 35 minutes if it's not a zombie and not skeletonized. Possible failsafe.
if(!is_zombie)
if(B.skeletonized)
dustme = TRUE
Expand Down Expand Up @@ -131,3 +141,5 @@
mid_length = 60
volume = 50
extra_range = 0

#undef DEAD_TO_ZOMBIE_TIME
7 changes: 5 additions & 2 deletions code/datums/mind.dm
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@
memory = null

// Datum antag mind procs
/datum/mind/proc/add_antag_datum(datum_type_or_instance, team)
/datum/mind/proc/add_antag_datum(datum_type_or_instance, team, admin_panel)
if(!datum_type_or_instance)
return
var/datum/antagonist/A
Expand All @@ -475,7 +475,10 @@
var/datum/team/antag_team = A.get_team()
if(antag_team)
antag_team.add_member(src)
A.on_gain()
if(admin_panel) //Admin panelled has special behaviour with zombie
A.on_gain(TRUE)
else
A.on_gain()
log_game("[key_name(src)] has gained antag datum [A.name]([A.type])")
return A

Expand Down
42 changes: 1 addition & 41 deletions code/datums/wounds/_wound.dm
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,7 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
/// Some wounds make no sense on a dismembered limb and need to go
var/qdel_on_droplimb = FALSE

/// Werewolf infection probability for bites on this wound
var/werewolf_infection_probability = 15
/// Time taken until werewolf infection comes in
var/werewolf_infection_time = 2 MINUTES
/// Actual infection timer
var/werewolf_infection_timer


/datum/wound/Destroy(force)
. = ..()
Expand Down Expand Up @@ -329,41 +324,6 @@ GLOBAL_LIST_INIT(primordial_wounds, init_primordial_wounds())
/datum/wound/proc/is_clotted()
return !isnull(clotting_threshold) && (bleed_rate <= clotting_threshold)

/datum/wound/proc/werewolf_infect_attempt()
if(QDELETED(src) || QDELETED(owner) || QDELETED(bodypart_owner))
return FALSE
if(werewolf_infection_timer || !ishuman(owner) || !prob(werewolf_infection_probability))
return
var/mob/living/carbon/human/human_owner = owner
if(!human_owner.can_werewolf())
return
if(human_owner.stat >= DEAD) //forget it
return
to_chat(human_owner, span_danger("I feel horrible... REALLY horrible..."))
human_owner.mob_timers["puke"] = world.time
human_owner.vomit(1, blood = TRUE, stun = FALSE)
werewolf_infection_timer = addtimer(CALLBACK(src, PROC_REF(wake_werewolf)), werewolf_infection_time, TIMER_STOPPABLE)
severity = WOUND_SEVERITY_BIOHAZARD
if(bodypart_owner)
sortTim(bodypart_owner.wounds, GLOBAL_PROC_REF(cmp_wound_severity_dsc))
return TRUE

/datum/wound/proc/wake_werewolf()
if(QDELETED(src) || QDELETED(owner) || QDELETED(bodypart_owner))
return FALSE
if(!ishuman(owner))
return FALSE
var/mob/living/carbon/human/human_owner = owner
var/datum/antagonist/werewolf/wolfy = human_owner.werewolf_check()
if(!wolfy)
return FALSE
werewolf_infection_timer = null
owner.flash_fullscreen("redflash3")
to_chat(owner, span_danger("It hurts... Is this really the end for me?"))
owner.emote("scream") // heres your warning to others bro
owner.Knockdown(1)
return wolfy

/// Returns whether or not this wound should embed a weapon
/proc/should_embed_weapon(datum/wound/wound_or_boolean, obj/item/weapon)
if(!istype(wound_or_boolean))
Expand Down
4 changes: 3 additions & 1 deletion code/game/objects/items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -679,9 +679,11 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(!disable_warning)
to_chat(M, span_warning("[src] is too bulky to carry with anything but my hands!"))
return 0

if(!M)
return FALSE
if(HAS_TRAIT(M, TRAIT_CHUNKYFINGERS) && (!equipper || equipper == M) && src.type != /obj/item/grabbing/bite) //If a zombie's trying to put something on without assistance that's not a bite
to_chat(M, span_warning("...What?"))
return FALSE

return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self)

Expand Down
15 changes: 15 additions & 0 deletions code/game/objects/items/rogueweapons/intents.dm
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,23 @@
return

/datum/intent/unarmed/claw
name = "claw"
//icon_state
attack_verb = list("mauls", "scratches", "claws")
chargetime = 0
animname = "blank22"
hitsound = list('sound/combat/hits/punch/punch (1).ogg', 'sound/combat/hits/punch/punch (2).ogg', 'sound/combat/hits/punch/punch (3).ogg')
misscost = 5
releasedrain = 5
swingdelay = 0
penfactor = 10
candodge = TRUE
canparry = TRUE
blade_class = BCLASS_CUT
miss_text = "claw at the air"
miss_sound = "punchwoosh"
item_d_type = "slash"


/datum/intent/unarmed/shove
name = "shove"
Expand Down
3 changes: 3 additions & 0 deletions code/game/objects/structures/roguewindow.dm
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@
if(brokenstate)
return
user.changeNext_move(CLICK_CD_MELEE)
if(HAS_TRAIT(user, TRAIT_BASHDOORS))
src.take_damage(15)
return
src.visible_message(span_info("[user] knocks on [src]."))
add_fingerprint(user)
playsound(src, 'sound/misc/glassknock.ogg', 100)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/antagonists/_common/antag_datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/admin_add(datum/mind/new_owner,mob/admin)
message_admins("[key_name_admin(admin)] made [key_name_admin(new_owner)] into [name].")
log_admin("[key_name(admin)] made [key_name(new_owner)] into [name].")
new_owner.add_antag_datum(src)
new_owner.add_antag_datum(datum_type_or_instance = src, team = null, admin_panel = TRUE)

//Called when removing antagonist using admin tools
/datum/antagonist/proc/admin_remove(mob/user)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/datum/wound
/// Werewolf infection probability for bites on this wound
var/werewolf_infection_probability = 15
/// Time taken until werewolf infection comes in
var/werewolf_infection_time = 2 MINUTES
/// Actual infection timer
var/werewolf_infection_timer

/datum/wound/proc/werewolf_infect_attempt()
if(QDELETED(src) || QDELETED(owner) || QDELETED(bodypart_owner))
return FALSE
if(werewolf_infection_timer || !ishuman(owner) || !prob(werewolf_infection_probability))
return
var/mob/living/carbon/human/human_owner = owner
if(!human_owner.can_werewolf())
return
if(human_owner.stat >= DEAD) //forget it
return
to_chat(human_owner, span_danger("I feel horrible... REALLY horrible..."))
human_owner.mob_timers["puke"] = world.time
human_owner.vomit(1, blood = TRUE, stun = FALSE)
werewolf_infection_timer = addtimer(CALLBACK(src, PROC_REF(wake_werewolf)), werewolf_infection_time, TIMER_STOPPABLE)
severity = WOUND_SEVERITY_BIOHAZARD
if(bodypart_owner)
sortTim(bodypart_owner.wounds, GLOBAL_PROC_REF(cmp_wound_severity_dsc))
return TRUE

/datum/wound/proc/wake_werewolf()
if(QDELETED(src) || QDELETED(owner) || QDELETED(bodypart_owner))
return FALSE
if(!ishuman(owner))
return FALSE
var/mob/living/carbon/human/human_owner = owner
var/datum/antagonist/werewolf/wolfy = human_owner.werewolf_check()
if(!wolfy)
return FALSE
werewolf_infection_timer = null
owner.flash_fullscreen("redflash3")
to_chat(owner, span_danger("It hurts... Is this really the end for me?"))
owner.emote("scream") // heres your warning to others bro
owner.Knockdown(1)
return wolfy
69 changes: 69 additions & 0 deletions code/modules/antagonists/roguetown/villain/zombie/remove_rot.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/proc/remove_rot(mob/living/carbon/human/target, mob/living/user, method = "unknown", damage = 0, success_message = "The rot is removed.", fail_message = "The rot removal failed.")
if (!istype(target, /mob/living/carbon/human) || QDELETED(target))
return FALSE

// Check if the target has rot
var/has_rot = FALSE
var/datum/antagonist/zombie/was_zombie = target.mind?.has_antag_datum(/datum/antagonist/zombie)

if (was_zombie)
has_rot = TRUE
else if (istype(target, /mob/living/carbon))
has_rot = check_bodyparts_for_rot(target)

// Handle failure case
if (!has_rot)
to_chat(user, span_warning(fail_message))
return FALSE

if (was_zombie)
remove_zombie_antag(target, user, method)

// Remove rot component
remove_rot_component(target)

// Clean body parts
clean_body_parts(target)

//Doing it out of this proc for now
//to_chat(user, span_notice(success_message))

return TRUE

/proc/check_bodyparts_for_rot(mob/living/carbon/target)
for (var/obj/item/bodypart/bodypart in target.bodyparts)
if (bodypart.rotted || bodypart.skeletonized)
return TRUE
return FALSE


/proc/remove_zombie_antag(mob/living/carbon/target, mob/living/user, method)
var/datum/antagonist/zombie/was_zombie = target.mind?.has_antag_datum(/datum/antagonist/zombie)
if (!was_zombie)
return

was_zombie.become_rotman = FALSE
target.mind.remove_antag_datum(/datum/antagonist/zombie)
target.Unconscious(20 SECONDS)
target.emote("breathgasp")
target.Jitter(100)

if (!HAS_TRAIT(target, TRAIT_IWASUNZOMBIFIED) && user?.ckey)
adjust_playerquality(PQ_GAIN_UNZOMBIFY, user.ckey)
ADD_TRAIT(target, TRAIT_IWASUNZOMBIFIED, "[method]")

///Removes the rot amount from the target
/proc/remove_rot_component(mob/living/carbon/target)
var/datum/component/rot/rot = target.GetComponent(/datum/component/rot)
if (rot)
rot.amount = 0

///Cure bodyparts
/proc/clean_body_parts(mob/living/carbon/target)
for (var/obj/item/bodypart/bodypart in target.bodyparts)
bodypart.rotted = FALSE
bodypart.skeletonized = FALSE
bodypart.update_limb()
bodypart.update_disabled()

target.update_body()
Loading

0 comments on commit 2abdf40

Please sign in to comment.