[MIRROR] Adds a Bluespace Connection component (#11860)

Co-authored-by: Guti <32563288+TheCaramelion@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-10-23 21:54:49 -07:00
committed by GitHub
parent 80a413f675
commit 62dd29255b
10 changed files with 163 additions and 3 deletions

View File

@@ -10,3 +10,6 @@
/// from base of [/atom/proc/extinguish]
#define COMSIG_ATOM_EXTINGUISH "atom_extinguish"
/// From base atom/hitby(atom/movable/AM)
#define COMSIG_ATOM_HITBY "atom_hitby"

View File

@@ -2,3 +2,5 @@
#define COMSIG_ARCADE_PRIZEVEND "arcade_prizevend"
///from /obj/machinery/rnd/destructive_analyzer/proc/destroy_item_individual(gain_research_points = FALSE): Runs when the destructive scanner scans a group of objects. (obj/item)
#define COMSIG_MACHINERY_DESTRUCTIVE_SCAN "machinery_destructive_scan"
///from /obj/structure/closet/close()
#define COMSIG_CLOSET_CLOSED "closet_closed"

View File

@@ -63,3 +63,5 @@ GLOBAL_LIST_EMPTY(verminstart)
GLOBAL_LIST_EMPTY(awayabductors) // List of scatter landmarks for Abductors in Gateways
GLOBAL_LIST_EMPTY(eventdestinations) // List of scatter landmarks for VOREStation event portals
GLOBAL_LIST_EMPTY(eventabductors) // List of scatter landmarks for VOREStation abductor portals
GLOBAL_LIST_EMPTY(bslockers) // List of (roundstart) bluespace lockers

View File

@@ -0,0 +1,127 @@
/// 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_noeffect_teleport(AM, exit_closet, 0, 1)
return
exit_closet.open()
var/turf/target = throw_target()
if(contents.len)
for(var/atom/movable/AM in contents)
if(QDELETED(AM))
continue
do_noeffect_teleport(AM, get_turf(exit_point), 0, 1)
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()

View File

@@ -298,6 +298,7 @@
/atom/proc/hitby(atom/movable/source)
SEND_SIGNAL(src, COMSIG_ATOM_HITBY, source)
if (density)
source.throwing = 0
return

View File

@@ -295,3 +295,11 @@
/// In landmarks.dm and not unit_test.dm so it is always active in the mapping tools.
/obj/effect/landmark/unit_test_top_right
name = "unit test zone top right"
/obj/effect/landmark/bslocker
name = "bslocker spawn"
/obj/effect/landmark/bslocker/Initialize(mapload)
. = ..()
var/obj/structure/closet/closet = new /obj/structure/closet/bluespace(loc)
GLOB.bslockers.Add(closet)

View File

@@ -168,6 +168,7 @@
if(initial(density))
density = !density
animate_door(TRUE)
SEND_SIGNAL(src, COMSIG_CLOSET_CLOSED, contents)
return 1
//Cham Projector Exception
@@ -585,3 +586,7 @@
var/mob/living/M = usr
if(isliving(M))
M.begin_instant_nom(M,target,M,M.vore_selected)
/obj/structure/closet/bluespace/Initialize(mapload)
. = ..()
AddComponent(/datum/component/bluespace_connection/permanent_network, GLOB.bslockers)

View File

@@ -17,9 +17,6 @@
AddElement(/datum/element/climbable)
AddElement(/datum/element/rotatable)
/obj/structure/closet/crate/can_open()
return 1
/obj/structure/closet/crate/can_close()
return 1
@@ -42,6 +39,8 @@
playsound(src, open_sound, 50, 1, -3)
for(var/obj/O in src)
O.forceMove(get_turf(src))
for(var/mob/M in src)
M.forceMove(get_turf(src))
src.opened = 1
SEND_SIGNAL(src, COMSIG_CLIMBABLE_SHAKE_CLIMBERS, null)
@@ -75,6 +74,8 @@
/obj/structure/closet/crate/attackby(obj/item/W as obj, mob/user as mob)
if(W.has_tool_quality(TOOL_WRENCH) && istype(src,/obj/structure/closet/crate/bin))
return ..()
else if(W.has_tool_quality(TOOL_WELDER))
return ..()
else if(opened)
if(isrobot(user))
return
@@ -129,6 +130,11 @@
return
return
/obj/structure/closet/req_breakout()
if(opened || !sealed)
return FALSE
return TRUE
/obj/structure/closet/crate/secure
desc = "A secure crate."
name = "Secure crate"
@@ -136,6 +142,11 @@
var/broken = 0
var/locked = 1
/obj/structure/closet/crate/secure/req_breakout()
if(opened || !locked || !sealed)
return FALSE
return TRUE
/obj/structure/closet/crate/secure/can_open()
return !locked

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -686,6 +686,7 @@
#include "code\datums\components\species\shadekin\powers\regenerate_other.dm"
#include "code\datums\components\species\shadekin\powers\dark_tunnel\dark_tunnel_structures.dm"
#include "code\datums\components\species\shadekin\powers\dark_tunnel\dark_tunneling.dm"
#include "code\datums\components\structures\bluespace_connection.dm"
#include "code\datums\components\traits\burninlight.dm"
#include "code\datums\components\traits\crowd_detection.dm"
#include "code\datums\components\traits\drippy.dm"