Files
Bubberstation/code/modules/shuttle/manipulator.dm
Emmett Gaines 49d1e9ee66 Shuttles have additional baseturfs, and other minor baseturf changes (#36388)
cl ninjanomnom
fix: Shuttles have proper baseturfs now.
fix: Mineral walls properly use their baseturfs when destroyed/drilled.
add: A new engineering goggle mode allows you to see the shuttle area you're standing in.
admin: Buildmode works a bit better with baseturfs now and can properly only remove the top layer of turfs when editing. Note that as a result the order you place turfs is important and a wall placed on space means when the wall is removed there will be space underneath.
/cl

This adds an area hook for turfs getting the PlaceOnTop proc called so shuttle areas are able to intercept it and add a special turf used for determining where the bottom of the shuttle is. I'm not too certain on this being the best way to handle it but the alternatives restrict the kind of turfs that are allowed to be on shuttles which I didn't want to do as it was part of the whole intent of the baseturf change to allow any turf type on shuttles.

The alternative to the area hook would require a tool which attaches turfs to a shuttle which is why there's a shuttle area viewing tool in this pr. I considered doing it this way first but decided it was too clunky.

In addition to other changes:

Tiled/Reinforced floors have proper baseturfs now.

A large amount of the remaining ChangeTurf calls were swapped over to various baseturf helpers so, for example, mining doesn't create a lavaland turf if somehow the mineral wall is on plating.

Escape pods, the aux base, and syndicate drop pod have been converted over to shuttle templates as well.

The error when the timid var is set incorrectly has been changed to a stack_trace.

The change turf file has been made all lowercase as per standard.
2018-04-05 11:13:20 +12:00

297 lines
8.7 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"
anchored = TRUE
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/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/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 = 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("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]")
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)
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(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)
var/m = "No dock found for preview shuttle ([preview_template.name]), aborting."
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 != 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()
preview_shuttle.initiate_docking(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(/obj/effect/landmark/shuttle_import) in GLOB.landmarks_list)
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)
log_world("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.
stack_trace("Template [S] is non-timid! Unloading.")
M.jumpToNullSpace()
return
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.on_bought()
/obj/machinery/shuttle_manipulator/proc/unload_preview()
if(preview_shuttle)
preview_shuttle.jumpToNullSpace()
preview_shuttle = null