Ports Bay's updated evacuation controller and bluespace jump. (#12445)

This commit is contained in:
Matt Atlas
2021-09-07 17:12:10 +02:00
committed by GitHub
parent 0b6631781a
commit b64224770c
59 changed files with 1137 additions and 597 deletions

View File

@@ -1,308 +0,0 @@
var/datum/controller/subsystem/emergency_shuttle/emergency_shuttle
/datum/controller/subsystem/emergency_shuttle
name = "Emergency Shuttle"
flags = SS_NO_TICK_CHECK | SS_NO_INIT
var/datum/shuttle/autodock/ferry/emergency/shuttle
var/launch_time //the time at which the shuttle will be launched
var/force_time //the time at which the shuttle will be forced
var/auto_recall = 0 //if set, the shuttle will be auto-recalled
var/auto_recall_time //the time at which the shuttle will be auto-recalled
var/evac = 0 //1 = emergency evacuation, 0 = crew transfer
var/wait_for_launch = 0 //if the shuttle is waiting to launch
var/wait_for_force = 0 //if the shuttle is waiting to be forced
var/autopilot = 1 //set to 0 to disable the shuttle automatically launching
var/deny_shuttle = 0 //allows admins to prevent the shuttle from being called
var/departed = 0 //if the shuttle has left the station at least once
/datum/controller/subsystem/emergency_shuttle/Recover()
// Just copy all the stuff over.
src.shuttle = emergency_shuttle.shuttle
src.launch_time = emergency_shuttle.launch_time
src.auto_recall = emergency_shuttle.auto_recall
src.auto_recall_time = emergency_shuttle.auto_recall_time
src.evac = emergency_shuttle.evac
src.wait_for_launch = emergency_shuttle.wait_for_launch
src.autopilot = emergency_shuttle.autopilot
src.deny_shuttle = emergency_shuttle.deny_shuttle
/datum/controller/subsystem/emergency_shuttle/New()
NEW_SS_GLOBAL(emergency_shuttle)
/datum/controller/subsystem/emergency_shuttle/fire()
if(!shuttle)
return
if (wait_for_launch)
if (evac && auto_recall && world.time >= auto_recall_time)
recall()
if (world.time >= launch_time) //time to launch the shuttle
stop_launch_countdown()
if (!shuttle.location) //leaving from the station
//launch the pods!
for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods)
if (!pod.arming_controller || pod.arming_controller.armed)
pod.launch(src)
if (autopilot)
shuttle.launch(src)
if (wait_for_force)
if (world.time > force_time)
stop_force_countdown()
if(waiting_to_leave())
shuttle.launch(src)
shuttle.force_launch(src)
/datum/controller/subsystem/emergency_shuttle/proc/shuttle_arrived()
if (!shuttle.location) //at station
if (autopilot)
set_launch_countdown(SHUTTLE_LEAVETIME) //get ready to return
if (evac)
set_force_countdown(SHUTTLE_FORCETIME)
priority_announcement.Announce(replacetext(current_map.emergency_shuttle_docked_message, "%ETD%", round(estimate_launch_time()/60,1)), new_sound = 'sound/AI/emergencyshuttledock.ogg')
else
set_force_countdown(SHUTTLE_LEAVETIME)
var/list/fields = list(
"%ETA%" = round(emergency_shuttle.estimate_launch_time()/60,1),
"%dock%" = current_map.dock_name
)
priority_announcement.Announce(replacemany(current_map.shuttle_docked_message, fields), new_sound = 'sound/AI/shuttledock.ogg')
//arm the escape pods
if (evac)
for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods)
if (pod.arming_controller)
pod.arming_controller.arm()
//begins the launch countdown and sets the amount of time left until launch
/datum/controller/subsystem/emergency_shuttle/proc/set_launch_countdown(var/seconds)
wait_for_launch = 1
launch_time = world.time + seconds*10
//begins the launch countdown and sets the amount of time left until launch
/datum/controller/subsystem/emergency_shuttle/proc/set_force_countdown(var/seconds)
if(!wait_for_force)
wait_for_force = 1
force_time = world.time + seconds*10
/datum/controller/subsystem/emergency_shuttle/proc/stop_launch_countdown()
wait_for_launch = 0
/datum/controller/subsystem/emergency_shuttle/proc/stop_force_countdown()
wait_for_force = 0
//calls the shuttle for an emergency evacuation
/datum/controller/subsystem/emergency_shuttle/proc/call_evac()
if(!can_call()) return
//set the launch timer
autopilot = 1
set_launch_countdown(get_shuttle_prep_time())
auto_recall_time = rand(world.time + 300, launch_time - 300)
//reset the shuttle transit time if we need to
shuttle.move_time = SHUTTLE_TRANSIT_DURATION
evac = 1
priority_announcement.Announce(replacetext(current_map.emergency_shuttle_called_message, "%ETA%", round(estimate_arrival_time()/60)), new_sound = 'sound/AI/emergencyshuttlecalled.ogg')
for(var/area/A in all_areas)
if(istype(A, /area/hallway))
A.readyalert()
//calls the shuttle for a routine crew transfer
/datum/controller/subsystem/emergency_shuttle/proc/call_transfer()
if(!can_call()) return
//set the launch timer
autopilot = 1
set_launch_countdown(get_shuttle_prep_time())
auto_recall_time = rand(world.time + 300, launch_time - 300)
//reset the shuttle transit time if we need to
shuttle.move_time = SHUTTLE_TRANSIT_DURATION
var/list/replacements = list(
"%ETA%" = round(estimate_arrival_time()/60),
"%dock%" = current_map.dock_name
)
priority_announcement.Announce(replacemany(current_map.shuttle_called_message, replacements), new_sound = 'sound/AI/shuttlecalled.ogg')
//recalls the shuttle
/datum/controller/subsystem/emergency_shuttle/proc/recall()
if (!can_recall()) return
wait_for_launch = 0
shuttle.cancel_launch(src)
if (evac)
priority_announcement.Announce(current_map.emergency_shuttle_recall_message, new_sound = 'sound/AI/emergencyshuttlerecalled.ogg')
for(var/area/A in all_areas)
if(istype(A, /area/hallway))
A.readyreset()
evac = 0
else
priority_announcement.Announce(current_map.shuttle_recall_message, new_sound = 'sound/AI/shuttlerecalled.ogg')
/datum/controller/subsystem/emergency_shuttle/proc/can_call()
if (!universe.OnShuttleCall(null))
return 0
if (deny_shuttle)
return 0
if (shuttle.moving_status != SHUTTLE_IDLE || !shuttle.location) //must be idle at centcom
return 0
if (wait_for_launch) //already launching
return 0
return 1
//this only returns 0 if it would absolutely make no sense to recall
//e.g. the shuttle is already at the station or wasn't called to begin with
//other reasons for the shuttle not being recallable should be handled elsewhere
/datum/controller/subsystem/emergency_shuttle/proc/can_recall()
if (shuttle.moving_status == SHUTTLE_INTRANSIT) //if the shuttle is already in transit then it's too late
return 0
if (!shuttle.location) //already at the station.
return 0
if (!wait_for_launch) //we weren't going anywhere, anyways...
return 0
return 1
/datum/controller/subsystem/emergency_shuttle/proc/get_shuttle_prep_time()
// During mutiny rounds, the shuttle takes twice as long.
if(SSticker.mode)
return SHUTTLE_PREPTIME * SSticker.mode.shuttle_delay
return SHUTTLE_PREPTIME
/*
These procs are not really used by the controller itself, but are for other parts of the
game whose logic depends on the emergency shuttle.
*/
//returns 1 if the shuttle is docked at the station and waiting to leave
/datum/controller/subsystem/emergency_shuttle/proc/waiting_to_leave()
if(!shuttle)
return
if (shuttle.location)
return 0 //not at station
return (wait_for_launch || shuttle.moving_status != SHUTTLE_INTRANSIT)
//so we don't have emergency_shuttle.shuttle.location everywhere
/datum/controller/subsystem/emergency_shuttle/proc/location()
if (!shuttle)
return 1 //if we dont have a shuttle datum, just act like it's at centcom
return shuttle.location
//returns the time left until the shuttle arrives at it's destination, in seconds
/datum/controller/subsystem/emergency_shuttle/proc/estimate_arrival_time()
var/eta
if (shuttle.has_arrive_time())
//we are in transition and can get an accurate ETA
eta = shuttle.arrive_time
else
//otherwise we need to estimate the arrival time using the scheduled launch time
eta = launch_time + shuttle.move_time*10 + shuttle.warmup_time*10
return (eta - world.time)/10
//returns the time left until the shuttle launches, in seconds
/datum/controller/subsystem/emergency_shuttle/proc/estimate_launch_time()
return (launch_time - world.time)/10
/datum/controller/subsystem/emergency_shuttle/proc/has_eta()
if(!shuttle)
return
return (wait_for_launch || shuttle.moving_status != SHUTTLE_IDLE)
//returns 1 if the shuttle has gone to the station and come back at least once,
//used for game completion checking purposes
/datum/controller/subsystem/emergency_shuttle/proc/returned()
return (departed && shuttle.moving_status == SHUTTLE_IDLE && shuttle.location) //we've gone to the station at least once, no longer in transit and are idle back at centcom
//returns 1 if the shuttle is not idle at centcom
/datum/controller/subsystem/emergency_shuttle/proc/online()
if (isnull(shuttle))
return FALSE
if (!shuttle.location) //not at centcom
return TRUE
if (wait_for_launch || shuttle.moving_status != SHUTTLE_IDLE)
return TRUE
return FALSE
//returns 1 if the shuttle is currently in transit (or just leaving) to the station
/datum/controller/subsystem/emergency_shuttle/proc/going_to_station()
return (!shuttle.direction && shuttle.moving_status != SHUTTLE_IDLE)
//returns 1 if the shuttle is currently in transit (or just leaving) to centcom
/datum/controller/subsystem/emergency_shuttle/proc/going_to_centcom()
return (shuttle && shuttle.direction && shuttle.moving_status != SHUTTLE_IDLE)
/datum/controller/subsystem/emergency_shuttle/proc/get_status_panel_eta()
if (online())
if (shuttle.has_arrive_time())
var/timeleft = emergency_shuttle.estimate_arrival_time()
return "ETA-[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]"
if (waiting_to_leave())
if (shuttle.moving_status == SHUTTLE_WARMUP)
return "Departing..."
var/timeleft = emergency_shuttle.estimate_launch_time()
return "ETD-[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]"
return ""
/*
Some slapped-together star effects for maximum spess immershuns. Basically consists of a
spawner, an ender, and bgstar. Spawners create bgstars, bgstars shoot off into a direction
until they reach a starender.
*/
/obj/effect/bgstar
name = "star"
var/speed = 10
var/direction = SOUTH
layer = 2 // TURF_LAYER
/obj/effect/bgstar/New()
..()
pixel_x += rand(-2,30)
pixel_y += rand(-2,30)
var/starnum = pick("1", "1", "1", "2", "3", "4")
icon_state = "star"+starnum
speed = rand(2, 5)
/obj/effect/bgstar/proc/startmove()
while(src)
sleep(speed)
step(src, direction)
for(var/obj/effect/starender/E in loc)
qdel(src)
return
/obj/effect/starender
invisibility = 101
/obj/effect/starspawner
invisibility = 101
var/spawndir = SOUTH
var/spawning = 0
/obj/effect/starspawner/West
spawndir = WEST
/obj/effect/starspawner/proc/startspawn()
spawning = 1
while(spawning)
sleep(rand(2, 30))
var/obj/effect/bgstar/S = new/obj/effect/bgstar(locate(x,y,z))
S.direction = spawndir
spawn()
S.startmove()

View File

@@ -0,0 +1,17 @@
var/datum/controller/subsystem/evac/SSevac
/datum/controller/subsystem/evac
name = "Evacuation"
priority = SS_PRIORITY_EVAC
//Initializes at default time
flags = SS_NO_TICK_CHECK|SS_BACKGROUND
wait = 2 SECONDS
/datum/controller/subsystem/evac/Initialize()
. = ..()
if(!evacuation_controller)
evacuation_controller = new current_map.evac_controller_type ()
evacuation_controller.set_up()
/datum/controller/subsystem/evac/fire()
evacuation_controller.process()

View File

@@ -0,0 +1,183 @@
#define EVAC_IDLE 0
#define EVAC_PREPPING 1
#define EVAC_LAUNCHING 2
#define EVAC_IN_TRANSIT 3
#define EVAC_COOLDOWN 4
#define EVAC_COMPLETE 5
var/datum/evacuation_controller/evacuation_controller
/datum/evacuation_controller
var/name = "generic evac controller"
var/state = EVAC_IDLE
var/deny
var/recall
var/auto_recall_time
var/emergency_evacuation
var/evac_prep_delay = 10 MINUTES
var/evac_launch_delay = 3 MINUTES
var/evac_transit_delay = 2 MINUTES
var/autotransfer_prep_additional_delay = 0 MINUTES
var/emergency_prep_additional_delay = 0 MINUTES
var/transfer_prep_additional_delay = 0 MINUTES
var/force_time = 0 MINUTES
var/wait_for_force = FALSE //If the evac is waiting to be forced
var/evac_cooldown_time
var/evac_called_at
var/evac_no_return
var/evac_ready_time
var/evac_launch_time
var/evac_arrival_time
var/list/evacuation_predicates = list()
var/list/evacuation_options = list()
var/datum/announcement/priority/evac_waiting = new(0)
var/datum/announcement/priority/evac_called = new(0)
var/datum/announcement/priority/evac_recalled = new(0)
/datum/evacuation_controller/proc/auto_recall(var/_recall)
recall = _recall
/datum/evacuation_controller/proc/set_up()
set waitfor=0
set background=1
/datum/evacuation_controller/proc/get_cooldown_message()
return "An evacuation cannot be called at this time. Please wait another [round((evac_cooldown_time-world.time)/600)] minute\s before trying again."
/datum/evacuation_controller/proc/add_can_call_predicate(var/datum/evacuation_predicate/esp)
if(esp in evacuation_predicates)
CRASH("[esp] has already been added as an evacuation predicate")
evacuation_predicates += esp
/datum/evacuation_controller/proc/call_evacuation(var/mob/user, var/_emergency_evac, var/forced, var/skip_announce, var/autotransfer)
if(state != EVAC_IDLE)
return FALSE
if(!can_evacuate(user, forced))
return FALSE
emergency_evacuation = _emergency_evac
var/evac_prep_delay_multiplier = 1
if(SSticker.mode)
evac_prep_delay_multiplier = SSticker.mode.shuttle_delay
var/additional_delay
if(_emergency_evac)
additional_delay = emergency_prep_additional_delay
else if(autotransfer)
additional_delay = autotransfer_prep_additional_delay
else
additional_delay = transfer_prep_additional_delay
evac_called_at = world.time
evac_no_return = evac_called_at + round(evac_prep_delay/2) + additional_delay
evac_ready_time = evac_called_at + (evac_prep_delay*evac_prep_delay_multiplier) + additional_delay
evac_launch_time = evac_ready_time + evac_launch_delay
evac_arrival_time = evac_launch_time + evac_transit_delay
var/evac_range = round((evac_launch_time - evac_called_at)/3)
auto_recall_time = rand(evac_called_at + evac_range, evac_launch_time - evac_range)
state = EVAC_PREPPING
if(emergency_evacuation)
for(var/area/A in all_areas)
if(istype(A, /area/hallway))
A.readyalert()
if(!skip_announce)
priority_announcement.Announce(replacetext(replacetext(current_map.emergency_shuttle_called_message, "%dock%", "[current_map.dock_name]"), "%ETA%", "[round(get_eta()/60)] minute\s"), new_sound = 'sound/AI/emergencyshuttlecalled.ogg')
else
if(!skip_announce)
priority_announcement.Announce(replacetext(replacetext(current_map.shuttle_called_message, "%dock%", "[current_map.dock_name]"), "%ETA%", "[round(get_eta()/60)] minute\s"), new_sound = 'sound/AI/shuttlecalled.ogg')
return TRUE
/datum/evacuation_controller/proc/cancel_evacuation()
if(!can_cancel())
return FALSE
evac_cooldown_time = world.time + (world.time - evac_called_at)
state = EVAC_COOLDOWN
evac_ready_time = null
evac_arrival_time = null
evac_no_return = null
evac_called_at = null
evac_launch_time = null
auto_recall_time = null
if(emergency_evacuation)
evac_recalled.Announce(current_map.emergency_shuttle_recall_message)
for(var/area/A in all_areas)
if(istype(A, /area/hallway))
A.readyreset()
emergency_evacuation = 0
else
priority_announcement.Announce(current_map.shuttle_recall_message)
return TRUE
/datum/evacuation_controller/proc/finish_preparing_evac()
state = EVAC_LAUNCHING
var/estimated_time = round(get_eta()/60,1)
if (emergency_evacuation)
evac_waiting.Announce(replacetext(current_map.emergency_shuttle_docked_message, "%ETA%", "[estimated_time] minute\s"), new_sound = sound('sound/AI/emergencyshuttledock.ogg'))
else
priority_announcement.Announce(replacetext(replacetext(current_map.shuttle_docked_message, "%dock%", "[current_map.dock_name]"), "%ETA%", "[estimated_time] minute\s"), new_sound = sound('sound/AI/shuttledock.ogg'))
/datum/evacuation_controller/proc/launch_evacuation()
if(waiting_to_leave())
return
state = EVAC_IN_TRANSIT
if (emergency_evacuation)
priority_announcement.Announce(replacetext(replacetext(current_map.emergency_shuttle_leaving_dock, "%dock%", "[current_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s"))
else
priority_announcement.Announce(replacetext(replacetext(current_map.shuttle_leaving_dock, "%dock%", "[current_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s"))
return TRUE
/datum/evacuation_controller/proc/finish_evacuation()
state = EVAC_COMPLETE
/datum/evacuation_controller/process()
if(state == EVAC_PREPPING && recall && world.time >= auto_recall_time)
cancel_evacuation()
return
if(state == EVAC_PREPPING)
if(world.time >= evac_ready_time)
finish_preparing_evac()
else if(state == EVAC_LAUNCHING)
if(world.time >= evac_launch_time)
launch_evacuation()
else if(state == EVAC_IN_TRANSIT)
if(world.time >= evac_arrival_time)
finish_evacuation()
else if(state == EVAC_COOLDOWN)
if(world.time >= evac_cooldown_time)
state = EVAC_IDLE
/datum/evacuation_controller/proc/available_evac_options()
return list()
/datum/evacuation_controller/proc/handle_evac_option(var/option_target, var/mob/user)
var/datum/evacuation_option/selected = evacuation_options[option_target]
if (!isnull(selected) && istype(selected))
selected.execute(user)
/datum/evacuation_controller/proc/get_evac_option(var/option_target)
return null
/datum/evacuation_controller/proc/should_call_autotransfer_vote()
return (state == EVAC_IDLE)

View File

@@ -0,0 +1,22 @@
/datum/evacuation_controller/proc/get_status_panel_eta()
if(waiting_to_leave())
return "Delayed"
var/timeleft = get_eta()
if(timeleft < 0)
return ""
return "[is_on_cooldown() ? "Returning" : (is_arriving() ? "ETA" : "ETD")] [add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]"
/datum/evacuation_controller/proc/has_eta()
return (state == EVAC_PREPPING || state == EVAC_LAUNCHING || state == EVAC_IN_TRANSIT || state == EVAC_COOLDOWN)
/datum/evacuation_controller/proc/get_eta()
if(state == EVAC_PREPPING)
return (evac_ready_time ? (evac_ready_time - world.time)/10 : -1)
else if(state == EVAC_LAUNCHING)
return (evac_launch_time ? (evac_launch_time - world.time)/10 : -1)
else if(state == EVAC_IN_TRANSIT)
return (evac_arrival_time ? (evac_arrival_time - world.time)/10 : -1)
else if(state == EVAC_COOLDOWN)
return (evac_cooldown_time ? (evac_cooldown_time - world.time)/10 : -1)
return -1

View File

@@ -0,0 +1,68 @@
/datum/evacuation_controller/proc/set_launch_time(var/val)
evac_launch_time = val
/datum/evacuation_controller/proc/set_arrival_time(var/val)
evac_arrival_time = val
/datum/evacuation_controller/proc/is_prepared()
return (state == EVAC_LAUNCHING)
/datum/evacuation_controller/proc/is_in_transit()
return (state == EVAC_IN_TRANSIT)
/datum/evacuation_controller/proc/is_idle()
return (state == EVAC_IDLE)
/datum/evacuation_controller/proc/has_evacuated()
return (!isnull(evac_launch_time) && world.time > evac_launch_time)
/datum/evacuation_controller/proc/round_over()
return state == EVAC_COMPLETE
/datum/evacuation_controller/proc/is_on_cooldown()
return state == EVAC_COOLDOWN
/datum/evacuation_controller/proc/is_evacuating()
return state != EVAC_IDLE
/datum/evacuation_controller/proc/can_evacuate(var/mob/user, var/forced)
if(!isnull(evac_called_at))
return FALSE
if (!universe.OnShuttleCall(null))
return FALSE
if(!forced)
for(var/predicate in evacuation_predicates)
var/datum/evacuation_predicate/esp = predicate
if(!esp.is_valid())
evacuation_predicates -= esp
qdel(esp)
else
if(!esp.can_call(user))
return FALSE
return TRUE
/datum/evacuation_controller/proc/waiting_to_leave()
return FALSE
/datum/evacuation_controller/proc/can_cancel()
// Are we evacuating?
if(isnull(evac_called_at))
return FALSE
// Have we already launched?
if(state != EVAC_PREPPING)
return FALSE
// Are we already committed?
if(world.time > evac_no_return)
return FALSE
return TRUE
/datum/evacuation_controller/proc/is_arriving()
if(state == EVAC_LAUNCHING)
return FALSE
return has_eta()
/datum/evacuation_controller/proc/is_departing()
if(state == EVAC_LAUNCHING)
return TRUE

View File

@@ -0,0 +1,28 @@
#define EVAC_OPT_ABANDON_SHIP "abandon_ship"
#define EVAC_OPT_CANCEL_ABANDON_SHIP "cancel_abandon_ship"
/datum/evacuation_controller/lifepods
name = "escape pod controller"
evac_prep_delay = 7 MINUTES
evac_launch_delay = 0
evac_transit_delay = 2 MINUTES
evacuation_options = list(
EVAC_OPT_ABANDON_SHIP = new /datum/evacuation_option/abandon_ship(),
EVAC_OPT_CANCEL_ABANDON_SHIP = new /datum/evacuation_option/cancel_abandon_ship(),
)
/datum/evacuation_controller/lifepods/launch_evacuation()
priority_announcement.Announce(replacetext(replacetext(current_map.emergency_shuttle_leaving_dock, "%dock_name%", "[current_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s"))
/datum/evacuation_controller/lifepods/available_evac_options()
if (is_on_cooldown())
return list()
if (is_idle())
return list(evacuation_options[EVAC_OPT_ABANDON_SHIP])
if (is_evacuating())
return list(evacuation_options[EVAC_OPT_CANCEL_ABANDON_SHIP])
#undef EVAC_OPT_ABANDON_SHIP
#undef EVAC_OPT_CANCEL_ABANDON_SHIP

View File

@@ -0,0 +1,10 @@
/datum/evacuation_option
var/option_text = "Generic evac option"
var/option_desc = "do something that should never be seen"
var/option_target = "generic"
var/needs_syscontrol = FALSE
var/silicon_allowed = TRUE
var/abandon_ship = FALSE
/datum/evacuation_option/proc/execute(var/mob/user)
return

View File

@@ -0,0 +1,145 @@
#define EVAC_OPT_ABANDON_SHIP "abandon_ship"
#define EVAC_OPT_BLUESPACE_JUMP "bluespace_jump"
#define EVAC_OPT_CANCEL_ABANDON_SHIP "cancel_abandon_ship"
#define EVAC_OPT_CANCEL_BLUESPACE_JUMP "cancel_bluespace_jump"
// Apparently, emergency_evacuation --> "abandon ship" and !emergency_evacuation --> "bluespace jump"
// That stuff should be moved to the evacuation option datums but someone can do that later
/datum/evacuation_controller/starship
name = "escape pod controller"
evac_prep_delay = 5 MINUTES
evac_launch_delay = 3 MINUTES
evac_transit_delay = 2 MINUTES
transfer_prep_additional_delay = 5 MINUTES
autotransfer_prep_additional_delay = 5 MINUTES
emergency_prep_additional_delay = 0 MINUTES
evacuation_options = list(
EVAC_OPT_ABANDON_SHIP = new /datum/evacuation_option/abandon_ship(),
EVAC_OPT_BLUESPACE_JUMP = new /datum/evacuation_option/bluespace_jump(),
EVAC_OPT_CANCEL_ABANDON_SHIP = new /datum/evacuation_option/cancel_abandon_ship(),
EVAC_OPT_CANCEL_BLUESPACE_JUMP = new /datum/evacuation_option/cancel_bluespace_jump()
)
/datum/evacuation_controller/starship/finish_preparing_evac()
. = ..()
// Arm the escape pods.
if (emergency_evacuation)
for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods)
if (pod.arming_controller)
pod.arming_controller.arm()
/datum/evacuation_controller/starship/launch_evacuation()
state = EVAC_IN_TRANSIT
if (emergency_evacuation)
// Abondon Ship
for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods) // Launch the pods!
if (!pod.arming_controller || pod.arming_controller.armed)
pod.move_time = (evac_transit_delay/10)
pod.launch(src)
priority_announcement.Announce(replacetext(replacetext(current_map.emergency_shuttle_leaving_dock, "%dock_name%", "[current_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s"))
else
// Bluespace Jump
priority_announcement.Announce(replacetext(replacetext(current_map.shuttle_leaving_dock, "%dock_name%", "[current_map.dock_name]"), "%ETA%", "[round(get_eta()/60,1)] minute\s"))
SetUniversalState(/datum/universal_state/bluespace_jump, arguments=list(current_map.station_levels))
/datum/evacuation_controller/starship/finish_evacuation()
..()
if(!emergency_evacuation) //bluespace jump
SetUniversalState(/datum/universal_state) //clear jump state
/datum/evacuation_controller/starship/available_evac_options()
if (is_on_cooldown())
return list()
if (is_idle())
return list(evacuation_options[EVAC_OPT_BLUESPACE_JUMP], evacuation_options[EVAC_OPT_ABANDON_SHIP])
if (is_evacuating())
if (emergency_evacuation)
return list(evacuation_options[EVAC_OPT_CANCEL_ABANDON_SHIP])
else
return list(evacuation_options[EVAC_OPT_CANCEL_BLUESPACE_JUMP])
/datum/evacuation_option/abandon_ship
option_text = "Abandon spacecraft"
option_desc = "abandon the spacecraft"
option_target = EVAC_OPT_ABANDON_SHIP
needs_syscontrol = TRUE
silicon_allowed = TRUE
abandon_ship = TRUE
/datum/evacuation_option/abandon_ship/execute(mob/user)
if (!evacuation_controller)
return
if (evacuation_controller.deny)
to_chat(user, "Unable to initiate escape procedures.")
return
if (evacuation_controller.is_on_cooldown())
to_chat(user, evacuation_controller.get_cooldown_message())
return
if (evacuation_controller.is_evacuating())
to_chat(user, "Escape procedures already in progress.")
return
if (evacuation_controller.call_evacuation(user, 1))
log_and_message_admins("[user? key_name(user) : "Autotransfer"] has initiated abandonment of the spacecraft.")
/datum/evacuation_option/bluespace_jump
option_text = "Initiate bluespace jump"
option_desc = "initiate a bluespace jump"
option_target = EVAC_OPT_BLUESPACE_JUMP
needs_syscontrol = TRUE
silicon_allowed = TRUE
/datum/evacuation_option/bluespace_jump/execute(mob/user)
if (!evacuation_controller)
return
if (evacuation_controller.deny)
to_chat(user, "Unable to initiate jump preparation.")
return
if (evacuation_controller.is_on_cooldown())
to_chat(user, evacuation_controller.get_cooldown_message())
return
if (evacuation_controller.is_evacuating())
to_chat(user, "Jump preparation already in progress.")
return
if (evacuation_controller.call_evacuation(user, 0))
log_and_message_admins("[user? key_name(user) : "Autotransfer"] has initiated bluespace jump preparation.")
/datum/evacuation_option/cancel_abandon_ship
option_text = "Cancel abandonment"
option_desc = "cancel abandonment of the spacecraft"
option_target = EVAC_OPT_CANCEL_ABANDON_SHIP
needs_syscontrol = TRUE
silicon_allowed = FALSE
/datum/evacuation_option/cancel_abandon_ship/execute(mob/user)
if (evacuation_controller && evacuation_controller.cancel_evacuation())
log_and_message_admins("[key_name(user)] has cancelled abandonment of the spacecraft.")
/datum/evacuation_option/cancel_bluespace_jump
option_text = "Cancel bluespace jump"
option_desc = "cancel the jump preparation"
option_target = EVAC_OPT_CANCEL_BLUESPACE_JUMP
needs_syscontrol = TRUE
silicon_allowed = FALSE
/datum/evacuation_option/cancel_bluespace_jump/execute(mob/user)
if (evacuation_controller && evacuation_controller.cancel_evacuation())
log_and_message_admins("[key_name(user)] has cancelled the bluespace jump.")
/obj/screen/fullscreen/bluespace_overlay
icon = 'icons/effects/effects.dmi'
icon_state = "mfoam"
screen_loc = "WEST,SOUTH to EAST,NORTH"
color = "#ff9900"
blend_mode = BLEND_SUBTRACT
layer = SCREEN_LAYER
#undef EVAC_OPT_ABANDON_SHIP
#undef EVAC_OPT_BLUESPACE_JUMP
#undef EVAC_OPT_CANCEL_ABANDON_SHIP
#undef EVAC_OPT_CANCEL_BLUESPACE_JUMP

View File

@@ -0,0 +1,13 @@
/datum/evacuation_predicate/New()
return
/datum/evacuation_predicate/Destroy(forced)
if(forced)
return ..()
return QDEL_HINT_LETMELIVE
/datum/evacuation_predicate/proc/is_valid()
return FALSE
/datum/evacuation_predicate/proc/can_call(var/user)
return TRUE

View File

@@ -0,0 +1,149 @@
#define EVAC_OPT_CALL_SHUTTLE "call_shuttle"
#define EVAC_OPT_RECALL_SHUTTLE "recall_shuttle"
/datum/evacuation_controller/shuttle
name = "escape shuttle controller"
evac_waiting = new(0, new_sound = sound('sound/AI/shuttledock.ogg'))
evac_called = new(0, new_sound = sound('sound/AI/shuttlecalled.ogg'))
evac_recalled = new(0, new_sound = sound('sound/AI/shuttlerecalled.ogg'))
emergency_prep_additional_delay = 0 MINUTES
transfer_prep_additional_delay = 0 MINUTES
evacuation_options = list(
EVAC_OPT_CALL_SHUTTLE = new /datum/evacuation_option/call_shuttle(),
EVAC_OPT_RECALL_SHUTTLE = new /datum/evacuation_option/recall_shuttle()
)
var/departed = 0
var/autopilot = 1
var/datum/shuttle/autodock/ferry/emergency/shuttle // Set in shuttle_emergency.dm
var/shuttle_launch_time
/datum/evacuation_controller/shuttle/has_evacuated()
return departed
/datum/evacuation_controller/shuttle/waiting_to_leave()
return (!autopilot || (shuttle && shuttle.is_launching()))
/datum/evacuation_controller/shuttle/launch_evacuation()
if(waiting_to_leave())
return
for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods)
if (!pod.arming_controller || pod.arming_controller.armed)
pod.move_time = evac_transit_delay
pod.launch(src)
if(autopilot && shuttle.moving_status == SHUTTLE_IDLE)
evac_arrival_time = world.time + (shuttle.move_time*10) + (shuttle.warmup_time*10)
shuttle.launch(src)
// Announcements, state changes and such are handled by the shuttle itself to prevent desync.
/datum/evacuation_controller/shuttle/finish_preparing_evac()
departed = 1
evac_launch_time = world.time + evac_launch_delay
set_force_countdown(SHUTTLE_FORCETIME)
. = ..()
// Arm the escape pods.
if (emergency_evacuation)
for (var/datum/shuttle/autodock/ferry/escape_pod/pod in escape_pods)
if (pod.arming_controller)
pod.arming_controller.arm()
/datum/evacuation_controller/shuttle/call_evacuation(var/mob/user, var/_emergency_evac, var/forced, var/skip_announce, var/autotransfer)
if(..())
autopilot = 1
shuttle_launch_time = evac_no_return
evac_ready_time += shuttle.warmup_time*10
return 1
return 0
/datum/evacuation_controller/shuttle/cancel_evacuation()
if(..() && shuttle.moving_status != SHUTTLE_INTRANSIT)
shuttle_launch_time = null
shuttle.cancel_launch(src)
return 1
return 0
/datum/evacuation_controller/shuttle/get_eta()
if (shuttle && shuttle.has_arrive_time())
return (shuttle.arrive_time-world.time)/10
return ..()
/datum/evacuation_controller/shuttle/get_status_panel_eta()
if(has_eta() && waiting_to_leave())
return "Launching..."
return ..()
// This is largely handled by the emergency shuttle datum.
/datum/evacuation_controller/shuttle/process()
if(state == EVAC_PREPPING)
if(!isnull(shuttle_launch_time) && world.time > shuttle_launch_time && shuttle.moving_status == SHUTTLE_IDLE)
shuttle.launch()
shuttle_launch_time = null
return
else if(state == EVAC_IN_TRANSIT)
return
return ..()
/datum/evacuation_controller/shuttle/can_cancel()
return (shuttle.moving_status == SHUTTLE_IDLE && shuttle.location && ..())
/datum/evacuation_controller/shuttle/proc/shuttle_leaving()
state = EVAC_IN_TRANSIT
/datum/evacuation_controller/shuttle/proc/shuttle_evacuated()
state = EVAC_COMPLETE
/datum/evacuation_controller/shuttle/proc/shuttle_preparing()
state = EVAC_PREPPING
/datum/evacuation_controller/shuttle/proc/get_long_jump_time()
if (shuttle.location)
return round(evac_prep_delay/10)/2
else
return round(evac_transit_delay/10)
//begins the launch countdown and sets the amount of time left until launch
/datum/evacuation_controller/proc/set_force_countdown(var/seconds)
if(!wait_for_force)
wait_for_force = TRUE
force_time = world.time + seconds*10
/datum/evacuation_controller/proc/stop_force_countdown()
wait_for_force = TRUE
/datum/evacuation_controller/shuttle/available_evac_options()
if (!shuttle.location)
return list()
if (is_idle())
return list(evacuation_options[EVAC_OPT_CALL_SHUTTLE])
else
return list(evacuation_options[EVAC_OPT_RECALL_SHUTTLE])
/datum/evacuation_option/call_shuttle
option_text = "Call emergency shuttle"
option_desc = "call the emergency shuttle"
option_target = EVAC_OPT_CALL_SHUTTLE
needs_syscontrol = TRUE
silicon_allowed = TRUE
/datum/evacuation_option/call_shuttle/execute(mob/user)
call_shuttle_proc(user)
/datum/evacuation_option/recall_shuttle
option_text = "Cancel shuttle call"
option_desc = "recall the emergency shuttle"
option_target = EVAC_OPT_RECALL_SHUTTLE
needs_syscontrol = TRUE
silicon_allowed = FALSE
/datum/evacuation_option/recall_shuttle/execute(mob/user)
cancel_call_proc(user)
#undef EVAC_OPT_CALL_SHUTTLE
#undef EVAC_OPT_RECALL_SHUTTLE

View File

@@ -0,0 +1,5 @@
#undef EVAC_IDLE
#undef EVAC_PREPPING
#undef EVAC_IN_TRANSIT
#undef EVAC_COOLDOWN
#undef EVAC_COMPLETE

View File

@@ -351,7 +351,7 @@
SearchVar(SScargo)
SearchVar(SSeconomy)
SearchVar(SSeffects)
SearchVar(emergency_shuttle)
SearchVar(evacuation_controller)
SearchVar(SSevents)
SearchVar(SSexplosives)
SearchVar(SSgarbage)

View File

@@ -168,10 +168,10 @@ var/datum/controller/subsystem/ticker/SSticker
game_finished = TRUE
mode_finished = TRUE
else if(config.continous_rounds)
game_finished = (emergency_shuttle.returned() || mode.station_was_nuked)
game_finished = (evacuation_controller.round_over() || mode.station_was_nuked)
mode_finished = (!post_game && mode.check_finished())
else
game_finished = (mode.check_finished() || (emergency_shuttle.returned() && emergency_shuttle.evac == 1)) || universe_has_ended
game_finished = (mode.check_finished() || (evacuation_controller.round_over() && evacuation_controller.emergency_evacuation)) || universe_has_ended
mode_finished = game_finished
if(!mode.explosion_in_progress && game_finished && (mode_finished || post_game))
@@ -243,7 +243,7 @@ var/datum/controller/subsystem/ticker/SSticker
if(Player.mind && !isnewplayer(Player))
if(Player.stat != DEAD)
var/turf/playerTurf = get_turf(Player)
if(emergency_shuttle.departed && emergency_shuttle.evac)
if(evacuation_controller.round_over() && evacuation_controller.emergency_evacuation)
if(isNotAdminLevel(playerTurf.z))
to_chat(Player, "<span class='notice'><b>You managed to survive, but were marooned on [station_name()] as [Player.real_name]...</b></span>")
else