diff --git a/code/modules/industrial_lift/tram/tram_lift_master.dm b/code/modules/industrial_lift/tram/tram_lift_master.dm index 79433c34f34..a2d88283f4c 100644 --- a/code/modules/industrial_lift/tram/tram_lift_master.dm +++ b/code/modules/industrial_lift/tram/tram_lift_master.dm @@ -108,18 +108,22 @@ * Tells the individual tram parts where to actually go and has an extra safety checks * incase multiple inputs get through, preventing conflicting directions and the tram * literally ripping itself apart. all of the actual movement is handled by SStramprocess + * Arguments: destination platform, rapid (bypass some safety checks) */ -/datum/lift_master/tram/proc/tram_travel(obj/effect/landmark/tram/destination_platform) +/datum/lift_master/tram/proc/tram_travel(obj/effect/landmark/tram/destination_platform, rapid = FALSE) if(destination_platform == idle_platform) return - update_tram_doors(CLOSE_DOORS) travel_direction = get_dir(idle_platform, destination_platform) travel_distance = get_dist(idle_platform, destination_platform) idle_platform = destination_platform set_travelling(TRUE) set_controls(LIFT_PLATFORM_LOCKED) - addtimer(CALLBACK(src, PROC_REF(dispatch_tram), destination_platform), 3 SECONDS) + if(rapid) // bypass for unsafe, rapid departure + dispatch_tram(destination_platform) + else + update_tram_doors(CLOSE_DOORS) + addtimer(CALLBACK(src, PROC_REF(dispatch_tram), destination_platform), 3 SECONDS) /datum/lift_master/tram/proc/dispatch_tram(obj/effect/landmark/tram/destination_platform) SEND_SIGNAL(src, COMSIG_TRAM_TRAVEL, idle_platform, destination_platform) diff --git a/code/modules/industrial_lift/tram/tram_remote.dm b/code/modules/industrial_lift/tram/tram_remote.dm new file mode 100644 index 00000000000..d29d595e08d --- /dev/null +++ b/code/modules/industrial_lift/tram/tram_remote.dm @@ -0,0 +1,154 @@ +#define TRAMCTRL_INBOUND 1 +#define TRAMCTRL_OUTBOUND 0 +#define TRAMCTRL_FAST 1 +#define TRAMCTRL_SAFE 0 + +/obj/item/tram_remote + icon_state = "tramremote_nis" + inhand_icon_state = "electronic" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + icon = 'icons/obj/device.dmi' + name = "tram remote" + desc = "A remote control that can be linked to a tram. This can only go well." + w_class = WEIGHT_CLASS_TINY + ///desired tram direction + var/direction = TRAMCTRL_INBOUND + ///fast and fun, or safe and boring + var/mode = TRAMCTRL_FAST + ///weakref to the tram piece we control + var/datum/weakref/tram_ref + ///cooldown for the remote + COOLDOWN_DECLARE(tram_remote) + +/obj/item/tram_remote/Initialize(mapload) + . = ..() + register_context() + +/obj/item/tram_remote/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(!tram_ref) + context[SCREENTIP_CONTEXT_LMB] = "Link tram" + return CONTEXTUAL_SCREENTIP_SET + context[SCREENTIP_CONTEXT_LMB] = "Dispatch tram" + context[SCREENTIP_CONTEXT_RMB] = "Change direction" + context[SCREENTIP_CONTEXT_CTRL_LMB] = "Toggle door safeties" + return CONTEXTUAL_SCREENTIP_SET + +///set tram control direction +/obj/item/tram_remote/attack_self_secondary(mob/user) + switch(direction) + if(TRAMCTRL_INBOUND) + direction = TRAMCTRL_OUTBOUND + if(TRAMCTRL_OUTBOUND) + direction = TRAMCTRL_INBOUND + update_appearance() + balloon_alert(user, "[direction ? "< inbound" : "outbound >"]") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +///set safety bypass +/obj/item/tram_remote/CtrlClick(mob/user) + switch(mode) + if(TRAMCTRL_SAFE) + mode = TRAMCTRL_FAST + if(TRAMCTRL_FAST) + mode = TRAMCTRL_SAFE + update_appearance() + balloon_alert(user, "mode: [mode ? "fast" : "safe"]") + +/obj/item/tram_remote/examine(mob/user) + . = ..() + if(!tram_ref) + . += "There is an X showing on the display." + . += "Left-click a tram request button to link." + return + . += "The arrow on the display is pointing [direction ? "inbound" : "outbound"]." + . += "The rapid mode light is [mode ? "on" : "off"]." + if (!COOLDOWN_FINISHED(src, tram_remote)) + . += "The number on the display shows [DisplayTimeText(COOLDOWN_TIMELEFT(src, tram_remote), 1)]." + else + . += "The display indicates ready." + . += "Left-click to dispatch tram." + . += "Right-click to toggle direction." + . += "Ctrl-click to toggle safety bypass." + +/obj/item/tram_remote/update_icon_state() + . = ..() + if(!tram_ref) + icon_state = "tramremote_nis" + return + switch(direction) + if(TRAMCTRL_INBOUND) + icon_state = "tramremote_ib" + if(TRAMCTRL_OUTBOUND) + icon_state = "tramremote_ob" + +/obj/item/tram_remote/update_overlays() + . = ..() + if(mode == TRAMCTRL_FAST) + . += mutable_appearance(icon, "tramremote_emag") + +/obj/item/tram_remote/attack_self(mob/user) + if (!COOLDOWN_FINISHED(src, tram_remote)) + balloon_alert(user, "cooldown: [DisplayTimeText(COOLDOWN_TIMELEFT(src, tram_remote), 1)]") + return FALSE + if(try_force_tram(user)) + COOLDOWN_START(src, tram_remote, 2 MINUTES) + +///send our selected commands to the tram +/obj/item/tram_remote/proc/try_force_tram(mob/user) + var/datum/lift_master/tram/tram_part = tram_ref?.resolve() + if(!tram_part) + balloon_alert(user, "no tram linked!") + return FALSE + if(tram_part.controls_locked || tram_part.travelling) // someone else started already + balloon_alert(user, "tram busy!") + return FALSE + var/tram_id = tram_part.specific_lift_id + var/destination_platform = null + var/platform = 0 + switch(direction) + if(TRAMCTRL_INBOUND) + platform = clamp(tram_part.idle_platform.platform_code - 1, 1, INFINITY) + if(TRAMCTRL_OUTBOUND) + platform = clamp(tram_part.idle_platform.platform_code + 1, 1, INFINITY) + if(platform == tram_part.idle_platform.platform_code) + balloon_alert(user, "invalid command!") + return FALSE + for (var/obj/effect/landmark/tram/destination as anything in GLOB.tram_landmarks[tram_id]) + if(destination.platform_code == platform) + destination_platform = destination + break + if(!destination_platform) + balloon_alert(user, "invalid command!") + return FALSE + else + switch(mode) + if(TRAMCTRL_FAST) + tram_part.tram_travel(destination_platform, rapid = TRUE) + if(TRAMCTRL_SAFE) + tram_part.tram_travel(destination_platform, rapid = FALSE) + balloon_alert(user, "tram dispatched") + return TRUE + +/obj/item/tram_remote/afterattack(atom/target, mob/user) + link_tram(user, target) + +/obj/item/tram_remote/proc/link_tram(mob/user, atom/target) + var/obj/machinery/button/tram/smacked_device = target + if(!istype(smacked_device, /obj/machinery/button/tram)) + return + tram_ref = null + for(var/datum/lift_master/lift as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID]) + if(lift.specific_lift_id == smacked_device.lift_id) + tram_ref = WEAKREF(lift) + break + if(tram_ref) + balloon_alert(user, "tram linked") + else + balloon_alert(user, "link failed!") + update_appearance() + +#undef TRAMCTRL_INBOUND +#undef TRAMCTRL_OUTBOUND +#undef TRAMCTRL_FAST +#undef TRAMCTRL_SAFE diff --git a/code/modules/uplink/uplink_items/device_tools.dm b/code/modules/uplink/uplink_items/device_tools.dm index 4ed280885c2..a4a9b738df6 100644 --- a/code/modules/uplink/uplink_items/device_tools.dm +++ b/code/modules/uplink/uplink_items/device_tools.dm @@ -40,6 +40,14 @@ item = /obj/item/storage/book/bible/syndicate cost = 5 +/datum/uplink_item/device_tools/tram_remote + name = "Tram Remote Control" + desc = "When linked to a tram's on board computer systems, this device allows the user to manipulate the controls remotely. \ + Includes direction toggle and a rapid mode to bypass door safety checks and crossing signals. \ + Perfect for running someone over in the name of a tram malfunction!" + item = /obj/item/tram_remote + cost = 2 + /datum/uplink_item/device_tools/thermal name = "Thermal Imaging Glasses" desc = "These goggles can be turned to resemble common eyewear found throughout the station. \ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index b98402328ff..7279d61688a 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/modular_skyrat/modules/opposing_force/code/equipment/utility.dm b/modular_skyrat/modules/opposing_force/code/equipment/utility.dm index 9a7c7dd3b1d..85fd924ebd4 100644 --- a/modular_skyrat/modules/opposing_force/code/equipment/utility.dm +++ b/modular_skyrat/modules/opposing_force/code/equipment/utility.dm @@ -11,6 +11,13 @@ item_type = /obj/item/card/emag/doorjack description = "Identifies commonly as a \"doorjack\", this illegally modified ID card can disrupt airlock electronics. Has a self recharging cell." +/datum/opposing_force_equipment/gear/tram_remote + name = "Tram Remote Control" + item_type = /obj/item/tram_remote + description = "When linked to a tram's on board computer systems, this device allows the user to manipulate the controls remotely. \ + Includes direction toggle and a rapid mode to bypass door safety checks and crossing signals. \ + Perfect for running someone over in the name of a tram malfunction!" + /datum/opposing_force_equipment/gear/stoolbox item_type = /obj/item/storage/toolbox/syndicate description = "A fully-kitted toolbox scavenged from maintenance by our highly-paid monkeys. The toolbox \ diff --git a/tgstation.dme b/tgstation.dme index 7343861badd..2d0a2b9f9a5 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3580,6 +3580,7 @@ #include "code\modules\industrial_lift\tram\tram_lift_master.dm" #include "code\modules\industrial_lift\tram\tram_machinery.dm" #include "code\modules\industrial_lift\tram\tram_override_objects.dm" +#include "code\modules\industrial_lift\tram\tram_remote.dm" #include "code\modules\industrial_lift\tram\tram_structures.dm" #include "code\modules\industrial_lift\tram\tram_walls.dm" #include "code\modules\industrial_lift\tram\tram_windows.dm"