From 5c44996ffb655633cf94b2c2a997ff5a451b65eb Mon Sep 17 00:00:00 2001
From: crazyraio2 <44246096+crazyraio2@users.noreply.github.com>
Date: Tue, 18 Aug 2020 21:30:47 -0300
Subject: [PATCH] yeet, help me
---
sandcode/code/_HELPERS/unsorted.dm | 12 +
sandcode/code/__DEFINES/combat.dm | 6 +
.../controllers/subsystem/bluespace_locker.dm | 69 +++++
.../code/game/area/Space_Station_13_areas.dm | 7 +
.../closets/bluespace_locker.dm | 283 ++++++++++++++++++
sandcode/icons/obj/closet.dmi | Bin 0 -> 4290 bytes
tgstation.dme | 5 +
7 files changed, 382 insertions(+)
create mode 100644 sandcode/code/_HELPERS/unsorted.dm
create mode 100644 sandcode/code/__DEFINES/combat.dm
create mode 100644 sandcode/code/controllers/subsystem/bluespace_locker.dm
create mode 100644 sandcode/code/game/area/Space_Station_13_areas.dm
create mode 100644 sandcode/code/game/objects/structures/crates_lockers/closets/bluespace_locker.dm
create mode 100644 sandcode/icons/obj/closet.dmi
diff --git a/sandcode/code/_HELPERS/unsorted.dm b/sandcode/code/_HELPERS/unsorted.dm
new file mode 100644
index 0000000000..945032216e
--- /dev/null
+++ b/sandcode/code/_HELPERS/unsorted.dm
@@ -0,0 +1,12 @@
+//i have no idea what the difference is between this and get_turf()
+/proc/get_turf_global(atom/A, recursion_limit = 5)
+ var/turf/T = get_turf(A)
+ if(!T)
+ return
+ if(recursion_limit <= 0)
+ return T
+ if(T.loc)
+ var/area/R = T.loc
+ if(R.global_turf_object)
+ return get_turf_global(R.global_turf_object, recursion_limit - 1)
+ return T
diff --git a/sandcode/code/__DEFINES/combat.dm b/sandcode/code/__DEFINES/combat.dm
new file mode 100644
index 0000000000..d7c1d86228
--- /dev/null
+++ b/sandcode/code/__DEFINES/combat.dm
@@ -0,0 +1,6 @@
+/*ALL DEFINES RELATED TO COMBAT GO HERE*/
+
+//Actual combat defines
+
+//click cooldowns, in tenths of a second, used for various combat actions
+#define CLICK_CD_BREAKOUT 100
diff --git a/sandcode/code/controllers/subsystem/bluespace_locker.dm b/sandcode/code/controllers/subsystem/bluespace_locker.dm
new file mode 100644
index 0000000000..0412d6e82c
--- /dev/null
+++ b/sandcode/code/controllers/subsystem/bluespace_locker.dm
@@ -0,0 +1,69 @@
+SUBSYSTEM_DEF(bluespace_locker)
+ name = "Bluespace Locker"
+ flags = SS_NO_FIRE
+ var/obj/structure/closet/bluespace/internal/internal_locker = null
+ var/obj/structure/closet/bluespace/external/external_locker = null
+
+/datum/controller/subsystem/bluespace_locker/Initialize()
+ bluespaceify_random_locker()
+ if(external_locker)
+ external_locker.take_contents()
+ return ..()
+
+/datum/controller/subsystem/bluespace_locker/proc/bluespaceify_random_locker()
+ if(external_locker)
+ return
+ // basically any normal-looking locker that isn't a secure one
+ var/list/valid_lockers = typecacheof(typesof(/obj/structure/closet) - typesof(/obj/structure/closet/body_bag)\
+ - typesof(/obj/structure/closet/secure_closet) - typesof(/obj/structure/closet/cabinet)\
+ - typesof(/obj/structure/closet/cardboard) - typesof(/obj/structure/closet/crate)\
+ - typesof(/obj/structure/closet/supplypod) - typesof(/obj/structure/closet/stasis)\
+ - typesof(/obj/structure/closet/abductor) - typesof(/obj/structure/closet/bluespace), only_root_path = TRUE)
+
+ var/list/lockers_list = list()
+ for(var/obj/structure/closet/L in world)
+ if(is_station_level(L.z) && is_type_in_typecache(L, valid_lockers))
+ lockers_list += L
+ if(!lockers_list.len)
+ // Congratulations, you managed to destroy all the lockers somehow.
+ // Now let's make a new one.
+ var/targetturf = find_safe_turf()
+ if(!targetturf)
+ if(GLOB.blobstart.len > 0)
+ targetturf = get_turf(pick(GLOB.blobstart))
+ else
+ CRASH("Unable to find a blobstart landmark")
+ lockers_list += new /obj/structure/closet(targetturf)
+ var/obj/structure/closet/L = pick(lockers_list)
+
+ var/obj/structure/closet/bluespace/external/E = new(L.loc)
+ E.contents = L.contents
+ E.name = L.name
+ E.desc = L.desc
+ if(L.opened)
+ E.open()
+ E.icon = L.icon
+ E.icon_state = L.icon_state
+ E.icon_door = L.icon_door
+ E.icon_door_override = L.icon_door_override
+ E.icon_welded = L.icon_welded
+ qdel(L)
+
+ relink_lockers()
+
+/datum/controller/subsystem/bluespace_locker/proc/relink_lockers()
+ if(!internal_locker)
+ return
+ //var/area/A = get_area(internal_locker)
+ //A.global_turf_object = external_locker
+ internal_locker.update_mirage()
+ if(!external_locker)
+ return
+ if(external_locker.opened)
+ internal_locker.close()
+ else
+ internal_locker.contents += external_locker.contents
+ internal_locker.open()
+ internal_locker.dump_contents()
+ internal_locker.update_icon()
+ external_locker.update_icon()
\ No newline at end of file
diff --git a/sandcode/code/game/area/Space_Station_13_areas.dm b/sandcode/code/game/area/Space_Station_13_areas.dm
new file mode 100644
index 0000000000..e278cb774c
--- /dev/null
+++ b/sandcode/code/game/area/Space_Station_13_areas.dm
@@ -0,0 +1,7 @@
+/area/bluespace_locker
+ name = "Bluespace Locker"
+ icon_state = "away"
+ requires_power = FALSE
+ has_gravity = STANDARD_GRAVITY
+ noteleport = TRUE
+ hidden = TRUE
diff --git a/sandcode/code/game/objects/structures/crates_lockers/closets/bluespace_locker.dm b/sandcode/code/game/objects/structures/crates_lockers/closets/bluespace_locker.dm
new file mode 100644
index 0000000000..d1456979e4
--- /dev/null
+++ b/sandcode/code/game/objects/structures/crates_lockers/closets/bluespace_locker.dm
@@ -0,0 +1,283 @@
+/obj/structure/closet/bluespace
+ name = "bluespace locker"
+
+/obj/structure/closet/bluespace/proc/get_other_locker()
+ return SSbluespace_locker.internal_locker
+
+/obj/structure/closet/bluespace/open()
+ var/obj/structure/closet/other = get_other_locker()
+ if(!other)
+ return ..()
+ if(!opened)
+ . = ..()
+ other.close()
+ dump_contents()
+
+/obj/structure/closet/bluespace/close()
+ var/obj/structure/closet/other = get_other_locker()
+ if(!other)
+ return ..()
+ if(opened)
+ . = ..()
+ other.contents += contents
+ other.open()
+
+/obj/structure/closet/bluespace/internal
+ name = "bluespace locker portal"
+ icon_state = null
+ desc = ""
+ cutting_tool = null
+ can_weld_shut = FALSE
+ anchored = TRUE
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ var/list/mirage_whitelist = list()
+
+/obj/structure/closet/bluespace/internal/Initialize()
+ if(SSbluespace_locker.internal_locker && SSbluespace_locker.internal_locker != src)
+ qdel(src)
+ return
+ SSbluespace_locker.internal_locker = src
+ ..()
+
+/obj/structure/closet/bluespace/internal/get_other_locker()
+ return SSbluespace_locker.external_locker
+
+/obj/structure/closet/bluespace/internal/can_open(user)
+ var/obj/structure/closet/other = get_other_locker()
+ if(!other)
+ return FALSE
+ if(!other.opened)
+ return TRUE
+ return other.can_close(user)
+/obj/structure/closet/bluespace/internal/can_close(user)
+ var/obj/structure/closet/other = get_other_locker()
+ if(!other || other.opened)
+ return TRUE
+ return other.can_open(user)
+
+/obj/structure/closet/bluespace/internal/tool_interact(obj/item/W, mob/user)
+ return
+
+/obj/structure/closet/bluespace/internal/attack_hand(mob/living/user)
+ var/obj/structure/closet/other = get_other_locker()
+ if(!other)
+ return ..()
+ if(!other.opened && (other.welded || other.locked))
+ if(ismovable(other.loc))
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ var/atom/movable/AM = other.loc
+ AM.relay_container_resist(user, other)
+ return
+
+ //okay, so the closet is either welded or locked... resist!!!
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ other.visible_message("[other] begins to shake violently!")
+ to_chat(user, "You start pushing the door open... (this will take about [DisplayTimeText(other.breakout_time)].)")
+ if(do_after(user,(other.breakout_time), target = src))
+ if(!user || user.stat != CONSCIOUS || other.opened || (!other.locked && !other.welded))
+ return
+ //we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
+ other.bust_open()
+ user.visible_message("[user] successfully broke out of [other]!",
+ "You successfully break out of [other]!")
+ else
+ if(!other.opened) //so we don't get the message if we resisted multiple times and succeeded.
+ to_chat(user, "You fail to break out of [other]!")
+ else
+ return ..()
+
+/obj/structure/closet/bluespace/internal/update_icon()
+ cut_overlays()
+ var/obj/structure/closet/other = get_other_locker()
+ if(!other)
+ other = src
+ var/mutable_appearance/masked_icon = mutable_appearance('sandcode/icons/obj/closet.dmi', "bluespace_locker_mask")
+ masked_icon.appearance_flags = KEEP_TOGETHER
+ var/mutable_appearance/masking_icon = mutable_appearance(other.icon, other.icon_state)
+ masking_icon.blend_mode = BLEND_MULTIPLY
+ masked_icon.add_overlay(masking_icon)
+ //add_overlay(image('yogstation/icons/obj/closet.dmi', "bluespace_locker_frame"))
+ add_overlay(masked_icon)
+ if(!opened)
+ layer = OBJ_LAYER
+ if(other.icon_door)
+ add_overlay(image(other.icon, "[other.icon_door]_door"))
+ else
+ add_overlay(image(other.icon, "[other.icon_state]_door"))
+ else
+ layer = BELOW_OBJ_LAYER
+ if(other.icon_door_override)
+ add_overlay(image(other.icon, "[other.icon_door]_open"))
+ else
+ add_overlay(image(other.icon, "[other.icon_state]_open"))
+
+/obj/structure/closet/bluespace/external/onTransitZ(old_z,new_z)
+ var/obj/structure/closet/O = get_other_locker()
+ if(O)
+ var/area/A = get_area(O)
+ if(A)
+ for(var/atom/movable/M in A)
+ M.onTransitZ(old_z,new_z)
+ return ..()
+
+/obj/structure/closet/bluespace/internal/proc/update_mirage()
+ var/area/A = get_area(src)
+ for(var/atom/movable/M in A)
+ if(M == src) // in case someone somehow manages to teleport the bluespace locker inside of itself
+ continue
+ M.update_parallax_contents()
+ var/turf/internal_origin
+ var/turf/external_origin = get_turf(get_other_locker())
+ for(var/obj/effect/landmark/bluespace_locker_origin/L in A)
+ internal_origin = get_turf(L)
+ break
+ mirage_whitelist.len = 0
+ for(var/turf/T in view(11, external_origin))
+ mirage_whitelist[T] = TRUE
+ for(var/turf/open/space/bluespace_locker_mirage/T in A)
+ T.internal_origin = internal_origin
+ T.external_origin = external_origin
+ T.turf_whitelist = mirage_whitelist
+ T.update_mirage()
+
+/obj/structure/closet/bluespace/external/Initialize()
+ if(SSbluespace_locker.external_locker && SSbluespace_locker.external_locker != src)
+ qdel(src)
+ return
+ SSbluespace_locker.external_locker = src
+ ..()
+
+/obj/structure/closet/bluespace/external/Destroy()
+ SSbluespace_locker.external_locker = null
+ SSbluespace_locker.bluespaceify_random_locker()
+ return ..()
+
+/obj/structure/closet/bluespace/external/can_open()
+ if(welded || locked)
+ return FALSE
+ return TRUE
+
+/obj/structure/closet/bluespace/external/can_close()
+ if(welded || locked)
+ return FALSE
+ return TRUE
+
+
+/obj/structure/closet/bluespace/external/Moved()
+ var/obj/structure/closet/bluespace/internal/C = get_other_locker()
+ if(C)
+ C.update_mirage()
+ return ..()
+
+/obj/structure/closet/bluespace/external/afterShuttleMove()
+ var/obj/structure/closet/bluespace/internal/C = get_other_locker()
+ if(C)
+ C.update_mirage()
+ return ..()
+
+/obj/effect/landmark/bluespace_locker_origin
+ name = "bluespace locker origin"
+
+/turf/open/space/bluespace_locker_mirage
+ density = 1
+ icon_state = "black"
+ blocks_air = 1
+ name = "holographic projection"
+ desc = "A holographic projection of the area surrounding the bluespace locker"
+ flags_1 = NOJAUNT_1
+ var/turf/internal_origin
+ var/turf/external_origin
+ var/turf/external_origin_prev
+ var/turf/external_origin_prev_prev
+ var/turf/external_origin_prev_time = -1
+ var/list/turf_whitelist
+ var/reset_timer_id
+
+/turf/open/space/bluespace_locker_mirage/CanBuildHere()
+ return FALSE
+
+/turf/open/space/bluespace_locker_mirage/proc/update_mirage()
+ if(!internal_origin || !external_origin)
+ vis_contents = list()
+ return
+ if(external_origin == external_origin_prev)
+ return
+ if(world.time == external_origin_prev_time)
+ external_origin_prev = external_origin_prev_prev
+ cut_overlays()
+ var/glide_dir = 0
+ if(external_origin_prev && external_origin_prev.z != external_origin && abs(external_origin.x - external_origin_prev.x) <= 1 && abs(external_origin.y - external_origin_prev.y) <= 1)
+ glide_dir = get_dir(external_origin_prev, external_origin)
+ var/turf/target_turf = locate(external_origin.x + x - internal_origin.x, external_origin.y + y - internal_origin.y, external_origin.z)
+ if(!target_turf || (turf_whitelist && !turf_whitelist[target_turf]))
+ vis_contents = list()
+ var/mutable_appearance/M = mutable_appearance('icons/turf/space.dmi', "black")
+ M.layer = TURF_LAYER
+ M.plane = FLOOR_PLANE
+ add_overlay(M)
+ else
+ vis_contents = list(target_turf)
+ if(glide_dir)
+ var/dx = 0
+ var/dy = 0
+ var/px = 0
+ var/py = 0
+ var/add_reset_timer
+ if(glide_dir & 1)
+ dy++
+ if(glide_dir & 2)
+ dy--
+ if(glide_dir & 4)
+ dx++
+ if(glide_dir & 8)
+ dx--
+ var/list/fullbrights = list()
+ var/area/A = target_turf.loc
+ if(!IS_DYNAMIC_LIGHTING(A))
+ fullbrights += new /obj/effect/fullbright()
+ for(var/cdir in GLOB.cardinals)
+ if(!(glide_dir & cdir))
+ continue
+ var/odir = turn(cdir, 180)
+ var/turf/T = get_step(src, odir)
+ if(T && T.type != /turf/open/space/bluespace_locker_mirage)
+ vis_contents += get_step(target_turf, odir)
+ add_reset_timer = TRUE
+ if(odir == 8)
+ px = -32
+ if(odir == 2)
+ py = -32
+ A = target_turf.loc
+ if(!IS_DYNAMIC_LIGHTING(A))
+ var/obj/effect/fullbright/F = new()
+ switch(odir)
+ if(1)
+ F.pixel_y = 32
+ if(2)
+ F.pixel_y = -32
+ if(4)
+ F.pixel_x = 32
+ if(8)
+ F.pixel_x = -32
+ fullbrights += F
+ for(var/V in fullbrights)
+ var/obj/F = V
+ F.pixel_x -= px // cancel out the pixel_x/y in the parent
+ F.pixel_y -= py
+ add_overlay(fullbrights)
+ if(add_reset_timer)
+ reset_timer_id = addtimer(CALLBACK(src, /turf/open/space/bluespace_locker_mirage.proc/reset_to_self), world.tick_lag * 4, TIMER_UNIQUE | TIMER_NO_HASH_WAIT | TIMER_OVERRIDE | TIMER_STOPPABLE)
+ else if(reset_timer_id)
+ deltimer(reset_timer_id)
+ pixel_x = px + dx*32
+ pixel_y = py + dy*32
+ animate(src, pixel_x = px, pixel_y = py, time = world.tick_lag * 4, flags = ANIMATION_END_NOW)
+ external_origin_prev_time = world.time
+ external_origin_prev_prev = external_origin_prev
+ external_origin_prev = external_origin
+
+/turf/open/space/bluespace_locker_mirage/proc/reset_to_self()
+ reset_timer_id = null
+ update_mirage()
diff --git a/sandcode/icons/obj/closet.dmi b/sandcode/icons/obj/closet.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..d4c17819462f8b6181575ea0d00897970835fb89
GIT binary patch
literal 4290
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