Files
Bubberstation/code/modules/assembly/doorcontrol.dm
SkyratBot 9bd406b65b [MIRROR] Adds support for "realistic" public elevators (elevator doors, elevator panel, etc) [MDB IGNORE] (#15515)
* Adds support for "realistic" public elevators (elevator doors, elevator panel, etc) (#68888)

* Elevators are a bit more friendly part 1
- Emaggable elevator buttons / support for emaggable device assemblies
- Delayed travel between floors
- Elevators can now show a warning sign to areas below while travelling
- Elevators can now optionally wound heavily instead of gibbing

* Adds supoprt for "lift doors"

* Comment tweak

* Splitting these variables

* Functional prototype

* multiz debug

* Elevator button framework

* Unifies these behaviors

* Emergency doors

* Lift button framework

* UI closes on floor change

* Testing changes

* Fix

* UI Tweaks

* Panel works pretty swell

* Minor tweaks

* Move to static

* Bonus tram change

* User experience

* Slight tweak to mapload stuff

* This is silly

* Some UI tweaks, need to update css

* CSS and ui overhaul

* Documentation updates.

* Multi-z lift support

* Multitile lift fix

* Adds support for "realistic" public elevators (elevator doors, elevator panel, etc)

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
2022-08-13 22:06:26 -07:00

233 lines
7.0 KiB
Plaintext

/obj/item/assembly/control
name = "blast door controller"
desc = "A small electronic device able to control a blast door remotely."
icon_state = "control"
attachable = TRUE
var/id = null
var/can_change_id = 0
var/cooldown = FALSE //Door cooldowns
var/sync_doors = TRUE
/obj/item/assembly/control/examine(mob/user)
. = ..()
if(id)
. += span_notice("Its channel ID is '[id]'.")
/obj/item/assembly/control/multitool_act(mob/living/user)
var/change_id = tgui_input_number(user, "Set the door controllers ID", "Door ID", id, 100)
if(!change_id || QDELETED(user) || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
id = change_id
to_chat(user, span_notice("You change the ID to [id]."))
/obj/item/assembly/control/activate()
var/openclose
if(cooldown)
return
cooldown = TRUE
for(var/obj/machinery/door/poddoor/M in GLOB.machines)
if(M.id == src.id)
if(openclose == null || !sync_doors)
openclose = M.density
INVOKE_ASYNC(M, openclose ? /obj/machinery/door/poddoor.proc/open : /obj/machinery/door/poddoor.proc/close)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
/obj/item/assembly/control/curtain
name = "curtain controller"
desc = "A small electronic device able to control a mechanical curtain remotely."
/obj/item/assembly/control/curtain/examine(mob/user)
. = ..()
if(id)
. += span_notice("Its channel ID is '[id]'.")
/obj/item/assembly/control/curtain/activate()
var/openclose
if(cooldown)
return
cooldown = TRUE
for(var/obj/structure/curtain/cloth/fancy/mechanical/M in GLOB.curtains)
if(M.id == src.id)
if(openclose == null || !sync_doors)
openclose = M.density
INVOKE_ASYNC(M, openclose ? /obj/structure/curtain/cloth/fancy/mechanical.proc/open : /obj/structure/curtain/cloth/fancy/mechanical.proc/close)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 5)
/obj/item/assembly/control/airlock
name = "airlock controller"
desc = "A small electronic device able to control an airlock remotely."
id = "badmin" // Set it to null for MEGAFUN.
var/specialfunctions = OPEN
/*
Bitflag, 1= open (OPEN)
2= idscan (IDSCAN)
4= bolts (BOLTS)
8= shock (SHOCK)
16= door safties (SAFE)
*/
/obj/item/assembly/control/airlock/activate()
if(cooldown)
return
cooldown = TRUE
var/doors_need_closing = FALSE
var/list/obj/machinery/door/airlock/open_or_close = list()
for(var/obj/machinery/door/airlock/D in GLOB.airlocks)
if(D.id_tag == src.id)
if(specialfunctions & OPEN)
open_or_close += D
if(!D.density)
doors_need_closing = TRUE
if(specialfunctions & IDSCAN)
D.aiDisabledIdScanner = !D.aiDisabledIdScanner
if(specialfunctions & BOLTS)
if(!D.wires.is_cut(WIRE_BOLTS) && D.hasPower())
D.locked = !D.locked
D.update_appearance()
if(specialfunctions & SHOCK)
if(D.secondsElectrified)
D.set_electrified(MACHINE_ELECTRIFIED_PERMANENT, usr)
else
D.set_electrified(MACHINE_NOT_ELECTRIFIED, usr)
if(specialfunctions & SAFE)
D.safe = !D.safe
for(var/D in open_or_close)
INVOKE_ASYNC(D, doors_need_closing ? /obj/machinery/door/airlock.proc/close : /obj/machinery/door/airlock.proc/open)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
/obj/item/assembly/control/massdriver
name = "mass driver controller"
desc = "A small electronic device able to control a mass driver."
/obj/item/assembly/control/massdriver/activate()
if(cooldown)
return
cooldown = TRUE
for(var/obj/machinery/door/poddoor/M in GLOB.machines)
if (M.id == src.id)
INVOKE_ASYNC(M, /obj/machinery/door/poddoor.proc/open)
sleep(10)
for(var/obj/machinery/mass_driver/M in GLOB.machines)
if(M.id == src.id)
M.drive()
sleep(60)
for(var/obj/machinery/door/poddoor/M in GLOB.machines)
if (M.id == src.id)
INVOKE_ASYNC(M, /obj/machinery/door/poddoor.proc/close)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
/obj/item/assembly/control/igniter
name = "ignition controller"
desc = "A remote controller for a mounted igniter."
/obj/item/assembly/control/igniter/activate()
if(cooldown)
return
cooldown = TRUE
for(var/obj/machinery/sparker/M in GLOB.machines)
if (M.id == src.id)
INVOKE_ASYNC(M, /obj/machinery/sparker.proc/ignite)
for(var/obj/machinery/igniter/M in GLOB.machines)
if(M.id == src.id)
M.use_power(50)
M.on = !M.on
M.icon_state = "igniter[M.on]"
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 30)
/obj/item/assembly/control/flasher
name = "flasher controller"
desc = "A remote controller for a mounted flasher."
/obj/item/assembly/control/flasher/activate()
if(cooldown)
return
cooldown = TRUE
for(var/obj/machinery/flasher/M in GLOB.machines)
if(M.id == src.id)
INVOKE_ASYNC(M, /obj/machinery/flasher.proc/flash)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
/obj/item/assembly/control/crematorium
name = "crematorium controller"
desc = "An evil-looking remote controller for a crematorium."
/obj/item/assembly/control/crematorium/activate()
if(cooldown)
return
cooldown = TRUE
for (var/obj/structure/bodycontainer/crematorium/C in GLOB.crematoriums)
if (C.id == id)
C.cremate(usr)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
/obj/item/assembly/control/tram
name = "tram call button"
desc = "A small device used to bring trams to you."
///for finding the landmark initially - should be the exact same as the landmark's destination id.
var/initial_id
///ID to link to allow us to link to one specific tram in the world
var/specific_lift_id = MAIN_STATION_TRAM
///this is our destination's landmark, so we only have to find it the first time.
var/datum/weakref/to_where
/obj/item/assembly/control/tram/Initialize(mapload)
..()
return INITIALIZE_HINT_LATELOAD
/obj/item/assembly/control/tram/LateInitialize()
. = ..()
//find where the tram needs to go to (our destination). only needs to happen the first time
for(var/obj/effect/landmark/tram/our_destination as anything in GLOB.tram_landmarks[specific_lift_id])
if(our_destination.destination_id == initial_id)
to_where = WEAKREF(our_destination)
break
/obj/item/assembly/control/tram/Destroy()
to_where = null
return ..()
/obj/item/assembly/control/tram/activate()
if(cooldown)
return
cooldown = TRUE
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 2 SECONDS)
var/datum/lift_master/tram/tram
for(var/datum/lift_master/tram/possible_match as anything in GLOB.active_lifts_by_type[TRAM_LIFT_ID])
if(possible_match.specific_lift_id == specific_lift_id)
tram = possible_match
break
if(!tram)
say("The tram is not responding to call signals. Please send a technician to repair the internals of the tram.")
return
if(tram.travelling) //in use
say("The tram is already travelling to [tram.from_where].")
return
if(!to_where)
return
var/obj/effect/landmark/tram/current_location = to_where.resolve()
if(!current_location)
return
if(tram.from_where == current_location) //already here
say("The tram is already here. Please board the tram and select a destination.")
return
say("The tram has been called to [current_location.name]. Please wait for its arrival.")
tram.tram_travel(current_location)