From bd4940a138f73acc782062cc897c204be5a1e865 Mon Sep 17 00:00:00 2001 From: EgorDinamit <53223414+EgorDinamit@users.noreply.github.com> Date: Sat, 13 Jan 2024 22:56:18 +0300 Subject: [PATCH] Singularity tweaks (#499) --- code/modules/power/singularity/singularity.dm | 176 +++++++++++------- 1 file changed, 107 insertions(+), 69 deletions(-) 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()