mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 00:29:02 +01:00
[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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -467,7 +467,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
else if(power > POWER_PENALTY_THRESHOLD)
|
||||
investigate_log("has spawned additional energy balls.", INVESTIGATE_SUPERMATTER)
|
||||
if(T)
|
||||
var/obj/singularity/energy_ball/E = new(T)
|
||||
var/obj/energy_ball/E = new(T)
|
||||
E.energy = 200 //Gets us about 9 balls
|
||||
else if(power > EVENT_POWER_PENALTY_THRESHOLD && prob(power/50) && !istype(src, /obj/machinery/power/supermatter_crystal/shard))
|
||||
var/datum/round_event_control/crystal_invasion/crystals = new/datum/round_event_control/crystal_invasion
|
||||
@@ -1008,7 +1008,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
user.dust(force = TRUE)
|
||||
if(power_changes)
|
||||
matter_power += 200
|
||||
else if(istype(AM, /obj/singularity))
|
||||
else if(AM.flags_1 & SUPERMATTER_IGNORES_1)
|
||||
return
|
||||
else if(isobj(AM))
|
||||
if(!iseffect(AM))
|
||||
|
||||
@@ -10,22 +10,26 @@
|
||||
#define BLOB (STRUCTURE + 1)
|
||||
#define STRUCTURE (1)
|
||||
|
||||
/obj/singularity/energy_ball
|
||||
/// The Tesla engine
|
||||
/obj/energy_ball
|
||||
name = "energy ball"
|
||||
desc = "An energy ball."
|
||||
icon = 'icons/obj/tesla_engine/energy_ball.dmi'
|
||||
icon_state = "energy_ball"
|
||||
anchored = TRUE
|
||||
appearance_flags = LONG_GLIDE
|
||||
density = TRUE
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
light_range = 6
|
||||
move_resist = INFINITY
|
||||
obj_flags = CAN_BE_HIT | DANGEROUS_POSSESSION
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
current_size = STAGE_TWO
|
||||
move_self = 1
|
||||
grav_pull = 0
|
||||
contained = 0
|
||||
density = TRUE
|
||||
energy = 0
|
||||
dissipate = FALSE
|
||||
dissipate_delay = 5
|
||||
dissipate_strength = 1
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
|
||||
flags_1 = SUPERMATTER_IGNORES_1
|
||||
|
||||
var/energy
|
||||
var/target
|
||||
var/list/orbiting_balls = list()
|
||||
var/miniball = FALSE
|
||||
var/produced_power
|
||||
@@ -33,39 +37,37 @@
|
||||
var/energy_to_lower = -20
|
||||
var/list/shocked_things = list()
|
||||
|
||||
/obj/singularity/energy_ball/Initialize(mapload, starting_energy = 50, is_miniball = FALSE)
|
||||
miniball = is_miniball
|
||||
/obj/energy_ball/Initialize(mapload, starting_energy = 50, is_miniball = FALSE)
|
||||
. = ..()
|
||||
if(!is_miniball)
|
||||
|
||||
energy = starting_energy
|
||||
miniball = is_miniball
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
if (!is_miniball)
|
||||
set_light(10, 7, "#5e5edd")
|
||||
|
||||
/obj/singularity/energy_ball/ex_act(severity, target)
|
||||
return
|
||||
var/turf/spawned_turf = get_turf(src)
|
||||
message_admins("A tesla has been created at [ADMIN_VERBOSEJMP(spawned_turf)].")
|
||||
investigate_log("(tesla) was created at [AREACOORD(spawned_turf)].", INVESTIGATE_SINGULO)
|
||||
|
||||
/obj/singularity/energy_ball/consume(severity, target)
|
||||
return
|
||||
/obj/energy_ball/Destroy()
|
||||
if(orbiting && istype(orbiting.parent, /obj/energy_ball))
|
||||
var/obj/energy_ball/parent_energy_ball = orbiting.parent
|
||||
parent_energy_ball.orbiting_balls -= src
|
||||
|
||||
/obj/singularity/energy_ball/Destroy()
|
||||
if(orbiting && istype(orbiting.parent, /obj/singularity/energy_ball))
|
||||
var/obj/singularity/energy_ball/EB = orbiting.parent
|
||||
EB.orbiting_balls -= src
|
||||
QDEL_LIST(orbiting_balls)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
for(var/ball in orbiting_balls)
|
||||
var/obj/singularity/energy_ball/EB = ball
|
||||
QDEL_NULL(EB)
|
||||
. = ..()
|
||||
return ..()
|
||||
|
||||
/obj/singularity/energy_ball/admin_investigate_setup()
|
||||
if(miniball)
|
||||
return //don't annnounce miniballs
|
||||
..()
|
||||
|
||||
|
||||
/obj/singularity/energy_ball/process()
|
||||
if(!orbiting)
|
||||
/obj/energy_ball/process()
|
||||
if(orbiting)
|
||||
energy = 0 // ensure we dont have miniballs of miniballs
|
||||
else
|
||||
handle_energy()
|
||||
|
||||
move_the_basket_ball(4 + orbiting_balls.len * 1.5)
|
||||
move(4 + orbiting_balls.len * 1.5)
|
||||
|
||||
playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, TRUE, extrarange = 30)
|
||||
|
||||
@@ -81,40 +83,46 @@
|
||||
var/list/temp_shock = list()
|
||||
tesla_zap(ball, range, TESLA_MINI_POWER/7*range, shocked_targets = temp_shock)
|
||||
shocked_things += temp_shock
|
||||
else
|
||||
energy = 0 // ensure we dont have miniballs of miniballs //But it'll be cool broooooooooooooooo
|
||||
|
||||
/obj/singularity/energy_ball/examine(mob/user)
|
||||
/obj/energy_ball/examine(mob/user)
|
||||
. = ..()
|
||||
if(orbiting_balls.len)
|
||||
. += "There are [orbiting_balls.len] mini-balls orbiting it."
|
||||
|
||||
|
||||
/obj/singularity/energy_ball/proc/move_the_basket_ball(move_amount)
|
||||
/obj/energy_ball/proc/move(move_amount)
|
||||
var/list/dirs = GLOB.alldirs.Copy()
|
||||
for(var/I in 1 to 30)
|
||||
for (var/i in 1 to 30)
|
||||
var/atom/real_thing = pick(shocked_things)
|
||||
dirs += get_dir(src, real_thing) //Carry some momentum yeah? Just a bit tho
|
||||
for(var/i in 0 to move_amount)
|
||||
for (var/i in 0 to move_amount)
|
||||
var/move_dir = pick(dirs) //ensures teslas don't just sit around
|
||||
if(target && prob(10))
|
||||
move_dir = get_dir(src,target)
|
||||
var/turf/T = get_step(src, move_dir)
|
||||
if(can_move(T))
|
||||
forceMove(T)
|
||||
if (target && prob(10))
|
||||
move_dir = get_dir(src, target)
|
||||
var/turf/turf_to_move = get_step(src, move_dir)
|
||||
if (can_move(turf_to_move))
|
||||
forceMove(turf_to_move)
|
||||
setDir(move_dir)
|
||||
for(var/mob/living/carbon/C in loc)
|
||||
dust_mobs(C)
|
||||
for (var/mob/living/carbon/mob_to_dust in loc)
|
||||
dust_mobs(mob_to_dust)
|
||||
|
||||
/obj/energy_ball/proc/can_move(turf/to_move)
|
||||
if (!to_move)
|
||||
return FALSE
|
||||
|
||||
/obj/singularity/energy_ball/proc/handle_energy()
|
||||
for (var/_thing in to_move)
|
||||
var/atom/thing = _thing
|
||||
if (SEND_SIGNAL(thing, COMSIG_ATOM_SINGULARITY_TRY_MOVE) & SINGULARITY_TRY_MOVE_BLOCK)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/energy_ball/proc/handle_energy()
|
||||
if(energy >= energy_to_raise)
|
||||
energy_to_lower = energy_to_raise - 20
|
||||
energy_to_raise = energy_to_raise * 1.25
|
||||
|
||||
playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, TRUE, extrarange = 30)
|
||||
addtimer(CALLBACK(src, .proc/new_mini_ball), 100)
|
||||
|
||||
else if(energy < energy_to_lower && orbiting_balls.len)
|
||||
energy_to_raise = energy_to_raise / 1.25
|
||||
energy_to_lower = (energy_to_raise / 1.25) - 20
|
||||
@@ -122,31 +130,31 @@
|
||||
var/Orchiectomy_target = pick(orbiting_balls)
|
||||
qdel(Orchiectomy_target)
|
||||
|
||||
else if(orbiting_balls.len)
|
||||
dissipate() //sing code has a much better system.
|
||||
|
||||
/obj/singularity/energy_ball/proc/new_mini_ball()
|
||||
/obj/energy_ball/proc/new_mini_ball()
|
||||
if(!loc)
|
||||
return
|
||||
var/obj/singularity/energy_ball/EB = new(loc, 0, TRUE)
|
||||
|
||||
EB.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7)
|
||||
var/icon/I = icon(icon,icon_state,dir)
|
||||
var/obj/energy_ball/miniball = new /obj/energy_ball(
|
||||
loc,
|
||||
/* starting_energy = */ 0,
|
||||
/* is_miniball = */ TRUE
|
||||
)
|
||||
|
||||
miniball.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7)
|
||||
var/icon/I = icon(icon, icon_state,dir)
|
||||
|
||||
var/orbitsize = (I.Width() + I.Height()) * pick(0.4, 0.5, 0.6, 0.7, 0.8)
|
||||
orbitsize -= (orbitsize / world.icon_size) * (world.icon_size * 0.25)
|
||||
|
||||
EB.orbit(src, orbitsize, pick(FALSE, TRUE), rand(10, 25), pick(3, 4, 5, 6, 36))
|
||||
miniball.orbit(src, orbitsize, pick(FALSE, TRUE), rand(10, 25), pick(3, 4, 5, 6, 36))
|
||||
|
||||
|
||||
/obj/singularity/energy_ball/Bump(atom/A)
|
||||
/obj/energy_ball/Bump(atom/A)
|
||||
dust_mobs(A)
|
||||
|
||||
/obj/singularity/energy_ball/Bumped(atom/movable/AM)
|
||||
/obj/energy_ball/Bumped(atom/movable/AM)
|
||||
dust_mobs(AM)
|
||||
|
||||
|
||||
/obj/singularity/energy_ball/attack_tk(mob/user)
|
||||
/obj/energy_ball/attack_tk(mob/user)
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
var/mob/living/carbon/jedi = user
|
||||
@@ -158,25 +166,22 @@
|
||||
jedi.death()
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
|
||||
/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target)
|
||||
/obj/energy_ball/orbit(obj/energy_ball/target)
|
||||
if (istype(target))
|
||||
target.orbiting_balls += src
|
||||
GLOB.poi_list -= src
|
||||
target.dissipate_strength = target.orbiting_balls.len
|
||||
. = ..()
|
||||
|
||||
/obj/singularity/energy_ball/stop_orbit()
|
||||
if (orbiting && istype(orbiting.parent, /obj/singularity/energy_ball))
|
||||
var/obj/singularity/energy_ball/orbitingball = orbiting.parent
|
||||
/obj/energy_ball/stop_orbit()
|
||||
if (orbiting && istype(orbiting.parent, /obj/energy_ball))
|
||||
var/obj/energy_ball/orbitingball = orbiting.parent
|
||||
orbitingball.orbiting_balls -= src
|
||||
orbitingball.dissipate_strength = orbitingball.orbiting_balls.len
|
||||
. = ..()
|
||||
if (!QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/singularity/energy_ball/proc/dust_mobs(atom/A)
|
||||
/obj/energy_ball/proc/dust_mobs(atom/A)
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
if(L.incorporeal_move || L.status_flags & GODMODE)
|
||||
|
||||
Reference in New Issue
Block a user