diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm index 57ef7701e32..9f2c758710c 100644 --- a/code/datums/saymode.dm +++ b/code/datums/saymode.dm @@ -86,7 +86,7 @@ return FALSE -/datum/saymode/binary //everything that uses .b (silicons, drones, blobbernauts/spores, swarmers) +/datum/saymode/binary //everything that uses .b (silicons, drones, swarmers) key = MODE_KEY_BINARY mode = MODE_BINARY @@ -95,10 +95,6 @@ var/mob/living/simple_animal/hostile/swarmer/S = user S.swarmer_chat(message) return FALSE - if(isblobmonster(user)) - var/mob/living/simple_animal/hostile/blob/B = user - B.blob_chat(message) - return FALSE if(isdrone(user)) var/mob/living/simple_animal/drone/D = user D.drone_chat(message) diff --git a/code/modules/antagonists/blob/blob_mobs.dm b/code/modules/antagonists/blob/blob_mobs.dm index 93c18c56313..bb79a4e9eef 100644 --- a/code/modules/antagonists/blob/blob_mobs.dm +++ b/code/modules/antagonists/blob/blob_mobs.dm @@ -15,8 +15,12 @@ maxbodytemp = 360 unique_name = 1 a_intent = INTENT_HARM + see_in_dark = 8 + lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE + initial_language_holder = /datum/language_holder/empty var/mob/camera/blob/overmind = null var/obj/structure/blob/factory/factory = null + var/independent = FALSE /mob/living/simple_animal/hostile/blob/update_icons() if(overmind) @@ -24,6 +28,13 @@ else remove_atom_colour(FIXED_COLOUR_PRIORITY) +/mob/living/simple_animal/hostile/blob/Initialize() + . = ..() + if(!independent) //no pulling people deep into the blob + verbs -= /mob/living/verb/pulled + else + pass_flags &= ~PASSBLOB + /mob/living/simple_animal/hostile/blob/Destroy() if(overmind) overmind.blob_mobs -= src @@ -56,8 +67,11 @@ return 1 return ..() -/mob/living/simple_animal/hostile/blob/proc/blob_chat(msg) - var/spanned_message = say_quote(msg) +/mob/living/simple_animal/hostile/blob/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) + if(!overmind) + ..() + return + var/spanned_message = say_quote(message) var/rendered = "\[Blob Telepathy\] [real_name] [spanned_message]" for(var/M in GLOB.mob_list) if(isovermind(M) || istype(M, /mob/living/simple_animal/hostile/blob)) @@ -75,6 +89,7 @@ desc = "A floating, fragile spore." icon_state = "blobpod" icon_living = "blobpod" + health_doll_icon = "blobpod" health = 30 maxHealth = 30 verb_say = "psychically pulses" @@ -89,18 +104,20 @@ attack_verb_simple = "hit" attack_sound = 'sound/weapons/genhit1.ogg' movement_type = FLYING - del_on_death = 1 + del_on_death = TRUE deathmessage = "explodes into a cloud of gas!" + gold_core_spawnable = HOSTILE_SPAWN var/death_cloud_size = 1 //size of cloud produced from a dying spore var/mob/living/carbon/human/oldguy - var/is_zombie = 0 - gold_core_spawnable = HOSTILE_SPAWN + var/is_zombie = FALSE /mob/living/simple_animal/hostile/blob/blobspore/Initialize(mapload, obj/structure/blob/factory/linked_node) if(istype(linked_node)) factory = linked_node factory.spores += src . = ..() + if(linked_node.overmind && istype(linked_node.overmind.blobstrain, /datum/blobstrain/reagent/distributed_neurons) && !istype(src, /mob/living/simple_animal/hostile/blob/blobspore/weak)) + notify_ghosts("A controllable spore has been created in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Sentient Spore Created") /mob/living/simple_animal/hostile/blob/blobspore/Life() if(!is_zombie && isturf(src.loc)) @@ -111,6 +128,26 @@ if(factory && z != factory.z) death() ..() + +/mob/living/simple_animal/hostile/blob/blobspore/attack_ghost(mob/user) + . = ..() + if(.) + return + humanize_pod(user) + +/mob/living/simple_animal/hostile/blob/blobspore/proc/humanize_pod(mob/user) + if((!overmind || istype(src, /mob/living/simple_animal/hostile/blob/blobspore/weak) || !istype(overmind.blobstrain, /datum/blobstrain/reagent/distributed_neurons)) && !is_zombie) + return + if(key || stat) + return + var/pod_ask = alert("Become a blob spore?", "Are you bulbous enough?", "Yes", "No") + if(pod_ask == "No" || !src || QDELETED(src)) + return + if(key) + to_chat(user, "Someone else already took this spore!") + return + key = user.key + log_game("[key_name(src)] took control of [name].") /mob/living/simple_animal/hostile/blob/blobspore/proc/Zombify(mob/living/carbon/human/H) is_zombie = 1 @@ -134,6 +171,8 @@ oldguy = H update_icons() visible_message("The corpse of [H.name] suddenly rises!") + if(!key) + notify_ghosts("\A [src] has been created in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Blob Zombie Created") /mob/living/simple_animal/hostile/blob/blobspore/death(gibbed) // On death, create a small smoke of harmful gas (s-Acid) @@ -215,17 +254,7 @@ force_threshold = 10 pressure_resistance = 50 mob_size = MOB_SIZE_LARGE - see_in_dark = 8 - lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE hud_type = /datum/hud/blobbernaut - var/independent = FALSE - -/mob/living/simple_animal/hostile/blob/blobbernaut/Initialize() - . = ..() - if(!independent) //no pulling people deep into the blob - verbs -= /mob/living/verb/pulled - else - pass_flags &= ~PASSBLOB /mob/living/simple_animal/hostile/blob/blobbernaut/Life() if(..()) diff --git a/code/modules/antagonists/blob/blobstrains/distributed_neurons.dm b/code/modules/antagonists/blob/blobstrains/distributed_neurons.dm new file mode 100644 index 00000000000..27edb0f205f --- /dev/null +++ b/code/modules/antagonists/blob/blobstrains/distributed_neurons.dm @@ -0,0 +1,39 @@ +//kills unconscious targets and turns them into blob zombies, produces fragile spores when killed. Spore produced by factories are sentient. +/datum/blobstrain/reagent/distributed_neurons + name = "Distributed Neurons" + description = "will do very low toxin damage and turns unconscious targets into blob zombies." + effectdesc = "will also produce fragile spores when killed. Spores produced by factories are sentient." + shortdesc = "will do very low toxin damage and will turn unconscious targets into blob zombies for additional resources(for your overmind). Spores produced by factories are sentient." + analyzerdescdamage = "Does very low toxin damage and kills unconscious humans, turning them into blob zombies." + analyzerdesceffect = "Produces spores when killed. Spores produced by factories are sentient." + color = "#E88D5D" + complementary_color = "#823ABB" + message_living = ", and you feel tired" + reagent = /datum/reagent/blob/distributed_neurons + +/datum/blobstrain/reagent/distributed_neurons/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag) + if((damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") && damage <= 20 && B.obj_integrity - damage <= 0 && prob(15)) //if the cause isn't fire or a bomb, the damage is less than 21, we're going to die from that damage, 15% chance of a shitty spore. + B.visible_message("A spore floats free of the blob!") + var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(B.loc) + BS.overmind = B.overmind + BS.update_icons() + B.overmind.blob_mobs.Add(BS) + return ..() + +/datum/reagent/blob/distributed_neurons + name = "Distributed Neurons" + color = "#E88D5D" + +/datum/reagent/blob/distributed_neurons/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O) + reac_volume = ..() + M.apply_damage(0.6*reac_volume, TOX) + if(O && ishuman(M) && M.stat == UNCONSCIOUS) + M.death() //sleeping in a fight? bad plan. + var/points = rand(5, 10) + var/mob/living/simple_animal/hostile/blob/blobspore/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(get_turf(M)) + BS.overmind = O + BS.update_icons() + O.blob_mobs.Add(BS) + BS.Zombify(M) + O.add_points(points) + to_chat(O, "Gained [points] resources from the zombification of [M].") diff --git a/code/modules/antagonists/blob/blobstrains/zombifying_pods.dm b/code/modules/antagonists/blob/blobstrains/zombifying_pods.dm deleted file mode 100644 index b2bb9d51157..00000000000 --- a/code/modules/antagonists/blob/blobstrains/zombifying_pods.dm +++ /dev/null @@ -1,46 +0,0 @@ -//kills sleeping targets and turns them into blob zombies, produces fragile spores when killed or on expanding -/datum/blobstrain/reagent/zombifying_pods - name = "Zombifying Pods" - description = "will do very low toxin damage and harvest sleeping targets for additional resources and a blob zombie." - effectdesc = "will also produce fragile spores when killed and on expanding." - shortdesc = "will do very low toxin damage and harvest sleeping targets for additional resources(for your overmind) and a blob zombie." - analyzerdescdamage = "Does very low toxin damage and kills unconscious humans, turning them into blob zombies." - analyzerdesceffect = "Produces spores when expanding and when killed." - color = "#E88D5D" - complementary_color = "#823ABB" - message_living = ", and you feel tired" - reagent = /datum/reagent/blob/zombifying_pods - -/datum/blobstrain/reagent/zombifying_pods/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag) - if((damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") && damage <= 20 && B.obj_integrity - damage <= 0 && prob(30)) //if the cause isn't fire or a bomb, the damage is less than 21, we're going to die from that damage, 20% chance of a shitty spore. - B.visible_message("A spore floats free of the blob!") - var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(B.loc) - BS.overmind = B.overmind - BS.update_icons() - B.overmind.blob_mobs.Add(BS) - return ..() - -/datum/blobstrain/reagent/zombifying_pods/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O) - if(prob(10)) - var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(T) - BS.overmind = B.overmind - BS.update_icons() - newB.overmind.blob_mobs.Add(BS) - -/datum/reagent/blob/zombifying_pods - name = "Zombifying Pods" - color = "#E88D5D" - -/datum/reagent/blob/zombifying_pods/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O) - reac_volume = ..() - M.apply_damage(0.6*reac_volume, TOX) - if(O && ishuman(M) && M.stat == UNCONSCIOUS) - M.death() //sleeping in a fight? bad plan. - var/points = rand(5, 10) - var/mob/living/simple_animal/hostile/blob/blobspore/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(get_turf(M)) - BS.overmind = O - BS.update_icons() - O.blob_mobs.Add(BS) - BS.Zombify(M) - O.add_points(points) - to_chat(O, "Gained [points] resources from the zombification of [M].") diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index e2567e091cc..a2b38e0b1be 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -39,6 +39,9 @@ GLOBAL_LIST_EMPTY(blob_nodes) var/blobwincount = 400 var/victory_in_progress = FALSE var/rerolling = FALSE + var/announcement_size = 75 + var/announcement_time + var/has_announced = FALSE /mob/camera/blob/Initialize(mapload, starting_points = 60) validate_location() @@ -56,6 +59,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) if(blob_core) blob_core.update_icon() SSshuttle.registerHostileEnvironment(src) + announcement_time = world.time + 6000 . = ..() START_PROCESSING(SSobj, src) @@ -117,6 +121,10 @@ GLOBAL_LIST_EMPTY(blob_nodes) if(!victory_in_progress && max_count < blobs_legit.len) max_count = blobs_legit.len + + if((world.time >= announcement_time || blobs_legit.len >= announcement_size) && !has_announced) + priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg') + has_announced = TRUE /mob/camera/blob/proc/victory() sound_to_playing_players('sound/machines/alarm.ogg') diff --git a/code/modules/antagonists/blob/powers.dm b/code/modules/antagonists/blob/powers.dm index 794819db9b8..2289e163052 100644 --- a/code/modules/antagonists/blob/powers.dm +++ b/code/modules/antagonists/blob/powers.dm @@ -318,7 +318,7 @@ if(!surrounding_turfs.len) return for(var/mob/living/simple_animal/hostile/blob/blobspore/BS in blob_mobs) - if(isturf(BS.loc) && get_dist(BS, T) <= 35) + if(isturf(BS.loc) && get_dist(BS, T) <= 35 && !BS.key) BS.LoseTarget() BS.Goto(pick(surrounding_turfs), BS.move_to_delay) diff --git a/code/modules/antagonists/blob/structures/core.dm b/code/modules/antagonists/blob/structures/core.dm index c2ae02c5ce3..0dc9d8b43df 100644 --- a/code/modules/antagonists/blob/structures/core.dm +++ b/code/modules/antagonists/blob/structures/core.dm @@ -8,6 +8,7 @@ explosion_block = 6 point_return = -1 health_regen = 0 //we regen in Life() instead of when pulsed + resistance_flags = LAVA_PROOF /obj/structure/blob/core/Initialize(mapload, client/new_overmind = null, placed = 0) GLOB.blob_cores += src @@ -18,12 +19,8 @@ return INITIALIZE_HINT_QDEL if(overmind) update_icon() - addtimer(CALLBACK(src, .proc/generate_announcement), 1800) . = ..() -/obj/structure/blob/core/proc/generate_announcement() - priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg') - /obj/structure/blob/core/scannerreport() return "Directs the blob's expansion, gradually expands, and sustains nearby blob spores and blobbernauts." diff --git a/code/modules/antagonists/blob/structures/factory.dm b/code/modules/antagonists/blob/structures/factory.dm index 3d955036b01..756d1b03fab 100644 --- a/code/modules/antagonists/blob/structures/factory.dm +++ b/code/modules/antagonists/blob/structures/factory.dm @@ -6,6 +6,7 @@ max_integrity = 200 health_regen = 1 point_return = 25 + resistance_flags = LAVA_PROOF var/list/spores = list() var/mob/living/simple_animal/hostile/blob/blobbernaut/naut = null var/max_spores = 3 diff --git a/code/modules/antagonists/blob/structures/node.dm b/code/modules/antagonists/blob/structures/node.dm index 14fbc741c0b..8a8645c1518 100644 --- a/code/modules/antagonists/blob/structures/node.dm +++ b/code/modules/antagonists/blob/structures/node.dm @@ -7,6 +7,7 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 65, "acid" = 90) health_regen = 3 point_return = 25 + resistance_flags = LAVA_PROOF /obj/structure/blob/node/Initialize() diff --git a/code/modules/antagonists/blob/structures/resource.dm b/code/modules/antagonists/blob/structures/resource.dm index 5024d0984c1..81eda7f4edd 100644 --- a/code/modules/antagonists/blob/structures/resource.dm +++ b/code/modules/antagonists/blob/structures/resource.dm @@ -5,6 +5,7 @@ desc = "A thin spire of slightly swaying tendrils." max_integrity = 60 point_return = 15 + resistance_flags = LAVA_PROOF var/resource_delay = 0 /obj/structure/blob/resource/scannerreport() diff --git a/tgstation.dme b/tgstation.dme index a6d482b40d4..b00e0e14596 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1367,6 +1367,7 @@ #include "code\modules\antagonists\blob\blobstrains\blazing_oil.dm" #include "code\modules\antagonists\blob\blobstrains\cryogenic_poison.dm" #include "code\modules\antagonists\blob\blobstrains\debris_devourer.dm" +#include "code\modules\antagonists\blob\blobstrains\distributed_neurons.dm" #include "code\modules\antagonists\blob\blobstrains\electromagnetic_web.dm" #include "code\modules\antagonists\blob\blobstrains\energized_jelly.dm" #include "code\modules\antagonists\blob\blobstrains\explosive_lattice.dm" @@ -1378,7 +1379,6 @@ #include "code\modules\antagonists\blob\blobstrains\replicating_foam.dm" #include "code\modules\antagonists\blob\blobstrains\shifting_fragments.dm" #include "code\modules\antagonists\blob\blobstrains\synchronous_mesh.dm" -#include "code\modules\antagonists\blob\blobstrains\zombifying_pods.dm" #include "code\modules\antagonists\blob\structures\_blob.dm" #include "code\modules\antagonists\blob\structures\core.dm" #include "code\modules\antagonists\blob\structures\factory.dm"