Files
CHOMPStation2/code/modules/shuttles/shuttles_web.dm
Neerti d0d6689263 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.
2018-01-14 14:03:58 -05:00

382 lines
13 KiB
Plaintext

//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 = 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()
qdel(web_master)
return ..()
/datum/shuttle/web_shuttle/current_dock_target()
if(web_master)
return web_master.current_dock_target()
/datum/shuttle/web_shuttle/move(var/area/origin, var/area/destination)
..()
last_move = world.time
/datum/shuttle/web_shuttle/on_shuttle_departure()
web_master.on_shuttle_departure()
/datum/shuttle/web_shuttle/on_shuttle_arrival()
web_master.on_shuttle_arrival()
/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"
icon_keyboard = "flight_center_key"
icon_screen = "flight_center"
// Fairly copypasta-y.
/obj/machinery/computer/shuttle_control/web/attack_hand(mob/user)
if(..(user))
return
src.add_fingerprint(user)
ui_interact(user)
/*
// If nanoUI falls over and you want a non-nanoUI UI, feel free to uncomment this section.
var/datum/shuttle/web_shuttle/WS = shuttle_controller.shuttles[shuttle_tag]
if(!istype(WS))
message_admins("ERROR: Shuttle computer ([src]) ([shuttle_tag]) could not find their shuttle in the shuttles list.")
return
var/list/dat = list()
dat += "<center>[shuttle_tag] Ship Control<hr>"
if(WS.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((WS.last_move + WS.cooldown) > world.time)
dat += "<font color='red'>Engines charging.</font><br>"
else
dat += "<font color='green'>Engines ready.</font><br>"
if(WS.can_cloak)
dat += "<br><b><A href='?src=\ref[src];toggle_cloak=[1]'>Toggle cloaking field</A></b><br>"
for(var/datum/shuttle_route/route in WS.current_destination.routes)
dat += "<b><a href='?src=\ref[src];traverse=\ref[route]'>[route.display_route(WS.current_destination)]</a></b><br>"
//Docking
dat += "<br><br>"
if(WS.skip_docking_checks())
dat += "Docking Status: <font color='grey'>Not in use.</font>"
else
var/override_en = WS.docking_controller.override_enabled
var/docking_status = WS.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.Join(), "window=[shuttle_tag]shuttlecontrol;size=300x300")
*/
/obj/machinery/computer/shuttle_control/web/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
var/list/routes[0]
var/datum/shuttle/web_shuttle/shuttle = shuttle_controller.shuttles[shuttle_tag]
if(!istype(shuttle))
return
var/list/R = shuttle.web_master.get_available_routes()
for (var/i = 1 to length(R))
var/datum/shuttle_route/route = R[i]
var/travel_time = null
var/travel_modifier = shuttle.flight_time_modifier
if(route.travel_time == 0)
travel_time = "Instant"
else if( (route.travel_time * travel_modifier) >= 1 MINUTE)
travel_time = "[ (route.travel_time * travel_modifier) / (1 MINUTE)] minute\s"
else
travel_time = "[ (route.travel_time * travel_modifier) / (1 SECOND)] second\s"
routes.Add(list(list("name" = html_encode(capitalize(route.display_route(shuttle.web_master.current_destination) )), "index" = i, "travel_time" = travel_time)))
var/shuttle_location = shuttle.web_master.current_destination.name // Destination related, not loc.
var/future_location = null
if(shuttle.web_master.future_destination)
future_location = shuttle.web_master.future_destination.name
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"
// For the progress bar.
var/elapsed_time = world.time - shuttle.depart_time
var/total_time = shuttle.arrive_time - shuttle.depart_time
var/percent_finished = 0
if(total_time) // Need to check or we might divide by zero.
percent_finished = (elapsed_time / total_time) * 100
data = list(
"shuttle_location" = shuttle_location,
"future_location" = future_location,
"shuttle_state" = shuttle_state,
"routes" = routes,
"has_docking" = shuttle.docking_controller? 1 : 0,
"skip_docking" = shuttle.skip_docking_checks(),
"is_moving" = shuttle.moving_status != SHUTTLE_IDLE,
"docking_status" = shuttle.docking_controller? shuttle.docking_controller.get_docking_status() : null,
"docking_override" = shuttle.docking_controller? shuttle.docking_controller.override_enabled : null,
"is_in_transit" = shuttle.has_arrive_time(),
"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,
"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.visible_name] Flight Computer", 470, 500)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/shuttle_control/web/Topic(href, href_list)
if(..())
return 1
usr.set_machine(src)
src.add_fingerprint(usr)
var/datum/shuttle/web_shuttle/WS = shuttle_controller.shuttles[shuttle_tag]
if(!istype(WS))
message_admins("ERROR: Shuttle computer ([src]) ([shuttle_tag]) could not find their shuttle in the shuttles list.")
return
if(href_list["refresh"])
ui_interact(usr)
if (WS.moving_status != SHUTTLE_IDLE)
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"])
if(!WS.can_cloak)
return
WS.cloaked = TRUE
to_chat(usr, "<span class='danger'>Ship stealth systems have been activated. The station will not be warned of our arrival.</span>")
if(href_list["uncloak_command"])
if(!WS.can_cloak)
return
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
var/index = text2num(href_list["traverse"])
var/datum/shuttle_route/new_route = WS.web_master.current_destination.routes[index]
if(!istype(new_route))
message_admins("ERROR: Shuttle computer was asked to traverse a nonexistant route.")
return
if(!check_docking(WS))
// updateUsrDialog()
ui_interact(usr)
return
var/datum/shuttle_destination/target_destination = new_route.get_other_side(WS.web_master.current_destination)
if(!istype(target_destination))
message_admins("ERROR: Shuttle computer was asked to travel to a nonexistant destination.")
return
WS.web_master.future_destination = target_destination
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
if(new_route.interim && new_route.travel_time)
WS.long_jump(WS.current_area, target_destination.my_area, new_route.interim, travel_time / 10)
else
WS.short_jump(WS.current_area, target_destination.my_area)
ui_interact(usr)
// Props, for now.
/obj/structure/flight_left
name = "flight computer meters"
desc = "You hope the pilot knows what this does."
icon = 'icons/obj/flight_computer.dmi'
icon_state = "left"
density = TRUE
anchored = TRUE
/obj/structure/flight_right
name = "flight computer panel"
desc = "Probably shouldn't open it."
icon = 'icons/obj/flight_computer.dmi'
icon_state = "right"
density = TRUE
anchored = TRUE