@@ -1,569 +0,0 @@
|
||||
#define TIME_LEFT (SSshuttle.emergency.timeLeft())
|
||||
#define ENGINES_START_TIME 100
|
||||
#define ENGINES_STARTED (SSshuttle.emergency.mode == SHUTTLE_IGNITING)
|
||||
#define IS_DOCKED (SSshuttle.emergency.mode == SHUTTLE_DOCKED || (ENGINES_STARTED))
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle
|
||||
name = "emergency shuttle console"
|
||||
desc = "For shuttle control."
|
||||
icon_screen = "shuttle"
|
||||
icon_keyboard = "tech_key"
|
||||
var/auth_need = 3
|
||||
var/list/authorized = list()
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/attackby(obj/item/I, mob/user,params)
|
||||
if(istype(I, /obj/item/card/id))
|
||||
say("Please equip your ID card into your ID slot to authenticate.")
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.human_adjacent_state)
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "emergency_shuttle_console", name,
|
||||
400, 400, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/ui_data()
|
||||
var/list/data = list()
|
||||
|
||||
data["timer_str"] = SSshuttle.emergency.getTimerStr()
|
||||
data["engines_started"] = ENGINES_STARTED
|
||||
data["authorizations_remaining"] = max((auth_need - authorized.len), 0)
|
||||
var/list/A = list()
|
||||
for(var/i in authorized)
|
||||
var/obj/item/card/id/ID = i
|
||||
var/name = ID.registered_name
|
||||
var/job = ID.assignment
|
||||
|
||||
if(obj_flags & EMAGGED)
|
||||
name = Gibberish(name, 0)
|
||||
job = Gibberish(job, 0)
|
||||
A += list(list("name" = name, "job" = job))
|
||||
data["authorizations"] = A
|
||||
|
||||
data["enabled"] = (IS_DOCKED && !ENGINES_STARTED)
|
||||
data["emagged"] = obj_flags & EMAGGED ? 1 : 0
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/ui_act(action, params, datum/tgui/ui)
|
||||
if(..())
|
||||
return
|
||||
if(ENGINES_STARTED) // past the point of no return
|
||||
return
|
||||
if(!IS_DOCKED) // shuttle computer only has uses when onstation
|
||||
return
|
||||
|
||||
var/mob/user = usr
|
||||
. = FALSE
|
||||
|
||||
var/obj/item/card/id/ID = user.get_idcard(TRUE)
|
||||
|
||||
if(!ID)
|
||||
to_chat(user, "<span class='warning'>You don't have an ID.</span>")
|
||||
return
|
||||
|
||||
if(!(ACCESS_HEADS in ID.access))
|
||||
to_chat(user, "<span class='warning'>The access level of your card is not high enough.</span>")
|
||||
return
|
||||
|
||||
var/old_len = authorized.len
|
||||
|
||||
switch(action)
|
||||
if("authorize")
|
||||
. = authorize(user)
|
||||
|
||||
if("repeal")
|
||||
authorized -= ID
|
||||
|
||||
if("abort")
|
||||
if(authorized.len)
|
||||
// Abort. The action for when heads are fighting over whether
|
||||
// to launch early.
|
||||
authorized.Cut()
|
||||
. = TRUE
|
||||
|
||||
if((old_len != authorized.len) && !ENGINES_STARTED)
|
||||
var/alert = (authorized.len > old_len)
|
||||
var/repeal = (authorized.len < old_len)
|
||||
var/remaining = max(0, auth_need - authorized.len)
|
||||
if(authorized.len && remaining)
|
||||
minor_announce("[remaining] authorizations needed until shuttle is launched early", null, alert)
|
||||
if(repeal)
|
||||
minor_announce("Early launch authorization revoked, [remaining] authorizations needed")
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/proc/authorize(mob/user, source)
|
||||
var/obj/item/card/id/ID = user.get_idcard(TRUE)
|
||||
|
||||
if(ID in authorized)
|
||||
return FALSE
|
||||
for(var/i in authorized)
|
||||
var/obj/item/card/id/other = i
|
||||
if(other.registered_name == ID.registered_name)
|
||||
return FALSE // No using IDs with the same name
|
||||
|
||||
authorized += ID
|
||||
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] has authorized early shuttle launch")
|
||||
log_game("[key_name(user)] has authorized early shuttle launch in [COORD(src)]")
|
||||
// Now check if we're on our way
|
||||
. = TRUE
|
||||
process()
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/process()
|
||||
// Launch check is in process in case auth_need changes for some reason
|
||||
// probably external.
|
||||
. = FALSE
|
||||
if(!SSshuttle.emergency)
|
||||
return
|
||||
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
|
||||
authorized.Cut()
|
||||
obj_flags &= ~EMAGGED
|
||||
|
||||
if(ENGINES_STARTED || (!IS_DOCKED))
|
||||
return .
|
||||
|
||||
// Check to see if we've reached criteria for early launch
|
||||
if((authorized.len >= auth_need) || (obj_flags & EMAGGED))
|
||||
// shuttle timers use 1/10th seconds internally
|
||||
SSshuttle.emergency.setTimer(ENGINES_START_TIME)
|
||||
var/system_error = obj_flags & EMAGGED ? "SYSTEM ERROR:" : null
|
||||
minor_announce("The emergency shuttle will launch in \
|
||||
[TIME_LEFT] seconds", system_error, alert=TRUE)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/emag_act(mob/user)
|
||||
. = ..()
|
||||
|
||||
// How did you even get on the shuttle before it go to the station?
|
||||
if(!IS_DOCKED)
|
||||
return
|
||||
|
||||
if((obj_flags & EMAGGED) || ENGINES_STARTED) //SYSTEM ERROR: THE SHUTTLE WILL LA-SYSTEM ERROR: THE SHUTTLE WILL LA-SYSTEM ERROR: THE SHUTTLE WILL LAUNCH IN 10 SECONDS
|
||||
to_chat(user, "<span class='warning'>The shuttle is already about to launch!</span>")
|
||||
return
|
||||
|
||||
var/time = TIME_LEFT
|
||||
message_admins("[ADMIN_LOOKUPFLW(user.client)] has emagged the emergency shuttle [time] seconds before launch.")
|
||||
log_game("[key_name(user)] has emagged the emergency shuttle in [COORD(src)] [time] seconds before launch.")
|
||||
obj_flags |= EMAGGED
|
||||
SSshuttle.emergency.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL
|
||||
var/datum/species/S = new
|
||||
for(var/i in 1 to 10)
|
||||
// the shuttle system doesn't know who these people are, but they
|
||||
// must be important, surely
|
||||
var/obj/item/card/id/ID = new(src)
|
||||
var/datum/job/J = pick(SSjob.occupations)
|
||||
ID.registered_name = S.random_name(pick(MALE, FEMALE))
|
||||
ID.assignment = J.title
|
||||
|
||||
authorized += ID
|
||||
|
||||
process()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/Destroy()
|
||||
// Our fake IDs that the emag generated are just there for colour
|
||||
// They're not supposed to be accessible
|
||||
|
||||
for(var/obj/item/card/id/ID in src)
|
||||
qdel(ID)
|
||||
if(authorized && authorized.len)
|
||||
authorized.Cut()
|
||||
authorized = null
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/docking_port/mobile/emergency
|
||||
name = "emergency shuttle"
|
||||
id = "emergency"
|
||||
|
||||
dwidth = 9
|
||||
width = 22
|
||||
height = 11
|
||||
dir = EAST
|
||||
port_direction = WEST
|
||||
var/sound_played = 0 //If the launch sound has been sent to all players on the shuttle itself
|
||||
|
||||
/obj/docking_port/mobile/emergency/canDock(obj/docking_port/stationary/S)
|
||||
return SHUTTLE_CAN_DOCK //If the emergency shuttle can't move, the whole game breaks, so it will force itself to land even if it has to crush a few departments in the process
|
||||
|
||||
/obj/docking_port/mobile/emergency/register()
|
||||
. = ..()
|
||||
SSshuttle.emergency = src
|
||||
|
||||
/obj/docking_port/mobile/emergency/Destroy(force)
|
||||
if(force)
|
||||
// This'll make the shuttle subsystem use the backup shuttle.
|
||||
if(src == SSshuttle.emergency)
|
||||
// If we're the selected emergency shuttle
|
||||
SSshuttle.emergencyDeregister()
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signalOrigin, reason, redAlert, set_coefficient=null, silent = FALSE)
|
||||
if(!isnum(set_coefficient))
|
||||
var/security_num = seclevel2num(get_security_level())
|
||||
switch(security_num)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
set_coefficient = 2
|
||||
if(SEC_LEVEL_BLUE)
|
||||
set_coefficient = 1.2
|
||||
if(SEC_LEVEL_AMBER)
|
||||
set_coefficient = 0.8
|
||||
else
|
||||
set_coefficient = 0.5
|
||||
var/call_time = SSshuttle.emergencyCallTime * set_coefficient * engine_coeff
|
||||
switch(mode)
|
||||
// The shuttle can not normally be called while "recalling", so
|
||||
// if this proc is called, it's via admin fiat
|
||||
if(SHUTTLE_RECALL, SHUTTLE_IDLE, SHUTTLE_CALL)
|
||||
mode = SHUTTLE_CALL
|
||||
setTimer(call_time)
|
||||
else
|
||||
return
|
||||
|
||||
SSshuttle.emergencyCallAmount++
|
||||
|
||||
if(prob(70))
|
||||
SSshuttle.emergencyLastCallLoc = signalOrigin
|
||||
else
|
||||
SSshuttle.emergencyLastCallLoc = null
|
||||
|
||||
if(!silent)
|
||||
priority_announce("The emergency shuttle has been called. [redAlert ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.[reason][SSshuttle.emergencyLastCallLoc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ]", null, "shuttlecalled", "Priority")
|
||||
|
||||
/obj/docking_port/mobile/emergency/cancel(area/signalOrigin)
|
||||
if(mode != SHUTTLE_CALL)
|
||||
return
|
||||
if(SSshuttle.emergencyNoRecall)
|
||||
return
|
||||
|
||||
invertTimer()
|
||||
mode = SHUTTLE_RECALL
|
||||
|
||||
if(prob(70))
|
||||
SSshuttle.emergencyLastCallLoc = signalOrigin
|
||||
else
|
||||
SSshuttle.emergencyLastCallLoc = null
|
||||
priority_announce("The emergency shuttle has been recalled.[SSshuttle.emergencyLastCallLoc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", null, "shuttlerecalled", "Priority")
|
||||
|
||||
/obj/docking_port/mobile/emergency/proc/is_hijacked()
|
||||
var/has_people = FALSE
|
||||
var/hijacker_present = FALSE
|
||||
for(var/mob/living/player in GLOB.player_list)
|
||||
if(player.mind)
|
||||
if(player.stat != DEAD)
|
||||
if(issilicon(player)) //Borgs are technically dead anyways
|
||||
continue
|
||||
if(isanimal(player)) //animals don't count
|
||||
continue
|
||||
if(isbrain(player)) //also technically dead
|
||||
continue
|
||||
if(shuttle_areas[get_area(player)])
|
||||
has_people = TRUE
|
||||
var/location = get_turf(player.mind.current)
|
||||
//Non-antag present. Can't hijack.
|
||||
if(!(player.mind.has_antag_datum(/datum/antagonist)) && !istype(location, /turf/open/floor/plasteel/shuttle/red) && !istype(location, /turf/open/floor/mineral/plastitanium/red/brig))
|
||||
return FALSE
|
||||
//Antag present, doesn't stop but let's see if we actually want to hijack
|
||||
var/prevent = FALSE
|
||||
for(var/datum/antagonist/A in player.mind.antag_datums)
|
||||
if(A.can_hijack == HIJACK_HIJACKER)
|
||||
hijacker_present = TRUE
|
||||
prevent = FALSE
|
||||
break //If we have both prevent and hijacker antags assume we want to hijack.
|
||||
else if(A.can_hijack == HIJACK_PREVENT)
|
||||
prevent = TRUE
|
||||
if(prevent)
|
||||
return FALSE
|
||||
|
||||
|
||||
return has_people && hijacker_present
|
||||
|
||||
/obj/docking_port/mobile/emergency/proc/ShuttleDBStuff()
|
||||
set waitfor = FALSE
|
||||
if(!SSdbcore.Connect())
|
||||
return
|
||||
var/datum/DBQuery/query_round_shuttle_name = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET shuttle_name = '[name]' WHERE id = [GLOB.round_id]")
|
||||
query_round_shuttle_name.Execute()
|
||||
qdel(query_round_shuttle_name)
|
||||
|
||||
/obj/docking_port/mobile/emergency/check()
|
||||
if(!timer)
|
||||
return
|
||||
var/time_left = timeLeft(1)
|
||||
|
||||
// The emergency shuttle doesn't work like others so this
|
||||
// ripple check is slightly different
|
||||
if(!ripples.len && (time_left <= SHUTTLE_RIPPLE_TIME) && ((mode == SHUTTLE_CALL) || (mode == SHUTTLE_ESCAPE)))
|
||||
var/destination
|
||||
if(mode == SHUTTLE_CALL)
|
||||
destination = SSshuttle.getDock("emergency_home")
|
||||
else if(mode == SHUTTLE_ESCAPE)
|
||||
destination = SSshuttle.getDock("emergency_away")
|
||||
create_ripples(destination)
|
||||
|
||||
switch(mode)
|
||||
if(SHUTTLE_RECALL)
|
||||
if(time_left <= 0)
|
||||
mode = SHUTTLE_IDLE
|
||||
timer = 0
|
||||
if(SHUTTLE_CALL)
|
||||
if(time_left <= 0)
|
||||
//move emergency shuttle to station
|
||||
if(initiate_docking(SSshuttle.getDock("emergency_home")) != DOCKING_SUCCESS)
|
||||
setTimer(20)
|
||||
return
|
||||
mode = SHUTTLE_DOCKED
|
||||
setTimer(SSshuttle.emergencyDockTime)
|
||||
send2irc("Server", "The Emergency Shuttle has docked with the station.")
|
||||
priority_announce("The Emergency Shuttle has docked with the station. You have [timeLeft(600)] minutes to board the Emergency Shuttle.", null, "shuttledock", "Priority")
|
||||
ShuttleDBStuff()
|
||||
|
||||
|
||||
if(SHUTTLE_DOCKED)
|
||||
if(time_left <= ENGINES_START_TIME)
|
||||
mode = SHUTTLE_IGNITING
|
||||
SSshuttle.checkHostileEnvironment()
|
||||
if(mode == SHUTTLE_STRANDED)
|
||||
return
|
||||
for(var/A in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = A
|
||||
if(M.launch_status == UNLAUNCHED) //Pods will not launch from the mine/planet, and other ships won't launch unless we tell them to.
|
||||
M.check_transit_zone()
|
||||
|
||||
if(SHUTTLE_IGNITING)
|
||||
var/success = TRUE
|
||||
SSshuttle.checkHostileEnvironment()
|
||||
if(mode == SHUTTLE_STRANDED)
|
||||
return
|
||||
|
||||
success &= (check_transit_zone() == TRANSIT_READY)
|
||||
for(var/A in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = A
|
||||
if(M.launch_status == UNLAUNCHED)
|
||||
success &= (M.check_transit_zone() == TRANSIT_READY)
|
||||
if(!success)
|
||||
setTimer(ENGINES_START_TIME)
|
||||
|
||||
if(time_left <= 50 && !sound_played) //4 seconds left:REV UP THOSE ENGINES BOYS. - should sync up with the launch
|
||||
sound_played = 1 //Only rev them up once.
|
||||
var/list/areas = list()
|
||||
for(var/area/shuttle/escape/E in GLOB.sortedAreas)
|
||||
areas += E
|
||||
hyperspace_sound(HYPERSPACE_WARMUP, areas)
|
||||
|
||||
if(time_left <= 0 && !SSshuttle.emergencyNoEscape)
|
||||
//move each escape pod (or applicable spaceship) to its corresponding transit dock
|
||||
for(var/A in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = A
|
||||
M.on_emergency_launch()
|
||||
|
||||
//now move the actual emergency shuttle to its transit dock
|
||||
var/list/areas = list()
|
||||
for(var/area/shuttle/escape/E in GLOB.sortedAreas)
|
||||
areas += E
|
||||
hyperspace_sound(HYPERSPACE_LAUNCH, areas)
|
||||
enterTransit()
|
||||
mode = SHUTTLE_ESCAPE
|
||||
launch_status = ENDGAME_LAUNCHED
|
||||
setTimer(SSshuttle.emergencyEscapeTime * engine_coeff)
|
||||
priority_announce("The Emergency Shuttle has left the station. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, "Priority")
|
||||
|
||||
if(SHUTTLE_STRANDED)
|
||||
SSshuttle.checkHostileEnvironment()
|
||||
|
||||
if(SHUTTLE_ESCAPE)
|
||||
if(sound_played && time_left <= HYPERSPACE_END_TIME)
|
||||
var/list/areas = list()
|
||||
for(var/area/shuttle/escape/E in GLOB.sortedAreas)
|
||||
areas += E
|
||||
hyperspace_sound(HYPERSPACE_END, areas)
|
||||
if(time_left <= PARALLAX_LOOP_TIME)
|
||||
var/area_parallax = FALSE
|
||||
for(var/place in shuttle_areas)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
if(shuttle_area.parallax_movedir)
|
||||
area_parallax = TRUE
|
||||
break
|
||||
if(area_parallax)
|
||||
parallax_slowdown()
|
||||
for(var/A in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = A
|
||||
if(M.launch_status == ENDGAME_LAUNCHED)
|
||||
if(istype(M, /obj/docking_port/mobile/pod))
|
||||
M.parallax_slowdown()
|
||||
|
||||
if(time_left <= 0)
|
||||
//move each escape pod to its corresponding escape dock
|
||||
for(var/A in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = A
|
||||
M.on_emergency_dock()
|
||||
|
||||
// now move the actual emergency shuttle to centcom
|
||||
// unless the shuttle is "hijacked"
|
||||
var/destination_dock = "emergency_away"
|
||||
if(is_hijacked())
|
||||
destination_dock = "emergency_syndicate"
|
||||
minor_announce("Corruption detected in \
|
||||
shuttle navigation protocols. Please contact your \
|
||||
supervisor.", "SYSTEM ERROR:", alert=TRUE)
|
||||
|
||||
dock_id(destination_dock)
|
||||
mode = SHUTTLE_ENDGAME
|
||||
timer = 0
|
||||
|
||||
/obj/docking_port/mobile/emergency/transit_failure()
|
||||
..()
|
||||
message_admins("Moving emergency shuttle directly to centcom dock to prevent deadlock.")
|
||||
|
||||
mode = SHUTTLE_ESCAPE
|
||||
launch_status = ENDGAME_LAUNCHED
|
||||
setTimer(SSshuttle.emergencyEscapeTime)
|
||||
priority_announce("The Emergency Shuttle preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, "Priority")
|
||||
|
||||
|
||||
/obj/docking_port/mobile/pod
|
||||
name = "escape pod"
|
||||
id = "pod"
|
||||
dwidth = 1
|
||||
width = 3
|
||||
height = 4
|
||||
launch_status = UNLAUNCHED
|
||||
|
||||
/obj/docking_port/mobile/pod/request(obj/docking_port/stationary/S)
|
||||
var/obj/machinery/computer/shuttle/C = getControlConsole()
|
||||
if(!istype(C, /obj/machinery/computer/shuttle/pod))
|
||||
return ..()
|
||||
if(GLOB.security_level >= SEC_LEVEL_RED || (C && (C.obj_flags & EMAGGED)))
|
||||
if(launch_status == UNLAUNCHED)
|
||||
launch_status = EARLY_LAUNCHED
|
||||
return ..()
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Escape pods will only launch during \"Code Red\" security alert.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/docking_port/mobile/pod/cancel()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/shuttle/pod
|
||||
name = "pod control computer"
|
||||
admin_controlled = 1
|
||||
possible_destinations = "pod_asteroid"
|
||||
icon = 'icons/obj/terminals.dmi'
|
||||
icon_state = "dorm_available"
|
||||
light_color = LIGHT_COLOR_BLUE
|
||||
density = FALSE
|
||||
clockwork = TRUE //it'd look weird
|
||||
|
||||
/obj/machinery/computer/shuttle/pod/update_icon()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/shuttle/pod/emag_act(mob/user)
|
||||
. = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>You fry the pod's alert level checking system.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/shuttle/pod/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
|
||||
. = ..()
|
||||
if(possible_destinations == initial(possible_destinations) || override)
|
||||
possible_destinations = "pod_lavaland[idnum]"
|
||||
|
||||
/obj/docking_port/stationary/random
|
||||
name = "escape pod"
|
||||
id = "pod"
|
||||
dwidth = 1
|
||||
width = 3
|
||||
height = 4
|
||||
var/target_area = /area/lavaland/surface/outdoors
|
||||
var/edge_distance = 16
|
||||
// Minimal distance from the map edge, setting this too low can result in shuttle landing on the edge and getting "sliced"
|
||||
|
||||
/obj/docking_port/stationary/random/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!mapload)
|
||||
return
|
||||
|
||||
var/list/turfs = get_area_turfs(target_area)
|
||||
var/turf/T = pick(turfs)
|
||||
|
||||
while(turfs.len)
|
||||
if(T.x<edge_distance || T.y<edge_distance || (world.maxx+1-T.x)<edge_distance || (world.maxy+1-T.y)<edge_distance)
|
||||
turfs -= T
|
||||
T = pick(turfs)
|
||||
else
|
||||
forceMove(T)
|
||||
break
|
||||
|
||||
//Pod suits/pickaxes
|
||||
|
||||
|
||||
/obj/item/clothing/head/helmet/space/orange
|
||||
name = "emergency space helmet"
|
||||
icon_state = "syndicate-helm-orange"
|
||||
item_state = "syndicate-helm-orange"
|
||||
|
||||
/obj/item/clothing/suit/space/orange
|
||||
name = "emergency space suit"
|
||||
icon_state = "syndicate-orange"
|
||||
item_state = "syndicate-orange"
|
||||
slowdown = 3
|
||||
|
||||
/obj/item/pickaxe/emergency
|
||||
name = "emergency disembarkation tool"
|
||||
desc = "For extracting yourself from rough landings."
|
||||
|
||||
/obj/item/storage/pod
|
||||
name = "emergency space suits"
|
||||
desc = "A wall mounted safe containing space suits. Will only open in emergencies."
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/storage.dmi'
|
||||
icon_state = "safe"
|
||||
integrity_failure = 100
|
||||
component_type = /datum/component/storage/concrete/emergency
|
||||
|
||||
/obj/item/storage/pod/PopulateContents()
|
||||
new /obj/item/clothing/head/helmet/space/orange(src)
|
||||
new /obj/item/clothing/head/helmet/space/orange(src)
|
||||
new /obj/item/clothing/suit/space/orange(src)
|
||||
new /obj/item/clothing/suit/space/orange(src)
|
||||
new /obj/item/clothing/mask/gas(src)
|
||||
new /obj/item/clothing/mask/gas(src)
|
||||
new /obj/item/tank/internals/oxygen/red(src)
|
||||
new /obj/item/tank/internals/oxygen/red(src)
|
||||
new /obj/item/pickaxe/emergency(src)
|
||||
new /obj/item/pickaxe/emergency(src)
|
||||
new /obj/item/survivalcapsule(src)
|
||||
new /obj/item/storage/toolbox/emergency(src)
|
||||
|
||||
/obj/docking_port/mobile/emergency/backup
|
||||
name = "backup shuttle"
|
||||
id = "backup"
|
||||
dwidth = 2
|
||||
width = 8
|
||||
height = 8
|
||||
dir = EAST
|
||||
|
||||
/obj/docking_port/mobile/emergency/backup/Initialize()
|
||||
// We want to be a valid emergency shuttle
|
||||
// but not be the main one, keep whatever's set
|
||||
// valid.
|
||||
// backup shuttle ignores `timid` because THERE SHOULD BE NO TOUCHING IT
|
||||
var/current_emergency = SSshuttle.emergency
|
||||
. = ..()
|
||||
SSshuttle.emergency = current_emergency
|
||||
SSshuttle.backup_shuttle = src
|
||||
|
||||
/obj/docking_port/mobile/emergency/shuttle_build/register()
|
||||
. = ..()
|
||||
initiate_docking(SSshuttle.getDock("emergency_home"))
|
||||
|
||||
#undef TIME_LEFT
|
||||
#undef ENGINES_START_TIME
|
||||
#undef ENGINES_STARTED
|
||||
#undef IS_DOCKED
|
||||
@@ -1,391 +0,0 @@
|
||||
/*
|
||||
All ShuttleMove procs go here
|
||||
*/
|
||||
|
||||
/************************************Base procs************************************/
|
||||
|
||||
// Called on every turf in the shuttle region, returns a bitflag for allowed movements of that turf
|
||||
// returns the new move_mode (based on the old)
|
||||
/turf/proc/fromShuttleMove(turf/newT, move_mode)
|
||||
if(!(move_mode & MOVE_AREA) || !isshuttleturf(src))
|
||||
return move_mode
|
||||
|
||||
return move_mode | MOVE_TURF | MOVE_CONTENTS
|
||||
|
||||
// Called from the new turf before anything has been moved
|
||||
// Only gets called if fromShuttleMove returns true first
|
||||
// returns the new move_mode (based on the old)
|
||||
/turf/proc/toShuttleMove(turf/oldT, move_mode, obj/docking_port/mobile/shuttle)
|
||||
. = move_mode
|
||||
if(!(. & MOVE_TURF))
|
||||
return
|
||||
|
||||
var/shuttle_dir = shuttle.dir
|
||||
for(var/i in contents)
|
||||
var/atom/movable/thing = i
|
||||
if(ismob(thing))
|
||||
if(isliving(thing))
|
||||
var/mob/living/M = thing
|
||||
if(M.buckled)
|
||||
M.buckled.unbuckle_mob(M, 1)
|
||||
if(M.pulledby)
|
||||
M.pulledby.stop_pulling()
|
||||
M.stop_pulling()
|
||||
M.visible_message("<span class='warning'>[shuttle] slams into [M]!</span>")
|
||||
SSblackbox.record_feedback("tally", "shuttle_gib", 1, M.type)
|
||||
M.gib()
|
||||
|
||||
else //non-living mobs shouldn't be affected by shuttles, which is why this is an else
|
||||
if(istype(thing, /obj/singularity) && !istype(thing, /obj/singularity/narsie)) //it's a singularity but not a god, ignore it.
|
||||
continue
|
||||
if(!thing.anchored)
|
||||
step(thing, shuttle_dir)
|
||||
else
|
||||
qdel(thing)
|
||||
|
||||
// Called on the old turf to move the turf data
|
||||
/turf/proc/onShuttleMove(turf/newT, list/movement_force, move_dir)
|
||||
if(newT == src) // In case of in place shuttle rotation shenanigans.
|
||||
return
|
||||
//Destination turf changes
|
||||
//Baseturfs is definitely a list or this proc wouldnt be called
|
||||
var/shuttle_boundary = baseturfs.Find(/turf/baseturf_skipover/shuttle)
|
||||
if(!shuttle_boundary)
|
||||
CRASH("A turf queued to move via shuttle somehow had no skipover in baseturfs. [src]([type]):[loc]")
|
||||
var/depth = baseturfs.len - shuttle_boundary + 1
|
||||
newT.CopyOnTop(src, 1, depth, TRUE)
|
||||
//Air stuff
|
||||
newT.blocks_air = TRUE
|
||||
newT.air_update_turf(TRUE)
|
||||
blocks_air = TRUE
|
||||
air_update_turf(TRUE)
|
||||
if(isopenturf(newT))
|
||||
var/turf/open/new_open = newT
|
||||
new_open.copy_air_with_tile(src)
|
||||
|
||||
return TRUE
|
||||
|
||||
// Called on the new turf after everything has been moved
|
||||
/turf/proc/afterShuttleMove(turf/oldT, rotation)
|
||||
//Dealing with the turf we left behind
|
||||
oldT.TransferComponents(src)
|
||||
var/shuttle_boundary = baseturfs.Find(/turf/baseturf_skipover/shuttle)
|
||||
if(shuttle_boundary)
|
||||
oldT.ScrapeAway(baseturfs.len - shuttle_boundary + 1)
|
||||
|
||||
if(rotation)
|
||||
shuttleRotate(rotation) //see shuttle_rotate.dm
|
||||
|
||||
return TRUE
|
||||
|
||||
/turf/proc/lateShuttleMove(turf/oldT)
|
||||
blocks_air = initial(blocks_air)
|
||||
air_update_turf(TRUE)
|
||||
oldT.blocks_air = initial(oldT.blocks_air)
|
||||
oldT.air_update_turf(TRUE)
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Called on every atom in shuttle turf contents before anything has been moved
|
||||
// returns the new move_mode (based on the old)
|
||||
// WARNING: Do not leave turf contents in beforeShuttleMove or dock() will runtime
|
||||
/atom/movable/proc/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
return move_mode
|
||||
|
||||
// Called on atoms to move the atom to the new location
|
||||
/atom/movable/proc/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
|
||||
if(newT == oldT) // In case of in place shuttle rotation shenanigans.
|
||||
return
|
||||
|
||||
if(loc != oldT) // This is for multi tile objects
|
||||
return
|
||||
|
||||
loc = newT
|
||||
|
||||
return TRUE
|
||||
|
||||
// Called on atoms after everything has been moved
|
||||
/atom/movable/proc/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
|
||||
var/turf/newT = get_turf(src)
|
||||
if (newT.z != oldT.z)
|
||||
onTransitZ(oldT.z, newT.z)
|
||||
|
||||
if(light)
|
||||
update_light()
|
||||
if(rotation)
|
||||
shuttleRotate(rotation)
|
||||
|
||||
update_parallax_contents()
|
||||
|
||||
return TRUE
|
||||
|
||||
/atom/movable/proc/lateShuttleMove(turf/oldT, list/movement_force, move_dir)
|
||||
if(!movement_force || anchored)
|
||||
return
|
||||
var/throw_force = movement_force["THROW"]
|
||||
if(!throw_force)
|
||||
return
|
||||
var/turf/target = get_edge_target_turf(src, move_dir)
|
||||
var/range = throw_force * 10
|
||||
range = CEILING(rand(range-(range*0.1), range+(range*0.1)), 10)/10
|
||||
var/speed = range/5
|
||||
throw_at(target, range, speed)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Called on areas before anything has been moved
|
||||
// returns the new move_mode (based on the old)
|
||||
/area/proc/beforeShuttleMove(list/shuttle_areas)
|
||||
if(!shuttle_areas[src])
|
||||
return NONE
|
||||
return MOVE_AREA
|
||||
|
||||
// Called on areas to move their turf between areas
|
||||
/area/proc/onShuttleMove(turf/oldT, turf/newT, area/underlying_old_area)
|
||||
if(newT == oldT) // In case of in place shuttle rotation shenanigans.
|
||||
return TRUE
|
||||
|
||||
contents -= oldT
|
||||
underlying_old_area.contents += oldT
|
||||
oldT.change_area(src, underlying_old_area)
|
||||
//The old turf has now been given back to the area that turf originaly belonged to
|
||||
|
||||
var/area/old_dest_area = newT.loc
|
||||
parallax_movedir = old_dest_area.parallax_movedir
|
||||
|
||||
old_dest_area.contents -= newT
|
||||
contents += newT
|
||||
newT.change_area(old_dest_area, src)
|
||||
return TRUE
|
||||
|
||||
// Called on areas after everything has been moved
|
||||
/area/proc/afterShuttleMove(new_parallax_dir)
|
||||
parallax_movedir = new_parallax_dir
|
||||
return TRUE
|
||||
|
||||
/area/proc/lateShuttleMove()
|
||||
return
|
||||
|
||||
/************************************Turf move procs************************************/
|
||||
|
||||
/************************************Area move procs************************************/
|
||||
|
||||
/************************************Machinery move procs************************************/
|
||||
|
||||
/obj/machinery/door/airlock/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
for(var/obj/machinery/door/airlock/A in range(1, src)) // includes src
|
||||
A.shuttledocked = FALSE
|
||||
A.air_tight = TRUE
|
||||
addtimer(CALLBACK(A, /obj/machinery/door/.proc/close), 0)
|
||||
|
||||
/obj/machinery/door/airlock/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
var/current_area = get_area(src)
|
||||
for(var/obj/machinery/door/airlock/A in orange(1, src)) // does not include src
|
||||
if(get_area(A) != current_area) // does not include double-wide airlocks unless actually docked
|
||||
// Cycle linking is only disabled if we are actually adjacent to another airlock
|
||||
shuttledocked = TRUE
|
||||
A.shuttledocked = TRUE
|
||||
|
||||
/obj/machinery/camera/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
GLOB.cameranet.removeCamera(src)
|
||||
|
||||
/obj/machinery/camera/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
GLOB.cameranet.addCamera(src)
|
||||
|
||||
/obj/machinery/mech_bay_recharge_port/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir)
|
||||
. = ..()
|
||||
recharging_turf = get_step(loc, dir)
|
||||
|
||||
/obj/machinery/atmospherics/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
if(pipe_vision_img)
|
||||
pipe_vision_img.loc = loc
|
||||
|
||||
/obj/machinery/computer/auxillary_base/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
if(is_mining_level(z)) //Avoids double logging and landing on other Z-levels due to badminnery
|
||||
SSblackbox.record_feedback("associative", "colonies_dropped", 1, list("x" = x, "y" = y, "z" = z))
|
||||
|
||||
/obj/machinery/gravity_generator/main/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
on = FALSE
|
||||
update_list()
|
||||
|
||||
/obj/machinery/gravity_generator/main/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
if(charge_count != 0 && charging_state != POWER_UP)
|
||||
on = TRUE
|
||||
update_list()
|
||||
|
||||
/obj/machinery/atmospherics/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
var/missing_nodes = FALSE
|
||||
for(var/i in 1 to device_type)
|
||||
if(nodes[i])
|
||||
var/obj/machinery/atmospherics/node = nodes[i]
|
||||
var/connected = FALSE
|
||||
for(var/D in GLOB.cardinals)
|
||||
if(node in get_step(src, D))
|
||||
connected = TRUE
|
||||
break
|
||||
|
||||
if(!connected)
|
||||
nullifyNode(i)
|
||||
|
||||
if(!nodes[i])
|
||||
missing_nodes = TRUE
|
||||
|
||||
if(missing_nodes)
|
||||
atmosinit()
|
||||
for(var/obj/machinery/atmospherics/A in pipeline_expansion())
|
||||
A.atmosinit()
|
||||
if(A.returnPipenet())
|
||||
A.addMember(src)
|
||||
build_network()
|
||||
else
|
||||
// atmosinit() calls update_icon(), so we don't need to call it
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/pipe/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
var/turf/T = loc
|
||||
hide(T.intact)
|
||||
|
||||
/obj/machinery/navbeacon/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
GLOB.navbeacons["[z]"] -= src
|
||||
GLOB.deliverybeacons -= src
|
||||
|
||||
/obj/machinery/navbeacon/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
var/turf/T = loc
|
||||
hide(T.intact)
|
||||
if(codes["patrol"])
|
||||
if(!GLOB.navbeacons["[z]"])
|
||||
GLOB.navbeacons["[z]"] = list()
|
||||
GLOB.navbeacons["[z]"] += src //Register with the patrol list!
|
||||
if(codes["delivery"])
|
||||
GLOB.deliverybeacons += src
|
||||
GLOB.deliverybeacontags += location
|
||||
|
||||
/obj/machinery/power/terminal/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
var/turf/T = src.loc
|
||||
if(level==1)
|
||||
hide(T.intact)
|
||||
|
||||
/************************************Item move procs************************************/
|
||||
|
||||
/obj/item/storage/pod/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
// If the pod was launched, the storage will always open. The CentCom check
|
||||
// ignores the movement of the shuttle from the staging area on CentCom to
|
||||
// the station as it is loaded in.
|
||||
if (oldT && !is_centcom_level(oldT.z))
|
||||
var/datum/component/storage/concrete/emergency/STR = GetComponent(/datum/component/storage/concrete/emergency)
|
||||
STR?.unlock_me()
|
||||
|
||||
/************************************Mob move procs************************************/
|
||||
|
||||
/mob/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
|
||||
if(!move_on_shuttle)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/mob/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
if(!move_on_shuttle)
|
||||
return
|
||||
. = ..()
|
||||
if(client && movement_force)
|
||||
var/shake_force = max(movement_force["THROW"], movement_force["KNOCKDOWN"])
|
||||
if(buckled)
|
||||
shake_force *= 0.25
|
||||
shake_camera(src, shake_force, 1)
|
||||
|
||||
/mob/living/lateShuttleMove(turf/oldT, list/movement_force, move_dir)
|
||||
if(buckled)
|
||||
return
|
||||
|
||||
. = ..()
|
||||
|
||||
var/knockdown = movement_force["KNOCKDOWN"]
|
||||
if(knockdown)
|
||||
Knockdown(knockdown)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
message_admins("Megafauna [src] [ADMIN_FLW(src)] moved via shuttle from [ADMIN_COORDJMP(oldT)] to [ADMIN_COORDJMP(loc)]")
|
||||
|
||||
/************************************Structure move procs************************************/
|
||||
|
||||
/obj/structure/grille/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/structure/lattice/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/structure/disposalpipe/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
update()
|
||||
|
||||
/obj/structure/cable/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
var/turf/T = loc
|
||||
if(level==1)
|
||||
hide(T.intact)
|
||||
|
||||
/obj/structure/shuttle/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/structure/ladder/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if (!(resistance_flags & INDESTRUCTIBLE))
|
||||
disconnect()
|
||||
|
||||
/obj/structure/ladder/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
|
||||
. = ..()
|
||||
if (!(resistance_flags & INDESTRUCTIBLE))
|
||||
LateInitialize()
|
||||
|
||||
/obj/structure/ladder/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
|
||||
if (resistance_flags & INDESTRUCTIBLE)
|
||||
// simply don't be moved
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/************************************Misc move procs************************************/
|
||||
|
||||
/atom/movable/lighting_object/onShuttleMove()
|
||||
return FALSE
|
||||
|
||||
/obj/docking_port/mobile/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(moving_dock == src)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/docking_port/stationary/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
|
||||
if(!moving_dock.can_move_docking_ports || old_dock == src)
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/docking_port/stationary/public_mining_dock/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
|
||||
id = "mining_public" //It will not move with the base, but will become enabled as a docking point.
|
||||
|
||||
/obj/effect/abstract/proximity_checker/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
|
||||
//timer so it only happens once
|
||||
addtimer(CALLBACK(monitor, /datum/proximity_monitor/proc/SetRange, monitor.current_range, TRUE), 0, TIMER_UNIQUE)
|
||||
@@ -1,809 +0,0 @@
|
||||
//use this define to highlight docking port bounding boxes (ONLY FOR DEBUG USE)
|
||||
#ifdef TESTING
|
||||
#define DOCKING_PORT_HIGHLIGHT
|
||||
#endif
|
||||
|
||||
//NORTH default dir
|
||||
/obj/docking_port
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "pinonfar"
|
||||
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
anchored = TRUE
|
||||
//
|
||||
var/id
|
||||
// this should point -away- from the dockingport door, ie towards the ship
|
||||
dir = NORTH
|
||||
var/width = 0 //size of covered area, perpendicular to dir
|
||||
var/height = 0 //size of covered area, parallel to dir
|
||||
var/dwidth = 0 //position relative to covered area, perpendicular to dir
|
||||
var/dheight = 0 //position relative to covered area, parallel to dir
|
||||
|
||||
var/area_type
|
||||
var/hidden = FALSE //are we invisible to shuttle navigation computers?
|
||||
|
||||
//these objects are indestructible
|
||||
/obj/docking_port/Destroy(force)
|
||||
// unless you assert that you know what you're doing. Horrible things
|
||||
// may result.
|
||||
if(force)
|
||||
..()
|
||||
. = QDEL_HINT_QUEUE
|
||||
else
|
||||
return QDEL_HINT_LETMELIVE
|
||||
|
||||
/obj/docking_port/has_gravity(turf/T)
|
||||
return FALSE
|
||||
|
||||
/obj/docking_port/take_damage()
|
||||
return
|
||||
|
||||
/obj/docking_port/singularity_pull()
|
||||
return
|
||||
/obj/docking_port/singularity_act()
|
||||
return 0
|
||||
/obj/docking_port/shuttleRotate()
|
||||
return //we don't rotate with shuttles via this code.
|
||||
|
||||
//returns a list(x0,y0, x1,y1) where points 0 and 1 are bounding corners of the projected rectangle
|
||||
/obj/docking_port/proc/return_coords(_x, _y, _dir)
|
||||
if(_dir == null)
|
||||
_dir = dir
|
||||
if(_x == null)
|
||||
_x = x
|
||||
if(_y == null)
|
||||
_y = y
|
||||
|
||||
//byond's sin and cos functions are inaccurate. This is faster and perfectly accurate
|
||||
var/cos = 1
|
||||
var/sin = 0
|
||||
switch(_dir)
|
||||
if(WEST)
|
||||
cos = 0
|
||||
sin = 1
|
||||
if(SOUTH)
|
||||
cos = -1
|
||||
sin = 0
|
||||
if(EAST)
|
||||
cos = 0
|
||||
sin = -1
|
||||
|
||||
return list(
|
||||
_x + (-dwidth*cos) - (-dheight*sin),
|
||||
_y + (-dwidth*sin) + (-dheight*cos),
|
||||
_x + (-dwidth+width-1)*cos - (-dheight+height-1)*sin,
|
||||
_y + (-dwidth+width-1)*sin + (-dheight+height-1)*cos
|
||||
)
|
||||
|
||||
//returns turfs within our projected rectangle in no particular order
|
||||
/obj/docking_port/proc/return_turfs()
|
||||
var/list/L = return_coords()
|
||||
var/turf/T0 = locate(L[1],L[2],z)
|
||||
var/turf/T1 = locate(L[3],L[4],z)
|
||||
return block(T0,T1)
|
||||
|
||||
//returns turfs within our projected rectangle in a specific order.
|
||||
//this ensures that turfs are copied over in the same order, regardless of any rotation
|
||||
/obj/docking_port/proc/return_ordered_turfs(_x, _y, _z, _dir)
|
||||
var/cos = 1
|
||||
var/sin = 0
|
||||
switch(_dir)
|
||||
if(WEST)
|
||||
cos = 0
|
||||
sin = 1
|
||||
if(SOUTH)
|
||||
cos = -1
|
||||
sin = 0
|
||||
if(EAST)
|
||||
cos = 0
|
||||
sin = -1
|
||||
|
||||
. = list()
|
||||
|
||||
for(var/dx in 0 to width-1)
|
||||
var/compX = dx-dwidth
|
||||
for(var/dy in 0 to height-1)
|
||||
var/compY = dy-dheight
|
||||
// realX = _x + compX*cos - compY*sin
|
||||
// realY = _y + compY*cos - compX*sin
|
||||
// locate(realX, realY, _z)
|
||||
var/turf/T = locate(_x + compX*cos - compY*sin, _y + compY*cos + compX*sin, _z)
|
||||
.[T] = NONE
|
||||
|
||||
#ifdef DOCKING_PORT_HIGHLIGHT
|
||||
//Debug proc used to highlight bounding area
|
||||
/obj/docking_port/proc/highlight(_color)
|
||||
var/list/L = return_coords()
|
||||
var/turf/T0 = locate(L[1],L[2],z)
|
||||
var/turf/T1 = locate(L[3],L[4],z)
|
||||
for(var/turf/T in block(T0,T1))
|
||||
T.color = _color
|
||||
LAZYINITLIST(T.atom_colours)
|
||||
T.maptext = null
|
||||
if(_color)
|
||||
var/turf/T = locate(L[1], L[2], z)
|
||||
T.color = "#0f0"
|
||||
T = locate(L[3], L[4], z)
|
||||
T.color = "#00f"
|
||||
#endif
|
||||
|
||||
//return first-found touching dockingport
|
||||
/obj/docking_port/proc/get_docked()
|
||||
return locate(/obj/docking_port/stationary) in loc
|
||||
|
||||
/obj/docking_port/proc/getDockedId()
|
||||
var/obj/docking_port/P = get_docked()
|
||||
if(P)
|
||||
return P.id
|
||||
|
||||
/obj/docking_port/proc/is_in_shuttle_bounds(atom/A)
|
||||
var/turf/T = get_turf(A)
|
||||
if(T.z != z)
|
||||
return FALSE
|
||||
var/list/bounds = return_coords()
|
||||
var/x0 = bounds[1]
|
||||
var/y0 = bounds[2]
|
||||
var/x1 = bounds[3]
|
||||
var/y1 = bounds[4]
|
||||
if(!ISINRANGE(T.x, min(x0, x1), max(x0, x1)))
|
||||
return FALSE
|
||||
if(!ISINRANGE(T.y, min(y0, y1), max(y0, y1)))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/docking_port/stationary
|
||||
name = "dock"
|
||||
|
||||
area_type = SHUTTLE_DEFAULT_UNDERLYING_AREA
|
||||
|
||||
var/last_dock_time
|
||||
|
||||
var/datum/map_template/shuttle/roundstart_template
|
||||
var/json_key
|
||||
|
||||
/obj/docking_port/stationary/Initialize(mapload)
|
||||
. = ..()
|
||||
SSshuttle.stationary += src
|
||||
if(!id)
|
||||
id = "[SSshuttle.stationary.len]"
|
||||
if(name == "dock")
|
||||
name = "dock[SSshuttle.stationary.len]"
|
||||
|
||||
if(mapload)
|
||||
for(var/turf/T in return_turfs())
|
||||
T.flags_1 |= NO_RUINS_1
|
||||
|
||||
#ifdef DOCKING_PORT_HIGHLIGHT
|
||||
highlight("#f00")
|
||||
#endif
|
||||
|
||||
/obj/docking_port/stationary/Destroy(force)
|
||||
if(force)
|
||||
SSshuttle.stationary -= src
|
||||
. = ..()
|
||||
|
||||
/obj/docking_port/stationary/proc/load_roundstart()
|
||||
if(json_key)
|
||||
var/sid = SSmapping.config.shuttles[json_key]
|
||||
roundstart_template = SSmapping.shuttle_templates[sid]
|
||||
if(!roundstart_template)
|
||||
CRASH("json_key:[json_key] value \[[sid]\] resulted in a null shuttle template for [src]")
|
||||
else if(roundstart_template) // passed a PATH
|
||||
var/sid = "[initial(roundstart_template.port_id)]_[initial(roundstart_template.suffix)]"
|
||||
|
||||
roundstart_template = SSmapping.shuttle_templates[sid]
|
||||
if(!roundstart_template)
|
||||
CRASH("Invalid path ([roundstart_template]) passed to docking port.")
|
||||
|
||||
if(roundstart_template)
|
||||
SSshuttle.manipulator.action_load(roundstart_template, src)
|
||||
|
||||
//returns first-found touching shuttleport
|
||||
/obj/docking_port/stationary/get_docked()
|
||||
. = locate(/obj/docking_port/mobile) in loc
|
||||
|
||||
/obj/docking_port/stationary/transit
|
||||
name = "In Transit"
|
||||
var/datum/turf_reservation/reserved_area
|
||||
var/area/shuttle/transit/assigned_area
|
||||
var/obj/docking_port/mobile/owner
|
||||
|
||||
/obj/docking_port/stationary/transit/Initialize()
|
||||
. = ..()
|
||||
SSshuttle.transit += src
|
||||
|
||||
/obj/docking_port/stationary/transit/Destroy(force=FALSE)
|
||||
if(force)
|
||||
if(get_docked())
|
||||
log_world("A transit dock was destroyed while something was docked to it.")
|
||||
SSshuttle.transit -= src
|
||||
if(owner)
|
||||
if(owner.assigned_transit == src)
|
||||
owner.assigned_transit = null
|
||||
owner = null
|
||||
if(!QDELETED(reserved_area))
|
||||
qdel(reserved_area)
|
||||
reserved_area = null
|
||||
return ..()
|
||||
|
||||
/obj/docking_port/mobile
|
||||
name = "shuttle"
|
||||
icon_state = "pinonclose"
|
||||
|
||||
area_type = SHUTTLE_DEFAULT_SHUTTLE_AREA_TYPE
|
||||
|
||||
var/list/shuttle_areas
|
||||
|
||||
var/timer //used as a timer (if you want time left to complete move, use timeLeft proc)
|
||||
var/last_timer_length
|
||||
|
||||
var/mode = SHUTTLE_IDLE //current shuttle mode
|
||||
var/callTime = 100 //time spent in transit (deciseconds). Should not be lower then 10 seconds without editing the animation of the hyperspace ripples.
|
||||
var/ignitionTime = 55 // time spent "starting the engines". Also rate limits how often we try to reserve transit space if its ever full of transiting shuttles.
|
||||
|
||||
// The direction the shuttle prefers to travel in
|
||||
var/preferred_direction = NORTH
|
||||
// And the angle from the front of the shuttle to the port
|
||||
var/port_direction = NORTH
|
||||
|
||||
var/obj/docking_port/stationary/destination
|
||||
var/obj/docking_port/stationary/previous
|
||||
|
||||
var/obj/docking_port/stationary/transit/assigned_transit
|
||||
|
||||
var/launch_status = NOLAUNCH
|
||||
|
||||
var/list/movement_force = list("KNOCKDOWN" = 3, "THROW" = 2)
|
||||
|
||||
var/list/ripples = list()
|
||||
var/engine_coeff = 1 //current engine coeff
|
||||
var/current_engines = 0 //current engine power
|
||||
var/initial_engines = 0 //initial engine power
|
||||
var/can_move_docking_ports = FALSE //if this shuttle can move docking ports other than the one it is docked at
|
||||
var/list/hidden_turfs = list()
|
||||
|
||||
/obj/docking_port/mobile/proc/register()
|
||||
SSshuttle.mobile += src
|
||||
|
||||
/obj/docking_port/mobile/Destroy(force)
|
||||
if(force)
|
||||
SSshuttle.mobile -= src
|
||||
destination = null
|
||||
previous = null
|
||||
QDEL_NULL(assigned_transit) //don't need it where we're goin'!
|
||||
shuttle_areas = null
|
||||
remove_ripples()
|
||||
. = ..()
|
||||
|
||||
/obj/docking_port/mobile/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
if(!id)
|
||||
id = "[SSshuttle.mobile.len]"
|
||||
if(name == "shuttle")
|
||||
name = "shuttle[SSshuttle.mobile.len]"
|
||||
|
||||
shuttle_areas = list()
|
||||
var/list/all_turfs = return_ordered_turfs(x, y, z, dir)
|
||||
for(var/i in 1 to all_turfs.len)
|
||||
var/turf/curT = all_turfs[i]
|
||||
var/area/cur_area = curT.loc
|
||||
if(istype(cur_area, area_type))
|
||||
shuttle_areas[cur_area] = TRUE
|
||||
|
||||
initial_engines = count_engines()
|
||||
current_engines = initial_engines
|
||||
|
||||
#ifdef DOCKING_PORT_HIGHLIGHT
|
||||
highlight("#0f0")
|
||||
#endif
|
||||
|
||||
// Called after the shuttle is loaded from template
|
||||
/obj/docking_port/mobile/proc/linkup(datum/map_template/shuttle/template, obj/docking_port/stationary/dock)
|
||||
var/list/static/shuttle_id = list()
|
||||
var/idnum = ++shuttle_id[template]
|
||||
if(idnum > 1)
|
||||
if(id == initial(id))
|
||||
id = "[id][idnum]"
|
||||
if(name == initial(name))
|
||||
name = "[name] [idnum]"
|
||||
for(var/i in shuttle_areas)
|
||||
var/area/place = i
|
||||
for(var/obj/machinery/computer/shuttle/comp in place)
|
||||
comp.connect_to_shuttle(src, dock, idnum)
|
||||
for(var/obj/machinery/computer/camera_advanced/shuttle_docker/comp in place)
|
||||
comp.connect_to_shuttle(src, dock, idnum)
|
||||
for(var/obj/machinery/status_display/shuttle/sd in place)
|
||||
sd.connect_to_shuttle(src, dock, idnum)
|
||||
|
||||
|
||||
//this is a hook for custom behaviour. Maybe at some point we could add checks to see if engines are intact
|
||||
/obj/docking_port/mobile/proc/canMove()
|
||||
return TRUE
|
||||
|
||||
//this is to check if this shuttle can physically dock at dock S
|
||||
/obj/docking_port/mobile/proc/canDock(obj/docking_port/stationary/S)
|
||||
if(!istype(S))
|
||||
return SHUTTLE_NOT_A_DOCKING_PORT
|
||||
|
||||
if(istype(S, /obj/docking_port/stationary/transit))
|
||||
return SHUTTLE_CAN_DOCK
|
||||
|
||||
if(dwidth > S.dwidth)
|
||||
return SHUTTLE_DWIDTH_TOO_LARGE
|
||||
|
||||
if(width-dwidth > S.width-S.dwidth)
|
||||
return SHUTTLE_WIDTH_TOO_LARGE
|
||||
|
||||
if(dheight > S.dheight)
|
||||
return SHUTTLE_DHEIGHT_TOO_LARGE
|
||||
|
||||
if(height-dheight > S.height-S.dheight)
|
||||
return SHUTTLE_HEIGHT_TOO_LARGE
|
||||
|
||||
//check the dock isn't occupied
|
||||
var/currently_docked = S.get_docked()
|
||||
if(currently_docked)
|
||||
// by someone other than us
|
||||
if(currently_docked != src)
|
||||
return SHUTTLE_SOMEONE_ELSE_DOCKED
|
||||
else
|
||||
// This isn't an error, per se, but we can't let the shuttle code
|
||||
// attempt to move us where we currently are, it will get weird.
|
||||
return SHUTTLE_ALREADY_DOCKED
|
||||
|
||||
return SHUTTLE_CAN_DOCK
|
||||
|
||||
/obj/docking_port/mobile/proc/check_dock(obj/docking_port/stationary/S, silent=FALSE)
|
||||
var/status = canDock(S)
|
||||
if(status == SHUTTLE_CAN_DOCK)
|
||||
return TRUE
|
||||
else
|
||||
if(status != SHUTTLE_ALREADY_DOCKED && !silent) // SHUTTLE_ALREADY_DOCKED is no cause for error
|
||||
var/msg = "Shuttle [src] cannot dock at [S], error: [status]"
|
||||
message_admins(msg)
|
||||
// We're already docked there, don't need to do anything.
|
||||
// Triggering shuttle movement code in place is weird
|
||||
return FALSE
|
||||
|
||||
/obj/docking_port/mobile/proc/transit_failure()
|
||||
message_admins("Shuttle [src] repeatedly failed to create transit zone.")
|
||||
|
||||
//call the shuttle to destination S
|
||||
/obj/docking_port/mobile/proc/request(obj/docking_port/stationary/S)
|
||||
if(!check_dock(S))
|
||||
testing("check_dock failed on request for [src]")
|
||||
return
|
||||
|
||||
if(mode == SHUTTLE_IGNITING && destination == S)
|
||||
return
|
||||
|
||||
switch(mode)
|
||||
if(SHUTTLE_CALL)
|
||||
if(S == destination)
|
||||
if(timeLeft(1) < callTime * engine_coeff)
|
||||
setTimer(callTime * engine_coeff)
|
||||
else
|
||||
destination = S
|
||||
setTimer(callTime * engine_coeff)
|
||||
if(SHUTTLE_RECALL)
|
||||
if(S == destination)
|
||||
setTimer(callTime * engine_coeff - timeLeft(1))
|
||||
else
|
||||
destination = S
|
||||
setTimer(callTime * engine_coeff)
|
||||
mode = SHUTTLE_CALL
|
||||
if(SHUTTLE_IDLE, SHUTTLE_IGNITING)
|
||||
destination = S
|
||||
mode = SHUTTLE_IGNITING
|
||||
setTimer(ignitionTime)
|
||||
|
||||
//recall the shuttle to where it was previously
|
||||
/obj/docking_port/mobile/proc/cancel()
|
||||
if(mode != SHUTTLE_CALL)
|
||||
return
|
||||
|
||||
remove_ripples()
|
||||
|
||||
invertTimer()
|
||||
mode = SHUTTLE_RECALL
|
||||
|
||||
/obj/docking_port/mobile/proc/enterTransit()
|
||||
if((SSshuttle.lockdown && is_station_level(z)) || !canMove()) //emp went off, no escape
|
||||
mode = SHUTTLE_IDLE
|
||||
return
|
||||
previous = null
|
||||
if(!destination)
|
||||
// sent to transit with no destination -> unlimited timer
|
||||
timer = INFINITY
|
||||
var/obj/docking_port/stationary/S0 = get_docked()
|
||||
var/obj/docking_port/stationary/S1 = assigned_transit
|
||||
if(S1)
|
||||
if(initiate_docking(S1) != DOCKING_SUCCESS)
|
||||
WARNING("shuttle \"[id]\" could not enter transit space. Docked at [S0 ? S0.id : "null"]. Transit dock [S1 ? S1.id : "null"].")
|
||||
else
|
||||
previous = S0
|
||||
else
|
||||
WARNING("shuttle \"[id]\" could not enter transit space. S0=[S0 ? S0.id : "null"] S1=[S1 ? S1.id : "null"]")
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/jumpToNullSpace()
|
||||
// Destroys the docking port and the shuttle contents.
|
||||
// Not in a fancy way, it just ceases.
|
||||
var/obj/docking_port/stationary/current_dock = get_docked()
|
||||
|
||||
var/underlying_area_type = SHUTTLE_DEFAULT_UNDERLYING_AREA
|
||||
// If the shuttle is docked to a stationary port, restore its normal
|
||||
// "empty" area and turf
|
||||
if(current_dock && current_dock.area_type)
|
||||
underlying_area_type = current_dock.area_type
|
||||
|
||||
var/list/old_turfs = return_ordered_turfs(x, y, z, dir)
|
||||
|
||||
var/area/underlying_area = GLOB.areas_by_type[underlying_area_type]
|
||||
if(!underlying_area)
|
||||
underlying_area = new underlying_area_type(null)
|
||||
|
||||
for(var/i in 1 to old_turfs.len)
|
||||
var/turf/oldT = old_turfs[i]
|
||||
if(!oldT || !istype(oldT.loc, area_type))
|
||||
continue
|
||||
var/area/old_area = oldT.loc
|
||||
underlying_area.contents += oldT
|
||||
oldT.change_area(old_area, underlying_area)
|
||||
oldT.empty(FALSE)
|
||||
|
||||
// Here we locate the bottomost shuttle boundary and remove all turfs above it
|
||||
var/list/baseturf_cache = oldT.baseturfs
|
||||
for(var/k in 1 to length(baseturf_cache))
|
||||
if(ispath(baseturf_cache[k], /turf/baseturf_skipover/shuttle))
|
||||
oldT.ScrapeAway(baseturf_cache.len - k + 1)
|
||||
break
|
||||
|
||||
qdel(src, force=TRUE)
|
||||
|
||||
/obj/docking_port/mobile/proc/intoTheSunset()
|
||||
// Loop over mobs
|
||||
for(var/t in return_turfs())
|
||||
var/turf/T = t
|
||||
for(var/mob/living/M in T.GetAllContents())
|
||||
// If they have a mind and they're not in the brig, they escaped
|
||||
if(M.mind && !istype(t, /turf/open/floor/plasteel/shuttle/red) && !istype(t, /turf/open/floor/mineral/plastitanium/red/brig))
|
||||
M.mind.force_escaped = TRUE
|
||||
// Ghostize them and put them in nullspace stasis (for stat & possession checks)
|
||||
M.notransform = TRUE
|
||||
M.ghostize(FALSE)
|
||||
M.moveToNullspace()
|
||||
|
||||
// Now that mobs are stowed, delete the shuttle
|
||||
jumpToNullSpace()
|
||||
|
||||
/obj/docking_port/mobile/proc/create_ripples(obj/docking_port/stationary/S1, animate_time)
|
||||
var/list/turfs = ripple_area(S1)
|
||||
for(var/t in turfs)
|
||||
ripples += new /obj/effect/abstract/ripple(t, animate_time)
|
||||
|
||||
/obj/docking_port/mobile/proc/remove_ripples()
|
||||
QDEL_LIST(ripples)
|
||||
|
||||
/obj/docking_port/mobile/proc/ripple_area(obj/docking_port/stationary/S1)
|
||||
var/list/L0 = return_ordered_turfs(x, y, z, dir)
|
||||
var/list/L1 = return_ordered_turfs(S1.x, S1.y, S1.z, S1.dir)
|
||||
|
||||
var/list/ripple_turfs = list()
|
||||
|
||||
for(var/i in 1 to L0.len)
|
||||
var/turf/T0 = L0[i]
|
||||
var/turf/T1 = L1[i]
|
||||
if(!T0 || !T1)
|
||||
continue // out of bounds
|
||||
if(T0.type == T0.baseturfs)
|
||||
continue // indestructible
|
||||
if(!istype(T0.loc, area_type) || istype(T0.loc, /area/shuttle/transit))
|
||||
continue // not part of the shuttle
|
||||
ripple_turfs += T1
|
||||
|
||||
return ripple_turfs
|
||||
|
||||
/obj/docking_port/mobile/proc/check_poddoors()
|
||||
for(var/obj/machinery/door/poddoor/shuttledock/pod in GLOB.airlocks)
|
||||
pod.check()
|
||||
|
||||
/obj/docking_port/mobile/proc/dock_id(id)
|
||||
var/port = SSshuttle.getDock(id)
|
||||
if(port)
|
||||
. = initiate_docking(port)
|
||||
else
|
||||
. = null
|
||||
|
||||
/obj/effect/landmark/shuttle_import
|
||||
name = "Shuttle Import"
|
||||
|
||||
// Never move the shuttle import landmark, otherwise things get WEIRD
|
||||
/obj/effect/landmark/shuttle_import/onShuttleMove()
|
||||
return FALSE
|
||||
|
||||
//used by shuttle subsystem to check timers
|
||||
/obj/docking_port/mobile/proc/check()
|
||||
check_effects()
|
||||
|
||||
if(mode == SHUTTLE_IGNITING)
|
||||
check_transit_zone()
|
||||
|
||||
if(timeLeft(1) > 0)
|
||||
return
|
||||
// If we can't dock or we don't have a transit slot, wait for 20 ds,
|
||||
// then try again
|
||||
switch(mode)
|
||||
if(SHUTTLE_CALL)
|
||||
var/error = initiate_docking(destination, preferred_direction)
|
||||
if(error && error & (DOCKING_NULL_DESTINATION | DOCKING_NULL_SOURCE))
|
||||
var/msg = "A mobile dock in transit exited initiate_docking() with an error. This is most likely a mapping problem: Error: [error], ([src]) ([previous][ADMIN_JMP(previous)] -> [destination][ADMIN_JMP(destination)])"
|
||||
WARNING(msg)
|
||||
message_admins(msg)
|
||||
mode = SHUTTLE_IDLE
|
||||
return
|
||||
else if(error)
|
||||
setTimer(20)
|
||||
return
|
||||
if(SHUTTLE_RECALL)
|
||||
if(initiate_docking(previous) != DOCKING_SUCCESS)
|
||||
setTimer(20)
|
||||
return
|
||||
if(SHUTTLE_IGNITING)
|
||||
if(check_transit_zone() != TRANSIT_READY)
|
||||
setTimer(20)
|
||||
return
|
||||
else
|
||||
mode = SHUTTLE_CALL
|
||||
setTimer(callTime * engine_coeff)
|
||||
enterTransit()
|
||||
return
|
||||
|
||||
mode = SHUTTLE_IDLE
|
||||
timer = 0
|
||||
destination = null
|
||||
|
||||
/obj/docking_port/mobile/proc/check_effects()
|
||||
if(!ripples.len)
|
||||
if((mode == SHUTTLE_CALL) || (mode == SHUTTLE_RECALL))
|
||||
var/tl = timeLeft(1)
|
||||
if(tl <= SHUTTLE_RIPPLE_TIME)
|
||||
create_ripples(destination, tl)
|
||||
|
||||
var/obj/docking_port/stationary/S0 = get_docked()
|
||||
if(istype(S0, /obj/docking_port/stationary/transit) && timeLeft(1) <= PARALLAX_LOOP_TIME)
|
||||
for(var/place in shuttle_areas)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
if(shuttle_area.parallax_movedir)
|
||||
parallax_slowdown()
|
||||
|
||||
/obj/docking_port/mobile/proc/parallax_slowdown()
|
||||
for(var/place in shuttle_areas)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
shuttle_area.parallax_movedir = FALSE
|
||||
if(assigned_transit && assigned_transit.assigned_area)
|
||||
assigned_transit.assigned_area.parallax_movedir = FALSE
|
||||
var/list/L0 = return_ordered_turfs(x, y, z, dir)
|
||||
for (var/thing in L0)
|
||||
var/turf/T = thing
|
||||
if(!T || !istype(T.loc, area_type))
|
||||
continue
|
||||
for (var/thing2 in T)
|
||||
var/atom/movable/AM = thing2
|
||||
if (length(AM.client_mobs_in_contents))
|
||||
AM.update_parallax_contents()
|
||||
|
||||
/obj/docking_port/mobile/proc/check_transit_zone()
|
||||
if(assigned_transit)
|
||||
return TRANSIT_READY
|
||||
else
|
||||
SSshuttle.request_transit_dock(src)
|
||||
|
||||
/obj/docking_port/mobile/proc/setTimer(wait)
|
||||
timer = world.time + wait
|
||||
last_timer_length = wait
|
||||
|
||||
/obj/docking_port/mobile/proc/modTimer(multiple)
|
||||
var/time_remaining = timer - world.time
|
||||
if(time_remaining < 0 || !last_timer_length)
|
||||
return
|
||||
time_remaining *= multiple
|
||||
last_timer_length *= multiple
|
||||
setTimer(time_remaining)
|
||||
|
||||
/obj/docking_port/mobile/proc/invertTimer()
|
||||
if(!last_timer_length)
|
||||
return
|
||||
var/time_remaining = timer - world.time
|
||||
if(time_remaining > 0)
|
||||
var/time_passed = last_timer_length - time_remaining
|
||||
setTimer(time_passed)
|
||||
|
||||
//returns timeLeft
|
||||
/obj/docking_port/mobile/proc/timeLeft(divisor)
|
||||
if(divisor <= 0)
|
||||
divisor = 10
|
||||
|
||||
var/ds_remaining
|
||||
if(!timer)
|
||||
ds_remaining = callTime * engine_coeff
|
||||
else
|
||||
ds_remaining = max(0, timer - world.time)
|
||||
|
||||
. = round(ds_remaining / divisor, 1)
|
||||
|
||||
// returns 3-letter mode string, used by status screens and mob status panel
|
||||
/obj/docking_port/mobile/proc/getModeStr()
|
||||
switch(mode)
|
||||
if(SHUTTLE_IGNITING)
|
||||
return "IGN"
|
||||
if(SHUTTLE_RECALL)
|
||||
return "RCL"
|
||||
if(SHUTTLE_CALL)
|
||||
return "ETA"
|
||||
if(SHUTTLE_DOCKED)
|
||||
return "ETD"
|
||||
if(SHUTTLE_ESCAPE)
|
||||
return "ESC"
|
||||
if(SHUTTLE_STRANDED)
|
||||
return "ERR"
|
||||
return ""
|
||||
|
||||
// returns 5-letter timer string, used by status screens and mob status panel
|
||||
/obj/docking_port/mobile/proc/getTimerStr()
|
||||
if(mode == SHUTTLE_STRANDED)
|
||||
return "--:--"
|
||||
|
||||
var/timeleft = timeLeft()
|
||||
if(timeleft > 1 HOURS)
|
||||
return "--:--"
|
||||
else if(timeleft > 0)
|
||||
return "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]"
|
||||
else
|
||||
return "00:00"
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/getStatusText()
|
||||
var/obj/docking_port/stationary/dockedAt = get_docked()
|
||||
|
||||
if(istype(dockedAt, /obj/docking_port/stationary/transit))
|
||||
if (timeLeft() > 1 HOURS)
|
||||
return "hyperspace"
|
||||
else
|
||||
var/obj/docking_port/stationary/dst
|
||||
if(mode == SHUTTLE_RECALL)
|
||||
dst = previous
|
||||
else
|
||||
dst = destination
|
||||
. = "transit towards [dst?.name || "unknown location"] ([getTimerStr()])"
|
||||
else
|
||||
return dockedAt?.name || "unknown"
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/getDbgStatusText()
|
||||
var/obj/docking_port/stationary/dockedAt = get_docked()
|
||||
. = (dockedAt && dockedAt.name) ? dockedAt.name : "unknown"
|
||||
if(istype(dockedAt, /obj/docking_port/stationary/transit))
|
||||
var/obj/docking_port/stationary/dst
|
||||
if(mode == SHUTTLE_RECALL)
|
||||
dst = previous
|
||||
else
|
||||
dst = destination
|
||||
if(dst)
|
||||
. = "(transit to) [dst.name || dst.id]"
|
||||
else
|
||||
. = "(transit to) nowhere"
|
||||
else if(dockedAt)
|
||||
. = dockedAt.name || dockedAt.id
|
||||
else
|
||||
. = "unknown"
|
||||
|
||||
|
||||
// attempts to locate /obj/machinery/computer/shuttle with matching ID inside the shuttle
|
||||
/obj/docking_port/mobile/proc/getControlConsole()
|
||||
for(var/place in shuttle_areas)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
for(var/obj/machinery/computer/shuttle/S in shuttle_area)
|
||||
if(S.shuttleId == id)
|
||||
return S
|
||||
return null
|
||||
|
||||
/obj/docking_port/mobile/proc/hyperspace_sound(phase, list/areas)
|
||||
var/s
|
||||
switch(phase)
|
||||
if(HYPERSPACE_WARMUP)
|
||||
s = 'sound/effects/hyperspace_begin.ogg'
|
||||
if(HYPERSPACE_LAUNCH)
|
||||
s = 'sound/effects/hyperspace_progress.ogg'
|
||||
if(HYPERSPACE_END)
|
||||
s = 'sound/effects/hyperspace_end.ogg'
|
||||
else
|
||||
CRASH("Invalid hyperspace sound phase: [phase]")
|
||||
for(var/A in areas)
|
||||
for(var/obj/machinery/door/E in A) //dumb, I know, but playing it on the engines doesn't do it justice
|
||||
playsound(E, s, 100, FALSE, max(width, height) - world.view)
|
||||
|
||||
// Losing all initial engines should get you 2
|
||||
// Adding another set of engines at 0.5 time
|
||||
/obj/docking_port/mobile/proc/alter_engines(mod)
|
||||
if(mod == 0)
|
||||
return
|
||||
var/old_coeff = engine_coeff
|
||||
engine_coeff = get_engine_coeff(current_engines,mod)
|
||||
current_engines = max(0,current_engines + mod)
|
||||
if(in_flight())
|
||||
var/delta_coeff = engine_coeff / old_coeff
|
||||
modTimer(delta_coeff)
|
||||
|
||||
/obj/docking_port/mobile/proc/count_engines()
|
||||
. = 0
|
||||
for(var/thing in shuttle_areas)
|
||||
var/area/shuttle/areaInstance = thing
|
||||
for(var/obj/structure/shuttle/engine/E in areaInstance.contents)
|
||||
if(!QDELETED(E))
|
||||
. += E.engine_power
|
||||
|
||||
// Double initial engines to get to 0.5 minimum
|
||||
// Lose all initial engines to get to 2
|
||||
//For 0 engine shuttles like BYOS 5 engines to get to doublespeed
|
||||
/obj/docking_port/mobile/proc/get_engine_coeff(current,engine_mod)
|
||||
var/new_value = max(0,current + engine_mod)
|
||||
if(new_value == initial_engines)
|
||||
return 1
|
||||
if(new_value > initial_engines)
|
||||
var/delta = new_value - initial_engines
|
||||
var/change_per_engine = (1 - ENGINE_COEFF_MIN) / ENGINE_DEFAULT_MAXSPEED_ENGINES // 5 by default
|
||||
if(initial_engines > 0)
|
||||
change_per_engine = (1 - ENGINE_COEFF_MIN) / initial_engines // or however many it had
|
||||
return CLAMP(1 - delta * change_per_engine,ENGINE_COEFF_MIN,ENGINE_COEFF_MAX)
|
||||
if(new_value < initial_engines)
|
||||
var/delta = initial_engines - new_value
|
||||
var/change_per_engine = 1 //doesn't really matter should not be happening for 0 engine shuttles
|
||||
if(initial_engines > 0)
|
||||
change_per_engine = (ENGINE_COEFF_MAX - 1) / initial_engines //just linear drop to max delay
|
||||
return CLAMP(1 + delta * change_per_engine,ENGINE_COEFF_MIN,ENGINE_COEFF_MAX)
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/in_flight()
|
||||
switch(mode)
|
||||
if(SHUTTLE_CALL,SHUTTLE_RECALL)
|
||||
return TRUE
|
||||
if(SHUTTLE_IDLE,SHUTTLE_IGNITING)
|
||||
return FALSE
|
||||
else
|
||||
return FALSE // hmm
|
||||
|
||||
/obj/docking_port/mobile/emergency/in_flight()
|
||||
switch(mode)
|
||||
if(SHUTTLE_ESCAPE)
|
||||
return TRUE
|
||||
if(SHUTTLE_STRANDED,SHUTTLE_ENDGAME)
|
||||
return FALSE
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
//Called when emergency shuttle leaves the station
|
||||
/obj/docking_port/mobile/proc/on_emergency_launch()
|
||||
if(launch_status == UNLAUNCHED) //Pods will not launch from the mine/planet, and other ships won't launch unless we tell them to.
|
||||
launch_status = ENDGAME_LAUNCHED
|
||||
enterTransit()
|
||||
|
||||
/obj/docking_port/mobile/emergency/on_emergency_launch()
|
||||
return
|
||||
|
||||
//Called when emergency shuttle docks at centcom
|
||||
/obj/docking_port/mobile/proc/on_emergency_dock()
|
||||
//Mapping a new docking point for each ship mappers could potentially want docking with centcom would take up lots of space, just let them keep flying off into the sunset for their greentext
|
||||
if(launch_status == ENDGAME_LAUNCHED)
|
||||
launch_status = ENDGAME_TRANSIT
|
||||
|
||||
/obj/docking_port/mobile/pod/on_emergency_dock()
|
||||
if(launch_status == ENDGAME_LAUNCHED)
|
||||
initiate_docking(SSshuttle.getDock("[id]_away")) //Escape pods dock at centcom
|
||||
mode = SHUTTLE_ENDGAME
|
||||
|
||||
/obj/docking_port/mobile/emergency/on_emergency_dock()
|
||||
return
|
||||
@@ -1,287 +0,0 @@
|
||||
// Special objects for shuttle templates go here if nowhere else
|
||||
|
||||
// Wabbajack statue, a sleeping frog statue that shoots bolts of change if
|
||||
// living carbons are put on its altar/tables
|
||||
|
||||
/obj/machinery/power/emitter/energycannon/magical
|
||||
name = "wabbajack statue"
|
||||
desc = "Who am I? What is my purpose in life? What do I mean by who am I?"
|
||||
projectile_type = /obj/item/projectile/magic/change
|
||||
icon = 'icons/obj/machines/magic_emitter.dmi'
|
||||
icon_state = "wabbajack_statue"
|
||||
icon_state_on = "wabbajack_statue_on"
|
||||
active = FALSE
|
||||
allow_switch_interact = FALSE
|
||||
var/list/active_tables = list()
|
||||
var/tables_required = 2
|
||||
|
||||
/obj/machinery/power/emitter/energycannon/magical/Initialize()
|
||||
. = ..()
|
||||
if(prob(50))
|
||||
desc = "Oh no, not again."
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/emitter/energycannon/magical/update_icon()
|
||||
if(active)
|
||||
icon_state = icon_state_on
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/obj/machinery/power/emitter/energycannon/magical/process()
|
||||
. = ..()
|
||||
if(active_tables.len >= tables_required)
|
||||
if(!active)
|
||||
visible_message("<span class='revenboldnotice'>\
|
||||
[src] opens its eyes.</span>")
|
||||
active = TRUE
|
||||
else
|
||||
if(active)
|
||||
visible_message("<span class='revenboldnotice'>\
|
||||
[src] closes its eyes.</span>")
|
||||
active = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/emitter/energycannon/magical/attackby(obj/item/W, mob/user, params)
|
||||
return
|
||||
|
||||
/obj/machinery/power/emitter/energycannon/magical/ex_act(severity)
|
||||
return
|
||||
|
||||
/obj/machinery/power/emitter/energycannon/magical/emag_act(mob/user)
|
||||
return SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
|
||||
|
||||
/obj/structure/table/abductor/wabbajack
|
||||
name = "wabbajack altar"
|
||||
desc = "Whether you're sleeping or waking, it's going to be quite chaotic."
|
||||
max_integrity = 1000
|
||||
verb_say = "chants"
|
||||
var/obj/machinery/power/emitter/energycannon/magical/our_statue
|
||||
var/list/mob/living/sleepers = list()
|
||||
var/never_spoken = TRUE
|
||||
flags_1 = NODECONSTRUCT_1
|
||||
|
||||
/obj/structure/table/abductor/wabbajack/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/structure/table/abductor/wabbajack/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/table/abductor/wabbajack/process()
|
||||
var/area = orange(4, src)
|
||||
if(!our_statue)
|
||||
for(var/obj/machinery/power/emitter/energycannon/magical/M in area)
|
||||
our_statue = M
|
||||
break
|
||||
|
||||
if(!our_statue)
|
||||
name = "inert [name]"
|
||||
return
|
||||
else
|
||||
name = initial(name)
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/found = list()
|
||||
for(var/mob/living/carbon/C in T)
|
||||
if(C.stat != DEAD)
|
||||
found += C
|
||||
|
||||
// New sleepers
|
||||
for(var/i in found - sleepers)
|
||||
var/mob/living/L = i
|
||||
L.add_atom_colour("#800080", TEMPORARY_COLOUR_PRIORITY)
|
||||
L.visible_message("<span class='revennotice'>A strange purple glow wraps itself around [L] as [L.p_they()] suddenly fall[L.p_s()] unconscious.</span>",
|
||||
"<span class='revendanger'>[desc]</span>")
|
||||
// Don't let them sit suround unconscious forever
|
||||
addtimer(CALLBACK(src, .proc/sleeper_dreams, L), 100)
|
||||
|
||||
// Existing sleepers
|
||||
for(var/i in found)
|
||||
var/mob/living/L = i
|
||||
L.SetSleeping(200)
|
||||
|
||||
// Missing sleepers
|
||||
for(var/i in sleepers - found)
|
||||
var/mob/living/L = i
|
||||
L.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#800080")
|
||||
L.visible_message("<span class='revennotice'>The glow from [L] fades \
|
||||
away.</span>")
|
||||
L.grab_ghost()
|
||||
|
||||
sleepers = found
|
||||
|
||||
if(sleepers.len)
|
||||
our_statue.active_tables |= src
|
||||
if(never_spoken || prob(5))
|
||||
say(desc)
|
||||
never_spoken = FALSE
|
||||
else
|
||||
our_statue.active_tables -= src
|
||||
|
||||
/obj/structure/table/abductor/wabbajack/proc/sleeper_dreams(mob/living/sleeper)
|
||||
if(sleeper in sleepers)
|
||||
to_chat(sleeper, "<span class='revennotice'>While you slumber, you have the strangest dream, like you can see yourself from the outside.</span>")
|
||||
sleeper.ghostize(TRUE)
|
||||
|
||||
/obj/structure/table/abductor/wabbajack/left
|
||||
desc = "You sleep so it may wake."
|
||||
|
||||
/obj/structure/table/abductor/wabbajack/right
|
||||
desc = "It wakes so you may sleep."
|
||||
|
||||
// Bar staff, GODMODE mobs that just want to make sure people have drinks
|
||||
// and a good time.
|
||||
|
||||
/mob/living/simple_animal/drone/snowflake/bardrone
|
||||
name = "Bardrone"
|
||||
desc = "A barkeeping drone, an indestructible robot built to tend bars."
|
||||
hacked = TRUE
|
||||
laws = "1. Serve drinks.\n\
|
||||
2. Talk to patrons.\n\
|
||||
3. Don't get messed up in their affairs."
|
||||
status_flags = GODMODE // Please don't punch the barkeeper
|
||||
unique_name = FALSE // disables the (123) number suffix
|
||||
initial_language_holder = /datum/language_holder/universal
|
||||
|
||||
/mob/living/simple_animal/drone/snowflake/bardrone/Initialize()
|
||||
. = ..()
|
||||
access_card.access |= ACCESS_CENT_BAR
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/maid/barmaid
|
||||
gold_core_spawnable = NO_SPAWN
|
||||
name = "Barmaid"
|
||||
desc = "A barmaid, a maiden found in a bar."
|
||||
pass_flags = PASSTABLE
|
||||
status_flags = GODMODE
|
||||
unique_name = FALSE
|
||||
AIStatus = AI_OFF
|
||||
stop_automated_movement = TRUE
|
||||
initial_language_holder = /datum/language_holder/universal
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/maid/barmaid/Initialize()
|
||||
. = ..()
|
||||
access_card = new /obj/item/card/id(src)
|
||||
var/datum/job/captain/C = new /datum/job/captain
|
||||
access_card.access = C.get_access()
|
||||
access_card.access |= ACCESS_CENT_BAR
|
||||
ADD_TRAIT(access_card, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/maid/barmaid/Destroy()
|
||||
qdel(access_card)
|
||||
. = ..()
|
||||
|
||||
// Bar table, a wooden table that kicks you in a direction if you're not
|
||||
// barstaff (defined as someone who was a roundstart bartender or someone
|
||||
// with CENTCOM_BARSTAFF)
|
||||
|
||||
/obj/structure/table/wood/bar
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
flags_1 = NODECONSTRUCT_1
|
||||
max_integrity = 1000
|
||||
var/boot_dir = 1
|
||||
|
||||
/obj/structure/table/wood/bar/Crossed(atom/movable/AM)
|
||||
if(isliving(AM) && !is_barstaff(AM))
|
||||
// No climbing on the bar please
|
||||
var/mob/living/M = AM
|
||||
var/throwtarget = get_edge_target_turf(src, boot_dir)
|
||||
M.Knockdown(40)
|
||||
M.throw_at(throwtarget, 5, 1)
|
||||
to_chat(M, "<span class='notice'>No climbing on the bar please.</span>")
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/structure/table/wood/bar/proc/is_barstaff(mob/living/user)
|
||||
. = FALSE
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.mind && H.mind.assigned_role == "Bartender")
|
||||
return TRUE
|
||||
|
||||
var/obj/item/card/id/ID = user.get_idcard(FALSE)
|
||||
if(ID && (ACCESS_CENT_BAR in ID.access))
|
||||
return TRUE
|
||||
|
||||
//Luxury Shuttle Blockers
|
||||
|
||||
/obj/effect/forcefield/luxury_shuttle
|
||||
timeleft = 0
|
||||
var/threshold = 500
|
||||
var/static/list/approved_passengers = list()
|
||||
var/static/list/check_times = list()
|
||||
|
||||
|
||||
/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target)
|
||||
if(mover in approved_passengers)
|
||||
return TRUE
|
||||
|
||||
if(!isliving(mover)) //No stowaways
|
||||
return FALSE
|
||||
|
||||
return FALSE
|
||||
|
||||
|
||||
#define LUXURY_MESSAGE_COOLDOWN 100
|
||||
/obj/effect/forcefield/luxury_shuttle/Bumped(atom/movable/AM)
|
||||
if(!isliving(AM))
|
||||
return ..()
|
||||
|
||||
if(check_times[AM] && check_times[AM] > world.time) //Let's not spam the message
|
||||
return ..()
|
||||
|
||||
check_times[AM] = world.time + LUXURY_MESSAGE_COOLDOWN
|
||||
|
||||
var/total_cash = 0
|
||||
var/list/counted_money = list()
|
||||
|
||||
for(var/obj/item/coin/C in AM.GetAllContents())
|
||||
total_cash += C.value
|
||||
counted_money += C
|
||||
if(total_cash >= threshold)
|
||||
break
|
||||
for(var/obj/item/stack/spacecash/S in AM.GetAllContents())
|
||||
total_cash += S.value * S.amount
|
||||
counted_money += S
|
||||
if(total_cash >= threshold)
|
||||
break
|
||||
|
||||
if(AM.pulling)
|
||||
if(istype(AM.pulling, /obj/item/coin))
|
||||
var/obj/item/coin/C = AM.pulling
|
||||
total_cash += C.value
|
||||
counted_money += C
|
||||
|
||||
else if(istype(AM.pulling, /obj/item/stack/spacecash))
|
||||
var/obj/item/stack/spacecash/S = AM.pulling
|
||||
total_cash += S.value * S.amount
|
||||
counted_money += S
|
||||
|
||||
if(total_cash >= threshold)
|
||||
for(var/obj/I in counted_money)
|
||||
qdel(I)
|
||||
|
||||
to_chat(AM, "Thank you for your payment! Please enjoy your flight.")
|
||||
approved_passengers += AM
|
||||
check_times -= AM
|
||||
return
|
||||
else
|
||||
to_chat(AM, "<span class='warning'>You don't have enough money to enter the main shuttle. You'll have to fly coach.</span>")
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/fightpit
|
||||
name = "fight pit bear"
|
||||
desc = "This bear's trained through ancient Russian secrets to fear the walls of its glass prison."
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
|
||||
/obj/effect/decal/hammerandsickle
|
||||
name = "hammer and sickle"
|
||||
desc = "Communism powerful force."
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "communist"
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
|
||||
/obj/effect/decal/hammerandsickle/shuttleRotate(rotation)
|
||||
setDir(angle2dir(rotation+dir2angle(dir))) // No parentcall, rest of the rotate code breaks the pixel offset.
|
||||
@@ -1,162 +0,0 @@
|
||||
GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
|
||||
/mob/living,
|
||||
/obj/structure/blob,
|
||||
/obj/effect/rune,
|
||||
/obj/structure/spider/spiderling,
|
||||
/obj/item/disk/nuclear,
|
||||
/obj/machinery/nuclearbomb,
|
||||
/obj/item/beacon,
|
||||
/obj/singularity/narsie,
|
||||
/obj/singularity/wizard,
|
||||
/obj/machinery/teleport/station,
|
||||
/obj/machinery/teleport/hub,
|
||||
/obj/machinery/quantumpad,
|
||||
/obj/machinery/clonepod,
|
||||
/obj/effect/mob_spawn,
|
||||
/obj/effect/hierophant,
|
||||
/obj/structure/receiving_pad,
|
||||
/obj/effect/clockwork/spatial_gateway,
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk,
|
||||
/obj/item/warp_cube,
|
||||
/obj/machinery/rnd/production/protolathe, //print tracking beacons, send shuttle
|
||||
/obj/machinery/autolathe, //same
|
||||
/obj/item/projectile/beam/wormhole,
|
||||
/obj/effect/portal,
|
||||
/obj/item/shared_storage,
|
||||
/obj/structure/extraction_point,
|
||||
/obj/machinery/syndicatebomb,
|
||||
/obj/item/hilbertshotel
|
||||
)))
|
||||
|
||||
/obj/docking_port/mobile/supply
|
||||
name = "supply shuttle"
|
||||
id = "supply"
|
||||
callTime = 600
|
||||
|
||||
dir = WEST
|
||||
port_direction = EAST
|
||||
width = 12
|
||||
dwidth = 5
|
||||
height = 7
|
||||
movement_force = list("KNOCKDOWN" = 0, "THROW" = 0)
|
||||
|
||||
|
||||
//Export categories for this run, this is set by console sending the shuttle.
|
||||
var/export_categories = EXPORT_CARGO
|
||||
|
||||
/obj/docking_port/mobile/supply/register()
|
||||
. = ..()
|
||||
SSshuttle.supply = src
|
||||
|
||||
/obj/docking_port/mobile/supply/canMove()
|
||||
if(is_station_level(z))
|
||||
return check_blacklist(shuttle_areas)
|
||||
return ..()
|
||||
|
||||
/obj/docking_port/mobile/supply/proc/check_blacklist(areaInstances)
|
||||
for(var/place in areaInstances)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
for(var/trf in shuttle_area)
|
||||
var/turf/T = trf
|
||||
for(var/a in T.GetAllContents())
|
||||
if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types))
|
||||
return FALSE
|
||||
if(istype(a, /obj/structure/closet))//Prevents eigenlockers from ending up at CC
|
||||
var/obj/structure/closet/c = a
|
||||
if(c.eigen_teleport == TRUE)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/docking_port/mobile/supply/request(obj/docking_port/stationary/S)
|
||||
if(mode != SHUTTLE_IDLE)
|
||||
return 2
|
||||
return ..()
|
||||
|
||||
/obj/docking_port/mobile/supply/initiate_docking()
|
||||
if(getDockedId() == "supply_away") // Buy when we leave home.
|
||||
buy()
|
||||
. = ..() // Fly/enter transit.
|
||||
if(. != DOCKING_SUCCESS)
|
||||
return
|
||||
if(getDockedId() == "supply_away") // Sell when we get home
|
||||
sell()
|
||||
|
||||
/obj/docking_port/mobile/supply/proc/buy()
|
||||
if(!SSshuttle.shoppinglist.len)
|
||||
return
|
||||
|
||||
var/list/empty_turfs = list()
|
||||
for(var/place in shuttle_areas)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
for(var/turf/open/floor/T in shuttle_area)
|
||||
if(is_blocked_turf(T))
|
||||
continue
|
||||
empty_turfs += T
|
||||
|
||||
var/value = 0
|
||||
var/purchases = 0
|
||||
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
|
||||
if(!empty_turfs.len)
|
||||
break
|
||||
if(SO.pack.cost > SSshuttle.points)
|
||||
continue
|
||||
|
||||
SSshuttle.points -= SO.pack.cost
|
||||
value += SO.pack.cost
|
||||
SSshuttle.shoppinglist -= SO
|
||||
SSshuttle.orderhistory += SO
|
||||
|
||||
SO.generate(pick_n_take(empty_turfs))
|
||||
SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]"))
|
||||
investigate_log("Order #[SO.id] ([SO.pack.name], placed by [key_name(SO.orderer_ckey)]) has shipped.", INVESTIGATE_CARGO)
|
||||
if(SO.pack.dangerous)
|
||||
message_admins("\A [SO.pack.name] ordered by [ADMIN_LOOKUPFLW(SO.orderer_ckey)] has shipped.")
|
||||
purchases++
|
||||
|
||||
investigate_log("[purchases] orders in this shipment, worth [value] credits. [SSshuttle.points] credits left.", INVESTIGATE_CARGO)
|
||||
|
||||
/obj/docking_port/mobile/supply/proc/sell()
|
||||
var/presale_points = SSshuttle.points
|
||||
|
||||
if(!GLOB.exports_list.len) // No exports list? Generate it!
|
||||
setupExports()
|
||||
|
||||
var/msg = ""
|
||||
var/matched_bounty = FALSE
|
||||
|
||||
var/datum/export_report/ex = new
|
||||
|
||||
for(var/place in shuttle_areas)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
for(var/atom/movable/AM in shuttle_area)
|
||||
if(iscameramob(AM))
|
||||
continue
|
||||
if(bounty_ship_item_and_contents(AM, dry_run = FALSE))
|
||||
matched_bounty = TRUE
|
||||
if(!AM.anchored || istype(AM, /obj/mecha))
|
||||
export_item_and_contents(AM, export_categories , dry_run = FALSE, external_report = ex)
|
||||
|
||||
if(ex.exported_atoms)
|
||||
ex.exported_atoms += "." //ugh
|
||||
|
||||
if(matched_bounty)
|
||||
msg += "Bounty items received. An update has been sent to all bounty consoles. "
|
||||
|
||||
for(var/datum/export/E in ex.total_amount)
|
||||
var/export_text = E.total_printout(ex)
|
||||
if(!export_text)
|
||||
continue
|
||||
|
||||
msg += export_text + "\n"
|
||||
SSshuttle.points += ex.total_value[E]
|
||||
|
||||
for(var/datum/reagent/R in ex.total_reagents)
|
||||
var/amount = ex.total_reagents[R]
|
||||
var/value = amount*R.value
|
||||
if(!value)
|
||||
continue
|
||||
msg += "[value] credits: received [amount]u of [R.name].\n"
|
||||
SSshuttle.points += value
|
||||
|
||||
SSshuttle.centcom_message = msg
|
||||
investigate_log("Shuttle contents sold for [SSshuttle.points - presale_points] credits. Contents: [ex.exported_atoms || "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO)
|
||||
@@ -1,67 +0,0 @@
|
||||
#define SYNDICATE_CHALLENGE_TIMER 12000 //20 minutes
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate
|
||||
name = "syndicate shuttle terminal"
|
||||
desc = "The terminal used to control the syndicate transport shuttle."
|
||||
circuit = /obj/item/circuitboard/computer/syndicate_shuttle
|
||||
icon_screen = "syndishuttle"
|
||||
icon_keyboard = "syndie_key"
|
||||
light_color = LIGHT_COLOR_RED
|
||||
req_access = list(ACCESS_SYNDICATE)
|
||||
shuttleId = "syndicate"
|
||||
possible_destinations = "syndicate_away;syndicate_z5;syndicate_ne;syndicate_nw;syndicate_n;syndicate_se;syndicate_sw;syndicate_s;syndicate_custom"
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate/recall
|
||||
name = "syndicate shuttle recall terminal"
|
||||
desc = "Use this if your friends left you behind."
|
||||
possible_destinations = "syndicate_away"
|
||||
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate/Topic(href, href_list)
|
||||
if(href_list["move"])
|
||||
var/obj/item/circuitboard/computer/syndicate_shuttle/board = circuit
|
||||
if(board.challenge && world.time < SYNDICATE_CHALLENGE_TIMER)
|
||||
to_chat(usr, "<span class='warning'>You've issued a combat challenge to the station! You've got to give them at least [DisplayTimeText(SYNDICATE_CHALLENGE_TIMER - world.time)] more to allow them to prepare.</span>")
|
||||
return 0
|
||||
board.moved = TRUE
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate/allowed(mob/M)
|
||||
if(issilicon(M) && !(ROLE_SYNDICATE in M.faction))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate/drop_pod
|
||||
name = "syndicate assault pod control"
|
||||
desc = "Controls the drop pod's launch system."
|
||||
icon = 'icons/obj/terminals.dmi'
|
||||
icon_state = "dorm_available"
|
||||
light_color = LIGHT_COLOR_BLUE
|
||||
req_access = list(ACCESS_SYNDICATE)
|
||||
shuttleId = "steel_rain"
|
||||
possible_destinations = null
|
||||
clockwork = TRUE //it'd look weird
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate/drop_pod/Topic(href, href_list)
|
||||
if(href_list["move"])
|
||||
if(!is_centcom_level(z))
|
||||
to_chat(usr, "<span class='warning'>Pods are one way!</span>")
|
||||
return 0
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate
|
||||
name = "syndicate shuttle navigation computer"
|
||||
desc = "Used to designate a precise transit location for the syndicate shuttle."
|
||||
icon_screen = "syndishuttle"
|
||||
icon_keyboard = "syndie_key"
|
||||
shuttleId = "syndicate"
|
||||
lock_override = CAMERA_LOCK_STATION
|
||||
shuttlePortId = "syndicate_custom"
|
||||
jumpto_ports = list("syndicate_ne" = 1, "syndicate_nw" = 1, "syndicate_n" = 1, "syndicate_se" = 1, "syndicate_sw" = 1, "syndicate_s" = 1)
|
||||
view_range = 13
|
||||
x_offset = -7
|
||||
y_offset = -1
|
||||
see_hidden = TRUE
|
||||
|
||||
#undef SYNDICATE_CHALLENGE_TIMER
|
||||
Reference in New Issue
Block a user