diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm
index 0ad95519fa7..5fc19b69531 100644
--- a/code/_onclick/hud/blob_overmind.dm
+++ b/code/_onclick/hud/blob_overmind.dm
@@ -30,6 +30,8 @@
/obj/screen/blob/JumpToCore/Click()
if(isovermind(usr))
var/mob/camera/blob/B = usr
+ if(!B.placed)
+ B.place_blob_core()
B.transport_core()
/obj/screen/blob/Blobbernaut
diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm
index 00565133e40..768f23fe646 100644
--- a/code/game/gamemodes/blob/blob.dm
+++ b/code/game/gamemodes/blob/blob.dm
@@ -7,6 +7,7 @@ var/list/overminds = list()
var/list/blob_nodes = list()
var/list/blobs_legit = list() //used for win-score calculations, contains only blobs counted for win condition
+#define BLOB_NO_PLACE_TIME 1800 //time, in deciseconds, blobs are prevented from bursting in the gamemode
/datum/game_mode/blob
name = "blob"
@@ -18,7 +19,6 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
recommended_enemies = 1
round_ends_with_antag_death = 1
- restricted_jobs = list("Cyborg", "AI")
var/burst = 0
@@ -28,10 +28,10 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
var/blobwincount = 350
- var/burstdelay_low = 1200 //in deciseconds
- var/burstdelay_high = 1800 //blobs will burst after a random value between these * 2.5(minimum 5 minutes, maximum 7 and a half minutes)
+ var/messagedelay_low = 2400 //in deciseconds
+ var/messagedelay_high = 3600 //blob report will be sent after a random value between these (minimum 4 minutes, maximum 6 minutes)
- var/list/infected_crew = list()
+ var/list/blob_overminds = list()
/datum/game_mode/blob/pre_setup()
cores_to_spawn = max(round(num_players()/players_per_core, 1), 1)
@@ -42,18 +42,17 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
if (!antag_candidates.len)
break
var/datum/mind/blob = pick(antag_candidates)
- infected_crew += blob
+ blob_overminds += blob
+ blob.assigned_role = "Blob"
blob.special_role = "Blob"
- blob.restricted_roles = restricted_jobs
log_game("[blob.key] (ckey) has been selected as a Blob")
antag_candidates -= blob
- if(!infected_crew.len)
+ if(!blob_overminds.len)
return 0
return 1
-
/datum/game_mode/blob/proc/get_blob_candidates()
var/list/candidates = list()
for(var/mob/living/carbon/human/player in player_list)
@@ -62,96 +61,23 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
candidates += player
return candidates
-
-/datum/game_mode/blob/proc/blobize(mob/living/carbon/human/blob)
- var/datum/mind/blobmind = blob.mind
- if(!istype(blobmind))
- return 0
- infected_crew += blobmind
- blobmind.special_role = "Blob"
- log_game("[blob.key] (ckey) has been selected as a Blob")
- greet_blob(blobmind)
- blob << "You feel very tired and bloated! You don't have long before you burst!"
- spawn(600)
- burst_blob(blobmind)
- return 1
-
-/datum/game_mode/blob/proc/make_blobs(count)
- var/list/candidates = get_blob_candidates()
- var/mob/living/carbon/human/blob = null
- count=min(count, candidates.len)
- for(var/i = 0, i < count, i++)
- blob = pick(candidates)
- candidates -= blob
- blobize(blob)
- return count
-
-
-
/datum/game_mode/blob/announce()
world << "The current game mode is - Blob!"
world << "A dangerous alien organism is rapidly spreading throughout the station!"
world << "You must kill it all while minimizing the damage to the station."
-
-/datum/game_mode/blob/proc/greet_blob(datum/mind/blob)
- blob.current << "You are infected by the Blob!"
- blob.current << "Your body is ready to give spawn to a new blob core which will eat this station."
- blob.current << "Find a good location to spawn the core and then take control and overwhelm the station!"
- blob.current << "When you have found a location, wait until you spawn; this will happen automatically and you cannot speed up the process."
- blob.current << "If you go outside of the station level, or in space, then you will die; make sure your location has lots of ground to cover."
- return
-
/datum/game_mode/blob/proc/show_message(message)
- for(var/datum/mind/blob in infected_crew)
+ for(var/datum/mind/blob in blob_overminds)
blob.current << message
-/datum/game_mode/blob/proc/burst_blobs()
- for(var/datum/mind/blob in infected_crew)
- if(blob.special_role != "Blob Overmind")
- burst_blob(blob)
-
-/datum/game_mode/blob/proc/burst_blob(datum/mind/blob, warned=0)
- var/client/blob_client = null
- var/turf/location = null
-
- if(iscarbon(blob.current))
- var/mob/living/carbon/C = blob.current
- if(directory[ckey(blob.key)])
- blob_client = directory[ckey(blob.key)]
- location = get_turf(C)
- if(location.z != ZLEVEL_STATION || istype(location, /turf/space))
- if(!warned)
- C << "You feel ready to burst, but this isn't an appropriate place! You must return to the station!"
- message_admins("[key_name(C)] was in space when the blobs burst, and will die if he doesn't return to the station.")
- spawn(300)
- burst_blob(blob, 1)
- else
- burst ++
- log_admin("[key_name(C)] was in space when attempting to burst as a blob.")
- message_admins("[key_name(C)] was in space when attempting to burst as a blob.")
- C.gib()
- make_blobs(1)
- check_finished() //Still needed in case we can't make any blobs
-
- else if(blob_client && location)
- burst ++
- C.gib()
- var/obj/effect/blob/core/core = new(location, 200, blob_client, blob_point_rate)
- if(core.overmind && core.overmind.mind)
- core.overmind.mind.name = blob.name
- infected_crew -= blob
- infected_crew += core.overmind.mind
- core.overmind.mind.special_role = "Blob Overmind"
-
/datum/game_mode/blob/post_setup()
- for(var/datum/mind/blob in infected_crew)
- greet_blob(blob)
- var/datum/action/innate/blob/earlyhelp/B = new
- B.Grant(blob.current)
- var/datum/action/innate/blob/earlycomm/C = new
- C.Grant(blob.current)
+ for(var/datum/mind/blob in blob_overminds)
+ var/mob/camera/blob/B = blob.current.become_overmind(1)
+ var/turf/T = pick(blobstart)
+ B.loc = T
+ B.base_point_rate = blob_point_rate
+
SSshuttle.emergencyNoEscape = 1
// Disable the blob event for this round.
@@ -160,21 +86,9 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
B.max_occurrences = 0 // disable the event
spawn(0)
- var/burst_delay = rand(burstdelay_low, burstdelay_high) //between 5 and 7 and a half minutes with 1200 low and 1800 high.
+ var/message_delay = rand(messagedelay_low, messagedelay_high) //between 4 and 6 minutes with 2400 low and 3600 high.
- sleep(burst_delay)
-
- show_message("You feel tired and bloated.")
-
- sleep(burst_delay)
-
- show_message("You feel like you are about to burst.")
-
- sleep(burst_delay * 0.5)
-
- burst_blobs()
-
- sleep(burst_delay * 0.5)
+ sleep(message_delay)
send_intercept(1)
diff --git a/code/game/gamemodes/blob/blob_finish.dm b/code/game/gamemodes/blob/blob_finish.dm
index 78e557c16cf..8bfc8e6f98f 100644
--- a/code/game/gamemodes/blob/blob_finish.dm
+++ b/code/game/gamemodes/blob/blob_finish.dm
@@ -1,9 +1,9 @@
/datum/game_mode/blob/check_finished()
- if(infected_crew.len > burst)//Some blobs have yet to burst
+ if(blob_overminds.len > cores_to_spawn && cores_to_spawn > blob_cores.len)//Some blobs have yet to burst
return 0
if(blobwincount <= blobs_legit.len)//Blob took over
return 1
- if(!blob_cores.len && !overminds.len) //blob is dead
+ if(!overminds.len && !blob_cores.len) //blob is dead
if(config.continuous["blob"])
continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise
SSshuttle.emergencyNoEscape = 0
@@ -43,9 +43,9 @@
/datum/game_mode/proc/auto_declare_completion_blob()
if(istype(ticker.mode,/datum/game_mode/blob) )
var/datum/game_mode/blob/blob_mode = src
- if(blob_mode.infected_crew.len)
- var/text = "The blob[(blob_mode.infected_crew.len > 1 ? "s were" : " was")]:"
- for(var/datum/mind/blob in blob_mode.infected_crew)
+ 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)
world << text
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/blob/blobs/core.dm b/code/game/gamemodes/blob/blobs/core.dm
index 42514f7194c..eb0955b150a 100644
--- a/code/game/gamemodes/blob/blobs/core.dm
+++ b/code/game/gamemodes/blob/blobs/core.dm
@@ -15,16 +15,16 @@
var/point_rate = 2
-/obj/effect/blob/core/New(loc, var/h = 200, var/client/new_overmind = null, var/new_rate = 2)
+/obj/effect/blob/core/New(loc, client/new_overmind = null, new_rate = 2, placed = 0)
blob_cores += src
SSobj.processing |= src
update_icon() //so it atleast appears
- if(!overmind)
+ if(!placed && !overmind)
create_overmind(new_overmind)
if(overmind)
update_icon()
point_rate = new_rate
- ..(loc, h)
+ ..()
/obj/effect/blob/core/update_icon()
overlays.Cut()
@@ -95,7 +95,7 @@
C = new_overmind
if(C)
- var/mob/camera/blob/B = new(src.loc)
+ var/mob/camera/blob/B = new(src.loc, 1)
B.key = C.key
B.blob_core = src
src.overmind = B
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
index b4b3f881929..8603e6096a6 100644
--- a/code/game/gamemodes/blob/overmind.dm
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -18,8 +18,22 @@
var/datum/reagent/blob/blob_reagent_datum = new/datum/reagent/blob()
var/list/blob_mobs = list()
var/ghostimage = null
+ var/placed = 0
+ 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
-/mob/camera/blob/New()
+/mob/camera/blob/New(loc, pre_placed = 0, mode_made = 0)
+ 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
overminds += src
var/new_name = "[initial(name)] ([rand(1, 999)])"
name = new_name
@@ -39,7 +53,15 @@
/mob/camera/blob/Life()
if(!blob_core)
- qdel(src)
+ if(!placed)
+ if(manualplace_min_time && world.time >= manualplace_min_time)
+ src << "You may now place your blob core."
+ src << "You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes."
+ manualplace_min_time = 0
+ if(autoplace_max_time && world.time >= autoplace_max_time)
+ place_blob_core(base_point_rate, 1)
+ else
+ qdel(src)
..()
/mob/camera/blob/Destroy()
@@ -115,13 +137,24 @@
if(blob_core)
stat(null, "Core Health: [blob_core.health]")
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
+ if(!placed)
+ stat(null, "Time Before Automatic Placement: [max(round((autoplace_max_time - world.time)*0.1, 0.1), 0)]")
+ if(manualplace_min_time)
+ stat(null, "Time Before Manual Placement: [max(round((manualplace_min_time - world.time)*0.1, 0.1), 0)]")
/mob/camera/blob/Move(NewLoc, Dir = 0)
- var/obj/effect/blob/B = locate() in range("3x3", NewLoc)
- if(B)
- loc = NewLoc
+ if(placed)
+ var/obj/effect/blob/B = locate() in range("3x3", NewLoc)
+ if(B)
+ loc = NewLoc
+ else
+ return 0
else
- return 0
+ var/area/A = get_area(NewLoc)
+ if(istype(NewLoc, /turf/space) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
+ return 0
+ loc = NewLoc
+ return 1
/mob/camera/blob/proc/can_attack()
return (world.time > (last_attack + CLICK_CD_RANGE))
diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm
index 4c647a30145..7efa0387a5b 100644
--- a/code/game/gamemodes/blob/powers.dm
+++ b/code/game/gamemodes/blob/powers.dm
@@ -7,6 +7,50 @@
// Power verbs
+/mob/camera/blob/proc/place_blob_core(var/point_rate = base_point_rate, var/override = 0)
+ if(!override && world.time <= manualplace_min_time && world.time <= autoplace_max_time)
+ src << "It is too early to place your blob core!"
+ return 0
+ if(placed)
+ return 1
+ if(!override)
+ for(var/mob/living/M in range(7, src))
+ if("blob" in M.faction)
+ continue
+ if(M.client)
+ 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)
+ src << "Someone could see your blob core from here!"
+ return 0
+ var/turf/T = get_turf(src)
+ if(T.density)
+ src << "This spot is too dense to place a blob core on!"
+ return 0
+ for(var/obj/O in T)
+ if(istype(O, /obj/effect/blob))
+ if(istype(O, /obj/effect/blob/normal))
+ qdel(O)
+ else
+ src << "There is already a blob here!"
+ return 0
+ if(O.density)
+ src << "This spot is too dense to place a blob core on!"
+ return 0
+ else if(override == 1)
+ var/turf/T = pick(blobstart)
+ loc = T //got overrided? you're somewhere random, motherfucker
+ var/obj/effect/blob/core/core = new(get_turf(src), null, point_rate, 1)
+ core.overmind = src
+ blob_core = core
+ core.update_icon()
+ update_health_hud()
+ placed = 1
+ return 1
+
/mob/camera/blob/verb/transport_core()
set category = "Blob"
set name = "Jump to Core"
@@ -263,32 +307,6 @@
src << "In addition to the buttons on your HUD, there are a few click shortcuts to speed up expansion and defense."
src << "Shortcuts: Click = Expand Blob | Middle Mouse Click = Rally Spores | Ctrl Click = Create Shield Blob | Alt Click = Remove Blob"
src << "Attempting to talk will send a message to all other overminds, allowing you to coordinate with them."
-
-/datum/action/innate/blob
- background_icon_state = "bg_alien"
-
-/datum/action/innate/blob/earlyhelp
- name = "Blob Help"
- button_icon_state = "blob"
-
-/datum/action/innate/blob_earlyhelp/Activate()
- owner << "You are a blob!"
- owner << "You will shortly burst, and should find a quiet place to do so, out of sight of the station."
- owner << "Alternatively, you could burst near a place that would hinder the station, such as telecomms or science."
- owner << "Once you burst, you can get additional information by pressing this button again."
-
-/datum/action/innate/blob/earlycomm
- name = "Blob Communication"
- button_icon_state = "blob_comm"
-
-/datum/action/innate/blob/earlycomm/Activate()
- var/msg = stripped_input(owner, "What do you wish to tell your fellow blobs?", null, "")
- if(msg && owner)
- var/mob/living/carbon/human/O = owner
- var/spanned_message = O.say_quote(msg, O.get_spans())
- var/rendered = "\[Blob Telepathy\] [O.real_name] [spanned_message]"
- var/datum/game_mode/blob/B = ticker.mode
- B.show_message("[rendered]")
- for(var/mob/M in mob_list)
- if(isobserver(M))
- M << "(F) [rendered]"
\ No newline at end of file
+ if(!placed)
+ src << "You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes."
+ src << "You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the button in the bottom right corner of the screen."
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index 124b9bd9250..d0aae03c7b1 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -588,7 +588,7 @@
dat += "
| Blob | ||
| Progress: [blobs_legit.len]/[mode.blobwincount] |