Web Shuttle Update

Adds autopilot functionality for shuttle one and shuttle two. It can be enabled and disabled by the flight computer.
Autopilot is active by default on both shuttles. The shuttle waits for two minutes when it reaches the outpost or station, except for the first flight, where it waits for about ten minutes, which should be plenty of time for people to get on and for the pilot to turn it off if one exists.
Adds renaming feature to all shuttles.
Ports /tg/'s 'shuttle warning' effect, which adds a bunch of blue circles where a ship is about to land, which should prevent surprise shuttle crushes if paying attention.
Flight times for all routes are cut in half to act as the bonus for flying manually. Automatic flight takes twice as long, and so it will take the current amount of time.
Makes Ninja shuttle faster because Nippen steal.
Does some cleanup with temporary effects.
This commit is contained in:
Neerti
2018-01-14 14:03:58 -05:00
parent cd298b1575
commit d0d6689263
20 changed files with 478 additions and 113 deletions
+15
View File
@@ -37,12 +37,20 @@
supply_controller.shuttle = null
. = ..()
/datum/shuttle/proc/process()
return
/datum/shuttle/proc/init_docking_controllers()
if(docking_controller_tag)
docking_controller = locate(docking_controller_tag)
if(!istype(docking_controller))
world << "<span class='danger'>warning: shuttle with docking tag [docking_controller_tag] could not find it's controller!</span>"
// This creates a graphical warning to where the shuttle is about to land, in approximately five seconds.
/datum/shuttle/proc/create_warning_effect(area/landing_area)
for(var/turf/T in landing_area)
new /obj/effect/temporary_effect/shuttle_landing(T) // It'll delete itself when needed.
// Return false to abort a jump, before the 'warmup' phase.
/datum/shuttle/proc/pre_warmup_checks()
return TRUE
@@ -70,6 +78,7 @@
spawn(warmup_time*10)
make_sounds(origin, HYPERSPACE_WARMUP)
create_warning_effect(destination)
sleep(5 SECONDS) // so the sound finishes.
if(!post_warmup_checks())
@@ -102,6 +111,7 @@
spawn(warmup_time*10)
make_sounds(departing, HYPERSPACE_WARMUP)
create_warning_effect(interim) // Really doubt someone is gonna get crushed in the interim area but for completeness's sake we'll make the warning.
sleep(5 SECONDS) // so the sound finishes.
if(!post_warmup_checks())
@@ -122,11 +132,16 @@
move(departing, interim, direction)
var/last_progress_sound = 0
var/made_warning = FALSE
while (world.time < arrive_time)
// Make the shuttle make sounds every four seconds, since the sound file is five seconds.
if(last_progress_sound + 4 SECONDS < world.time)
make_sounds(interim, HYPERSPACE_PROGRESS)
last_progress_sound = world.time
if(arrive_time - world.time <= 5 SECONDS && !made_warning)
made_warning = TRUE
create_warning_effect(destination)
sleep(5)
move(interim, destination, direction)
+2 -2
View File
@@ -57,9 +57,9 @@
..() // Do everything else
/datum/shuttle/ferry/arrivals/proc/message_passengers(area/A, var/message)
/datum/shuttle/proc/message_passengers(area/A, var/message)
for(var/mob/M in A)
to_chat(M, message)
M.show_message(message, 2)
/*
/datum/shuttle/ferry/arrivals/current_dock_target()
+1 -1
View File
@@ -76,7 +76,7 @@
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/proc/process()
/datum/shuttle/ferry/process()
switch(process_state)
if (WAIT_LAUNCH)
if (skip_docking_checks() || docking_controller.can_launch())
+112 -5
View File
@@ -1,20 +1,32 @@
//This shuttle traverses a "web" of route_datums to have a wider range of places to go and make flying feel like movement is actually occuring.
/datum/shuttle/web_shuttle
flags = SHUTTLE_FLAGS_NONE
var/visible_name = null // The pretty name shown to people in announcements, since the regular name var is used internally for other things.
var/cloaked = FALSE
var/can_cloak = FALSE
var/cooldown = 5 SECONDS
var/cooldown = 0
var/last_move = 0 //the time at which we last moved
var/area/current_area = null
var/datum/shuttle_web_master/web_master = null
var/web_master_type = null
var/flight_time_modifier = 1.0
var/autopilot = FALSE
var/can_autopilot = FALSE
var/autopilot_delay = 60 // How many ticks to not do anything when not following an autopath. Should equal two minutes.
var/autopilot_first_delay = null // If your want your shuttle to stay for a different amount of time for the first time, set this.
var/can_rename = TRUE // Lets the pilot rename the shuttle. Only available once.
category = /datum/shuttle/web_shuttle
/datum/shuttle/web_shuttle/New()
current_area = locate(current_area)
web_master = new web_master_type(src)
build_destinations()
if(autopilot)
flags |= SHUTTLE_FLAGS_PROCESS
if(autopilot_first_delay)
autopilot_delay = autopilot_first_delay
if(!visible_name)
visible_name = name
..()
/datum/shuttle/web_shuttle/Destroy()
@@ -39,6 +51,78 @@
/datum/shuttle/web_shuttle/proc/build_destinations()
return
/datum/shuttle/web_shuttle/process()
if(moving_status == SHUTTLE_IDLE)
if(web_master.autopath) // We're currently flying a path.
autopilot_say("Continuing route.")
web_master.process_autopath()
else // Otherwise we are about to start one or just finished one.
if(autopilot_delay > 0) // Wait for awhile so people can get on and off.
if(docking_controller && !skip_docking_checks()) // Dock to the destination if possible.
var/docking_status = docking_controller.get_docking_status()
if(docking_status == "undocked")
dock()
autopilot_say("Docking.")
return
else if(docking_status == "docking")
return // Give it a few more ticks to finish docking.
if(autopilot_delay % 10 == 0) // Every ten ticks.
var/seconds_left = autopilot_delay * 2
if(seconds_left >= 60) // A minute
var/minutes_left = Floor(seconds_left / 60)
seconds_left = seconds_left % 60
autopilot_say("Departing in [minutes_left] minute\s[seconds_left ? ", [seconds_left] seconds":""].")
else
autopilot_say("Departing in [seconds_left] seconds.")
autopilot_delay--
else // Time to go.
if(docking_controller && !skip_docking_checks()) // Undock if possible.
var/docking_status = docking_controller.get_docking_status()
if(docking_status == "docked")
undock()
autopilot_say("Undocking.")
return
else if(docking_status == "undocking")
return // Give it a few more ticks to finish undocking.
autopilot_delay = initial(autopilot_delay)
autopilot_say("Taking off.")
web_master.process_autopath()
/datum/shuttle/web_shuttle/proc/adjust_autopilot(on)
if(on)
if(autopilot)
return
autopilot = TRUE
autopilot_delay = initial(autopilot_delay)
shuttle_controller.process_shuttles += src
else
if(!autopilot)
return
autopilot = FALSE
shuttle_controller.process_shuttles -= src
/datum/shuttle/web_shuttle/proc/autopilot_say(message) // Makes the autopilot 'talk' to the passengers.
var/padded_message = "<span class='game say'><span class='name'>shuttle autopilot</span> states, \"[message]\"</span>"
message_passengers(current_area, padded_message)
/datum/shuttle/web_shuttle/proc/rename_shuttle(mob/user)
if(!can_rename)
to_chat(user, "<span class='warning'>You can't rename this vessel.</span>")
return
var/new_name = input(user, "Please enter a new name for this vessel. Note that you can only set its name once, so choose wisely.", "Rename Shuttle", visible_name) as null|text
var/sanitized_name = sanitizeName(new_name, MAX_NAME_LEN, TRUE)
if(sanitized_name)
can_rename = FALSE
to_chat(user, "<span class='notice'>You've renamed the vessel to '[sanitized_name]'.</span>")
message_admins("[key_name_admin(user)] renamed shuttle '[visible_name]' to '[sanitized_name]'.")
visible_name = sanitized_name
else
to_chat(user, "<span class='warning'>The name you supplied was invalid. Try another name.</span>")
/obj/machinery/computer/shuttle_control/web
name = "flight computer"
icon_state = "flightcomp_center"
@@ -174,13 +258,16 @@
"travel_progress" = between(0, percent_finished, 100),
"time_left" = round( (total_time - elapsed_time) / 10),
"can_cloak" = shuttle.can_cloak ? 1 : 0,
"cloaked" = shuttle.cloaked ? 1 : 0
"cloaked" = shuttle.cloaked ? 1 : 0,
"can_autopilot" = shuttle.can_autopilot ? 1 : 0,
"autopilot" = shuttle.autopilot ? 1 : 0,
"can_rename" = shuttle.can_rename ? 1 : 0
)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "flight.tmpl", "[shuttle_tag] Flight Computer", 470, 500)
ui = new(user, src, ui_key, "flight.tmpl", "[shuttle.visible_name] Flight Computer", 470, 500)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
@@ -202,13 +289,22 @@
ui_interact(usr)
if (WS.moving_status != SHUTTLE_IDLE)
usr << "<font color='blue'>[shuttle_tag] vessel is busy moving.</font>"
usr << "<font color='blue'>[WS.visible_name] is busy moving.</font>"
return
if(href_list["rename_command"])
WS.rename_shuttle(usr)
if(href_list["dock_command"])
if(WS.autopilot)
to_chat(usr, "<span class='warning'>The autopilot must be disabled before you can control the vessel manually.</span>")
return
WS.dock()
if(href_list["undock_command"])
if(WS.autopilot)
to_chat(usr, "<span class='warning'>The autopilot must be disabled before you can control the vessel manually.</span>")
return
WS.undock()
if(href_list["cloak_command"])
@@ -223,7 +319,17 @@
WS.cloaked = FALSE
to_chat(usr, "<span class='danger'>Ship stealth systems have been deactivated. The station will be warned of our arrival.</span>")
if(href_list["autopilot_on_command"])
WS.adjust_autopilot(TRUE)
if(href_list["autopilot_off_command"])
WS.adjust_autopilot(FALSE)
if(href_list["traverse"])
if(WS.autopilot)
to_chat(usr, "<span class='warning'>The autopilot must be disabled before you can control the vessel manually.</span>")
return
if((WS.last_move + WS.cooldown) > world.time)
usr << "<font color='red'>The ship's drive is inoperable while the engines are charging.</font>"
return
@@ -245,7 +351,8 @@
return
WS.web_master.future_destination = target_destination
to_chat(usr, "<span class='notice'>[shuttle_tag] flight computer received command.</span>")
to_chat(usr, "<span class='notice'>[WS.visible_name] flight computer received command.</span>")
WS.web_master.reset_autopath() // Deviating from the path will almost certainly confuse the autopilot, so lets just reset its memory.
var/travel_time = new_route.travel_time * WS.flight_time_modifier
+117 -8
View File
@@ -1,4 +1,8 @@
// This file actually has three seperate datums.
// This file actually has four seperate datums.
/**********
* Routes *
**********/
// This is the first datum, and it connects shuttle_destinations together.
/datum/shuttle_route
@@ -39,6 +43,10 @@
return target.name
/****************
* Destinations *
****************/
// This is the second datum, and contains information on all the potential destinations for a specific shuttle.
/datum/shuttle_destination
var/name = "a place" // Name of the destination, used for the flight computer.
@@ -50,8 +58,8 @@
var/dock_target = null // The tag_id that the shuttle will use to try to dock to the destination, if able.
var/announcer = null // The name of the 'announcer' that will say the arrival/departure messages. Defaults to the map's boss name if blank.
var/arrival_message = null // Message said if the ship enters this destination. Not announced if the ship is cloaked.
var/departure_message = null // Message said if the ship exits this destination. Not announced if the ship is cloaked.
// var/arrival_message = null // Message said if the ship enters this destination. Not announced if the ship is cloaked.
// var/departure_message = null // Message said if the ship exits this destination. Not announced if the ship is cloaked.
// When this destination is instantiated, it will go and instantiate other destinations in this assoc list and build routes between them.
// The list format is '/datum/shuttle_destination/subtype = 1 MINUTES'
@@ -101,18 +109,23 @@
/datum/shuttle_destination/proc/exit(var/datum/shuttle_destination/new_destination)
announce_departure()
/datum/shuttle_destination/proc/get_departure_message()
return null
/datum/shuttle_destination/proc/announce_departure()
if(isnull(departure_message) || master.my_shuttle.cloaked)
if(isnull(get_departure_message()) || master.my_shuttle.cloaked)
return
command_announcement.Announce(departure_message,(announcer ? announcer : "[using_map.boss_name]"))
command_announcement.Announce(get_departure_message(),(announcer ? announcer : "[using_map.boss_name]"))
/datum/shuttle_destination/proc/get_arrival_message()
return null
/datum/shuttle_destination/proc/announce_arrival()
if(isnull(arrival_message) || master.my_shuttle.cloaked)
if(isnull(get_arrival_message()) || master.my_shuttle.cloaked)
return
command_announcement.Announce(arrival_message,(announcer ? announcer : "[using_map.boss_name]"))
command_announcement.Announce(get_arrival_message(),(announcer ? announcer : "[using_map.boss_name]"))
/datum/shuttle_destination/proc/link_destinations(var/datum/shuttle_destination/other_place, var/area/interim_area, var/travel_time = 0)
// First, check to make sure this doesn't cause a duplicate route.
@@ -131,6 +144,17 @@
/datum/shuttle_destination/proc/flight_failure()
return
// Returns a /datum/shuttle_route connecting this destination to origin, if one exists.
/datum/shuttle_destination/proc/get_route_to(origin_type)
for(var/datum/shuttle_route/R in routes)
if(R.start.type == origin_type || R.end.type == origin_type)
return R
return null
/***************
* Web Masters *
***************/
// This is the third and final datum, which coordinates with the shuttle datum to tell it where it is, where it can go, and how long it will take.
// It is also responsible for instancing all the destinations it has control over, and linking them together.
/datum/shuttle_web_master
@@ -141,12 +165,17 @@
var/list/destinations = list() // List of currently instanced destinations.
var/destination_class = null // Type to use in typesof(), to build destinations.
var/datum/shuttle_autopath/autopath = null // Datum used to direct an autopilot.
var/list/autopaths = list() // Potential autopaths the autopilot can use. The autopath's start var must equal current_destination to be viable.
var/autopath_class = null // Similar to destination_class, used for typesof().
/datum/shuttle_web_master/New(var/new_shuttle, var/new_destination_class = null)
my_shuttle = new_shuttle
if(new_destination_class)
destination_class = new_destination_class
build_destinations()
current_destination = get_destination_by_type(starting_destination)
build_autopaths()
/datum/shuttle_web_master/Destroy()
my_shuttle = null
@@ -189,4 +218,84 @@
return current_destination
/datum/shuttle_web_master/proc/get_destination_by_type(var/type_to_get)
return locate(type_to_get) in destinations
return locate(type_to_get) in destinations
// Autopilot stuff.
/datum/shuttle_web_master/proc/build_autopaths()
init_subtypes(autopath_class, autopaths)
for(var/datum/shuttle_autopath/P in autopaths)
P.master = src
/datum/shuttle_web_master/proc/choose_path()
if(!autopaths.len)
return
for(var/datum/shuttle_autopath/path in autopaths)
if(path.start == current_destination.type)
autopath = path
break
/datum/shuttle_web_master/proc/path_finished(datum/shuttle_autopath/path)
autopath = null
/datum/shuttle_web_master/proc/walk_path(target_type)
var/datum/shuttle_route/R = current_destination.get_route_to(target_type)
if(!R)
return FALSE
future_destination = R.get_other_side(current_destination)
var/travel_time = R.travel_time * my_shuttle.flight_time_modifier * 2 // Autopilot is less efficent than having someone flying manually.
if(R.interim && R.travel_time > 0)
my_shuttle.long_jump(my_shuttle.current_area, future_destination.my_area, R.interim, travel_time / 10)
else
my_shuttle.short_jump(my_shuttle.current_area, future_destination.my_area)
return TRUE // Note this will return before the shuttle actually arrives.
/datum/shuttle_web_master/proc/process_autopath()
if(!autopath) // If we don't have a path, get one.
if(!autopaths.len)
return
choose_path()
if(!autopath) // Still nothing, oh well.
return
var/datum/shuttle_destination/target = autopath.get_next_node()
if(walk_path(target))
autopath.walk_path()
// Call this to reset everything related to autopiloting.
/datum/shuttle_web_master/proc/reset_autopath()
autopath = null
my_shuttle.autopilot = FALSE
/*************
* Autopaths *
*************/
// Fourth datum, this one essentially acts as directions for an autopilot to go to the correct places.
/datum/shuttle_autopath
var/datum/shuttle_web_master/master = null
var/datum/shuttle_destination/start = null
var/list/path_nodes = list()
var/index = 1
/datum/shuttle_autopath/Destroy()
master = null
return ..()
/datum/shuttle_autopath/proc/reset_path()
index = 1
/datum/shuttle_autopath/proc/get_next_node()
return path_nodes[index]
/datum/shuttle_autopath/proc/walk_path()
index++
if(index > path_nodes.len)
finish_path()
/datum/shuttle_autopath/proc/finish_path()
reset_path()
master.path_finished(src)