initial commit - cross reference with 5th port - obviously has compile errors
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/obj/docking_port/mobile/assault_pod
|
||||
name = "assault pod"
|
||||
id = "steel_rain"
|
||||
dwidth = 3
|
||||
width = 7
|
||||
height = 7
|
||||
|
||||
/obj/docking_port/mobile/assault_pod/request()
|
||||
if(z == initial(src.z)) //No launching pods that have already launched
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/docking_port/mobile/assault_pod/dock(obj/docking_port/stationary/S1)
|
||||
..()
|
||||
if(!istype(S1, /obj/docking_port/stationary/transit))
|
||||
playsound(get_turf(src.loc), 'sound/effects/Explosion1.ogg',50,1)
|
||||
|
||||
|
||||
|
||||
/obj/item/device/assault_pod
|
||||
name = "Assault Pod Targetting Device"
|
||||
icon_state = "gangtool-red"
|
||||
item_state = "walkietalkie"
|
||||
desc = "Used to select a landing zone for assault pods."
|
||||
var/shuttle_id = "steel_rain"
|
||||
var/dwidth = 3
|
||||
var/dheight = 0
|
||||
var/width = 7
|
||||
var/height = 7
|
||||
var/lz_dir = 1
|
||||
|
||||
|
||||
/obj/item/device/assault_pod/attack_self(mob/living/user)
|
||||
var/target_area
|
||||
target_area = input("Area to land", "Select a Landing Zone", target_area) in teleportlocs
|
||||
var/area/picked_area = teleportlocs[target_area]
|
||||
if(!src || qdeleted(src))
|
||||
return
|
||||
|
||||
var/turf/T = safepick(get_area_turfs(picked_area))
|
||||
if(!T)
|
||||
return
|
||||
var/obj/docking_port/stationary/landing_zone = new /obj/docking_port/stationary(T)
|
||||
landing_zone.id = "assault_pod(\ref[src])"
|
||||
landing_zone.name = "Landing Zone"
|
||||
landing_zone.dwidth = dwidth
|
||||
landing_zone.dheight = dheight
|
||||
landing_zone.width = width
|
||||
landing_zone.height = height
|
||||
landing_zone.setDir(lz_dir)
|
||||
|
||||
for(var/obj/machinery/computer/shuttle/S in machines)
|
||||
if(S.shuttleId == shuttle_id)
|
||||
S.possible_destinations = "[landing_zone.id]"
|
||||
|
||||
user << "Landing zone set."
|
||||
|
||||
qdel(src)
|
||||
@@ -0,0 +1,78 @@
|
||||
/obj/machinery/computer/shuttle
|
||||
name = "Shuttle Console"
|
||||
icon_screen = "shuttle"
|
||||
icon_keyboard = "tech_key"
|
||||
req_access = list( )
|
||||
circuit = /obj/item/weapon/circuitboard/computer/shuttle
|
||||
var/shuttleId
|
||||
var/possible_destinations = ""
|
||||
var/admin_controlled
|
||||
var/no_destination_swap = 0
|
||||
|
||||
/obj/machinery/computer/shuttle/New(location, obj/item/weapon/circuitboard/computer/shuttle/C)
|
||||
..()
|
||||
if(istype(C))
|
||||
possible_destinations = C.possible_destinations
|
||||
shuttleId = C.shuttleId
|
||||
|
||||
/obj/machinery/computer/shuttle/attack_hand(mob/user)
|
||||
if(..(user))
|
||||
return
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
var/list/options = params2list(possible_destinations)
|
||||
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
|
||||
var/dat = "Status: [M ? M.getStatusText() : "*Missing*"]<br><br>"
|
||||
if(M)
|
||||
var/destination_found
|
||||
for(var/obj/docking_port/stationary/S in SSshuttle.stationary)
|
||||
if(!options.Find(S.id))
|
||||
continue
|
||||
if(M.canDock(S))
|
||||
continue
|
||||
destination_found = 1
|
||||
dat += "<A href='?src=\ref[src];move=[S.id]'>Send to [S.name]</A><br>"
|
||||
if(!destination_found)
|
||||
dat += "<B>Shuttle Locked</B><br>"
|
||||
if(admin_controlled)
|
||||
dat += "Authorized personnel only<br>"
|
||||
dat += "<A href='?src=\ref[src];request=1]'>Request Authorization</A><br>"
|
||||
dat += "<a href='?src=\ref[user];mach_close=computer'>Close</a>"
|
||||
|
||||
var/datum/browser/popup = new(user, "computer", M ? M.name : "shuttle", 300, 200)
|
||||
popup.set_content("<center>[dat]</center>")
|
||||
popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/shuttle/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
if(!allowed(usr))
|
||||
usr << "<span class='danger'>Access denied.</span>"
|
||||
return
|
||||
|
||||
if(href_list["move"])
|
||||
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
|
||||
if(M.launch_status == ENDGAME_LAUNCHED)
|
||||
usr << "<span class='warning'>You've already escaped. Never going back to that place again!</span>"
|
||||
return
|
||||
if(no_destination_swap)
|
||||
if(M.mode != SHUTTLE_IDLE)
|
||||
usr << "<span class='warning'>Shuttle already in transit.</span>"
|
||||
return
|
||||
switch(SSshuttle.moveShuttle(shuttleId, href_list["move"], 1))
|
||||
if(0)
|
||||
usr << "<span class='notice'>Shuttle received message and will be sent shortly.</span>"
|
||||
if(1)
|
||||
usr << "<span class='warning'>Invalid shuttle requested.</span>"
|
||||
else
|
||||
usr << "<span class='notice'>Unable to comply.</span>"
|
||||
|
||||
/obj/machinery/computer/shuttle/emag_act(mob/user)
|
||||
if(!emagged)
|
||||
src.req_access = list()
|
||||
emagged = 1
|
||||
user << "<span class='notice'>You fried the consoles ID checking system.</span>"
|
||||
|
||||
@@ -0,0 +1,479 @@
|
||||
#define TIME_LEFT (SSshuttle.emergency.timeLeft())
|
||||
#define ENGINES_START_TIME 10
|
||||
#define ENGINES_STARTED (TIME_LEFT <= ENGINES_START_TIME)
|
||||
#define IS_DOCKED (SSshuttle.emergency.mode == SHUTTLE_DOCKED)
|
||||
|
||||
/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/weapon/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 = 0, datum/tgui/master_ui = null, datum/ui_state/state = 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/weapon/card/id/ID = i
|
||||
var/name = ID.registered_name
|
||||
var/job = ID.assignment
|
||||
|
||||
if(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"] = emagged
|
||||
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/weapon/card/id/ID = user.get_idcard()
|
||||
|
||||
if(!ID)
|
||||
user << "<span class='warning'>You don't have an ID.</span>"
|
||||
return
|
||||
|
||||
if(!(access_heads in ID.access))
|
||||
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)
|
||||
if(authorized.len)
|
||||
minor_announce("[auth_need - authorized.len] authorizations \
|
||||
needed until shuttle is launched early", null, alert)
|
||||
else
|
||||
minor_announce("All authorizations to launch the shuttle \
|
||||
early have been revoked.")
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/proc/authorize(mob/user, source)
|
||||
var/obj/item/weapon/card/id/ID = user.get_idcard()
|
||||
|
||||
if(ID in authorized)
|
||||
return FALSE
|
||||
for(var/i in authorized)
|
||||
var/obj/item/weapon/card/id/other = i
|
||||
if(other.registered_name == ID.registered_name)
|
||||
return FALSE // No using IDs with the same name
|
||||
|
||||
authorized += ID
|
||||
|
||||
message_admins("[key_name_admin(user.client)] \
|
||||
(<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) \
|
||||
(<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) \
|
||||
has authorized early shuttle launch", 0, 1)
|
||||
log_game("[key_name(user)] has authorized early shuttle launch in \
|
||||
([x],[y],[z])")
|
||||
// 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(ENGINES_STARTED || (!IS_DOCKED))
|
||||
return .
|
||||
|
||||
// Check to see if we've reached criteria for early launch
|
||||
if((authorized.len >= auth_need) || emagged)
|
||||
// shuttle timers use 1/10th seconds internally
|
||||
SSshuttle.emergency.setTimer(ENGINES_START_TIME * 10)
|
||||
var/system_error = emagged ? "SYSTEM ERROR:" : null
|
||||
minor_announce("The emergency shuttle will launch in \
|
||||
[ENGINES_START_TIME] 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
|
||||
|
||||
var/time = TIME_LEFT
|
||||
message_admins("[key_name_admin(user.client)] \
|
||||
(<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) \
|
||||
(<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) \
|
||||
has emagged the emergency shuttle [time] seconds before launch.", 0, 1)
|
||||
log_game("[key_name(user)] has emagged the emergency shuttle in \
|
||||
([x],[y],[z]) [time] seconds before launch.")
|
||||
emagged = TRUE
|
||||
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/weapon/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
|
||||
|
||||
if(ENGINES_STARTED)
|
||||
// Give them a message anyway
|
||||
user << "<span class='warning'>The shuttle is already \
|
||||
about to launch!</span>"
|
||||
else
|
||||
process()
|
||||
|
||||
/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/weapon/card/id/ID in src)
|
||||
qdel(ID)
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/docking_port/mobile/emergency
|
||||
name = "emergency shuttle"
|
||||
id = "emergency"
|
||||
|
||||
dwidth = 9
|
||||
width = 22
|
||||
height = 11
|
||||
dir = EAST
|
||||
travelDir = -90
|
||||
roundstart_move = "emergency_away"
|
||||
var/sound_played = 0 //If the launch sound has been sent to all players on the shuttle itself
|
||||
|
||||
/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/timeLeft(divisor)
|
||||
if(divisor <= 0)
|
||||
divisor = 10
|
||||
if(!timer)
|
||||
return round(SSshuttle.emergencyCallTime/divisor, 1)
|
||||
|
||||
var/dtime = world.time - timer
|
||||
switch(mode)
|
||||
if(SHUTTLE_ESCAPE)
|
||||
dtime = max(SSshuttle.emergencyEscapeTime - dtime, 0)
|
||||
if(SHUTTLE_DOCKED)
|
||||
dtime = max(SSshuttle.emergencyDockTime - dtime, 0)
|
||||
else
|
||||
dtime = max(SSshuttle.emergencyCallTime - dtime, 0)
|
||||
return round(dtime/divisor, 1)
|
||||
|
||||
/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, coefficient=1, area/signalOrigin, reason, redAlert)
|
||||
SSshuttle.emergencyCallTime = initial(SSshuttle.emergencyCallTime) * coefficient
|
||||
switch(mode)
|
||||
if(SHUTTLE_RECALL)
|
||||
mode = SHUTTLE_CALL
|
||||
timer = world.time - timeLeft(1)
|
||||
if(SHUTTLE_IDLE)
|
||||
mode = SHUTTLE_CALL
|
||||
timer = world.time
|
||||
if(SHUTTLE_CALL)
|
||||
if(world.time < timer) //this is just failsafe
|
||||
timer = world.time
|
||||
else
|
||||
return
|
||||
|
||||
if(prob(70))
|
||||
SSshuttle.emergencyLastCallLoc = signalOrigin
|
||||
else
|
||||
SSshuttle.emergencyLastCallLoc = null
|
||||
|
||||
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, 'sound/AI/shuttlecalled.ogg', "Priority")
|
||||
|
||||
/obj/docking_port/mobile/emergency/cancel(area/signalOrigin)
|
||||
if(mode != SHUTTLE_CALL)
|
||||
return
|
||||
|
||||
timer = world.time - timeLeft(1)
|
||||
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, 'sound/AI/shuttlerecalled.ogg', "Priority")
|
||||
|
||||
/*
|
||||
/obj/docking_port/mobile/emergency/findTransitDock()
|
||||
. = SSshuttle.getDock("emergency_transit")
|
||||
if(.)
|
||||
return .
|
||||
return ..()
|
||||
*/
|
||||
|
||||
|
||||
/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(dock(SSshuttle.getDock("emergency_home")))
|
||||
setTimer(20)
|
||||
return
|
||||
mode = SHUTTLE_DOCKED
|
||||
timer = world.time
|
||||
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, 'sound/AI/shuttledock.ogg', "Priority")
|
||||
feedback_add_details("emergency_shuttle", src.name)
|
||||
|
||||
// Gangs only have one attempt left if the shuttle has
|
||||
// docked with the station to prevent suffering from
|
||||
// endless dominator delays
|
||||
for(var/datum/gang/G in ticker.mode.gangs)
|
||||
if(G.is_dominating)
|
||||
G.dom_attempts = 0
|
||||
else
|
||||
G.dom_attempts = min(1,G.dom_attempts)
|
||||
|
||||
if(SHUTTLE_DOCKED)
|
||||
|
||||
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.
|
||||
for(var/area/shuttle/escape/E in world)
|
||||
E << 'sound/effects/hyperspace_begin.ogg'
|
||||
|
||||
if(time_left <= 0 && SSshuttle.emergencyNoEscape)
|
||||
priority_announce("Hostile environment detected. Departure has been postponed indefinitely pending conflict resolution.", null, 'sound/misc/notice1.ogg', "Priority")
|
||||
sound_played = 0 //Since we didn't launch, we will need to rev up the engines again next pass.
|
||||
mode = SHUTTLE_STRANDED
|
||||
|
||||
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
|
||||
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.launch_status = ENDGAME_LAUNCHED
|
||||
M.enterTransit()
|
||||
|
||||
//now move the actual emergency shuttle to its transit dock
|
||||
for(var/area/shuttle/escape/E in world)
|
||||
E << 'sound/effects/hyperspace_progress.ogg'
|
||||
enterTransit()
|
||||
mode = SHUTTLE_ESCAPE
|
||||
launch_status = ENDGAME_LAUNCHED
|
||||
timer = world.time
|
||||
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_ESCAPE)
|
||||
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
|
||||
if(M.launch_status == ENDGAME_LAUNCHED)
|
||||
if(istype(M, /obj/docking_port/mobile/pod))
|
||||
M.dock(SSshuttle.getDock("[M.id]_away")) //Escape pods dock at centcomm
|
||||
else
|
||||
continue //Mapping a new docking point for each ship mappers could potentially want docking with centcomm would take up lots of space, just let them keep flying off into the sunset for their greentext
|
||||
|
||||
//now move the actual emergency shuttle to centcomm
|
||||
for(var/area/shuttle/escape/E in world)
|
||||
E << 'sound/effects/hyperspace_end.ogg'
|
||||
dock(SSshuttle.getDock("emergency_away"))
|
||||
mode = SHUTTLE_ENDGAME
|
||||
timer = 0
|
||||
open_dock()
|
||||
|
||||
/obj/docking_port/mobile/emergency/proc/open_dock()
|
||||
for(var/obj/machinery/door/poddoor/shuttledock/D in airlocks)
|
||||
var/turf/T = get_step(D, D.checkdir)
|
||||
if(!istype(T,/turf/open/space))
|
||||
spawn(0)
|
||||
D.open()
|
||||
|
||||
/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()
|
||||
if((security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA) && launch_status == UNLAUNCHED)
|
||||
launch_status = EARLY_LAUNCHED
|
||||
return ..()
|
||||
|
||||
/obj/docking_port/mobile/pod/New()
|
||||
if(id == "pod")
|
||||
WARNING("[type] id has not been changed from the default. Use the id convention \"pod1\" \"pod2\" etc.")
|
||||
..()
|
||||
|
||||
/obj/docking_port/mobile/pod/cancel()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/shuttle/pod
|
||||
name = "pod control computer"
|
||||
admin_controlled = 1
|
||||
shuttleId = "pod"
|
||||
possible_destinations = "pod_asteroid"
|
||||
icon = 'icons/obj/terminals.dmi'
|
||||
icon_state = "dorm_available"
|
||||
density = 0
|
||||
clockwork = TRUE //it'd look weird
|
||||
|
||||
/obj/machinery/computer/shuttle/pod/update_icon()
|
||||
return
|
||||
|
||||
/obj/docking_port/stationary/random
|
||||
name = "escape pod"
|
||||
id = "pod"
|
||||
dwidth = 1
|
||||
width = 3
|
||||
height = 4
|
||||
var/target_area = /area/lavaland/surface/outdoors
|
||||
|
||||
/obj/docking_port/stationary/random/initialize()
|
||||
..()
|
||||
var/list/turfs = get_area_turfs(target_area)
|
||||
var/turf/T = pick(turfs)
|
||||
src.loc = T
|
||||
|
||||
//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/weapon/pickaxe/emergency
|
||||
name = "emergency disembarkation tool"
|
||||
desc = "For extracting yourself from rough landings."
|
||||
|
||||
/obj/item/weapon/storage/pod
|
||||
name = "emergency space suits"
|
||||
desc = "A wall mounted safe containing space suits. Will only open in emergencies."
|
||||
anchored = 1
|
||||
density = 0
|
||||
icon = 'icons/obj/storage.dmi'
|
||||
icon_state = "safe"
|
||||
|
||||
/obj/item/weapon/storage/pod/New()
|
||||
..()
|
||||
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/weapon/tank/internals/oxygen/red(src)
|
||||
new /obj/item/weapon/tank/internals/oxygen/red(src)
|
||||
new /obj/item/weapon/pickaxe/emergency(src)
|
||||
new /obj/item/weapon/pickaxe/emergency(src)
|
||||
new /obj/item/weapon/survivalcapsule(src)
|
||||
|
||||
/obj/item/weapon/storage/pod/attackby(obj/item/weapon/W, mob/user, params)
|
||||
return
|
||||
|
||||
/obj/item/weapon/storage/pod/MouseDrop(over_object, src_location, over_location)
|
||||
if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA)
|
||||
return ..()
|
||||
else
|
||||
usr << "The storage unit will only unlock during a Red or Delta security alert."
|
||||
|
||||
/obj/item/weapon/storage/pod/attack_hand(mob/user)
|
||||
return
|
||||
|
||||
/obj/docking_port/mobile/emergency/backup
|
||||
name = "backup shuttle"
|
||||
id = "backup"
|
||||
dwidth = 2
|
||||
width = 8
|
||||
height = 8
|
||||
dir = EAST
|
||||
roundstart_move = "backup_away"
|
||||
|
||||
/obj/docking_port/mobile/emergency/backup/New()
|
||||
// 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
|
||||
|
||||
#undef UNLAUNCHED
|
||||
#undef LAUNCHED
|
||||
#undef EARLY_LAUNCHED
|
||||
#undef TIMELEFT
|
||||
#undef ENGINES_START_TIME
|
||||
#undef ENGINES_STARTED
|
||||
#undef IS_DOCKED
|
||||
@@ -0,0 +1,23 @@
|
||||
/obj/machinery/computer/shuttle/ferry
|
||||
name = "transport ferry console"
|
||||
circuit = /obj/item/weapon/circuitboard/computer/ferry
|
||||
shuttleId = "ferry"
|
||||
possible_destinations = "ferry_home;ferry_away"
|
||||
|
||||
|
||||
/obj/machinery/computer/shuttle/ferry/request
|
||||
name = "ferry console"
|
||||
circuit = /obj/item/weapon/circuitboard/computer/ferry/request
|
||||
var/last_request //prevents spamming admins
|
||||
var/cooldown = 600
|
||||
possible_destinations = "ferry_home"
|
||||
admin_controlled = 1
|
||||
|
||||
/obj/machinery/computer/shuttle/ferry/request/Topic(href, href_list)
|
||||
..()
|
||||
if(href_list["request"])
|
||||
if(last_request && (last_request + cooldown > world.time))
|
||||
return
|
||||
last_request = world.time
|
||||
usr << "<span class='notice'>Your request has been recieved by Centcom.</span>"
|
||||
admins << "<b>FERRY: <font color='blue'>[key_name_admin(usr)] (<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[usr]'>FLW</A>) (<A HREF='?_src_=holder;secrets=moveferry'>Move Ferry</a>)</b> is requesting to move the transport ferry to Centcom.</font>"
|
||||
@@ -0,0 +1,293 @@
|
||||
/obj/machinery/shuttle_manipulator
|
||||
name = "shuttle manipulator"
|
||||
desc = "I shall be telling this with a sigh\n\
|
||||
Somewhere ages and ages hence:\n\
|
||||
Two roads diverged in a wood, and I,\n\
|
||||
I took the one less traveled by,\n\
|
||||
And that has made all the difference."
|
||||
|
||||
icon = 'icons/obj/machines/shuttle_manipulator.dmi'
|
||||
icon_state = "holograph_on"
|
||||
|
||||
// UI state variables
|
||||
var/datum/map_template/shuttle/selected
|
||||
|
||||
var/obj/docking_port/mobile/existing_shuttle
|
||||
|
||||
var/obj/docking_port/mobile/preview_shuttle
|
||||
var/datum/map_template/shuttle/preview_template
|
||||
|
||||
/obj/machinery/shuttle_manipulator/New()
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/shuttle_manipulator/update_icon()
|
||||
cut_overlays()
|
||||
var/image/hologram_projection = image(icon, "hologram_on")
|
||||
hologram_projection.pixel_y = 22
|
||||
var/image/hologram_ship = image(icon, "hologram_whiteship")
|
||||
hologram_ship.pixel_y = 27
|
||||
add_overlay(hologram_projection)
|
||||
add_overlay(hologram_ship)
|
||||
|
||||
/obj/machinery/shuttle_manipulator/process()
|
||||
return
|
||||
|
||||
/obj/machinery/shuttle_manipulator/ui_interact(mob/user, ui_key = "main", \
|
||||
datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, \
|
||||
datum/ui_state/state = admin_state)
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "shuttle_manipulator", name, 800, 600, \
|
||||
master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/proc/shuttlemode2str(mode)
|
||||
switch(mode)
|
||||
if(SHUTTLE_IDLE)
|
||||
. = "idle"
|
||||
if(SHUTTLE_RECALL)
|
||||
. = "recalled"
|
||||
if(SHUTTLE_CALL)
|
||||
. = "called"
|
||||
if(SHUTTLE_DOCKED)
|
||||
. = "docked"
|
||||
if(SHUTTLE_STRANDED)
|
||||
. = "stranded"
|
||||
if(SHUTTLE_ESCAPE)
|
||||
. = "escape"
|
||||
if(SHUTTLE_ENDGAME)
|
||||
. = "endgame"
|
||||
if(!.)
|
||||
throw EXCEPTION("shuttlemode2str(): invalid mode [mode]")
|
||||
|
||||
|
||||
/obj/machinery/shuttle_manipulator/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["tabs"] = list("Status", "Templates", "Modification")
|
||||
|
||||
// Templates panel
|
||||
data["templates"] = list()
|
||||
var/list/templates = data["templates"]
|
||||
data["templates_tabs"] = list()
|
||||
data["selected"] = list()
|
||||
|
||||
for(var/shuttle_id in shuttle_templates)
|
||||
var/datum/map_template/shuttle/S = shuttle_templates[shuttle_id]
|
||||
|
||||
if(!templates[S.port_id])
|
||||
data["templates_tabs"] += S.port_id
|
||||
templates[S.port_id] = list(
|
||||
"port_id" = S.port_id,
|
||||
"templates" = list())
|
||||
|
||||
var/list/L = list()
|
||||
L["name"] = S.name
|
||||
L["shuttle_id"] = S.shuttle_id
|
||||
L["port_id"] = S.port_id
|
||||
L["description"] = S.description
|
||||
L["admin_notes"] = S.admin_notes
|
||||
|
||||
if(selected == S)
|
||||
data["selected"] = L
|
||||
|
||||
templates[S.port_id]["templates"] += list(L)
|
||||
|
||||
data["templates_tabs"] = sortList(data["templates_tabs"])
|
||||
|
||||
data["existing_shuttle"] = null
|
||||
|
||||
// Status panel
|
||||
data["shuttles"] = list()
|
||||
for(var/i in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = i
|
||||
var/list/L = list()
|
||||
L["name"] = M.name
|
||||
L["id"] = M.id
|
||||
L["timer"] = M.timer
|
||||
L["timeleft"] = M.getTimerStr()
|
||||
var/can_fast_travel = FALSE
|
||||
if(M.timer && M.timeLeft() >= 50)
|
||||
can_fast_travel = TRUE
|
||||
L["can_fast_travel"] = can_fast_travel
|
||||
L["mode"] = capitalize(shuttlemode2str(M.mode))
|
||||
L["status"] = M.getStatusText()
|
||||
if(M == existing_shuttle)
|
||||
data["existing_shuttle"] = L
|
||||
|
||||
data["shuttles"] += list(L)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/shuttle_manipulator/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/mob/user = usr
|
||||
|
||||
// Preload some common parameters
|
||||
var/shuttle_id = params["shuttle_id"]
|
||||
var/datum/map_template/shuttle/S = shuttle_templates[shuttle_id]
|
||||
|
||||
switch(action)
|
||||
if("select_template")
|
||||
if(S)
|
||||
existing_shuttle = SSshuttle.getShuttle(S.port_id)
|
||||
selected = S
|
||||
. = TRUE
|
||||
if("jump_to")
|
||||
if(params["type"] == "mobile")
|
||||
for(var/i in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = i
|
||||
if(M.id == params["id"])
|
||||
user.forceMove(get_turf(M))
|
||||
. = TRUE
|
||||
break
|
||||
if("fast_travel")
|
||||
for(var/i in SSshuttle.mobile)
|
||||
var/obj/docking_port/mobile/M = i
|
||||
if(M.id == params["id"] && M.timer && M.timeLeft() >= 50)
|
||||
M.setTimer(50)
|
||||
. = TRUE
|
||||
message_admins("[key_name_admin(usr)] fast travelled \
|
||||
[M]")
|
||||
log_admin("[key_name(usr)] fast travelled [M]")
|
||||
feedback_add_details("shuttle_fasttravel", M.name)
|
||||
break
|
||||
|
||||
if("preview")
|
||||
if(S)
|
||||
. = TRUE
|
||||
unload_preview()
|
||||
load_template(S)
|
||||
if(preview_shuttle)
|
||||
preview_template = S
|
||||
user.forceMove(get_turf(preview_shuttle))
|
||||
if("load")
|
||||
if(existing_shuttle == SSshuttle.backup_shuttle)
|
||||
// TODO make the load button disabled
|
||||
WARNING("The shuttle that the selected shuttle will replace \
|
||||
is the backup shuttle. Backup shuttle is required to be \
|
||||
intact for round sanity.")
|
||||
else if(S)
|
||||
. = TRUE
|
||||
// If successful, returns the mobile docking port
|
||||
var/obj/docking_port/mobile/mdp = action_load(S)
|
||||
if(mdp)
|
||||
user.forceMove(get_turf(mdp))
|
||||
message_admins("[key_name_admin(usr)] loaded [mdp] \
|
||||
with the shuttle manipulator.")
|
||||
log_admin("[key_name(usr)] loaded [mdp] with the \
|
||||
shuttle manipulator.</span>")
|
||||
feedback_add_details("shuttle_manipulator", mdp.name)
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/shuttle_manipulator/proc/action_load(
|
||||
datum/map_template/shuttle/loading_template)
|
||||
// Check for an existing preview
|
||||
if(preview_shuttle && (loading_template != preview_template))
|
||||
preview_shuttle.jumpToNullSpace()
|
||||
preview_shuttle = null
|
||||
preview_template = null
|
||||
|
||||
if(!preview_shuttle)
|
||||
load_template(loading_template)
|
||||
preview_template = loading_template
|
||||
|
||||
// get the existing shuttle information, if any
|
||||
var/timer = 0
|
||||
var/mode = SHUTTLE_IDLE
|
||||
var/obj/docking_port/stationary/D
|
||||
|
||||
if(existing_shuttle)
|
||||
timer = existing_shuttle.timer
|
||||
mode = existing_shuttle.mode
|
||||
D = existing_shuttle.get_docked()
|
||||
else
|
||||
D = preview_shuttle.findRoundstartDock()
|
||||
|
||||
if(!D)
|
||||
var/m = "No dock found for preview shuttle, aborting."
|
||||
WARNING(m)
|
||||
throw EXCEPTION(m)
|
||||
|
||||
var/result = preview_shuttle.canDock(D)
|
||||
// truthy value means that it cannot dock for some reason
|
||||
// but we can ignore the someone else docked error because we'll
|
||||
// be moving into their place shortly
|
||||
if(result && (result != SHUTTLE_SOMEONE_ELSE_DOCKED))
|
||||
var/m = "Unsuccessful dock of [preview_shuttle] ([result])."
|
||||
WARNING(m)
|
||||
return
|
||||
|
||||
existing_shuttle.jumpToNullSpace()
|
||||
|
||||
preview_shuttle.dock(D)
|
||||
. = preview_shuttle
|
||||
|
||||
// Shuttle state involves a mode and a timer based on world.time, so
|
||||
// plugging the existing shuttles old values in works fine.
|
||||
preview_shuttle.timer = timer
|
||||
preview_shuttle.mode = mode
|
||||
|
||||
preview_shuttle.register()
|
||||
|
||||
// TODO indicate to the user that success happened, rather than just
|
||||
// blanking the modification tab
|
||||
preview_shuttle = null
|
||||
preview_template = null
|
||||
existing_shuttle = null
|
||||
selected = null
|
||||
|
||||
/obj/machinery/shuttle_manipulator/proc/load_template(
|
||||
datum/map_template/shuttle/S)
|
||||
// load shuttle template, centred at shuttle import landmark,
|
||||
var/turf/landmark_turf = get_turf(locate("landmark*Shuttle Import"))
|
||||
S.load(landmark_turf, centered = TRUE)
|
||||
|
||||
var/affected = S.get_affected_turfs(landmark_turf, centered=TRUE)
|
||||
|
||||
var/found = 0
|
||||
// Search the turfs for docking ports
|
||||
// - We need to find the mobile docking port because that is the heart of
|
||||
// the shuttle.
|
||||
// - We need to check that no additional ports have slipped in from the
|
||||
// template, because that causes unintended behaviour.
|
||||
for(var/T in affected)
|
||||
for(var/obj/docking_port/P in T)
|
||||
if(istype(P, /obj/docking_port/mobile))
|
||||
var/obj/docking_port/mobile/M = P
|
||||
found++
|
||||
if(found > 1)
|
||||
qdel(P, force=TRUE)
|
||||
world.log << "Map warning: Shuttle Template [S.mappath] \
|
||||
has multiple mobile docking ports."
|
||||
else if(!M.timid)
|
||||
// The shuttle template we loaded isn't "timid" which means
|
||||
// it's already registered with the shuttles subsystem.
|
||||
// This is a bad thing.
|
||||
var/m = "Template [S] is non-timid! Unloading."
|
||||
WARNING(m)
|
||||
M.jumpToNullSpace()
|
||||
return
|
||||
else
|
||||
preview_shuttle = P
|
||||
if(istype(P, /obj/docking_port/stationary))
|
||||
world.log << "Map warning: Shuttle Template [S.mappath] has a \
|
||||
stationary docking port."
|
||||
if(!found)
|
||||
var/msg = "load_template(): Shuttle Template [S.mappath] has no \
|
||||
mobile docking port. Aborting import."
|
||||
for(var/T in affected)
|
||||
var/turf/T0 = T
|
||||
T0.empty()
|
||||
|
||||
message_admins(msg)
|
||||
WARNING(msg)
|
||||
|
||||
/obj/machinery/shuttle_manipulator/proc/unload_preview()
|
||||
if(preview_shuttle)
|
||||
preview_shuttle.jumpToNullSpace()
|
||||
preview_shuttle = null
|
||||
@@ -0,0 +1,18 @@
|
||||
/obj/effect/overlay/temp/ripple
|
||||
name = "hyperspace ripple"
|
||||
desc = "Something is coming through hyperspace, you can see the \
|
||||
visual disturbances. It's probably best not to be on top of these \
|
||||
when whatever is tunneling comes through."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "medi_holo"
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
layer = RIPPLE_LAYER
|
||||
mouse_opacity = 1
|
||||
alpha = 0
|
||||
|
||||
duration = 3 * SHUTTLE_RIPPLE_TIME
|
||||
|
||||
/obj/effect/overlay/temp/ripple/New()
|
||||
. = ..()
|
||||
animate(src, alpha=255, time=SHUTTLE_RIPPLE_TIME)
|
||||
@@ -0,0 +1,726 @@
|
||||
//use this define to highlight docking port bounding boxes (ONLY FOR DEBUG USE)
|
||||
// #define DOCKING_PORT_HIGHLIGHT
|
||||
|
||||
//NORTH default dir
|
||||
/obj/docking_port
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
icon = 'icons/obj/device.dmi'
|
||||
//icon = 'icons/dirsquare.dmi'
|
||||
icon_state = "pinonfar"
|
||||
|
||||
unacidable = 1
|
||||
anchored = 1
|
||||
|
||||
var/id
|
||||
dir = NORTH//this should point -away- from the dockingport door, ie towards the ship
|
||||
var/width = 0 //size of covered area, perpendicular to dir
|
||||
var/height = 0 //size of covered area, paralell to dir
|
||||
var/dwidth = 0 //position relative to covered area, perpendicular to dir
|
||||
var/dheight = 0 //position relative to covered area, parallel to dir
|
||||
|
||||
//these objects are indestructable
|
||||
/obj/docking_port/Destroy(force)
|
||||
// unless you assert that you know what you're doing. Horrible things
|
||||
// may result.
|
||||
if(force)
|
||||
..()
|
||||
. = QDEL_HINT_HARDDEL_NOW
|
||||
else
|
||||
return QDEL_HINT_LETMELIVE
|
||||
|
||||
/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)
|
||||
_dir = dir
|
||||
if(!_x)
|
||||
_x = x
|
||||
if(!_y)
|
||||
_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 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, area/A)
|
||||
if(!_dir)
|
||||
_dir = dir
|
||||
if(!_x)
|
||||
_x = x
|
||||
if(!_y)
|
||||
_y = y
|
||||
if(!_z)
|
||||
_z = z
|
||||
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()
|
||||
|
||||
var/xi
|
||||
var/yi
|
||||
for(var/dx=0, dx<width, ++dx)
|
||||
for(var/dy=0, dy<height, ++dy)
|
||||
xi = _x + (dx-dwidth)*cos - (dy-dheight)*sin
|
||||
yi = _y + (dy-dheight)*cos + (dx-dwidth)*sin
|
||||
var/turf/T = locate(xi, yi, _z)
|
||||
if(A)
|
||||
if(get_area(T) == A)
|
||||
. += T
|
||||
else
|
||||
. += null
|
||||
else
|
||||
. += T
|
||||
|
||||
#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
|
||||
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/stationary
|
||||
name = "dock"
|
||||
|
||||
var/turf_type = /turf/open/space
|
||||
var/area_type = /area/space
|
||||
|
||||
/obj/docking_port/stationary/New()
|
||||
..()
|
||||
SSshuttle.stationary += src
|
||||
if(!id)
|
||||
id = "[SSshuttle.stationary.len]"
|
||||
if(name == "dock")
|
||||
name = "dock[SSshuttle.stationary.len]"
|
||||
|
||||
#ifdef DOCKING_PORT_HIGHLIGHT
|
||||
highlight("#f00")
|
||||
#endif
|
||||
|
||||
//returns first-found touching shuttleport
|
||||
/obj/docking_port/stationary/get_docked()
|
||||
. = locate(/obj/docking_port/mobile) in loc
|
||||
/*
|
||||
for(var/turf/T in return_ordered_turfs())
|
||||
. = locate(/obj/docking_port/mobile) in loc
|
||||
if(.)
|
||||
return .
|
||||
*/
|
||||
|
||||
/obj/docking_port/stationary/transit
|
||||
name = "In Transit"
|
||||
turf_type = /turf/open/space/transit
|
||||
|
||||
/obj/docking_port/stationary/transit/New()
|
||||
..()
|
||||
SSshuttle.transit += src
|
||||
|
||||
|
||||
/obj/docking_port/mobile
|
||||
icon_state = "mobile"
|
||||
name = "shuttle"
|
||||
icon_state = "pinonclose"
|
||||
|
||||
var/area/shuttle/areaInstance
|
||||
|
||||
var/timer //used as a timer (if you want time left to complete move, use timeLeft proc)
|
||||
var/mode = SHUTTLE_IDLE //current shuttle mode (see /__DEFINES/stat.dm)
|
||||
var/callTime = 150 //time spent in transit (deciseconds)
|
||||
var/roundstart_move //id of port to send shuttle to at roundstart
|
||||
var/travelDir = 0 //direction the shuttle would travel in
|
||||
|
||||
var/obj/docking_port/stationary/destination
|
||||
var/obj/docking_port/stationary/previous
|
||||
|
||||
var/launch_status = NOLAUNCH
|
||||
|
||||
// A timid shuttle will not register itself with the shuttle subsystem
|
||||
// All shuttle templates are timid
|
||||
var/timid = FALSE
|
||||
|
||||
var/list/ripples = list()
|
||||
|
||||
/obj/docking_port/mobile/New()
|
||||
..()
|
||||
if(!timid)
|
||||
register()
|
||||
|
||||
/obj/docking_port/mobile/proc/register()
|
||||
SSshuttle.mobile += src
|
||||
|
||||
/obj/docking_port/mobile/Destroy(force)
|
||||
if(force)
|
||||
SSshuttle.mobile -= src
|
||||
. = ..()
|
||||
|
||||
/obj/docking_port/mobile/initialize()
|
||||
var/area/A = get_area(src)
|
||||
if(istype(A, /area/shuttle))
|
||||
areaInstance = A
|
||||
|
||||
if(!id)
|
||||
id = "[SSshuttle.mobile.len]"
|
||||
if(name == "shuttle")
|
||||
name = "shuttle[SSshuttle.mobile.len]"
|
||||
|
||||
if(!areaInstance)
|
||||
areaInstance = new()
|
||||
areaInstance.name = name
|
||||
areaInstance.contents += return_ordered_turfs()
|
||||
|
||||
#ifdef DOCKING_PORT_HIGHLIGHT
|
||||
highlight("#0f0")
|
||||
#endif
|
||||
|
||||
//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 0 //0 means we can move
|
||||
|
||||
//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 FALSE
|
||||
|
||||
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 FALSE
|
||||
|
||||
//call the shuttle to destination S
|
||||
/obj/docking_port/mobile/proc/request(obj/docking_port/stationary/S)
|
||||
var/status = canDock(S)
|
||||
if(status == SHUTTLE_ALREADY_DOCKED)
|
||||
// We're already docked there, don't need to do anything.
|
||||
// Triggering shuttle movement code in place is weird
|
||||
return
|
||||
else if(status)
|
||||
var/msg = "request(): shuttle [src] cannot dock at [S], \
|
||||
error: [status]"
|
||||
message_admins(msg)
|
||||
throw EXCEPTION(msg)
|
||||
|
||||
switch(mode)
|
||||
if(SHUTTLE_CALL)
|
||||
if(S == destination)
|
||||
if(world.time <= timer)
|
||||
timer = world.time
|
||||
else
|
||||
destination = S
|
||||
timer = world.time
|
||||
if(SHUTTLE_RECALL)
|
||||
if(S == destination)
|
||||
timer = world.time - timeLeft(1)
|
||||
else
|
||||
destination = S
|
||||
timer = world.time
|
||||
mode = SHUTTLE_CALL
|
||||
else
|
||||
destination = S
|
||||
mode = SHUTTLE_CALL
|
||||
timer = world.time
|
||||
enterTransit() //hyperspace
|
||||
|
||||
//recall the shuttle to where it was previously
|
||||
/obj/docking_port/mobile/proc/cancel()
|
||||
if(mode != SHUTTLE_CALL)
|
||||
return
|
||||
|
||||
remove_ripples()
|
||||
|
||||
timer = world.time - timeLeft(1)
|
||||
mode = SHUTTLE_RECALL
|
||||
|
||||
/obj/docking_port/mobile/proc/enterTransit()
|
||||
previous = null
|
||||
// if(!destination)
|
||||
// return
|
||||
var/obj/docking_port/stationary/S0 = get_docked()
|
||||
var/obj/docking_port/stationary/S1 = findTransitDock()
|
||||
if(S1)
|
||||
if(dock(S1))
|
||||
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"]")
|
||||
|
||||
//default shuttleRotate
|
||||
/atom/proc/shuttleRotate(rotation)
|
||||
//rotate our direction
|
||||
setDir(angle2dir(rotation+dir2angle(dir)))
|
||||
|
||||
//resmooth if need be.
|
||||
if(smooth)
|
||||
queue_smooth(src)
|
||||
|
||||
//rotate the pixel offsets too.
|
||||
if (pixel_x || pixel_y)
|
||||
if (rotation < 0)
|
||||
rotation += 360
|
||||
for (var/turntimes=rotation/90;turntimes>0;turntimes--)
|
||||
var/oldPX = pixel_x
|
||||
var/oldPY = pixel_y
|
||||
pixel_x = oldPY
|
||||
pixel_y = (oldPX*(-1))
|
||||
|
||||
/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/S0 = get_docked()
|
||||
var/turf_type = /turf/open/space
|
||||
var/area_type = /area/space
|
||||
// If the shuttle is docked to a stationary port, restore its normal
|
||||
// "empty" area and turf
|
||||
if(S0)
|
||||
if(S0.turf_type)
|
||||
turf_type = S0.turf_type
|
||||
if(S0.area_type)
|
||||
area_type = S0.area_type
|
||||
|
||||
var/list/L0 = return_ordered_turfs(x, y, z, dir, areaInstance)
|
||||
|
||||
//remove area surrounding docking port
|
||||
if(areaInstance.contents.len)
|
||||
var/area/A0 = locate("[area_type]")
|
||||
if(!A0)
|
||||
A0 = new area_type(null)
|
||||
for(var/turf/T0 in L0)
|
||||
A0.contents += T0
|
||||
|
||||
for(var/i in L0)
|
||||
var/turf/T0 =i
|
||||
if(!T0)
|
||||
continue
|
||||
T0.empty(turf_type)
|
||||
|
||||
qdel(src, force=TRUE)
|
||||
|
||||
/obj/docking_port/mobile/proc/create_ripples(obj/docking_port/stationary/S1)
|
||||
var/list/turfs = ripple_area(S1)
|
||||
for(var/t in turfs)
|
||||
ripples += PoolOrNew(/obj/effect/overlay/temp/ripple, t)
|
||||
|
||||
/obj/docking_port/mobile/proc/remove_ripples()
|
||||
for(var/R in ripples)
|
||||
qdel(R)
|
||||
ripples.Cut()
|
||||
|
||||
/obj/docking_port/mobile/proc/ripple_area(obj/docking_port/stationary/S1)
|
||||
var/list/L0 = return_ordered_turfs(x, y, z, dir, areaInstance)
|
||||
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]
|
||||
if(!T0)
|
||||
continue
|
||||
var/turf/T1 = L1[i]
|
||||
if(!T1)
|
||||
continue
|
||||
if(T0.type != T0.baseturf)
|
||||
ripple_turfs += T1
|
||||
|
||||
return ripple_turfs
|
||||
//this is the main proc. It instantly moves our mobile port to stationary port S1
|
||||
//it handles all the generic behaviour, such as sanity checks, closing doors on the shuttle, stunning mobs, etc
|
||||
/obj/docking_port/mobile/proc/dock(obj/docking_port/stationary/S1, force=FALSE)
|
||||
// Crashing this ship with NO SURVIVORS
|
||||
if(!force)
|
||||
var/status = canDock(S1)
|
||||
if(status == SHUTTLE_ALREADY_DOCKED)
|
||||
return status
|
||||
else if(status)
|
||||
var/msg = "dock(): shuttle [src] cannot dock at [S1], \
|
||||
error: [status]"
|
||||
message_admins(msg)
|
||||
return status
|
||||
|
||||
if(canMove())
|
||||
return -1
|
||||
|
||||
closePortDoors()
|
||||
|
||||
// //rotate transit docking ports, so we don't need zillions of variants
|
||||
// if(istype(S1, /obj/docking_port/stationary/transit))
|
||||
// S1.setDir(turn(NORTH, -travelDir))
|
||||
|
||||
var/obj/docking_port/stationary/S0 = get_docked()
|
||||
var/turf_type = /turf/open/space
|
||||
var/area_type = /area/space
|
||||
if(S0)
|
||||
if(S0.turf_type)
|
||||
turf_type = S0.turf_type
|
||||
if(S0.area_type)
|
||||
area_type = S0.area_type
|
||||
|
||||
var/list/L0 = return_ordered_turfs(x, y, z, dir, areaInstance)
|
||||
var/list/L1 = return_ordered_turfs(S1.x, S1.y, S1.z, S1.dir)
|
||||
|
||||
var/rotation = dir2angle(S1.dir)-dir2angle(dir)
|
||||
if ((rotation % 90) != 0)
|
||||
rotation += (rotation % 90) //diagonal rotations not allowed, round up
|
||||
rotation = SimplifyDegrees(rotation)
|
||||
|
||||
//remove area surrounding docking port
|
||||
if(areaInstance.contents.len)
|
||||
var/area/A0 = locate("[area_type]")
|
||||
if(!A0)
|
||||
A0 = new area_type(null)
|
||||
for(var/turf/T0 in L0)
|
||||
A0.contents += T0
|
||||
|
||||
|
||||
remove_ripples()
|
||||
|
||||
//move or squish anything in the way ship at destination
|
||||
roadkill(L0, L1, S1.dir)
|
||||
|
||||
for(var/i in 1 to L0.len)
|
||||
var/turf/T0 = L0[i]
|
||||
if(!T0)
|
||||
continue
|
||||
var/turf/T1 = L1[i]
|
||||
if(!T1)
|
||||
continue
|
||||
if(T0.type != T0.baseturf) //So if there is a hole in the shuttle we don't drag along the space/asteroid/etc to wherever we are going next
|
||||
T0.copyTurf(T1)
|
||||
areaInstance.contents += T1
|
||||
|
||||
//copy over air
|
||||
if(istype(T1, /turf/open))
|
||||
var/turf/open/Ts1 = T1
|
||||
Ts1.copy_air_with_tile(T0)
|
||||
|
||||
//move mobile to new location
|
||||
for(var/atom/movable/AM in T0)
|
||||
AM.onShuttleMove(T1, rotation)
|
||||
|
||||
if(rotation)
|
||||
T1.shuttleRotate(rotation)
|
||||
|
||||
//lighting stuff
|
||||
T1.redraw_lighting()
|
||||
SSair.remove_from_active(T1)
|
||||
T1.CalculateAdjacentTurfs()
|
||||
SSair.add_to_active(T1,1)
|
||||
|
||||
T0.ChangeTurf(turf_type)
|
||||
|
||||
T0.redraw_lighting()
|
||||
SSair.remove_from_active(T0)
|
||||
T0.CalculateAdjacentTurfs()
|
||||
SSair.add_to_active(T0,1)
|
||||
|
||||
loc = S1.loc
|
||||
setDir(S1.dir)
|
||||
|
||||
/atom/movable/proc/onShuttleMove(turf/T1, rotation)
|
||||
if(rotation)
|
||||
shuttleRotate(rotation)
|
||||
loc = T1
|
||||
return 1
|
||||
|
||||
/obj/onShuttleMove()
|
||||
if(invisibility >= INVISIBILITY_ABSTRACT)
|
||||
return 0
|
||||
. = ..()
|
||||
|
||||
/atom/movable/light/onShuttleMove()
|
||||
return 0
|
||||
|
||||
/obj/machinery/door/onShuttleMove()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
addtimer(src, "close", 0)
|
||||
|
||||
/mob/onShuttleMove()
|
||||
if(!move_on_shuttle)
|
||||
return 0
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(client)
|
||||
if(buckled)
|
||||
shake_camera(src, 2, 1) // turn it down a bit come on
|
||||
else
|
||||
shake_camera(src, 7, 1)
|
||||
|
||||
/mob/living/carbon/onShuttleMove()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!buckled)
|
||||
Weaken(3)
|
||||
|
||||
/*
|
||||
if(istype(S1, /obj/docking_port/stationary/transit))
|
||||
var/d = turn(dir, 180 + travelDir)
|
||||
for(var/turf/open/space/transit/T in S1.return_ordered_turfs())
|
||||
T.pushdirection = d
|
||||
T.update_icon()
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/findTransitDock()
|
||||
var/obj/docking_port/stationary/transit/T = SSshuttle.getDock("[id]_transit")
|
||||
if(T && !canDock(T))
|
||||
return T
|
||||
|
||||
/obj/docking_port/mobile/proc/findRoundstartDock()
|
||||
var/obj/docking_port/stationary/D
|
||||
D = SSshuttle.getDock(roundstart_move)
|
||||
|
||||
if(D)
|
||||
return D
|
||||
|
||||
/obj/docking_port/mobile/proc/dockRoundstart()
|
||||
// Instead of spending a lot of time trying to work out where to place
|
||||
// our shuttle, just create it somewhere empty and send it to where
|
||||
// it should go
|
||||
var/obj/docking_port/stationary/D = findRoundstartDock()
|
||||
return dock(D)
|
||||
|
||||
/obj/effect/landmark/shuttle_import
|
||||
name = "Shuttle Import"
|
||||
|
||||
/* commented out due to issues with rotation
|
||||
for(var/obj/docking_port/stationary/transit/S in SSshuttle.transit)
|
||||
if(S.id)
|
||||
continue
|
||||
if(!canDock(S))
|
||||
return S
|
||||
*/
|
||||
|
||||
|
||||
//shuttle-door closing is handled in the dock() proc whilst looping through turfs
|
||||
//this one closes the door where we are docked at, if there is one there.
|
||||
/obj/docking_port/mobile/proc/closePortDoors()
|
||||
var/turf/T = get_step(loc, turn(dir,180))
|
||||
if(T)
|
||||
var/obj/machinery/door/Door = locate() in T
|
||||
if(Door)
|
||||
addtimer(Door, "close", 0)
|
||||
|
||||
/obj/docking_port/mobile/proc/roadkill(list/L0, list/L1, dir)
|
||||
var/list/hurt_mobs = list()
|
||||
for(var/i in 1 to L0.len)
|
||||
var/turf/T0 = L0[i]
|
||||
var/turf/T1 = L1[i]
|
||||
if(!T0 || !T1)
|
||||
continue
|
||||
if(T0.type == T0.baseturf)
|
||||
continue
|
||||
// The corresponding tile will not be changed, so no roadkill
|
||||
|
||||
for(var/atom/movable/AM in T1)
|
||||
if(isliving(AM) && (!(AM in hurt_mobs)))
|
||||
hurt_mobs |= AM
|
||||
var/mob/living/M = AM
|
||||
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'>[M] is hit by \
|
||||
a hyperspace ripple[M.anchored ? "":" and is thrown clear"]!</span>",
|
||||
"<span class='userdanger'>You feel an immense \
|
||||
crushing pressure as the space around you ripples.</span>")
|
||||
if(M.anchored)
|
||||
M.gib()
|
||||
else
|
||||
M.Paralyse(10)
|
||||
M.ex_act(2)
|
||||
step(M, dir)
|
||||
continue
|
||||
|
||||
if(!AM.anchored)
|
||||
step(AM, dir)
|
||||
else
|
||||
qdel(AM)
|
||||
/*
|
||||
//used to check if atom/A is within the shuttle's bounding box
|
||||
/obj/docking_port/mobile/proc/onShuttleCheck(atom/A)
|
||||
var/turf/T = get_turf(A)
|
||||
if(!T)
|
||||
return 0
|
||||
|
||||
var/list/L = return_coords()
|
||||
if(L[1] > L[3])
|
||||
L.Swap(1,3)
|
||||
if(L[2] > L[4])
|
||||
L.Swap(2,4)
|
||||
|
||||
if(L[1] <= T.x && T.x <= L[3])
|
||||
if(L[2] <= T.y && T.y <= L[4])
|
||||
return 1
|
||||
return 0
|
||||
*/
|
||||
//used by shuttle subsystem to check timers
|
||||
/obj/docking_port/mobile/proc/check()
|
||||
var/timeLeft = timeLeft(1)
|
||||
if(!ripples.len && (timeLeft <= SHUTTLE_RIPPLE_TIME) && ((mode == SHUTTLE_CALL) || (mode == SHUTTLE_RECALL)))
|
||||
create_ripples(destination)
|
||||
|
||||
if(timeLeft <= 0)
|
||||
switch(mode)
|
||||
if(SHUTTLE_CALL)
|
||||
if(dock(destination))
|
||||
setTimer(20) //can't dock for some reason, try again in 2 seconds
|
||||
return
|
||||
if(SHUTTLE_RECALL)
|
||||
if(dock(previous))
|
||||
setTimer(20) //can't dock for some reason, try again in 2 seconds
|
||||
return
|
||||
mode = SHUTTLE_IDLE
|
||||
timer = 0
|
||||
destination = null
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/setTimer(wait)
|
||||
if(timer <= 0)
|
||||
timer = world.time
|
||||
timer += wait - timeLeft(1)
|
||||
|
||||
//returns timeLeft
|
||||
/obj/docking_port/mobile/proc/timeLeft(divisor)
|
||||
if(divisor <= 0)
|
||||
divisor = 10
|
||||
if(!timer)
|
||||
return round(callTime/divisor, 1)
|
||||
return max( round((timer+callTime-world.time)/divisor,1), 0 )
|
||||
|
||||
// returns 3-letter mode string, used by status screens and mob status panel
|
||||
/obj/docking_port/mobile/proc/getModeStr()
|
||||
switch(mode)
|
||||
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 > 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()
|
||||
. = (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
|
||||
. += " towards [dst ? dst.name : "unknown location"] ([timeLeft(600)] minutes)"
|
||||
#undef DOCKING_PORT_HIGHLIGHT
|
||||
|
||||
|
||||
/turf/proc/copyTurf(turf/T)
|
||||
if(T.type != type)
|
||||
var/obj/O
|
||||
if(underlays.len) //we have underlays, which implies some sort of transparency, so we want to a snapshot of the previous turf as an underlay
|
||||
O = new()
|
||||
O.underlays.Add(T)
|
||||
T.ChangeTurf(type)
|
||||
if(underlays.len)
|
||||
T.underlays = O.underlays
|
||||
if(T.icon_state != icon_state)
|
||||
T.icon_state = icon_state
|
||||
if(T.icon != icon)
|
||||
T.icon = icon
|
||||
if(T.color != color)
|
||||
T.color = color
|
||||
if(T.dir != dir)
|
||||
T.setDir(dir)
|
||||
return T
|
||||
@@ -0,0 +1,217 @@
|
||||
// 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"
|
||||
var/list/active_tables = list()
|
||||
var/tables_required = 2
|
||||
active = FALSE
|
||||
|
||||
/obj/machinery/power/emitter/energycannon/magical/New()
|
||||
. = ..()
|
||||
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/attack_hand(mob/user)
|
||||
return
|
||||
|
||||
/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
|
||||
|
||||
/obj/structure/table/abductor/wabbajack
|
||||
name = "wabbajack altar"
|
||||
desc = "Whether you're sleeping or waking, it's going to be \
|
||||
quite chaotic."
|
||||
health = 1000
|
||||
verb_say = "chants"
|
||||
var/obj/machinery/power/emitter/energycannon/magical/our_statue
|
||||
var/list/mob/living/sleepers = list()
|
||||
var/never_spoken = TRUE
|
||||
flags = NODECONSTRUCT
|
||||
|
||||
/obj/structure/table/abductor/wabbajack/New()
|
||||
. = ..()
|
||||
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.color = "#800080"
|
||||
L.visible_message("<span class='revennotice'>A strange purple glow \
|
||||
wraps itself around [L] as they suddenly fall unconcious.</span>",
|
||||
"<span class='revendanger'>[desc]</span>")
|
||||
// Don't let them sit suround unconscious forever
|
||||
addtimer(src, "sleeper_dreams", 100, FALSE, L)
|
||||
|
||||
// Existing sleepers
|
||||
for(var/i in found)
|
||||
var/mob/living/L = i
|
||||
L.SetSleeping(10)
|
||||
|
||||
// Missing sleepers
|
||||
for(var/i in sleepers - found)
|
||||
var/mob/living/L = i
|
||||
L.color = initial(L.color)
|
||||
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)
|
||||
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."
|
||||
seeStatic = FALSE
|
||||
laws = "1. Serve drinks.\n\
|
||||
2. Talk to patrons.\n\
|
||||
3. Don't get messed up in their affairs."
|
||||
languages_spoken = ALL
|
||||
languages_understood = ALL
|
||||
status_flags = GODMODE // Please don't punch the barkeeper
|
||||
unique_name = FALSE // disables the (123) number suffix
|
||||
|
||||
/mob/living/simple_animal/drone/snowflake/bardrone/New()
|
||||
. = ..()
|
||||
access_card.access |= access_cent_bar
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/maid/barmaid
|
||||
gold_core_spawnable = 0
|
||||
name = "Barmaid"
|
||||
desc = "A barmaid, a maiden found in a bar."
|
||||
pass_flags = PASSTABLE
|
||||
status_flags = GODMODE
|
||||
languages_spoken = ALL
|
||||
languages_understood = ALL
|
||||
unique_name = FALSE
|
||||
AIStatus = AI_OFF
|
||||
stop_automated_movement = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/maid/barmaid/New()
|
||||
. = ..()
|
||||
access_card = new /obj/item/weapon/card/id(src)
|
||||
var/datum/job/captain/C = new /datum/job/captain
|
||||
access_card.access = C.get_access()
|
||||
access_card.access |= access_cent_bar
|
||||
access_card.flags |= NODROP
|
||||
|
||||
/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
|
||||
burn_state = LAVA_PROOF
|
||||
flags = NODECONSTRUCT
|
||||
health = 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.Weaken(2)
|
||||
M.throw_at_fast(throwtarget, 5, 1,src)
|
||||
M << "<span class='notice'>No climbing on the bar please.</span>"
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/structure/table/wood/bar/shuttleRotate(rotation)
|
||||
. = ..()
|
||||
boot_dir = angle2dir(rotation + dir2angle(boot_dir))
|
||||
|
||||
/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/weapon/card/id/ID = user.get_idcard()
|
||||
if(ID && (access_cent_bar in ID.access))
|
||||
return TRUE
|
||||
@@ -0,0 +1,124 @@
|
||||
var/list/blacklisted_cargo_types = typecacheof(list(
|
||||
/mob/living,
|
||||
/obj/effect/blob,
|
||||
/obj/effect/rune,
|
||||
/obj/effect/spider/spiderling,
|
||||
/obj/item/weapon/disk/nuclear,
|
||||
/obj/machinery/nuclearbomb,
|
||||
/obj/item/device/radio/beacon,
|
||||
/obj/singularity,
|
||||
/obj/machinery/teleport/station,
|
||||
/obj/machinery/teleport/hub,
|
||||
/obj/machinery/telepad,
|
||||
/obj/machinery/clonepod,
|
||||
/obj/effect/mob_spawn
|
||||
))
|
||||
|
||||
/obj/docking_port/mobile/supply
|
||||
name = "supply shuttle"
|
||||
id = "supply"
|
||||
callTime = 600
|
||||
|
||||
dir = WEST
|
||||
travelDir = 90
|
||||
width = 12
|
||||
dwidth = 5
|
||||
height = 7
|
||||
roundstart_move = "supply_away"
|
||||
|
||||
// When TRUE, these vars allow exporting emagged/contraband items, and add some special interactions to existing exports.
|
||||
var/contraband = FALSE
|
||||
var/emagged = FALSE
|
||||
|
||||
/obj/docking_port/mobile/supply/register()
|
||||
. = ..()
|
||||
SSshuttle.supply = src
|
||||
|
||||
/obj/docking_port/mobile/supply/canMove()
|
||||
if(z == ZLEVEL_STATION)
|
||||
return check_blacklist(areaInstance)
|
||||
return ..()
|
||||
|
||||
/obj/docking_port/mobile/supply/proc/check_blacklist(areaInstance)
|
||||
for(var/trf in areaInstance)
|
||||
var/turf/T = trf
|
||||
for(var/a in T.GetAllContents())
|
||||
if(is_type_in_typecache(a, blacklisted_cargo_types))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/docking_port/mobile/supply/request()
|
||||
if(mode != SHUTTLE_IDLE)
|
||||
return 2
|
||||
return ..()
|
||||
|
||||
/obj/docking_port/mobile/supply/dock()
|
||||
if(getDockedId() == "supply_away") // Buy when we leave home.
|
||||
buy()
|
||||
if(..()) // Fly/enter transit.
|
||||
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/turf/open/floor/T in areaInstance)
|
||||
if(T.density || T.contents.len)
|
||||
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))
|
||||
feedback_add_details("cargo_imports",
|
||||
"[SO.pack.type]|[SO.pack.name]|[SO.pack.cost]")
|
||||
investigate_log("Order #[SO.id] ([SO.pack.name], placed by [key_name(SO.orderer_ckey)]) has shipped.", "cargo")
|
||||
if(SO.pack.dangerous)
|
||||
message_admins("\A [SO.pack.name] ordered by [key_name_admin(SO.orderer_ckey)] has shipped.")
|
||||
purchases++
|
||||
|
||||
investigate_log("[purchases] orders in this shipment, worth [value] credits. [SSshuttle.points] credits left.", "cargo")
|
||||
|
||||
/obj/docking_port/mobile/supply/proc/sell()
|
||||
var/presale_points = SSshuttle.points
|
||||
|
||||
if(!exports_list.len) // No exports list? Generate it!
|
||||
setupExports()
|
||||
|
||||
var/msg = ""
|
||||
var/sold_atoms = ""
|
||||
|
||||
for(var/atom/movable/AM in areaInstance)
|
||||
if(AM.anchored)
|
||||
continue
|
||||
sold_atoms += export_item_and_contents(AM, contraband, emagged, dry_run = FALSE)
|
||||
|
||||
if(sold_atoms)
|
||||
sold_atoms += "."
|
||||
|
||||
for(var/a in exports_list)
|
||||
var/datum/export/E = a
|
||||
var/export_text = E.total_printout()
|
||||
if(!export_text)
|
||||
continue
|
||||
|
||||
msg += export_text + "\n"
|
||||
SSshuttle.points += E.total_cost
|
||||
E.export_end()
|
||||
|
||||
SSshuttle.centcom_message = msg
|
||||
investigate_log("Shuttle contents sold for [SSshuttle.points - presale_points] credits. Contents: [sold_atoms || "none."] Message: [SSshuttle.centcom_message || "none."]", "cargo")
|
||||
@@ -0,0 +1,57 @@
|
||||
#define SYNDICATE_CHALLENGE_TIMER 12000 //20 minutes
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate
|
||||
name = "syndicate shuttle terminal"
|
||||
circuit = /obj/item/weapon/circuitboard/computer/syndicate_shuttle
|
||||
icon_screen = "syndishuttle"
|
||||
icon_keyboard = "syndie_key"
|
||||
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"
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate/recall
|
||||
name = "syndicate shuttle recall terminal"
|
||||
possible_destinations = "syndicate_away"
|
||||
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate/Topic(href, href_list)
|
||||
if(href_list["move"])
|
||||
var/obj/item/weapon/circuitboard/computer/syndicate_shuttle/board = circuit
|
||||
if(board.challenge && world.time < SYNDICATE_CHALLENGE_TIMER)
|
||||
usr << "<span class='warning'>You've issued a combat challenge to the station! You've got to give them at least [round(((SYNDICATE_CHALLENGE_TIMER - world.time) / 10) / 60)] more minutes to allow them to prepare.</span>"
|
||||
return 0
|
||||
board.moved = TRUE
|
||||
..()
|
||||
|
||||
/obj/item/weapon/circuitboard/computer/syndicate_shuttle
|
||||
name = "circuit board (Syndicate Shuttle)"
|
||||
build_path = /obj/machinery/computer/shuttle/syndicate
|
||||
var/challenge = FALSE
|
||||
var/moved = FALSE
|
||||
|
||||
/obj/item/weapon/circuitboard/computer/syndicate_shuttle/New()
|
||||
syndicate_shuttle_boards += src
|
||||
..()
|
||||
|
||||
/obj/item/weapon/circuitboard/computer/syndicate_shuttle/Destroy()
|
||||
syndicate_shuttle_boards -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/shuttle/syndicate/drop_pod
|
||||
name = "syndicate assault pod control"
|
||||
icon = 'icons/obj/terminals.dmi'
|
||||
icon_state = "dorm_available"
|
||||
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(z != ZLEVEL_CENTCOM)
|
||||
usr << "<span class='warning'>Pods are one way!</span>"
|
||||
return 0
|
||||
..()
|
||||
|
||||
|
||||
#undef SYNDICATE_CHALLENGE_TIMER
|
||||
@@ -0,0 +1,6 @@
|
||||
/obj/machinery/computer/shuttle/white_ship
|
||||
name = "White Ship Console"
|
||||
desc = "Used to control the White Ship."
|
||||
circuit = /obj/item/weapon/circuitboard/computer/white_ship
|
||||
shuttleId = "whiteship"
|
||||
possible_destinations = "whiteship_away;whiteship_home;whiteship_z4;whiteship_lavaland"
|
||||
Reference in New Issue
Block a user