Files
CHOMPStation2/code/datums/components/structures/bluespace_connection.dm
2025-11-07 23:17:27 +01:00

128 lines
4.2 KiB
Plaintext

/// Bluespace connection component.
/// Given to lockers to make them into portals.
/datum/component/bluespace_connection
/// Assigned closet
VAR_PROTECTED/obj/structure/closet/assigned_closet = null
/// List of possible exits
var/list/connections = list()
/// Exit sound that it'll make upon exiting
var/exit_sound
// How far things gets thrown
var/throw_range
// Turf range when exiting, x
var/throw_range_x
// Turf range when exiting, y
var/throw_range_y
/// Use this one when using a global list of exits
/// Giving this to any locker will connect it to the network, allowing extra or none at any given point.
/datum/component/bluespace_connection/permanent_network
/datum/component/bluespace_connection/Initialize(var/list/connections, exit_sound = 'sound/effects/clang.ogg', throw_range = 3, throw_range_x = 5, throw_range_y = 5)
assigned_closet = parent
if(!istype(assigned_closet, /obj/structure/closet)) // Might expand this in the future? For now, it only goes on closets.
return COMPONENT_INCOMPATIBLE
src.connections = connections
src.exit_sound = exit_sound
src.throw_range = throw_range
src.throw_range_x = throw_range_x
src.throw_range_y = throw_range_y
/datum/component/bluespace_connection/RegisterWithParent()
RegisterSignal(parent, COMSIG_CLOSET_CLOSED, PROC_REF(on_close))
RegisterSignal(parent, COMSIG_ATOM_HITBY, PROC_REF(on_hit))
/datum/component/bluespace_connection/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_CLOSET_CLOSED, COMSIG_ATOM_HITBY))
/datum/component/bluespace_connection/Destroy()
assigned_closet = null
. = ..()
/datum/component/bluespace_connection/proc/on_close()
SIGNAL_HANDLER
if(isemptylist(assigned_closet.contents))
return
var/exit_point = pick(connections)
if(exit_point == assigned_closet)
sever_connection(exit_point)
return
if(istype(exit_point, /obj/structure/closet))
var/obj/structure/closet/exit_closet = exit_point
exit_closet.visible_message(span_notice("\The [exit_closet] rumbles..."), span_notice("Something rumbles..."))
exit_closet.animate_shake()
addtimer(CALLBACK(exit_closet, TYPE_PROC_REF(/obj/structure/closet, open)), 1 SECONDS)
playsound(exit_point, exit_sound, 50, TRUE)
addtimer(CALLBACK(src, PROC_REF(exit_connection), exit_point, assigned_closet.contents), 1.3 SECONDS)
/datum/component/bluespace_connection/proc/exit_connection(var/atom/exit_point, var/list/contents)
// Nope, must be closed.
if(assigned_closet.opened)
return
if(QDELETED(exit_point))
sever_connection(exit_point)
return
// Now the fun begins
if(istype(exit_point, /obj/structure/closet))
var/obj/structure/closet/exit_closet = exit_point
if(!exit_closet.can_open()) // Bwomp. You're locked now. :)
for(var/atom/movable/AM in contents)
do_teleport(AM, exit_closet, channel = TELEPORT_CHANNEL_BLUESPACE, no_effects = TRUE)
return
exit_closet.open()
var/turf/target = throw_target()
if(contents.len)
for(var/atom/movable/AM in contents)
if(QDELETED(AM))
continue
do_teleport(AM, get_turf(exit_point), channel = TELEPORT_CHANNEL_BLUESPACE, no_effects = TRUE)
if(!isbelly(exit_point))
AM.throw_at(target, throw_range, 1)
contents.Cut()
return
/datum/component/bluespace_connection/proc/on_hit()
SIGNAL_HANDLER
if(assigned_closet.opened)
assigned_closet.close()
return
/datum/component/bluespace_connection/proc/throw_target()
return get_offset_target_turf(get_turf(assigned_closet), rand(throw_range_x)-rand(throw_range_x), rand(throw_range_y)-rand(throw_range_y))
/datum/component/bluespace_connection/proc/add_exit(var/exit_point)
connections.Add(exit_point)
return TRUE
/datum/component/bluespace_connection/proc/sever_connection(var/removed_exit)
connections -= removed_exit
do_sparks()
if(!connections.len) // No exit points left, bluespace connection severed.
qdel(src)
return TRUE
/datum/component/bluespace_connection/permanent_network/sever_connection(removed_exit)
do_sparks()
return TRUE
/datum/component/bluespace_connection/proc/do_sparks()
playsound(assigned_closet, 'sound/effects/sparks6.ogg', 100, TRUE)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread
sparks.set_up(2, 1, assigned_closet.loc)
sparks.start()