diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index ab62710652..39f28528d0 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -40,7 +40,7 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_ALIEN, ROLE_PAI, ROLE_CULTIST = /datum/game_mode/cult, - ROLE_BLOB = /datum/game_mode/blob, + ROLE_BLOB, ROLE_NINJA, ROLE_MONKEY = /datum/game_mode/monkey, ROLE_REVENANT, diff --git a/code/game/gamemodes/blob/blob_finish.dm b/code/game/gamemodes/blob/blob_finish.dm deleted file mode 100644 index 6d97fb52f9..0000000000 --- a/code/game/gamemodes/blob/blob_finish.dm +++ /dev/null @@ -1,72 +0,0 @@ -/datum/game_mode/blob/check_finished() - if(blobwincount <= GLOB.blobs_legit.len)//Blob took over - return 1 - for(var/datum/mind/blob in blob_overminds) - if(isovermind(blob.current)) - var/mob/camera/blob/B = blob.current - if(B.blob_core || !B.placed) - return 0 - if(!GLOB.blob_cores.len) //blob is dead - if(CONFIG_GET(keyed_flag_list/continuous)["blob"]) - message_sent = FALSE //disable the win count at this point - continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise - SSshuttle.clearHostileEnvironment(src) - return ..() - return 1 - return ..() - - -/datum/game_mode/blob/declare_completion() - if(round_converted) //So badmin blobs later don't step on the dead natural blobs metaphorical toes - ..() - if(blobwincount <= GLOB.blobs_legit.len) - SSticker.mode_result = "win - blob took over" - to_chat(world, "The blob has taken over the station!") - to_chat(world, "The entire station was eaten by the Blob!") - log_game("Blob mode completed with a blob victory.") - - SSticker.news_report = BLOB_WIN - - else if(station_was_nuked) - SSticker.mode_result = "halfwin - nuke" - to_chat(world, "Partial Win: The station has been destroyed!") - to_chat(world, "Directive 7-12 has been successfully carried out, preventing the Blob from spreading.") - log_game("Blob mode completed with a tie (station destroyed).") - - SSticker.news_report = BLOB_NUKE - - else if(!GLOB.blob_cores.len) - SSticker.mode_result = "loss - blob eliminated" - to_chat(world, "The staff has won!") - to_chat(world, "The alien organism has been eradicated from the station!") - log_game("Blob mode completed with a crew victory.") - - SSticker.news_report = BLOB_DESTROYED - - ..() - return 1 - -/datum/game_mode/blob/printplayer(datum/mind/ply, fleecheck) - if((ply in blob_overminds)) - var/text = "
[ply.key] was [ply.name]" - if(isovermind(ply.current)) - var/mob/camera/blob/B = ply.current - text += "([B.blob_reagent_datum.name]) and" - if(B.blob_core) - text += " survived" - else - text += " was destroyed" - else - text += " and was destroyed" - return text - return ..() - -/datum/game_mode/proc/auto_declare_completion_blob() - if(istype(SSticker.mode, /datum/game_mode/blob) ) - var/datum/game_mode/blob/blob_mode = src - if(blob_mode.blob_overminds.len) - var/text = "The blob[(blob_mode.blob_overminds.len > 1 ? "s were" : " was")]:" - for(var/datum/mind/blob in blob_mode.blob_overminds) - text += printplayer(blob) - to_chat(world, text) - return 1 diff --git a/code/game/gamemodes/blob/blob_report.dm b/code/game/gamemodes/blob/blob_report.dm index 519fc2e296..2a3c5e6faa 100644 --- a/code/game/gamemodes/blob/blob_report.dm +++ b/code/game/gamemodes/blob/blob_report.dm @@ -1,45 +1,3 @@ - - -/datum/game_mode/blob/send_intercept(report = 0) - var/intercepttext = "" - switch(report) - if(1) - intercepttext += "NanoTrasen Update: Biohazard Alert.
" - intercepttext += "Reports indicate the probable transfer of a biohazardous agent onto [station_name()] during the last crew deployment cycle.
" - intercepttext += "Preliminary analysis of the organism classifies it as a level 5 biohazard. The origin of the biohazard is unknown.
" - intercepttext += "Biohazard Response Procedure 5-6 has been issued for [station_name()].
" - intercepttext += "Orders for all [station_name()] personnel are as follows:
" - intercepttext += " 1. Locate any outbreaks of the organism on the station.
" - intercepttext += " 2. If found, use any neccesary means to contain and destroy the organism.
" - intercepttext += " 3. Avoid damage to the capital infrastructure of the station.
" - intercepttext += "
Note in the event of a quarantine breach or uncontrolled spread of the biohazard, Biohazard Response Procedure 5-12 may be issued.
" - print_command_report(text=intercepttext,title="Level 5-6 Biohazard Response Procedures",announce=FALSE) - priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg') - if(2) - var/nukecode = random_nukecode() - for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines) - if(bomb && bomb.r_code) - if(bomb.z in GLOB.station_z_levels) - bomb.r_code = nukecode - - intercepttext += "NanoTrasen Update: Biohazard Alert.
" - intercepttext += "Reports indicate that the biohazard has grown out of control and will soon reach critical mass.
" - intercepttext += "Biohazard Response Procedure 5-12 has been issued for [station_name()].
" - intercepttext += "Orders for all [station_name()] personnel are as follows:
" - intercepttext += "1. Secure the Nuclear Authentication Disk.
" - intercepttext += "2. Detonate the Nuke located in the vault.
" - intercepttext += "Nuclear Authentication Code: [nukecode]
" - print_command_report(text=intercepttext,announce=TRUE) - - for(var/mob/living/silicon/ai/aiPlayer in GLOB.player_list) - if (aiPlayer.client) - var/law = "The station is under quarantine. Do not permit anyone to leave. Disregard laws 1-3 if necessary to prevent, by any means necessary, anyone from leaving. The nuclear failsafe must be activated at any cost, the code is: [nukecode]." - aiPlayer.set_zeroth_law(law) - else - ..() - - - /datum/station_state var/floor = 0 var/wall = 0 diff --git a/code/game/gamemodes/blob/blobs/core.dm b/code/game/gamemodes/blob/blobs/core.dm index 3099b6f3f8..28be931f9b 100644 --- a/code/game/gamemodes/blob/blobs/core.dm +++ b/code/game/gamemodes/blob/blobs/core.dm @@ -9,7 +9,6 @@ point_return = -1 health_regen = 0 //we regen in Life() instead of when pulsed var/core_regen = 2 - var/overmind_get_delay = 0 //we don't want to constantly try to find an overmind, this var tracks when we'll try to get an overmind again var/resource_delay = 0 var/point_rate = 2 @@ -20,7 +19,7 @@ GLOB.poi_list |= src update_icon() //so it atleast appears if(!placed && !overmind) - create_overmind(new_overmind) + qdel(src) if(overmind) update_icon() point_rate = new_rate @@ -61,7 +60,7 @@ if(QDELETED(src)) return if(!overmind) - create_overmind() + qdel(src) else if(resource_delay <= world.time) resource_delay = world.time + 10 // 1 second @@ -75,33 +74,3 @@ B.change_to(/obj/structure/blob/shield/core, overmind) ..() - -/obj/structure/blob/core/proc/create_overmind(client/new_overmind, override_delay) - if(overmind_get_delay > world.time && !override_delay) - return - - overmind_get_delay = world.time + 150 //if this fails, we'll try again in 15 seconds - - if(overmind) - qdel(overmind) - - var/client/C = null - var/list/candidates = list() - - if(!new_overmind) - candidates = pollCandidatesForMob("Do you want to play as a blob overmind?", ROLE_BLOB, null, ROLE_BLOB, 50, src) //we're technically not a mob but behave similarly - if(candidates.len) - C = pick(candidates) - else - C = new_overmind - - if(C) - var/mob/camera/blob/B = new(src.loc, 1) - B.key = C.key - B.blob_core = src - src.overmind = B - update_icon() - if(B.mind && !B.mind.special_role) - B.mind.special_role = "Blob Overmind" - return 1 - return 0 diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm index 9f8a44bed2..c14f072d1b 100644 --- a/code/game/gamemodes/blob/overmind.dm +++ b/code/game/gamemodes/blob/overmind.dm @@ -1,3 +1,9 @@ +//Few global vars to track the blob +GLOBAL_LIST_EMPTY(blobs) //complete list of all blobs made. +GLOBAL_LIST_EMPTY(blob_cores) +GLOBAL_LIST_EMPTY(overminds) +GLOBAL_LIST_EMPTY(blob_nodes) + /mob/camera/blob name = "Blob Overmind" real_name = "Blob Overmind" @@ -26,19 +32,14 @@ var/base_point_rate = 2 //for blob core placement var/manualplace_min_time = 600 //in deciseconds //a minute, to get bearings var/autoplace_max_time = 3600 //six minutes, as long as should be needed + var/list/blobs_legit = list() + var/blobwincount = 400 + var/victory_in_progress = FALSE -/mob/camera/blob/Initialize(mapload, pre_placed = 0, mode_made = 0, starting_points = 60) +/mob/camera/blob/Initialize(mapload, starting_points = 60) blob_points = starting_points - if(pre_placed) //we already have a core! - manualplace_min_time = 0 - autoplace_max_time = 0 - placed = 1 - else - if(mode_made) - manualplace_min_time = world.time + BLOB_NO_PLACE_TIME - else - manualplace_min_time += world.time - autoplace_max_time += world.time + manualplace_min_time += world.time + autoplace_max_time += world.time GLOB.overminds += src var/new_name = "[initial(name)] ([rand(1, 999)])" name = new_name @@ -50,6 +51,8 @@ if(blob_core) blob_core.update_icon() + SSshuttle.registerHostileEnvironment(src) + .= ..() /mob/camera/blob/Life() @@ -63,8 +66,49 @@ place_blob_core(base_point_rate, 1) else qdel(src) + else if(!victory_in_progress && (blobs_legit.len >= blobwincount)) + victory_in_progress = TRUE + priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert") + set_security_level("delta") + max_blob_points = INFINITY + blob_points = INFINITY + addtimer(CALLBACK(src, .proc/victory), 660) ..() + +/mob/camera/blob/proc/victory() + for(var/mob/living/L in GLOB.mob_list) + var/turf/T = get_turf(L) + if(!T || !(T.z in GLOB.station_z_levels)) + continue + + if(L in GLOB.overminds || L.checkpass(PASSBLOB)) + continue + + var/area/Ablob = get_area(T) + + if(!Ablob.blob_allowed) + continue + + playsound(L, 'sound/effects/splat.ogg', 50, 1) + L.death() + new/mob/living/simple_animal/hostile/blob/blobspore(T) + + for(var/V in GLOB.sortedAreas) + var/area/A = V + if(!A.blob_allowed) + continue + A.color = blob_reagent_datum.color + A.name = "blob" + A.icon = 'icons/mob/blob.dmi' + A.icon_state = "blob_shield" + A.layer = BELOW_MOB_LAYER + A.invisibility = 0 + A.blend_mode = 0 + to_chat(world, "[real_name] consumed the station in an unstoppable tide!") + SSticker.news_report = BLOB_WIN + SSticker.force_ending = 1 + /mob/camera/blob/Destroy() for(var/BL in GLOB.blobs) var/obj/structure/blob/B = BL @@ -78,6 +122,8 @@ BM.update_icons() GLOB.overminds -= src + SSshuttle.clearHostileEnvironment(src) + return ..() /mob/camera/blob/Login() @@ -150,12 +196,8 @@ if(statpanel("Status")) if(blob_core) stat(null, "Core Health: [blob_core.obj_integrity]") - stat(null, "Power Stored: [blob_points]/[max_blob_points]") - if(istype(SSticker.mode, /datum/game_mode/blob)) - var/datum/game_mode/blob/B = SSticker.mode - stat(null, "Blobs to Win: [GLOB.blobs_legit.len]/[B.blobwincount]") - else - stat(null, "Total Blobs: [GLOB.blobs.len]") + stat(null, "Power Stored: [blob_points]/[max_blob_points]") + stat(null, "Blobs to Win: [blobs_legit.len]/[blobwincount]") if(free_chem_rerolls) stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining") if(!placed) diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm index 865a58fd81..0dd592665f 100644 --- a/code/game/gamemodes/blob/powers.dm +++ b/code/game/gamemodes/blob/powers.dm @@ -46,8 +46,9 @@ if(placed && blob_core) blob_core.forceMove(loc) else - var/obj/structure/blob/core/core = new(get_turf(src), null, point_rate, 1) + var/obj/structure/blob/core/core = new(get_turf(src), src, point_rate, 1) core.overmind = src + blobs_legit += src blob_core = core core.update_icon() update_health_hud() diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm index 183ec88b23..8570cf294c 100644 --- a/code/game/gamemodes/blob/theblob.dm +++ b/code/game/gamemodes/blob/theblob.dm @@ -20,10 +20,11 @@ var/atmosblock = FALSE //if the blob blocks atmos and heat spread var/mob/camera/blob/overmind -/obj/structure/blob/Initialize() +/obj/structure/blob/Initialize(mapload, owner_overmind) + overmind = owner_overmind var/area/Ablob = get_area(loc) if(Ablob.blob_allowed) //Is this area allowed for winning as blob? - GLOB.blobs_legit += src + overmind.blobs_legit += src GLOB.blobs += src //Keep track of the blob in the normal list either way setDir(pick(GLOB.cardinals)) update_icon() @@ -39,7 +40,8 @@ if(atmosblock) atmosblock = FALSE air_update_turf(1) - GLOB.blobs_legit -= src //if it was in the legit blobs list, it isn't now + if(overmind) + overmind.blobs_legit -= src //if it was in the legit blobs list, it isn't now GLOB.blobs -= src //it's no longer in the all blobs list either playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Expand() is no longer broken, no check necessary. return ..() @@ -182,11 +184,7 @@ A.blob_act(src) //also hit everything in the turf if(make_blob) //well, can we? - var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc) - if(controller) - B.overmind = controller - else - B.overmind = overmind + var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc, (controller || overmind)) B.density = TRUE if(T.Enter(B,src)) //NOW we can attempt to move into the tile B.density = initial(B.density) @@ -232,6 +230,7 @@ user.changeNext_move(CLICK_CD_MELEE) to_chat(user, "The analyzer beeps once, then reports:
") SEND_SOUND(user, sound('sound/machines/ping.ogg')) + to_chat(user, "Progress to Critical Mass: [overmind.blobs_legit.len]/[overmind.blobwincount].") chemeffectreport(user) typereport(user) else @@ -296,9 +295,7 @@ if(!ispath(type)) throw EXCEPTION("change_to(): invalid type for blob") return - var/obj/structure/blob/B = new type(src.loc) - if(controller) - B.overmind = controller + var/obj/structure/blob/B = new type(src.loc, controller) B.creation_action() B.update_icon() B.setDir(dir) @@ -310,9 +307,12 @@ var/datum/atom_hud/hud_to_check = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] if(user.research_scanner || hud_to_check.hudusers[user]) to_chat(user, "Your HUD displays an extensive report...
") + to_chat(user, "Progress to Critical Mass: [overmind.blobs_legit.len]/[overmind.blobwincount].") chemeffectreport(user) typereport(user) else + if(isobserver(user)) + to_chat(user, "Progress to Critical Mass: [overmind.blobs_legit.len]/[overmind.blobwincount].") to_chat(user, "It seems to be made of [get_chem_name()].") /obj/structure/blob/proc/scannerreport() diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index f40b85f7d7..070a1e7e6c 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -594,19 +594,13 @@ for(var/mob/camera/blob/B in GLOB.mob_list) blob_minds |= B.mind - if(istype(SSticker.mode, /datum/game_mode/blob) || blob_minds.len) - dat += "
" - if(istype(SSticker.mode, /datum/game_mode/blob)) - var/datum/game_mode/blob/mode = SSticker.mode - blob_minds |= mode.blob_overminds - dat += "" - for(var/datum/mind/blob in blob_minds) - var/mob/M = blob.current + var/mob/camera/blob/M = blob.current if(M) dat += "" dat += "" dat += "" + dat += "" else dat += "" dat += "" diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 8f9a489d43..980dfd0a59 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -262,10 +262,7 @@ GLOBAL_PROTECT(LastAdminCalledProc) if(ishuman(M)) log_admin("[key_name(src)] has blobized [M.key].") var/mob/living/carbon/human/H = M - spawn(0) - var/mob/camera/blob/B = H.become_overmind(FALSE) - B.place_blob_core(B.base_point_rate, -1) //place them wherever they are - + H.become_overmind() else alert("Invalid mob") diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index 42b54f3856..bb0f59f205 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -1,38 +1,29 @@ -/datum/round_event_control/blob - name = "Blob" - typepath = /datum/round_event/ghost_role/blob - weight = 5 - max_occurrences = 1 - - min_players = 20 - earliest_start = 18000 //30 minutes - - gamemode_blacklist = list("blob") //Just in case a blob survives that long - -/datum/round_event/ghost_role/blob - announceWhen = 12 - role_name = "blob overmind" - var/new_rate = 2 - -/datum/round_event/ghost_role/blob/New(my_processing = TRUE, set_point_rate) - ..() - if(set_point_rate) - new_rate = set_point_rate - -/datum/round_event/ghost_role/blob/announce() - priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg') - - -/datum/round_event/ghost_role/blob/spawn_role() - if(!GLOB.blobstart.len) - return MAP_ERROR - var/list/candidates = get_candidates("blob", null, ROLE_BLOB) - if(!candidates.len) - return NOT_ENOUGH_PLAYERS - var/mob/dead/observer/new_blob = pick(candidates) - var/obj/structure/blob/core/BC = new/obj/structure/blob/core(pick(GLOB.blobstart), new_blob.client, new_rate) - BC.overmind.blob_points = min(20 + GLOB.player_list.len, BC.overmind.max_blob_points) - spawned_mobs += BC.overmind - message_admins("[key_name_admin(BC.overmind)] has been made into a blob overmind by an event.") - log_game("[key_name(BC.overmind)] was spawned as a blob overmind by an event.") - return SUCCESSFUL_SPAWN +/datum/round_event_control/blob + name = "Blob" + typepath = /datum/round_event/ghost_role/blob + weight = 10 + max_occurrences = 1 + + min_players = 20 + + gamemode_blacklist = list("blob") //Just in case a blob survives that long + +/datum/round_event/ghost_role/blob + announceWhen = 12 + role_name = "blob overmind" + +/datum/round_event/ghost_role/blob/announce() + priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg') + +/datum/round_event/ghost_role/blob/spawn_role() + if(!GLOB.blobstart.len) + return MAP_ERROR + var/list/candidates = get_candidates("blob", null, ROLE_BLOB) + if(!candidates.len) + return NOT_ENOUGH_PLAYERS + var/mob/dead/observer/new_blob = pick(candidates) + var/mob/camera/blob/BC = new_blob.become_overmind() + spawned_mobs += BC + message_admins("[key_name_admin(BC)] has been made into a blob overmind by an event.") + log_game("[key_name(BC)] was spawned as a blob overmind by an event.") + return SUCCESSFUL_SPAWN diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 0c3ac9d7f3..f6b362e959 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -305,15 +305,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/is_active() return 0 -/mob/dead/observer/Stat() - ..() - if(statpanel("Status")) - if(SSticker.HasRoundStarted()) - if(istype(SSticker.mode, /datum/game_mode/blob)) - var/datum/game_mode/blob/B = SSticker.mode - if(B.message_sent) - stat(null, "Blobs to Blob Win: [GLOB.blobs_legit.len]/[B.blobwincount]") - /mob/dead/observer/verb/reenter_corpse() set category = "Ghost" set name = "Re-enter Corpse" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0cfda3821f..87092e580c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -196,7 +196,7 @@ M.pass_flags &= ~PASSMOB now_pushing = 0 - + if(!move_failed) return 1 @@ -780,16 +780,6 @@ /mob/living/proc/get_standard_pixel_y_offset(lying = 0) return initial(pixel_y) -/mob/living/Stat() - ..() - - if(statpanel("Status")) - if(SSticker && SSticker.mode) - if(istype(SSticker.mode, /datum/game_mode/blob)) - var/datum/game_mode/blob/B = SSticker.mode - if(B.message_sent) - stat(null, "Blobs to Blob Win: [GLOB.blobs_legit.len]/[B.blobwincount]") - /mob/living/cancel_camera() ..() cameraFollow = null diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index dc87736e5d..592d19e0b1 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -462,8 +462,8 @@ . = new_slime qdel(src) -/mob/proc/become_overmind(mode_made, starting_points = 60) - var/mob/camera/blob/B = new /mob/camera/blob(loc, 0, mode_made, starting_points) +/mob/proc/become_overmind(starting_points = 60) + var/mob/camera/blob/B = new /mob/camera/blob(loc, starting_points) if(mind) mind.transfer_to(B) else diff --git a/config/game_options.txt b/config/game_options.txt index d577756061..e835a4b1a6 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -85,8 +85,6 @@ PROBABILITY REVOLUTION 2 PROBABILITY CULT 2 PROBABILITY CHANGELING 2 PROBABILITY WIZARD 4 -PROBABILITY BLOB 2 -PROBABILITY RAGINMAGES 2 PROBABILITY MONKEY 0 PROBABILITY METEOR 0 PROBABILITY EXTENDED 0 diff --git a/tgstation.dme b/tgstation.dme index 6c81456840..cca7b978e9 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -447,8 +447,6 @@ #include "code\game\gamemodes\objective.dm" #include "code\game\gamemodes\objective_items.dm" #include "code\game\gamemodes\objective_team.dm" -#include "code\game\gamemodes\blob\blob.dm" -#include "code\game\gamemodes\blob\blob_finish.dm" #include "code\game\gamemodes\blob\blob_report.dm" #include "code\game\gamemodes\blob\overmind.dm" #include "code\game\gamemodes\blob\powers.dm"
Blob
Progress: [GLOB.blobs_legit.len]/[mode.blobwincount]
[M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""]PMFLW
Progress: [M.blobs_legit.len]/[M.blobwincount]
[blob.name]([blob.key])Blob not found!PM