diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index f12c98963e2..97cf6b738c0 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -30,14 +30,17 @@
var/last_warning
var/chained = 0//Adminbus chain-grab
+ // We only check IsContained() every ~30 seconds
+ var/next_contained_check_time = 0
+ var/last_contained_check = TRUE
-/obj/singularity/New(loc, var/starting_energy = 50, var/temp = 0)
+/obj/singularity/New(loc, starting_energy = 50, temp = 0)
//CARN: admin-alert for chuckle-fuckery.
admin_investigate_setup()
energy = starting_energy
- if (temp)
- addtimer(CALLBACK(null, /proc/qdel, src), temp)
+ if(temp)
+ QDEL_IN(src, temp)
..()
START_PROCESSING(SSobj, src)
@@ -48,9 +51,9 @@
/obj/singularity/Destroy()
STOP_PROCESSING(SSobj, src)
- . = ..()
+ return ..()
-/obj/singularity/attack_hand(mob/user as mob)
+/obj/singularity/attack_hand(mob/user)
consume(user)
return 1
@@ -83,11 +86,11 @@
dissipate()
check_energy()
- if (current_size >= STAGE_TWO)
+ if(current_size >= STAGE_TWO)
move()
pulse()
- if (prob(event_chance)) //Chance for it to run a special event TODO: Come up with one or two more that fit.
+ if(prob(event_chance)) //Chance for it to run a special event TODO: Come up with one or two more that fit.
event()
/obj/singularity/attack_ai() //To prevent ais from gibbing themselves when they click on one.
@@ -97,13 +100,13 @@
last_warning = world.time
var/count = locate(/obj/machinery/containment_field) in orange(30, src)
- if (!count)
+ if(!count)
message_admins("A singulo has been created without containment fields active ([x], [y], [z] - JMP).")
investigate_log("was created. [count ? "" : "No containment fields were active."]", I_SINGULO)
/obj/singularity/proc/dissipate()
- if (!dissipate)
+ if(!dissipate)
return
if(dissipate_track >= dissipate_delay)
@@ -118,11 +121,11 @@
return
var/temp_allowed_size = allowed_size
- if (force_size)
+ if(force_size)
temp_allowed_size = force_size
- switch (temp_allowed_size)
- if (STAGE_ONE)
+ switch(temp_allowed_size)
+ if(STAGE_ONE)
SetName("gravitational singularity")
desc = "A gravitational singularity."
current_size = STAGE_ONE
@@ -139,7 +142,7 @@
emp_strong_range = 3
overlays.Cut()
visible_message("The singularity has shrunk to a rather pitiful size.")
- if (STAGE_TWO) //1 to 3 does not check for the turfs if you put the gens right next to a 1x1 then its going to eat them.
+ if(STAGE_TWO) //1 to 3 does not check for the turfs if you put the gens right next to a 1x1 then its going to eat them.
SetName("gravitational singularity")
desc = "A gravitational singularity."
current_size = STAGE_TWO
@@ -161,8 +164,8 @@
visible_message("The singularity noticeably grows in size.")
else
visible_message("The singularity has shrunk to a less powerful size.")
- if (STAGE_THREE)
- if ((check_turfs_in(1, 2)) && (check_turfs_in(2, 2)) && (check_turfs_in(4, 2)) && (check_turfs_in(8, 2)))
+ if(STAGE_THREE)
+ if((check_turfs_in(1, 2)) && (check_turfs_in(2, 2)) && (check_turfs_in(4, 2)) && (check_turfs_in(8, 2)))
SetName("gravitational singularity")
desc = "A gravitational singularity."
current_size = STAGE_THREE
@@ -185,7 +188,7 @@
else
visible_message("The singularity has returned to a safe size.")
if(STAGE_FOUR)
- if ((check_turfs_in(1, 3)) && (check_turfs_in(2, 3)) && (check_turfs_in(4, 3)) && (check_turfs_in(8, 3)))
+ if((check_turfs_in(1, 3)) && (check_turfs_in(2, 3)) && (check_turfs_in(4, 3)) && (check_turfs_in(8, 3)))
SetName("gravitational singularity")
desc = "A gravitational singularity."
current_size = STAGE_FOUR
@@ -245,61 +248,61 @@
overlays = list("emfield_s11")
visible_message("You witness the creation of a destructive force that cannot possibly be stopped by human hands.")
- if (current_size == allowed_size)
+ if(current_size == allowed_size)
investigate_log("grew to size [current_size].", I_SINGULO)
return 1
- else if (current_size < (--temp_allowed_size) && current_size != STAGE_SUPER)
+ else if(current_size < (--temp_allowed_size) && current_size != STAGE_SUPER)
expand(temp_allowed_size)
else
return 0
/obj/singularity/proc/check_energy()
- if (energy <= 0)
+ if(energy <= 0)
investigate_log("collapsed.", I_SINGULO)
qdel(src)
- return 0
+ return FALSE
- switch (energy) //Some of these numbers might need to be changed up later -Mport.
- if (1 to 399)
+ switch(energy) //Some of these numbers might need to be changed up later -Mport.
+ if(1 to 399)
allowed_size = STAGE_ONE
- if (400 to 799)
+ if(400 to 799)
allowed_size = STAGE_TWO
- if (800 to 1199)
+ if(800 to 1199)
allowed_size = STAGE_THREE
- if (1200 to 2499)
+ if(1200 to 2499)
allowed_size = STAGE_FOUR
if(2500 to 499999)
allowed_size = STAGE_FIVE
if(500000 to INFINITY)
allowed_size = STAGE_SUPER
- if (current_size != allowed_size && current_size != STAGE_SUPER)
+ if(current_size != allowed_size && current_size != STAGE_SUPER)
expand(null, current_size < allowed_size)
- return 1
+ return TRUE
/obj/singularity/proc/eat()
- for(var/atom/X in orange(grav_pull, src))
- var/dist = get_dist(X, src)
- var/obj/singularity/S = src
- if(!istype(src))
- return
+ for(var/atom/A in range(grav_pull, src))
+ if(A == src)
+ continue
+ var/dist = get_dist(A, src)
if(dist > consume_range)
- X.singularity_pull(S, current_size)
- else if(dist <= consume_range)
- consume(X)
-
- //for (var/turf/T in trange(grav_pull, src)) //TODO: Create a similar trange for orange to prevent snowflake of self check.
- // consume(T)
-
+ A.singularity_pull(src, current_size)
+ continue
+ consume(A)
return
/obj/singularity/proc/consume(atom/A)
+ if(A == src)
+ return
+ // Prevents the singulo from consuming turfs when it's contained
+ if(isturf(A) && IsContained())
+ return
energy += A.singularity_act(src, current_size)
return
-/obj/singularity/proc/move(force_move = 0)
+/obj/singularity/proc/move(force_move = FALSE)
if(!move_self)
- return 0
+ return FALSE
var/movement_dir = pick(GLOB.alldirs - last_failed_movement)
@@ -309,10 +312,19 @@
if(target && prob(60))
movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one
- if(!target && (current_size >= STAGE_FIVE) && prob(5)) // Random chance to move through z-levels at later stages
- var/turf/destination
- destination = pick(GetAbove(src), GetBelow(src))
- forceMove(destination)
+ var/atom/atom_target = target
+ if((!atom_target || atom_target?.z != z) && !IsContained() && (current_size >= STAGE_THREE) && prob(5)) // Random chance to move through z-levels at later stages
+ var/list/valid_destinations = list()
+ var/turf/T1 = GetAbove(src)
+ if(isturf(T1))
+ valid_destinations += T1
+ var/turf/T2 = GetBelow(src)
+ if(isturf(T2))
+ valid_destinations += T2
+ if(LAZYLEN(valid_destinations))
+ var/turf/destination = pick(valid_destinations)
+ forceMove(destination)
+ return
if(current_size >= 9)//The superlarge one does not care about things in its way
spawn(0)
@@ -327,7 +339,7 @@
return 1
else
last_failed_movement = movement_dir
- return 0
+ return FALSE
/obj/singularity/proc/check_turfs_in(var/direction = 0, var/step = 0)
if(!direction)
@@ -383,45 +395,71 @@
return 0
return 1
-/obj/singularity/proc/can_move(const/turf/T)
- if (!isturf(T))
- return 0
+/obj/singularity/proc/can_move(turf/T)
+ if(!isturf(T))
+ return FALSE
- if ((locate(/obj/machinery/containment_field) in T) || (locate(/obj/machinery/shieldwall) in T))
- return 0
- else if (locate(/obj/machinery/field_generator) in T)
+ return !ContainmentCheck(T)
+
+/obj/singularity/proc/ContainmentCheck(turf/T)
+ if(!istype(T))
+ T = get_turf(src)
+
+ if((locate(/obj/machinery/containment_field) in T) || (locate(/obj/machinery/shieldwall) in T))
+ return TRUE
+
+ else if(locate(/obj/machinery/field_generator) in T)
var/obj/machinery/field_generator/G = locate(/obj/machinery/field_generator) in T
+ if(G && G.active)
+ return TRUE
- if (G && G.active)
- return 0
- else if (locate(/obj/machinery/shieldwallgen) in T)
+ else if(locate(/obj/machinery/shieldwallgen) in T)
var/obj/machinery/shieldwallgen/S = locate(/obj/machinery/shieldwallgen) in T
+ if(S && S.active)
+ return TRUE
- if (S && S.active)
- return 0
- return 1
+ return FALSE
+
+// God-awful check that looks around the singulo; If FALSE - it can eat turfs and travel through z-levels
+/obj/singularity/proc/IsContained()
+ if(current_size >= STAGE_FIVE)
+ return FALSE
+
+ if(world.time < next_contained_check_time)
+ return last_contained_check
+
+ for(var/turf/T in range(6))
+ if(!ContainmentCheck(T))
+ last_contained_check = FALSE
+ // Might as well forget about checking entirely
+ next_contained_check_time = INFINITY
+ return FALSE
+
+ last_contained_check = TRUE
+ next_contained_check_time = world.time + 30 SECONDS
+ return TRUE
/obj/singularity/proc/event()
var/numb = pick(1, 2, 3, 4, 5, 6)
- switch (numb)
- if (1) //EMP.
+ switch(numb)
+ if(1) //EMP.
emp_area()
- if (2, 3) //Irradiate area
+ if(2, 3) //Irradiate area
irradiate()
- if (4) //Stun mobs who lack optic scanners.
+ if(4) //Stun mobs who lack optic scanners.
mezzer()
else
- return 0
+ return FALSE
if(current_size == 11)
smwave()
- return 1
+ return TRUE
/obj/singularity/proc/irradiate()
var/radiation = 15
- if (src.energy>200)
- radiation = round(((src.energy-150)/50)*5,1)
+ if(energy > 200)
+ radiation = round(((energy-150)/50)*5, 1)
SSradiation.radiate(src, radiation)
/obj/singularity/proc/mezzer()
@@ -431,7 +469,7 @@
if(M.status_flags & GODMODE)
continue
if(M.stat == CONSCIOUS)
- if (istype(M,/mob/living/carbon/human))
+ if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
if(istype(H.glasses,/obj/item/clothing/glasses/meson) && current_size != 11)
to_chat(H, "You look directly into The [src.name], good thing you had your protective eyewear on!")
@@ -441,7 +479,7 @@
to_chat(M, "You look directly into The [src.name] and feel [current_size == 11 ? "helpless" : "weak"].")
M.apply_effect(3, STUN)
for(var/mob/O in viewers(M, null))
- O.show_message(text("[] stares blankly at The []!", M, src), 1)
+ O.show_message("[M] stares blankly at the [src]!", 1)
/obj/singularity/proc/emp_area()
empulse(src, emp_strong_range, emp_weak_range)
@@ -460,7 +498,7 @@
/obj/singularity/proc/pulse()
for(var/obj/machinery/power/rad_collector/R in rad_collectors)
- if (get_dist(R, src) <= 15) //Better than using orange() every process.
+ if(get_dist(R, src) <= 15) //Better than using orange() every process.
R.receive_pulse(energy)
/obj/singularity/proc/on_capture()