mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-12 02:32:10 +00:00
- Normal shuttles that are not emagged will no longer throw things around. People will still be knocked down. - Emagged shuttles and poorly designed shuttles will also throw things around on tables, as well as closets. Shuttles were not mapped with the idea that their contents would be thrown around violently every time they moved. This means that things like wheely chairs, potted plants get chucked about the place. To get around this, the "magnetic_catch" component was added, to partially bypass this effect in the first place. But this component is only used in one place, in shuttle loading, which means if a shuttle is custom built, suddenly and unexpectedly, everything flies everywhere. Instead, violent shuttle throwing should be limited to crappy shuttles, (ie. asteroid with engines) and emagged shuttles. As such, I've removed the magnetic component from tables and racks, to make shuttle throwing more violent when it happens.
374 lines
11 KiB
Plaintext
374 lines
11 KiB
Plaintext
/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"
|
|
|
|
density = TRUE
|
|
|
|
// 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/Initialize()
|
|
. = ..()
|
|
update_icon()
|
|
SSshuttle.manipulator = src
|
|
|
|
/obj/machinery/shuttle_manipulator/Destroy(force)
|
|
if(!force)
|
|
. = QDEL_HINT_LETMELIVE
|
|
else
|
|
SSshuttle.manipulator = null
|
|
. = ..()
|
|
|
|
/obj/machinery/shuttle_manipulator/update_icon()
|
|
cut_overlays()
|
|
var/mutable_appearance/hologram_projection = mutable_appearance(icon, "hologram_on")
|
|
hologram_projection.pixel_y = 22
|
|
var/mutable_appearance/hologram_ship = mutable_appearance(icon, "hologram_whiteship")
|
|
hologram_ship.pixel_y = 27
|
|
add_overlay(hologram_projection)
|
|
add_overlay(hologram_ship)
|
|
|
|
/obj/machinery/shuttle_manipulator/can_interact(mob/user)
|
|
// Only admins can use this, but they can use it from anywhere
|
|
return user.client && check_rights_for(user.client, R_ADMIN)
|
|
|
|
/obj/machinery/shuttle_manipulator/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.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_IGNITING)
|
|
. = "engines charging"
|
|
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(!.)
|
|
CRASH("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 SSmapping.shuttle_templates)
|
|
var/datum/map_template/shuttle/S = SSmapping.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/timeleft = M.timeLeft(1)
|
|
var/list/L = list()
|
|
L["name"] = M.name
|
|
L["id"] = M.id
|
|
L["timer"] = M.timer
|
|
L["timeleft"] = M.getTimerStr()
|
|
if (timeleft > 1 HOURS)
|
|
L["timeleft"] = "Infinity"
|
|
L["can_fast_travel"] = M.timer && timeleft >= 50
|
|
L["can_fly"] = TRUE
|
|
if(istype(M, /obj/docking_port/mobile/emergency))
|
|
L["can_fly"] = FALSE
|
|
else if(!M.destination)
|
|
L["can_fast_travel"] = FALSE
|
|
if (M.mode != SHUTTLE_IDLE)
|
|
L["mode"] = capitalize(shuttlemode2str(M.mode))
|
|
L["status"] = M.getDbgStatusText()
|
|
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 = SSmapping.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("fly")
|
|
for(var/i in SSshuttle.mobile)
|
|
var/obj/docking_port/mobile/M = i
|
|
if(M.id == params["id"])
|
|
. = TRUE
|
|
M.admin_fly_shuttle(user)
|
|
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(1) >= 50)
|
|
M.setTimer(50)
|
|
. = TRUE
|
|
message_admins("[key_name_admin(usr)] fast travelled [M]")
|
|
log_admin("[key_name(usr)] fast travelled [M]")
|
|
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[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>")
|
|
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]")
|
|
|
|
update_icon()
|
|
|
|
/obj/machinery/shuttle_manipulator/proc/action_load(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port)
|
|
// Check for an existing preview
|
|
if(preview_shuttle && (loading_template != preview_template))
|
|
preview_shuttle.jumpToNullSpace()
|
|
preview_shuttle = null
|
|
preview_template = null
|
|
|
|
if(!preview_shuttle)
|
|
if(load_template(loading_template))
|
|
preview_shuttle.linkup(loading_template, destination_port)
|
|
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(istype(destination_port))
|
|
D = destination_port
|
|
else if(existing_shuttle)
|
|
timer = existing_shuttle.timer
|
|
mode = existing_shuttle.mode
|
|
D = existing_shuttle.get_docked()
|
|
|
|
if(!D)
|
|
CRASH("No dock found for preview shuttle ([preview_template.name]), aborting.")
|
|
|
|
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 != SHUTTLE_CAN_DOCK) && (result != SHUTTLE_SOMEONE_ELSE_DOCKED))
|
|
WARNING("Template shuttle [preview_shuttle] cannot dock at [D] ([result]).")
|
|
return
|
|
|
|
if(existing_shuttle)
|
|
existing_shuttle.jumpToNullSpace()
|
|
|
|
var/list/force_memory = preview_shuttle.movement_force
|
|
preview_shuttle.movement_force = list("KNOCKDOWN" = 0, "THROW" = 0)
|
|
preview_shuttle.initiate_docking(D)
|
|
preview_shuttle.movement_force = force_memory
|
|
|
|
. = 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)
|
|
. = FALSE
|
|
// load shuttle template, centred at shuttle import landmark,
|
|
var/turf/landmark_turf = get_turf(locate(/obj/effect/landmark/shuttle_import) in GLOB.landmarks_list)
|
|
S.load(landmark_turf, centered = TRUE, register = FALSE)
|
|
|
|
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))
|
|
found++
|
|
if(found > 1)
|
|
qdel(P, force=TRUE)
|
|
log_world("Map warning: Shuttle Template [S.mappath] has multiple mobile docking ports.")
|
|
else
|
|
preview_shuttle = P
|
|
if(istype(P, /obj/docking_port/stationary))
|
|
log_world("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)
|
|
return
|
|
//Everything fine
|
|
S.post_load(preview_shuttle)
|
|
return TRUE
|
|
|
|
/obj/machinery/shuttle_manipulator/proc/unload_preview()
|
|
if(preview_shuttle)
|
|
preview_shuttle.jumpToNullSpace()
|
|
preview_shuttle = null
|
|
|
|
/obj/docking_port/mobile/proc/admin_fly_shuttle(mob/user)
|
|
var/list/options = list()
|
|
|
|
for(var/port in SSshuttle.stationary)
|
|
if (istype(port, /obj/docking_port/stationary/transit))
|
|
continue // please don't do this
|
|
var/obj/docking_port/stationary/S = port
|
|
if (canDock(S) == SHUTTLE_CAN_DOCK)
|
|
options[S.name || S.id] = S
|
|
|
|
options += "--------"
|
|
options += "Infinite Transit"
|
|
options += "Delete Shuttle"
|
|
options += "Into The Sunset (delete & greentext 'escape')"
|
|
|
|
var/selection = input(user, "Select where to fly [name || id]:", "Fly Shuttle") as null|anything in options
|
|
if(!selection)
|
|
return
|
|
|
|
switch(selection)
|
|
if("Infinite Transit")
|
|
destination = null
|
|
mode = SHUTTLE_IGNITING
|
|
setTimer(ignitionTime)
|
|
|
|
if("Delete Shuttle")
|
|
if(alert(user, "Really delete [name || id]?", "Delete Shuttle", "Cancel", "Really!") != "Really!")
|
|
return
|
|
jumpToNullSpace()
|
|
|
|
if("Into The Sunset (delete & greentext 'escape')")
|
|
if(alert(user, "Really delete [name || id] and greentext escape objectives?", "Delete Shuttle", "Cancel", "Really!") != "Really!")
|
|
return
|
|
intoTheSunset()
|
|
|
|
else
|
|
if(options[selection])
|
|
request(options[selection])
|
|
|
|
/obj/docking_port/mobile/emergency/admin_fly_shuttle(mob/user)
|
|
return // use the existing verbs for this
|
|
|
|
/obj/docking_port/mobile/arrivals/admin_fly_shuttle(mob/user)
|
|
switch(alert(user, "Would you like to fly the arrivals shuttle once or change its destination?", "Fly Shuttle", "Fly", "Retarget", "Cancel"))
|
|
if("Cancel")
|
|
return
|
|
if("Fly")
|
|
return ..()
|
|
|
|
var/list/options = list()
|
|
|
|
for(var/port in SSshuttle.stationary)
|
|
if (istype(port, /obj/docking_port/stationary/transit))
|
|
continue // please don't do this
|
|
var/obj/docking_port/stationary/S = port
|
|
if (canDock(S) == SHUTTLE_CAN_DOCK)
|
|
options[S.name || S.id] = S
|
|
|
|
var/selection = input(user, "Select the new arrivals destination:", "Fly Shuttle") as null|anything in options
|
|
if(!selection)
|
|
return
|
|
target_dock = options[selection]
|
|
if(!QDELETED(target_dock))
|
|
destination = target_dock
|