diff --git a/code/datums/antagonists/blob.dm b/code/datums/antagonists/blob.dm
new file mode 100644
index 0000000000..5689e6a567
--- /dev/null
+++ b/code/datums/antagonists/blob.dm
@@ -0,0 +1,59 @@
+/datum/antagonist/blob
+ name = "Blob"
+ roundend_category = "blobs"
+ job_rank = ROLE_BLOB
+
+ var/datum/action/innate/blobpop/pop_action
+ var/starting_points_human_blob = 60
+ var/point_rate_human_blob = 2
+
+/datum/antagonist/blob/roundend_report()
+ var/basic_report = ..()
+ //Display max blobpoints for blebs that lost
+ if(isovermind(owner.current)) //embarrasing if not
+ var/mob/camera/blob/overmind = owner.current
+ if(!overmind.victory_in_progress) //if it won this doesn't really matter
+ var/point_report = "
[owner.name] took over [overmind.max_count] tiles at the height of its growth."
+ return basic_report+point_report
+ return basic_report
+
+/datum/antagonist/blob/greet()
+ if(!isovermind(owner.current))
+ to_chat(owner,"You feel bloated.")
+
+/datum/antagonist/blob/on_gain()
+ create_objectives()
+ . = ..()
+
+/datum/antagonist/blob/proc/create_objectives()
+ var/datum/objective/blob_takeover/main = new
+ main.owner = owner
+ objectives += main
+ owner.objectives |= objectives
+
+/datum/antagonist/blob/apply_innate_effects(mob/living/mob_override)
+ if(!isovermind(owner.current))
+ if(!pop_action)
+ pop_action = new
+ pop_action.Grant(owner.current)
+
+/datum/objective/blob_takeover
+ explanation_text = "Reach critical mass!"
+
+//Non-overminds get this on blob antag assignment
+/datum/action/innate/blobpop
+ name = "Pop"
+ desc = "Unleash the blob"
+ icon_icon = 'icons/mob/blob.dmi'
+ button_icon_state = "blob"
+
+/datum/action/innate/blobpop/Activate()
+ var/mob/old_body = owner
+ var/datum/antagonist/blob/blobtag = owner.mind.has_antag_datum(/datum/antagonist/blob)
+ if(!blobtag)
+ Remove()
+ return
+ var/mob/camera/blob/B = new /mob/camera/blob(get_turf(old_body), blobtag.starting_points_human_blob)
+ owner.mind.transfer_to(B)
+ old_body.gib()
+ B.place_blob_core(blobtag.point_rate_human_blob, pop_override = TRUE)
\ No newline at end of file
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
index 878b747ea9..cc96a69f34 100644
--- a/code/game/gamemodes/blob/overmind.dm
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -4,6 +4,7 @@ GLOBAL_LIST_EMPTY(blob_cores)
GLOBAL_LIST_EMPTY(overminds)
GLOBAL_LIST_EMPTY(blob_nodes)
+
/mob/camera/blob
name = "Blob Overmind"
real_name = "Blob Overmind"
@@ -33,10 +34,12 @@ GLOBAL_LIST_EMPTY(blob_nodes)
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/max_count = 0 //The biggest it got before death
var/blobwincount = 400
var/victory_in_progress = FALSE
/mob/camera/blob/Initialize(mapload, starting_points = 60)
+ validate_location()
blob_points = starting_points
manualplace_min_time += world.time
autoplace_max_time += world.time
@@ -50,11 +53,18 @@ GLOBAL_LIST_EMPTY(blob_nodes)
color = blob_reagent_datum.complementary_color
if(blob_core)
blob_core.update_icon()
-
SSshuttle.registerHostileEnvironment(src)
-
.= ..()
+/mob/camera/blob/proc/validate_location()
+ var/turf/T = get_turf(src)
+ var/area/A = get_area(T)
+ if(((A && !A.blob_allowed) || !T || !(T.z in GLOB.station_z_levels)) && LAZYLEN(GLOB.blobstart))
+ T = get_turf(pick(GLOB.blobstart))
+ if(!T)
+ CRASH("No blobspawnpoints and blob spawned in nullspace.")
+ forceMove(T)
+
/mob/camera/blob/Life()
if(!blob_core)
if(!placed)
@@ -73,6 +83,9 @@ GLOBAL_LIST_EMPTY(blob_nodes)
max_blob_points = INFINITY
blob_points = INFINITY
addtimer(CALLBACK(src, .proc/victory), 450)
+
+ if(!victory_in_progress && max_count < blobs_legit.len)
+ max_count = blobs_legit.len
..()
@@ -111,6 +124,11 @@ GLOBAL_LIST_EMPTY(blob_nodes)
A.layer = BELOW_MOB_LAYER
A.invisibility = 0
A.blend_mode = 0
+ var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
+ if(B)
+ var/datum/objective/blob_takeover/main_objective = locate() in B.objectives
+ if(main_objective)
+ main_objective.completed = TRUE
to_chat(world, "[real_name] consumed the station in an unstoppable tide!")
SSticker.news_report = BLOB_WIN
SSticker.force_ending = 1
@@ -134,7 +152,6 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob/Login()
..()
- sync_mind()
to_chat(src, "You are the overmind!")
blob_help()
update_health_hud()
@@ -224,3 +241,9 @@ GLOBAL_LIST_EMPTY(blob_nodes)
return 0
forceMove(NewLoc)
return 1
+
+/mob/camera/blob/mind_initialize()
+ . = ..()
+ var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
+ if(!B)
+ mind.add_antag_datum(/datum/antagonist/blob)
\ No newline at end of file
diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm
index 2ef047506f..e88cc8fb96 100644
--- a/code/game/gamemodes/blob/powers.dm
+++ b/code/game/gamemodes/blob/powers.dm
@@ -7,22 +7,23 @@
// Power verbs
-/mob/camera/blob/proc/place_blob_core(point_rate, placement_override)
+/mob/camera/blob/proc/place_blob_core(point_rate, placement_override , pop_override = FALSE)
if(placed && placement_override != -1)
return 1
if(!placement_override)
- for(var/mob/living/M in range(7, src))
- if("blob" in M.faction)
- continue
- if(M.client)
- to_chat(src, "There is someone too close to place your blob core!")
- return 0
- for(var/mob/living/M in view(13, src))
- if("blob" in M.faction)
- continue
- if(M.client)
- to_chat(src, "Someone could see your blob core from here!")
- return 0
+ if(!pop_override)
+ for(var/mob/living/M in range(7, src))
+ if("blob" in M.faction)
+ continue
+ if(M.client)
+ to_chat(src, "There is someone too close to place your blob core!")
+ return 0
+ for(var/mob/living/M in view(13, src))
+ if("blob" in M.faction)
+ continue
+ if(M.client)
+ to_chat(src, "Someone could see your blob core from here!")
+ return 0
var/turf/T = get_turf(src)
if(T.density)
to_chat(src, "This spot is too dense to place a blob core on!")
@@ -37,7 +38,7 @@
else if(O.density)
to_chat(src, "This spot is too dense to place a blob core on!")
return 0
- if(world.time <= manualplace_min_time && world.time <= autoplace_max_time)
+ if(!pop_override && world.time <= manualplace_min_time && world.time <= autoplace_max_time)
to_chat(src, "It is too early to place your blob core!")
return 0
else if(placement_override == 1)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 42a1ce725f..c501984de8 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -468,11 +468,7 @@
qdel(src)
/mob/proc/become_overmind(starting_points = 60)
- var/turf/T = get_turf(loc) //just to avoid messing up in lockers
- var/area/A = get_area(T)
- if(((A && !A.blob_allowed) || !(T.z in GLOB.station_z_levels)) && LAZYLEN(GLOB.blobstart))
- T = get_turf(pick(GLOB.blobstart))
- var/mob/camera/blob/B = new /mob/camera/blob(T, starting_points)
+ var/mob/camera/blob/B = new /mob/camera/blob(get_turf(src), starting_points)
B.key = key
. = B
qdel(src)
diff --git a/tgstation.dme b/tgstation.dme
index 4d7f43a3e4..d65f136de9 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -326,6 +326,7 @@
#include "code\datums\actions\ninja.dm"
#include "code\datums\antagonists\abductor.dm"
#include "code\datums\antagonists\antag_datum.dm"
+#include "code\datums\antagonists\blob.dm"
#include "code\datums\antagonists\brother.dm"
#include "code\datums\antagonists\changeling.dm"
#include "code\datums\antagonists\clockcult.dm"