diff --git a/baystation12.dme b/baystation12.dme index 0d8b5e670f9..ca75948dfff 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -49,6 +49,7 @@ #include "code\_helpers\mobs.dm" #include "code\_helpers\names.dm" #include "code\_helpers\sanitize_values.dm" +#include "code\_helpers\spawn_sync.dm" #include "code\_helpers\text.dm" #include "code\_helpers\time.dm" #include "code\_helpers\turfs.dm" @@ -141,6 +142,7 @@ #include "code\controllers\Processes\ticker.dm" #include "code\controllers\Processes\turf.dm" #include "code\controllers\Processes\vote.dm" +#include "code\controllers\Processes\wireless.dm" #include "code\controllers\ProcessScheduler\core\_stubs.dm" #include "code\controllers\ProcessScheduler\core\process.dm" #include "code\controllers\ProcessScheduler\core\processScheduler.dm" @@ -1833,6 +1835,8 @@ #include "code\modules\virus2\helpers.dm" #include "code\modules\virus2\isolator.dm" #include "code\modules\virus2\items_devices.dm" +#include "code\modules\wireless\devices.dm" +#include "code\modules\wireless\interfaces.dm" #include "code\modules\xgm\xgm_gas_data.dm" #include "code\modules\xgm\xgm_gas_mixture.dm" #include "code\ZAS\_docs.dm" diff --git a/code/_helpers/spawn_sync.dm b/code/_helpers/spawn_sync.dm new file mode 100644 index 00000000000..91631d86712 --- /dev/null +++ b/code/_helpers/spawn_sync.dm @@ -0,0 +1,86 @@ +//------------------------------- +/* + Spawn sync helper + + Helps syncronize spawn()ing multiple processes in loops. + + Example for using this: + + //Create new spawn_sync datum + var/datum/spawn_sync/sync = new() + + for(var/obj/O in list) + //Call start_worker(), passing it first the object, then a string of the name of the proc you want called, then + // any and all arguments you want passed to the proc. + sync.start_worker(O, "do_something", arg1, arg2) + + //Finally call wait_until_done() + sync.wait_until_done() + + //Once all the workers have completed, or the failsafe has triggered, the code will continue. By default the + // failsafe is roughly 10 seconds (100 checks). +*/ +//------------------------------- +/datum/spawn_sync + var/count = 1 + var/failsafe = 100 //how many checks before the failsafe triggers and the helper stops waiting + +//Opens a thread counter +/datum/spawn_sync/proc/open() + count++ + +//Closes a thread counter +/datum/spawn_sync/proc/close() + count-- + +//Finalizes the spawn sync by removing the original starting count +/datum/spawn_sync/proc/finalize() + close() + +//Resets the counter if you want to utilize the same datum multiple times +// Optional: pass the number of checks you want for the failsafe +/datum/spawn_sync/proc/reset(var/safety = 100) + count = 1 + failsafe = safety + +//Check if all threads have returned +// Returns 0 if not all threads have completed +// Returns 1 if all threads have completed +/datum/spawn_sync/proc/check() + safety_check() + return count > 0 ? 1 : 0 + +//Failsafe in case something breaks horribly +/datum/spawn_sync/proc/safety_check() + failsafe-- + if(failsafe < 1) + count = 0 + +//Set failsafe check count in case you need more time for the workers to return +/datum/spawn_sync/proc/set_failsafe(var/safety) + failsafe = safety + +/datum/spawn_sync/proc/start_worker() + //Extract the thread run proc and it's arguments from the variadic args list. + ASSERT(args.len > 0) + var/obj = args[1] + var/thread_proc = args[2] + + //dispatch a new thread + open() + spawn() + //Utilise try/catch keywords here so the code continues even if an error occurs. + try + call(obj, thread_proc)(arglist(args.Copy(3))) + catch(var/exception/e) + error("[e] on [e.file]:[e.line]") + close() + +/datum/spawn_sync/proc/wait_until_done() + finalize() + + //Create a while loop to check if the sync is complete yet, it will return once all the spawn threads have + // completed, or the failsafe has expired. + while(check()) + //Add a sleep call to delay each check. + sleep(1) diff --git a/code/controllers/Processes/wireless.dm b/code/controllers/Processes/wireless.dm new file mode 100644 index 00000000000..5af6af5c3d3 --- /dev/null +++ b/code/controllers/Processes/wireless.dm @@ -0,0 +1,71 @@ +//------------------------------- +/* + Wireless controller + + Used for connecting devices to each other (i.e. machinery, doors, emitters, etc.) + Unlike the radio controller, the wireless controller does not pass communications between devices. Once the devices + have been connected they call each others procs directly, they do not use the wireless controller to communicate. + + See code\modules\wireless\interfaces.dm for details of how to connect devices. +*/ +//------------------------------- + +var/datum/controller/process/wireless/wirelessProcess + +/datum/controller/process/wireless + var/list/receiver_list + var/list/pending_connections + var/list/retry_connections + var/list/failed_connections + +/datum/controller/process/wireless/setup() + name = "wireless" + schedule_interval = 50 + pending_connections = new() + retry_connections = new() + failed_connections = new() + receiver_list = new() + wirelessProcess = src + +/datum/controller/process/wireless/proc/add_device(var/datum/wifi/receiver/R) + if(receiver_list) + receiver_list |= R + else + receiver_list = new() + receiver_list |= R + +/datum/controller/process/wireless/proc/remove_device(var/datum/wifi/receiver/R) + if(receiver_list) + receiver_list -= R + +/datum/controller/process/wireless/proc/add_request(var/datum/connection_request/C) + if(pending_connections) + pending_connections += C + else + pending_connections = new() + pending_connections += C + +/datum/controller/process/wireless/doWork() + //process any connection requests waiting to be retried + if(retry_connections.len > 0) + //any that fail are moved into the failed connections list + process_queue(retry_connections, failed_connections) + + //process any pending connection requests + if(pending_connections.len > 0) + //any that fail are moved to the retry queue + process_queue(pending_connections, retry_connections) + +/datum/controller/process/wireless/proc/process_queue(var/list/process_conections, var/list/unsuccesful_connections) + for(var/datum/connection_request/C in process_conections) + var/target_found = 0 + for(var/datum/wifi/receiver/R in receiver_list) + if(R.id == C.id) + var/datum/wifi/sender/S = C.source + S.connect_device(R) + R.connect_device(S) + target_found = 1 + process_conections -= C + if(!target_found) + unsuccesful_connections += C + SCHECK diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index c394318c286..f47070b6b20 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -25,7 +25,7 @@ usr.client.debug_variables(antag) message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.") -/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry")) +/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Wireless")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -92,5 +92,8 @@ if("Chemistry") debug_variables(chemistryProcess) feedback_add_details("admin_verb", "DChem") + if("Wireless") + debug_variables(wirelessProcess) + feedback_add_details("admin_verb", "DWifi") message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 70557a2e18b..a5475561a8b 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -5,14 +5,127 @@ desc = "A remote control switch for something." var/id = null var/active = 0 + var/operating = 0 anchored = 1.0 use_power = 1 idle_power_usage = 2 active_power_usage = 4 + var/_wifi_id + var/datum/wifi/sender/button/wifi_sender +/obj/machinery/button/initialize() + ..() + update_icon() + if(_wifi_id) + wifi_sender = new(_wifi_id, src) + +/obj/machinery/button/Destroy() + qdel(wifi_sender) + wifi_sender = null + return..() /obj/machinery/button/attack_ai(mob/user as mob) - return src.attack_hand(user) + return attack_hand(user) /obj/machinery/button/attackby(obj/item/weapon/W, mob/user as mob) - return src.attack_hand(user) \ No newline at end of file + return attack_hand(user) + +/obj/machinery/button/attack_hand(mob/living/user) + ..() + activate(user) + +/obj/machinery/button/proc/activate(mob/living/user) + if(operating || !istype(wifi_sender)) + return + + operating = 1 + active = 1 + use_power(5) + update_icon() + wifi_sender.activate(user) + sleep(10) + active = 0 + update_icon() + operating = 0 + +/obj/machinery/button/update_icon() + if(active) + icon_state = "launcheract" + else + icon_state = "launcherbtt" + +//alternate button with the same functionality, except has a lightswitch sprite instead +/obj/machinery/button/alternate + icon = 'icons/obj/power.dmi' + icon_state = "light0" + +/obj/machinery/button/alternate/update_icon() + icon_state = "light[active]" + +//Toggle button with two states (on and off) and calls seperate procs for each state +/obj/machinery/button/toggle/activate(mob/living/user) + if(operating || !istype(wifi_sender)) + return + + operating = 1 + active = !active + use_power(5) + if(active) + wifi_sender.activate(user) + else + wifi_sender.deactivate(user) + update_icon() + operating = 0 + +/obj/machinery/button/toggle/alternate + icon = 'icons/obj/power.dmi' + icon_state = "light0" + +/obj/machinery/button/toggle/alternate/update_icon() + icon_state = "light[active]" + + +//------------------------------- +// Mass Driver Button +// Passes the activate call to a mass driver wifi sender +//------------------------------- +/obj/machinery/button/mass_driver + var/datum/wifi/sender/mass_driver/sender + +/obj/machinery/button/mass_driver/initialize() + ..() + sender = new(_wifi_id, src) + +/obj/machinery/button/mass_driver/activate(mob/living/user) + if(active || !istype(wifi_sender)) + return + active = 1 + use_power(5) + update_icon() + sender.cycle() + active = 0 + update_icon() + +//------------------------------- +// Door Button +//------------------------------- +/obj/machinery/button/toggle/door + var/datum/wifi/sender/door/sender + +/obj/machinery/button/toggle/door/initialize() + ..() + sender = new(_wifi_id, src) + +/obj/machinery/button/toggle/door/activate(mob/living/user) + if(operating || !istype(sender)) + return + + operating = 1 + active = !active + use_power(5) + update_icon() + if(!active) + sender.open() + else + sender.close() + operating = 0 diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 25492ce3d5f..5fa7010f53e 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -34,6 +34,9 @@ var/open_sound_powered = 'sound/machines/airlock.ogg' var/open_sound_unpowered = 'sound/machines/airlock_creaking.ogg' + var/_wifi_id + var/datum/wifi/receiver/button/door/wifi_receiver + /obj/machinery/door/airlock/attack_generic(var/mob/user, var/damage) if(stat & (BROKEN|NOPOWER)) if(damage >= 10) @@ -1037,9 +1040,15 @@ About the new airlock wires panel: src.closeOther = A break + //wireless connection + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + /obj/machinery/door/airlock/Destroy() qdel(wires) wires = null + qdel(wifi_receiver) + wifi_receiver = null return ..() // Most doors will never be deconstructed over the course of a round, diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm index 8c960e7bdf4..145bb63ab0c 100644 --- a/code/game/machinery/doors/blast_door.dm +++ b/code/game/machinery/doors/blast_door.dm @@ -28,6 +28,19 @@ //turning this off prevents awkward zone geometry in places like medbay lobby, for example. block_air_zones = 0 + var/_wifi_id + var/datum/wifi/receiver/button/door/wifi_receiver + +/obj/machinery/door/blast/initialize() + ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/door/airlock/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + // Proc: Bumped() // Parameters: 1 (AM - Atom that tried to walk through this object) // Description: If we are open returns zero, otherwise returns result of parent function. @@ -144,7 +157,7 @@ if(stat & BROKEN) stat &= ~BROKEN - + /obj/machinery/door/blast/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(air_group) return 1 return ..() diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index e6fb41193cb..bea0c443a74 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -15,6 +15,8 @@ use_power = 1 idle_power_usage = 2 flags = PROXMOVE + var/_wifi_id + var/datum/wifi/receiver/button/flasher/wifi_receiver /obj/machinery/flasher/portable //Portable version of the flasher. Only flashes when anchored name = "portable flasher" @@ -25,6 +27,16 @@ base_state = "pflash" density = 1 +/obj/machinery/flasher/initialize() + ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/flasher/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + /obj/machinery/flasher/power_change() ..() if ( !(stat & NOPOWER) ) diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm index 63198710227..69f12726342 100644 --- a/code/game/machinery/holosign.dm +++ b/code/game/machinery/holosign.dm @@ -12,6 +12,18 @@ var/lit = 0 var/id = null var/on_icon = "sign_on" + var/_wifi_id + var/datum/wifi/receiver/button/holosign/wifi_receiver + +/obj/machinery/holosign/initialize() + ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/holosign/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() /obj/machinery/holosign/proc/toggle() if (stat & (BROKEN|NOPOWER)) diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index 5fd791843d9..70527609282 100755 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -4,11 +4,32 @@ icon = 'icons/obj/stationobjs.dmi' icon_state = "igniter1" var/id = null - var/on = 1.0 - anchored = 1.0 + var/on = 0 + anchored = 1 use_power = 1 idle_power_usage = 2 active_power_usage = 4 + var/_wifi_id + var/datum/wifi/receiver/button/igniter/wifi_receiver + +/obj/machinery/igniter/New() + ..() + update_icon() + +/obj/machinery/igniter/initialize() + ..() + update_icon() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/igniter/update_icon() + ..() + icon_state = "igniter[on]" + +/obj/machinery/igniter/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() /obj/machinery/igniter/attack_ai(mob/user as mob) return src.attack_hand(user) @@ -17,29 +38,25 @@ if(..()) return add_fingerprint(user) - - use_power(50) - src.on = !( src.on ) - src.icon_state = text("igniter[]", src.on) + ignite() return /obj/machinery/igniter/process() //ugh why is this even in process()? - if (src.on && !(stat & NOPOWER) ) + if (on && powered() ) var/turf/location = src.loc if (isturf(location)) location.hotspot_expose(1000,500,1) return 1 -/obj/machinery/igniter/New() - ..() - icon_state = "igniter[on]" - /obj/machinery/igniter/power_change() ..() - if(!( stat & NOPOWER) ) - icon_state = "igniter[src.on]" - else - icon_state = "igniter0" + update_icon() + +/obj/machinery/igniter/proc/ignite() + use_power(50) + on = !on + update_icon() + // Wall mounted remote-control igniter. @@ -56,50 +73,59 @@ use_power = 1 idle_power_usage = 2 active_power_usage = 4 + var/_wifi_id + var/datum/wifi/receiver/button/sparker/wifi_receiver - -/obj/machinery/sparker/New() +/obj/machinery/sparker/initialize() ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/sparker/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() + +/obj/machinery/sparker/update_icon() + ..() + if(disable) + icon_state = "migniter-d" + else if(powered()) + icon_state = "migniter" +// src.sd_SetLuminosity(2) + else + icon_state = "migniter-p" +// src.sd_SetLuminosity(0) /obj/machinery/sparker/power_change() ..() - if ( !(stat & NOPOWER) && disable == 0 ) - - icon_state = "[base_state]" -// src.sd_SetLuminosity(2) - else - icon_state = "[base_state]-p" -// src.sd_SetLuminosity(0) + update_icon() /obj/machinery/sparker/attackby(obj/item/weapon/W as obj, mob/user as mob) if (istype(W, /obj/item/weapon/screwdriver)) add_fingerprint(user) - src.disable = !src.disable - if (src.disable) + disable = !disable + if(disable) user.visible_message("[user] has disabled the [src]!", "You disable the connection to the [src].") - icon_state = "[base_state]-d" - if (!src.disable) + else if(!disable) user.visible_message("[user] has reconnected the [src]!", "You fix the connection to the [src].") - if(src.powered()) - icon_state = "[base_state]" - else - icon_state = "[base_state]-p" + update_icon() /obj/machinery/sparker/attack_ai() - if (src.anchored) - return src.ignite() + if (anchored) + return ignite() else return /obj/machinery/sparker/proc/ignite() - if (!(powered())) + if (!powered()) return - if ((src.disable) || (src.last_spark && world.time < src.last_spark + 50)) + if (disable || (last_spark && world.time < last_spark + 50)) return - flick("[base_state]-spark", src) + flick("migniter-spark", src) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(2, 1, src) s.start() @@ -132,15 +158,13 @@ icon_state = "launcheract" for(var/obj/machinery/sparker/M in machines) - if (M.id == src.id) + if (M.id == id) spawn( 0 ) M.ignite() for(var/obj/machinery/igniter/M in machines) - if(M.id == src.id) - use_power(50) - M.on = !( M.on ) - M.icon_state = text("igniter[]", M.on) + if(M.id == id) + M.ignite() sleep(50) diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index abd98091760..7b2775d9547 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -14,7 +14,18 @@ var/code = 1.0 var/id = 1.0 var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess. + var/_wifi_id + var/datum/wifi/receiver/button/mass_driver/wifi_receiver +/obj/machinery/mass_driver/initialize() + ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) + +/obj/machinery/mass_driver/Destroy() + qdel(wifi_receiver) + wifi_receiver = null + return ..() /obj/machinery/mass_driver/proc/drive(amount) if(stat & (BROKEN|NOPOWER)) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 9f8eed2eb57..8a9e29a0da2 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -186,11 +186,21 @@ var/cremating = 0 var/id = 1 var/locked = 0 + var/_wifi_id + var/datum/wifi/receiver/button/crematorium/wifi_receiver + +/obj/structure/crematorium/initialize() + ..() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) /obj/structure/crematorium/Destroy() if(connected) qdel(connected) connected = null + if(wifi_receiver) + qdel(wifi_receiver) + wifi_receiver = null return ..() /obj/structure/crematorium/proc/update() diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 51093296b27..53668d80de7 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -24,6 +24,8 @@ var/state = 0 var/locked = 0 + var/_wifi_id + var/datum/wifi/receiver/button/emitter/wifi_receiver /obj/machinery/power/emitter/verb/rotate() set name = "Rotate" @@ -40,12 +42,16 @@ ..() if(state == 2 && anchored) connect_to_network() + if(_wifi_id) + wifi_receiver = new(_wifi_id, src) /obj/machinery/power/emitter/Destroy() message_admins("Emitter deleted at ([x],[y],[z] - JMP)",0,1) log_game("Emitter deleted at ([x],[y],[z])") investigate_log("deleted at ([x],[y],[z])","singulo") - ..() + qdel(wifi_receiver) + wifi_receiver = null + return ..() /obj/machinery/power/emitter/update_icon() if (active && powernet && avail(active_power_usage)) diff --git a/code/modules/wireless/devices.dm b/code/modules/wireless/devices.dm new file mode 100644 index 00000000000..f3a56867a7c --- /dev/null +++ b/code/modules/wireless/devices.dm @@ -0,0 +1,164 @@ +//------------------------------- +// Buttons +// Sender: intended to be used by buttons, when the button is pressed it will call activate() on all connected /button +// receivers. +// Receiver: does whatever the subtype does. deactivate() by default calls activate(), so you will have to override in +// it in a subtype if you want it to do something. +//------------------------------- +/datum/wifi/sender/button/proc/activate(mob/living/user) + for(var/datum/wifi/receiver/button/B in connected_devices) + B.activate(user) + +/datum/wifi/sender/button/proc/deactivate(mob/living/user) + for(var/datum/wifi/receiver/button/B in connected_devices) + B.deactivate(user) + +/datum/wifi/receiver/button/proc/activate(mob/living/user) + +/datum/wifi/receiver/button/proc/deactivate(mob/living/user) + activate(user) //override this if you want deactivate to actually do something + +//------------------------------- +// Doors +// Sender: sends an open/close request to all connected /door receivers. Utilises spawn_sync to trigger all doors to +// open at approximately the same time. Waits until all doors have finished opening before returning. +// Receiver: will try to open/close the parent door when activate/deactivate is called. +//------------------------------- +/datum/wifi/sender/door/proc/open() + var/datum/spawn_sync/S = new() + + for(var/datum/wifi/receiver/button/door/D in connected_devices) + S.start_worker(D, "activate") + S.wait_until_done() + return + +/datum/wifi/sender/door/proc/close() + var/datum/spawn_sync/S = new() + + for(var/datum/wifi/receiver/button/door/D in connected_devices) + S.start_worker(D, "deactivate") + S.wait_until_done() + return + +/datum/wifi/receiver/button/door/activate() + var/obj/machinery/door/D = parent + if(istype(D) && D.can_open()) + D.open() + +/datum/wifi/receiver/button/door/deactivate() + var/obj/machinery/door/D = parent + if(istype(D) && D.can_close()) + D.close() + +//------------------------------- +// Emitter +// Activates/deactivates the parent emitter. +//------------------------------- +/datum/wifi/receiver/button/emitter/activate(mob/living/user) + ..() + var/obj/machinery/power/emitter/E = parent + if(istype(E) && !E.active) + E.activate(user) //if the emitter is not active, trigger the activate proc to toggle it + +/datum/wifi/receiver/button/emitter/deactivate(mob/living/user) + var/obj/machinery/power/emitter/E = parent + if(istype(E) && E.active) + E.activate(user) //if the emitter is active, trigger the activate proc to toggle it + +//------------------------------- +// Crematorium +// Triggers cremate() on the parent /crematorium. +//------------------------------- +/datum/wifi/receiver/button/crematorium/activate(mob/living/user) + ..() + var/obj/structure/crematorium/C = parent + if(istype(C)) + C.cremate(user) + +//------------------------------- +// Mounted Flash +// Triggers flash() on the parent /flasher. +//------------------------------- +/datum/wifi/receiver/button/flasher/activate(mob/living/user) + ..() + var/obj/machinery/flasher/F = parent + if(istype(F)) + F.flash() + +//------------------------------- +// Holosign +// Turns the parent /holosign on/off. +//------------------------------- +/datum/wifi/receiver/button/holosign/activate(mob/living/user) + ..() + var/obj/machinery/holosign/H = parent + if(istype(H) && !H.lit) + H.toggle() + +/datum/wifi/receiver/button/holosign/deactivate(mob/living/user) + var/obj/machinery/holosign/H = parent + if(istype(H) && H.lit) + H.toggle() + +//------------------------------- +// Igniter +// Turns the parent /igniter on/off. +//------------------------------- +/datum/wifi/receiver/button/igniter/activate(mob/living/user) + ..() + var/obj/machinery/igniter/I = parent + if(istype(I)) + if(!I.on) + I.ignite() + +/datum/wifi/receiver/button/igniter/deactivate(mob/living/user) + if(istype(parent, /obj/machinery/igniter)) + var/obj/machinery/igniter/I = parent + if(I.on) + I.ignite() + +//------------------------------- +// Sparker +// Triggers the parent /sparker to ignite(). +//------------------------------- +/datum/wifi/receiver/button/sparker/activate(mob/living/user) + ..() + var/obj/machinery/sparker/S = parent + if(istype(S)) + S.ignite() + +//------------------------------- +// Mass Driver +// Sender: carries out a sequence of first opening all connected doors, then activating all connected mass drivers, +// then closes all connected doors. It will wait before continuing the sequence after opening/closing the doors. +// Receiver: Triggers the parent mass dirver to activate. +//------------------------------- +/datum/wifi/sender/mass_driver/proc/cycle() + var/datum/spawn_sync/S = new() + + //tell all doors to open + for(var/datum/wifi/receiver/button/door/D in connected_devices) + S.start_worker(D, "activate") + S.wait_until_done() + + S.reset() + //tell all mass drivers to launch + for(var/datum/wifi/receiver/button/mass_driver/M in connected_devices) + spawn() + M.activate() + + sleep(20) + + //tell all doors to close + S.reset() + for(var/datum/wifi/receiver/button/door/D in connected_devices) + S.start_worker(D, "deactivate") + S.wait_until_done() + + return + +/datum/wifi/receiver/button/mass_driver/activate(mob/living/user) + ..() + var/obj/machinery/mass_driver/M = parent + if(istype(M)) + M.drive() diff --git a/code/modules/wireless/interfaces.dm b/code/modules/wireless/interfaces.dm new file mode 100644 index 00000000000..0d80b84b1fa --- /dev/null +++ b/code/modules/wireless/interfaces.dm @@ -0,0 +1,110 @@ +//------------------------------- +/* + Interfaces + + These are the datums that an object needs to connect via the wireless controller. You will need a /wifi/receiver to + allow other devices to connect to your device and send it instructions. You will need a /wifi/sender to send signals + to other devices with wifi receivers. You can have multiple devices (senders and receivers) if you program your + device to handle them. + + Each wifi interface has one "id". This identifies which devices can connect to each other. Multiple senders can + connect to multiple receivers as long as they have the same id. + + Variants are found in devices.dm + + To add a receiver to an object: + Add the following variables to the object: + var/_wifi_id << variable that can be configured on the map, this is passed to the receiver later + var/datum/wifi/receiver/subtype/wifi_receiver << the receiver (and subtype itself) + + Add or modify the objects initialize() proc to include: + if(_wifi_id) << only creates a wifi receiver if an id is set + wifi_receiver = new(_wifi_id, src) << this needs to be in initialize() as New() is usually too + early, and the receiver will try to connect to the controller + before it is setup. + + Add or modify the objects Destroy() proc to include: + qdel(wifi_receiver) + wifi_receiver = null + + Senders are setup the same way, except with a var/datum/wifi/sender/subtype/wifi_sender variable instead of (or in + addition to) a /wifi/receiver variable. + You will however need to call the /wifi/senders code to pass commands onto any connected receivers. + Example: + /obj/machinery/button/attack_hand() + wifi_sender.activate() +*/ +//------------------------------- + + +//------------------------------- +// Wifi +//------------------------------- +/datum/wifi + var/obj/parent + var/list/connected_devices + var/id + +/datum/wifi/New(var/new_id, var/obj/O) + connected_devices = new() + id = new_id + if(istype(O)) + parent = O + +/datum/wifi/Destroy(var/wifi/device) + parent = null + for(var/datum/wifi/D in connected_devices) + D.disconnect_device(src) + disconnect_device(D) + return ..() + +/datum/wifi/proc/connect_device(var/datum/wifi/device) + if(connected_devices) + connected_devices |= device + else + connected_devices = new() + connected_devices |= device + +/datum/wifi/proc/disconnect_device(var/datum/wifi/device) + if(connected_devices) + connected_devices -= device + +//------------------------------- +// Receiver +//------------------------------- +/datum/wifi/receiver/New() + ..() + if(wirelessProcess) + wirelessProcess.add_device(src) + +/datum/wifi/receiver/Destroy() + if(wirelessProcess) + wirelessProcess.remove_device(src) + return ..() + +//------------------------------- +// Sender +//------------------------------- +/datum/wifi/sender/New() + ..() + send_connection_request() + +/datum/wifi/sender/proc/set_target(var/new_target) + id = new_target + +/datum/wifi/sender/proc/send_connection_request() + var/datum/connection_request/C = new(src, id) + wirelessProcess.add_request(C) + + +//------------------------------- +// Connection request +//------------------------------- +/datum/connection_request + var/datum/wifi/sender/source //wifi/sender object creating the request + var/id //id tag of the target device(s) to try to connect to + +/datum/connection_request/New(var/datum/wifi/sender/sender, var/receiver) + if(istype(sender)) + source = sender + id = receiver diff --git a/html/changelogs/Loganbacca-wireless.yml b/html/changelogs/Loganbacca-wireless.yml new file mode 100644 index 00000000000..20e7eff0cf9 --- /dev/null +++ b/html/changelogs/Loganbacca-wireless.yml @@ -0,0 +1,4 @@ +author: Loganbacca +delete-after: True +changes: + - rscadd: "Added a backend (wireless) system for communication between machinery and other devices." \ No newline at end of file