Landmark Shuttles (#8512)

The lifeless live again. Or in this case, what never actually lived here.

Ports Baystation12/Baystation12#17460 probably for real this time. What this allows us to do is create shuttles on runtime and make shuttles easier by just making landmarks and a shuttle instead of areas and shuttles. Also allows runtime landmark creation via flares or whatever AND allows shuttles to use different landmarks at will.

I removed most of the overmap stuff, I think. It shouldn't be hard to slam it in whenever we need to.

Changes:

    "Shuttle code has been completely reworked."
    "Shuttles can now be modified to have more than one destination."
    "Shuttles now have a takeoff sound."
    "You can now throw mobs against walls to damage them. A lot."
    "You now need a neckgrab to throw mobs."
    "BEING UNBUCKLED DURING SHUTTLE LAUNCH IS DANGEROUS! Don't do it."
    "Adminghosts can now interact with all shuttles."
This commit is contained in:
Matt Atlas
2020-04-05 21:15:31 +03:00
committed by GitHub
parent cf7fe3eff7
commit 2e5fdf970c
100 changed files with 15780 additions and 16628 deletions
+2 -2
View File
@@ -4,8 +4,8 @@
shuttle_tag = "Skipjack"
light_color = LIGHT_COLOR_RED
/obj/machinery/computer/shuttle_control/multi/syndicate
/obj/machinery/computer/shuttle_control/multi/antag/syndicate
name = "mercenary shuttle control console"
req_access = list(access_syndicate)
shuttle_tag = "Mercenary"
shuttle_tag = "Mercenary Shuttle"
light_color = LIGHT_COLOR_RED
+3 -5
View File
@@ -1,13 +1,11 @@
/obj/machinery/computer/shuttle_control/mining
name = "mining shuttle control console"
shuttle_tag = "Mining"
//req_access = list(access_mining)
circuit = /obj/item/circuitboard/mining_shuttle
/obj/machinery/computer/shuttle_control/engineering
name = "engineering shuttle control console"
shuttle_tag = "Engineering"
//req_one_access = list(access_engine_equip,access_atmospherics)
circuit = /obj/item/circuitboard/engineering_shuttle
/obj/machinery/computer/shuttle_control/research
@@ -16,10 +14,10 @@
req_access = list(access_research)
circuit = /obj/item/circuitboard/research_shuttle
/datum/shuttle/ferry/research
/datum/shuttle/autodock/ferry/research
var/triggered_away_sites = FALSE
/datum/shuttle/ferry/research/launch()
/datum/shuttle/autodock/ferry/research/shuttle_moved()
. = ..()
if(!triggered_away_sites)
for(var/s in SSghostroles.spawners)
@@ -31,4 +29,4 @@
/obj/machinery/computer/shuttle_control/merchant
name = "merchant shuttle control console"
req_access = list(access_merchant)
shuttle_tag = "Merchant"
shuttle_tag = "Merchant Shuttle"
+20 -15
View File
@@ -1,39 +1,44 @@
/datum/shuttle/ferry/escape_pod
var/list/escape_pods = list()
/datum/shuttle/autodock/ferry/escape_pod
var/datum/computer/file/embedded_program/docking/simple/escape_pod/arming_controller
category = /datum/shuttle/autodock/ferry/escape_pod
move_time = 100
/datum/shuttle/ferry/escape_pod/init_docking_controllers()
/datum/shuttle/autodock/ferry/escape_pod/New()
..()
arming_controller = locate(dock_target_station)
var/arming_controller_tag = arming_controller
arming_controller = SSshuttle.docking_registry[arming_controller_tag]
if(!istype(arming_controller))
to_world("<span class='danger'>warning: escape pod with station dock tag [dock_target_station] could not find it's dock target!</span>")
CRASH("Could not find arming controller for escape pod \"[name]\", tag was '[arming_controller_tag]'.")
if(docking_controller)
var/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/controller_master = docking_controller.master
if(!istype(controller_master))
to_world("<span class='danger'>warning: escape pod with docking tag [docking_controller_tag] could not find it's controller master!</span>")
else
controller_master.pod = src
escape_pods += src
if(dock_target)
var/datum/computer/file/embedded_program/docking/simple/own_target = SSshuttle.docking_registry[dock_target]
if(own_target)
var/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/own_target_master = own_target.master
if(own_target_master)
own_target_master.pod = src
/datum/shuttle/ferry/escape_pod/can_launch()
/datum/shuttle/autodock/ferry/escape_pod/can_launch()
if(arming_controller && !arming_controller.armed) //must be armed
return 0
if(location)
return 0 //it's a one-way trip.
return ..()
/datum/shuttle/ferry/escape_pod/can_force()
/datum/shuttle/autodock/ferry/escape_pod/can_force()
if (arming_controller.eject_time && world.time < arming_controller.eject_time + 50)
return 0 //dont allow force launching until 5 seconds after the arming controller has reached it's countdown
return ..()
/datum/shuttle/ferry/escape_pod/can_cancel()
/datum/shuttle/autodock/ferry/escape_pod/can_cancel()
return 0
//This controller goes on the escape pod itself
/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod
name = "escape pod controller"
var/datum/shuttle/ferry/escape_pod/pod
var/datum/shuttle/autodock/ferry/escape_pod/pod
/obj/machinery/embedded_controller/radio/simple_docking_controller/escape_pod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
+135
View File
@@ -0,0 +1,135 @@
//making this separate from /obj/effect/landmark until that mess can be dealt with
/obj/effect/shuttle_landmark
name = "Nav Point"
icon = 'icons/effects/effects.dmi'
icon_state = "energynet"
anchored = TRUE
unacidable = TRUE
simulated = 0
invisibility = 101
var/landmark_tag
//ID of the controller on the dock side
var/datum/computer/file/embedded_program/docking/docking_controller
//ID of controller used for this landmark for shuttles with multiple ones.
var/list/special_dock_targets
//when the shuttle leaves this landmark, it will leave behind the base area
//also used to determine if the shuttle can arrive here without obstruction
var/area/base_area
//Will also leave this type of turf behind if set.
var/turf/base_turf
//Name of the shuttle, null for generic waypoint
var/shuttle_restricted
var/landmark_flags = 0
/obj/effect/shuttle_landmark/Initialize()
. = ..()
if(docking_controller)
. = INITIALIZE_HINT_LATELOAD
if(landmark_flags & SLANDMARK_FLAG_AUTOSET)
base_area = get_area(src)
var/turf/T = get_turf(src)
if(T)
base_turf = T.type
else
base_area = locate(base_area || world.area)
name = name + " ([x],[y])"
SSshuttle.register_landmark(landmark_tag, src)
/obj/effect/shuttle_landmark/LateInitialize()
if(!docking_controller)
return
var/docking_tag = docking_controller
docking_controller = SSshuttle.docking_registry[docking_tag]
if(!istype(docking_controller))
log_debug("Could not find docking controller for shuttle waypoint '[name]', docking tag was '[docking_tag]'.")
/obj/effect/shuttle_landmark/proc/is_valid(var/datum/shuttle/shuttle)
if(shuttle.current_location == src)
return FALSE
for(var/area/A in shuttle.shuttle_area)
var/list/translation = get_turf_translation(get_turf(shuttle.current_location), get_turf(src), A.contents)
if(check_collision(base_area, list_values(translation)))
return FALSE
var/conn = GetConnectedZlevels(z)
for(var/w in (z - shuttle.multiz) to z)
if(!(w in conn))
return FALSE
return TRUE
/obj/effect/shuttle_landmark/proc/cannot_depart(datum/shuttle/shuttle)
return FALSE
/obj/effect/shuttle_landmark/proc/shuttle_arrived(datum/shuttle/shuttle)
return
/proc/check_collision(area/target_area, list/target_turfs)
for(var/target_turf in target_turfs)
var/turf/target = target_turf
if(!target)
return TRUE //collides with edge of map
if(target.loc != target_area)
return TRUE //collides with another area
if(target.density)
return TRUE //dense turf
return FALSE
//Self-naming/numbering ones.
/obj/effect/shuttle_landmark/automatic
name = "Navpoint"
landmark_tag = "navpoint"
flags = SLANDMARK_FLAG_AUTOSET
/obj/effect/shuttle_landmark/automatic/Initialize()
landmark_tag += "-[x]-[y]-[z]"
return ..()
//Subtype that calls explosion on init to clear space for shuttles
/obj/effect/shuttle_landmark/automatic/clearing
var/radius = 10
/obj/effect/shuttle_landmark/automatic/clearing/Initialize()
..()
return INITIALIZE_HINT_LATELOAD
/obj/effect/shuttle_landmark/automatic/clearing/LateInitialize()
..()
for(var/turf/T in range(radius, src))
if(T.density)
T.ChangeTurf(get_base_turf_by_area(T))
/obj/item/device/spaceflare
name = "bluespace flare"
desc = "Burst transmitter used to broadcast all needed information for shuttle navigation systems. Has a flare attached for marking the spot where you probably shouldn't be standing."
icon_state = "bluflare"
light_color = "#3728ff"
var/active
/obj/item/device/spaceflare/attack_self(var/mob/user)
if(!active)
visible_message("<span class='notice'>[user] pulls the cord, activating \the [src].</span>")
activate()
/obj/item/device/spaceflare/proc/activate()
if(active)
return
var/turf/T = get_turf(src)
var/mob/M = loc
if(istype(M) && !M.unEquip(src, T))
return
active = 1
anchored = 1
var/obj/effect/shuttle_landmark/automatic/mark = new(T)
mark.name = "beacon signal ([T.x],[T.y])"
T.hotspot_expose(1500, 5)
update_icon()
/obj/item/device/spaceflare/update_icon()
if(active)
icon_state = "bluflare_on"
set_light(0.3, 0.1, 6, 2, "85d1ff")
+191 -115
View File
@@ -1,161 +1,237 @@
#define DO_BOOT 1
#define DO_BUCKLE 2
//These lists are populated in /datum/shuttle_controller/New()
//Shuttle controller is instantiated in master_controller.dm.
//shuttle moving state defines are in setup.dm
/datum/shuttle
var/name = ""
var/warmup_time = 0
var/moving_status = SHUTTLE_IDLE
var/lift = 0 //To make zlevel stuff work right
var/lift_lowest_zlevel = 1 //At least 1 unless you always want open floor
var/docking_controller_tag //tag of the controller used to coordinate docking
var/datum/computer/file/embedded_program/docking/docking_controller //the controller itself. (micro-controller, not game controller)
var/list/shuttle_area //can be both single area type or a list of areas
var/obj/effect/shuttle_landmark/current_location //This variable is type-abused initially: specify the landmark_tag, not the actual landmark.
var/arrive_time = 0 //the time at which the shuttle arrives when long jumping
var/flags = 0
var/process_state = IDLE_STATE //Used with SHUTTLE_FLAGS_PROCESS, as well as to store current state.
var/category = /datum/shuttle
var/multiz = 0 //how many multiz levels, starts at 0
/datum/shuttle/proc/init_docking_controllers()
if(docking_controller_tag)
docking_controller = locate(docking_controller_tag)
if(!istype(docking_controller))
to_world("<span class='danger'>warning: shuttle with docking tag [docking_controller_tag] could not find it's controller!</span>")
var/ceiling_type = /turf/simulated/shuttle_roof
/datum/shuttle/proc/short_jump(var/area/origin,var/area/destination)
var/sound_takeoff = 'sound/effects/shuttle_takeoff.ogg'
var/sound_landing = 'sound/effects/shuttle_landing.ogg'
var/knockdown = TRUE //whether shuttle downs non-buckled people when it moves
var/defer_initialisation = FALSE //this shuttle will/won't be initialised automatically. If set to true, you are responsible for initialzing the shuttle manually.
//Useful for shuttles that are initialed by map_template loading, or shuttles that are created in-game or not used.
var/logging_home_tag //Whether in-game logs will be generated whenever the shuttle leaves/returns to the landmark with this landmark_tag.
var/logging_access //Controls who has write access to log-related stuff; should correlate with pilot access.
/datum/shuttle/New(_name, var/obj/effect/shuttle_landmark/initial_location)
..()
if(_name)
src.name = _name
var/list/areas = list()
if(!islist(shuttle_area))
shuttle_area = list(shuttle_area)
for(var/T in shuttle_area)
var/area/A = locate(T)
if(!istype(A))
CRASH("Shuttle \"[name]\" couldn't locate area [T].")
areas += A
shuttle_area = areas
if(initial_location)
current_location = initial_location
else
current_location = SSshuttle.get_landmark(current_location)
if(!istype(current_location))
CRASH("Shuttle \"[name]\" could not find its starting location.")
if(src.name in SSshuttle.shuttles)
CRASH("A shuttle with the name '[name]' is already defined.")
SSshuttle.shuttles[src.name] = src
if(flags & SHUTTLE_FLAGS_PROCESS)
SSshuttle.process_shuttles += src
if(flags & SHUTTLE_FLAGS_SUPPLY)
if(SScargo.shuttle)
CRASH("A supply shuttle is already defined.")
SScargo.shuttle = src
/datum/shuttle/Destroy()
current_location = null
SSshuttle.shuttles -= src.name
SSshuttle.process_shuttles -= src
if(SScargo.shuttle == src)
SScargo.shuttle = null
. = ..()
/datum/shuttle/proc/short_jump(var/obj/effect/shuttle_landmark/destination)
if(moving_status != SHUTTLE_IDLE) return
//it would be cool to play a sound here
moving_status = SHUTTLE_WARMUP
if(sound_takeoff)
playsound(current_location, sound_takeoff, 50, 20, is_global = TRUE)
spawn(warmup_time*10)
if (moving_status == SHUTTLE_IDLE)
return //someone cancelled the launch
if(moving_status == SHUTTLE_IDLE)
return FALSE //someone cancelled the launch
callHook("shuttle_moved", list(origin,destination))
if(!fuel_check()) //fuel error (probably out of fuel) occured, so cancel the launch
var/datum/shuttle/autodock/S = src
if(istype(S))
S.cancel_launch(null)
return
moving_status = SHUTTLE_INTRANSIT //shouldn't matter but just to be safe
move(origin, destination)
attempt_move(destination)
moving_status = SHUTTLE_IDLE
/datum/shuttle/proc/long_jump(var/area/departing, var/area/destination, var/area/interim, var/travel_time, var/direction)
if(moving_status != SHUTTLE_IDLE) return
/datum/shuttle/proc/long_jump(var/obj/effect/shuttle_landmark/destination, var/obj/effect/shuttle_landmark/interim, var/travel_time)
if(moving_status != SHUTTLE_IDLE)
return
var/obj/effect/shuttle_landmark/start_location = current_location
//it would be cool to play a sound here
moving_status = SHUTTLE_WARMUP
if(sound_takeoff)
playsound(current_location, sound_takeoff, 100, 20, is_global = TRUE)
spawn(warmup_time*10)
if (moving_status == SHUTTLE_IDLE)
if(moving_status == SHUTTLE_IDLE)
return //someone cancelled the launch
callHook("shuttle_moved", list(departing,destination))
if(!fuel_check()) //fuel error (probably out of fuel) occured, so cancel the launch
var/datum/shuttle/autodock/S = src
if(istype(S))
S.cancel_launch(null)
return
arrive_time = world.time + travel_time*10
moving_status = SHUTTLE_INTRANSIT
move(departing, interim, direction)
if(attempt_move(interim))
var/fwooshed = 0
while (world.time < arrive_time)
if(!fwooshed && (arrive_time - world.time) < 100)
fwooshed = 1
playsound(destination, sound_landing, 100, 20, is_global = TRUE)
sleep(5)
if(!attempt_move(destination))
attempt_move(start_location) //try to go back to where we started. If that fails, I guess we're stuck in the interim location
while (world.time < arrive_time)
sleep(5)
move(interim, destination, direction)
moving_status = SHUTTLE_IDLE
/datum/shuttle/proc/dock()
if (!docking_controller)
return
/datum/shuttle/proc/fuel_check()
return 1 //fuel check should always pass in non-overmap shuttles (they have magic engines)
var/dock_target = current_dock_target()
if (!dock_target)
return
/*****************
* Shuttle Moved Handling * (Observer Pattern Implementation: Shuttle Moved)
* Shuttle Pre Move Handling * (Observer Pattern Implementation: Shuttle Pre Move)
*****************/
docking_controller.initiate_docking(dock_target)
/datum/shuttle/proc/attempt_move(var/obj/effect/shuttle_landmark/destination)
if(current_location == destination)
return FALSE
/datum/shuttle/proc/undock()
if (!docking_controller)
return
docking_controller.initiate_undocking()
/datum/shuttle/proc/current_dock_target()
return null
/datum/shuttle/proc/skip_docking_checks()
if (!docking_controller || !current_dock_target())
return 1 //shuttles without docking controllers or at locations without docking ports act like old-style shuttles
return 0
if(!destination.is_valid(src))
return FALSE
if(current_location.cannot_depart(src))
return FALSE
testing("[src] moving to [destination]. Areas are [english_list(shuttle_area)]")
var/list/translation = list()
for(var/area/A in shuttle_area)
testing("Moving [A]")
translation += get_turf_translation(get_turf(current_location), get_turf(destination), A.contents)
shuttle_moved(destination, translation)
destination.shuttle_arrived(src)
return TRUE
//just moves the shuttle from A to B, if it can be moved
//A note to anyone overriding move in a subtype. move() must absolutely not, under any circumstances, fail to move the shuttle.
//If you want to conditionally cancel shuttle launches, that logic must go in short_jump() or long_jump()
/datum/shuttle/proc/move(var/area/origin, var/area/destination)
if(origin == destination)
return
//A note to anyone overriding move in a subtype. shuttle_moved() must absolutely not, under any circumstances, fail to move the shuttle.
//If you want to conditionally cancel shuttle launches, that logic must go in short_jump(), long_jump() or attempt_move()
/datum/shuttle/proc/shuttle_moved(var/obj/effect/shuttle_landmark/destination, var/list/turf_translation)
if(!origin.contents.len || !destination.contents.len)
return
// log_debug("move_shuttle() called for [shuttle_tag] leaving [origin] en route to [destination].")
// log_debug("area_coming_from: [origin]")
// log_debug("destination: [destination]")
if((flags & SHUTTLE_FLAGS_ZERO_G))
var/new_grav = 1
if(destination.landmark_flags & SLANDMARK_FLAG_ZERO_G)
var/area/new_area = get_area(destination)
new_grav = new_area.has_gravity
for(var/area/our_area in shuttle_area)
if(our_area.has_gravity != new_grav)
our_area.gravitychange(new_grav)
if (docking_controller && !docking_controller.undocked())
docking_controller.force_undock()
for(var/turf/src_turf in turf_translation)
var/turf/dst_turf = turf_translation[src_turf]
if(src_turf.is_solid_structure()) //in case someone put a hole in the shuttle and you were lucky enough to be under it
for(var/atom/movable/AM in dst_turf)
if(!AM.simulated)
continue
if(isliving(AM))
var/mob/living/bug = AM
bug.gib()
else
qdel(AM) //it just gets atomized I guess? TODO throw it into space somewhere, prevents people from using shuttles as an atom-smasher
var/list/powernets = list()
for(var/area/A in shuttle_area)
// if there was a zlevel above our origin, erase our ceiling now we're leaving
if(HasAbove(current_location.z))
for(var/turf/TO in A.contents)
var/turf/TA = GetAbove(TO)
if(istype(TA, ceiling_type))
TA.ChangeTurf(get_base_turf_by_area(TA), 1, 1)
if(knockdown)
for(var/mob/M in A)
spawn(0)
if(istype(M, /mob/living/carbon))
if(M.buckled)
to_chat(M, "<span class='warning'>Sudden acceleration presses you into your chair!</span>")
shake_camera(M, 3, 1)
else
to_chat(M, "<span class='warning'>The floor lurches beneath you!</span>")
shake_camera(M, 10, 1)
M.visible_message("<span class='warning'>[M.name] is tossed around by the sudden acceleration!</span>")
M.throw_at_random(FALSE, 4, 1)
var/list/dstturfs = list()
var/throwy = world.maxy
for(var/obj/structure/cable/C in A)
powernets |= C.powernet
for(var/turf/T in destination)
dstturfs += T
if(T.y < throwy)
throwy = T.y
translate_turfs(turf_translation, current_location.base_area, current_location.base_turf)
current_location = destination
for(var/turf/T in dstturfs)
var/turf/D = locate(T.x, throwy - 1, 1)
for(var/atom/movable/AM as mob|obj in T)
AM.Move(D)
if(istype(T, /turf/simulated))
T.ChangeTurf(/turf/space)
// if there's a zlevel above our destination, paint in a ceiling on it so we retain our air
if(HasAbove(current_location.z))
for(var/area/A in shuttle_area)
for(var/turf/TD in A.contents)
var/turf/TA = GetAbove(TD)
if(istype(TA, get_base_turf_by_area(TA)) || istype(TA, /turf/simulated/open))
if(get_area(TA) in shuttle_area)
continue
TA.ChangeTurf(ceiling_type, TRUE, TRUE, TRUE)
for(var/mob/living/carbon/bug in destination)
bug.gib()
for(var/mob/living/simple_animal/pest in destination)
pest.gib()
origin.move_contents_to(destination)
for(var/mob/M in destination)
var/effect = FALSE
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(istype(H.shoes, /obj/item/clothing/shoes/magboots))
var/obj/item/clothing/shoes/magboots/boots = H.shoes
if(boots.magpulse)
effect = DO_BOOT
if(!effect)
if(M.buckled)
effect = DO_BUCKLE
if(effect == DO_BOOT)
magboot_effect(M)
else if(effect == DO_BUCKLE)
buckled_effect(M)
else // If they have neither of the former, then it'll always be loose (at the time of writing this, oh god)
loose_effect(M)
/datum/shuttle/proc/magboot_effect(mob/M)
to_chat(M, span("warning","You manage to maintain your footing with the magboots!"))
shake_camera(M, 5, 1)
/datum/shuttle/proc/buckled_effect(mob/M)
to_chat(M, span("warning","Sudden acceleration presses you into your chair!"))
shake_camera(M, 3, 1)
/datum/shuttle/proc/loose_effect(mob/M)
to_chat(M, span("warning","You lose your footing as the floor lurches beneath you!"))
shake_camera(M, 10, 1)
M.Weaken(3)
// Remove all powernets that were affected, and rebuild them.
var/list/cables = list()
for(var/datum/powernet/P in powernets)
cables |= P.cables
qdel(P)
for(var/obj/structure/cable/C in cables)
if(!C.powernet)
var/datum/powernet/NewPN = new()
NewPN.add_cable(C)
propagate_network(C,C.powernet)
//returns 1 if the shuttle has a valid arrive time
/datum/shuttle/proc/has_arrive_time()
return (moving_status == SHUTTLE_INTRANSIT)
#undef DO_BOOT
#undef DO_BUCKLE
/datum/shuttle/autodock/proc/get_location_name()
if(moving_status == SHUTTLE_INTRANSIT)
return "In transit"
return current_location.name
/datum/shuttle/autodock/proc/get_destination_name()
if(!next_location)
return "None"
return next_location.name
+25 -41
View File
@@ -1,34 +1,26 @@
/datum/shuttle/ferry/arrival
/datum/shuttle/autodock/ferry/arrival
category = /datum/shuttle/autodock/ferry/arrival
/datum/shuttle/ferry/arrival/long_jump(var/area/departing, var/area/destination, var/area/interim, var/travel_time, var/direction)
if(isnull(location))
return
/datum/shuttle/autodock/ferry/arrival/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint)
..(_name, start_waypoint)
SSarrivals.shuttle = src
if(!destination)
destination = get_location_area(!location)
if(!departing)
departing = get_location_area(location)
/datum/shuttle/autodock/ferry/arrival/proc/try_jump()
spawn(warmup_time * 10)
if(moving_status != SHUTTLE_IDLE) //The shuttle's already been launched.
return FALSE
direction = !location
if(moving_status != SHUTTLE_IDLE) return
//it would be cool to play a sound here
moving_status = SHUTTLE_WARMUP
spawn(warmup_time*10)
if (moving_status == SHUTTLE_IDLE)
return //someone cancelled the launch
if (at_station() && forbidden_atoms_check())
if(at_station() && forbidden_atoms_check())
//cancel the launch because of forbidden atoms
moving_status = SHUTTLE_IDLE
global_announcer.autosay("Unacceptable items detected aboard the arrivals shuttle. Launch attempt failed. Restarting launch in one minute.", "Arrivals Shuttle Oversight")
global_announcer.autosay("Unacceptable items or lifeforms detected aboard the arrivals shuttle. Launch attempt aborted. Reattempting launch in one minute.", "Arrivals Shuttle Oversight")
SSarrivals.set_launch_countdown(60)
SSarrivals.failreturnnumber++
if(SSarrivals.failreturnnumber >= 2) // get off my shuttle fool
var/list/mobstoyellat = mobs_in_area(get_location_area(location))
var/list/mobstoyellat = list()
for(var/area/subarea in shuttle_area)
mobs_in_area(subarea)
if (!mobstoyellat || !mobstoyellat.len)
return
return FALSE
for(var/mob/living/A in mobstoyellat)
to_chat(A, "<span class='danger'>You feel as if you shouldn't be on the shuttle.</span>") // give them an angry text
if(!A.client && ishuman(A) && SSarrivals.failreturnnumber >= 3) // well they are SSD and holding up the shuttle so might as well.
@@ -38,38 +30,30 @@
else if(A.client && ishuman(A) && SSarrivals.failreturnnumber >= 3) // they aren't SSD and are holding up the shuttle so we are booting them.
A.forceMove(pick(kickoffsloc))
mobstoyellat -= A
else if(!ishuman(A) && SSarrivals.failreturnnumber >=4 && !A.client) // remove non-player mobs to keep things rolling
else if(!ishuman(A) && SSarrivals.failreturnnumber >= 4 && !A.client) // remove non-player mobs to keep things rolling
qdel(A)
else if(issilicon(A.loc) && isMMI(A))
mobstoyellat -= A
if (mobstoyellat)
global_announcer.autosay("Current life-forms on shuttle: [english_list(mobstoyellat)].", "Arrivals Shuttle Oversight") // tell on them
return
return FALSE
if (!forbidden_atoms_check() && !at_station())
//cancel the launch because of there's no one on the shuttle.
moving_status = SHUTTLE_IDLE
return
return FALSE
if(!at_station())
global_announcer.autosay("Central Command Arrivals shuttle inbound to [station_name()]. ETA: one minute.", "Arrivals Shuttle Oversight")
SSarrivals.failreturnnumber = 0
arrive_time = world.time + travel_time*10
moving_status = SHUTTLE_INTRANSIT
move(departing, interim, direction)
launch(SSarrivals)
while (world.time < arrive_time)
sleep(5)
move(interim, destination, direction)
moving_status = SHUTTLE_IDLE
/datum/shuttle/ferry/arrival/arrived()
/datum/shuttle/autodock/ferry/arrival/arrived()
SSarrivals.shuttle_arrived()
/datum/shuttle/ferry/arrival/proc/forbidden_atoms_check()
return SSarrivals.forbidden_atoms_check(get_location_area())
/datum/shuttle/autodock/ferry/arrival/proc/forbidden_atoms_check()
for(var/area/subarea in shuttle_area)
if(SSarrivals.forbidden_atoms_check(subarea))
return TRUE
/datum/shuttle/ferry/arrival/proc/at_station()
/datum/shuttle/autodock/ferry/arrival/proc/at_station()
return (!location)
+181
View File
@@ -0,0 +1,181 @@
#define DOCK_ATTEMPT_TIMEOUT 200 //how long in ticks we wait before assuming the docking controller is broken or blown up.
/datum/shuttle/autodock
var/in_use = null //tells the controller whether this shuttle needs processing, also attempts to prevent double-use
var/last_dock_attempt_time = 0
var/current_dock_target
//ID of the controller on the shuttle
var/dock_target = null
var/obj/effect/shuttle_landmark/next_location
var/datum/computer/file/embedded_program/docking/active_docking_controller
var/obj/effect/shuttle_landmark/landmark_transition
var/move_time = 240 //the time spent in the transition area
category = /datum/shuttle/autodock
flags = SHUTTLE_FLAGS_PROCESS | SHUTTLE_FLAGS_ZERO_G
/datum/shuttle/autodock/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint)
..(_name, start_waypoint)
//Initial dock
update_docking_target(current_location)
active_docking_controller = current_location.docking_controller
current_dock_target = get_docking_target(current_location)
dock()
//Optional transition area
if(landmark_transition)
landmark_transition = SSshuttle.get_landmark(landmark_transition)
/datum/shuttle/autodock/Destroy()
next_location = null
active_docking_controller = null
landmark_transition = null
return ..()
/datum/shuttle/autodock/shuttle_moved()
force_undock() //bye!
..()
/datum/shuttle/autodock/proc/update_docking_target(var/obj/effect/shuttle_landmark/location)
if(location && location.special_dock_targets && location.special_dock_targets[name])
current_dock_target = location.special_dock_targets[name]
else
current_dock_target = dock_target
active_docking_controller = SSshuttle.docking_registry[current_dock_target]
/datum/shuttle/autodock/proc/get_docking_target(var/obj/effect/shuttle_landmark/location)
if(location && location.special_dock_targets)
if(location.special_dock_targets[name])
return location.special_dock_targets[name]
return dock_target
/*
Docking stuff
*/
/datum/shuttle/autodock/proc/dock()
if(active_docking_controller)
active_docking_controller.initiate_docking(current_dock_target)
last_dock_attempt_time = world.time
/datum/shuttle/autodock/proc/undock()
if(active_docking_controller)
active_docking_controller.initiate_undocking()
/datum/shuttle/autodock/proc/force_undock()
if(active_docking_controller)
active_docking_controller.force_undock()
/datum/shuttle/autodock/proc/check_docked()
if(active_docking_controller)
return active_docking_controller.docked()
return TRUE
/datum/shuttle/autodock/proc/check_undocked()
if(active_docking_controller)
return active_docking_controller.can_launch()
return TRUE
/*
Please ensure that long_jump() and short_jump() are only called from here. This applies to subtypes as well.
Doing so will ensure that multiple jumps cannot be initiated in parallel.
*/
/datum/shuttle/autodock/process()
switch(process_state)
if (WAIT_LAUNCH)
if(check_undocked())
//*** ready to go
if(next_location.is_valid(src))
process_launch()
process_state = WAIT_ARRIVE
else
process_state = IDLE_STATE
in_use = null
if (FORCE_LAUNCH)
process_launch()
if (WAIT_ARRIVE)
if (moving_status == SHUTTLE_IDLE)
//*** we made it to the destination, update stuff
process_arrived()
process_state = WAIT_FINISH
if (WAIT_FINISH)
if (world.time > last_dock_attempt_time + DOCK_ATTEMPT_TIMEOUT || check_docked())
//*** all done here
process_state = IDLE_STATE
arrived()
//not to be confused with the arrived() proc
/datum/shuttle/autodock/proc/process_arrived()
update_docking_target(next_location)
active_docking_controller = next_location.docking_controller
current_dock_target = get_docking_target(next_location)
dock()
next_location = null
in_use = null //release lock
/datum/shuttle/autodock/proc/process_launch()
if (move_time && landmark_transition)
. = long_jump(next_location, landmark_transition, move_time)
else
. = short_jump(next_location)
process_state = WAIT_ARRIVE
/*
Guards
*/
/datum/shuttle/autodock/proc/can_launch()
return (next_location && moving_status == SHUTTLE_IDLE && !in_use)
/datum/shuttle/autodock/proc/can_force()
return (next_location && moving_status == SHUTTLE_IDLE && process_state == WAIT_LAUNCH)
/datum/shuttle/autodock/proc/can_cancel()
return (moving_status == SHUTTLE_WARMUP || process_state == WAIT_LAUNCH || process_state == FORCE_LAUNCH)
/*
"Public" procs
*/
/datum/shuttle/autodock/proc/launch(var/user)
if(!can_launch())
return
in_use = user //obtain an exclusive lock on the shuttle
process_state = WAIT_LAUNCH
undock()
/datum/shuttle/autodock/proc/force_launch(var/user)
if(!can_force())
return
in_use = user //obtain an exclusive lock on the shuttle
process_state = FORCE_LAUNCH
/datum/shuttle/autodock/proc/cancel_launch(var/user)
if (!can_cancel()) return
moving_status = SHUTTLE_IDLE
process_state = WAIT_FINISH
in_use = null
//whatever we were doing with docking: stop it, then redock
force_undock()
spawn(1 SECOND)
dock()
//returns 1 if the shuttle is getting ready to move, but is not in transit yet
/datum/shuttle/autodock/proc/is_launching()
return (moving_status == SHUTTLE_WARMUP || process_state == WAIT_LAUNCH || process_state == FORCE_LAUNCH)
//This gets called when the shuttle finishes arriving at it's destination
//This can be used by subtypes to do things when the shuttle arrives.
//Note that this is called when the shuttle leaves the WAIT_FINISHED state, the proc name is a little misleading
/datum/shuttle/autodock/proc/arrived()
return //do nothing for now
+13 -12
View File
@@ -1,17 +1,18 @@
/datum/shuttle/ferry/autoreturn
/datum/shuttle/autodock/ferry/autoreturn
var/auto_return_time = 60 //Time after which the shuttle should return in seconds
category = /datum/shuttle/autodock/ferry/autoreturn
/datum/shuttle/ferry/autoreturn/arrived()
addtimer(CALLBACK(src, .proc/announce_return), 20)
addtimer(CALLBACK(src, .proc/do_return), auto_return_time*10)
/datum/shuttle/autodock/ferry/autoreturn/arrived()
if(waypoint_station == current_location)
addtimer(CALLBACK(src, .proc/announce_return), 20)
addtimer(CALLBACK(src, .proc/do_return), auto_return_time*10)
/datum/shuttle/ferry/autoreturn/proc/announce_return()
/datum/shuttle/autodock/ferry/autoreturn/proc/announce_return()
if(!location)
for(var/turf/T in get_area_turfs(area_station))
var/mob/M = locate(/mob) in T
to_chat(M, span("notice","You have arrived at [current_map.station_name]. The shuttle will return in [auto_return_time] seconds."))
for(var/area/A in shuttle_area)
for(var/mob/M in A)
if(ishuman(M))
to_chat(M, SPAN_NOTICE("You have arrived at the [current_map.station_name]! The shuttle will return in [auto_return_time] seconds. Enjoy your stay!"))
/datum/shuttle/ferry/autoreturn/proc/do_return()
if(!location)
launch(null)
force_launch(null)
/datum/shuttle/autodock/ferry/autoreturn/proc/do_return()
launch(src)
+74 -54
View File
@@ -1,102 +1,122 @@
/obj/machinery/computer/shuttle_control
name = "shuttle control console"
icon = 'icons/obj/computer.dmi'
icon_screen = "explosive"
light_color = LIGHT_COLOR_ORANGE
light_color = LIGHT_COLOR_CYAN
icon_screen = "shuttle"
circuit = null
var/shuttle_tag // Used to coordinate data in shuttle controller.
var/hacked = FALSE // Has been emagged, no access restrictions.
var/shuttle_tag // Used to coordinate data in shuttle controller.
var/hacked = 0 // Has been emagged, no access restrictions.
/obj/machinery/computer/shuttle_control/attack_hand(user as mob)
if(..(user))
return
//src.add_fingerprint(user) //shouldn't need fingerprints just for looking at it.
if(!allowed(user))
to_chat(user, "<span class='warning'>Access Denied.</span>")
return 1
var/ui_template = "shuttle_control_console.tmpl"
/obj/machinery/computer/shuttle_control/attack_hand(mob/user)
ui_interact(user)
/obj/machinery/computer/shuttle_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag]
if (!istype(shuttle))
return
/obj/machinery/computer/shuttle_control/attack_ai(mob/user)
ui_interact(user)
/obj/machinery/computer/shuttle_control/attack_ghost(var/mob/abstract/observer/user)
if(check_rights(R_ADMIN, 0, user))
ui_interact(user)
/obj/machinery/computer/shuttle_control/proc/get_ui_data(var/datum/shuttle/autodock/shuttle)
var/shuttle_state
switch(shuttle.moving_status)
if(SHUTTLE_IDLE) shuttle_state = "idle"
if(SHUTTLE_WARMUP) shuttle_state = "warmup"
if(SHUTTLE_INTRANSIT) shuttle_state = "in_transit"
if(SHUTTLE_HALT) shuttle_state = "halt"
var/shuttle_status
switch (shuttle.process_state)
if(IDLE_STATE)
var/cannot_depart = shuttle.current_location.cannot_depart(shuttle)
if (shuttle.in_use)
shuttle_status = "Busy."
else if (!shuttle.location)
shuttle_status = "Standing-by at station."
else if(cannot_depart)
shuttle_status = cannot_depart
else
shuttle_status = "Standing-by at offsite location."
shuttle_status = "Standing-by at \the [shuttle.get_location_name()]."
if(WAIT_LAUNCH, FORCE_LAUNCH)
shuttle_status = "Shuttle has received command and will depart shortly."
shuttle_status = "Shuttle has recieved command and will depart shortly."
if(WAIT_ARRIVE)
shuttle_status = "Proceeding to destination."
shuttle_status = "Proceeding to \the [shuttle.get_destination_name()]."
if(WAIT_FINISH)
shuttle_status = "Arriving at destination now."
data = list(
return list(
"shuttle_status" = shuttle_status,
"shuttle_state" = shuttle_state,
"has_docking" = shuttle.docking_controller? 1 : 0,
"docking_status" = shuttle.docking_controller? shuttle.docking_controller.get_docking_status() : null,
"docking_override" = shuttle.docking_controller? shuttle.docking_controller.override_enabled : null,
"has_docking" = shuttle.active_docking_controller? 1 : 0,
"docking_status" = shuttle.active_docking_controller? shuttle.active_docking_controller.get_docking_status() : null,
"docking_override" = shuttle.active_docking_controller? shuttle.active_docking_controller.override_enabled : null,
"can_launch" = shuttle.can_launch(),
"can_cancel" = shuttle.can_cancel(),
"can_force" = shuttle.can_force()
"can_force" = shuttle.can_force(),
)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
// This is a subset of the actual checks; contains those that give messages to the user.
/obj/machinery/computer/shuttle_control/proc/can_move(var/datum/shuttle/autodock/shuttle, var/user)
var/cannot_depart = shuttle.current_location.cannot_depart(shuttle)
if(cannot_depart)
to_chat(user, SPAN_WARNING(cannot_depart))
return FALSE
if(!shuttle.next_location.is_valid(shuttle))
to_chat(user, SPAN_WARNING("Destination zone is invalid or obstructed."))
return FALSE
return TRUE
if (!ui)
ui = new(user, src, ui_key, "shuttle_control_console.tmpl", "[shuttle_tag] Shuttle Control", 470, 310)
/obj/machinery/computer/shuttle_control/proc/handle_topic_href(var/datum/shuttle/autodock/shuttle, var/list/href_list, var/user)
if(!istype(shuttle))
return TOPIC_NOACTION
if(href_list["move"])
if(can_move(shuttle, user))
shuttle.launch(src)
return TOPIC_REFRESH
return TOPIC_HANDLED
if(href_list["force"])
if(can_move(shuttle, user))
shuttle.force_launch(src)
return TOPIC_REFRESH
return TOPIC_HANDLED
if(href_list["cancel"])
shuttle.cancel_launch(src)
return TOPIC_REFRESH
/obj/machinery/computer/shuttle_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/datum/shuttle/autodock/shuttle = SSshuttle.shuttles[shuttle_tag]
if (!istype(shuttle))
to_chat(user,"<span class='warning'>Unable to establish link with the shuttle.</span>")
return
var/list/data = get_ui_data(shuttle)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, ui_template, "[shuttle_tag] Shuttle Control", 470, 450)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/shuttle_control/Topic(href, href_list)
if(..())
return 1
/obj/machinery/computer/shuttle_control/Topic(user, href_list)
..()
usr.set_machine(src)
src.add_fingerprint(usr)
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag]
if (!istype(shuttle))
return
if(href_list["move"])
shuttle.launch(src)
if(href_list["force"])
shuttle.force_launch(src)
else if(href_list["cancel"])
shuttle.cancel_launch(src)
handle_topic_href(SSshuttle.shuttles[shuttle_tag], href_list, user)
/obj/machinery/computer/shuttle_control/emag_act(var/remaining_charges, var/mob/user)
if (!hacked)
if(!hacked)
req_access = list()
req_one_access = list()
hacked = 1
hacked = TRUE
to_chat(user, "You short out the console's ID checking system. It's now available to everyone!")
return 1
return TRUE
/obj/machinery/computer/shuttle_control/bullet_act(var/obj/item/projectile/Proj)
visible_message("\The [Proj] ricochets off \the [src]!")
/obj/machinery/computer/shuttle_control/ex_act(var/severity = 2.0)
/obj/machinery/computer/shuttle_control/ex_act()
return
/obj/machinery/computer/shuttle_control/emp_act()
@@ -0,0 +1,36 @@
/obj/machinery/computer/shuttle_control/multi
ui_template = "shuttle_control_console_multi.tmpl"
/obj/machinery/computer/shuttle_control/multi/get_ui_data(var/datum/shuttle/autodock/multi/shuttle)
. = ..()
if(istype(shuttle))
. += list(
"destination_name" = shuttle.next_location? shuttle.next_location.name : "No destination set.",
"can_pick" = shuttle.moving_status == SHUTTLE_IDLE,
)
/obj/machinery/computer/shuttle_control/multi/handle_topic_href(var/datum/shuttle/autodock/multi/shuttle, var/list/href_list)
..()
if(href_list["pick"])
var/dest_key = input("Choose shuttle destination", "Shuttle Destination") as null|anything in shuttle.get_destinations()
if(dest_key && (!use_check(usr) || (isobserver(usr) && check_rights(R_ADMIN, FALSE))))
shuttle.set_destination(dest_key, usr)
return TOPIC_REFRESH
/obj/machinery/computer/shuttle_control/multi/antag
ui_template = "shuttle_control_console_antag.tmpl"
/obj/machinery/computer/shuttle_control/multi/antag/get_ui_data(var/datum/shuttle/autodock/multi/antag/shuttle)
. = ..()
if(istype(shuttle))
. += list(
"cloaked" = shuttle.cloaked,
)
/obj/machinery/computer/shuttle_control/multi/antag/handle_topic_href(var/datum/shuttle/autodock/multi/antag/shuttle, var/list/href_list)
..()
if(href_list["toggle_cloaked"])
shuttle.cloaked = !shuttle.cloaked
return TOPIC_REFRESH
+37 -33
View File
@@ -1,30 +1,32 @@
/datum/shuttle/ferry/emergency
/datum/shuttle/autodock/ferry/emergency
//pass
/datum/shuttle/ferry/emergency/arrived()
/datum/shuttle/autodock/ferry/emergency/New()
..()
if(emergency_shuttle.shuttle)
CRASH("An emergency shuttle has already been created.")
return
emergency_shuttle.shuttle = src
/datum/shuttle/autodock/ferry/emergency/arrived()
. = ..()
if (istype(in_use, /obj/machinery/computer/shuttle_control/emergency))
var/obj/machinery/computer/shuttle_control/emergency/C = in_use
C.reset_authorization()
emergency_shuttle.shuttle_arrived()
/datum/shuttle/ferry/emergency/long_jump(var/area/departing, var/area/destination, var/area/interim, var/travel_time, var/direction)
if (!location)
travel_time = SHUTTLE_TRANSIT_DURATION_RETURN
else
travel_time = SHUTTLE_TRANSIT_DURATION
/datum/shuttle/autodock/ferry/emergency/long_jump(var/obj/effect/shuttle_landmark/destination, var/obj/effect/shuttle_landmark/interim, var/travel_time)
var/time_to_go = SHUTTLE_TRANSIT_DURATION
if(destination == waypoint_offsite)
time_to_go = SHUTTLE_TRANSIT_DURATION_RETURN
//update move_time and launch_time so we get correct ETAs
move_time = travel_time
..(destination, interim, time_to_go)
emergency_shuttle.launch_time = world.time
..()
/datum/shuttle/ferry/emergency/move(var/area/origin,var/area/destination)
..(origin, destination)
if (origin == area_station) //leaving the station
emergency_shuttle.departed = 1
/datum/shuttle/autodock/ferry/emergency/shuttle_moved()
if (next_location != waypoint_station) //leaving the station
emergency_shuttle.departed = TRUE
var/list/replacements = list(
"%ETA%" = round(emergency_shuttle.estimate_arrival_time()/60,1),
@@ -34,15 +36,16 @@
priority_announcement.Announce(replacemany(current_map.emergency_shuttle_leaving_dock, replacements))
else
priority_announcement.Announce(replacemany(current_map.shuttle_leaving_dock, replacements))
..()
/datum/shuttle/ferry/emergency/can_launch(var/user)
/datum/shuttle/autodock/ferry/emergency/can_launch(var/user)
if (istype(user, /obj/machinery/computer/shuttle_control/emergency))
var/obj/machinery/computer/shuttle_control/emergency/C = user
if (!C.has_authorization())
return 0
return ..()
/datum/shuttle/ferry/emergency/can_force(var/user)
/datum/shuttle/autodock/ferry/emergency/can_force(var/user)
if (istype(user, /obj/machinery/computer/shuttle_control/emergency))
var/obj/machinery/computer/shuttle_control/emergency/C = user
@@ -52,7 +55,7 @@
return 0
return ..()
/datum/shuttle/ferry/emergency/can_cancel(var/user)
/datum/shuttle/autodock/ferry/emergency/can_cancel(var/user)
//If we try to cancel it via the shuttle computer
if (istype(user, /obj/machinery/computer/shuttle_control/emergency))
var/obj/machinery/computer/shuttle_control/emergency/C = user
@@ -61,13 +64,14 @@
return 0
// If the emergency shuttle is waiting to leave the station and the world time exceeded the force time
if (emergency_shuttle.waiting_to_leave() && (world.time > emergency_shuttle.force_time))
if(emergency_shuttle.waiting_to_leave() && (world.time > emergency_shuttle.force_time))
return 0
return ..()
/datum/shuttle/ferry/emergency/launch(var/user)
if (!can_launch(user)) return
/datum/shuttle/autodock/ferry/emergency/launch(var/user)
if (!can_launch(user))
return
if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console
if (emergency_shuttle.autopilot)
@@ -80,8 +84,9 @@
..(user)
/datum/shuttle/ferry/emergency/force_launch(var/user)
if (!can_force(user)) return
/datum/shuttle/autodock/ferry/emergency/force_launch(var/user)
if (!can_force(user))
return
if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console
if (emergency_shuttle.autopilot)
@@ -94,8 +99,9 @@
..(user)
/datum/shuttle/ferry/emergency/cancel_launch(var/user)
if (!can_cancel(user)) return
/datum/shuttle/autodock/ferry/emergency/cancel_launch(var/user)
if (!can_cancel(user))
return
if (istype(user, /obj/machinery/computer/shuttle_control/emergency)) //if we were given a command by an emergency shuttle console
if (emergency_shuttle.autopilot)
@@ -108,10 +114,8 @@
..(user)
/obj/machinery/computer/shuttle_control/emergency
shuttle_tag = "Escape"
shuttle_tag = "Escape Shuttle"
var/debug = 0
var/req_authorizations = 2
var/list/authorized = list()
@@ -177,7 +181,7 @@
/obj/machinery/computer/shuttle_control/emergency/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
var/datum/shuttle/ferry/emergency/shuttle = shuttle_controller.shuttles[shuttle_tag]
var/datum/shuttle/autodock/ferry/emergency/shuttle = SSshuttle.shuttles[shuttle_tag]
if (!istype(shuttle))
return
@@ -223,9 +227,9 @@
data = list(
"shuttle_status" = shuttle_status,
"shuttle_state" = shuttle_state,
"has_docking" = shuttle.docking_controller? 1 : 0,
"docking_status" = shuttle.docking_controller? shuttle.docking_controller.get_docking_status() : null,
"docking_override" = shuttle.docking_controller? shuttle.docking_controller.override_enabled : null,
"has_docking" = shuttle.active_docking_controller? 1 : 0,
"docking_status" = shuttle.active_docking_controller? shuttle.active_docking_controller.get_docking_status() : null,
"docking_override" = shuttle.active_docking_controller? shuttle.active_docking_controller.override_enabled : null,
"can_launch" = shuttle.can_launch(src),
"can_cancel" = shuttle.can_cancel(src),
"can_force" = shuttle.can_force(src),
+29 -157
View File
@@ -1,175 +1,47 @@
#define DOCK_ATTEMPT_TIMEOUT 200 //how long in ticks we wait before assuming the docking controller is broken or blown up.
/datum/shuttle/ferry
/datum/shuttle/autodock/ferry
var/location = 0 //0 = at area_station, 1 = at area_offsite
var/direction = 0 //0 = going to station, 1 = going to offsite.
var/process_state = IDLE_STATE
var/in_use = null //tells the controller whether this shuttle needs processing
var/obj/effect/shuttle_landmark/waypoint_station //This variable is type-abused initially: specify the landmark_tag, not the actual landmark.
var/obj/effect/shuttle_landmark/waypoint_offsite //This variable is type-abused initially: specify the landmark_tag, not the actual landmark.
var/area_transition
var/move_time = 0 //the time spent in the transition area
var/transit_direction = null //needed for area/move_contents_to() to properly handle shuttle corners - not exactly sure how it works.
category = /datum/shuttle/autodock/ferry
var/area/area_station
var/area/area_offsite
//TODO: change location to a string and use a mapping for area and dock targets.
var/dock_target_station
var/dock_target_offsite
/datum/shuttle/autodock/ferry/New(_name)
if(waypoint_station)
waypoint_station = SSshuttle.get_landmark(waypoint_station)
if(waypoint_offsite)
waypoint_offsite = SSshuttle.get_landmark(waypoint_offsite)
var/last_dock_attempt_time = 0
..(_name, get_location_waypoint(location))
/datum/shuttle/ferry/short_jump(var/area/origin, var/area/destination)
if(isnull(location))
return
next_location = get_location_waypoint(!location)
if(!destination)
destination = get_location_area(!location)
if(!origin)
origin = get_location_area(location)
direction = !location
..(origin, destination)
/datum/shuttle/ferry/long_jump(var/area/departing, var/area/destination, var/area/interim, var/travel_time, var/direction)
if(isnull(location))
return
if(!destination)
destination = get_location_area(!location)
if(!departing)
departing = get_location_area(location)
direction = !location
..(departing, destination, interim, travel_time, direction)
/datum/shuttle/ferry/move(var/area/origin,var/area/destination)
..(origin, destination)
if (destination == area_station) location = 0
if (destination == area_offsite) location = 1
//if this is a long_jump retain the location we were last at until we get to the new one
/datum/shuttle/ferry/dock()
..()
last_dock_attempt_time = world.time
/datum/shuttle/ferry/proc/get_location_area(location_id = null)
//Gets the shuttle landmark associated with the given location (defaults to current location)
/datum/shuttle/autodock/ferry/proc/get_location_waypoint(location_id = null)
if (isnull(location_id))
location_id = location
if (!location_id)
return area_station
return area_offsite
return waypoint_station
return waypoint_offsite
/*
Please ensure that long_jump() and short_jump() are only called from here. This applies to subtypes as well.
Doing so will ensure that multiple jumps cannot be initiated in parallel.
*/
/datum/shuttle/ferry/process()
if(moving_status != SHUTTLE_HALT)
if(!area_station || !area_offsite)
moving_status = SHUTTLE_HALT
return
if(!area_station.contents.len || !area_offsite.contents.len)
moving_status = SHUTTLE_HALT
return
switch(process_state)
if (WAIT_LAUNCH)
if (skip_docking_checks() || docking_controller.can_launch())
/datum/shuttle/autodock/ferry/short_jump(var/destination)
direction = !location
..()
if (move_time && area_transition)
long_jump(interim=area_transition, travel_time=move_time, direction=transit_direction)
else
short_jump()
/datum/shuttle/autodock/ferry/long_jump(var/obj/effect/shuttle_landmark/destination, var/obj/effect/shuttle_landmark/interim, var/travel_time)
direction = !location
..()
process_state = WAIT_ARRIVE
/datum/shuttle/autodock/ferry/shuttle_moved()
..()
if (FORCE_LAUNCH)
if (move_time && area_transition)
long_jump(interim=area_transition, travel_time=move_time, direction=transit_direction)
else
short_jump()
process_state = WAIT_ARRIVE
if (WAIT_ARRIVE)
if (moving_status == SHUTTLE_IDLE)
dock()
in_use = null //release lock
process_state = WAIT_FINISH
if (WAIT_FINISH)
if (skip_docking_checks() || docking_controller.docked() || world.time > last_dock_attempt_time + DOCK_ATTEMPT_TIMEOUT)
process_state = IDLE_STATE
arrived()
/datum/shuttle/ferry/current_dock_target()
var/dock_target
if (!location) //station
dock_target = dock_target_station
else
dock_target = dock_target_offsite
return dock_target
/datum/shuttle/ferry/proc/launch(var/user)
if (!can_launch()) return
in_use = user //obtain an exclusive lock on the shuttle
process_state = WAIT_LAUNCH
undock()
/datum/shuttle/ferry/proc/force_launch(var/user)
if (!can_force()) return
in_use = user //obtain an exclusive lock on the shuttle
process_state = FORCE_LAUNCH
/datum/shuttle/ferry/proc/cancel_launch(var/user)
if (!can_cancel()) return
moving_status = SHUTTLE_IDLE
process_state = WAIT_FINISH
in_use = null
if (docking_controller && !docking_controller.undocked())
docking_controller.force_undock()
spawn(10)
dock()
return
/datum/shuttle/ferry/proc/can_launch()
if (moving_status != SHUTTLE_IDLE)
return 0
if (in_use)
return 0
return 1
/datum/shuttle/ferry/proc/can_force()
if (moving_status == SHUTTLE_IDLE && process_state == WAIT_LAUNCH)
return 1
return 0
/datum/shuttle/ferry/proc/can_cancel()
if(moving_status == SHUTTLE_HALT)
return 0
if (moving_status == SHUTTLE_WARMUP || process_state == WAIT_LAUNCH || process_state == FORCE_LAUNCH)
return 1
return 0
//returns 1 if the shuttle is getting ready to move, but is not in transit yet
/datum/shuttle/ferry/proc/is_launching()
return (moving_status == SHUTTLE_WARMUP || process_state == WAIT_LAUNCH || process_state == FORCE_LAUNCH)
//This gets called when the shuttle finishes arriving at it's destination
//This can be used by subtypes to do things when the shuttle arrives.
/datum/shuttle/ferry/proc/arrived()
return //do nothing for now
if (next_location == waypoint_station) location = 0
if (next_location == waypoint_offsite) location = 1
/datum/shuttle/autodock/ferry/process_arrived()
..()
next_location = get_location_waypoint(!location)
+22 -52
View File
@@ -1,60 +1,32 @@
/obj/machinery/computer/shuttle_control/specops
name = "special operations shuttle console"
shuttle_tag = "Special Operations"
shuttle_tag = "Phoenix Shuttle"
req_access = list(access_cent_specops)
/obj/machinery/computer/shuttle_control/specops/attack_ai(user as mob)
to_chat(user, "<span class='warning'>Access Denied.</span>")
return 1
//for shuttles that may use a different docking port at each location
/datum/shuttle/ferry/multidock
var/docking_controller_tag_station
var/docking_controller_tag_offsite
var/datum/computer/file/embedded_program/docking/docking_controller_station
var/datum/computer/file/embedded_program/docking/docking_controller_offsite
/datum/shuttle/ferry/multidock/init_docking_controllers()
if(docking_controller_tag_station)
docking_controller_station = locate(docking_controller_tag_station)
if(!istype(docking_controller_station))
to_world("<span class='danger'>warning: shuttle with docking tag [docking_controller_station] could not find it's controller!</span>")
if(docking_controller_tag_offsite)
docking_controller_offsite = locate(docking_controller_tag_offsite)
if(!istype(docking_controller_offsite))
to_world("<span class='danger'>warning: shuttle with docking tag [docking_controller_offsite] could not find it's controller!</span>")
if (!location)
docking_controller = docking_controller_station
else
docking_controller = docking_controller_offsite
/datum/shuttle/ferry/multidock/move(var/area/origin,var/area/destination)
..(origin, destination)
if (!location)
docking_controller = docking_controller_station
else
docking_controller = docking_controller_offsite
/datum/shuttle/ferry/multidock/specops
/datum/shuttle/autodock/ferry/specops
var/specops_return_delay = 6000 //After moving, the amount of time that must pass before the shuttle may move again
var/specops_countdown_time = 600 //Length of the countdown when moving the shuttle
var/obj/item/device/radio/intercom/announcer = null
var/obj/item/device/radio/intercom/announcer
var/reset_time = 0 //the world.time at which the shuttle will be ready to move again.
var/launch_prep = 0
var/cancel_countdown = 0
category = /datum/shuttle/autodock/ferry/specops
/datum/shuttle/ferry/multidock/specops/New()
/datum/shuttle/autodock/ferry/specops/New()
..()
announcer = new /obj/item/device/radio/intercom(null)//We need a fake AI to announce some stuff below. Otherwise it will be wonky.
announcer.config(list("Response Team" = 0))
/datum/shuttle/ferry/multidock/specops/proc/radio_announce(var/message)
/datum/shuttle/autodock/ferry/specops/proc/radio_announce(var/message)
if(announcer)
announcer.autosay(message, "Bubble", "Response Team")
/datum/shuttle/ferry/multidock/specops/launch(var/user)
/datum/shuttle/autodock/ferry/specops/launch(var/user)
if (!can_launch())
return
@@ -79,31 +51,31 @@
sleep_until_launch()
if (location)
var/obj/machinery/light/small/readylight/light = locate() in get_location_area()
var/obj/machinery/light/small/readylight/light = locate() in shuttle_area
if(light) light.set_state(0)
//launch
radio_announce("ALERT: INITIATING LAUNCH SEQUENCE")
..(user)
/datum/shuttle/ferry/multidock/specops/move(var/area/origin,var/area/destination)
..(origin, destination)
/datum/shuttle/autodock/ferry/specops/shuttle_moved()
. = ..()
spawn(20)
if (!location) //just arrived home
for(var/turf/T in get_area_turfs(destination))
for(var/turf/T in get_area_turfs(shuttle_area))
var/mob/M = locate(/mob) in T
to_chat(M, "<span class='danger'>You have arrived at [current_map.boss_name]. Operation has ended!</span>")
else //just left for the station
launch_mauraders()
for(var/turf/T in get_area_turfs(destination))
for(var/turf/T in get_area_turfs(shuttle_area))
var/mob/M = locate(/mob) in T
to_chat(M, "<span class='danger'>You have arrived at [current_map.station_name]. Commence operation!</span>")
var/obj/machinery/light/small/readylight/light = locate() in T
if(light) light.set_state(1)
/datum/shuttle/ferry/multidock/specops/cancel_launch()
/datum/shuttle/autodock/ferry/specops/cancel_launch()
if (!can_cancel())
return
@@ -115,23 +87,21 @@
..()
/datum/shuttle/ferry/multidock/specops/can_launch()
/datum/shuttle/autodock/ferry/specops/can_launch()
if(launch_prep)
return 0
return ..()
//should be fine to allow forcing. process_state only becomes WAIT_LAUNCH after the countdown is over.
///datum/shuttle/ferry/multidock/specops/can_force()
///datum/shuttle/autodock/ferry/specops/can_force()
// return 0
/datum/shuttle/ferry/multidock/specops/can_cancel()
/datum/shuttle/autodock/ferry/specops/can_cancel()
if(launch_prep)
return 1
return ..()
/datum/shuttle/ferry/multidock/specops/proc/sleep_until_launch()
/datum/shuttle/autodock/ferry/specops/proc/sleep_until_launch()
var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a a list with potential time values.
var/launch_time = world.time + specops_countdown_time
@@ -246,17 +216,17 @@
/obj/machinery/computer/shuttle_control/legion
name = "dropship control console"
req_access = list(access_legion)
shuttle_tag = "Tau Ceti Foreign Legion"
shuttle_tag = "Legion Shuttle"
/datum/shuttle/ferry/legion
/datum/shuttle/autodock/ferry/legion
var/dropship_return_delay = 6600
var/earliest_departure_time = 0
/datum/shuttle/ferry/legion/arrived()
/datum/shuttle/autodock/ferry/legion/arrived()
if(!location)
earliest_departure_time = world.time + dropship_return_delay
/datum/shuttle/ferry/legion/launch(var/user)
/datum/shuttle/autodock/ferry/legion/launch(var/user)
if(!location && earliest_departure_time > world.time)
var/obj/machinery/computer/shuttle_control/legion/L = user
L.visible_message(span("notice","The dropship's skipthrusters will be done recharging in approximately [round((earliest_departure_time - world.time)/600)] minute\s."),null,3)
@@ -267,4 +237,4 @@
/obj/machinery/computer/shuttle_control/distress
name = "shuttle control computer"
req_access = list(access_distress)
shuttle_tag = "Distress"
shuttle_tag = "Distress Shuttle"
+30 -28
View File
@@ -1,75 +1,77 @@
/datum/shuttle/ferry/supply
/datum/shuttle/autodock/ferry/supply
category = /datum/shuttle/autodock/ferry/supply
var/away_location = 1 //the location to hide at while pretending to be in-transit
var/late_chance = 80
var/max_late_time = 300
/datum/shuttle/ferry/supply/short_jump(var/area/origin,var/area/destination)
/datum/shuttle/autodock/ferry/supply/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint)
..(_name, start_waypoint)
SScargo.shuttle = src
/datum/shuttle/autodock/ferry/supply/short_jump(var/area/destination)
if(moving_status != SHUTTLE_IDLE)
return
if(isnull(location))
return
if(!destination)
destination = get_location_area(!location)
if(!origin)
origin = get_location_area(location)
//it would be cool to play a sound here
moving_status = SHUTTLE_WARMUP
spawn(warmup_time*10)
if (moving_status == SHUTTLE_IDLE)
if (moving_status == SHUTTLE_IDLE)
return //someone cancelled the launch
if (at_station() && forbidden_atoms_check())
//cancel the launch because of forbidden atoms. announce over supply channel?
moving_status = SHUTTLE_IDLE
return
if (!at_station()) //at centcom
if(!SScargo.buy()) //Check if the shuttle can be sent
moving_status = SHUTTLE_IDLE //Dont move the shuttle
//We pretend it's a long_jump by making the shuttle stay at centcom for the "in-transit" period.
var/area/away_area = get_location_area(away_location)
var/obj/effect/shuttle_landmark/away_waypoint = get_location_waypoint(away_location)
moving_status = SHUTTLE_INTRANSIT
//If we are at the away_area then we are just pretending to move, otherwise actually do the move
if (origin != away_area)
move(origin, away_area)
//If we are at the away_landmark then we are just pretending to move, otherwise actually do the move
if (next_location == away_waypoint)
attempt_move(away_waypoint)
//wait ETA here.
arrive_time = world.time + SScargo.movetime
while (world.time <= arrive_time)
sleep(5)
if (destination != away_area)
if (next_location != away_waypoint)
//late
if (prob(late_chance))
sleep(rand(0,max_late_time))
move(away_area, destination)
attempt_move(destination)
moving_status = SHUTTLE_IDLE
if (!at_station()) //at centcom
SScargo.sell()
// returns 1 if the supply shuttle should be prevented from moving because it contains forbidden atoms
/datum/shuttle/ferry/supply/proc/forbidden_atoms_check()
/datum/shuttle/autodock/ferry/supply/proc/forbidden_atoms_check()
if (!at_station())
return 0 //if badmins want to send mobs or a nuke on the supply shuttle from centcom we don't care
return SScargo.forbidden_atoms_check(get_location_area())
/datum/shuttle/ferry/supply/proc/at_station()
for(var/area/A in shuttle_area)
if(SScargo.forbidden_atoms_check(A))
return 1
/datum/shuttle/autodock/ferry/supply/proc/at_station()
return (!location)
//returns 1 if the shuttle is idle and we can still mess with the cargo shopping list
/datum/shuttle/ferry/supply/proc/idle()
/datum/shuttle/autodock/ferry/supply/proc/idle()
return (moving_status == SHUTTLE_IDLE)
//returns the ETA in minutes
/datum/shuttle/ferry/supply/proc/eta_minutes()
/datum/shuttle/autodock/ferry/supply/proc/eta_minutes()
var/ticksleft = arrive_time - world.time
return round(ticksleft/600,1)
+56 -240
View File
@@ -1,256 +1,72 @@
//This is a holder for things like the Skipjack and Nuke shuttle.
/datum/shuttle/multi_shuttle
/datum/shuttle/autodock/multi
var/list/destination_tags
var/list/destinations_cache = list()
var/last_cache_rebuild_time = 0
category = /datum/shuttle/autodock/multi
var/cloaked = 1
var/at_origin = 1
var/returned_home = 0
var/move_time = 240
var/cooldown = 20
var/last_move = 0 //the time at which we last moved
/datum/shuttle/autodock/multi/proc/set_destination(var/destination_key, mob/user)
if(moving_status != SHUTTLE_IDLE)
return
next_location = destinations_cache[destination_key]
/datum/shuttle/autodock/multi/proc/get_destinations()
if (last_cache_rebuild_time < SSshuttle.last_landmark_registration_time)
build_destinations_cache()
return destinations_cache
/datum/shuttle/autodock/multi/proc/build_destinations_cache()
last_cache_rebuild_time = world.time
destinations_cache.Cut()
for(var/destination_tag in destination_tags)
var/obj/effect/shuttle_landmark/landmark = SSshuttle.get_landmark(destination_tag)
if(istype(landmark))
destinations_cache["[landmark.name]"] = landmark
//Antag play announcements when they leave/return to their home area
/datum/shuttle/autodock/multi/antag
warmup_time = 10 SECONDS //replaced the old move cooldown
//This variable is type-abused initially: specify the landmark_tag, not the actual landmark.
var/obj/effect/shuttle_landmark/home_waypoint
var/cloaked = TRUE
var/returned = FALSE
var/announcer
var/arrival_message
var/departure_message
var/area/interim
var/area/last_departed
var/start_location
var/last_location
var/list/destinations
var/list/destination_dock_controller_tags = list() //optional, in case the shuttle has multiple docking ports like the ERT shuttle (even though that isn't a multi_shuttle)
var/list/destination_dock_controllers = list()
var/list/destination_dock_targets = list()
var/area/origin
var/return_warning = 0
var/start_warning = 0
category = /datum/shuttle/autodock/multi/antag
/datum/shuttle/multi_shuttle/New()
/datum/shuttle/autodock/multi/antag/New()
..()
if(home_waypoint)
home_waypoint = SSshuttle.get_landmark(home_waypoint)
else
home_waypoint = current_location
/datum/shuttle/autodock/multi/antag/shuttle_moved()
if(current_location == home_waypoint)
announce_arrival()
else if(next_location == home_waypoint)
announce_departure()
..()
/datum/shuttle/multi_shuttle/init_docking_controllers()
..()
for(var/destination in destinations)
var/controller_tag = destination_dock_controller_tags[destination]
if(!controller_tag)
destination_dock_controllers[destination] = docking_controller
else
var/datum/computer/file/embedded_program/docking/C = locate(controller_tag)
/datum/shuttle/autodock/multi/antag/arrived()
if(current_location == home_waypoint)
returned = TRUE
if(!istype(C))
to_world("<span class='danger'>warning: shuttle with docking tag [controller_tag] could not find it's controller!</span>")
else
destination_dock_controllers[destination] = C
//might as well set this up here.
if(origin) last_departed = origin
last_location = start_location
/datum/shuttle/multi_shuttle/current_dock_target()
return destination_dock_targets[last_location]
//If they returned home, they wont be able to depart again
/datum/shuttle/multi_shuttle/long_jump(var/area/departing, var/area/destination, var/area/interim, var/travel_time, var/direction)
if(returned_home)
return
return ..()
/datum/shuttle/multi_shuttle/move(var/area/origin, var/area/destination)
..()
last_move = world.time
if (destination == src.origin)
returned_home = 1
docking_controller = destination_dock_controllers[last_location]
/datum/shuttle/multi_shuttle/proc/announce_departure()
/datum/shuttle/autodock/multi/antag/launch(var/user)
if(returned)
if(user)
to_chat(user, SPAN_WARNING("You don't have enough fuel for another launch!"))
return //Nada, can't go back.
..(user)
/datum/shuttle/autodock/multi/antag/proc/announce_departure()
if(cloaked || isnull(departure_message))
return
command_announcement.Announce(departure_message, announcer || "[current_map.boss_name]")
command_announcement.Announce(departure_message,(announcer ? announcer : "[current_map.boss_name]"))
/datum/shuttle/multi_shuttle/proc/announce_arrival()
/datum/shuttle/autodock/multi/antag/proc/announce_arrival()
if(cloaked || isnull(arrival_message))
return
command_announcement.Announce(arrival_message,(announcer ? announcer : "[current_map.boss_name]"))
/obj/machinery/computer/shuttle_control/multi
icon_screen = "syndishuttle"
/obj/machinery/computer/shuttle_control/multi/attack_hand(user as mob)
if(..(user))
return
src.add_fingerprint(user)
var/datum/shuttle/multi_shuttle/MS = shuttle_controller.shuttles[shuttle_tag]
if(!istype(MS)) return
var/dat
dat = "<center>[shuttle_tag] Ship Control<hr>"
if(MS.moving_status != SHUTTLE_IDLE)
dat += "Location: <font color='red'>Moving</font> <br>"
else
var/area/areacheck = get_area(src)
dat += "Location: [areacheck.name]<br>"
if((MS.last_move + MS.cooldown*10) > world.time)
dat += "<font color='red'>Engines charging.</font><br>"
else if (MS.returned_home)
dat += "<font color='red'>Engines offline.</font><br>"
else
dat += "<font color='green'>Engines ready.</font><br>"
dat += "<br><b><A href='?src=\ref[src];toggle_cloak=[1]'>Toggle cloaking field</A></b><br>"
dat += "<b><A href='?src=\ref[src];move_multi=[1]'>Move ship</A></b><br>"
dat += "<b><A href='?src=\ref[src];start=[1]'>Return to base</A></b></center>"
//Docking
dat += "<center><br><br>"
if(MS.skip_docking_checks())
dat += "Docking Status: <font color='grey'>Not in use.</font>"
else
var/override_en = MS.docking_controller.override_enabled
var/docking_status = MS.docking_controller.get_docking_status()
dat += "Docking Status: "
switch(docking_status)
if("undocked")
dat += "<font color='[override_en? "red" : "grey"]'>Undocked</font>"
if("docking")
dat += "<font color='[override_en? "red" : "yellow"]'>Docking</font>"
if("undocking")
dat += "<font color='[override_en? "red" : "yellow"]'>Undocking</font>"
if("docked")
dat += "<font color='[override_en? "red" : "green"]'>Docked</font>"
if(override_en) dat += " <font color='red'>(Override Enabled)</font>"
dat += ". <A href='?src=\ref[src];refresh=[1]'>\[Refresh\]</A><br><br>"
switch(docking_status)
if("undocked")
dat += "<b><A href='?src=\ref[src];dock_command=[1]'>Dock</A></b>"
if("docked")
dat += "<b><A href='?src=\ref[src];undock_command=[1]'>Undock</A></b>"
dat += "</center>"
user << browse("[dat]", "window=[shuttle_tag]shuttlecontrol;size=300x600")
//check if we're undocked, give option to force launch
/obj/machinery/computer/shuttle_control/proc/check_docking(datum/shuttle/multi_shuttle/MS)
if(MS.skip_docking_checks() || MS.docking_controller.can_launch())
return 1
var/choice = alert("The shuttle is currently docked! Please undock before continuing.","Error","Cancel","Force Launch")
if(choice == "Cancel")
return 0
choice = alert("Forcing a shuttle launch while docked may result in severe injury, death and/or damage to property. Are you sure you wish to continue?", "Force Launch", "Force Launch", "Cancel")
if(choice == "Cancel")
return 0
return 1
/obj/machinery/computer/shuttle_control/multi/Topic(href, href_list)
if(..())
return 1
usr.set_machine(src)
src.add_fingerprint(usr)
var/datum/shuttle/multi_shuttle/MS = shuttle_controller.shuttles[shuttle_tag]
if(!istype(MS))
return
if(href_list["refresh"])
updateUsrDialog()
return
if (MS.moving_status != SHUTTLE_IDLE)
to_chat(usr, "<span class='notice'>[shuttle_tag] vessel is moving.</span>")
return
if(href_list["dock_command"])
MS.dock()
return
if(href_list["undock_command"])
MS.undock()
return
if(href_list["start"])
if(MS.at_origin)
to_chat(usr, "<span class='warning'>You are already at your home base.</span>")
return
if((MS.last_move + MS.cooldown*10) > world.time)
to_chat(usr, "<span class='warning'>The ship's drive is inoperable while the engines are charging.</span>")
return
if(!check_docking(MS))
updateUsrDialog()
return
if(!MS.return_warning)
to_chat(usr, "<span class='warning'>Returning to your home base will end your mission. If you are sure, press the button again.</span>")
MS.return_warning = 1
return
MS.long_jump(MS.last_departed,MS.origin,MS.interim,MS.move_time)
MS.last_departed = MS.origin
MS.last_location = MS.start_location
MS.at_origin = 1
if(href_list["toggle_cloak"])
MS.cloaked = !MS.cloaked
to_chat(usr, "<span class='warning'>Ship stealth systems have been [(MS.cloaked ? "activated. The station will not" : "deactivated. The station will")] be warned of our arrival.</span>")
if(href_list["move_multi"])
if(MS.returned_home)
to_chat(usr, "<span class='warning'>The ship's drive is offline.</span>")
return
if(MS.at_origin && !MS.start_warning)
MS.start_warning = 1
to_chat(usr, "<span class='warning'>You can only make one roundtrip between the target and the base. If you are sure you want to depart, press the button again.</span>")
return
if((MS.last_move + MS.cooldown*10) > world.time)
to_chat(usr, "<span class='warning'>The ship's drive is inoperable while the engines are charging.</span>")
return
if(!check_docking(MS))
updateUsrDialog()
return
var/choice = input("Select a destination.") as null|anything in MS.destinations
if(!choice) return
to_chat(usr, "<span class='notice'>[shuttle_tag] main computer received message.</span>")
if(MS.at_origin)
MS.announce_arrival()
MS.last_departed = MS.origin
MS.at_origin = 0
MS.long_jump(MS.last_departed, MS.destinations[choice], MS.interim, MS.move_time)
MS.last_departed = MS.destinations[choice]
MS.last_location = choice
return
else if(choice == MS.origin)
MS.announce_departure()
MS.short_jump(MS.last_departed, MS.destinations[choice])
MS.last_departed = MS.destinations[choice]
MS.last_location = choice
updateUsrDialog()
command_announcement.Announce(arrival_message, announcer || "[current_map.boss_name]")