diff --git a/code/__DATASTRUCTURES/globals.dm b/code/__DATASTRUCTURES/globals.dm
index bcc860245f..808f8da757 100644
--- a/code/__DATASTRUCTURES/globals.dm
+++ b/code/__DATASTRUCTURES/globals.dm
@@ -1,38 +1,38 @@
-//See controllers/globals.dm
-#define GLOBAL_MANAGED(X, InitValue)\
-/datum/controller/global_vars/proc/InitGlobal##X(){\
- ##X = ##InitValue;\
- gvars_datum_init_order += #X;\
-}
-#define GLOBAL_UNMANAGED(X, InitValue) /datum/controller/global_vars/proc/InitGlobal##X()
-
-#ifndef TESTING
-#define GLOBAL_PROTECT(X)\
-/datum/controller/global_vars/InitGlobal##X(){\
- ..();\
- gvars_datum_protected_varlist += #X;\
-}
-#else
-#define GLOBAL_PROTECT(X)
-#endif
-
-#define GLOBAL_REAL_VAR(X) var/global/##X
-#define GLOBAL_REAL(X, Typepath) var/global##Typepath/##X
-
-#define GLOBAL_RAW(X) /datum/controller/global_vars/var/global##X
-
-#define GLOBAL_VAR_INIT(X, InitValue) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, InitValue)
-
-#define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X, InitValue)
-
-#define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue)
-
-#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
-
-#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)
-
-#define GLOBAL_VAR(X) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, null)
-
-#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, null)
-
-#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, null)
\ No newline at end of file
+//See controllers/globals.dm
+#define GLOBAL_MANAGED(X, InitValue)\
+/datum/controller/global_vars/proc/InitGlobal##X(){\
+ ##X = ##InitValue;\
+ gvars_datum_init_order += #X;\
+}
+#define GLOBAL_UNMANAGED(X) /datum/controller/global_vars/proc/InitGlobal##X() { return; }
+
+#ifndef TESTING
+#define GLOBAL_PROTECT(X)\
+/datum/controller/global_vars/InitGlobal##X(){\
+ ..();\
+ gvars_datum_protected_varlist += #X;\
+}
+#else
+#define GLOBAL_PROTECT(X)
+#endif
+
+#define GLOBAL_REAL_VAR(X) var/global/##X
+#define GLOBAL_REAL(X, Typepath) var/global##Typepath/##X
+
+#define GLOBAL_RAW(X) /datum/controller/global_vars/var/global##X
+
+#define GLOBAL_VAR_INIT(X, InitValue) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, InitValue)
+
+#define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X)
+
+#define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue)
+
+#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
+
+#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)
+
+#define GLOBAL_VAR(X) GLOBAL_RAW(/##X); GLOBAL_UNMANAGED(X)
+
+#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_UNMANAGED(X)
+
+#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_UNMANAGED(X)
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index b83fc3dd39..66c12adc72 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -468,4 +468,6 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define DUMMY_HUMAN_SLOT_MANIFEST "dummy_manifest_generation"
#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round
- //This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored
\ No newline at end of file
+ //This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored
+
+#define MAX_PROC_DEPTH 195 // 200 proc calls deep and shit breaks, this is a bit lower to give some safety room
\ No newline at end of file
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/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index cae42d62e8..75e912dee7 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -503,12 +503,22 @@ Turf and target are separate in case you want to teleport some distance from a t
var/y=arcsin(x/sqrt(1+x*x))
return y
-/atom/proc/GetAllContents(list/output=list())
+/*
+Recursively gets all contents of contents and returns them all in a list.
+
+recursive_depth is useful if you only want a turf and everything on it (recursive_depth=1)
+Do not set recursive depth higher than MAX_PROC_DEPTH as byond breaks when that limit is reached.
+*/
+/atom/proc/GetAllContents(list/output=list(), recursive_depth=MAX_PROC_DEPTH, _current_depth=0)
. = output
output += src
+ if(_current_depth == recursive_depth)
+ if(_current_depth == MAX_PROC_DEPTH)
+ WARNING("Get all contents reached the max recursive depth of [MAX_PROC_DEPTH]. More and we would break shit. Offending atom: [src]")
+ return
for(var/i in 1 to contents.len)
var/atom/thing = contents[i]
- thing.GetAllContents(output)
+ thing.GetAllContents(output, recursive_depth, ++_current_depth)
//Step-towards method of determining whether one atom can see another. Similar to viewers()
/proc/can_see(atom/source, atom/target, length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate.
diff --git a/code/citadel/cit_guns.dm b/code/citadel/cit_guns.dm
index 7127371830..bf8d034148 100644
--- a/code/citadel/cit_guns.dm
+++ b/code/citadel/cit_guns.dm
@@ -190,13 +190,15 @@
needs_permit = 0
mag_type = /obj/item/ammo_box/magazine/toy/x9
casing_ejector = 0
- spread = 45 //MAXIMUM XCOM MEMES (actually that'd be 90 spread)
+ spread = 90 //MAXIMUM XCOM MEMES (actually that'd be 180 spread)
+ w_class = WEIGHT_CLASS_BULKY
+ weapon_weight = WEAPON_HEAVY
/datum/design/foam_x9
name = "Foam Force X9 Rifle"
id = "foam_x9"
build_type = AUTOLATHE
- materials = list(MAT_METAL = 20000, MAT_GLASS = 10000)
+ materials = list(MAT_METAL = 24000, MAT_GLASS = 14000)
build_path = /obj/item/gun/ballistic/automatic/x9/toy
category = list("hacked", "Misc")
@@ -496,6 +498,9 @@
mag_type = /obj/item/ammo_box/magazine/toy/foamag
casing_ejector = FALSE
origin_tech = "combat=2;engineering=2;magnets=2"
+ spread = 60
+ w_class = WEIGHT_CLASS_BULKY
+ weapon_weight = WEAPON_HEAVY
/datum/design/foam_magrifle
name = "Foam Force MagRifle"
@@ -635,7 +640,7 @@
name = "MagTag Hyper Rifle"
id = "foam_hyperburst"
build_type = AUTOLATHE
- materials = list(MAT_METAL = 35000, MAT_GLASS = 15000)
+ materials = list(MAT_METAL = 35000, MAT_GLASS = 25000)
build_path = /obj/item/gun/energy/laser/practice/hyperburst
category = list("hacked", "Misc")
@@ -680,6 +685,7 @@
suppressed = TRUE
burst_size = 1
fire_delay = 0
+ spread = 60
actions_types = list()
/obj/item/gun/ballistic/automatic/toy/pistol/stealth/update_icon()
@@ -695,7 +701,7 @@
name = "Foam Force Stealth Pistol"
id = "foam_sp"
build_type = AUTOLATHE
- materials = list(MAT_METAL = 15000, MAT_GLASS = 1000)
+ materials = list(MAT_METAL = 30000, MAT_GLASS = 15000)
build_path = /obj/item/gun/ballistic/automatic/toy/pistol/stealth
category = list("hacked", "Misc")
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 5607dde491..852437705b 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -86,8 +86,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
sortTim(subsystems, /proc/cmp_subsystem_init)
reverseRange(subsystems)
for(var/datum/controller/subsystem/ss in subsystems)
- testing("Shutdown [ss.name] subsystem")
+ log_world("Shutting down [ss.name] subsystem...")
ss.Shutdown()
+ log_world("Shutdown complete")
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
// -1 if we encountered a runtime trying to recreate it
@@ -595,4 +596,4 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
if (client_count < CONFIG_GET(number/mc_tick_rate/disable_high_pop_mc_mode_amount))
processing = CONFIG_GET(number/mc_tick_rate/base_mc_tick_rate)
else if (client_count > CONFIG_GET(number/mc_tick_rate/high_pop_mc_mode_amount))
- processing = CONFIG_GET(number/mc_tick_rate/high_pop_mc_tick_rate)
\ No newline at end of file
+ processing = CONFIG_GET(number/mc_tick_rate/high_pop_mc_tick_rate)
diff --git a/code/datums/antagonists/brother.dm b/code/datums/antagonists/brother.dm
index 77f611cf2c..6458e6da09 100644
--- a/code/datums/antagonists/brother.dm
+++ b/code/datums/antagonists/brother.dm
@@ -20,6 +20,7 @@
/datum/antagonist/brother/on_gain()
SSticker.mode.brothers += owner
owner.objectives += team.objectives
+ owner.special_role = special_role
finalize_brother()
return ..()
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 91bc8a4f8a..91409ac4ed 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
@@ -65,7 +64,7 @@
if(QDELETED(src))
return
if(!overmind)
- create_overmind()
+ qdel(src)
else
if(resource_delay <= world.time)
resource_delay = world.time + 10 // 1 second
@@ -79,33 +78,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 3199cc369a..e6cae65c03 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()
@@ -121,6 +124,8 @@
BM.update_icons()
GLOB.overminds -= src
+ SSshuttle.clearHostileEnvironment(src)
+
return ..()
/mob/camera/blob/Login()
@@ -193,12 +198,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/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 694255702a..128a794bc6 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -182,6 +182,10 @@
/datum/game_mode/process()
return 0
+//For things that do not die easily
+/datum/game_mode/proc/are_special_antags_dead()
+ return TRUE
+
/datum/game_mode/proc/check_finished(force_ending) //to be called by SSticker
if(!SSticker.setup_done)
@@ -218,6 +222,9 @@
living_antag_player = Player
return 0
+ if(!are_special_antags_dead())
+ return FALSE
+
if(!continuous[config_tag] || force_ending)
return 1
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index 149c2ae912..b38ac384fb 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -44,6 +44,11 @@
if(spent)
to_chat(user, "This shard is spent; it is now just a creepy rock.")
+/obj/item/device/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
+ for(var/mob/living/simple_animal/shade/A in src)
+ A.death()
+ return ..()
+
//////////////////////////////Capturing////////////////////////////////////////////////////////
/obj/item/device/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index 326889b872..304f80b470 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -42,7 +42,8 @@
man is a dangerous mutant with the ability to alter himself and the world around him by what he and his leaders believe to be magic. If this man attempts an attack on your station, \
his execution is highly encouraged, as is the preservation of his body for later study."
-/datum/game_mode/wizard/check_finished()
+
+/datum/game_mode/wizard/are_special_antags_dead()
for(var/datum/mind/wizard in wizards)
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
return FALSE
@@ -54,8 +55,8 @@
if(SSevents.wizardmode) //If summon events was active, turn it off
SSevents.toggleWizardmode()
SSevents.resetFrequency()
-
- return ..()
+
+ return TRUE
/datum/game_mode/wizard/declare_completion()
if(finished)
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index 1a931bc291..f91ebb7557 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -441,7 +441,7 @@
dat += "| [N.name]([N.key])Head body destroyed! | "
dat += "PM |
"
dat += ""
-
+
if(SSticker.mode.changelings.len > 0)
dat += "
| Changelings | | |
"
for(var/datum/mind/changeling in SSticker.mode.changelings)
@@ -596,11 +596,12 @@
if(blob_minds.len)
dat += "
| Blob | | |
"
for(var/datum/mind/blob in blob_minds)
- var/mob/M = blob.current
+ var/mob/camera/blob/M = blob.current
if(M)
dat += "| [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""] | "
dat += "PM | "
dat += "FLW |
"
+ dat += "| Progress: [M.blobs_legit.len]/[M.blobwincount] |
"
else
dat += "| [blob.name]([blob.key])Blob not found! | "
dat += "PM |
"
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/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/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
index 14b313d815..03f466ddfd 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -159,18 +159,18 @@ Difficulty: Medium
Shoot(target)
changeNext_move(CLICK_CD_RANGE)
+//I'm still of the belief that this entire proc needs to be wiped from existence.
+// do not take my touching of it to be endorsement of it. ~mso
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
- if(next_move <= world.time)
- stoplag(1)
- .() //retry
- return
- sleep((next_move - world.time) * 1.5)
+ while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
+ stoplag(1)
+ sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
if(QDELETED(target))
return
if(dashing || next_move > world.time || !Adjacent(target))
if(dashing && next_move <= world.time)
next_move = world.time + 1
- .() //recurse
+ INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
return
AttackingTarget()
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index a605d5e479..af12b87eec 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -335,9 +335,9 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
/proc/is_special_character(mob/M) // returns 1 for special characters and 2 for heroes of gamemode //moved out of admins.dm because things other than admin procs were calling this.
if(!SSticker.HasRoundStarted())
- return 0
+ return FALSE
if(!istype(M))
- return 0
+ return FALSE
if(issilicon(M))
if(iscyborg(M)) //For cyborgs, returns 1 if the cyborg has a law 0 and special_role. Returns 0 if the borg is merely slaved to an AI traitor.
var/mob/living/silicon/robot/R = M
@@ -346,13 +346,13 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
if(R.connected_ai)
if(is_special_character(R.connected_ai) && R.connected_ai.laws && (R.connected_ai.laws.zeroth_borg == R.laws.zeroth || R.connected_ai.laws.zeroth == R.laws.zeroth))
return 0 //AI is the real traitor here, so the borg itself is not a traitor
- return 1 //Slaved but also a traitor
- return 1 //Unslaved, traitor
+ return TRUE//Slaved but also a traitor
+ return TRUE //Unslaved, traitor
else if(isAI(M))
var/mob/living/silicon/ai/A = M
if(A.laws && A.laws.zeroth && A.mind && A.mind.special_role)
- return 1
- return 0
+ return TRUE
+ return FALSE
if(M.mind && M.mind.special_role)//If they have a mind and special role, they are some type of traitor or antagonist.
switch(SSticker.mode.config_tag)
if("revolution")
@@ -379,8 +379,10 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
if("abductor")
if(M.mind in SSticker.mode.abductors)
return 2
- return 1
- return 0
+ return TRUE
+ if(M.mind && LAZYLEN(M.mind.antag_datums)) //they have an antag datum!
+ return TRUE
+ return FALSE
/mob/proc/reagent_check(datum/reagent/R) // utilized in the species code
return 1
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index b934572e4f..d17b79eddc 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -376,8 +376,6 @@
if(!transfer_after)
mind.active = FALSE
mind.transfer_to(R)
- if(mind.special_role)
- R.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite")
else if(transfer_after)
R.key = key
diff --git a/code/modules/orbit/orbit.dm b/code/modules/orbit/orbit.dm
index 27fc2d86df..e4df15efaf 100644
--- a/code/modules/orbit/orbit.dm
+++ b/code/modules/orbit/orbit.dm
@@ -1,112 +1,114 @@
-/datum/orbit
- var/atom/movable/orbiter
- var/atom/orbiting
- var/lock = TRUE
- var/turf/lastloc
- var/lastprocess
-
-/datum/orbit/New(_orbiter, _orbiting, _lock)
- orbiter = _orbiter
- orbiting = _orbiting
- SSorbit.processing += src
- if (!orbiting.orbiters)
- orbiting.orbiters = list()
- orbiting.orbiters += src
-
- if (orbiter.orbiting)
- orbiter.stop_orbit()
- orbiter.orbiting = src
- Check()
- lock = _lock
-
-
-
-//do not qdel directly, use stop_orbit on the orbiter. (This way the orbiter can bind to the orbit stopping)
-/datum/orbit/Destroy(force = FALSE)
- SSorbit.processing -= src
- if (orbiter)
- orbiter.orbiting = null
- orbiter = null
- if (orbiting)
- if (orbiting.orbiters)
- orbiting.orbiters -= src
- if (!orbiting.orbiters.len)//we are the last orbit, delete the list
- orbiting.orbiters = null
- orbiting = null
- return ..()
-
-/datum/orbit/proc/Check(turf/targetloc)
- if (!orbiter)
- qdel(src)
- return
- if (!orbiting)
- orbiter.stop_orbit()
- return
- if (!orbiter.orbiting) //admin wants to stop the orbit.
- orbiter.orbiting = src //set it back to us first
- orbiter.stop_orbit()
- lastprocess = world.time
- if (!targetloc)
- targetloc = get_turf(orbiting)
- if (!targetloc || (!lock && orbiter.loc != lastloc && orbiter.loc != targetloc))
- orbiter.stop_orbit()
- return
- orbiter.loc = targetloc
- orbiter.update_parallax_contents()
- lastloc = orbiter.loc
-
-
-/atom/movable/var/datum/orbit/orbiting = null
-/atom/var/list/orbiters = null
-
-//A: atom to orbit
-//radius: range to orbit at, radius of the circle formed by orbiting (in pixels)
-//clockwise: whether you orbit clockwise or anti clockwise
-//rotation_speed: how fast to rotate (how many ds should it take for a rotation to complete)
-//rotation_segments: the resolution of the orbit circle, less = a more block circle, this can be used to produce hexagons (6 segments) triangles (3 segments), and so on, 36 is the best default.
-//pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts
-//lockinorbit: Forces src to always be on A's turf, otherwise the orbit cancels when src gets too far away (eg: ghosts)
-
-/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lockinorbit = FALSE)
- if (!istype(A))
- return
-
- new/datum/orbit(src, A, lockinorbit)
- if (!orbiting) //something failed, and our orbit datum deleted itself
- return
- var/matrix/initial_transform = matrix(transform)
-
- //Head first!
- if (pre_rotation)
- var/matrix/M = matrix(transform)
- var/pre_rot = 90
- if(!clockwise)
- pre_rot = -90
- M.Turn(pre_rot)
- transform = M
-
- var/matrix/shift = matrix(transform)
- shift.Translate(0,radius)
- transform = shift
-
- SpinAnimation(rotation_speed, -1, clockwise, rotation_segments)
-
- //we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
- transform = initial_transform
-
-/atom/movable/proc/stop_orbit()
- SpinAnimation(0,0)
- qdel(orbiting)
-
-/atom/Destroy(force = FALSE)
- . = ..()
- if (orbiters)
- for (var/thing in orbiters)
- var/datum/orbit/O = thing
- if (O.orbiter)
- O.orbiter.stop_orbit()
-
-/atom/movable/Destroy(force = FALSE)
- . = ..()
- if (orbiting)
- stop_orbit()
+/datum/orbit
+ var/atom/movable/orbiter
+ var/atom/orbiting
+ var/lock = TRUE
+ var/turf/lastloc
+ var/lastprocess
+
+/datum/orbit/New(_orbiter, _orbiting, _lock)
+ orbiter = _orbiter
+ orbiting = _orbiting
+ SSorbit.processing += src
+ if (!orbiting.orbiters)
+ orbiting.orbiters = list()
+ orbiting.orbiters += src
+
+ if (orbiter.orbiting)
+ orbiter.stop_orbit()
+ orbiter.orbiting = src
+ Check()
+ lock = _lock
+
+//do not qdel directly, use stop_orbit on the orbiter. (This way the orbiter can bind to the orbit stopping)
+/datum/orbit/Destroy(force = FALSE)
+ SSorbit.processing -= src
+ if (orbiter)
+ orbiter.orbiting = null
+ orbiter = null
+ if (orbiting)
+ if (orbiting.orbiters)
+ orbiting.orbiters -= src
+ if (!orbiting.orbiters.len)//we are the last orbit, delete the list
+ orbiting.orbiters = null
+ orbiting = null
+ return ..()
+
+/datum/orbit/proc/Check(turf/targetloc)
+ if (!orbiter)
+ qdel(src)
+ return
+ if (!orbiting)
+ orbiter.stop_orbit()
+ return
+ if (!orbiter.orbiting) //admin wants to stop the orbit.
+ orbiter.orbiting = src //set it back to us first
+ orbiter.stop_orbit()
+ lastprocess = world.time
+ if (!targetloc)
+ targetloc = get_turf(orbiting)
+ if (!targetloc || (!lock && orbiter.loc != lastloc && orbiter.loc != targetloc))
+ orbiter.stop_orbit()
+ return
+ orbiter.loc = targetloc
+ orbiter.update_parallax_contents()
+ lastloc = orbiter.loc
+ for(var/other_orbit in orbiter.orbiters)
+ var/datum/orbit/OO = other_orbit
+ if(OO == src)
+ continue
+ OO.Check(targetloc)
+
+/atom/movable/var/datum/orbit/orbiting = null
+/atom/var/list/orbiters = null
+
+//A: atom to orbit
+//radius: range to orbit at, radius of the circle formed by orbiting (in pixels)
+//clockwise: whether you orbit clockwise or anti clockwise
+//rotation_speed: how fast to rotate (how many ds should it take for a rotation to complete)
+//rotation_segments: the resolution of the orbit circle, less = a more block circle, this can be used to produce hexagons (6 segments) triangles (3 segments), and so on, 36 is the best default.
+//pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts
+//lockinorbit: Forces src to always be on A's turf, otherwise the orbit cancels when src gets too far away (eg: ghosts)
+
+/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lockinorbit = FALSE)
+ if (!istype(A))
+ return
+
+ new/datum/orbit(src, A, lockinorbit)
+ if (!orbiting) //something failed, and our orbit datum deleted itself
+ return
+ var/matrix/initial_transform = matrix(transform)
+
+ //Head first!
+ if (pre_rotation)
+ var/matrix/M = matrix(transform)
+ var/pre_rot = 90
+ if(!clockwise)
+ pre_rot = -90
+ M.Turn(pre_rot)
+ transform = M
+
+ var/matrix/shift = matrix(transform)
+ shift.Translate(0,radius)
+ transform = shift
+
+ SpinAnimation(rotation_speed, -1, clockwise, rotation_segments)
+
+ //we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
+ transform = initial_transform
+
+/atom/movable/proc/stop_orbit()
+ SpinAnimation(0,0)
+ qdel(orbiting)
+
+/atom/Destroy(force = FALSE)
+ . = ..()
+ if (orbiters)
+ for (var/thing in orbiters)
+ var/datum/orbit/O = thing
+ if (O.orbiter)
+ O.orbiter.stop_orbit()
+
+/atom/movable/Destroy(force = FALSE)
+ . = ..()
+ if (orbiting)
+ stop_orbit()
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index 55a0875b62..962802aa6d 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -25,10 +25,6 @@
P.loc = src
bin_pen = P
update_icon()
- var/static/warned = FALSE
- if(P.type == /obj/item/pen && !warned)
- warning("one or more paperbins ate a pen duing initialize()")
- warned = TRUE
/obj/item/paper_bin/fire_act(exposed_temperature, exposed_volume)
if(!total_paper)
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index b566d65f49..81dcd573f5 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -142,7 +142,7 @@
for(var/mob/living/carbon/food in GLOB.living_mob_list) //we don't care about constructs or cult-Ians or whatever. cult-monkeys are fair game i guess
var/turf/pos = get_turf(food)
- if(pos.z != src.z)
+ if(!pos || (pos.z != z))
continue
if(iscultist(food))
@@ -163,7 +163,7 @@
if(!ghost.client)
continue
var/turf/pos = get_turf(ghost)
- if(pos.z != src.z)
+ if(!pos || (pos.z != z))
continue
cultists += ghost
if(cultists.len)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 4ecfc3bde8..3f70f4f8ff 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -220,7 +220,7 @@
var/mob/M = safepick(mobs)
if(M)
return M.lowest_buckled_mob()
- var/obj/O = safepick(typecache_filter_list(T, GLOB.typecache_machine_or_structure)) - A
+ var/obj/O = safepick(typecache_filter_list(T, GLOB.typecache_machine_or_structure) - A)
if(O)
return O
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/html/changelogs/AutoChangeLog-pr-3492.yml b/html/changelogs/AutoChangeLog-pr-3492.yml
new file mode 100644
index 0000000000..bcae1670b8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3492.yml
@@ -0,0 +1,9 @@
+author: "Kor"
+delete-after: True
+changes:
+ - rscadd: "Blob is now a side antagonist."
+ - rscadd: "Event and admin blobs will now be able to choose their spawn location."
+ - rscadd: "Blob can now win in any mode by gaining enough tiles to reach Critical Mass."
+ - rscadd: "Blobs that have Critical Mass have unlimited points, and a minute after achieving critical mass, they will spread to every tile on station, killing anyone still on board and ending the round."
+ - rscadd: "Using an analyzer on a blob will now reveal its progress towards Critical Mass."
+ - rscadd: "The blob event is now more common."
diff --git a/html/changelogs/AutoChangeLog-pr-3529.yml b/html/changelogs/AutoChangeLog-pr-3529.yml
new file mode 100644
index 0000000000..02a915824f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3529.yml
@@ -0,0 +1,7 @@
+author: "Toriate"
+delete-after: True
+changes:
+ - balance: "OP foam stuff now cost slightly more to build from autolathes"
+ - balance: "OP foam stuff now turned into total memes instead of practical weapons, all burst firing foam guns have at least 60 spread. Stealth pistol also has 60 spread."
+ - balance: "Foam X9 and Mag Rifle now requires two hands to fire"
+ - bugfix: "Foam Force X9 and Mag Rifle now has its correct weight class of NOT FITTING IN FUCKING BACKPACKS"
diff --git a/html/changelogs/AutoChangeLog-pr-3546.yml b/html/changelogs/AutoChangeLog-pr-3546.yml
new file mode 100644
index 0000000000..3ce8ca350c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3546.yml
@@ -0,0 +1,4 @@
+author: "More Robust Than You"
+delete-after: True
+changes:
+ - bugfix: "Blood Brother now properly shows up in player panel"
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"