[MIRROR] Singularity component (#2082)

* Singularity component (#55096)

Adds singularity component

* Singularity component

Co-authored-by: Jared-Fogle <35135081+Jared-Fogle@users.noreply.github.com>
This commit is contained in:
SkyratBot
2020-12-08 11:30:39 +00:00
committed by GitHub
co-authored by Jared-Fogle
parent bd29550b77
commit f105b47a55
30 changed files with 749 additions and 514 deletions
+26 -30
View File
@@ -1,51 +1,47 @@
/// BoH tear
/// The BoH tear is a stationary singularity with a really high gravitational pull, which collapses briefly after being created
/// The BoH isn't deleted for 10 minutes (only moved to nullspace) so that admins may retrieve the things back in case of a grief
/obj/singularity/boh_tear
#define BOH_TEAR_CONSUME_RANGE 1
#define BOH_TEAR_GRAV_PULL 25
/obj/boh_tear
name = "tear in the fabric of reality"
desc = "Your own comprehension of reality starts bending as you stare this."
anchored = TRUE
appearance_flags = LONG_GLIDE
density = TRUE
icon = 'icons/effects/96x96.dmi'
icon_state = "boh_tear"
layer = MASSIVE_OBJ_LAYER
light_range = 6
move_resist = INFINITY
obj_flags = CAN_BE_HIT | DANGEROUS_POSSESSION
pixel_x = -32
pixel_y = -32
dissipate = 0
move_self = 0
consume_range = 1
grav_pull = 25
current_size = STAGE_SIX
allowed_size = STAGE_SIX
var/ghosts = list()
var/old_loc
var/start_time = 0
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
flags_1 = SUPERMATTER_IGNORES_1
/obj/singularity/boh_tear/Initialize()
/obj/boh_tear/Initialize()
. = ..()
old_loc = loc
start_time = world.time
QDEL_IN(src, 5 SECONDS) // vanishes after 5 seconds
/obj/singularity/boh_tear/process()
//Backup to catch timerss errors
if(start_time + (10 SECONDS) < world.time)
stack_trace("The timer subsytem isn't firing properly, yell at your local coders posthaste")
qdel(src)
eat()
AddComponent(
/datum/component/singularity, \
consume_range = BOH_TEAR_CONSUME_RANGE, \
grav_pull = BOH_TEAR_GRAV_PULL, \
roaming = FALSE, \
singularity_size = STAGE_SIX, \
)
/obj/singularity/boh_tear/consume(atom/A)
A.singularity_act(current_size, src)
/obj/singularity/boh_tear/admin_investigate_setup()
var/turf/T = get_turf(src)
message_admins("A BoH tear has been created at [ADMIN_VERBOSEJMP(T)].")
investigate_log("was created at [AREACOORD(T)].", INVESTIGATE_SINGULO)
/obj/singularity/boh_tear/attack_tk(mob/user)
/obj/boh_tear/attack_tk(mob/user)
if(!isliving(user))
return
var/mob/living/jedi = user
to_chat(jedi, "<span class='userdanger'>You don't feel like you are real anymore.</span>")
jedi.dust_animation()
jedi.spawn_dust()
addtimer(CALLBACK(src, .proc/consume, jedi), 0.5 SECONDS)
addtimer(CALLBACK(src, /atom/proc/attack_hand, jedi), 0.5 SECONDS)
return COMPONENT_CANCEL_ATTACK_CHAIN
#undef BOH_TEAR_CONSUME_RANGE
#undef BOH_TEAR_GRAV_PULL
@@ -20,6 +20,7 @@
/obj/machinery/field/containment/Initialize()
. = ..()
air_update_turf(TRUE)
RegisterSignal(src, COMSIG_ATOM_SINGULARITY_TRY_MOVE, .proc/block_singularity)
/obj/machinery/field/containment/Destroy()
FG1.fields -= src
@@ -79,6 +80,11 @@
FG2 = master2
return TRUE
/obj/machinery/field/containment/proc/block_singularity()
SIGNAL_HANDLER
return SINGULARITY_TRY_MOVE_BLOCK
/obj/machinery/field/containment/shock(mob/living/user)
if(!FG1 || !FG2)
qdel(src)
@@ -58,6 +58,7 @@ no power level overlay is currently in the overlays list.
. = ..()
fields = list()
connected_gens = list()
RegisterSignal(src, COMSIG_ATOM_SINGULARITY_TRY_MOVE, .proc/block_singularity_if_active)
/obj/machinery/field/generator/anchored/Initialize()
. = ..()
@@ -340,11 +341,6 @@ no power level overlay is currently in the overlays list.
clean_up = 0
update_icon()
//This is here to help fight the "hurr durr, release singulo cos nobody will notice before the
//singulo eats the evidence". It's not fool-proof but better than nothing.
//I want to avoid using global variables.
INVOKE_ASYNC(src, .proc/notify_admins)
move_resist = initial(move_resist)
/obj/machinery/field/generator/proc/shield_floor(create)
@@ -386,17 +382,11 @@ no power level overlay is currently in the overlays list.
if(S)
qdel(S)
/obj/machinery/field/generator/proc/notify_admins()
var/temp = TRUE //stops spam
for(var/obj/singularity/O in GLOB.singularities)
if(O.last_warning && temp)
if((world.time - O.last_warning) > 50) //to stop message-spam
temp = FALSE
var/turf/T = get_turf(src)
message_admins("A singulo exists and a containment field has failed at [ADMIN_VERBOSEJMP(T)].")
investigate_log("has <font color='red'>failed</font> whilst a singulo exists at [AREACOORD(T)].", INVESTIGATE_SINGULO)
notify_ghosts("IT'S LOOSE", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, ghost_sound = 'sound/machines/warning-buzzer.ogg', header = "IT'S LOOSE", notify_volume = 75)
O.last_warning = world.time
/obj/machinery/field/generator/proc/block_singularity_if_active()
SIGNAL_HANDLER
if (active)
return SINGULARITY_TRY_MOVE_BLOCK
/obj/machinery/field/generator/shock(mob/living/user)
if(fields.len)
+181 -163
View File
@@ -1,74 +1,204 @@
/obj/singularity/narsie //Moving narsie to a child object of the singularity so it can be made to function differently. --NEO
name = "Nar'Sie's Avatar"
#define NARSIE_CHANCE_TO_PICK_NEW_TARGET 5
#define NARSIE_CONSUME_RANGE 12
#define NARSIE_GRAV_PULL 10
#define NARSIE_MESMERIZE_CHANCE 25
#define NARSIE_MESMERIZE_EFFECT 60
#define NARSIE_SINGULARITY_SIZE 12
/// Nar'Sie, the God of the blood cultists
/obj/narsie
name = "Nar'Sie"
desc = "Your mind begins to bubble and ooze as it tries to comprehend what it sees."
icon = 'icons/obj/narsie_small.dmi'
icon = 'icons/obj/narsie.dmi'
icon_state = "narsie"
pixel_x = -89
pixel_y = -85
anchored = TRUE
appearance_flags = LONG_GLIDE
density = FALSE
current_size = 9 //It moves/eats like a max-size singulo, aside from range. --NEO
contained = 0 //Are we going to move around?
dissipate = 0 //Do we lose energy over time?
move_self = 1 //Do we move on our own?
grav_pull = 5 //How many tiles out do we pull?
consume_range = 6 //How many tiles out do we eat
gender = FEMALE
layer = MASSIVE_OBJ_LAYER
light_color = COLOR_RED
light_power = 0.7
light_range = 15
light_color = COLOR_RED
gender = FEMALE
/obj/singularity/narsie/large
name = "Nar'Sie"
icon = 'icons/obj/narsie.dmi'
// Pixel stuff centers Narsie.
light_range = 6
move_resist = INFINITY
obj_flags = CAN_BE_HIT | DANGEROUS_POSSESSION
pixel_x = -236
pixel_y = -256
current_size = 12
grav_pull = 10
consume_range = 12 //How many tiles out do we eat
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
flags_1 = SUPERMATTER_IGNORES_1
/obj/singularity/narsie/large/Initialize()
. = ..()
send_to_playing_players("<span class='narsie'>NAR'SIE HAS RISEN</span>")
sound_to_playing_players('sound/creatures/narsie_rises.ogg')
/// The singularity component to move around Nar'Sie.
/// A weak ref in case an admin removes the component to preserve the functionality.
var/datum/weakref/singularity
var/area/A = get_area(src)
if(A)
var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/cult_effects.dmi', "ghostalertsie")
notify_ghosts("Nar'Sie has risen in \the [A.name]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, action=NOTIFY_ATTACK)
narsie_spawn_animation()
UnregisterSignal(src, COMSIG_ATOM_BSA_BEAM) //set up in /singularity/Initialize()
/obj/singularity/narsie/large/cult // For the new cult ending, guaranteed to end the round within 3 minutes
var/list/souls_needed = list()
var/soul_goal = 0
var/souls = 0
var/resolved = FALSE
/obj/singularity/narsie/large/cult/Initialize()
/obj/narsie/Initialize()
. = ..()
singularity = WEAKREF(AddComponent(
/datum/component/singularity, \
bsa_targetable = FALSE, \
consume_callback = CALLBACK(src, .proc/consume), \
consume_range = NARSIE_CONSUME_RANGE, \
disregard_failed_movements = TRUE, \
grav_pull = NARSIE_GRAV_PULL, \
roaming = FALSE, /* This is set once the animation finishes */ \
singularity_size = NARSIE_SINGULARITY_SIZE, \
))
send_to_playing_players("<span class='narsie'>NAR'SIE HAS RISEN</span>")
sound_to_playing_players('sound/creatures/narsie_rises.ogg')
var/area/area = get_area(src)
if(area)
var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/cult_effects.dmi', "ghostalertsie")
notify_ghosts("Nar'Sie has risen in [area]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, action = NOTIFY_ATTACK)
narsie_spawn_animation()
GLOB.cult_narsie = src
var/list/all_cults = list()
for(var/datum/antagonist/cult/C in GLOB.antagonists)
if(!C.owner)
for (var/datum/antagonist/cult/cultist in GLOB.antagonists)
if (!cultist.owner)
continue
all_cults |= C.cult_team
for(var/datum/team/cult/T in all_cults)
deltimer(T.blood_target_reset_timer)
T.blood_target = src
var/datum/objective/eldergod/summon_objective = locate() in T.objectives
all_cults |= cultist.cult_team
for (var/_cult_team in all_cults)
var/datum/team/cult/cult_team = _cult_team
deltimer(cult_team.blood_target_reset_timer)
cult_team.blood_target = src
var/datum/objective/eldergod/summon_objective = locate() in cult_team.objectives
if(summon_objective)
summon_objective.summoned = TRUE
for(var/datum/mind/cult_mind in SSticker.mode.cult)
if(isliving(cult_mind.current))
for (var/_cult_mind in SSticker.mode.cult)
var/datum/mind/cult_mind = _cult_mind
if (isliving(cult_mind.current))
var/mob/living/L = cult_mind.current
L.narsie_act()
for(var/mob/living/player in GLOB.player_list)
if(player.stat != DEAD && player.loc && is_station_level(player.loc.z) && !iscultist(player) && !isanimal(player))
for (var/mob/living/carbon/player in GLOB.player_list)
if (player.stat != DEAD && is_station_level(player.loc?.z) && !iscultist(player))
souls_needed[player] = TRUE
soul_goal = round(1 + LAZYLEN(souls_needed) * 0.75)
INVOKE_ASYNC(GLOBAL_PROC, .proc/begin_the_end)
/obj/narsie/Destroy()
send_to_playing_players("<span class='narsie'>\"<b>[pick("Nooooo...", "Not die. How-", "Die. Mort-", "Sas tyen re-")]\"</b></span>")
sound_to_playing_players('sound/magic/demon_dies.ogg', 50)
var/list/all_cults = list()
for (var/datum/antagonist/cult/cultist in GLOB.antagonists)
if (!cultist.owner)
continue
all_cults |= cultist.cult_team
for(var/_cult_team in all_cults)
var/datum/team/cult/cult_team = _cult_team
var/datum/objective/eldergod/summon_objective = locate() in cult_team.objectives
if (summon_objective)
summon_objective.summoned = FALSE
summon_objective.killed = TRUE
return ..()
/obj/narsie/attack_ghost(mob/user)
makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, cultoverride = TRUE, loc_override = loc)
/obj/narsie/process()
var/datum/component/singularity/singularity_component = singularity.resolve()
if (!isnull(singularity_component) && (!singularity_component?.target || prob(NARSIE_CHANCE_TO_PICK_NEW_TARGET)))
pickcultist()
if (prob(NARSIE_MESMERIZE_CHANCE))
mesmerize()
/obj/narsie/Bump(atom/target)
var/turf/target_turf = get_turf(target)
if (target_turf == loc)
target_turf = get_step(target, target.dir) //please don't slam into a window like a bird, Nar'Sie
forceMove(target_turf)
/// Stun people around Nar'Sie that aren't cultists
/obj/narsie/proc/mesmerize()
for (var/mob/living/carbon/victim in viewers(NARSIE_CONSUME_RANGE, src))
if (victim.stat == CONSCIOUS)
if (!iscultist(victim))
to_chat(victim, "<span class='cultsmall'>You feel conscious thought crumble away in an instant as you gaze upon [src]...</span>")
victim.apply_effect(NARSIE_MESMERIZE_EFFECT, EFFECT_STUN)
/// Narsie rewards her cultists with being devoured first, then picks a ghost to follow.
/obj/narsie/proc/pickcultist()
var/list/cultists = list()
var/list/noncultists = list()
for (var/mob/living/carbon/food in GLOB.alive_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 || (pos.z != z))
continue
if (iscultist(food))
cultists += food
else
noncultists += food
if (cultists.len) //cultists get higher priority
acquire(pick(cultists))
return
if (noncultists.len)
acquire(pick(noncultists))
return
//no living humans, follow a ghost instead.
for (var/mob/dead/observer/ghost in GLOB.player_list)
var/turf/pos = get_turf(ghost)
if (!pos || (pos.z != z))
continue
cultists += ghost
if (cultists.len)
acquire(pick(cultists))
return
/// Nar'Sie gets a taste of something, and will start to gravitate towards it
/obj/narsie/proc/acquire(atom/food)
var/datum/component/singularity/singularity_component = singularity.resolve()
if (isnull(singularity_component))
return
var/old_target = singularity_component.target
if (food == old_target)
return
to_chat(old_target, "<span class='cultsmall'>NAR'SIE HAS LOST INTEREST IN YOU.</span>")
singularity_component.target = food
if(ishuman(food))
to_chat(food, "<span class='cult'>NAR'SIE HUNGERS FOR YOUR SOUL.</span>")
else
to_chat(food, "<span class='cult'>NAR'SIE HAS CHOSEN YOU TO LEAD HER TO HER NEXT MEAL.</span>")
/// Called to make Nar'Sie convert objects to cult stuff, or to eat
/obj/narsie/proc/consume(atom/target)
if (isturf(target))
target.narsie_act()
/obj/narsie/proc/narsie_spawn_animation()
setDir(SOUTH)
flick("narsie_spawn_anim", src)
addtimer(CALLBACK(src, .proc/narsie_spawn_animation_end), 3.5 SECONDS)
/obj/narsie/proc/narsie_spawn_animation_end()
var/datum/component/singularity/singularity_component = singularity.resolve()
singularity_component?.roaming = TRUE
/proc/begin_the_end()
sleep(50)
if(QDELETED(GLOB.cult_narsie)) // uno
@@ -105,21 +235,6 @@
sound_to_playing_players('sound/machines/alarm.ogg')
addtimer(CALLBACK(GLOBAL_PROC, .proc/cult_ending_helper), 120)
/obj/singularity/narsie/large/cult/Destroy()
send_to_playing_players("<span class='narsie'>\"<b>[pick("Nooooo...", "Not die. How-", "Die. Mort-", "Sas tyen re-")]\"</b></span>")
sound_to_playing_players('sound/magic/demon_dies.ogg', 50)
var/list/all_cults = list()
for(var/datum/antagonist/cult/C in GLOB.antagonists)
if(!C.owner)
continue
all_cults |= C.cult_team
for(var/datum/team/cult/T in all_cults)
var/datum/objective/eldergod/summon_objective = locate() in T.objectives
if(summon_objective)
summon_objective.summoned = FALSE
summon_objective.killed = TRUE
return ..()
/proc/ending_helper()
SSticker.force_ending = 1
@@ -131,106 +246,9 @@
else // explosion
Cinematic(CINEMATIC_CULT_NUKE,world,CALLBACK(GLOBAL_PROC,/proc/ending_helper))
//ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob)
makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, cultoverride = TRUE, loc_override = src.loc)
/obj/singularity/narsie/process()
eat()
if(!target || prob(5))
pickcultist()
move()
if(prob(25))
mezzer()
/obj/singularity/narsie/Bump(atom/A)
var/turf/T = get_turf(A)
if(T == loc)
T = get_step(A, A.dir) //please don't slam into a window like a bird, Nar'Sie
forceMove(T)
/obj/singularity/narsie/mezzer()
for(var/mob/living/carbon/M in viewers(consume_range, src))
if(M.stat == CONSCIOUS)
if(!iscultist(M))
to_chat(M, "<span class='cultsmall'>You feel conscious thought crumble away in an instant as you gaze upon [src.name]...</span>")
M.apply_effect(60, EFFECT_STUN)
/obj/singularity/narsie/consume(atom/A)
if(isturf(A))
A.narsie_act()
/obj/singularity/narsie/ex_act() //No throwing bombs at her either.
return
/obj/singularity/narsie/proc/pickcultist() //Narsie rewards her cultists with being devoured first, then picks a ghost to follow.
var/list/cultists = list()
var/list/noncultists = list()
for(var/mob/living/carbon/food in GLOB.alive_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 || (pos.z != z))
continue
if(iscultist(food))
cultists += food
else
noncultists += food
if(cultists.len) //cultists get higher priority
acquire(pick(cultists))
return
if(noncultists.len)
acquire(pick(noncultists))
return
//no living humans, follow a ghost instead.
for(var/mob/dead/observer/ghost in GLOB.player_list)
var/turf/pos = get_turf(ghost)
if(!pos || (pos.z != z))
continue
cultists += ghost
if(cultists.len)
acquire(pick(cultists))
return
/obj/singularity/narsie/proc/acquire(atom/food)
if(food == target)
return
to_chat(target, "<span class='cultsmall'>NAR'SIE HAS LOST INTEREST IN YOU.</span>")
target = food
if(ishuman(target))
to_chat(target, "<span class='cult'>NAR'SIE HUNGERS FOR YOUR SOUL.</span>")
else
to_chat(target, "<span class='cult'>NAR'SIE HAS CHOSEN YOU TO LEAD HER TO HER NEXT MEAL.</span>")
//Wizard narsie
/obj/singularity/narsie/wizard
grav_pull = 0
/obj/singularity/narsie/wizard/eat()
// if(defer_powernet_rebuild != 2)
// defer_powernet_rebuild = 1
for(var/atom/X in urange(consume_range,src,1))
if(isturf(X) || ismovable(X))
consume(X)
// if(defer_powernet_rebuild != 2)
// defer_powernet_rebuild = 0
return
/obj/singularity/narsie/proc/narsie_spawn_animation()
setDir(SOUTH)
move_self = FALSE
flick("narsie_spawn_anim",src)
addtimer(CALLBACK(src, .proc/narsie_spawn_animation_end), 3.5 SECONDS)
/obj/singularity/narsie/proc/narsie_spawn_animation_end()
move_self = TRUE
#undef NARSIE_CHANCE_TO_PICK_NEW_TARGET
#undef NARSIE_CONSUME_RANGE
#undef NARSIE_GRAV_PULL
#undef NARSIE_MESMERIZE_CHANCE
#undef NARSIE_MESMERIZE_EFFECT
#undef NARSIE_SINGULARITY_SIZE
+67 -168
View File
@@ -1,5 +1,4 @@
/// The gravitational singularity
/obj/singularity
name = "gravitational singularity"
desc = "A gravitational singularity."
@@ -11,41 +10,51 @@
layer = MASSIVE_OBJ_LAYER
light_range = 6
appearance_flags = LONG_GLIDE
/// The singularity component itself.
/// A weak ref in case an admin removes the component to preserve the functionality.
var/datum/weakref/singularity_component
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 = TRUE //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 = 10 //Prob for event each tick
var/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/consumedSupermatter = 0 //If the singularity has eaten a supermatter shard and can go to stage six
var/drifting_dir = 0 // Chosen direction to drift in
var/move_self = TRUE
var/consumed_supermatter = FALSE //If the singularity has eaten a supermatter shard and can go to stage six
flags_1 = SUPERMATTER_IGNORES_1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
obj_flags = CAN_BE_HIT | DANGEROUS_POSSESSION
/obj/singularity/Initialize(mapload, starting_energy = 50)
//CARN: admin-alert for chuckle-fuckery.
admin_investigate_setup()
src.energy = starting_energy
. = ..()
energy = starting_energy
START_PROCESSING(SSobj, src)
GLOB.poi_list |= src
GLOB.singularities |= src
for(var/obj/machinery/power/singularity_beacon/singubeacon in GLOB.machines)
if(singubeacon.active)
target = singubeacon
var/datum/component/singularity/new_component = AddComponent(
/datum/component/singularity, \
consume_callback = CALLBACK(src, .proc/consume), \
)
singularity_component = WEAKREF(new_component)
expand(current_size)
for (var/obj/machinery/power/singularity_beacon/singubeacon in GLOB.machines)
if (singubeacon.active)
new_component.target = singubeacon
break
AddElement(/datum/element/bsa_blocker)
RegisterSignal(src, COMSIG_ATOM_BSA_BEAM, .proc/bluespace_reaction)
if (!mapload)
notify_ghosts("IT'S LOOSE", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, ghost_sound = 'sound/machines/warning-buzzer.ogg', header = "IT'S LOOSE", notify_volume = 75)
/obj/singularity/Destroy()
STOP_PROCESSING(SSobj, src)
@@ -53,49 +62,6 @@
GLOB.singularities.Remove(src)
return ..()
/obj/singularity/Move(atom/newloc, direct)
var/turf/T = get_turf(src)
for(var/dir in GLOB.cardinals)
if(direct & dir)
T = get_step(T, dir)
if(!T)
break
// eat the stuff if we're going to move into it so it doesn't mess up our movement
for(var/atom/A in T.contents)
consume(A)
consume(T)
if(current_size >= STAGE_FIVE || check_turfs_in(direct))
last_failed_movement = 0//Reset this because we moved
return ..()
else
last_failed_movement = direct
return FALSE
/obj/singularity/attack_hand(mob/user)
consume(user)
return TRUE
/obj/singularity/attack_paw(mob/user)
consume(user)
/obj/singularity/attack_alien(mob/user)
consume(user)
/obj/singularity/attack_animal(mob/user)
consume(user)
/obj/singularity/attackby(obj/item/W, mob/user, params)
consume(user)
return TRUE
/obj/singularity/Process_Spacemove() //The singularity stops drifting for no man!
return FALSE
/obj/singularity/blob_act(obj/structure/blob/B)
return
/obj/singularity/attack_tk(mob/user)
if(!iscarbon(user))
return
@@ -150,7 +116,6 @@
rip_u.dismember(BURN)
qdel(rip_u)
/obj/singularity/ex_act(severity, target)
switch(severity)
if(1)
@@ -164,52 +129,14 @@
energy -= round(((energy+1)/3),1)
if(3)
energy -= round(((energy+1)/4),1)
return
/obj/singularity/bullet_act(obj/projectile/P)
qdel(P)
return BULLET_ACT_HIT //Will there be an impact? Who knows. Will we see it? No.
/obj/singularity/Bump(atom/A)
consume(A)
if(QDELETED(A)) // don't keep moving into objects that weren't destroyed infinitely
step(src, drifting_dir)
return
/obj/singularity/Crossed(atom/A)
..()
consume(A)
/obj/singularity/Bumped(atom/movable/AM)
consume(AM)
/obj/singularity/process()
if(current_size >= STAGE_TWO)
move()
if(prob(event_chance))//Chance for it to run a special event TODO:Come up with one or two more that fit
event()
eat()
dissipate()
check_energy()
return
/obj/singularity/attack_ai() //to prevent ais from gibbing themselves when they click on one.
return
/obj/singularity/proc/admin_investigate_setup()
var/turf/T = get_turf(src)
last_warning = world.time
var/count = locate(/obj/machinery/field/containment) in urange(30, src, 1)
if(!count)
message_admins("A singulo has been created without containment fields active at [ADMIN_VERBOSEJMP(T)].")
investigate_log("was created at [AREACOORD(T)]. [count?"":"<font color='red'>No containment fields were active</font>"]", INVESTIGATE_SINGULO)
/obj/singularity/proc/dissipate()
if(!dissipate)
return
@@ -219,13 +146,18 @@
else
dissipate_track++
/obj/singularity/proc/expand(force_size = 0)
/obj/singularity/proc/expand(force_size)
var/temp_allowed_size = src.allowed_size
if(force_size)
temp_allowed_size = force_size
if(temp_allowed_size >= STAGE_SIX && !consumedSupermatter)
if(temp_allowed_size >= STAGE_SIX && !consumed_supermatter)
temp_allowed_size = STAGE_FIVE
var/new_grav_pull
var/new_consume_range
switch(temp_allowed_size)
if(STAGE_ONE)
current_size = STAGE_ONE
@@ -233,8 +165,8 @@
icon_state = "singularity_s1"
pixel_x = 0
pixel_y = 0
grav_pull = 4
consume_range = 0
new_grav_pull = 4
new_consume_range = 0
dissipate_delay = 10
dissipate_track = 0
dissipate_strength = 1
@@ -245,8 +177,8 @@
icon_state = "singularity_s3"
pixel_x = -32
pixel_y = -32
grav_pull = 6
consume_range = 1
new_grav_pull = 6
new_consume_range = 1
dissipate_delay = 5
dissipate_track = 0
dissipate_strength = 5
@@ -257,8 +189,8 @@
icon_state = "singularity_s5"
pixel_x = -64
pixel_y = -64
grav_pull = 8
consume_range = 2
new_grav_pull = 8
new_consume_range = 2
dissipate_delay = 4
dissipate_track = 0
dissipate_strength = 20
@@ -269,8 +201,8 @@
icon_state = "singularity_s7"
pixel_x = -96
pixel_y = -96
grav_pull = 10
consume_range = 3
new_grav_pull = 10
new_consume_range = 3
dissipate_delay = 10
dissipate_track = 0
dissipate_strength = 10
@@ -280,18 +212,27 @@
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
new_grav_pull = 10
new_consume_range = 4
dissipate = FALSE //It cant go smaller due to e loss
if(STAGE_SIX) //This only happens if a stage 5 singulo consumes a supermatter shard.
current_size = STAGE_SIX
icon = 'icons/effects/352x352.dmi'
icon_state = "singularity_s11"
pixel_x = -160
pixel_y = -160
grav_pull = 15
consume_range = 5
dissipate = 0
new_grav_pull = 15
new_consume_range = 5
dissipate = FALSE
var/datum/component/singularity/resolved_singularity = singularity_component.resolve()
if (!isnull(resolved_singularity))
resolved_singularity.consume_range = new_consume_range
resolved_singularity.grav_pull = new_grav_pull
resolved_singularity.disregard_failed_movements = current_size >= STAGE_FIVE
resolved_singularity.roaming = move_self && current_size >= STAGE_TWO
resolved_singularity.singularity_size = current_size
if(current_size == allowed_size)
investigate_log("<font color='red'>grew to size [current_size]</font>", INVESTIGATE_SINGULO)
return TRUE
@@ -316,7 +257,7 @@
if(1000 to 1999)
allowed_size = STAGE_FOUR
if(2000 to INFINITY)
if(energy >= 3000 && consumedSupermatter)
if(energy >= 3000 && consumed_supermatter)
allowed_size = STAGE_SIX
else
allowed_size = STAGE_FIVE
@@ -324,51 +265,14 @@
expand()
return TRUE
/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(atom/A)
var/gain = A.singularity_act(current_size, src)
src.energy += gain
if(istype(A, /obj/machinery/power/supermatter_crystal) && !consumedSupermatter)
/obj/singularity/proc/consume(atom/thing)
var/gain = thing.singularity_act(current_size, src)
energy += gain
if(istype(thing, /obj/machinery/power/supermatter_crystal) && !consumed_supermatter)
desc = "[initial(desc)] It glows fiercely with inner fire."
name = "supermatter-charged [initial(name)]"
consumedSupermatter = 1
consumed_supermatter = TRUE
set_light(10)
return
/obj/singularity/proc/move(force_move = 0)
if(!move_self)
return FALSE
var/drifting_dir = pick(GLOB.alldirs - last_failed_movement)
if(force_move)
drifting_dir = force_move
if(target && prob(60))
drifting_dir = get_dir(src,target) //moves to a singulo beacon, if there is one
step(src, drifting_dir)
/obj/singularity/proc/check_cardinals_range(steps, retry_with_move = FALSE)
. = length(GLOB.cardinals) //Should be 4.
@@ -497,18 +401,13 @@
/obj/singularity/proc/emp_area()
empulse(src, 8, 10)
return
/obj/singularity/singularity_act()
var/gain = (energy/2)
var/dist = max((current_size - 2),1)
explosion(src.loc,(dist),(dist*2),(dist*4))
qdel(src)
return(gain)
/obj/singularity/proc/bluespace_reaction()
investigate_log("has been shot by bluespace artillery and destroyed.", INVESTIGATE_SINGULO)
qdel(src)
return gain
/obj/singularity/deadchat_controlled
move_self = FALSE