diff --git a/aurorastation.dme b/aurorastation.dme index e21a90788ed..1e134ff5ce5 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1053,6 +1053,7 @@ #include "code\game\objects\items\devices\taperecorder.dm" #include "code\game\objects\items\devices\traitordevices.dm" #include "code\game\objects\items\devices\transfer_valve.dm" +#include "code\game\objects\items\devices\tvcamera.dm" #include "code\game\objects\items\devices\uplink.dm" #include "code\game\objects\items\devices\uplink_random_lists.dm" #include "code\game\objects\items\devices\versebook.dm" diff --git a/code/__DEFINES/machinery.dm b/code/__DEFINES/machinery.dm index 4dd82657e11..2e57c309280 100644 --- a/code/__DEFINES/machinery.dm +++ b/code/__DEFINES/machinery.dm @@ -82,6 +82,7 @@ #define NETWORK_THIRD_DECK "Third Deck" #define NETWORK_INTREPID "Intrepid" #define NETWORK_CANARY "Canary" +#define NETWORK_NEWS "News" // Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them. diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm index 235c2380399..c86ed1cd4e7 100644 --- a/code/game/jobs/job/civilian.dm +++ b/code/game/jobs/job/civilian.dm @@ -238,7 +238,8 @@ messengerbag_faction = /obj/item/storage/backpack/messenger/nt backpack_contents = list( - /obj/item/clothing/accessory/badge/press = 1 + /obj/item/clothing/accessory/badge/press = 1, + /obj/item/device/tvcamera = 1 ) /datum/outfit/job/journalistf @@ -253,7 +254,8 @@ tablet = /obj/item/modular_computer/handheld/preset/civilian/librarian backpack_contents = list( - /obj/item/clothing/accessory/badge/press/independent = 1 + /obj/item/clothing/accessory/badge/press/independent = 1, + /obj/item/device/tvcamera = 1 ) diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index 2608195c214..0e402ce2db2 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -77,6 +77,9 @@ var/global/list/engineering_networks = list( /obj/machinery/camera/network/thunder network = list(NETWORK_THUNDER) +/obj/machinery/camera/network/news + network = list(NETWORK_NEWS) + // EMP /obj/machinery/camera/emp_proof/Initialize() diff --git a/code/game/objects/items/devices/tvcamera.dm b/code/game/objects/items/devices/tvcamera.dm new file mode 100644 index 00000000000..9146459ac83 --- /dev/null +++ b/code/game/objects/items/devices/tvcamera.dm @@ -0,0 +1,151 @@ +/obj/item/device/tvcamera + name = "press camera drone" + desc = "An Ingi Usang Entertainment Co. livestreaming press camera drone. Weapon of choice for war correspondents and reality show cameramen. It does not appear to have any internal memory storage." + icon_state = "camcorder" + item_state = "camcorder" + w_class = ITEMSIZE_LARGE + slot_flags = SLOT_BELT + var/channel = "General News Feed" + var/obj/machinery/camera/network/news/camera + var/obj/item/device/radio/radio + +/obj/item/device/tvcamera/Destroy() + GLOB.listening_objects -= src + QDEL_NULL(camera) + QDEL_NULL(radio) + . = ..() + +/obj/item/device/tvcamera/Initialize() + camera = new(src) + camera.c_tag = channel + camera.status = FALSE + radio = new(src) + radio.get_frequency(FALSE) + radio.set_frequency(ENT_FREQ) + GLOB.listening_objects += src + . = ..() + +/obj/item/device/tvcamera/examine(mob/user) + . = ..() + to_chat(user, "Video feed is currently: [camera.status ? "Online" : "Offline"]") + to_chat(user, "Audio feed is currently: [radio.get_broadcasting() ? "Online" : "Offline"]") + +/obj/item/device/tvcamera/attack_self(mob/user) + add_fingerprint(user) + user.set_machine(src) + var/dat = list() + dat += "Channel name is: [channel ? channel : "unidentified broadcast"]
" + dat += "Video streaming is: [camera.status ? "Online" : "Offline"]
" + dat += "Microphone is: [radio.get_broadcasting() ? "Online" : "Offline"]
" + dat += "Sound is being broadcasted on frequency: [format_frequency(radio.get_frequency())] ([get_frequency_name(radio.get_frequency())])
" + var/datum/browser/popup = new(user, "Press Camera Drone", "EyeBuddy", 300, 390, src) + popup.set_content(jointext(dat,null)) + popup.open() + +/obj/item/device/tvcamera/Topic(bred, href_list, state = physical_state) + if(..()) + return 1 + if(href_list["channel"]) + var/nc = tgui_input_text(usr, "Select new channel name", "Channel Name", channel) + if(nc) + channel = nc + camera.c_tag = channel + to_chat(usr, SPAN_WARNING("New channel name: '[channel]' has been set.")) + if(href_list["video"]) + camera.set_status(!camera.status) + if(camera.status) + balloon_alert(usr, SPAN_NOTICE("Video streaming: Activated. Broadcasting on channel: [channel]")) + playsound(src.loc, 'sound/machines/ping.ogg', 50, 1) + else + balloon_alert(usr, SPAN_NOTICE("Video streaming: Deactivated.")) + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1) + update_icon() + if(href_list["sound"]) + radio.set_broadcasting(!radio.get_broadcasting()) + if(radio.get_broadcasting()) + balloon_alert(usr, SPAN_NOTICE("Audio streaming: Activated. Broadcasting on frequency: [format_frequency(radio.get_frequency())].")) + playsound(src.loc, 'sound/machines/ping.ogg', 50, 1) + else + balloon_alert(usr, SPAN_NOTICE("Audio streaming: Deactivated.")) + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1) + if(!href_list["close"]) + attack_self(usr) + +/obj/item/device/tvcamera/update_icon() + ..() + if(camera.status) + icon_state = "camcorder_on" + item_state = "camcorder_on" + else + icon_state = "camcorder" + item_state = "camcorder" + var/mob/living/carbon/human/H = loc + if(istype(H)) + H.update_inv_r_hand(0) + H.update_inv_l_hand() + +/* Assembly by a roboticist */ +/obj/item/robot_parts/head/attackby(var/obj/item/device/assembly/S, mob/user as mob) + if(!istype(S, /obj/item/device/assembly/infra)) + ..() + return + var/obj/item/tv_assembly/A = new(user) + qdel(S) + user.put_in_hands(A) + to_chat(user, SPAN_NOTICE("You add the infrared sensor to the robot head.")) + qdel(src) + +/* Using camcorder icon as I can't sprite. +Using robohead because of restricting to roboticist */ +/obj/item/tv_assembly + name = "tv camera assembly" + desc = "A robotic head with an infrared sensor inside." + icon = 'icons/obj/robot_parts.dmi' + icon_state = "head" + item_state = "head" + var/buildstep = 0 + w_class = ITEMSIZE_LARGE + +/obj/item/tv_assembly/attackby(var/obj/item/W, var/mob/user) + switch(buildstep) + if(0) + if(istype(W, /obj/item/robot_parts/robot_component/camera)) + to_chat(user, SPAN_NOTICE("You add the camera module to [src].")) + qdel(W) + desc = "This TV camera assembly has a camera module." + buildstep++ + if(1) + if(istype(W, /obj/item/device/taperecorder)) + qdel(W) + buildstep++ + to_chat(user, SPAN_NOTICE("You add the tape recorder to [src].")) + desc = "This TV camera assembly has a camera and audio module." + return + if(2) + if(W.iscoil()) + var/obj/item/stack/cable_coil/C = W + if(!C.use(3)) + to_chat(user, SPAN_NOTICE("You need three cable coils to wire the devices.")) + ..() + return + buildstep++ + to_chat(user, SPAN_NOTICE("You wire the assembly.")) + desc = "This TV camera assembly has wires sticking out." + return + if(3) + if(W.iswirecutter()) + to_chat(user, SPAN_NOTICE("You trim the wires.")) + buildstep++ + desc = "This TV camera assembly needs casing." + return + if(4) + if(istype(W, /obj/item/stack/material/steel)) + var/obj/item/stack/material/steel/S = W + if(S.use(1)) + buildstep++ + to_chat(user, SPAN_NOTICE("You encase the assembly.")) + var/turf/T = get_turf(src) + new /obj/item/device/tvcamera(T) + qdel(src) + return + ..() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/service.dm b/code/game/objects/structures/crates_lockers/closets/secure/service.dm index 633833462ec..69f9e25aadf 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/service.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/service.dm @@ -56,3 +56,20 @@ new /obj/item/clothing/suit/caution(src) new /obj/item/storage/box/lights/mixed(src) new /obj/item/storage/box/mousetraps(src) + +// Journalist's Locker +/obj/structure/closet/secure_closet/journalist + name = "journalist's closet" + desc = "It's a storage unit for a journalist's gear." + req_access = list(ACCESS_JOURNALIST) + +/obj/structure/closet/secure_closet/journalist/fill() + new /obj/item/storage/photo_album(src) + new /obj/item/device/camera_film(src) + new /obj/item/device/camera(src) + new /obj/item/paper_scanner(src) + new /obj/item/folder/white(src) + new /obj/item/storage/secure/briefcase(src) + new /obj/item/clipboard(src) + new /obj/item/folder/red(src) + new /obj/item/device/tvcamera(src) diff --git a/code/modules/modular_computers/file_system/programs/security/camera.dm b/code/modules/modular_computers/file_system/programs/security/camera.dm index 3ac28c56857..bf134b2549c 100644 --- a/code/modules/modular_computers/file_system/programs/security/camera.dm +++ b/code/modules/modular_computers/file_system/programs/security/camera.dm @@ -8,7 +8,7 @@ return switch(network) - if(NETWORK_THUNDER) + if(NETWORK_THUNDER, NETWORK_NEWS) return FALSE if(NETWORK_REACTOR,NETWORK_ENGINEERING,NETWORK_ENGINEERING_OUTPOST,NETWORK_ALARM_ATMOS,NETWORK_ALARM_FIRE,NETWORK_ALARM_POWER) return ACCESS_ENGINE @@ -223,3 +223,21 @@ networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1))) networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1))) return networks + +/datum/computer_file/program/camera_monitor/news + filename = "idcammon" + filedesc = "Journalism Camera Monitoring" + extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements. This version has has a connection to news networks." + size = 6 + nanomodule_path = /datum/nano_module/camera_monitor/news + required_access_download = null + usage_flags = PROGRAM_ALL + +/datum/nano_module/camera_monitor/news + name = "Journalism Camera Monitoring Program" + +/datum/computer_file/program/camera_monitor/news/modify_networks_list(var/list/networks) + networks = list() + networks.Add(list(list("tag" = NETWORK_NEWS, "has_access" = 1))) + networks.Add(list(list("tag" = NETWORK_THUNDER, "has_access" = 1))) + return networks diff --git a/html/changelogs/SimpleMaroon-cameradrone.yml b/html/changelogs/SimpleMaroon-cameradrone.yml new file mode 100644 index 00000000000..d3992c1414d --- /dev/null +++ b/html/changelogs/SimpleMaroon-cameradrone.yml @@ -0,0 +1,43 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: LonelyHowls, SimpleMaroon + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Ports a journalist camera to Aurora! This allows the journalist to broadcast their antics to the wider crew. This item can also be built by machinists." + - rscadd: "Adds a new News network. Currently only used for cameras." + - rscadd: "To properly implement cameras, allows any arbitrary individual to DL the camera application onto their modular computer of choice. Only the News network will be available by default." diff --git a/icons/mob/belt.dmi b/icons/mob/belt.dmi index 882722c1ac0..f2b52800870 100644 Binary files a/icons/mob/belt.dmi and b/icons/mob/belt.dmi differ diff --git a/icons/mob/items/device/lefthand_device.dmi b/icons/mob/items/device/lefthand_device.dmi index a18d90369d3..a143a1d38c1 100644 Binary files a/icons/mob/items/device/lefthand_device.dmi and b/icons/mob/items/device/lefthand_device.dmi differ diff --git a/icons/mob/items/device/righthand_device.dmi b/icons/mob/items/device/righthand_device.dmi index 4bc86f5adc1..777c0de18c3 100644 Binary files a/icons/mob/items/device/righthand_device.dmi and b/icons/mob/items/device/righthand_device.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index f1feebd653a..164424eb7de 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/maps/sccv_horizon/code/sccv_horizon.dm b/maps/sccv_horizon/code/sccv_horizon.dm index b6c6606496b..4a2a3941c87 100644 --- a/maps/sccv_horizon/code/sccv_horizon.dm +++ b/maps/sccv_horizon/code/sccv_horizon.dm @@ -60,7 +60,8 @@ NETWORK_FIRST_DECK, NETWORK_SECOND_DECK, NETWORK_THIRD_DECK, - NETWORK_INTREPID + NETWORK_INTREPID, + NETWORK_NEWS ) shuttle_docked_message = "Attention all hands: the shift change preparations are over. It will start in approximately %ETA%." diff --git a/tgui/packages/tgui/interfaces/CameraMonitoring.tsx b/tgui/packages/tgui/interfaces/CameraMonitoring.tsx index 460b16de42b..5ad1beb83c0 100644 --- a/tgui/packages/tgui/interfaces/CameraMonitoring.tsx +++ b/tgui/packages/tgui/interfaces/CameraMonitoring.tsx @@ -94,24 +94,28 @@ export const ShowNetworkCameras = (props, context) => { value={searchTerm} /> }> - {data.cameras - .filter( - (c) => c.name?.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1 - ) - .map((camera) => ( -