Files
Aurora.3/code/modules/power/singularity/singularity.dm
Cody Brittain ddb14f4036 Planes & Layers part 1: The Re-Layering Redux (#18741)
This is part 1 of a project to, eventually, bring the render planes
system from /tg/ and bay into Aurora. This is a prerequisite and blocker
for many things the development team and community want to have, and
this was long overdue.

Many objects have been re-assigned layers, which are now thoroughly
defined. Maps have had their custom layer defines purged, as we should
be moving away from this in favor of saner definitions in the base
items.

This should be a test-merge due to the sheer amount of layers changed,
which will very likely create issues that I cannot possibly discover and
debug in a reasonable amount of time myself.

---------

Co-authored-by: Cody Brittain <cbrittain10@live.com>
2024-04-01 14:50:27 +00:00

515 lines
15 KiB
Plaintext

#define I_SINGULO "singulo"
/obj/singularity
name = "gravitational singularity"
desc = "A gravitational singularity."
icon = 'icons/obj/singularity.dmi'
icon_state = "singularity_s1"
anchored = 1
density = 1
layer = SINGULARITY_LAYER
light_power = -100 //eats all light
unacidable = 1 //Don't comment this out.
appearance_flags = NO_CLIENT_COLOR
var/current_size = 1
var/allowed_size = 1
var/contained = 1 //Are we going to move around?
var/energy = 100 //How strong are we?
var/dissipate = 1 //Do we lose energy over time?
var/dissipate_delay = 10
var/dissipate_track = 0
var/dissipate_strength = 1 //How much energy do we lose?
var/move_self = 1 //Do we move on our own?
var/grav_pull = 4 //How many tiles out do we pull?
var/consume_range = 0 //How many tiles out do we eat.
var/event_chance = 15 //Prob for event each tick.
var/atom/target = null //Its target. Moves towards the target if it has one.
var/last_failed_movement = 0 //Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing.
var/last_warning
var/chained = 0//Adminbus chain-grab
/obj/singularity/New(loc, var/starting_energy = 50, var/temp = 0, var/alert = TRUE)
//CARN: admin-alert for chuckle-fuckery.
if(alert)
admin_investigate_setup()
energy = starting_energy
if (temp)
QDEL_IN(src, temp)
..()
START_PROCESSING(SScalamity, src)
SScalamity.singularities += src
for(var/obj/machinery/power/tesla_beacon/singubeacon in SSmachinery.processing)
if(singubeacon.active)
target = singubeacon
break
/obj/singularity/Destroy()
STOP_PROCESSING(SScalamity, src)
SScalamity.singularities -= src
return ..()
/obj/singularity/attack_hand(mob/user as mob)
consume(user)
return 1
/obj/singularity/ex_act(severity)
if(current_size == STAGE_SUPER)//IT'S UNSTOPPABLE
return
switch(severity)
if(1.0)
if(prob(25))
investigate_log("has been destroyed by an explosion.", I_SINGULO)
qdel(src)
return
else
energy += 50
if(2.0 to 3.0)
energy += round((rand(20,60)/2),1)
return
/obj/singularity/bullet_act(obj/item/projectile/P)
return 0 //Will there be an impact? Who knows. Will we see it? No.
/obj/singularity/Collide(atom/A)
. = ..()
if (A)
consume(A)
/obj/singularity/CollidedWith(atom/movable/AM)
. = ..()
if (AM)
consume(AM)
/obj/singularity/process()
eat()
dissipate()
check_energy()
light_range = current_size-2
if(light_range < 0)
light_range = 0
if (current_size >= STAGE_THREE)
move()
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.
return
/obj/singularity/proc/admin_investigate_setup()
last_warning = world.time
var/count = locate(/obj/machinery/containment_field) in orange(30, src)
var/msg = "A singulo has been created."
if (!count)
msg += " No containment field active!"
log_and_message_admins("A singulo has been created without containment fields active.", location = get_turf(src))
investigate_log("was created.[count ? "" : " <span class='warning'>No containment fields were active.</span>"]. usr=[usr ? key_name(usr) : "null"]", I_SINGULO)
/obj/singularity/proc/dissipate()
if (!dissipate)
return
if(dissipate_track >= dissipate_delay)
energy -= dissipate_strength
dissipate_track = 0
else
dissipate_track++
/obj/singularity/proc/expand(var/force_size = 0, var/growing = 1)
if(current_size == STAGE_SUPER)//if this is happening, this is an error
message_admins("expand() was called on a super singulo. This should not happen. Contact a coder immediately!")
return
var/temp_allowed_size = allowed_size
if (force_size)
temp_allowed_size = force_size
switch (temp_allowed_size)
if (STAGE_ONE)
name = "gravitational singularity"
desc = "A gravitational singularity."
current_size = STAGE_ONE
icon = 'icons/obj/singularity.dmi'
icon_state = "singularity_s1"
pixel_x = 0
pixel_y = 0
grav_pull = 4
consume_range = 0
dissipate_delay = 10
dissipate_track = 0
dissipate_strength = 1
overlays = 0
if(chained)
overlays = "chain_s1"
visible_message("<span class='notice'>The singularity has shrunk to a rather pitiful size.</span>")
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.
name = "gravitational singularity"
desc = "A gravitational singularity."
current_size = STAGE_TWO
icon = 'icons/effects/96x96.dmi'
icon_state = "singularity_s3"
pixel_x = -32
pixel_y = -32
grav_pull = 6
consume_range = 1
dissipate_delay = 5
dissipate_track = 0
dissipate_strength = 5
overlays = 0
if(chained)
overlays = "chain_s3"
if(growing)
visible_message("<span class='notice'>The singularity noticeably grows in size.</span>")
else
visible_message("<span class='notice'>The singularity has shrunk to a less powerful size.</span>")
if (STAGE_THREE)
if ((check_turfs_in(1, 2)) && (check_turfs_in(2, 2)) && (check_turfs_in(4, 2)) && (check_turfs_in(8, 2)))
name = "gravitational singularity"
desc = "A gravitational singularity."
current_size = STAGE_THREE
icon = 'icons/effects/160x160.dmi'
icon_state = "singularity_s5"
pixel_x = -64
pixel_y = -64
grav_pull = 8
consume_range = 2
dissipate_delay = 4
dissipate_track = 0
dissipate_strength = 20
overlays = 0
if(chained)
overlays = "chain_s5"
if(growing)
visible_message("<span class='notice'>The singularity expands to a reasonable size.</span>")
else
visible_message("<span class='notice'>The singularity has returned to a safe size.</span>")
if(STAGE_FOUR)
if ((check_turfs_in(1, 3)) && (check_turfs_in(2, 3)) && (check_turfs_in(4, 3)) && (check_turfs_in(8, 3)))
name = "gravitational singularity"
desc = "A gravitational singularity."
current_size = STAGE_FOUR
icon = 'icons/effects/224x224.dmi'
icon_state = "singularity_s7"
pixel_x = -96
pixel_y = -96
grav_pull = 10
consume_range = 3
dissipate_delay = 10
dissipate_track = 0
dissipate_strength = 10
overlays = 0
if(chained)
overlays = "chain_s7"
if(growing)
visible_message("<span class='warning'>The singularity expands to a dangerous size.</span>")
else
visible_message("<span class='notice'>Miraculously, the singularity reduces in size, and can be contained.</span>")
if(STAGE_FIVE) //This one also lacks a check for gens because it eats everything.
name = "gravitational singularity"
desc = "A gravitational singularity."
current_size = STAGE_FIVE
icon = 'icons/effects/288x288.dmi'
icon_state = "singularity_s9"
pixel_x = -128
pixel_y = -128
grav_pull = 10
consume_range = 4
dissipate = 0 //It cant go smaller due to e loss.
overlays = 0
if(chained)
overlays = "chain_s9"
if(growing)
visible_message("<span class='danger'><font size='2'>The singularity has grown out of control!</font></span>")
else
visible_message("<span class='warning'>The singularity miraculously reduces in size and loses its supermatter properties.</span>")
if(STAGE_SUPER)//SUPERSINGULO
name = "super gravitational singularity"
desc = "A gravitational singularity with the properties of supermatter. <b>It has the power to destroy worlds.</b>"
current_size = STAGE_SUPER
icon = 'icons/effects/352x352.dmi'
icon_state = "singularity_s11"//uh, whoever drew that, you know that black holes are supposed to look dark right? What's this, the clown's singulo?
pixel_x = -160
pixel_y = -160
grav_pull = 16
consume_range = 5
dissipate = 0 //It cant go smaller due to e loss
event_chance = 25 //Events will fire off more often.
if(chained)
overlays = "chain_s9"
visible_message("<span class='danger'><font size='3'>You witness the creation of a destructive force that cannot possibly be stopped by human hands.</font></span>")
if (current_size == allowed_size)
investigate_log("<span class='warning'>grew to size [current_size].</span>", I_SINGULO)
return 1
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)
investigate_log("collapsed.", I_SINGULO)
qdel(src)
return 0
switch (energy) //Some of these numbers might need to be changed up later -Mport.
if (1 to 199)
allowed_size = STAGE_ONE
if (200 to 499)
allowed_size = STAGE_TWO
if (500 to 999)
allowed_size = STAGE_THREE
if (1000 to 1999)
allowed_size = STAGE_FOUR
if(2000 to 49999)
allowed_size = STAGE_FIVE
if(50000 to INFINITY)
allowed_size = STAGE_SUPER
if (current_size != allowed_size && current_size != STAGE_SUPER)
expand(null, current_size < allowed_size)
return 1
/obj/singularity/proc/eat()
for(var/tile in spiral_range_turfs(grav_pull, src))
var/turf/T = tile
if(!T || !isturf(loc))
continue
if(get_dist(T, src) > consume_range)
T.singularity_pull(src, current_size)
else
consume(T)
for(var/thing in T)
if(isturf(loc) && thing != src)
var/atom/movable/X = thing
if(get_dist(X, src) > consume_range)
X.singularity_pull(src, current_size)
else
consume(X)
CHECK_TICK
return
/obj/singularity/proc/consume(const/atom/A)
src.energy += A.singularity_act(src, current_size)
return
/obj/singularity/proc/move(var/force_move = 0)
if(!move_self)
return 0
var/movement_dir = pick(GLOB.alldirs - last_failed_movement)
if(force_move)
movement_dir = force_move
if(target && prob(60))
movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one
if(target.z < z)
visible_message("<span class='danger'>\The [src] gravitates downwards.</span>")
zMove(DOWN)
visible_message("<span class='danger'>\The [src] appears from above.</span>")
else if(target.z > z)
visible_message("<span class='danger'>\The [src] gravitates upwards.</span>")
zMove(UP)
visible_message("<span class='danger'>\The [src] appears from below.</span>")
if(current_size >= 9)//The superlarge one does not care about things in its way
spawn(0)
step(src, movement_dir)
spawn(1)
step(src, movement_dir)
return 1
else if(check_turfs_in(movement_dir))
last_failed_movement = 0//Reset this because we moved
spawn(0)
step(src, movement_dir)
return 1
else
if(current_size >= STAGE_FIVE)
var/z_dir = pick(UP,DOWN)
if(!zMove(z_dir))
last_failed_movement = movement_dir
else
last_failed_movement = movement_dir
return 0
/obj/singularity/proc/check_turfs_in(var/direction = 0, var/step = 0)
if(!direction)
return 0
var/steps = 0
if(!step)
switch(current_size)
if(1)
steps = 1
if(3)
steps = 3//Yes this is right
if(5)
steps = 3
if(7)
steps = 4
if(9)
steps = 5
if(11)
steps = 6
else
steps = step
var/list/turfs = list()
var/turf/T = src.loc
for(var/i = 1 to steps)
T = get_step(T,direction)
if(!isturf(T))
return 0
turfs.Add(T)
var/dir2 = 0
var/dir3 = 0
switch(direction)
if(NORTH, SOUTH)
dir2 = 4
dir3 = 8
if(EAST, WEST)
dir2 = 1
dir3 = 2
var/turf/T2 = T
for(var/j = 1 to steps)
T2 = get_step(T2,dir2)
if(!isturf(T2))
return 0
turfs.Add(T2)
for(var/k = 1 to steps)
T = get_step(T,dir3)
if(!isturf(T))
return 0
turfs.Add(T)
for(var/turf/T3 in turfs)
if(isnull(T3))
continue
if(!can_move(T3))
return 0
return 1
/obj/singularity/proc/can_move(const/turf/T)
if (!isturf(T))
return 0
if ((locate(/obj/machinery/containment_field) in T) || (locate(/obj/shieldwall) in T))
return 0
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 0
else if (locate(/obj/machinery/shieldwallgen) in T)
var/obj/machinery/shieldwallgen/S = locate(/obj/machinery/shieldwallgen) in T
if (S?.power_state)
return 0
return 1
/obj/singularity/proc/event()
var/numb = pick(1, 2, 3, 4, 5, 6)
switch (numb)
if (1) //EMP.
emp_area()
if (2, 3) //Tox damage all carbon mobs in area.
toxmob()
if (4) //Stun mobs who lack optic scanners.
mezzer()
else
return 0
if(current_size == 11)
smwave()
return 1
/obj/singularity/proc/toxmob()
var/radiation = 15
if (src.energy > 200)
radiation = round(((src.energy-150)/50)*5,1)
SSradiation.radiate(src, radiation)
/obj/singularity/proc/mezzer()
for(var/mob/living/carbon/M in oviewers(8, src))
if(istype(M, /mob/living/carbon/brain)) //Ignore brains
continue
if(M.status_flags & GODMODE)
continue
if(M.stat == CONSCIOUS)
if (istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
if(istype(H.glasses,/obj/item/clothing/glasses/safety) && current_size != 11)
to_chat(H, "<span class=\"notice\">You look directly into The [src.name], good thing you had your protective eyewear on!</span>")
return
else
to_chat(H, "<span class=\"warning\">You look directly into The [src.name], but your eyewear does absolutely nothing to protect you from it!</span>")
to_chat(M, "<span class='danger'>You look directly into The [src.name] and feel [current_size == 11 ? "helpless" : "weak"].</span>")
M.apply_effect(3, STUN)
for(var/mob/O in viewers(M, null))
O.show_message(text("<span class='danger'>[] stares blankly at The []!</span>", M, src), 1)
/obj/singularity/proc/emp_area()
if(current_size != 11)
empulse(src, 8, 10)
else
empulse(src, 12, 16)
/obj/singularity/proc/smwave()
for(var/mob/living/M in view(10, src.loc))
if(prob(67))
to_chat(M, "<span class=\"warning\">You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.</span>")
to_chat(M, "<span class=\"notice\">Miraculously, it fails to kill you.</span>")
else
to_chat(M, "<span class=\"danger\">You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.</span>")
to_chat(M, "<span class=\"danger\">You don't even have a moment to react as you are reduced to ashes by the intense radiation.</span>")
M.dust()
SSradiation.radiate(src, rand(energy))
return
/obj/singularity/proc/on_capture()
chained = 1
overlays = 0
move_self = 0
switch (current_size)
if(1)
add_overlay(image('icons/obj/singularity.dmi',"chain_s1"))
if(3)
add_overlay(image('icons/effects/96x96.dmi',"chain_s3"))
if(5)
add_overlay(image('icons/effects/160x160.dmi',"chain_s5"))
if(7)
add_overlay(image('icons/effects/224x224.dmi',"chain_s7"))
if(9)
add_overlay(image('icons/effects/288x288.dmi',"chain_s9"))
/obj/singularity/proc/on_release()
chained = 0
overlays = 0
move_self = 1
/obj/singularity/singularity_act(S, size)
if(current_size <= size)
var/gain = (energy/2)
var/dist = max((current_size - 2), 1)
explosion(src.loc,(dist),(dist*2),(dist*4))
spawn(0)
qdel(src)
return gain
/obj/singularity/can_fall()
return FALSE
/obj/singularity/proc/zMove(direction)
var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
if(destination)
forceMove(destination)
#undef I_SINGULO