diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index dd810edfe60..c66079312ed 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -6977,7 +6977,7 @@ "cEi" = (/obj/machinery/light{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{dir = 4; icon_state = "blue"},/area/medical/patients_rooms) "cEj" = (/turf/simulated/wall/r_wall,/area/medical/patient_b) "cEk" = (/obj/structure/closet/l3closet/scientist,/obj/machinery/light{dir = 8},/turf/simulated/floor/plasteel{dir = 4; icon_state = "warning"},/area/toxins/xenobiology) -"cEl" = (/obj/structure/table,/obj/item/weapon/storage/box/monkeycubes,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cEl" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cEm" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/item/stack/sheet/mineral/plasma{amount = 8; layer = 2.9},/obj/machinery/media/receiver/boombox,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cEn" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cEo" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) @@ -7098,7 +7098,7 @@ "cGz" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/plating,/area/maintenance/asmaint) "cGA" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "xenobio1"; name = "Containment Blast Doors"; opacity = 0},/obj/machinery/door/window/northleft{base_state = "right"; dir = 8; icon_state = "right"; name = "Containment Pen"; req_access_txt = "55"},/turf/simulated/floor/engine,/area/toxins/xenobiology) "cGB" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) -"cGC" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cGC" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/computer/camera_advanced/xenobio,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cGD" = (/obj/machinery/camera{c_tag = "Xenobiology Module East"; dir = 8; network = list("Research","SS13"); pixel_y = -22},/obj/machinery/firealarm{dir = 4; pixel_x = 24},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cGE" = (/turf/simulated/floor/plating/airless,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0; tag = ""},/turf/simulated/floor/plating/airless/catwalk{tag = "icon-catwalk3"; icon_state = "catwalk3"},/area/solar/starboard) "cGF" = (/turf/simulated/floor/plating/airless,/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating/airless/catwalk{tag = "icon-catwalk3"; icon_state = "catwalk3"},/area/solar/port) @@ -7260,14 +7260,14 @@ "cJF" = (/obj/machinery/air_sensor{frequency = 1441; id_tag = "n2o_sensor"},/turf/simulated/floor/engine/n20,/area/atmos) "cJG" = (/obj/machinery/portable_atmospherics/canister/sleeping_agent/roomfiller{valve_open = 0; volume = 1e+006},/turf/simulated/floor/engine/n20,/area/atmos) "cJH" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor/engine/n20,/area/atmos) -"cJI" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) -"cJJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cJI" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/machinery/computer/camera_advanced/xenobio,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cJJ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/stool/bed/chair/comfy/blue{dir = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cJK" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cJL" = (/obj/item/weapon/extinguisher,/obj/item/weapon/extinguisher{pixel_x = 4; pixel_y = 4},/obj/structure/table/glass,/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/structure/sign/deathsposal{pixel_y = -32},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cJM" = (/obj/structure/rack,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cJN" = (/turf/simulated/floor/plating/airless/catwalk{tag = "icon-catwalk0"; icon_state = "catwalk0"},/area/space) "cJO" = (/obj/structure/rack,/obj/effect/spawner/lootdrop/maintenance,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/maintenance/asmaint) -"cJP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) +"cJP" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/disposalpipe/segment,/obj/structure/stool/bed/chair/comfy/blue{dir = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "cJQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4; level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4; level = 1},/turf/simulated/floor/plasteel{dir = 5; icon_state = "whitegreencorner"},/area/medical/virology) "cJR" = (/obj/structure/table,/obj/item/device/healthanalyzer,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/asmaint) "cJS" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{level = 1},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) @@ -8730,6 +8730,7 @@ "dlT" = (/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/machinery/power/treadmill{dir = 8},/obj/structure/cable/yellow,/obj/machinery/treadmill_monitor{id = "Cell 2"; pixel_y = -32},/turf/simulated/floor/plasteel,/area/security/prison/cell_block/A) "dlU" = (/obj/structure/stool/bed,/obj/machinery/flasher{id = "Cell 2"; pass_flags = 0; pixel_x = 0; pixel_y = -26},/turf/simulated/floor/plasteel{icon_state = "red"; dir = 4},/area/security/prison/cell_block/A) "dlV" = (/obj/machinery/power/treadmill{dir = 4},/obj/machinery/treadmill_monitor{on = 1; pixel_y = -32; redeem_immediately = 1},/obj/structure/cable/yellow,/turf/simulated/floor/plasteel,/area/security/prison/cell_block/C) +"dlW" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) (1,1,1) = {" bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8905,8 +8906,8 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikafxaabczocAkczqbikczocAkczqaabczocAkczqaabbikbikaabaabaabaabaabbikbikbikbikbikaabbikbikczscwWcvKcBecxjcBfcBgcBhcBicBjcBicBkcBicBlcBmcxfcBncztcztczxcBocBpcBqcBrcBscBtcBucBvcBwcBxcBycBzcBAcBBcBCcBDcBDcBEcBFcBGcBHcBIcBJcBKcBLcBMcrecBOcHucHtcDPcDPcDPcDPcDPcDPcHvcoAcEhclUclUclUclUclUclUcjmbEJcjmcFfclUclUcoAcoAcoAcoAcusbGycoAbikbikckPcxOcBZcxOcCacxRcqUcCbcCccCdcCecqUcqUcCgcqUcChckPbikaabaabcwGcwGcCscwGcwGbikbwobxXcvzcyJcHycHxbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikczocAkczqaabczocAkczqbikczocAkczqbikbikbikbikbikbikaabaabaabbikaabbikaabaabbikbikcybcCicvKcCjcCkcCkcClcvKcvKcvKcvKcvKcvKcvKcvKcvKcvKcvKcvKcvKcCmcCncCmcCocCmcrmcCpcCqcFbcCtcCtcCtcCucCvcBCcCwcCxcCycCzcCAcCBcBIcCCcCDcCEcCFcHzcCHcHAcCJaabcCKcCKcCKcCKcCKcHBcoAcHDcHCcIGcHHcIHctackycjocBWckuckycBXcCPcBYcCRcCQcoAcusbGycoAbikbikckPcxOcxOcxOcAQcCTczbcCUcCVcCWcCXcCZcCZcDacqUcDbckPaabaabbikbikbikcIKbikbikbikbwobxXcvzcyJbxXbxXbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGacGafxaabbikczocAkczqaabczocAkczqbikczocAkczqaabbikbikbikbikbikbikbikbikaabcDccDdcDdcDdcDdcybcDecwWcDfcDgcDhcDhcDicDjcDkcDlcDlcDlcDlcDmcDncDocDncDncDpcDpcDncDqcDrcDscDtcDtctYcDvcDwcDxcDycDzcDzcDAcDBcDCcDDcDEcDFcCAcDGcBIcDHcDIcDJcDKcILcDMcIMcDOcDPcDQcDRcDScDTcCKcHBcoDcEhclUcvscvqcIOcINcxLckxckwdcrclUcCSczVcuqczVcDUcoAcusbGycoAcoAbikckPcwAcwAcwAcwAcEkcqUcCbcElcEmcCecqUcEncEocEocEpcEqcXYaabbikbikbikbikbikbikbikbwobxXcGybxXbxXcIPbwoaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabaabcEraabaabaabcEraabbikaabcEraabbikbikbikbikbikbikbikbikcDccDccDccEscEtcEucEvcEwcExcEycDfcDfcEzcEAcvKcvKcEBcECcECcECcECcEDcEEcEFcEEcEEcEEcDtcDtcEGcEHcEIcEJcEKcDzcELcDwcDzcDzcDzcDzcEMcBCcENcEOcCycDFcCAcDFcBIcDHcDIcEPcEQcERcEScETcEUaabcEVcEWcDTcEXcCKcHBcoDcHDcHCcxKcxJczVcxMclUcIIcDVdcsclUcDWcDYczVcEbcEaclUcusbGycITcoAbikckPcwtcwucwvcFjcARczbcFkcJJcJIcJKcJKcFocFpcFqcJLckPaabaabaabbikbikbikbikbikbikbwocJMcvzbwobwobwobwobwoaabaabaabcJNcJNcJNcJNcJNcJNaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabcFscFtcFtcFucFvcFwcFwcFwcFvcFwcFwcFwcFvcFwcFwcFxcFtcFtcFtcFtcFtcFycFzcFAcFBcFCcFDcFEcFFcFGcfRcwWcFHcDfcvKcvKcvKcFIcEBcECcFJcFKcFLcyrcFNcDucFPcFOcFQcFScFTcSpcFVcFWcFXcFScFYcFZcDwcGacDzcDzcDzcGbcBCcGccGccDFcGdcGecGfcGgcGhcGicGjcGkcGlcGmcGncDOcGocDQcGpcDTcDTcCKcHBcoDcEhclUcyMcyLcyNcFfclUcnkclTcFfclUcyQcyScyRcyTcyTclUcusbGycJOcoAbikckPcxOcxPcxOcGAcxRcqUcGBcJPcGCcqUcqUcGDcwAcwAcwAckPbikbikaabaabbikbikbikbikbikbwocyKcvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabaabcEraabaabaabcEraabbikaabcEraabbikbikbikbikbikbikbikbikcDccDccDccEscEtcEucEvcEwcExcEycDfcDfcEzcEAcvKcvKcEBcECcECcECcECcEDcEEcEFcEEcEEcEEcDtcDtcEGcEHcEIcEJcEKcDzcELcDwcDzcDzcDzcDzcEMcBCcENcEOcCycDFcCAcDFcBIcDHcDIcEPcEQcERcEScETcEUaabcEVcEWcDTcEXcCKcHBcoDcHDcHCcxKcxJczVcxMclUcIIcDVdcsclUcDWcDYczVcEbcEaclUcusbGycITcoAbikckPcwtcwucwvcFjcARczbcFkcJIcGCcJKcJKcFocFpcFqcJLckPaabaabaabbikbikbikbikbikbikbwocJMcvzbwobwobwobwobwoaabaabaabcJNcJNcJNcJNcJNcJNaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabcFscFtcFtcFucFvcFwcFwcFwcFvcFwcFwcFwcFvcFwcFwcFxcFtcFtcFtcFtcFtcFycFzcFAcFBcFCcFDcFEcFFcFGcfRcwWcFHcDfcvKcvKcvKcFIcEBcECcFJcFKcFLcyrcFNcDucFPcFOcFQcFScFTcSpcFVcFWcFXcFScFYcFZcDwcGacDzcDzcDzcGbcBCcGccGccDFcGdcGecGfcGgcGhcGicGjcGkcGlcGmcGncDOcGocDQcGpcDTcDTcCKcHBcoDcEhclUcyMcyLcyNcFfclUcnkclTcFfclUcyQcyScyRcyTcyTclUcusbGycJOcoAbikckPcxOcxPcxOcGAcxRcqUcGBcJPcJJcqUdlWcGDcwAcwAcwAckPbikbikaabaabbikbikbikbikbikbwocyKcvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabaabcGFaabbikaabcGFaabbikaabcGFaabbikbikbikbikbikbikbikbikcDccDccDccGGcGHcFMcDdcGJcfRcGKcExcExcExcExcGLcExcFGcECcGMcGNcGOcGPcGQcGRcGScGTcGUcGVcGWcGXcGYcGZcHacHbcFYcELcDwcHccHdcDzcDzcHecBCcHfcHgcDFcHhcCAcHicHjcHkcHlcHmcHncHocHpcHocHqaabcCKcCKcCKcCKcCKcHBcoAcEhclUcIJcyVcyYcyXcEecEccEgcEfcHwcGucHZczVcIRcIQclUcusbGycJRcoAbikckPcxOcxOcxOcFjcHEcHFcHGcJScHIcCZcCZcCZcHJcHKcHLcHMbikbikbikaabaabbikbikbikbikbwobwocvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGacGafxaabaabczocHOczqbikczocHOczqbikczocHOczqaabbikbikbikbikbikbikbikaabaabcDccDdcDdcDdcDdcHPcHQcHRcfRcHScfRcfRcEBcHTcfRcECcHUcHVcGOcHWcFNcHXcHYcIacIacIbcIccIdcIecIfbRFcIbcIhcIicIjcIkcIlcImcIncIocIpcIqcGfcIrcIscItcIucIvcIwcIxcIycIzcIAcIBcICcIDcDPcDQcIEcIFcIFcCKcHBcoAcEhclUclUclUclUclUcJhcANcBRcJQcMccBScMecMdcMCcBVclUcuscGqcGrcGrcGrcJTcJTcJTcJTcJTcJUcKTcKbcKUcIUczbcIVczbcIWczbcIXcHMbikbikbikbikaabaabbikbikbikbikbwocvzbwoaabaabaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikczocHOczqaabczocHOczqbikczocHOczqbikbikbikaabbikbikbikbikaabaabaabbikbikaabaabcJbcJbcJbcJbcJbcJbcJbcJccJbcJbcECcJdcJecGOcHWcFNcJfcFNcJgcLhcDtcJicJjcFWcJkcFRcDtcJmcDzcDwcJncJocJpcIncJqcJrcJscJtcJucJvcJwcJtcJxcJycJzcJAcDFcJBcJCcJDcJEaabcEVcJFcJGcJHcCKcHBcoDcKWcKVcKVcKVcKXclUcFacyLcCLcFecyScCMcyTcyTcyScCNclUcuscGvbVibGycKYcKZcoAbikbikckPcJVcJWcJXcJYcJVcJWcJZcKacJVcJWcLackPaabaabaabaabaabaabaabaabaabaabbwocvzbwobwobwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjcbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik diff --git a/code/__DEFINES/stat.dm b/code/__DEFINES/stat.dm index 4ab2ba43203..fe780c5d154 100644 --- a/code/__DEFINES/stat.dm +++ b/code/__DEFINES/stat.dm @@ -39,5 +39,17 @@ #define SHUTTLE_CALL 2 #define SHUTTLE_DOCKED 3 #define SHUTTLE_STRANDED 4 -#define SHUTTLE_ESCAPE 5 -#define SHUTTLE_ENDGAME 6 \ No newline at end of file +#define SHUTTLE_ESCAPE 5 +#define SHUTTLE_ENDGAME 6 + + +/* + Logic +*/ +// State When to Use Example +#define LOGIC_OFF 0 //Use this for when you want it to stay off (continuous signal, lever) +#define LOGIC_ON 1 //Use this for when you want it to stay on (continuous signal, lever) +#define LOGIC_FLICKER 2 //Use this for when you want it to turn on and then turn off (buttons, clocks) + +//Logic-related stuff (Misc. defines for logic things, to keep it organized or something) +#define LOGIC_FLICKER_TIME 10 //number of deciseconds LOGIC_TEMP_ON will remain active before turning off diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm index fd3fa222c82..43bee48f267 100644 --- a/code/controllers/communications.dm +++ b/code/controllers/communications.dm @@ -202,6 +202,7 @@ var/const/RADIO_CLEANBOT = "10" var/const/RADIO_FLOORBOT = "11" var/const/RADIO_MEDBOT = "12" var/const/RADIO_MAGNETS = "radio_magnet" +var/const/RADIO_LOGIC = "radio_logic" var/global/datum/controller/radio/radio_controller diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index b38830b4b44..0934959d20f 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -1,3 +1,8 @@ + +////////////////////////////////////// +// Driver Button // +////////////////////////////////////// + /obj/machinery/driver_button name = "mass driver button" icon = 'icons/obj/objects.dmi' @@ -5,11 +10,17 @@ desc = "A remote control switch for a mass driver." var/id_tag = "default" var/active = 0 - settagwhitelist = list("id_tag") + settagwhitelist = list("id_tag", "logic_id_tag") anchored = 1.0 use_power = 1 idle_power_usage = 2 active_power_usage = 4 + var/range = 7 + + var/datum/radio_frequency/radio_connection + var/frequency = 0 + var/logic_id_tag = "default" //Defines the ID tag to send logic signals to, so you don't have to unlink from doors and stuff + var/logic_connect = 0 //Set this to allow the button to send out logic signals when pressed in addition to normal stuff /obj/machinery/driver_button/New(turf/loc, var/w_dir=null) ..() @@ -22,6 +33,123 @@ pixel_x = 25 if(WEST) pixel_x = -25 + if(radio_controller) + set_frequency(frequency) + +/obj/machinery/driver_button/initialize() + ..() + set_frequency(frequency) + +/obj/machinery/driver_button/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) + return + +/obj/machinery/driver_button/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + + +/obj/machinery/driver_button/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/driver_button/attackby(obj/item/weapon/W, mob/user as mob, params) + + if(istype(W, /obj/item/device/detective_scanner)) + return + + if(istype(W, /obj/item/device/multitool)) + update_multitool_menu(user) + return 1 + + if(istype(W, /obj/item/weapon/wrench)) + playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 30, target = src)) + user << "You detach \the [src] from the wall." + new/obj/item/mounted/frame/driver_button(get_turf(src)) + qdel(src) + return 1 + + return src.attack_hand(user) + +/obj/machinery/driver_button/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) + return {" + "} + +/obj/machinery/driver_button/attack_hand(mob/user as mob) + + src.add_fingerprint(usr) + if(stat & (NOPOWER|BROKEN)) + return + if(active) + return + add_fingerprint(user) + + use_power(5) + + launch_sequence() + + return + +/obj/machinery/driver_button/proc/launch_sequence() + active = 1 + icon_state = "launcheract" + + if(logic_connect) + if(!radio_connection) //can't output without this + return + + if(logic_id_tag == null) //Don't output to an undefined id_tag + return + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = logic_id_tag, + "sigtype" = "logic", + "state" = LOGIC_FLICKER, //Buttons are a FLICKER source, since they only register as ON when you press it, then turn OFF after you release + ) + + radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) + + for(var/obj/machinery/door/poddoor/M in range(src,range)) + if (M.id_tag == src.id_tag && !M.protected) + spawn() + M.open() + + sleep(20) + + for(var/obj/machinery/mass_driver/M in range(src,range)) + if(M.id_tag == src.id_tag) + M.drive() + + sleep(50) + + for(var/obj/machinery/door/poddoor/M in range(src,range)) + if (M.id_tag == src.id_tag && !M.protected) + spawn() + M.close() + return + + icon_state = "launcherbtt" + active = 0 + +/obj/machinery/driver_button/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + if("toggle_logic" in href_list) + logic_connect = !logic_connect + +////////////////////////////////////// +// Ignition Switch // +////////////////////////////////////// /obj/machinery/ignition_switch name = "ignition switch" @@ -35,6 +163,46 @@ idle_power_usage = 2 active_power_usage = 4 +/obj/machinery/ignition_switch/attack_ai(mob/user as mob) + return src.attack_hand(user) + +/obj/machinery/ignition_switch/attackby(obj/item/weapon/W, mob/user as mob, params) + return src.attack_hand(user) + +/obj/machinery/ignition_switch/attack_hand(mob/user as mob) + + if(stat & (NOPOWER|BROKEN)) + return + if(active) + return + + use_power(5) + + active = 1 + icon_state = "launcheract" + + for(var/obj/machinery/sparker/M in world) + if (M.id == src.id) + spawn( 0 ) + M.spark() + + for(var/obj/machinery/igniter/M in world) + if(M.id == src.id) + use_power(50) + M.on = !( M.on ) + M.icon_state = text("igniter[]", M.on) + + sleep(50) + + icon_state = "launcherbtt" + active = 0 + + return + +////////////////////////////////////// +// Flasher Button // +////////////////////////////////////// + /obj/machinery/flasher_button name = "flasher button" desc = "A remote control switch for a mounted flasher." @@ -47,6 +215,10 @@ idle_power_usage = 2 active_power_usage = 4 +////////////////////////////////////// +// Crematorium Switch // +////////////////////////////////////// + /obj/machinery/crema_switch desc = "Burn baby burn!" name = "crematorium igniter" diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 8886c865722..49cc616d174 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -878,4 +878,50 @@ obj/item/weapon/circuitboard/rdserver req_components = list( /obj/item/weapon/stock_parts/matter_bin = 1, /obj/item/weapon/stock_parts/manipulator = 1, - /obj/item/weapon/stock_parts/console_screen = 1) \ No newline at end of file + /obj/item/weapon/stock_parts/console_screen = 1) + + +//Selectable mode board, like vending machine boards +/obj/item/weapon/circuitboard/logic_gate + name = "circuit board (Logic Connector)" + build_path = /obj/machinery/logic_gate + board_type = "machine" + origin_tech = "programming=1" //This stuff is pretty much the absolute basis of programming, so it's mostly useless for research + req_components = list(/obj/item/stack/cable_coil = 1) + + var/list/names_paths = list( + "NOT Gate" = /obj/machinery/logic_gate/not, + "OR Gate" = /obj/machinery/logic_gate/or, + "AND Gate" = /obj/machinery/logic_gate/and, + "NAND Gate" = /obj/machinery/logic_gate/nand, + "NOR Gate" = /obj/machinery/logic_gate/nor, + "XOR Gate" = /obj/machinery/logic_gate/xor, + "XNOR Gate" = /obj/machinery/logic_gate/xnor, + "STATUS Gate" = /obj/machinery/logic_gate/status, + "CONVERT Gate" = /obj/machinery/logic_gate/convert + ) + +/obj/item/weapon/circuitboard/logic_gate/New() + ..() + if(build_path == /obj/machinery/logic_gate) //If we spawn the base type board (determined by the base type machine as the build path), become a random gate board + var/new_path = names_paths[pick(names_paths)] + set_type(new_path) + +/obj/item/weapon/circuitboard/logic_gate/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/screwdriver)) + set_type(null, user) + +/obj/item/weapon/circuitboard/logic_gate/proc/set_type(typepath, mob/user) + var/new_name = "Logic Base" + if(!typepath) + new_name = input("Circuit Setting", "What would you change the board setting to?") in names_paths + typepath = names_paths[new_name] + else + for(var/name in names_paths) + if(names_paths[name] == typepath) + new_name = name + break + build_path = typepath + name = "circuit board ([new_name])" + if(user) + user << "You set the board to [new_name]." diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index d2172bd9294..8c419216d07 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -131,74 +131,3 @@ icon_state = "doorctrl-p" else icon_state = "doorctrl0" - -/obj/machinery/driver_button/var/range = 7 - -/obj/machinery/driver_button/attack_ai(mob/user as mob) - return src.attack_hand(user) - -/obj/machinery/driver_button/attackby(obj/item/weapon/W, mob/user as mob, params) - - if(istype(W, /obj/item/device/detective_scanner)) - return - - if(istype(W, /obj/item/device/multitool)) - update_multitool_menu(user) - return 1 - - if(istype(W, /obj/item/weapon/wrench)) - playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1) - if(do_after(user, 30, target = src)) - to_chat(user, "You detach \the [src] from the wall.") - new/obj/item/mounted/frame/driver_button(get_turf(src)) - qdel(src) - return 1 - - return src.attack_hand(user) - -/obj/machinery/driver_button/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) - return {" - "} - -/obj/machinery/driver_button/attack_hand(mob/user as mob) - - src.add_fingerprint(usr) - if(stat & (NOPOWER|BROKEN)) - return - if(active) - return - add_fingerprint(user) - - use_power(5) - - launch_sequence() - - return - -/obj/machinery/driver_button/proc/launch_sequence() - active = 1 - icon_state = "launcheract" - - for(var/obj/machinery/door/poddoor/M in range(src,range)) - if (M.id_tag == src.id_tag && !M.protected) - spawn() - M.open() - - sleep(20) - - for(var/obj/machinery/mass_driver/M in range(src,range)) - if(M.id_tag == src.id_tag) - M.drive() - - sleep(50) - - for(var/obj/machinery/door/poddoor/M in range(src,range)) - if (M.id_tag == src.id_tag && !M.protected) - spawn() - M.close() - return - - icon_state = "launcherbtt" - active = 0 \ No newline at end of file diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index 25989db9e0f..d6e41d29fa2 100755 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -114,39 +114,3 @@ return spark() ..(severity) - -/obj/machinery/ignition_switch/attack_ai(mob/user as mob) - return src.attack_hand(user) - -/obj/machinery/ignition_switch/attackby(obj/item/weapon/W, mob/user as mob, params) - return src.attack_hand(user) - -/obj/machinery/ignition_switch/attack_hand(mob/user as mob) - - if(stat & (NOPOWER|BROKEN)) - return - if(active) - return - - use_power(5) - - active = 1 - icon_state = "launcheract" - - for(var/obj/machinery/sparker/M in world) - if (M.id == src.id) - spawn( 0 ) - M.spark() - - for(var/obj/machinery/igniter/M in world) - if(M.id == src.id) - use_power(50) - M.on = !( M.on ) - M.icon_state = text("igniter[]", M.on) - - sleep(50) - - icon_state = "launcherbtt" - active = 0 - - return \ No newline at end of file diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index f83a92ff3e7..41e1587ecd4 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -11,9 +11,27 @@ var/area/area = null var/otherarea = null // luminosity = 1 + settagwhitelist = list("logic_id_tag") + var/light_connect = 1 //Allows the switch to control lights in its associated areas. When set to 0, using the switch won't affect the lights. + var/datum/radio_frequency/radio_connection + var/frequency = 0 + var/logic_id_tag = "default" //Defines the ID tag to send logic signals to. + var/logic_connect = 0 //Set this to allow the switch to send out logic signals. -/obj/machinery/light_switch/New() + +/obj/machinery/light_switch/New(turf/loc, var/w_dir=null) ..() + switch(w_dir) + if(NORTH) + pixel_y = 25 + if(SOUTH) + pixel_y = -25 + if(EAST) + pixel_x = 25 + if(WEST) + pixel_x = -25 + if(radio_controller) + set_frequency(frequency) spawn(5) src.area = src.loc.loc @@ -26,7 +44,20 @@ src.on = src.area.lightswitch updateicon() +/obj/machinery/light_switch/initialize() + ..() + set_frequency(frequency) +/obj/machinery/light_switch/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) + return + +/obj/machinery/light_switch/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() /obj/machinery/light_switch/proc/updateicon() if(stat & NOPOWER) @@ -41,22 +72,55 @@ if(..(user, 1)) to_chat(user, "A light switch. It is [on? "on" : "off"].") - /obj/machinery/light_switch/attack_hand(mob/user) on = !on + updateicon() - area.lightswitch = on - area.updateicon() + if(light_connect) + area.lightswitch = on + area.updateicon() - for(var/obj/machinery/light_switch/L in area) - L.on = on - L.updateicon() + if(logic_connect && powered(LIGHT)) //Don't bother sending a signal if we aren't set to send them or we have no power to send with. + handle_output() - area.power_change() + if(light_connect) + for(var/obj/machinery/light_switch/L in area) + L.on = on + L.updateicon() + + area.power_change() + +/obj/machinery/light_switch/proc/handle_output() + if(!radio_connection) //can't output without this + return + + if(logic_id_tag == null) //Don't output to an undefined id_tag + return + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + //Light switches are continuous signal sources, since they register as ON or OFF and stay that way until adjusted again + if(on) + signal.data = list( + "tag" = logic_id_tag, + "sigtype" = "logic", + "state" = LOGIC_ON, + ) + else + signal.data = list( + "tag" = logic_id_tag, + "sigtype" = "logic", + "state" = LOGIC_OFF, + ) + + radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) + if(on) + use_power(5, LIGHT) //Use a tiny bit of power every time we send an ON signal. Draws from the local APC's lighting circuit, since this is a LIGHT switch. /obj/machinery/light_switch/power_change() - if(!otherarea) if(powered(LIGHT)) stat &= ~NOPOWER @@ -71,3 +135,40 @@ return power_change() ..(severity) + +/obj/machinery/light_switch/process() + if(logic_connect && powered(LIGHT)) //We won't send signals while unpowered, but the last signal will remain valid for anything that received it before we went dark + handle_output() + +/obj/machinery/light_switch/attackby(obj/item/weapon/W as obj, mob/user as mob, params) + if(istype(W, /obj/item/device/detective_scanner)) + return + + if(istype(W, /obj/item/device/multitool)) + update_multitool_menu(user) + return 1 + + if(istype(W, /obj/item/weapon/wrench)) + playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1) + if(do_after(user, 30, target = src)) + user << "You detach \the [src] from the wall." + new/obj/item/mounted/frame/light_switch(get_turf(src)) + qdel(src) + return 1 + + return src.attack_hand(user) + +/obj/machinery/light_switch/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) + return {" + "} + +/obj/machinery/light_switch/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + if("toggle_light_connect" in href_list) + light_connect = !light_connect + if("toggle_logic" in href_list) + logic_connect = !logic_connect diff --git a/code/game/objects/items/mountable_frames/buttons_switches.dm b/code/game/objects/items/mountable_frames/buttons_switches.dm new file mode 100644 index 00000000000..b1e3fabbb86 --- /dev/null +++ b/code/game/objects/items/mountable_frames/buttons_switches.dm @@ -0,0 +1,23 @@ +/obj/item/mounted/frame/driver_button + name = "mass driver button frame" + desc = "Used for repairing or building mass driver buttons" + icon = 'icons/obj/objects.dmi' + icon_state = "launcherbtt_frame" + mount_reqs = list("simfloor") + sheets_refunded = 1 + +/obj/item/mounted/frame/driver_button/do_build(turf/on_wall, mob/user) + new /obj/machinery/driver_button(get_turf(user), get_dir(user, on_wall)) + qdel(src) + +/obj/item/mounted/frame/light_switch + name = "light switch frame" + desc = "Used for repairing or building light switches" + icon = 'icons/obj/power.dmi' + icon_state = "light-p" + mount_reqs = list("simfloor", "nospace") + sheets_refunded = 1 + +/obj/item/mounted/frame/light_switch/do_build(turf/on_wall, mob/user) + new /obj/machinery/light_switch(get_turf(user), get_dir(user, on_wall)) + qdel(src) \ No newline at end of file diff --git a/code/game/objects/items/mountable_frames/driver_button.dm b/code/game/objects/items/mountable_frames/driver_button.dm deleted file mode 100644 index 7c888b48c95..00000000000 --- a/code/game/objects/items/mountable_frames/driver_button.dm +++ /dev/null @@ -1,10 +0,0 @@ -/obj/item/mounted/frame/driver_button - name = "mass driver button frame" - desc = "Used for repairing or building mass driver buttons" - icon = 'icons/obj/objects.dmi' - icon_state = "launcherbtt_frame" - mount_reqs = list("simfloor") - -/obj/item/mounted/frame/driver_button/do_build(turf/on_wall, mob/user) - new /obj/machinery/driver_button(get_turf(user), get_dir(user, on_wall)) - qdel(src) \ No newline at end of file diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 21680521d34..7cb53eaed5f 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -73,6 +73,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \ ), 4), \ null, \ new/datum/stack_recipe("mass driver button frame", /obj/item/mounted/frame/driver_button, 1, time = 50, one_per_turf = 0, on_floor = 1), \ + new/datum/stack_recipe("light switch frame", /obj/item/mounted/frame/light_switch, 1, time = 50, one_per_turf = 0, on_floor = 1), \ null, \ new/datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade), \ new/datum/stack_recipe("light fixture frame", /obj/item/mounted/frame/light_fixture, 2), \ diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index fe33be50f48..d6d6352f333 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -18,149 +18,150 @@ var/datum/radio_frequency/radio_connection var/airlock_wire = null - New() - ..() - if(!radio_controller) - spawn(40) - set_frequency(frequency) - else - spawn(1) // For things that set the frequency directly - set_frequency(frequency) +/obj/item/device/assembly/signaler/New() + ..() + if(radio_controller) + set_frequency(frequency) + +/obj/item/device/assembly/signaler/initialize() + if(radio_controller) + set_frequency(frequency) + +/obj/item/device/assembly/signaler/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + +/obj/item/device/assembly/signaler/describe() + return "\The [src]'s power light is [receiving?"on":"off"]" + +/obj/item/device/assembly/signaler/activate() + if(cooldown > 0) return 0 + cooldown = 2 + spawn(10) + process_cooldown() + + signal() + return 1 + +/obj/item/device/assembly/signaler/update_icon() + if(holder) + holder.update_icon() + return + +/obj/item/device/assembly/signaler/interact(mob/user as mob, flag1) + var/t1 = "-------" +// if ((src.b_stat && !( flag1 ))) +// t1 = text("-------
\nGreen Wire: []
\nRed Wire: []
\nBlue Wire: []
\n", (src.wires & 4 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 2 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 1 ? text("Cut Wire", src) : text("Mend Wire", src))) +// else +// t1 = "-------" Speaker: [src.listening ? "Engaged" : "Disengaged"]
+ var/dat = {" + + "} + if(!flag1) + dat += {" + Send Signal
+ Reciever is [receiving?"on":"off"]
+ "} + dat += {" + Frequency/Code for signaler:
+ Frequency: + - + - + [format_frequency(src.frequency)] + + + +
+ + Code: + - + - + [src.code] + + + +
+ [t1] +
+ "} + user << browse(dat, "window=radio") + onclose(user, "radio") + return + + +/obj/item/device/assembly/signaler/Topic(href, href_list) + ..() + + if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + usr << browse(null, "window=radio") + onclose(usr, "radio") return - Destroy() - if(radio_controller) - radio_controller.remove_object(src,frequency) - return ..() + if (href_list["freq"]) + var/new_frequency = (frequency + text2num(href_list["freq"])) + if(new_frequency < RADIO_LOW_FREQ || new_frequency > RADIO_HIGH_FREQ) + new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + set_frequency(new_frequency) - describe() - return "\The [src]'s power light is [receiving?"on":"off"]" - - activate() - if(cooldown > 0) return 0 - cooldown = 2 - spawn(10) - process_cooldown() + if(href_list["code"]) + src.code += text2num(href_list["code"]) + src.code = round(src.code) + src.code = min(100, src.code) + src.code = max(1, src.code) + if(href_list["receive"]) + receiving = !receiving + if(href_list["send"]) + spawn( 0 ) signal() - return 1 - update_icon() - if(holder) - holder.update_icon() - return - - interact(mob/user as mob, flag1) - var/t1 = "-------" -// if ((src.b_stat && !( flag1 ))) -// t1 = text("-------
\nGreen Wire: []
\nRed Wire: []
\nBlue Wire: []
\n", (src.wires & 4 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 2 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 1 ? text("Cut Wire", src) : text("Mend Wire", src))) -// else -// t1 = "-------" Speaker: [src.listening ? "Engaged" : "Disengaged"]
- var/dat = {" - - - Send Signal
- Reciever is [receiving?"on":"off"]
- Frequency/Code for signaler:
- Frequency: - - - - - [format_frequency(src.frequency)] - + - +
- - Code: - - - - - [src.code] - + - +
- [t1] -
"} - user << browse(dat, "window=radio") - onclose(user, "radio") - return - - - Topic(href, href_list) - ..() - - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=radio") - onclose(usr, "radio") - return - - if (href_list["freq"]) - var/new_frequency = (frequency + text2num(href_list["freq"])) - if(new_frequency < RADIO_LOW_FREQ || new_frequency > RADIO_HIGH_FREQ) - new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) - set_frequency(new_frequency) - - if(href_list["code"]) - src.code += text2num(href_list["code"]) - src.code = round(src.code) - src.code = min(100, src.code) - src.code = max(1, src.code) - if(href_list["receive"]) - receiving = !receiving - - if(href_list["send"]) - spawn( 0 ) - signal() - - if(usr) - attack_self(usr) - - return - - - proc/signal() - if(!radio_connection) return - - var/datum/signal/signal = new - signal.source = src - signal.encryption = code - signal.data["message"] = "ACTIVATE" - radio_connection.post_signal(src, signal) - - var/time = time2text(world.realtime,"hh:mm:ss") - var/turf/T = get_turf(src) - if(usr) - lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]") - - return - - - pulse(var/radio = 0) - if(src.connected && src.wires) - connected.Pulse(src) - else - return ..(radio) - - - receive_signal(datum/signal/signal) - if( !receiving || !signal ) - return 0 - - if(signal.encryption != code) - return 0 - if(!(src.wires & WIRE_RADIO_RECEIVE)) return 0 - - pulse(1) - for(var/mob/O in hearers(1, src.loc)) - O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2) - return - - - proc/set_frequency(new_frequency) - if(!radio_controller) - sleep(20) - if(!radio_controller) - return - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + if(usr) + attack_self(usr) + + return + +/obj/item/device/assembly/signaler/proc/signal() + if(!radio_connection) return + + var/datum/signal/signal = new + signal.source = src + signal.encryption = code + signal.data["message"] = "ACTIVATE" + radio_connection.post_signal(src, signal) + + var/time = time2text(world.realtime,"hh:mm:ss") + var/turf/T = get_turf(src) + if(usr) + lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]") + + return + +/obj/item/device/assembly/signaler/pulse(var/radio = 0) + if(src.connected && src.wires) + connected.Pulse(src) + else + return ..(radio) + +/obj/item/device/assembly/signaler/receive_signal(datum/signal/signal) + if( !receiving || !signal ) + return 0 + + if(signal.encryption != code) + return 0 + + if(!(src.wires & WIRE_RADIO_RECEIVE)) return 0 + pulse(1) + + for(var/mob/O in hearers(1, src.loc)) + O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2) + return + +/obj/item/device/assembly/signaler/proc/set_frequency(new_frequency) + if(!radio_controller) + sleep(20) + if(!radio_controller) return + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + return // Embedded signaller used in anomalies. /obj/item/device/assembly/signaler/anomaly diff --git a/code/modules/logic/converter.dm b/code/modules/logic/converter.dm new file mode 100644 index 00000000000..635bbf87176 --- /dev/null +++ b/code/modules/logic/converter.dm @@ -0,0 +1,143 @@ + +////////////////////////////////// +// Converter Gate // +////////////////////////////////// + +/* + This gate is special enough to warrant its own file, as it overrides a lot of the logic_gate procs as well as adds a new one. + - CONVERT Gates convert signaler and logic signals, to allow logic gates to actually be used in tandem with assemblies and station equipment like doors. + - While technically a mono-input device, the input and output are actually completely different types of signals, and thus incompatible without this gate. + - A signaler must be attached manually before the gate is fully functional, and will retain any frequency and code settings it had when attached. + - You can adjust these settings through a link in the multitool menu, but the receiving mode is automatically controlled by the converter. + - While attached, the ability to manually send the signal on the signaler through its menu is also disabled, to avoid messing up the logic system. +*/ + +//CONVERT Gate +/obj/machinery/logic_gate/convert + name = "CONVERT Gate" + desc = "Converts signals between radio and logic types, allowing for signaller input/output from logic systems." + icon_state = "logic_convert" + mono_input = 1 + + var/logic_output = 0 //When set to 1, the logic signal is the output. When set to 0, the logic signal is the input. + var/obj/item/device/assembly/signaler/attached_signaler = null + +/obj/machinery/logic_gate/convert/handle_logic() + output_state = input1_state + return + +/obj/machinery/logic_gate/convert/attackby(obj/item/O, mob/user, params) + if(tamperproof) //Extra precaution to avoid people attaching/removing signalers from tamperproofed converters + return + if(istype(O, /obj/item/device/assembly/signaler)) + var/obj/item/device/assembly/signaler/S = O + if(S.secured) + user << "The [S] is already secured." + return + if(attached_signaler) + user << "There is already a device attached, remove it first." + return + user.unEquip(S) + S.forceMove(src) + S.holder = src + S.toggle_secure() + if(logic_output) //Make sure we are set to receive if the converter is set to output logic, and send if the converter is set to accept logic input + S.receiving = 1 + else + S.receiving = 0 + attached_signaler = S + user << "You attach \the [S] to the I/O connection port and secure it." + return + if(attached_signaler && istype(O, /obj/item/weapon/screwdriver)) //Makes sure we remove the attached signaler before we can open up and deconstruct the machine + var/obj/item/device/assembly/signaler/S = attached_signaler + attached_signaler = null + S.forceMove(get_turf(src)) + S.holder = null + S.toggle_secure() + user << "You unsecure and detach \the [S] from the I/O connection port." + return + ..() + +/obj/machinery/logic_gate/convert/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) + var/logic_state_string + var/menu_contents = {" +
+ "} + if(logic_output) + switch(output_state) + if(LOGIC_OFF) + logic_state_string = "OFF" + if(LOGIC_ON) + logic_state_string = "ON" + if(LOGIC_FLICKER) + logic_state_string = "FLICKER" + else + logic_state_string = "ERROR: UNKNOWN STATE" + menu_contents += {" +
Output: [format_tag("ID Tag","output_id_tag")]
+
Output State: [logic_state_string]
+ "} + else + switch(input1_state) + if(LOGIC_OFF) + logic_state_string = "OFF" + if(LOGIC_ON) + logic_state_string = "ON" + if(LOGIC_FLICKER) + logic_state_string = "FLICKER" + else + logic_state_string = "ERROR: UNKNOWN STATE" + menu_contents += {" +
Input: [format_tag("ID Tag","input1_id_tag")]
+
Input State: [logic_state_string]
+ "} + menu_contents += {" +
Logic Signal Designation: [logic_output ? "Output" : "Input"]
+ "} + if(attached_signaler) + menu_contents += "
Adjust Signaler Settings
" + else + menu_contents += "
NO SIGNALER ATTACHED!
" + menu_contents += {" +
+ "} + return menu_contents + +/obj/machinery/logic_gate/convert/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + if("toggle_logic" in href_list) + logic_output = !logic_output + if(attached_signaler) //If we have a signaler attached, make sure we update it to send/receive when we change the logic signal desgination + if(logic_output) + attached_signaler.receiving = 1 + else + attached_signaler.receiving = 0 + if(("adjust_signaler" in href_list) && attached_signaler) //Make sure that we have a signaler attached to handle this one, otherwise ignore this command + attached_signaler.interact(user, 1) + update_multitool_menu(user) + +/obj/machinery/logic_gate/convert/receive_signal(datum/signal/signal, receive_method, receive_param) + if(logic_output) + if(attached_signaler) + attached_signaler.receive_signal(signal) + return + else + ..() + +/obj/machinery/logic_gate/convert/handle_output() + if(logic_output) + ..() + else + if(attached_signaler && (output_state == LOGIC_ON || output_state == LOGIC_FLICKER)) + attached_signaler.signal() + return + +/obj/machinery/logic_gate/convert/proc/process_activation(var/obj/item/device/D) + if(!logic_output) //Don't bother if our input is a logic signal + return + if(D == attached_signaler) //Ignore if we somehow got called by a device that isn't what we have attached + input1_state = LOGIC_FLICKER + spawn(LOGIC_FLICKER_TIME) + if(input1_state == LOGIC_FLICKER) + input1_state = LOGIC_OFF + return diff --git a/code/modules/logic/dual_input.dm b/code/modules/logic/dual_input.dm new file mode 100644 index 00000000000..03bfa4f1688 --- /dev/null +++ b/code/modules/logic/dual_input.dm @@ -0,0 +1,99 @@ + +////////////////////////////////// +// Dual-Input Gates // +////////////////////////////////// + + +// OR Gate +/obj/machinery/logic_gate/or + name = "OR Gate" + desc = "Outputs ON when at least one input is ON." + icon_state = "logic_or" + +/obj/machinery/logic_gate/or/handle_logic() + if(input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER || input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER) + if(input1_state == LOGIC_ON || input2_state == LOGIC_ON) //continuous signal takes priority in determining what to output + output_state = LOGIC_ON + else + output_state = LOGIC_FLICKER + else //Both inputs were off, so input is off + output_state = LOGIC_OFF + return + +// AND Gate +/obj/machinery/logic_gate/and + name = "AND Gate" + desc = "Outputs ON only when both inputs are ON." + icon_state = "logic_and" + +/obj/machinery/logic_gate/and/handle_logic() + if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) + if(input1_state == LOGIC_ON && input2_state == LOGIC_ON) //only output a continuous signal when both inputs are continuous signals + output_state = LOGIC_ON + else + output_state = LOGIC_FLICKER + else //At least one input was off, so output is off + output_state = LOGIC_OFF + return + +// NAND Gate +/obj/machinery/logic_gate/nand + name = "NAND Gate" + desc = "Outputs OFF only when both inputs are ON." + output_state = LOGIC_ON + icon_state = "logic_nand" + +/obj/machinery/logic_gate/nand/handle_logic() + if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) + output_state = LOGIC_OFF //This can only output continuous signals + else //At least one input was ON/FLICKER, so output is off + output_state = LOGIC_OFF + return + +// NOR Gate +/obj/machinery/logic_gate/nor + name = "NOR Gate" + desc = "Outputs OFF when at least one input is ON." + icon_state = "logic_nor" + output_state = LOGIC_ON + +/obj/machinery/logic_gate/nor/handle_logic() + if(input1_state == LOGIC_OFF ||input2_state == LOGIC_OFF) + output_state = LOGIC_ON //This can only output continuous signals + else //Both inputs are ON, so output is OFF + output_state = LOGIC_OFF + return + +// XOR Gate +/obj/machinery/logic_gate/xor + name = "XOR Gate" + desc = "Outputs ON when only one input is ON." + icon_state = "logic_xor" + +/obj/machinery/logic_gate/xor/handle_logic() + if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) || input2_state == LOGIC_OFF) //Only input1 is ON/FLICKER, so output matches input1 + output_state = input1_state + else if((input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER) || input1_state == LOGIC_OFF) //Only input2 is ON/FLICKER, so output matches input2 + output_state = input2_state + else //Both inputs are ON or OFF, so output is OFF + output_state = LOGIC_OFF + return + +// XNOR Gate +/obj/machinery/logic_gate/xnor + name = "XNOR Gate" + desc = "Outputs ON when both inputs are ON or OFF." + icon_state = "logic_xnor" + output_state = LOGIC_ON + +/obj/machinery/logic_gate/xnor/handle_logic() + if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) //Both inputs are ON/FLICKER + if(input1_state == LOGIC_ON && input2_state == LOGIC_ON) //Only continuous signal when both inputs are ON + output_state = LOGIC_ON + else //If at least one input is FLICKER, output FLICKER + output_state = LOGIC_FLICKER + else if(input1_state == LOGIC_OFF && input2_state == LOGIC_OFF) //Both inputs are OFF + output_state = LOGIC_ON //Always continuous in this case + else //Only one input is ON/FLICKER + output_state = LOGIC_OFF + return diff --git a/code/modules/logic/logic_base.dm b/code/modules/logic/logic_base.dm new file mode 100644 index 00000000000..b126b1af214 --- /dev/null +++ b/code/modules/logic/logic_base.dm @@ -0,0 +1,283 @@ + +/obj/machinery/logic_gate + name = "Logic Base" + desc = "This does nothing except connect to things. Highly illogical, report to a coder at once if you see this in-game." + icon = 'icons/obj/computer3.dmi' + icon_state = "serverframe" + density = 1 + anchored = 1 + + settagwhitelist = list("input1_id_tag", "input2_id_tag", "output_id_tag") + + var/tamperproof = 0 //if set, will make the machine unable to be destroyed, adjusted, etc. via in-game interaction (USE ONLY FOR MAPPING STUFF) + var/mono_input = 0 //if set, will ignore input2 + + var/datum/radio_frequency/radio_connection + var/frequency = 0 + + /* + Some notes on Input/Output: + - Multiple things can be linked to the same input or output tag, just like how wires can connect multiple sources and receivers. + - For inputs, only the last signal received BEFORE a process() call will be used in the logic handling. + - Input states are updated immediately whenever an input signal is received, so it is possible to update multiple times within a single process cycle. + - This means if you have multiple connected inputs, but the last signal received before the process() call is OFF, it won't matter if the others are both ON. + - For this reason, please set up your logic properly. You can theoretically chain these infinitely, so there's no need to link multiple things to a single input. + - For outputs, the signal will attempt to be sent out every process() call, to ensure newly connected things are updated within one process cycle + - Connecting an output to multiple inputs should not cause issues, as long as you don't have multiple connections to a given input (see previous notes on inputs). + - The output state is determined immediately preceeding the signal broadcast, using the input states at the time of the process() call, not when a signal is received. + - Because of how the process cycle works, it is possible that it may take multiple cycles for a signal to fully propogate through a logic chain. + - This is because machines attempt to process in the order they were added to the scheduler. + - Building the logic gates at the end of the chain first may cause delays in signal propogation. + If you take all this into consideration when linking and using logic machinery, you should have no unexpected issues with input/output. Your design flaws are on you though. + */ + + var/input1_id_tag = null + var/input1_state = LOGIC_OFF + var/input2_id_tag = null + var/input2_state = LOGIC_OFF + var/output_id_tag = null + var/output_state = LOGIC_OFF + +/obj/machinery/logic_gate/New() + if(tamperproof) //doing this during New so we don't have to worry about forgetting to set these vars during editting / defining + unacidable = 1 + ..() + if(radio_controller) + set_frequency(frequency) + component_parts = list() + var/obj/item/weapon/circuitboard/logic_gate/LG = new(null) + LG.set_type(type) + component_parts += LG + component_parts += new /obj/item/stack/cable_coil(null, 1) + +/obj/machinery/logic_gate/initialize() + ..() + set_frequency(frequency) + +/obj/machinery/logic_gate/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_LOGIC) + return + +/obj/machinery/logic_gate/Destroy() + if(radio_controller) + radio_controller.remove_object(src,frequency) + return ..() + +/obj/machinery/logic_gate/process() + handle_logic() + handle_output() //All output will send for at least one cycle, and will attempt to send every cycle. Hopefully this won't be too taxing. + return + +/obj/machinery/logic_gate/proc/handle_logic() + return + +/obj/machinery/logic_gate/proc/handle_output() + if(!radio_connection) //can't output without this + return + + if(output_id_tag == null) //Don't output to an undefined id_tag + return + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = output_id_tag, + "sigtype" = "logic", + "state" = output_state, + ) + + radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) + +/obj/machinery/logic_gate/receive_signal(datum/signal/signal, receive_method, receive_param) + if(!signal.data["tag"] || ((signal.data["tag"] != input1_id_tag) && (signal.data["tag"] != input2_id_tag)) || (signal.data["sigtype"] != "logic")) + //If the signal lacks tag data, the signal's tag data doesn't match either input id tag, or is not a "logic" signal, ignore it since it's not for us + return + + if(signal.data["tag"] == input1_id_tag) //If the signal is for input1 + if(signal.data["state"] == input1_state) //If we already match, ignore the new signal since nothing changes + return + if(signal.data["state"] == LOGIC_OFF) //Shut it down and keep it off + input1_state = LOGIC_OFF + return + if(signal.data["state"] == LOGIC_ON) //Turn it on and keep it on + input1_state = LOGIC_ON + return + if(signal.data["state"] == LOGIC_FLICKER) //Turn it on then turn it off + if(input1_state == LOGIC_ON) //An existing continuous ON state overrides new flicker signals + return + input1_state = LOGIC_FLICKER + spawn(LOGIC_FLICKER_TIME) + if(input1_state == LOGIC_FLICKER) //Make sure we didn't get a new continuous signal set while we waited (those take priority) + input1_state = LOGIC_OFF + return + + //Now, you may be wondering why I included those returns. + //The answer is "If you link both inputs to the same source, you're an idiot and deserve to have it break", so yeah. Deal with it. + + if(mono_input) + //We only care about input1, so if we didn't receive a signal for that, we're done. + return + + if(signal.data["tag"] == input2_id_tag) //If the signal is for input2 (reaching this point assumes mono_input is not set) + if(signal.data["state"] == input2_state) //If we already match, ignore the new signal since nothing changes + return + if(signal.data["state"] == LOGIC_OFF) //Shut it down and keep it off + input2_state = LOGIC_OFF + return + if(signal.data["state"] == LOGIC_ON) //Turn it on and keep it on + input2_state = LOGIC_ON + return + if(signal.data["state"] == LOGIC_FLICKER) //Turn it on then turn it off + if(input2_state == LOGIC_ON) //An existing continuous ON state overrides new flicker signals + return + input2_state = LOGIC_FLICKER + spawn(LOGIC_FLICKER_TIME) + if(input2_state == LOGIC_FLICKER) //Make sure we didn't get a new continuous signal set while we waited (those take priority) + input2_state = LOGIC_OFF + return + +/obj/machinery/logic_gate/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) + var/input1_state_string + var/input2_state_string + var/output_state_string + + switch(input1_state) + if(LOGIC_OFF) + input1_state_string = "OFF" + if(LOGIC_ON) + input1_state_string = "ON" + if(LOGIC_FLICKER) + input1_state_string = "FLICKER" + else + input1_state_string = "ERROR: UNKNOWN STATE" + + switch(input2_state) + if(LOGIC_OFF) + input2_state_string = "OFF" + if(LOGIC_ON) + input2_state_string = "ON" + if(LOGIC_FLICKER) + input2_state_string = "FLICKER" + else + input2_state_string = "ERROR: UNKNOWN STATE" + + switch(output_state) + if(LOGIC_OFF) + output_state_string = "OFF" + if(LOGIC_ON) + output_state_string = "ON" + if(LOGIC_FLICKER) + output_state_string = "FLICKER" + else + output_state_string = "ERROR: UNKNOWN STATE" + var/menu_contents = {" +
+
Input: [format_tag("ID Tag","input1_id_tag")]
+
Input State: [input1_state_string]
+ "} + if(!mono_input) + menu_contents = {" +
Input 1: [format_tag("ID Tag","input1_id_tag")]
+
Input 1 State: [input1_state_string]
+
Input 2: [format_tag("ID Tag","input2_id_tag")]
+
Input 2 State: [input2_state_string]
+ "} + menu_contents += {" +
Output: [format_tag("ID Tag","output_id_tag")]
+
Output State: [output_state_string]
+
+ "} + return menu_contents + +/obj/machinery/logic_gate/convert/multitool_topic(var/mob/user,var/list/href_list,var/obj/O) + ..() + update_multitool_menu(user) + +/obj/machinery/logic_gate/attackby(obj/item/O, mob/user, params) + if(tamperproof) + user << "The [src] appears to be tamperproofed! You can't interact with it!" + return 0 + if(istype(O, /obj/item/device/multitool)) + update_multitool_menu(user) + return 1 + if(istype(O, /obj/item/weapon/screwdriver)) + panel_open = !panel_open + user << "You [panel_open ? "open" : "close"] the access panel." + return 1 + if(panel_open && istype(O, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(O) + return 1 + +////////////////////////////////////// +// Attack procs // +////////////////////////////////////// + +/obj/machinery/logic_gate/attack_ai(mob/user) + if(tamperproof) + user << "The [src] appears to be tamperproofed! You can't interface with it!" + return 0 + add_hiddenprint(user) + return ui_interact(user) + +/obj/machinery/logic_gate/attack_ghost(mob/user) + if(tamperproof) + user << "The [src] appears to be tamperproofed! You can't haunt it!" + return 0 + return ui_interact(user) + +/obj/machinery/logic_gate/attack_hand(mob/user) + if(tamperproof) + user << "The [src] appears to be tamperproofed! You can't interact with it!" + return 0 + . = ..() + if(.) + return 0 + return interact(user) + +/obj/machinery/logic_gate/attack_alien(mob/user) //No xeno logic, that's too silly. + user << "The [src] appears to be too complex! You can't comprehend it and back off in fear!" + return 0 + +/obj/machinery/logic_gate/attack_animal(mob/user) //No animal logic either. + user << "The [src] appears to be beyond your comprehension! You can't fathom it!" + return 0 + +/obj/machinery/logic_gate/attack_slime(mob/user) //No slime logic. Seriously. + user << "The [src] appears to be beyond your gelatinous understanding! You ignore it!" + return 0 + +/obj/machinery/logic_gate/emp_act(severity) + if(tamperproof) + return 0 + ..() + +/obj/machinery/logic_gate/ex_act(severity) + if(tamperproof) + return 0 + ..() + +/obj/machinery/logic_gate/blob_act() + if(tamperproof) + return 0 + ..() + +/obj/machinery/logic_gate/singularity_act() + if(tamperproof) + //This is some top-level tamperproofing right here, that's for sure. It can even defy a singularity! + return 0 + ..() + +/obj/machinery/logic_gate/bullet_act() + if(tamperproof) + return 0 + ..() + +/obj/machinery/logic_gate/tesla_act(var/power) + if(tamperproof) + tesla_zap(src, 3, power) //If we're tamperproof, we'll just bounce the full shock of the tesla zap we got hit by, so it continues on normally without diminishing + return 0 + ..() \ No newline at end of file diff --git a/code/modules/logic/mono_input.dm b/code/modules/logic/mono_input.dm new file mode 100644 index 00000000000..58b76232fa0 --- /dev/null +++ b/code/modules/logic/mono_input.dm @@ -0,0 +1,62 @@ + +////////////////////////////////// +// Mono-Input Gates // +////////////////////////////////// + +//NOT Gate +/obj/machinery/logic_gate/not + name = "NOT Gate" + desc = "Accepts one input and outputs the reverse state." + icon_state = "logic_not" + mono_input = 1 //NOT Gates are the simplest logic gate because they only utilize one input. + output_state = LOGIC_ON //Starts with an active output, since the input will be OFF at start +/* + A quick note regarding NOT Gates: + - Connecting multiple things to the input of a NOT Gate can cause weird behaviour due to updating both when it receives a signal and when it calls process(). + - This means it will attempt to output once for every logic machine connected to its input's own process() call. + - It will then attempt to output an additional time based on the current state when it comes to its own process() call. + - For this reason, it is HIGHLY RECOMMENDED that you only connect a single signal source to the input of a NOT Gate to avoid signal spasms. + - Connecting multiple things to the output of a NOT Gate should not cause this unusual behavior. +*/ +/obj/machinery/logic_gate/not/handle_logic() //Our output will always be a continuous signal, even with a FLICKER, it just will update the output when the FLICKER ends + if(input1_state == LOGIC_ON) //Output is OFF while input is ON + output_state = LOGIC_OFF + else if(input1_state == LOGIC_FLICKER) //Output is OFF while input is FLICKER, then output returns to ON when input returns to OFF + output_state = LOGIC_OFF + spawn(LOGIC_FLICKER_TIME + 1) //Call handle_logic again after this delay (the input should update from the spawn(LOGIC_FLICKER_TIME) in receive_signal() by then) + handle_logic() + else //Output is ON while input is OFF + output_state = LOGIC_ON + handle_output() + return + +//STATUS Gate +/obj/machinery/logic_gate/status + name = "Status Gate" + desc = "Accepts one input and outputs the same state, showing a colored light based on current state." + icon_state = "logic_status" + mono_input = 1 //STATUS Gate doesn't actually perform logic operations, but instead acts as a testing conduit. + +/* + STATUS Gates are largely a diagnostics tool, but I'm sure someone will still make a logic gate rave with them anyways. + - There is no need to actually connect an output for these to work, they just need an input to sample from. + - STATUS Gates attempt to update their lights whenever they receive a signal. +*/ + +/obj/machinery/logic_gate/status/receive_signal(datum/signal/signal, receive_method, receive_params) + ..() + handle_logic() //STATUS Gate calls handle_logic() when it receives a signal to update its light and output_state + +/obj/machinery/logic_gate/status/handle_logic() + output_state = input1_state //Output is equal to input, since it is simply a connection with an attached light + if(output_state == LOGIC_OFF) //Red light when OFF + set_light(2,2,"#ff0000") + return + if(output_state == LOGIC_ON) //Green light when ON + set_light(2,2,"#009933") + return + if(output_state == LOGIC_FLICKER) //Orange light when FLICKER, then update after LOGIC_FLICKER_TIME + 1 to reflect the changed state + set_light(2,2,"#ff9900") + spawn(LOGIC_FLICKER_TIME + 1) + handle_logic() + return diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index 355f26af6da..234b23800e6 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -638,4 +638,12 @@ build_type = AUTOLATHE materials = list(MAT_METAL = 150, MAT_GLASS = 125) build_path = /obj/item/weapon/hand_labeler + category = list("initial", "Electronics") + +/datum/design/logic_board + name = "Logic Circuit" + id = "logic_board" + build_type = AUTOLATHE + materials = list(MAT_METAL = 50, MAT_GLASS = 50) + build_path = /obj/item/weapon/circuitboard/logic_gate category = list("initial", "Electronics") \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-4041.yml b/html/changelogs/AutoChangeLog-pr-4041.yml new file mode 100644 index 00000000000..5f208e673c7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4041.yml @@ -0,0 +1,6 @@ +author: FalseIncarnate +delete-after: True +changes: + - rscadd: "Adds logic gates, for doing illogical things in a logical manner." + - rscadd: "Adds buildable light switches, for all your light toggling needs." + - bugfix: "Fixes a resource duplication bug with mass driver buttons." diff --git a/html/changelogs/AutoChangeLog-pr-4075.yml b/html/changelogs/AutoChangeLog-pr-4075.yml new file mode 100644 index 00000000000..bd13595c356 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4075.yml @@ -0,0 +1,5 @@ +author: Fox McCloud +delete-after: True +changes: + - rscadd: "Maps in the slime management console to Xenobio" + - tweak: "Reduces Xenobio monkey box count from 4 to 2" diff --git a/icons/obj/computer3.dmi b/icons/obj/computer3.dmi index 7c87ec36102..30705076d62 100644 Binary files a/icons/obj/computer3.dmi and b/icons/obj/computer3.dmi differ diff --git a/paradise.dme b/paradise.dme index 986b83d97b3..75cdb9919c3 100644 --- a/paradise.dme +++ b/paradise.dme @@ -727,7 +727,7 @@ #include "code\game\objects\items\devices\radio\radio.dm" #include "code\game\objects\items\mountable_frames\air_alarm.dm" #include "code\game\objects\items\mountable_frames\apc_frame.dm" -#include "code\game\objects\items\mountable_frames\driver_button.dm" +#include "code\game\objects\items\mountable_frames\buttons_switches.dm" #include "code\game\objects\items\mountable_frames\fire_alarm.dm" #include "code\game\objects\items\mountable_frames\frames.dm" #include "code\game\objects\items\mountable_frames\intercom.dm" @@ -1319,6 +1319,10 @@ #include "code\modules\lighting\lighting_process.dm" #include "code\modules\lighting\lighting_system.dm" #include "code\modules\lighting\lighting_turf.dm" +#include "code\modules\logic\converter.dm" +#include "code\modules\logic\dual_input.dm" +#include "code\modules\logic\logic_base.dm" +#include "code\modules\logic\mono_input.dm" #include "code\modules\media\jukebox.dm" #include "code\modules\media\machinery.dm" #include "code\modules\media\mediamanager.dm"