diff --git a/code/__DEFINES/time_defines.dm b/code/__DEFINES/time_defines.dm
new file mode 100644
index 000000000000..d40f492be3a5
--- /dev/null
+++ b/code/__DEFINES/time_defines.dm
@@ -0,0 +1,18 @@
+#define MILLISECONDS *0.01
+
+#define DECISECONDS *1 //the base unit all of these defines are scaled by, because byond uses that as a unit of measurement for some fucking reason
+
+// So you can be all 10 SECONDS
+#define SECONDS *10
+
+#define MINUTES *600
+
+#define HOURS *36000
+
+#define TICKS *world.tick_lag
+
+#define SECONDS_TO_LIFE_CYCLES /2
+
+#define DS2TICKS(DS) ((DS)/world.tick_lag)
+
+#define TICKS2DS(T) ((T) TICKS)
diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm
index bf944777d231..65075c74c0a9 100644
--- a/code/__HELPERS/time.dm
+++ b/code/__HELPERS/time.dm
@@ -1,22 +1,3 @@
-#define MILLISECONDS *0.01
-
-#define DECISECONDS *1 //the base unit all of these defines are scaled by, because byond uses that as a unit of measurement for some fucking reason
-
-// So you can be all 10 SECONDS
-#define SECONDS *10
-
-#define MINUTES *600
-
-#define HOURS *36000
-
-#define TICKS *world.tick_lag
-
-#define SECONDS_TO_LIFE_CYCLES /2
-
-#define DS2TICKS(DS) ((DS)/world.tick_lag)
-
-#define TICKS2DS(T) ((T) TICKS)
-
/* This proc should only be used for world/Topic.
* If you want to display the time for which dream daemon has been running ("round time") use worldtime2text.
* If you want to display the canonical station "time" (aka the in-character time of the station) use station_time_timestamp
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 99a0b48e5734..520a6e7abbc5 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1562,12 +1562,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
if(areas)
. |= T.loc
-/proc/turf_clear(turf/T)
- for(var/atom/A in T)
- if(A.simulated)
- return FALSE
- return TRUE
-
/proc/screen_loc2turf(scr_loc, turf/origin)
var/tX = splittext(scr_loc, ",")
var/tY = splittext(tX[2], ":")
diff --git a/code/datums/components/scope.dm b/code/datums/components/scope.dm
index 4ad8faa83d65..59e32cfedd70 100644
--- a/code/datums/components/scope.dm
+++ b/code/datums/components/scope.dm
@@ -58,6 +58,9 @@
))
/datum/component/scope/process()
+ if(!tracker)
+ STOP_PROCESSING(SSprojectiles, src)
+ return
var/mob/user_mob = tracker.owner
var/client/user_client = user_mob.client
if(!user_client)
diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm
index bb31a2381a10..2fd7f426a9c8 100644
--- a/code/datums/status_effects/neutral.dm
+++ b/code/datums/status_effects/neutral.dm
@@ -351,7 +351,7 @@
for(var/mob/living/L in range(10, our_scope.given_turf))
if(locks >= LWAP_LOCK_CAP)
return
- if(L == owner || L.stat == DEAD || isslime(L) || ismonkeybasic(L) || L.invisibility > owner.see_invisible) //xenobio moment
+ if(L == owner || L.stat == DEAD || isslime(L) || ismonkeybasic(L) || L.invisibility > owner.see_invisible || isLivingSSD(L)) //xenobio moment
continue
new /obj/effect/temp_visual/single_user/lwap_ping(owner.loc, owner, L)
locks++
diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm
index 8e05021c240c..fb40dd438f33 100644
--- a/code/game/gamemodes/miniantags/morph/morph.dm
+++ b/code/game/gamemodes/miniantags/morph/morph.dm
@@ -199,6 +199,10 @@
failed_ambush()
to_chat(src, "You moved out of your ambush spot!")
+/mob/living/simple_animal/hostile/morph/add_ventcrawl()
+ . = ..()
+ on_move()
+
/mob/living/simple_animal/hostile/morph/death(gibbed)
. = ..()
add_to_all_human_data_huds()
diff --git a/code/game/machinery/vendors/custom_vendors.dm b/code/game/machinery/vendors/custom_vendors.dm
index 82e0b0c98913..12ca4b0f06a1 100644
--- a/code/game/machinery/vendors/custom_vendors.dm
+++ b/code/game/machinery/vendors/custom_vendors.dm
@@ -1,3 +1,7 @@
+#define INSERT_FAIL 0
+#define INSERT_DONE 1
+#define INSERT_NEEDS_INPUT 2
+
/obj/machinery/economy/vending/custom
name = "\improper CrewVend 3000"
refill_canister = null
@@ -17,6 +21,9 @@
return linked_pos?.linked_account || ..()
/obj/machinery/economy/vending/custom/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
+
if(istype(used, /obj/item/eftpos))
visible_message("[src] beeps as [user] links it to [used].", "You hear something beep.")
if(!isnull(linked_pos))
@@ -30,9 +37,25 @@
return ITEM_INTERACT_COMPLETE
else if(locked())
return ..()
- if(!user.canUnEquip(used, FALSE))
+
+ try_add_stock(user, used)
+ return ITEM_INTERACT_COMPLETE
+
+/// Tries to add something to the vendor. can_wait returns INSERT_NEEDS_INPUT if it would wait for user input, quiet suppresses success messages, and bag is used when the item is being transferred from a storage item.
+/obj/machinery/economy/vending/custom/proc/try_add_stock(mob/living/user, obj/item/used, can_wait = TRUE, quiet = FALSE, obj/item/storage/bag = null)
+ if(isnull(bag) && !user.canUnEquip(used, FALSE))
to_chat(user, "\The [used] is stuck to your hand!")
- return ITEM_INTERACT_COMPLETE
+ return INSERT_FAIL
+ else if(bag)
+ if(!Adjacent(user))
+ to_chat(user, "You can't reach [src] from here!")
+ return INSERT_FAIL
+ if(!user.is_holding(bag))
+ to_chat(user, "\The [bag] isn't in your hand anymore!")
+ return INSERT_FAIL
+ if(used.loc != bag)
+ to_chat(user, "\The [used] isn't in [bag] anymore!")
+ return INSERT_FAIL
for(var/datum/data/vending_product/physical/record in physical_product_records)
if(record.get_amount_left() == 0)
@@ -42,33 +65,82 @@
var/obj/item/existing = record.items[1]
if(existing.should_stack_with(used))
record.items += used
- user.unequip(used)
+ if(isnull(bag))
+ user.unequip(used)
+ else
+ bag.remove_from_storage(used)
used.moveToNullspace()
- user.visible_message("[user] puts [used] into [src].", "")
- return ITEM_INTERACT_COMPLETE
+ if(!quiet)
+ user.visible_message("[user] puts [used] into [src].", "")
+ return INSERT_DONE
+
+ if(!can_wait)
+ return INSERT_NEEDS_INPUT
var/price = tgui_input_number(user, "How much do you want to sell [used] for?")
if(!isnum(price))
- return ITEM_INTERACT_COMPLETE
+ return INSERT_FAIL
if(!Adjacent(user))
to_chat(user, "You can't reach [src] from here!")
- return ITEM_INTERACT_COMPLETE
- if(!user.is_holding(used))
- to_chat(user, "\The [used] isn't in your hand anymore!")
- return ITEM_INTERACT_COMPLETE
- if(!user.canUnEquip(used, FALSE))
- to_chat(user, "\The [used] is stuck to your hand!")
- return ITEM_INTERACT_COMPLETE
+ return INSERT_FAIL
+ if(isnull(bag))
+ if(!user.is_holding(used))
+ to_chat(user, "\The [used] isn't in your hand anymore!")
+ return INSERT_FAIL
+ if(!user.canUnEquip(used, FALSE))
+ to_chat(user, "\The [used] is stuck to your hand!")
+ return INSERT_FAIL
+ else
+ if(!user.is_holding(bag))
+ to_chat(user, "\The [bag] isn't in your hand anymore!")
+ return INSERT_FAIL
+ if(used.loc != bag)
+ to_chat(user, "\The [used] isn't in [bag] anymore!")
+ return INSERT_FAIL
var/datum/data/vending_product/physical/record = new(used.name, used.icon, used.icon_state)
record.items += used
record.price = price
physical_product_records += record
SStgui.update_uis(src, TRUE)
- user.unequip(used)
+ if(isnull(bag))
+ user.unequip(used)
+ else
+ bag.remove_from_storage(used)
used.moveToNullspace()
- user.visible_message("[user] puts [used] into [src].", "You put [used] into [src].")
- return ITEM_INTERACT_COMPLETE
+ if(!quiet)
+ user.visible_message("[user] puts [used] into [src].", "You put [used] into [src].")
+ return INSERT_DONE
+
+/obj/machinery/economy/vending/custom/MouseDrop_T(atom/dragged, mob/user, params)
+ if(!istype(dragged, /obj/item/storage))
+ return ..()
+
+ var/obj/item/storage/bag = dragged
+ var/inserted = FALSE
+ for(var/obj/item/thing in bag.contents.Copy())
+ var/result = try_add_stock(user, thing, can_wait = FALSE, quiet = TRUE, bag = bag)
+ if(result == INSERT_FAIL)
+ break
+ if(result == INSERT_DONE)
+ inserted = TRUE
+ continue
+
+ // result == INSERT_NEEDS_INPUT
+ if(inserted)
+ user.visible_message("[user] transfers some things from [bag] into [src].", "You transfer some things from [bag] into [src].")
+ // We've reported on our insertions so far, don't repeat it.
+ inserted = FALSE
+
+ // Try again, this time expecting it to wait.
+ result = try_add_stock(user, thing, bag = bag)
+ if(result == INSERT_FAIL)
+ break
+
+ if(inserted)
+ user.visible_message("[user] transfers everything from [bag] into [src].", "You transfer everything from [bag] into [src].")
+
+ return TRUE
/obj/machinery/economy/vending/custom/crowbar_act(mob/user, obj/item/I)
if(!isnull(linked_pos) && linked_pos.transaction_locked)
@@ -82,3 +154,7 @@
physical_product_records -= R
physical_hidden_records -= R
SStgui.update_uis(src, TRUE)
+
+#undef INSERT_FAIL
+#undef INSERT_DONE
+#undef INSERT_NEEDS_INPUT
diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm
index d1b2605b4b99..dfa081f7d09f 100644
--- a/code/game/objects/items/weapons/cards_ids.dm
+++ b/code/game/objects/items/weapons/cards_ids.dm
@@ -59,7 +59,7 @@
/obj/item/card/emag/magic_key/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!isairlock(target))
- return ITEM_INTERACT_COMPLETE
+ return NONE
var/obj/machinery/door/D = target
D.locked = FALSE
D.update_icon()
diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm
index 536bb735ccde..6bbda1895167 100644
--- a/code/game/objects/items/weapons/dice.dm
+++ b/code/game/objects/items/weapons/dice.dm
@@ -197,6 +197,13 @@
qdel(I)
if(5)
//Monkeying
+ if(ismachineperson(user))
+ playsound(get_turf(user), 'sound/machines/ding.ogg', 100, 1)
+ var/obj/fresh_toast = new /obj/item/food/toast(get_turf(user))
+ fresh_toast.desc += " It came out of [user]!"
+ to_chat(user, "Your internal structure is getting really toasty!")
+ user.gib()
+ return
T.visible_message("[user] transforms into a monkey!")
user.monkeyize()
if(6)
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index 912db6732717..8d82961b4663 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -213,6 +213,20 @@
throw_range = 0
throw_speed = 0
var/datum/action/changeling/weapon/parent_action
+ /// Used for deleting gun after hitting something
+ var/hit_something = FALSE
+ /// True if we're shooting our shot -- used to track shooting to prevent deleting mid shot
+ var/shooting_right_now = FALSE
+
+/obj/item/gun/magic/tentacle/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
+ shooting_right_now = TRUE
+ . = ..()
+ shooting_right_now = FALSE
+ check_should_delete()
+
+/obj/item/gun/magic/tentacle/proc/check_should_delete()
+ if(!shooting_right_now && hit_something)
+ qdel(src)
/obj/item/gun/magic/tentacle/customised_abstract_text(mob/living/carbon/owner)
return "[owner.p_their(TRUE)] [owner.l_hand == src ? "left arm" : "right arm"] has been turned into a grotesque tentacle."
@@ -294,7 +308,8 @@
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = 0)
var/mob/living/carbon/human/H = firer
- qdel(source.gun)
+ source.gun.hit_something = TRUE
+ source.gun.check_should_delete()
if(blocked >= 100)
return FALSE
if(isitem(target))
@@ -353,8 +368,8 @@
add_attack_logs(H, C, "imobilised with a changeling tentacle")
if(!iscarbon(H))
return TRUE
- var/obj/item/restraints/legcuffs/beartrap/changeling/B = new(H.loc)
- B.Crossed(C)
+ var/obj/item/restraints/legcuffs/beartrap/changeling/B = new(get_turf(L))
+ B.on_atom_entered(C, L)
return TRUE
if(INTENT_HARM)
diff --git a/code/modules/events/infestation.dm b/code/modules/events/infestation.dm
index 4b362a79ad76..b9ee7130e7db 100644
--- a/code/modules/events/infestation.dm
+++ b/code/modules/events/infestation.dm
@@ -27,17 +27,27 @@
/datum/event/infestation/start()
var/list/turf/simulated/floor/turfs = list()
- spawn_area_type = pick(spawn_areas)
- for(var/areapath in typesof(spawn_area_type))
- var/area/A = locate(areapath)
- if(!A)
- log_debug("Failed to locate area for infestation event!")
- kill()
- return
- for(var/turf/simulated/floor/F in A.contents)
- if(turf_clear(F))
- turfs += F
+ // shuffle in place so we don't have do that dance where we make a copy of
+ // the list, then pick and take, then do some conditional logic to make sure
+ // there's still areas to choose from, etc etc, it's a small list, it's cheap
+ shuffle_inplace(spawn_areas)
+ for(var/spawn_area in spawn_areas)
+ for(var/area_type in typesof(spawn_area))
+ var/area/destination = locate(area_type)
+ if(!destination)
+ continue
+ for(var/turf/simulated/floor/F in destination.contents)
+ if(!is_blocked_turf(F))
+ turfs += F
+ if(length(turfs))
+ spawn_area_type = area_type
+ spawn_on_turfs(turfs)
+ return
+
+ log_debug("Failed to locate area for infestation event!")
+ kill()
+/datum/event/infestation/proc/spawn_on_turfs(list/turfs)
var/list/spawn_types = list()
var/max_number
vermin = rand(0, 2)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 04cfc4d45625..fb1ddae797b6 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -842,7 +842,7 @@ emp_act
return TRUE
/mob/living/carbon/human/projectile_hit_check(obj/item/projectile/P)
- return (HAS_TRAIT(src, TRAIT_FLOORED) || HAS_TRAIT(src, TRAIT_NOKNOCKDOWNSLOWDOWN)) && !density && !(P.always_hit_living_nondense && (stat != DEAD)) // hit mobs that are intentionally lying down to prevent combat crawling.
+ return (HAS_TRAIT(src, TRAIT_FLOORED) || HAS_TRAIT(src, TRAIT_NOKNOCKDOWNSLOWDOWN)) && !density && !(P.always_hit_living_nondense && (stat != DEAD) && !isLivingSSD(src)) // hit mobs that are intentionally lying down to prevent combat crawling.
/mob/living/carbon/human/canBeHandcuffed()
return has_left_hand() || has_right_hand()
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 2f625649540c..479dd84f1100 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -21,7 +21,7 @@
return (!mover.density || !density || horizontal)
/mob/proc/projectile_hit_check(obj/item/projectile/P)
- return !(P.always_hit_living_nondense && (stat != DEAD)) && !density
+ return !(P.always_hit_living_nondense && (stat != DEAD) && !isLivingSSD(src)) && !density
/client/verb/toggle_throw_mode()
set hidden = 1
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 54dadd93b812..7d433e8a9187 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -187,6 +187,8 @@
var/icon_off = "camera_off"
var/size = 3
var/see_ghosts = FALSE //for the spoop of it
+ /// Cult portals and unconcealed runes have a minor form of invisibility
+ var/see_cult = TRUE
var/current_photo_num = 1
var/digital = FALSE
/// Should camera light up the scene
@@ -291,6 +293,10 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor
atoms.Add(A)
continue
+ // AI can't see unconcealed runes or cult portals
+ if(A.invisibility == INVISIBILITY_RUNES && see_cult)
+ atoms.Add(A)
+ continue
if(A.invisibility)
if(see_ghosts && isobserver(A))
var/mob/dead/observer/O = A
diff --git a/code/modules/paperwork/silicon_photography.dm b/code/modules/paperwork/silicon_photography.dm
index 283ec043d772..0b55e74003e9 100644
--- a/code/modules/paperwork/silicon_photography.dm
+++ b/code/modules/paperwork/silicon_photography.dm
@@ -15,6 +15,7 @@
/// camera AI can take pictures with
/obj/item/camera/siliconcam/ai_camera
name = "AI photo camera"
+ see_cult = FALSE
/// camera cyborgs can take pictures with
/obj/item/camera/siliconcam/robot_camera
diff --git a/code/modules/power/engines/supermatter/supermatter.dm b/code/modules/power/engines/supermatter/supermatter.dm
index e0afec9fa40c..facb53a60ac2 100644
--- a/code/modules/power/engines/supermatter/supermatter.dm
+++ b/code/modules/power/engines/supermatter/supermatter.dm
@@ -474,7 +474,7 @@
// Pass all the gas related code an empty gas container
removed = new()
damage_archived = damage
- if(!removed || !removed.total_moles() || isspaceturf(T)) //we're in space or there is no gas to process
+ if(!removed || removed.total_moles() <= 0 || isspaceturf(T)) //we're in space or there is no gas to process
if(takes_damage)
damage += max((power / 1000) * DAMAGE_INCREASE_MULTIPLIER, 0.1) // always does at least some damage
else
@@ -577,18 +577,18 @@
//Power * 0.55 * a value between 1 and 0.8
var/device_energy = power * REACTION_POWER_MODIFIER
- // Calculate temperature change in terms of thermal energy, scaled by the average specific heat of the gas.
- if(removed.total_moles())
- var/produced_joules = max(0, ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER) * heat_multiplier)
- produced_joules *= (removed.heat_capacity() / removed.total_moles())
- removed.set_temperature((removed.thermal_energy() + produced_joules) / removed.heat_capacity())
-
//Calculate how much gas to release
//Varies based on power and gas content
removed.set_toxins(removed.toxins() + max(((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER) * gas_multiplier, 0))
//Varies based on power, gas content, and heat
removed.set_oxygen(removed.oxygen() + max((((device_energy + removed.temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER) * gas_multiplier, 0))
+ // Calculate temperature change in terms of thermal energy, scaled by the average specific heat of the gas.
+ if(removed.total_moles() >= 1)
+ var/produced_joules = max(0, ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER) * heat_multiplier)
+ produced_joules *= (removed.heat_capacity() / removed.total_moles())
+ removed.set_temperature((removed.thermal_energy() + produced_joules) / removed.heat_capacity())
+
if(produces_gas)
env.merge(removed)
diff --git a/code/modules/projectiles/guns/energy/special_eguns.dm b/code/modules/projectiles/guns/energy/special_eguns.dm
index 585190d4bed9..7d5fab6f293e 100644
--- a/code/modules/projectiles/guns/energy/special_eguns.dm
+++ b/code/modules/projectiles/guns/energy/special_eguns.dm
@@ -357,7 +357,7 @@
P.precision = 0
P.failchance = 0
P.can_multitool_to_remove = 1
- if(W.name == "bluespace beam")
+ if(W.name == "wormhole beam")
qdel(blue)
blue = P
else
diff --git a/code/tests/_game_test.dm b/code/tests/_game_test.dm
index a7853c1d277b..24a5d2a32e9c 100644
--- a/code/tests/_game_test.dm
+++ b/code/tests/_game_test.dm
@@ -19,6 +19,8 @@ GLOBAL_LIST_EMPTY(game_test_chats)
#define TEST_ASSERT_ANY_CHATLOG(puppet, text) if(!puppet.any_chatlog_has_text(text)) { return Fail("Expected `[text]` in any chatlog but got [jointext(puppet.get_chatlogs(), "\n")]", __FILE__, __LINE__) }
+#define TEST_ASSERT_NOT_CHATLOG(puppet, text) if(puppet.any_chatlog_has_text(text)) { return Fail("Didn't expect `[text]` in any chatlog but got [jointext(puppet.get_chatlogs(), "\n")]", __FILE__, __LINE__) }
+
/// Asserts that the two parameters passed are equal, fails otherwise
/// Optionally allows an additional message in the case of a failure
#define TEST_ASSERT_EQUAL(a, b, message) do { \
diff --git a/code/tests/_game_test_puppeteer.dm b/code/tests/_game_test_puppeteer.dm
index e4c6c039a7c2..3c340d925d8e 100644
--- a/code/tests/_game_test_puppeteer.dm
+++ b/code/tests/_game_test_puppeteer.dm
@@ -48,6 +48,16 @@
origin_test.Fail("could not spawn obj [obj_type] near [src]")
+/datum/test_puppeteer/proc/use_item_in_hand()
+ var/obj/item/item = puppet.get_active_hand()
+ if(!item)
+ return
+
+ item.activate_self(puppet)
+ puppet.next_click = world.time
+ puppet.next_move = world.time
+ return TRUE
+
/datum/test_puppeteer/proc/click_on(target, params)
var/datum/test_puppeteer/puppet_target = target
if(istype(puppet_target))
diff --git a/modular_ss220/events/code/headcrabs.dm b/modular_ss220/events/code/headcrabs.dm
index f6a71bceb4d8..f16f19994e81 100644
--- a/modular_ss220/events/code/headcrabs.dm
+++ b/modular_ss220/events/code/headcrabs.dm
@@ -18,7 +18,7 @@
var/area/randomarea = pick(availableareas)
var/list/turf/simulated/floor/turfs = list()
for(var/turf/simulated/floor/F in randomarea)
- if(turf_clear(F))
+ if(!is_blocked_turf(F))
turfs += F
var/list/spawn_types = list()
var/max_number
diff --git a/modular_ss220/events/code/infestation_extended.dm b/modular_ss220/events/code/infestation_extended.dm
index 67214e1d7ff0..04654bc43478 100644
--- a/modular_ss220/events/code/infestation_extended.dm
+++ b/modular_ss220/events/code/infestation_extended.dm
@@ -40,7 +40,7 @@
kill()
return
for(var/turf/simulated/floor/F in A.contents)
- if(turf_clear(F))
+ if(!is_blocked_turf(F))
turfs += F
var/list/spawn_types = list()
diff --git a/paradise.dme b/paradise.dme
index 6df31d62b74a..33f8c7c3f3eb 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -135,6 +135,7 @@
#include "code\__DEFINES\tgs.dm"
#include "code\__DEFINES\tgui_defines.dm"
#include "code\__DEFINES\tickets_defines.dm"
+#include "code\__DEFINES\time_defines.dm"
#include "code\__DEFINES\tools_defines.dm"
#include "code\__DEFINES\turfs.dm"
#include "code\__DEFINES\typeids.dm"
diff --git a/rustlibs.dll b/rustlibs.dll
index 1c7b3cec49f6..fd0fde8a12b5 100644
Binary files a/rustlibs.dll and b/rustlibs.dll differ
diff --git a/rustlibs_prod.dll b/rustlibs_prod.dll
index 7b60ae6cf9e5..e91053a07f08 100644
Binary files a/rustlibs_prod.dll and b/rustlibs_prod.dll differ