From 8083b51a96f9dd05061cb46c2d886b7473cd0770 Mon Sep 17 00:00:00 2001 From: Couls Date: Thu, 16 May 2019 22:36:30 -0400 Subject: [PATCH 01/10] Initial commit --- code/__DEFINES/genetics.dm | 5 +- code/__DEFINES/is_helpers.dm | 1 + code/_globalvars/lists/objects.dm | 1 + code/datums/datumvars.dm | 17 +-- code/datums/uplink_item.dm | 8 ++ .../items/weapons/storage/uplink_kits.dm | 13 ++ code/modules/mob/living/carbon/human/life.dm | 1 - .../living/carbon/human/species/_species.dm | 11 +- .../living/carbon/human/species/zombies.dm | 70 +++++++++++ .../mob/living/carbon/human/status_procs.dm | 16 ++- code/modules/mob/mob_helpers.dm | 18 +++ .../reagents/chemistry/reagents/toxins.dm | 17 +++ .../reagents/reagent_containers/bottle.dm | 5 + code/modules/zombie/items.dm | 112 ++++++++++++++++++ code/modules/zombie/organs.dm | 87 ++++++++++++++ icons/obj/surgery.dmi | Bin 38790 -> 38952 bytes paradise.dme | 3 + 17 files changed, 361 insertions(+), 24 deletions(-) create mode 100644 code/modules/mob/living/carbon/human/species/zombies.dm create mode 100644 code/modules/zombie/items.dm create mode 100644 code/modules/zombie/organs.dm diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm index 0fb9253a083..bc8b8236032 100644 --- a/code/__DEFINES/genetics.dm +++ b/code/__DEFINES/genetics.dm @@ -23,6 +23,8 @@ // MUTATIONS /////////////////////////////////////// +#define CHECK_DNA_AND_SPECIES(C) if((!(C.dna)) || (!(C.dna.species))) return + // Generic mutations: #define TK 1 #define COLDRES 2 @@ -146,4 +148,5 @@ #define RESISTHOT 16 #define RESISTCOLD 17 #define NO_EXAMINE 18 -#define CAN_WINGDINGS 19 \ No newline at end of file +#define CAN_WINGDINGS 19 +#define NOZOMBIE 20 \ No newline at end of file diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index ba0d1858616..d793737eb6b 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -4,6 +4,7 @@ // Mobs #define ismegafauna(A) istype(A, /mob/living/simple_animal/hostile/megafauna) +#define iszombie(A) (is_species(A, /datum/species/zombie)) //Simple animals #define isshade(A) (istype(A, /mob/living/simple_animal/shade)) diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index e6f463d6f23..00417c5b47a 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -16,6 +16,7 @@ GLOBAL_LIST_INIT(prisoncomputer_list, list()) GLOBAL_LIST_INIT(celltimers_list, list()) // list of all cell timers GLOBAL_LIST_INIT(cell_logs, list()) GLOBAL_LIST_INIT(navigation_computers, list()) +GLOBAL_LIST_INIT(zombie_infection_list, list()) GLOBAL_LIST_INIT(all_areas, list()) GLOBAL_LIST_INIT(machines, list()) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 13c3fb64f33..17e1abf3b7b 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -738,22 +738,7 @@ if(!istype(M)) to_chat(usr, "This can only be used on instances of type /mob") return - to_chat(M, "Control of your mob has been offered to dead players.") - log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.") - var/minhours = input(usr, "Minimum hours required to play [M]?", "Set Min Hrs", 10) as num - message_admins("[key_name_admin(usr)] has offered control of ([key_name_admin(M)]) to ghosts with [minhours] hrs playtime") - var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as [M.real_name ? M.real_name : M.name]?", poll_time = 100, min_hours = minhours) - var/mob/dead/observer/theghost = null - - if(candidates.len) - theghost = pick(candidates) - to_chat(M, "Your mob has been taken over by a ghost!") - message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(M)])") - M.ghostize() - M.key = theghost.key - else - to_chat(M, "There were no ghosts willing to take control.") - message_admins("No ghosts were willing to take control of [key_name_admin(M)])") + offer_control(M) else if(href_list["delete"]) if(!check_rights(R_DEBUG, 0)) diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index b6167338ad3..4a21c92ffa9 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -190,6 +190,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 1 job = list("Clown") +/datum/uplink_item/stealthy_weapons/romerol_kit + name = "Romerol" + reference = "ROM" + desc = "A highly experimental bioterror agent which creates dormant nodules to be etched into the grey matter of the brain. On death, these nodules take control of the dead body, causing limited revivification, along with slurred speech, aggression, and the ability to infect others with this agent." + item = /obj/item/storage/box/syndie_kit/romerol + cost = 25 + //mime /datum/uplink_item/jobspecific/caneshotgun name = "Cane Shotgun and Assassination Shells" @@ -638,6 +645,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/dangerous/guardian name = "Holoparasites" + reference = "HPA" desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an organic host as a home base and source of fuel. \ The holoparasites are unable to incoporate themselves to changeling and vampire agents." item = /obj/item/storage/box/syndie_kit/guardian diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 56db11ad058..06ea21b4f4e 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -113,6 +113,19 @@ desc = "A sleek, sturdy box" icon_state = "box_of_doom" +/obj/item/storage/box/syndie_kit/romerol + name = "Romerol Kit" + desc = "A box containing a deadly virus capable of reanimating dead as zombies." + max_w_class = WEIGHT_CLASS_NORMAL + can_hold = list(/obj/item/reagent_containers/glass/bottle/romerol,/obj/item/reagent_containers/syringe,/obj/item/reagent_containers/dropper) + +/obj/item/storage/box/syndie_kit/romerol/New() + ..() + new /obj/item/reagent_containers/glass/bottle/romerol(src) + new /obj/item/reagent_containers/syringe(src) + new /obj/item/reagent_containers/dropper(src) + return + /obj/item/storage/box/syndie_kit/space name = "Boxed Space Suit and Helmet" can_hold = list(/obj/item/clothing/suit/space/syndicate/black/red, /obj/item/clothing/head/helmet/space/syndicate/black/red, /obj/item/tank/emergency_oxygen/syndi, /obj/item/clothing/mask/gas/syndicate) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index d6c667b1b74..fe048fb8137 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -14,7 +14,6 @@ handle_heartbeat() handle_drunk() dna.species.handle_life(src) - if(!client) dna.species.handle_npc(src) diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index 7dc6c042e0c..c82433e557e 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -51,9 +51,10 @@ var/clone_mod = 1 // Clone damage reduction/amplification var/brain_mod = 1 // Brain damage damage reduction/amplification var/stun_mod = 1 // If a species is more/less impacated by stuns/weakens/paralysis - + var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster + var/armor = 0 // overall defense for the race... or less defense, if it's negative. var/blood_damage_type = OXY //What type of damage does this species take if it's low on blood? - + var/obj/item/mutanthands var/total_health = 100 var/punchdamagelow = 0 //lowest possible punch damage var/punchdamagehigh = 9 //highest possible punch damage @@ -307,6 +308,12 @@ /datum/species/proc/handle_death(mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns). return +/datum/species/proc/spec_death(mob/living/carbon/human/C) + return + +/datum/species/proc/spec_stun(mob/living/carbon/human/H,amount) + return + /datum/species/proc/spec_electrocute_act(mob/living/carbon/human/H, shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE) return diff --git a/code/modules/mob/living/carbon/human/species/zombies.dm b/code/modules/mob/living/carbon/human/species/zombies.dm new file mode 100644 index 00000000000..9fa6cf37de2 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/zombies.dm @@ -0,0 +1,70 @@ +#define REGENERATION_DELAY 60 // After taking damage, how long it takes for automatic regeneration to begin + +/datum/species/zombie + // 1spooky + name = "High-Functioning Zombie" + name_plural = "High-Functioning Zombies" + icobase = 'icons/mob/human_races/r_human.dmi' + deform = 'icons/mob/human_races/r_def_human.dmi' + dies_at_threshold = TRUE + species_traits = list(NO_BLOOD,NOZOMBIE,NOTRANSSTING,NO_BREATHE, RADIMMUNE, NO_SCAN) + var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg') + warning_low_pressure = 50 + hazard_low_pressure = 0 + +/datum/species/zombie/infectious + name = "Infectious Zombie" + mutanthands = /obj/item/zombie_hand + armor = 20 // 120 damage to KO a zombie, which kills it + speedmod = 1.6 + var/heal_rate = 1 + var/regen_cooldown = 0 + +/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount) + . = min(20, amount) + +/datum/species/zombie/infectious/spec_attacked_by(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H) + if(.) + regen_cooldown = world.time + REGENERATION_DELAY + +/datum/species/zombie/infectious/handle_life(mob/living/carbon/human/C) + . = ..() + C.a_intent = INTENT_HARM // THE SUFFERING MUST FLOW + + //Zombies never actually die, they just fall down until they regenerate enough to rise back up. + //They must be restrained, beheaded or gibbed to stop being a threat. + if(regen_cooldown < world.time) + var/heal_amt = heal_rate + if(C.InCritical()) + heal_amt *= 2 + C.heal_overall_damage(heal_amt,heal_amt) + C.adjustToxLoss(-heal_amt) + if(!C.InCritical() && prob(4)) + playsound(C, pick(spooks), 50, TRUE, 10) + +//Congrats you somehow died so hard you stopped being a zombie +/datum/species/zombie/infectious/spec_death(mob/living/carbon/C) + . = ..() + var/obj/item/organ/internal/zombie_infection/infection + infection = C.get_organ_slot("zombie_infection") + if(infection) + qdel(infection) + +/datum/species/zombie/infectious/on_species_gain(mob/living/carbon/human/C, datum/species/old_species) + . = ..() + // Deal with the source of this zombie corruption + // Infection organ needs to be handled separately from mutant_organs + // because it persists through species transitions + if(mutanthands) + C.drop_l_hand() + C.drop_r_hand() + C.put_in_hands(new mutanthands()) + C.put_in_hands(new mutanthands()) + C.ChangeToHusk() + var/obj/item/organ/internal/zombie_infection/infection + infection = C.get_organ_slot("zombie_infection") + if(!infection) + infection = new() + infection.insert(C) + +#undef REGENERATION_DELAY diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 30653023751..10bbd27edcc 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -5,21 +5,29 @@ . = ..() /mob/living/carbon/human/SetStunned(amount, updating = 1, force = 0) - if(dna.species) + if(dna.species.stun_mod) amount = amount * dna.species.stun_mod + else + amount = dna.species.spec_stun(src,amount) ..() /mob/living/carbon/human/SetWeakened(amount, updating = 1, force = 0) - if(dna.species) + if(dna.species.stun_mod) amount = amount * dna.species.stun_mod + else + amount = dna.species.spec_stun(src,amount) ..() /mob/living/carbon/human/SetParalysis(amount, updating = 1, force = 0) - if(dna.species) + if(dna.species.stun_mod) amount = amount * dna.species.stun_mod + else + amount = dna.species.spec_stun(src,amount) ..() /mob/living/carbon/human/SetSleeping(amount, updating = 1, no_alert = FALSE) - if(dna.species) + if(dna.species.stun_mod) amount = amount * dna.species.stun_mod + else + amount = dna.species.spec_stun(src,amount) ..() \ No newline at end of file diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index beb474539f1..fa3275a053b 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -113,6 +113,24 @@ return U.sensor_mode return SUIT_SENSOR_OFF +/proc/offer_control(mob/M) + to_chat(M, "Control of your mob has been offered to dead players.") + log_admin("[key_name(usr)] has offered control of ([key_name(M)]) to ghosts.") + var/minhours = input(usr, "Minimum hours required to play [M]?", "Set Min Hrs", 10) as num + message_admins("[key_name_admin(usr)] has offered control of ([key_name_admin(M)]) to ghosts with [minhours] hrs playtime") + var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as [M.real_name ? M.real_name : M.name]?", poll_time = 100, min_hours = minhours) + var/mob/dead/observer/theghost = null + + if(candidates.len) + theghost = pick(candidates) + to_chat(M, "Your mob has been taken over by a ghost!") + message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(M)])") + M.ghostize() + M.key = theghost.key + else + to_chat(M, "There were no ghosts willing to take control.") + message_admins("No ghosts were willing to take control of [key_name_admin(M)])") + /proc/check_zone(zone) if(!zone) return "chest" switch(zone) diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm index 4cf50c9f661..8a9976bddba 100644 --- a/code/modules/reagents/chemistry/reagents/toxins.dm +++ b/code/modules/reagents/chemistry/reagents/toxins.dm @@ -203,6 +203,23 @@ return ..() +datum/reagent/romerol + name = "romerol" + // the REAL zombie powder + id = "romerol" + description = "Romerol is a highly experimental bioterror agent \ + which causes dormant nodules to be etched into the grey matter of \ + the subject. These nodules only become active upon death of the \ + host, upon which, the secondary structures activate and take control \ + of the host body." + color = "#123524" // RGB (18, 53, 36) + metabolization_rate = INFINITY + +/datum/reagent/romerol/reaction_mob(mob/living/carbon/human/H) + // Silently add the zombie infection organ to be activated upon death + new /obj/item/organ/internal/zombie_infection(H) + ..() + /datum/reagent/stable_mutagen/on_tick() var/datum/reagent/blood/B = locate() in holder.reagent_list if(B && islist(B.data) && !data) diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm index 6aeafd92cf0..3e5c69ff484 100644 --- a/code/modules/reagents/reagent_containers/bottle.dm +++ b/code/modules/reagents/reagent_containers/bottle.dm @@ -12,6 +12,11 @@ container_type = OPENCONTAINER volume = 30 +/obj/item/reagent_containers/glass/bottle/romerol + name = "romerol bottle" + desc = "A small bottle of Romerol. The REAL zombie powder." + list_reagents = list("romerol" = 30) + /obj/item/reagent_containers/glass/bottle/on_reagent_change() update_icon() diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm new file mode 100644 index 00000000000..e939299f1ed --- /dev/null +++ b/code/modules/zombie/items.dm @@ -0,0 +1,112 @@ +/obj/item/zombie_hand + name = "zombie claw" + desc = "A zombie's claw is its primary tool, capable of infecting \ + unconcious or dead humans, butchering all other living things to \ + sustain the zombie, forcing open airlock doors and opening \ + child-safe caps on bottles." + flags = NODROP|ABSTRACT + icon = 'icons/effects/blood.dmi' + icon_state = "bloodhand_left" + var/icon_left = "bloodhand_left" + var/icon_right = "bloodhand_right" + //hitsound = 'sound/hallucinations/growl1.ogg' + force = 25 + damtype = "brute" + + var/removing_airlock = FALSE + +/obj/item/zombie_hand/equipped(mob/user, slot) + . = ..() + switch(slot) + // Yes, these intentionally don't match + if(slot_l_hand) + icon_state = icon_right + if(slot_r_hand) + icon_state = icon_left + +/obj/item/zombie_hand/dropped(mob/user) + . = ..() + // Zombie hands are force dropped upon species loss + qdel(src) + +/obj/item/zombie_hand/afterattack(atom/target, mob/user, proximity_flag) + . = ..() + if(!proximity_flag) + return + if(istype(target, /obj/machinery/door/airlock) && !removing_airlock) + tear_airlock(target, user) + + else if(isliving(target)) + if(ishuman(target)) + check_infection(target, user) + else + check_feast(target, user) + +/obj/item/zombie_hand/proc/check_infection(var/mob/living/carbon/human/target, var/mob/user) + CHECK_DNA_AND_SPECIES(target) + var/mob/living/carbon/human/T = target + if(NOZOMBIE in T.dna.species.species_traits) + // cannot infect any NOZOMBIE subspecies (such as high functioning + // zombies) + return + + var/obj/item/organ/internal/zombie_infection/infection + infection = target.get_organ_slot("zombie_infection") + if(!infection) + if (target.InCritical || (!target.check_death_method && H.health <= HEALTH_THRESHOLD_DEAD)) + infection = new(target) + +/obj/item/zombie_hand/proc/check_feast(mob/living/target, mob/living/user) + if(target.stat == DEAD) + var/hp_gained = target.maxHealth + target.gib() + user.adjustBruteLoss(-hp_gained) + user.adjustToxLoss(-hp_gained) + user.adjustFireLoss(-hp_gained) + user.adjustCloneLoss(-hp_gained) + user.adjustBrainLoss(-hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!" + +/obj/item/zombie_hand/proc/tear_airlock(obj/machinery/door/airlock/A, mob/user) + removing_airlock = TRUE + to_chat(user,"You start tearing apart the airlock...\ + ") + + playsound(src.loc, 'sound/machines/airlock_alien_prying.ogg', 100, 1) + A.audible_message("You hear a loud metallic \ + grinding sound.") + + spawn(20) + if(removing_airlock) + playsound(src.loc, 'sound/hallucinations/growl3.ogg', 50, 1) + user.audible_message("[user] growls as \ + their claws dig into the metal frame...") + + if(do_after(user, delay=160, needhand=FALSE, target=A, progress=TRUE)) + playsound(src.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) + A.audible_message("With a screech, [A] is torn \ + apart!") + var/obj/structure/door_assembly/door = new A.assemblytype(get_turf(A)) + door.density = 0 + door.anchored = 1 + door.name = "ravaged [door]" + door.desc = "An airlock that has been torn apart. Looks like it \ + won't be keeping much out now." + qdel(A) + removing_airlock = FALSE + +/obj/item/zombie_hand/suicide_act(mob/living/carbon/human/user) + // Suiciding as a zombie brings someone else in to play it + user.visible_message("[user] is lying down.") + if(!istype(user)) + return + + user.Weaken(30) + var/success = offer_control(user) + if(success) + user.visible_message("[user] appears to have \ + found new spirit.") + return SHAME + else + user.visible_message("[user] stops moving.\ + ") + return OXYLOSS \ No newline at end of file diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm new file mode 100644 index 00000000000..bed6f646200 --- /dev/null +++ b/code/modules/zombie/organs.dm @@ -0,0 +1,87 @@ +#define START_TIMER reanimation_timer = world.time + rand(600,1200) + +/obj/item/organ/internal/zombie_infection + name = "festering ooze" + desc = "A black web of pus and vicera." + parent_organ = "head" + slot = "zombie_infection" + icon_state = "blacktumor" + var/causes_damage = TRUE + var/reanimation_timer + var/datum/species/old_species = /datum/species/human + var/living_transformation_time = 5 + var/converts_living = FALSE + +/obj/item/organ/internal/zombie_infection/New() + . = ..() + if(iscarbon(loc)) + insert(loc) + GLOB.zombie_infection_list += src + +/obj/item/organ/internal/zombie_infection/Destroy() + GLOB.zombie_infection_list -= src + . = ..() + +/obj/item/organ/internal/zombie_infection/insert(mob/living/carbon/human/M, special = 0) + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/organ/internal/zombie_infection/remove(mob/living/carbon/human/M, special = 0) + . = ..() + STOP_PROCESSING(SSobj, src) + if(iszombie(M) && old_species) + M.set_species(old_species) + +/obj/item/organ/internal/zombie_infection/on_find(mob/living/finder) + to_chat(finder,"Inside the head is a disgusting black \ + web of pus and vicera, bound tightly around the brain like some \ + biological harness.") + +/obj/item/organ/internal/zombie_infection/process() + if(!ishuman(owner)) // We do not support monkey or xeno zombies. Yet. + qdel(src) + return + if(owner.suiciding) + return + if(owner.stat != DEAD && !converts_living) + return + if (causes_damage && !iszombie(owner) && owner.stat != DEAD) + owner.adjustToxLoss(1) + if (prob(10)) + to_chat(owner, "You feel sick...") + if(!owner.get_int_organ(/obj/item/organ/internal/brain)) + return + else if(reanimation_timer && (reanimation_timer < world.time)) + zombify() // Rise and shine, Mr Romero... rise and shine. + reanimation_timer = null + else if(owner.stat == DEAD && !reanimation_timer) + START_TIMER + else if(converts_living && !iszombie(owner) && !reanimation_timer) + START_TIMER + +/obj/item/organ/internal/zombie_infection/remove(mob/living/carbon/human/M, special = 0) + . = ..() + CHECK_DNA_AND_SPECIES(M) + if(iszombie(M) && old_species) + M.set_species(old_species) + +/obj/item/organ/internal/zombie_infection/proc/zombify() + CHECK_DNA_AND_SPECIES(owner) + var/datum/species/zombie = /datum/species/zombie/infectious + if(!iszombie(owner)) + old_species = owner.dna.species + owner.set_species(zombie) + //Fully heal the zombie's damage the first time they rise + owner.setToxLoss(0, 0) + owner.setOxyLoss(0, 0) + owner.heal_overall_damage(INFINITY, INFINITY, INFINITY, null, TRUE) + + if(!owner.revive()) + return + + owner.grab_ghost() + owner.visible_message("[owner] suddenly convulses, as [owner.p_they()] stagger to [owner.p_their()] feet and gain a ravenous hunger in [owner.p_their()] eyes!", "You HUNGER!") + playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) + to_chat(owner, "You are now a zombie!") + +#undef START_TIMER \ No newline at end of file diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index e212d9c5882c0a020f82a4708f2affc0154eb710..963bb718a395f7686c0bbcdb285967c5d61bee77 100644 GIT binary patch delta 20276 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 NWo~M1QfcHC{cp;=9qa%A delta 20113 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 plzmF>ZvZYbT Date: Thu, 16 May 2019 22:44:16 -0400 Subject: [PATCH 02/10] Update items.dm --- code/modules/zombie/items.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index e939299f1ed..f710c060b0e 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -53,7 +53,7 @@ var/obj/item/organ/internal/zombie_infection/infection infection = target.get_organ_slot("zombie_infection") if(!infection) - if (target.InCritical || (!target.check_death_method && H.health <= HEALTH_THRESHOLD_DEAD)) + if (target.InCritical || (!target.check_death_method && target.health <= HEALTH_THRESHOLD_DEAD)) infection = new(target) /obj/item/zombie_hand/proc/check_feast(mob/living/target, mob/living/user) From ad6b0dc9cdfe8bdd320b67b442c032bc7395a290 Mon Sep 17 00:00:00 2001 From: Couls Date: Thu, 16 May 2019 22:46:47 -0400 Subject: [PATCH 03/10] Update items.dm --- code/modules/zombie/items.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index f710c060b0e..bda4eeba2c6 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -53,7 +53,7 @@ var/obj/item/organ/internal/zombie_infection/infection infection = target.get_organ_slot("zombie_infection") if(!infection) - if (target.InCritical || (!target.check_death_method && target.health <= HEALTH_THRESHOLD_DEAD)) + if (T.InCritical() || (!T.check_death_method() && T.health <= HEALTH_THRESHOLD_DEAD)) infection = new(target) /obj/item/zombie_hand/proc/check_feast(mob/living/target, mob/living/user) From 883594178bf28b04e0c95bff8c6e4b90dc8b7e2f Mon Sep 17 00:00:00 2001 From: Couls Date: Fri, 17 May 2019 14:43:24 -0400 Subject: [PATCH 04/10] Objective handling, Species now properly saved, new zombie language only fellow zombies can understand --- code/__DEFINES/genetics.dm | 3 -- code/game/gamemodes/objective.dm | 10 ++--- code/modules/mob/language.dm | 9 +++++ .../living/carbon/human/species/zombies.dm | 21 ++++++++-- code/modules/shuttle/emergency.dm | 2 +- code/modules/zombie/items.dm | 4 +- code/modules/zombie/organs.dm | 39 +++++++++++-------- goon/browserassets/css/browserOutput-dark.css | 2 +- goon/browserassets/css/browserOutput.css | 2 +- 9 files changed, 58 insertions(+), 34 deletions(-) diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm index bc8b8236032..1bd6dc7f34e 100644 --- a/code/__DEFINES/genetics.dm +++ b/code/__DEFINES/genetics.dm @@ -22,9 +22,6 @@ /////////////////////////////////////// // MUTATIONS /////////////////////////////////////// - -#define CHECK_DNA_AND_SPECIES(C) if((!(C.dna)) || (!(C.dna.species))) return - // Generic mutations: #define TK 1 #define COLDRES 2 diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 7c358ba951d..66a6748a683 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -65,7 +65,7 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu /datum/objective/assassinate/check_completion() if(target && target.current) - if(target.current.stat == DEAD) + if(target.current.stat == DEAD || iszombie(target)) return 1 if(issilicon(target.current) || isbrain(target.current)) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite return 1 @@ -109,7 +109,7 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu /datum/objective/maroon/check_completion() if(target && target.current) - if(target.current.stat == DEAD) + if(target.current.stat == DEAD || iszombie(target)) return 1 if(!target.current.ckey) return 1 @@ -166,7 +166,7 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu if(!target) //If it's a free objective. return 1 if(target.current) - if(target.current.stat == DEAD) + if(target.current.stat == DEAD || iszombie(target)) return 0 if(issilicon(target.current)) return 0 @@ -261,7 +261,7 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu return 0 if(isbrain(owner.current)) return 0 - if(!owner.current || owner.current.stat == DEAD) + if(!owner.current || owner.current.stat == DEAD || iszombie(owner)) return 0 if(SSticker.force_ending) //This one isn't their fault, so lets just assume good faith return 1 @@ -316,7 +316,7 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu explanation_text = "Die a glorious death." /datum/objective/die/check_completion() - if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current)) + if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current) || iszombie(owner)) return 1 if(issilicon(owner.current) && owner.current != owner.original) return 1 diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index 25b188911ad..dcb328c8264 100644 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -757,6 +757,15 @@ desc = "Bark bark bark." key = "vu" +/datum/language/com_srus + name = "Zombie" + desc = "BRAAAAAAINS!" + speech_verb = "moans" + whisper_verb = "mutters" + exclaim_verb = "wails" + colour = "zombie" + key = "zom" + syllables = list("BRAAAAAAAAAAAAAAAAINS", "BRAAINS", "BRAINS") #undef SCRAMBLE_CACHE_LEN diff --git a/code/modules/mob/living/carbon/human/species/zombies.dm b/code/modules/mob/living/carbon/human/species/zombies.dm index 9fa6cf37de2..f11c3a7fbd3 100644 --- a/code/modules/mob/living/carbon/human/species/zombies.dm +++ b/code/modules/mob/living/carbon/human/species/zombies.dm @@ -11,15 +11,32 @@ var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg') warning_low_pressure = 50 hazard_low_pressure = 0 + has_organ = list( + "heart" = /obj/item/organ/internal/heart, + "lungs" = /obj/item/organ/internal/lungs, + "liver" = /obj/item/organ/internal/liver, + "kidneys" = /obj/item/organ/internal/kidneys, + "brain" = /obj/item/organ/internal/brain, + "appendix" = /obj/item/organ/internal/appendix, + "eyes" = /obj/item/organ/internal/eyes, + "ears" = /obj/item/organ/internal/ears, + "zombie_infection" = /obj/item/organ/internal/zombie_infection) + /datum/species/zombie/infectious name = "Infectious Zombie" mutanthands = /obj/item/zombie_hand armor = 20 // 120 damage to KO a zombie, which kills it speedmod = 1.6 + default_language = "Zombie" + language = "Zombie" var/heal_rate = 1 var/regen_cooldown = 0 +/datum/species/zombie/infectious/handle_dna(mob/living/carbon/human/H, remove) + H.mutations.Add(HUSK) + . = ..() + /datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount) . = min(20, amount) @@ -29,14 +46,12 @@ /datum/species/zombie/infectious/handle_life(mob/living/carbon/human/C) . = ..() - C.a_intent = INTENT_HARM // THE SUFFERING MUST FLOW - //Zombies never actually die, they just fall down until they regenerate enough to rise back up. //They must be restrained, beheaded or gibbed to stop being a threat. if(regen_cooldown < world.time) var/heal_amt = heal_rate if(C.InCritical()) - heal_amt *= 2 + heal_amt *= 5 C.heal_overall_damage(heal_amt,heal_amt) C.adjustToxLoss(-heal_amt) if(!C.InCritical() && prob(4)) diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index b796e3d8a7d..8aa63f0a130 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -175,7 +175,7 @@ /obj/docking_port/mobile/emergency/proc/is_hijacked() for(var/mob/living/player in GLOB.player_list) if(player.mind) - if(player.stat != DEAD) + if(player.stat != DEAD || !iszombie(player)) if(issilicon(player)) //Borgs are technically dead anyways continue if(isanimal(player)) //Poly does not own the shuttle diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index bda4eeba2c6..90bd16e53b0 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -1,7 +1,7 @@ /obj/item/zombie_hand name = "zombie claw" desc = "A zombie's claw is its primary tool, capable of infecting \ - unconcious or dead humans, butchering all other living things to \ + unconscious or dead humans, butchering all other living things to \ sustain the zombie, forcing open airlock doors and opening \ child-safe caps on bottles." flags = NODROP|ABSTRACT @@ -9,7 +9,6 @@ icon_state = "bloodhand_left" var/icon_left = "bloodhand_left" var/icon_right = "bloodhand_right" - //hitsound = 'sound/hallucinations/growl1.ogg' force = 25 damtype = "brute" @@ -43,7 +42,6 @@ check_feast(target, user) /obj/item/zombie_hand/proc/check_infection(var/mob/living/carbon/human/target, var/mob/user) - CHECK_DNA_AND_SPECIES(target) var/mob/living/carbon/human/T = target if(NOZOMBIE in T.dna.species.species_traits) // cannot infect any NOZOMBIE subspecies (such as high functioning diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index bed6f646200..07c97e4162a 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -2,20 +2,21 @@ /obj/item/organ/internal/zombie_infection name = "festering ooze" - desc = "A black web of pus and vicera." + desc = "A black web of pus and viscera." parent_organ = "head" slot = "zombie_infection" icon_state = "blacktumor" var/causes_damage = TRUE var/reanimation_timer - var/datum/species/old_species = /datum/species/human + var/datum/species/old_species = new /datum/species/human var/living_transformation_time = 5 var/converts_living = FALSE /obj/item/organ/internal/zombie_infection/New() . = ..() - if(iscarbon(loc)) - insert(loc) + if(ishuman(owner) && !ismachine(owner)) + old_species = owner.dna.species + insert(owner) GLOB.zombie_infection_list += src /obj/item/organ/internal/zombie_infection/Destroy() @@ -27,14 +28,14 @@ START_PROCESSING(SSobj, src) /obj/item/organ/internal/zombie_infection/remove(mob/living/carbon/human/M, special = 0) - . = ..() STOP_PROCESSING(SSobj, src) if(iszombie(M) && old_species) M.set_species(old_species) + ..() /obj/item/organ/internal/zombie_infection/on_find(mob/living/finder) to_chat(finder,"Inside the head is a disgusting black \ - web of pus and vicera, bound tightly around the brain like some \ + web of pus and viscera, bound tightly around the brain like some \ biological harness.") /obj/item/organ/internal/zombie_infection/process() @@ -50,7 +51,12 @@ if (prob(10)) to_chat(owner, "You feel sick...") if(!owner.get_int_organ(/obj/item/organ/internal/brain)) - return + return + if(!iszombie(owner) && !reanimation_timer) + to_chat(owner, "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, you will rise again!") + START_TIMER else if(reanimation_timer && (reanimation_timer < world.time)) zombify() // Rise and shine, Mr Romero... rise and shine. reanimation_timer = null @@ -61,25 +67,24 @@ /obj/item/organ/internal/zombie_infection/remove(mob/living/carbon/human/M, special = 0) . = ..() - CHECK_DNA_AND_SPECIES(M) if(iszombie(M) && old_species) M.set_species(old_species) /obj/item/organ/internal/zombie_infection/proc/zombify() - CHECK_DNA_AND_SPECIES(owner) var/datum/species/zombie = /datum/species/zombie/infectious if(!iszombie(owner)) old_species = owner.dna.species owner.set_species(zombie) //Fully heal the zombie's damage the first time they rise - owner.setToxLoss(0, 0) - owner.setOxyLoss(0, 0) - owner.heal_overall_damage(INFINITY, INFINITY, INFINITY, null, TRUE) - - if(!owner.revive()) - return - - owner.grab_ghost() + owner.setToxLoss(0, 1) + owner.setOxyLoss(0, 1) + owner.setBrainLoss(0, 1) + owner.setCloneLoss(0,1) + owner.heal_overall_damage(INFINITY,INFINITY,TRUE,TRUE,FALSE) + owner.updatehealth() + owner.grab_ghost(TRUE) + owner.update_revive() + owner.ChangeToHusk() owner.visible_message("[owner] suddenly convulses, as [owner.p_they()] stagger to [owner.p_their()] feet and gain a ravenous hunger in [owner.p_their()] eyes!", "You HUNGER!") playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) to_chat(owner, "You are now a zombie!") diff --git a/goon/browserassets/css/browserOutput-dark.css b/goon/browserassets/css/browserOutput-dark.css index fed5a252ba3..3ee14b2a4d4 100644 --- a/goon/browserassets/css/browserOutput-dark.css +++ b/goon/browserassets/css/browserOutput-dark.css @@ -335,6 +335,7 @@ h1.alert, h2.alert {color: #FFF;} .skrell {color: #00CED1;} .solcom {color: #8282FB;} .com_srus {color: #7c4848;} +.zombie {color: #ff0000;} .soghun {color: #228B22;} .changeling {color: #800080;} .vox {color: #AA00AA;} @@ -388,7 +389,6 @@ h1.alert, h2.alert {color: #FFF;} .whisper {font-style:italic;color:#CCCCCC;} /* Recruiting stuff */ .recruit {color: #5c00e6; font-weight: bold; font-style: italic;} -"} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 75%;} diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css index 1af8b03bd58..b664c1e9752 100644 --- a/goon/browserassets/css/browserOutput.css +++ b/goon/browserassets/css/browserOutput.css @@ -332,6 +332,7 @@ h1.alert, h2.alert {color: #000000;} .skrell {color: #00CED1;} .solcom {color: #22228B;} .com_srus {color: #7c4848;} +.zombie {color: #ff0000;} .soghun {color: #228B22;} .changeling {color: #800080;} .vox {color: #AA00AA;} @@ -385,7 +386,6 @@ h1.alert, h2.alert {color: #000000;} .whisper {font-style:italic;color:#333333;} /* Recruiting stuff */ .recruit {color: #5c00e6; font-weight: bold; font-style: italic;} -"} .memo {color: #638500; text-align: center;} .memoedit {text-align: center; font-size: 75%;} From bf46dd18e5101a3d39fa151f6a1ef471990a6154 Mon Sep 17 00:00:00 2001 From: Couls Date: Wed, 22 May 2019 20:21:16 -0400 Subject: [PATCH 05/10] Zombie sprites! green zombie species name on examine! --- .../living/carbon/human/species/zombies.dm | 18 ++++++++++++++---- .../sprite_accessories/sprite_accessories.dm | 2 +- code/modules/zombie/organs.dm | 1 - icons/mob/human_races/r_def_zombie.dmi | Bin 0 -> 2032 bytes icons/mob/human_races/r_zombie.dmi | Bin 0 -> 2032 bytes 5 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 icons/mob/human_races/r_def_zombie.dmi create mode 100644 icons/mob/human_races/r_zombie.dmi diff --git a/code/modules/mob/living/carbon/human/species/zombies.dm b/code/modules/mob/living/carbon/human/species/zombies.dm index f11c3a7fbd3..2789b075990 100644 --- a/code/modules/mob/living/carbon/human/species/zombies.dm +++ b/code/modules/mob/living/carbon/human/species/zombies.dm @@ -4,13 +4,16 @@ // 1spooky name = "High-Functioning Zombie" name_plural = "High-Functioning Zombies" - icobase = 'icons/mob/human_races/r_human.dmi' - deform = 'icons/mob/human_races/r_def_human.dmi' + icobase = 'icons/mob/human_races/r_zombie.dmi' + deform = 'icons/mob/human_races/r_def_zombie.dmi' dies_at_threshold = TRUE species_traits = list(NO_BLOOD,NOZOMBIE,NOTRANSSTING,NO_BREATHE, RADIMMUNE, NO_SCAN) var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg') warning_low_pressure = 50 hazard_low_pressure = 0 + flesh_color = "#00FF00" // for green examine text + bodyflags = HAS_SKIN_COLOR + dietflags = DIET_CARN has_organ = list( "heart" = /obj/item/organ/internal/heart, "lungs" = /obj/item/organ/internal/lungs, @@ -26,21 +29,24 @@ /datum/species/zombie/infectious name = "Infectious Zombie" mutanthands = /obj/item/zombie_hand + icobase = 'icons/mob/human_races/r_zombie.dmi' + deform = 'icons/mob/human_races/r_def_zombie.dmi' armor = 20 // 120 damage to KO a zombie, which kills it speedmod = 1.6 default_language = "Zombie" language = "Zombie" var/heal_rate = 1 var/regen_cooldown = 0 + flesh_color = "#00FF00" // for green examine text /datum/species/zombie/infectious/handle_dna(mob/living/carbon/human/H, remove) - H.mutations.Add(HUSK) . = ..() /datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount) . = min(20, amount) /datum/species/zombie/infectious/spec_attacked_by(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H) + . = ..() if(.) regen_cooldown = world.time + REGENERATION_DELAY @@ -75,11 +81,15 @@ C.drop_r_hand() C.put_in_hands(new mutanthands()) C.put_in_hands(new mutanthands()) - C.ChangeToHusk() var/obj/item/organ/internal/zombie_infection/infection infection = C.get_organ_slot("zombie_infection") if(!infection) infection = new() infection.insert(C) +/datum/species/zombie/infectious/on_species_loss(mob/living/carbon/human/C, datum/species/old_species) + qdel(C.r_hand) + qdel(C.l_hand) + return ..() + #undef REGENERATION_DELAY diff --git a/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm index 10f7b1acd46..e1020628151 100644 --- a/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm @@ -48,7 +48,7 @@ var/gender = NEUTER //Determines if the accessory will be skipped or included in random hair generations // Restrict some styles to specific species - var/list/species_allowed = list("Human", "Slime People") + var/list/species_allowed = list("Human", "Slime People", "Infectious Zombie", "High-Functioning Zombie") var/list/sprite_sheets = list() //For accessories common across species but need to use 'fitted' sprites (like underwear). e.g. list("Vox" = 'icons/mob/species/vox/iconfile.dmi') var/list/models_allowed = list() //Specifies which, if any, hairstyles or markings can be accessed by which prosthetics. Should equal the manufacturing company name in robolimbs.dm. var/list/heads_allowed = null //Specifies which, if any, alt heads a head marking, hairstyle or facial hair style is compatible with. diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index 07c97e4162a..c14bc195ebe 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -84,7 +84,6 @@ owner.updatehealth() owner.grab_ghost(TRUE) owner.update_revive() - owner.ChangeToHusk() owner.visible_message("[owner] suddenly convulses, as [owner.p_they()] stagger to [owner.p_their()] feet and gain a ravenous hunger in [owner.p_their()] eyes!", "You HUNGER!") playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) to_chat(owner, "You are now a zombie!") diff --git a/icons/mob/human_races/r_def_zombie.dmi b/icons/mob/human_races/r_def_zombie.dmi new file mode 100644 index 0000000000000000000000000000000000000000..007eb3f31f3ab8651f9294fe6c3339ac10682af7 GIT binary patch literal 2032 zcmX|Bdpy(s8vkz0hM$9wB<1qUh|t9?GItv`tYK-*Etf?usaV!FYUX}Tix%nRnno0U zQdZ*SL@DXwvWYO|pr&%0?QqVo^ZfHX@6Yr4JkR^{yr0)6!yDtKAh%Nv000FP(isZ? zpv@2jz@#=^R6QQI>GHijaV}ggHzL#9_llL%Wi8u84Fbd2CUp<#f>dY>;N}I8&I1vt zT9_*)AplSW06qo)nN0Tg_qW{*SldBeJ>|{Jfv^m;ud+UYX-`aZKEZGxraL<`w1`X> zQnrsD!y3;x8pK3~rh5?6T#qvl!Az7>sum&L-j`t&vUTXa1#l`?Y5<92xkzAMAA1)E=MxITqC+|)6 z>YR$CKHVX@gOP3;9qep)YkV^E;g@G`)SyF|QHboK*%&?APEXMGcx3^vtl9tdFe~oJ z*%@@4U93)6FYKK-Lt19{JlMx^&Bp~@rql0k%U*}{N_$QaDsR;||GXwHSn#zf zJgke>8$7Iw>e8&NtPK8X!BpCQ&>wLFq@uKDu@D<*v{t(=9*2@|x22eVY+3>U8E=%c z11^a@e=|P$hJ{j3fwb)Q?!6@BwJOrwz4`Wsean(0o8Z_>Ewh-QMr-rM0WUG~4vd$T zuawBn0&l+lZ=?H~z0cvy)n|wwKX5&LhyAg#c``c8&A+PM#|Z`07G%}lJOby`>1P8~ zXGz_`S9gI->>9;+R{gm>Xj1WA!mGJb73gaO?1RS5lDfhl@%lqn8FUYOp2zY_)OKuz ztsPqBfOo4GiTyjN{3_eo2cRwL=H=y*J3SecUvOBB1QGM=!u!2G- z&wBfXQ#8M}v0sxzO+slVXI_DaR7Cq<4c$k;376aB!w)&o(L;lS;i8V0=p*FsBPDrs zmI-${+;RS8*bsKyljN*^WA;H0RuE;l)r0OhHVeq=U@*DLSS{VD{u&rZ3D&b!b=V(vEku#Rp%RA{k z4Tn>qkSTF>zlWa^{|P#ob2jM`!d$9;AGhrbY39#sE6aa@`}+dTdRqP}S}}ycn(1ug zYIYI#ld;hX0hDdbHBhwb+vc%?63|P)*%pgQT0i*GYDHy&-o$6agC=iRv(^5uGys?u zA~?vhTQS}eaR3ETy;kOGCQuB#`H_Jsu@wr=~S z40xI8cRCzIA`#KlRG(FaG-;W-POOpajnp6<^>PJ<4+g&7CMSIE7HW>CPv@|zW#_Fu z`RS<0%-fbt;3uT#GSA#^lS?`dxZ=3Hoq9P1Rm+nB*2ecU)ov{%xb3mS{$Rb9Bojdq zmp2kSfW+b$(7rdoWI+`z*_=k7{C3mI4d}63=Dv5U&HOiS*tt#Ax8u0kAfANwo1+ zD9JiwDa`eU4hWaM`X!3LM@y&BX}iVb6~RO~lU8QR+yW()qRk&;(>^hRne$fVH9D%L zmCt_SLR{9J?yDK8G8#+v@{c~D*|x+A9CEws>d(LTb7VYUmhVWGAb0T|C1@{RwX+h~ zv1{SK+W>&zsd`AhU!ZCRtFkgrzsO z*Yh0HbDCXoz2-TSD_3+*1awbh<)?q<%F#A*@+ReUFoh`-@^F92piiz6B0+mCh6Hn{ ze+kzqY^eWA%y!h&O+VE+3dN@+Ss78Z8OP#qs7< z1-~$>GPM#~z9Zo~k&fO^1eZeMpr9)#zR2+TL;>IclH}NMElWYYVm4$&{2?(|LvOSu zgV-)D>JcV9|9YpR)9bRmS2WogrcD69ADRU4!-(=-Ag`|P<#?&S2@7|k%$$3>0{#PH zQHER|(YV?wild-_)s+c9AJw3f5(>ISBVu@icycjs!1bT-yv5WFM@iQCjivKPDS432 ziTN%Yw~C$eC&81{5At_wz%%gE-zoLtUb*3-i@W2>h`&|omHVIWe=k79X)Z!hVk=tu zHqeEjVI`s$2Hyr6vScKpx|+>Eb}L~D{C78m6R|ue8!CrWWW7}k<$`hMI0mKu2Mi9T AbpQYW literal 0 HcmV?d00001 diff --git a/icons/mob/human_races/r_zombie.dmi b/icons/mob/human_races/r_zombie.dmi new file mode 100644 index 0000000000000000000000000000000000000000..007eb3f31f3ab8651f9294fe6c3339ac10682af7 GIT binary patch literal 2032 zcmX|Bdpy(s8vkz0hM$9wB<1qUh|t9?GItv`tYK-*Etf?usaV!FYUX}Tix%nRnno0U zQdZ*SL@DXwvWYO|pr&%0?QqVo^ZfHX@6Yr4JkR^{yr0)6!yDtKAh%Nv000FP(isZ? zpv@2jz@#=^R6QQI>GHijaV}ggHzL#9_llL%Wi8u84Fbd2CUp<#f>dY>;N}I8&I1vt zT9_*)AplSW06qo)nN0Tg_qW{*SldBeJ>|{Jfv^m;ud+UYX-`aZKEZGxraL<`w1`X> zQnrsD!y3;x8pK3~rh5?6T#qvl!Az7>sum&L-j`t&vUTXa1#l`?Y5<92xkzAMAA1)E=MxITqC+|)6 z>YR$CKHVX@gOP3;9qep)YkV^E;g@G`)SyF|QHboK*%&?APEXMGcx3^vtl9tdFe~oJ z*%@@4U93)6FYKK-Lt19{JlMx^&Bp~@rql0k%U*}{N_$QaDsR;||GXwHSn#zf zJgke>8$7Iw>e8&NtPK8X!BpCQ&>wLFq@uKDu@D<*v{t(=9*2@|x22eVY+3>U8E=%c z11^a@e=|P$hJ{j3fwb)Q?!6@BwJOrwz4`Wsean(0o8Z_>Ewh-QMr-rM0WUG~4vd$T zuawBn0&l+lZ=?H~z0cvy)n|wwKX5&LhyAg#c``c8&A+PM#|Z`07G%}lJOby`>1P8~ zXGz_`S9gI->>9;+R{gm>Xj1WA!mGJb73gaO?1RS5lDfhl@%lqn8FUYOp2zY_)OKuz ztsPqBfOo4GiTyjN{3_eo2cRwL=H=y*J3SecUvOBB1QGM=!u!2G- z&wBfXQ#8M}v0sxzO+slVXI_DaR7Cq<4c$k;376aB!w)&o(L;lS;i8V0=p*FsBPDrs zmI-${+;RS8*bsKyljN*^WA;H0RuE;l)r0OhHVeq=U@*DLSS{VD{u&rZ3D&b!b=V(vEku#Rp%RA{k z4Tn>qkSTF>zlWa^{|P#ob2jM`!d$9;AGhrbY39#sE6aa@`}+dTdRqP}S}}ycn(1ug zYIYI#ld;hX0hDdbHBhwb+vc%?63|P)*%pgQT0i*GYDHy&-o$6agC=iRv(^5uGys?u zA~?vhTQS}eaR3ETy;kOGCQuB#`H_Jsu@wr=~S z40xI8cRCzIA`#KlRG(FaG-;W-POOpajnp6<^>PJ<4+g&7CMSIE7HW>CPv@|zW#_Fu z`RS<0%-fbt;3uT#GSA#^lS?`dxZ=3Hoq9P1Rm+nB*2ecU)ov{%xb3mS{$Rb9Bojdq zmp2kSfW+b$(7rdoWI+`z*_=k7{C3mI4d}63=Dv5U&HOiS*tt#Ax8u0kAfANwo1+ zD9JiwDa`eU4hWaM`X!3LM@y&BX}iVb6~RO~lU8QR+yW()qRk&;(>^hRne$fVH9D%L zmCt_SLR{9J?yDK8G8#+v@{c~D*|x+A9CEws>d(LTb7VYUmhVWGAb0T|C1@{RwX+h~ zv1{SK+W>&zsd`AhU!ZCRtFkgrzsO z*Yh0HbDCXoz2-TSD_3+*1awbh<)?q<%F#A*@+ReUFoh`-@^F92piiz6B0+mCh6Hn{ ze+kzqY^eWA%y!h&O+VE+3dN@+Ss78Z8OP#qs7< z1-~$>GPM#~z9Zo~k&fO^1eZeMpr9)#zR2+TL;>IclH}NMElWYYVm4$&{2?(|LvOSu zgV-)D>JcV9|9YpR)9bRmS2WogrcD69ADRU4!-(=-Ag`|P<#?&S2@7|k%$$3>0{#PH zQHER|(YV?wild-_)s+c9AJw3f5(>ISBVu@icycjs!1bT-yv5WFM@iQCjivKPDS432 ziTN%Yw~C$eC&81{5At_wz%%gE-zoLtUb*3-i@W2>h`&|omHVIWe=k79X)Z!hVk=tu zHqeEjVI`s$2Hyr6vScKpx|+>Eb}L~D{C78m6R|ue8!CrWWW7}k<$`hMI0mKu2Mi9T AbpQYW literal 0 HcmV?d00001 From d83d8099ecb16bde10c2dd7c0a146779af395a19 Mon Sep 17 00:00:00 2001 From: Couls Date: Wed, 22 May 2019 20:24:29 -0400 Subject: [PATCH 06/10] remove airlock tearing(they can just smash them down) --- code/modules/zombie/items.dm | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index 90bd16e53b0..5c1f91bd247 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -12,8 +12,6 @@ force = 25 damtype = "brute" - var/removing_airlock = FALSE - /obj/item/zombie_hand/equipped(mob/user, slot) . = ..() switch(slot) @@ -32,9 +30,7 @@ . = ..() if(!proximity_flag) return - if(istype(target, /obj/machinery/door/airlock) && !removing_airlock) - tear_airlock(target, user) - + else if(isliving(target)) if(ishuman(target)) check_infection(target, user) @@ -64,34 +60,6 @@ user.adjustCloneLoss(-hp_gained) user.adjustBrainLoss(-hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!" -/obj/item/zombie_hand/proc/tear_airlock(obj/machinery/door/airlock/A, mob/user) - removing_airlock = TRUE - to_chat(user,"You start tearing apart the airlock...\ - ") - - playsound(src.loc, 'sound/machines/airlock_alien_prying.ogg', 100, 1) - A.audible_message("You hear a loud metallic \ - grinding sound.") - - spawn(20) - if(removing_airlock) - playsound(src.loc, 'sound/hallucinations/growl3.ogg', 50, 1) - user.audible_message("[user] growls as \ - their claws dig into the metal frame...") - - if(do_after(user, delay=160, needhand=FALSE, target=A, progress=TRUE)) - playsound(src.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) - A.audible_message("With a screech, [A] is torn \ - apart!") - var/obj/structure/door_assembly/door = new A.assemblytype(get_turf(A)) - door.density = 0 - door.anchored = 1 - door.name = "ravaged [door]" - door.desc = "An airlock that has been torn apart. Looks like it \ - won't be keeping much out now." - qdel(A) - removing_airlock = FALSE - /obj/item/zombie_hand/suicide_act(mob/living/carbon/human/user) // Suiciding as a zombie brings someone else in to play it user.visible_message("[user] is lying down.") From 5045980323c436063f6a1b7ed342bbd0489b4676 Mon Sep 17 00:00:00 2001 From: Coul Date: Mon, 2 Sep 2019 05:32:15 -0400 Subject: [PATCH 07/10] review changes --- code/__DEFINES/genetics.dm | 2 + code/datums/uplink_item.dm | 1 + code/modules/mob/living/carbon/human/human.dm | 7 +- .../mob/living/carbon/human/human_damage.dm | 4 +- .../living/carbon/human/species/_species.dm | 5 +- .../living/carbon/human/species/zombies.dm | 18 ++--- code/modules/mob/mob_helpers.dm | 2 +- .../reagents/chemistry/reagents/toxins.dm | 2 + code/modules/zombie/items.dm | 37 ++++----- code/modules/zombie/organs.dm | 77 ++++++++++--------- 10 files changed, 78 insertions(+), 77 deletions(-) diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm index 1bd6dc7f34e..30501daee70 100644 --- a/code/__DEFINES/genetics.dm +++ b/code/__DEFINES/genetics.dm @@ -1,6 +1,8 @@ // String identifiers for associative list lookup +#define CHECK_DNA_AND_SPECIES(C) if((!(C.dna)) || (!(C.dna.species))) return + #define MUTCHK_FORCED 1 // mob/var/list/mutations diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 24b714acef7..ca2d64868ad 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -196,6 +196,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A highly experimental bioterror agent which creates dormant nodules to be etched into the grey matter of the brain. On death, these nodules take control of the dead body, causing limited revivification, along with slurred speech, aggression, and the ability to infect others with this agent." item = /obj/item/storage/box/syndie_kit/romerol cost = 25 + cant_discount = TRUE //mime /datum/uplink_item/jobspecific/caneshotgun diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6481f6bc04a..69c486b6155 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1305,8 +1305,13 @@ oldspecies.handle_dna(src, TRUE) // Remove any genes that belong to the old species oldspecies.on_species_loss(src) + var/datum/species/new_race + if(ispath(new_species)) + new_race = new new_species + else if(istype(new_species)) + new_race = new_species - dna.species = new new_species() + dna.species = new_race tail = dna.species.tail diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index e106d214fd3..80b376bf33b 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -334,7 +334,9 @@ This function restores all organs. //Handle BRUTE and BURN damage handle_suit_punctures(damagetype, damage) - + //Handle species apply_damage procs + dna.species.spec_apply_damage(damage, damagetype, def_zone, blocked, sharp, used_weapon) + blocked = (100 - blocked) / 100 if(blocked <= 0) return 0 diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index b71e6e8075e..7016e523cea 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -308,7 +308,10 @@ /datum/species/proc/handle_death(mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns). return -/datum/species/proc/spec_death(mob/living/carbon/human/C) +/datum/species/proc/spec_death(gibbed, mob/living/carbon/human/C) + return + +/datum/species/proc/spec_apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, sharp = 0, obj/used_weapon = null) return /datum/species/proc/spec_stun(mob/living/carbon/human/H,amount) diff --git a/code/modules/mob/living/carbon/human/species/zombies.dm b/code/modules/mob/living/carbon/human/species/zombies.dm index 2789b075990..5b019ead911 100644 --- a/code/modules/mob/living/carbon/human/species/zombies.dm +++ b/code/modules/mob/living/carbon/human/species/zombies.dm @@ -37,17 +37,13 @@ language = "Zombie" var/heal_rate = 1 var/regen_cooldown = 0 - flesh_color = "#00FF00" // for green examine text -/datum/species/zombie/infectious/handle_dna(mob/living/carbon/human/H, remove) - . = ..() - -/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H,amount) +/datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H, amount) . = min(20, amount) -/datum/species/zombie/infectious/spec_attacked_by(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H) +/datum/species/zombie/infectious/spec_apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, sharp = 0, obj/used_weapon = null) . = ..() - if(.) + if(damage) regen_cooldown = world.time + REGENERATION_DELAY /datum/species/zombie/infectious/handle_life(mob/living/carbon/human/C) @@ -57,14 +53,14 @@ if(regen_cooldown < world.time) var/heal_amt = heal_rate if(C.InCritical()) - heal_amt *= 5 + heal_amt *= 2 C.heal_overall_damage(heal_amt,heal_amt) C.adjustToxLoss(-heal_amt) if(!C.InCritical() && prob(4)) playsound(C, pick(spooks), 50, TRUE, 10) //Congrats you somehow died so hard you stopped being a zombie -/datum/species/zombie/infectious/spec_death(mob/living/carbon/C) +/datum/species/zombie/infectious/spec_death(gibbed, mob/living/carbon/C) . = ..() var/obj/item/organ/internal/zombie_infection/infection infection = C.get_organ_slot("zombie_infection") @@ -88,8 +84,8 @@ infection.insert(C) /datum/species/zombie/infectious/on_species_loss(mob/living/carbon/human/C, datum/species/old_species) - qdel(C.r_hand) - qdel(C.l_hand) + QDEL_NULL(C.r_hand) + QDEL_NULL(C.l_hand) return ..() #undef REGENERATION_DELAY diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index d4e03fa7ca7..ded601d1c70 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -121,7 +121,7 @@ var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as [M.real_name ? M.real_name : M.name]?", poll_time = 100, min_hours = minhours) var/mob/dead/observer/theghost = null - if(candidates.len) + if(LAZYLEN(candidates)) theghost = pick(candidates) to_chat(M, "Your mob has been taken over by a ghost!") message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(M)])") diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm index 8a9976bddba..85af8f7bb97 100644 --- a/code/modules/reagents/chemistry/reagents/toxins.dm +++ b/code/modules/reagents/chemistry/reagents/toxins.dm @@ -214,6 +214,8 @@ datum/reagent/romerol of the host body." color = "#123524" // RGB (18, 53, 36) metabolization_rate = INFINITY + can_synth = FALSE + taste_message = "CAAAARL" /datum/reagent/romerol/reaction_mob(mob/living/carbon/human/H) // Silently add the zombie infection organ to be activated upon death diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index 5c1f91bd247..3ba12518dd2 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -4,11 +4,12 @@ unconscious or dead humans, butchering all other living things to \ sustain the zombie, forcing open airlock doors and opening \ child-safe caps on bottles." - flags = NODROP|ABSTRACT + flags = NODROP|ABSTRACT|DROPDEL icon = 'icons/effects/blood.dmi' icon_state = "bloodhand_left" var/icon_left = "bloodhand_left" var/icon_right = "bloodhand_right" + hitsound = 'sound/hallucinations/growl1.ogg' force = 25 damtype = "brute" @@ -21,11 +22,6 @@ if(slot_r_hand) icon_state = icon_left -/obj/item/zombie_hand/dropped(mob/user) - . = ..() - // Zombie hands are force dropped upon species loss - qdel(src) - /obj/item/zombie_hand/afterattack(atom/target, mob/user, proximity_flag) . = ..() if(!proximity_flag) @@ -38,8 +34,9 @@ check_feast(target, user) /obj/item/zombie_hand/proc/check_infection(var/mob/living/carbon/human/target, var/mob/user) - var/mob/living/carbon/human/T = target - if(NOZOMBIE in T.dna.species.species_traits) + CHECK_DNA_AND_SPECIES(target) + + if(NOZOMBIE in target.dna.species.species_traits) // cannot infect any NOZOMBIE subspecies (such as high functioning // zombies) return @@ -47,7 +44,7 @@ var/obj/item/organ/internal/zombie_infection/infection infection = target.get_organ_slot("zombie_infection") if(!infection) - if (T.InCritical() || (!T.check_death_method() && T.health <= HEALTH_THRESHOLD_DEAD)) + if (target.InCritical() || (!target.check_death_method() && target.health <= HEALTH_THRESHOLD_DEAD)) infection = new(target) /obj/item/zombie_hand/proc/check_feast(mob/living/target, mob/living/user) @@ -61,18 +58,10 @@ user.adjustBrainLoss(-hp_gained) // Zom Bee gibbers "BRAAAAISNSs!1!" /obj/item/zombie_hand/suicide_act(mob/living/carbon/human/user) - // Suiciding as a zombie brings someone else in to play it - user.visible_message("[user] is lying down.") - if(!istype(user)) - return - - user.Weaken(30) - var/success = offer_control(user) - if(success) - user.visible_message("[user] appears to have \ - found new spirit.") - return SHAME - else - user.visible_message("[user] stops moving.\ - ") - return OXYLOSS \ No newline at end of file + user.visible_message("[user] is ripping [user.p_their()] brains out! It looks like [user.p_theyre()] trying to commit suicide!") + if(ishuman(user)) + var/mob/living/carbon/human/L = user + var/obj/item/organ/external/O = L.get_organ("head") + if(O) + O.droplimb() + return (BRUTELOSS) \ No newline at end of file diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index c14bc195ebe..220c6c985da 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -1,5 +1,3 @@ -#define START_TIMER reanimation_timer = world.time + rand(600,1200) - /obj/item/organ/internal/zombie_infection name = "festering ooze" desc = "A black web of pus and viscera." @@ -7,16 +5,17 @@ slot = "zombie_infection" icon_state = "blacktumor" var/causes_damage = TRUE - var/reanimation_timer - var/datum/species/old_species = new /datum/species/human - var/living_transformation_time = 5 - var/converts_living = FALSE + var/datum/species/old_species = /datum/species/human + var/living_transformation_time = 3 + var/revive_time_min = 450 + var/revive_time_max = 700 + var/timer_id + var/dont_delete = FALSE // to prevent set_species proc in zombify from deleting the infection organ immediately /obj/item/organ/internal/zombie_infection/New() . = ..() - if(ishuman(owner) && !ismachine(owner)) + if(ishuman(owner) && !ismachine(owner) && !iszombie(owner.dna.species)) old_species = owner.dna.species - insert(owner) GLOB.zombie_infection_list += src /obj/item/organ/internal/zombie_infection/Destroy() @@ -29,8 +28,10 @@ /obj/item/organ/internal/zombie_infection/remove(mob/living/carbon/human/M, special = 0) STOP_PROCESSING(SSobj, src) - if(iszombie(M) && old_species) + if(iszombie(M) && old_species && !dont_delete) M.set_species(old_species) + if(timer_id) + deltimer(timer_id) ..() /obj/item/organ/internal/zombie_infection/on_find(mob/living/finder) @@ -44,48 +45,48 @@ return if(owner.suiciding) return - if(owner.stat != DEAD && !converts_living) + if(owner.stat != DEAD) return - if (causes_damage && !iszombie(owner) && owner.stat != DEAD) + if(causes_damage && !iszombie(owner) && owner.stat != DEAD) owner.adjustToxLoss(1) if (prob(10)) to_chat(owner, "You feel sick...") if(!owner.get_int_organ(/obj/item/organ/internal/brain)) return - if(!iszombie(owner) && !reanimation_timer) + if(!iszombie(owner) && !timer_id) to_chat(owner, "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, you will rise again!") - START_TIMER - else if(reanimation_timer && (reanimation_timer < world.time)) - zombify() // Rise and shine, Mr Romero... rise and shine. - reanimation_timer = null - else if(owner.stat == DEAD && !reanimation_timer) - START_TIMER - else if(converts_living && !iszombie(owner) && !reanimation_timer) - START_TIMER - -/obj/item/organ/internal/zombie_infection/remove(mob/living/carbon/human/M, special = 0) - . = ..() - if(iszombie(M) && old_species) - M.set_species(old_species) + not even death can stop, you will rise again!") + var/revive_time = rand(revive_time_min, revive_time_max) + var/flags = TIMER_STOPPABLE + timer_id = addtimer(CALLBACK(src, .proc/zombify), revive_time, flags) /obj/item/organ/internal/zombie_infection/proc/zombify() - var/datum/species/zombie = /datum/species/zombie/infectious + timer_id = null + if(owner.stat != DEAD) + return + if(!iszombie(owner)) old_species = owner.dna.species - owner.set_species(zombie) + dont_delete = TRUE // make sure the remove code above does not run when the species code replaces all the organs + owner.set_species(/datum/species/zombie/infectious) + for(var/thing in owner.viruses) // cure any new crit viruses + var/datum/disease/D = thing + D.cure(0) + dont_delete = FALSE //Fully heal the zombie's damage the first time they rise - owner.setToxLoss(0, 1) - owner.setOxyLoss(0, 1) - owner.setBrainLoss(0, 1) - owner.setCloneLoss(0,1) + owner.setToxLoss(0) + owner.setOxyLoss(0) + owner.setBrainLoss(0) + owner.setCloneLoss(0) + owner.SetLoseBreath(0) owner.heal_overall_damage(INFINITY,INFINITY,TRUE,TRUE,FALSE) - owner.updatehealth() - owner.grab_ghost(TRUE) - owner.update_revive() + + if(owner.update_revive()) + owner.grab_ghost() + owner.visible_message("[owner] suddenly convulses, as [owner.p_they()] stagger to [owner.p_their()] feet and gain a ravenous hunger in [owner.p_their()] eyes!", "You HUNGER!") playsound(owner.loc, 'sound/hallucinations/far_noise.ogg', 50, 1) - to_chat(owner, "You are now a zombie!") - -#undef START_TIMER \ No newline at end of file + owner.do_jitter_animation(living_transformation_time) + owner.Stun(living_transformation_time) + to_chat(owner, "You are now a zombie! Do not seek to be cured, do not help any non-zombies in any way, do not harm your zombie brethren and spread the disease by killing others. You are a creature of hunger and violence.") From 2014d57332d7b222f008f9bc1ff0a7c4521a92c7 Mon Sep 17 00:00:00 2001 From: Coul Date: Tue, 3 Sep 2019 15:42:31 -0400 Subject: [PATCH 08/10] override apply_damage, revert set_species changes, allow admemes to convert living people --- code/modules/mob/living/carbon/human/human.dm | 7 +-- .../mob/living/carbon/human/human_damage.dm | 55 +------------------ .../living/carbon/human/species/_species.dm | 52 +++++++++++++++++- .../living/carbon/human/species/zombies.dm | 2 +- code/modules/zombie/organs.dm | 5 +- 5 files changed, 56 insertions(+), 65 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 69c486b6155..6481f6bc04a 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1305,13 +1305,8 @@ oldspecies.handle_dna(src, TRUE) // Remove any genes that belong to the old species oldspecies.on_species_loss(src) - var/datum/species/new_race - if(ispath(new_species)) - new_race = new new_species - else if(istype(new_species)) - new_race = new_species - dna.species = new_race + dna.species = new new_species() tail = dna.species.tail diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 80b376bf33b..d33682e3c73 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -335,57 +335,4 @@ This function restores all organs. //Handle BRUTE and BURN damage handle_suit_punctures(damagetype, damage) //Handle species apply_damage procs - dna.species.spec_apply_damage(damage, damagetype, def_zone, blocked, sharp, used_weapon) - - blocked = (100 - blocked) / 100 - if(blocked <= 0) - return 0 - - var/obj/item/organ/external/organ = null - if(isorgan(def_zone)) - organ = def_zone - else - if(!def_zone) - def_zone = ran_zone(def_zone) - organ = get_organ(check_zone(def_zone)) - if(!organ) - return 0 - - damage = damage * blocked - - switch(damagetype) - if(BRUTE) - damageoverlaytemp = 20 - if(dna.species) - damage = damage * dna.species.brute_mod - - if(organ.receive_damage(damage, 0, sharp, used_weapon)) - UpdateDamageIcon() - - if(LAssailant && ishuman(LAssailant)) //superheros still get the comical hit markers - var/mob/living/carbon/human/H = LAssailant - if(H.mind && H.mind in (SSticker.mode.superheroes || SSticker.mode.supervillains || SSticker.mode.greyshirts)) - var/list/attack_bubble_recipients = list() - var/mob/living/user - for(var/mob/O in viewers(user, src)) - if(O.client && O.has_vision(information_only=TRUE)) - attack_bubble_recipients.Add(O.client) - spawn(0) - var/image/dmgIcon = image('icons/effects/hit_blips.dmi', src, "dmg[rand(1,2)]",MOB_LAYER+1) - dmgIcon.pixel_x = (!lying) ? rand(-3,3) : rand(-11,12) - dmgIcon.pixel_y = (!lying) ? rand(-11,9) : rand(-10,1) - flick_overlay(dmgIcon, attack_bubble_recipients, 9) - - - if(BURN) - damageoverlaytemp = 20 - - if(dna.species) - damage = damage * dna.species.burn_mod - - if(organ.receive_damage(0, damage, sharp, used_weapon)) - UpdateDamageIcon() - - // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). - updatehealth("apply damage") - return 1 + return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src, sharp, used_weapon) diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index 7016e523cea..3f5d8ba3709 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -311,8 +311,56 @@ /datum/species/proc/spec_death(gibbed, mob/living/carbon/human/C) return -/datum/species/proc/spec_apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, sharp = 0, obj/used_weapon = null) - return +/datum/species/proc/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, mob/living/carbon/human/H, sharp = 0, obj/used_weapon = null) + blocked = (100 - blocked) / 100 + if(blocked <= 0) + return 0 + + var/obj/item/organ/external/organ = null + if(isorgan(def_zone)) + organ = def_zone + else + if(!def_zone) + def_zone = ran_zone(def_zone) + organ = H.get_organ(check_zone(def_zone)) + if(!organ) + return 0 + + damage = damage * blocked + + switch(damagetype) + if(BRUTE) + H.damageoverlaytemp = 20 + damage = damage * brute_mod + + if(organ.receive_damage(damage, 0, sharp, used_weapon)) + H.UpdateDamageIcon() + + if(H.LAssailant && ishuman(H.LAssailant)) //superheros still get the comical hit markers + var/mob/living/carbon/human/A = H.LAssailant + if(A.mind && A.mind in (SSticker.mode.superheroes || SSticker.mode.supervillains || SSticker.mode.greyshirts)) + var/list/attack_bubble_recipients = list() + var/mob/living/user + for(var/mob/O in viewers(user, src)) + if(O.client && O.has_vision(information_only=TRUE)) + attack_bubble_recipients.Add(O.client) + spawn(0) + var/image/dmgIcon = image('icons/effects/hit_blips.dmi', src, "dmg[rand(1,2)]",MOB_LAYER+1) + dmgIcon.pixel_x = (!H.lying) ? rand(-3,3) : rand(-11,12) + dmgIcon.pixel_y = (!H.lying) ? rand(-11,9) : rand(-10,1) + flick_overlay(dmgIcon, attack_bubble_recipients, 9) + + + if(BURN) + H.damageoverlaytemp = 20 + damage = damage * burn_mod + + if(organ.receive_damage(0, damage, sharp, used_weapon)) + H.UpdateDamageIcon() + + // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). + H.updatehealth("apply damage") + return 1 /datum/species/proc/spec_stun(mob/living/carbon/human/H,amount) return diff --git a/code/modules/mob/living/carbon/human/species/zombies.dm b/code/modules/mob/living/carbon/human/species/zombies.dm index 5b019ead911..c03f92af40d 100644 --- a/code/modules/mob/living/carbon/human/species/zombies.dm +++ b/code/modules/mob/living/carbon/human/species/zombies.dm @@ -41,7 +41,7 @@ /datum/species/zombie/infectious/spec_stun(mob/living/carbon/human/H, amount) . = min(20, amount) -/datum/species/zombie/infectious/spec_apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, sharp = 0, obj/used_weapon = null) +/datum/species/zombie/infectious/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, sharp = 0, obj/used_weapon = null) . = ..() if(damage) regen_cooldown = world.time + REGENERATION_DELAY diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index 220c6c985da..76bce6ead3d 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -4,6 +4,7 @@ parent_organ = "head" slot = "zombie_infection" icon_state = "blacktumor" + var/converts_living = FALSE var/causes_damage = TRUE var/datum/species/old_species = /datum/species/human var/living_transformation_time = 3 @@ -45,7 +46,7 @@ return if(owner.suiciding) return - if(owner.stat != DEAD) + if(owner.stat != DEAD && !converts_living) return if(causes_damage && !iszombie(owner) && owner.stat != DEAD) owner.adjustToxLoss(1) @@ -63,7 +64,7 @@ /obj/item/organ/internal/zombie_infection/proc/zombify() timer_id = null - if(owner.stat != DEAD) + if(owner.stat != DEAD && !converts_living) return if(!iszombie(owner)) From ba269fdf796f9a7be760232979ae9abefac299b8 Mon Sep 17 00:00:00 2001 From: Coul Date: Tue, 3 Sep 2019 15:53:04 -0400 Subject: [PATCH 09/10] give high functoning zombies the zombie language too --- code/modules/mob/living/carbon/human/species/zombies.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/species/zombies.dm b/code/modules/mob/living/carbon/human/species/zombies.dm index c03f92af40d..6ff30c54a67 100644 --- a/code/modules/mob/living/carbon/human/species/zombies.dm +++ b/code/modules/mob/living/carbon/human/species/zombies.dm @@ -7,6 +7,7 @@ icobase = 'icons/mob/human_races/r_zombie.dmi' deform = 'icons/mob/human_races/r_def_zombie.dmi' dies_at_threshold = TRUE + language = "Zombie" species_traits = list(NO_BLOOD,NOZOMBIE,NOTRANSSTING,NO_BREATHE, RADIMMUNE, NO_SCAN) var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg') warning_low_pressure = 50 @@ -34,7 +35,6 @@ armor = 20 // 120 damage to KO a zombie, which kills it speedmod = 1.6 default_language = "Zombie" - language = "Zombie" var/heal_rate = 1 var/regen_cooldown = 0 From 7ad4479f58c0c5f821427348c3909b46d85ecf86 Mon Sep 17 00:00:00 2001 From: Couls Date: Tue, 3 Sep 2019 20:39:31 -0400 Subject: [PATCH 10/10] description not message --- code/modules/reagents/chemistry/reagents/toxins.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm index 6da16c65a92..7a060a93996 100644 --- a/code/modules/reagents/chemistry/reagents/toxins.dm +++ b/code/modules/reagents/chemistry/reagents/toxins.dm @@ -219,7 +219,7 @@ datum/reagent/romerol color = "#123524" // RGB (18, 53, 36) metabolization_rate = INFINITY can_synth = FALSE - taste_message = "CAAAARL" + taste_description = "CAAAARL" /datum/reagent/romerol/reaction_mob(mob/living/carbon/human/H) // Silently add the zombie infection organ to be activated upon death