Files
Bubberstation/code/datums/proximity_monitor/fields/timestop.dm
SkyratBot 2090bf4df3 [MIRROR] timestop the SM [MDB IGNORE] (#20352)
* timestop the SM (#74302)

## About The Pull Request

Allows the timestop effects to freeze the Supermatter processing so that
engineers might be able to save it this time
## Why It's Good For The Game

Both wizards and science nerds are able to stop the SM seconds from
meltdown so that engies can figure out what's the right pipe to place to
prevent a destruction of property.
## Changelog
🆑
add: Timestop blocks the SM from processing (can't be healed, doesn't
output gases but can still take damage)
/🆑

* timestop the SM

---------

Co-authored-by: Ghilker <42839747+Ghilker@users.noreply.github.com>
2023-04-05 11:32:12 -07:00

251 lines
8.1 KiB
Plaintext

/obj/effect/timestop
anchored = TRUE
name = "chronofield"
desc = "ZA WARUDO"
icon = 'icons/effects/160x160.dmi'
icon_state = "time"
layer = FLY_LAYER
plane = ABOVE_GAME_PLANE
pixel_x = -64
pixel_y = -64
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/list/immune = list() // the one who creates the timestop is immune, which includes wizards and the dead slime you murdered to make this chronofield
var/turf/target
var/freezerange = 2
var/duration = 140
var/datum/proximity_monitor/advanced/timestop/chronofield
alpha = 125
var/antimagic_flags = NONE
///if true, immune atoms moving ends the timestop instead of duration.
var/channelled = FALSE
/// hides time icon effect and mutes sound
var/hidden = FALSE
/obj/effect/timestop/Initialize(mapload, radius, time, list/immune_atoms, start = TRUE, silent = FALSE) //Immune atoms assoc list atom = TRUE
. = ..()
if(!isnull(time))
duration = time
if(!isnull(radius))
freezerange = radius
if(silent)
hidden = TRUE
alpha = 0
for(var/A in immune_atoms)
immune[A] = TRUE
for(var/mob/living/to_check in GLOB.player_list)
if(HAS_TRAIT(to_check, TRAIT_TIME_STOP_IMMUNE))
immune[to_check] = TRUE
for(var/mob/living/simple_animal/hostile/guardian/stand in GLOB.parasites)
if(stand.summoner && HAS_TRAIT(stand.summoner, TRAIT_TIME_STOP_IMMUNE)) //It would only make sense that a person's stand would also be immune.
immune[stand] = TRUE
if(start)
INVOKE_ASYNC(src, PROC_REF(timestop))
/obj/effect/timestop/Destroy()
QDEL_NULL(chronofield)
if(!hidden)
playsound(src, 'sound/magic/timeparadox2.ogg', 75, TRUE, frequency = -1) //reverse!
return ..()
/obj/effect/timestop/proc/timestop()
target = get_turf(src)
if(!hidden)
playsound(src, 'sound/magic/timeparadox2.ogg', 75, TRUE, -1)
chronofield = new (src, freezerange, TRUE, immune, antimagic_flags, channelled)
if(!channelled)
QDEL_IN(src, duration)
/obj/effect/timestop/magic
antimagic_flags = MAGIC_RESISTANCE
///indefinite version, but only if no immune atoms move.
/obj/effect/timestop/channelled
channelled = TRUE
/datum/proximity_monitor/advanced/timestop
edge_is_a_field = TRUE
var/list/immune = list()
var/list/frozen_things = list()
var/list/frozen_mobs = list() //cached separately for processing
var/list/frozen_structures = list() //Also machinery, and only frozen aestethically
var/list/frozen_turfs = list() //Only aesthetically
var/antimagic_flags = NONE
///if true, this doesn't time out after a duration but rather when an immune atom inside moves.
var/channelled = FALSE
var/static/list/global_frozen_atoms = list()
/datum/proximity_monitor/advanced/timestop/New(atom/_host, range, _ignore_if_not_on_turf = TRUE, list/immune, antimagic_flags, channelled)
..()
src.immune = immune
src.antimagic_flags = antimagic_flags
src.channelled = channelled
recalculate_field()
START_PROCESSING(SSfastprocess, src)
/datum/proximity_monitor/advanced/timestop/Destroy()
unfreeze_all()
if(channelled)
for(var/atom in immune)
UnregisterSignal(atom, COMSIG_MOVABLE_MOVED)
STOP_PROCESSING(SSfastprocess, src)
return ..()
/datum/proximity_monitor/advanced/timestop/field_turf_crossed(atom/movable/movable, turf/location)
freeze_atom(movable)
/datum/proximity_monitor/advanced/timestop/proc/freeze_atom(atom/movable/A)
if(global_frozen_atoms[A] || !istype(A))
return FALSE
if(immune[A]) //a little special logic but yes immune things don't freeze
if(channelled)
RegisterSignal(A, COMSIG_MOVABLE_MOVED, PROC_REF(atom_broke_channel), override = TRUE)
return FALSE
if(ismob(A))
var/mob/M = A
if(M.can_block_magic(antimagic_flags))
immune[A] = TRUE
return
var/frozen = TRUE
if(isliving(A))
freeze_mob(A)
else if(isprojectile(A))
freeze_projectile(A)
else if(ismecha(A))
freeze_mecha(A)
else if((ismachinery(A) && !istype(A, /obj/machinery/light)) || isstructure(A)) //Special exception for light fixtures since recoloring causes them to change light
freeze_structure(A)
else
frozen = FALSE
if(A.throwing)
freeze_throwing(A)
frozen = TRUE
if(!frozen)
return
frozen_things[A] = A.move_resist
A.move_resist = INFINITY
global_frozen_atoms[A] = src
into_the_negative_zone(A)
RegisterSignal(A, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(unfreeze_atom))
RegisterSignal(A, COMSIG_ITEM_PICKUP, PROC_REF(unfreeze_atom))
SEND_SIGNAL(A, COMSIG_ATOM_TIMESTOP_FREEZE, src)
return TRUE
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_all()
for(var/i in frozen_things)
unfreeze_atom(i)
for(var/T in frozen_turfs)
unfreeze_turf(T)
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_atom(atom/movable/A)
SIGNAL_HANDLER
if(A.throwing)
unfreeze_throwing(A)
if(isliving(A))
unfreeze_mob(A)
else if(isprojectile(A))
unfreeze_projectile(A)
else if(ismecha(A))
unfreeze_mecha(A)
UnregisterSignal(A, COMSIG_MOVABLE_PRE_MOVE)
UnregisterSignal(A, COMSIG_ITEM_PICKUP)
SEND_SIGNAL(A, COMSIG_ATOM_TIMESTOP_UNFREEZE, src)
escape_the_negative_zone(A)
A.move_resist = frozen_things[A]
frozen_things -= A
global_frozen_atoms -= A
/datum/proximity_monitor/advanced/timestop/proc/freeze_mecha(obj/vehicle/sealed/mecha/M)
M.completely_disabled = TRUE
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mecha(obj/vehicle/sealed/mecha/M)
M.completely_disabled = FALSE
/datum/proximity_monitor/advanced/timestop/proc/freeze_throwing(atom/movable/AM)
var/datum/thrownthing/T = AM.throwing
T.paused = TRUE
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_throwing(atom/movable/AM)
var/datum/thrownthing/T = AM.throwing
if(T)
T.paused = FALSE
/datum/proximity_monitor/advanced/timestop/proc/freeze_turf(turf/T)
into_the_negative_zone(T)
frozen_turfs += T
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_turf(turf/T)
escape_the_negative_zone(T)
/datum/proximity_monitor/advanced/timestop/proc/freeze_structure(obj/O)
into_the_negative_zone(O)
frozen_structures += O
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_structure(obj/O)
escape_the_negative_zone(O)
/datum/proximity_monitor/advanced/timestop/process()
for(var/i in frozen_mobs)
var/mob/living/m = i
m.Stun(20, ignore_canstun = TRUE)
/datum/proximity_monitor/advanced/timestop/setup_field_turf(turf/target)
. = ..()
for(var/i in target.contents)
freeze_atom(i)
freeze_turf(target)
/datum/proximity_monitor/advanced/timestop/proc/freeze_projectile(obj/projectile/P)
P.paused = TRUE
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_projectile(obj/projectile/P)
P.paused = FALSE
/datum/proximity_monitor/advanced/timestop/proc/freeze_mob(mob/living/victim)
frozen_mobs += victim
victim.Stun(20, ignore_canstun = TRUE)
victim.add_traits(list(TRAIT_MUTE, TRAIT_EMOTEMUTE), TIMESTOP_TRAIT)
SSmove_manager.stop_looping(victim) //stops them mid pathing even if they're stunimmune //This is really dumb
if(isanimal(victim))
var/mob/living/simple_animal/animal_victim = victim
animal_victim.toggle_ai(AI_OFF)
if(ishostile(victim))
var/mob/living/simple_animal/hostile/hostile_victim = victim
hostile_victim.LoseTarget()
else if(isbasicmob(victim))
var/mob/living/basic/basic_victim = victim
basic_victim.ai_controller?.set_ai_status(AI_STATUS_OFF)
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mob(mob/living/victim)
victim.AdjustStun(-20, ignore_canstun = TRUE)
victim.remove_traits(list(TRAIT_MUTE, TRAIT_EMOTEMUTE), TIMESTOP_TRAIT)
frozen_mobs -= victim
if(isanimal(victim))
var/mob/living/simple_animal/animal_victim = victim
animal_victim.toggle_ai(initial(animal_victim.AIStatus))
else if(isbasicmob(victim))
var/mob/living/basic/basic_victim = victim
basic_victim.ai_controller?.reset_ai_status()
//you don't look quite right, is something the matter?
/datum/proximity_monitor/advanced/timestop/proc/into_the_negative_zone(atom/A)
A.add_atom_colour(list(-1,0,0,0, 0,-1,0,0, 0,0,-1,0, 0,0,0,1, 1,1,1,0), TEMPORARY_COLOUR_PRIORITY)
//let's put some colour back into your cheeks
/datum/proximity_monitor/advanced/timestop/proc/escape_the_negative_zone(atom/A)
A.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
//signal fired when an immune atom moves in the time freeze zone
/datum/proximity_monitor/advanced/timestop/proc/atom_broke_channel(datum/source)
SIGNAL_HANDLER
qdel(host)