mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
## About The Pull Request Some borg players complained about this so I made a PR ## Why It's Good For The Game ## Proof Of Testing <details> <summary>Screenshots/Videos</summary> </details> ## Changelog 🆑 balance: Borgs can go into gateway now /🆑
480 lines
16 KiB
Plaintext
480 lines
16 KiB
Plaintext
/// Station home gateway
|
|
GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
|
|
/// List of possible gateway destinations.
|
|
GLOBAL_LIST_EMPTY(gateway_destinations)
|
|
|
|
/**
|
|
* Corresponds to single entry in gateway control.
|
|
*
|
|
* Will NOT be added automatically to GLOB.gateway_destinations list.
|
|
*/
|
|
/datum/gateway_destination
|
|
var/name = "Unknown Destination"
|
|
var/wait = 0 /// How long after roundstart this destination becomes active
|
|
var/enabled = TRUE /// If disabled, the destination won't be available
|
|
var/hidden = FALSE /// Will not show on gateway controls at all.
|
|
|
|
/* Can a gateway link to this destination right now. */
|
|
/datum/gateway_destination/proc/is_available()
|
|
return enabled && (world.time - SSticker.round_start_time >= wait)
|
|
|
|
/* Returns user-friendly description why you can't connect to this destination, displayed in UI */
|
|
/datum/gateway_destination/proc/get_available_reason()
|
|
. = "Unreachable"
|
|
if(world.time - SSticker.round_start_time < wait)
|
|
playsound(src, 'sound/machines/gateway/gateway_calibrating.ogg', 80, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
. = "Connection desynchronized. Recalibration in progress."
|
|
|
|
/* Check if the movable is allowed to arrive at this destination (exile implants mostly) */
|
|
/datum/gateway_destination/proc/incoming_pass_check(atom/movable/AM)
|
|
return TRUE
|
|
|
|
/* Get the actual turf we'll arrive at */
|
|
/datum/gateway_destination/proc/get_target_turf()
|
|
CRASH("get target turf not implemented for this destination type")
|
|
|
|
/* Called after moving the movable to target turf */
|
|
/datum/gateway_destination/proc/post_transfer(atom/movable/AM)
|
|
if (ismob(AM))
|
|
var/mob/M = AM
|
|
if (M.client)
|
|
M.client.move_delay = max(world.time + 5, M.client.move_delay)
|
|
|
|
/* Called when gateway activates with this destination. */
|
|
/datum/gateway_destination/proc/activate(obj/machinery/gateway/activated)
|
|
return
|
|
|
|
/* Called when gateway targeting this destination deactivates. */
|
|
/datum/gateway_destination/proc/deactivate(obj/machinery/gateway/deactivated)
|
|
return
|
|
|
|
/* Returns data used by gateway controller ui */
|
|
/datum/gateway_destination/proc/get_ui_data()
|
|
. = list()
|
|
.["ref"] = REF(src)
|
|
.["name"] = name
|
|
.["available"] = is_available()
|
|
.["reason"] = get_available_reason()
|
|
if(wait)
|
|
.["timeout"] = max(1 - (wait - (world.time - SSticker.round_start_time)) / wait, 0)
|
|
|
|
/* Destination is another gateway */
|
|
/datum/gateway_destination/gateway
|
|
/// The gateway this destination points at
|
|
var/obj/machinery/gateway/target_gateway
|
|
|
|
/* We set the target gateway target to activator gateway */
|
|
/datum/gateway_destination/gateway/activate(obj/machinery/gateway/activated)
|
|
if(!target_gateway.target)
|
|
target_gateway.activate(activated)
|
|
|
|
/* We turn off the target gateway if it's linked with us */
|
|
/datum/gateway_destination/gateway/deactivate(obj/machinery/gateway/deactivated)
|
|
if(target_gateway.target == deactivated.destination)
|
|
target_gateway.deactivate()
|
|
|
|
/datum/gateway_destination/gateway/is_available()
|
|
return ..() && target_gateway.calibrated && !target_gateway.target && target_gateway.powered()
|
|
|
|
/datum/gateway_destination/gateway/get_available_reason()
|
|
. = ..()
|
|
if(!target_gateway.calibrated)
|
|
. = "Exit gateway malfunction. Manual recalibration required."
|
|
if(target_gateway.target)
|
|
. = "Exit gateway in use."
|
|
if(!target_gateway.powered())
|
|
. = "Exit gateway unpowered."
|
|
|
|
/datum/gateway_destination/gateway/get_target_turf()
|
|
return get_step(target_gateway.portal, target_gateway.dir)
|
|
|
|
/datum/gateway_destination/gateway/post_transfer(atom/movable/AM)
|
|
. = ..()
|
|
addtimer(CALLBACK(AM, TYPE_PROC_REF(/atom/movable, setDir), target_gateway.dir),0)
|
|
|
|
/* Special home destination, so we can check exile implants */
|
|
/datum/gateway_destination/gateway/home
|
|
|
|
/datum/gateway_destination/gateway/home/incoming_pass_check(atom/movable/AM)
|
|
if(isliving(AM))
|
|
if(check_exile_implant(AM))
|
|
return FALSE
|
|
else
|
|
for(var/mob/living/L in AM.contents)
|
|
if(check_exile_implant(L))
|
|
target_gateway.say("Rejecting [AM]: Exile implant detected in contained lifeform.")
|
|
return FALSE
|
|
if(AM.has_buckled_mobs())
|
|
for(var/mob/living/L in AM.buckled_mobs)
|
|
if(check_exile_implant(L))
|
|
target_gateway.say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/gateway_destination/gateway/home/proc/check_exile_implant(mob/living/L)
|
|
for(var/obj/item/implant/exile/E in L.implants)//Checking that there is an exile implant
|
|
to_chat(L, span_userdanger("The station gate has detected your exile implant and is blocking your entry."))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
|
|
/* Destination is one ore more turfs - created by landmarks */
|
|
/datum/gateway_destination/point
|
|
var/list/target_turfs = list()
|
|
/// Used by away landmarks
|
|
var/id
|
|
|
|
/datum/gateway_destination/point/get_target_turf()
|
|
return pick(target_turfs)
|
|
|
|
/* Dense invisible object starting the teleportation. Created by gateways on activation. */
|
|
/obj/effect/gateway_portal_bumper
|
|
var/obj/machinery/gateway/gateway
|
|
density = TRUE
|
|
invisibility = INVISIBILITY_ABSTRACT
|
|
|
|
/obj/effect/gateway_portal_bumper/Bumped(atom/movable/AM)
|
|
if(get_dir(src,AM) == gateway?.dir)
|
|
playsound(src, 'sound/machines/gateway/gateway_travel.ogg', 70, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
gateway.Transfer(AM)
|
|
|
|
/obj/effect/gateway_portal_bumper/Destroy(force)
|
|
. = ..()
|
|
gateway = null
|
|
|
|
/obj/machinery/gateway
|
|
name = "gateway"
|
|
desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations."
|
|
icon = 'icons/obj/machines/gateway.dmi'
|
|
icon_state = "portal_frame"
|
|
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
|
|
|
// 3x2 offset by one row
|
|
pixel_x = -32
|
|
pixel_y = -32
|
|
bound_height = 64
|
|
bound_width = 96
|
|
bound_x = -32
|
|
bound_y = 0
|
|
density = TRUE
|
|
|
|
active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 5
|
|
|
|
var/calibrated = TRUE
|
|
/// Type of instanced gateway destination, needs to be subtype of /datum/gateway_destination/gateway
|
|
var/destination_type = /datum/gateway_destination/gateway
|
|
/// Name of the generated destination
|
|
var/destination_name = "Unknown Gateway"
|
|
/// This is our own destination, pointing at this gateway
|
|
var/datum/gateway_destination/gateway/destination
|
|
/// This is current active destination
|
|
var/datum/gateway_destination/target
|
|
/// bumper object, the thing that starts actual teleport
|
|
var/obj/effect/gateway_portal_bumper/portal
|
|
/// Visual object for handling the viscontents
|
|
var/atom/movable/screen/map_view/gateway_port/portal_visuals
|
|
var/teleportion_possible = FALSE
|
|
var/transport_active = FALSE
|
|
|
|
//SKYRAT EDIT ADDITION
|
|
var/requires_key = FALSE
|
|
var/key_used = FALSE
|
|
|
|
/obj/machinery/gateway/attacked_by(obj/item/I, mob/living/user)
|
|
. = ..()
|
|
if(istype(I, /obj/item/key/gateway) && requires_key)
|
|
to_chat(user, "<span class='notice'>You insert [src] into the keyway, unlocking the gateway!</span>")
|
|
key_used = TRUE
|
|
qdel(I)
|
|
return
|
|
//SKYRAT EDIT END
|
|
|
|
/obj/machinery/gateway/Initialize(mapload)
|
|
generate_destination()
|
|
update_appearance()
|
|
portal_visuals = new
|
|
portal_visuals.generate_view("gateway_popup_[REF(src)]")
|
|
portal_visuals.update_portal_filters()
|
|
return ..()
|
|
|
|
/obj/machinery/gateway/Destroy()
|
|
QDEL_NULL(portal_visuals)
|
|
destination.target_gateway = null
|
|
GLOB.gateway_destinations -= destination
|
|
destination = null
|
|
return ..()
|
|
|
|
/obj/machinery/gateway/proc/generate_destination()
|
|
destination = new destination_type
|
|
destination.name = destination_name
|
|
destination.target_gateway = src
|
|
GLOB.gateway_destinations += destination
|
|
|
|
/obj/machinery/gateway/proc/deactivate()
|
|
var/datum/gateway_destination/dest = target
|
|
target = null
|
|
playsound(src, 'sound/machines/gateway/gateway_close.ogg', 140, TRUE, TRUE, SOUND_RANGE)
|
|
dest.deactivate(src)
|
|
QDEL_NULL(portal)
|
|
update_use_power(IDLE_POWER_USE)
|
|
transport_active = FALSE
|
|
update_appearance()
|
|
portal_visuals.reset_visuals()
|
|
|
|
/obj/machinery/gateway/process()
|
|
if((machine_stat & (NOPOWER)) && use_power)
|
|
teleportion_possible = FALSE
|
|
if(target)
|
|
deactivate()
|
|
return
|
|
if(teleportion_possible)
|
|
return
|
|
for(var/datum/gateway_destination/possible_destination as anything in GLOB.gateway_destinations)
|
|
if(!valid_destination(possible_destination) || !possible_destination.is_available())
|
|
continue
|
|
teleportion_possible = TRUE
|
|
update_appearance()
|
|
break
|
|
|
|
/obj/machinery/gateway/proc/valid_destination(datum/gateway_destination/possible_destination)
|
|
if(possible_destination == destination)
|
|
return FALSE
|
|
if(istype(possible_destination, /datum/gateway_destination/gateway))
|
|
var/datum/gateway_destination/gateway/gateway_dest = possible_destination
|
|
if(gateway_dest.target_gateway == src)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/machinery/gateway/proc/show_light_overlays(light_state, toggle)
|
|
if(!toggle)
|
|
return list()
|
|
|
|
var/list/image/to_animate = list()
|
|
to_animate += image('icons/obj/machines/gateway.dmi', light_state)
|
|
var/image/glowing_light = image('icons/obj/machines/gateway.dmi', light_state)
|
|
glowing_light.color = GLOB.emissive_color
|
|
SET_PLANE_EXPLICIT(glowing_light, EMISSIVE_PLANE, src)
|
|
to_animate += glowing_light
|
|
return to_animate
|
|
|
|
/obj/machinery/gateway/update_overlays()
|
|
. = ..()
|
|
. += show_light_overlays("portal_light", teleportion_possible)
|
|
. += show_light_overlays("portal_effect", transport_active)
|
|
|
|
/obj/machinery/gateway/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE)
|
|
return
|
|
|
|
/obj/machinery/gateway/proc/generate_bumper()
|
|
portal = new(get_turf(src))
|
|
portal.gateway = src
|
|
|
|
/obj/machinery/gateway/proc/activate(datum/gateway_destination/D)
|
|
if(!powered() || target)
|
|
return
|
|
//SKYRAT EDIT ADDITION
|
|
if(requires_key && !key_used)
|
|
return
|
|
//SKYRAT EDIT END
|
|
target = D
|
|
target.activate(destination)
|
|
portal_visuals.setup_visuals(target)
|
|
transport_active = TRUE
|
|
playsound(src, 'sound/machines/gateway/gateway_open.ogg', 140, TRUE, TRUE, SOUND_RANGE)
|
|
generate_bumper()
|
|
update_use_power(ACTIVE_POWER_USE)
|
|
update_appearance()
|
|
|
|
/obj/machinery/gateway/proc/Transfer(atom/movable/AM)
|
|
if(!target || !target.incoming_pass_check(AM))
|
|
return
|
|
AM.forceMove(target.get_target_turf())
|
|
target.post_transfer(AM)
|
|
|
|
/obj/machinery/gateway/attack_ghost(mob/user)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
var/turf/tar_turf = target?.get_target_turf()
|
|
if(isnull(tar_turf))
|
|
to_chat(user, span_warning("There's no active destination for the gateway... or it's broken. Maybe try again later?"))
|
|
return
|
|
if(is_secret_level(tar_turf.z) && !user.client?.holder)
|
|
to_chat(user, span_warning("The gateway destination is secret."))
|
|
return
|
|
Transfer(user)
|
|
|
|
/* Station's primary gateway */
|
|
/obj/machinery/gateway/centerstation
|
|
destination_type = /datum/gateway_destination/gateway/home
|
|
destination_name = "Home Gateway"
|
|
|
|
/obj/machinery/gateway/centerstation/Initialize(mapload)
|
|
. = ..()
|
|
if(!GLOB.the_gateway)
|
|
GLOB.the_gateway = src
|
|
|
|
/obj/machinery/gateway/centerstation/Destroy()
|
|
if(GLOB.the_gateway == src)
|
|
GLOB.the_gateway = null
|
|
return ..()
|
|
|
|
/obj/machinery/gateway/multitool_act(mob/living/user, obj/item/I)
|
|
if(calibrated)
|
|
to_chat(user, span_alert("The gate is already calibrated, there is no work for you to do here."))
|
|
else
|
|
playsound(src, 'sound/machines/gateway/gateway_calibrated.ogg', 80, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
|
to_chat(user, "[span_boldnotice("Recalibration successful!")]: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.")
|
|
calibrated = TRUE
|
|
return TRUE
|
|
|
|
/* Doesn't need control console or power, always links to home when interacting. */
|
|
/obj/machinery/gateway/away
|
|
density = TRUE
|
|
use_power = NO_POWER_USE
|
|
|
|
/obj/machinery/gateway/away/interact(mob/user)
|
|
. = ..()
|
|
if(!target)
|
|
if(!GLOB.the_gateway)
|
|
to_chat(user,span_warning("Home gateway is not responding!"))
|
|
if(GLOB.the_gateway.target)
|
|
GLOB.the_gateway.deactivate() //this will turn the home gateway off so that it's free for us to connect to
|
|
activate(GLOB.the_gateway.destination)
|
|
else
|
|
deactivate()
|
|
|
|
/* Gateway control computer */
|
|
/obj/machinery/computer/gateway_control
|
|
name = "Gateway Control"
|
|
desc = "Human friendly interface to the mysterious gate next to it."
|
|
var/obj/machinery/gateway/G
|
|
|
|
/obj/machinery/computer/gateway_control/Initialize(mapload, obj/item/circuitboard/C)
|
|
. = ..()
|
|
try_to_linkup()
|
|
|
|
/obj/machinery/computer/gateway_control/ui_interact(mob/user, datum/tgui/ui)
|
|
. = ..()
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
G.portal_visuals.display_to(user)
|
|
ui = new(user, src, "Gateway", name)
|
|
ui.open()
|
|
|
|
/obj/machinery/computer/gateway_control/ui_data(mob/user)
|
|
. = ..()
|
|
.["gateway_present"] = G
|
|
.["gateway_status"] = G ? G.powered() : FALSE
|
|
.["current_target"] = G?.target?.get_ui_data()
|
|
.["gateway_mapkey"] = G.portal_visuals.assigned_map
|
|
var/list/destinations = list()
|
|
if(G)
|
|
for(var/datum/gateway_destination/possible_destination in GLOB.gateway_destinations)
|
|
if(!G.valid_destination(possible_destination))
|
|
continue
|
|
destinations += list(possible_destination.get_ui_data())
|
|
.["destinations"] = destinations
|
|
|
|
/obj/machinery/computer/gateway_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
switch(action)
|
|
if("linkup")
|
|
try_to_linkup()
|
|
return TRUE
|
|
if("activate")
|
|
//SKYRAT EDIT ADDITION BEGIN
|
|
if(ishuman(usr))
|
|
var/mob/living/carbon/human/interacting_human = usr
|
|
if(!allowed(interacting_human))
|
|
to_chat(interacting_human, "<span class='notice'>Error, you do not have the required access to link up the gateway.</span>")
|
|
return FALSE
|
|
//SKYRAT EDIT END
|
|
var/datum/gateway_destination/D = locate(params["destination"]) in GLOB.gateway_destinations
|
|
try_to_connect(D)
|
|
return TRUE
|
|
if("deactivate")
|
|
if(G?.target)
|
|
G.deactivate()
|
|
return TRUE
|
|
|
|
/obj/machinery/computer/gateway_control/ui_close(mob/user)
|
|
. = ..()
|
|
G.portal_visuals.hide_from(user)
|
|
|
|
/obj/machinery/computer/gateway_control/proc/try_to_linkup()
|
|
G = locate(/obj/machinery/gateway) in view(7,get_turf(src))
|
|
|
|
/obj/machinery/computer/gateway_control/proc/try_to_connect(datum/gateway_destination/D)
|
|
if(!D || !G)
|
|
return
|
|
if(!D.is_available() || G.target)
|
|
return
|
|
G.activate(D)
|
|
|
|
/obj/item/paper/fluff/gateway
|
|
default_raw_text = "Congratulations,<br><br>Your station has been selected to carry out the Gateway Project.<br><br>The equipment will be shipped to you at the start of the next quarter.<br> You are to prepare a secure location to house the equipment as outlined in the attached documents.<br><br>--Nanotrasen Bluespace Research"
|
|
name = "Confidential Correspondence, Pg 1"
|
|
|
|
/atom/movable/screen/map_view/gateway_port
|
|
var/datum/gateway_destination/our_destination
|
|
/// Handles the background of the portal, ensures the effect well, works properly
|
|
var/atom/movable/screen/background/cam_background
|
|
|
|
/atom/movable/screen/map_view/gateway_port/Initialize(mapload, datum/hud/hud_owner)
|
|
. = ..()
|
|
cam_background = new
|
|
cam_background.del_on_map_removal = FALSE
|
|
// Draw above everything
|
|
cam_background.layer = 200
|
|
cam_background.plane = HIGHEST_EVER_PLANE
|
|
cam_background.blend_mode = BLEND_OVERLAY
|
|
|
|
|
|
/atom/movable/screen/map_view/gateway_port/generate_view(map_key)
|
|
. = ..()
|
|
cam_background.assigned_map = assigned_map
|
|
cam_background.fill_rect(1, 1, 3, 3)
|
|
|
|
/atom/movable/screen/map_view/gateway_port/Destroy()
|
|
QDEL_NULL(cam_background)
|
|
return ..()
|
|
|
|
/atom/movable/screen/map_view/gateway_port/display_to(mob/show_to)
|
|
. = ..()
|
|
show_to.client.register_map_obj(cam_background)
|
|
|
|
/atom/movable/screen/map_view/gateway_port/proc/setup_visuals(datum/gateway_destination/D)
|
|
our_destination = D
|
|
update_portal_filters()
|
|
|
|
/atom/movable/screen/map_view/gateway_port/proc/reset_visuals()
|
|
our_destination = null
|
|
update_portal_filters()
|
|
|
|
/atom/movable/screen/map_view/gateway_port/proc/update_portal_filters()
|
|
cam_background.clear_filters()
|
|
// ok so what this used to do was render the tiles "on the other side" of the gateway onto the gateway mask
|
|
// Unfortunately since I've removed the plane inheriting from /atom vis_flags, this no longer works
|
|
// You could setup gateways to draw onto "lower then everything" z layers, but generating a whole stack of plane masters
|
|
// Just for this one effect is kinda silly. Maybe next time
|
|
// Rather then that, let's just render a little preview port to the console, because for reasons that's trivial
|
|
vis_contents = null
|
|
|
|
var/turf/center_turf = our_destination?.get_target_turf()
|
|
if(!center_turf)
|
|
// Draw static
|
|
cam_background.icon_state = "scanline2"
|
|
cam_background.color = null
|
|
cam_background.alpha = 255
|
|
return
|
|
|
|
cam_background.add_filter("portal_blur", 1, list("type" = "blur", "size" = 0.5))
|
|
|
|
vis_contents += TURF_NEIGHBORS(center_turf)
|
|
cam_background.icon_state = "scanline4"
|
|
cam_background.color = "#adadff"
|
|
cam_background.alpha = 128
|