diff --git a/_maps/map_files/TgStation/tgstation.2.1.3.dmm b/_maps/map_files/TgStation/tgstation.2.1.3.dmm index 3299ce24c7d..d77e656a08c 100644 --- a/_maps/map_files/TgStation/tgstation.2.1.3.dmm +++ b/_maps/map_files/TgStation/tgstation.2.1.3.dmm @@ -6262,7 +6262,7 @@ "cqv" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/area/aisat) "cqw" = (/obj/machinery/door/airlock/hatch{name = "Teleporter Room"; req_access_txt = "17;65"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/aisat) "cqx" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/wall/r_wall,/area/tcommsat/computer) -"cqy" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/components/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 0; scrub_Toxins = 0},/turf/simulated/floor/plasteel,/area/tcommsat/computer) +"cqy" = (/obj/machinery/light{dir = 1},/obj/machinery/atmospherics/components/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 0; scrub_Toxins = 0},/obj/machinery/announcement_system,/turf/simulated/floor/plasteel,/area/tcommsat/computer) "cqz" = (/obj/structure/closet/crate/freezer,/obj/item/weapon/reagent_containers/blood/empty,/obj/item/weapon/reagent_containers/blood/empty{pixel_x = -3; pixel_y = -3},/obj/item/weapon/reagent_containers/blood/AMinus,/obj/item/weapon/reagent_containers/blood/BMinus{pixel_x = -4; pixel_y = 4},/obj/item/weapon/reagent_containers/blood/BPlus{pixel_x = 1; pixel_y = 2},/obj/item/weapon/reagent_containers/blood/OMinus,/obj/item/weapon/reagent_containers/blood/OPlus{pixel_x = -2; pixel_y = -1},/obj/item/weapon/reagent_containers/blood/random,/obj/item/weapon/reagent_containers/blood/random,/obj/item/weapon/reagent_containers/blood/random,/obj/machinery/atmospherics/components/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 0; scrub_Toxins = 0},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/virology) "cqA" = (/obj/machinery/camera/emp_proof{c_tag = "Singularity West"; dir = 1; network = list("Singularity")},/turf/simulated/floor/plating/airless,/area/engine/engineering) "cqB" = (/obj/machinery/camera/emp_proof{c_tag = "Singularity East"; dir = 1; network = list("Singularity")},/turf/simulated/floor/plating/airless,/area/engine/engineering) @@ -6587,7 +6587,7 @@ "cwI" = (/obj/structure/table,/obj/item/weapon/paper_bin{pixel_x = -3; pixel_y = 7},/obj/item/weapon/pen,/turf/simulated/floor/plasteel{icon_state = "showroomfloor"},/area/security/brig) "cwJ" = (/obj/machinery/camera{c_tag = "Brig Evidence Storage"; dir = 1},/obj/machinery/light,/obj/structure/table,/obj/item/weapon/hand_labeler,/turf/simulated/floor/plasteel{icon_state = "showroomfloor"},/area/security/brig) "cwK" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'RADIOACTIVE AREA'"; icon_state = "radiation"; name = "RADIOACTIVE AREA"; pixel_x = 0; pixel_y = 0},/turf/simulated/wall,/area/engine/engineering) - + (1,1,1) = {" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/code/controllers/subsystem/jobs.dm b/code/controllers/subsystem/jobs.dm index 5d6c83b8206..e3d1114edbf 100644 --- a/code/controllers/subsystem/jobs.dm +++ b/code/controllers/subsystem/jobs.dm @@ -390,6 +390,7 @@ var/datum/subsystem/job/SSjob else //We ran out of spare locker spawns! break + /datum/subsystem/job/proc/LoadJobs(jobsfile) //ran during round setup, reads info from jobs.txt -- Urist if(!config.load_jobs_from_txt) return 0 diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index e6b7500a866..3b453e491cc 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -302,4 +302,4 @@ text += "
" world << text - return 1 \ No newline at end of file + return 1 diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm index 3d97869a1ca..2af85ca36ba 100644 --- a/code/game/jobs/job/captain.dm +++ b/code/game/jobs/job/captain.dm @@ -89,3 +89,5 @@ Head of Personnel //Equip ID box & telebaton H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/ids(H.back), slot_in_backpack) H.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(H), slot_in_backpack) + + announce_head(H.mind, list("Supply", "Service")) //tell underlings (suuply/service) they have a head diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm index e686d1e9593..fa8f10f9eff 100644 --- a/code/game/jobs/job/engineering.dm +++ b/code/game/jobs/job/engineering.dm @@ -41,6 +41,8 @@ Chief Engineer //Equip telebaton H.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(H), slot_in_backpack) + announce_head(H.mind, list("Engineering")) //tell underlings (engineering radio) they have a head + /* Station Engineer */ diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index e77878cd7f0..fe7638427f8 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -167,4 +167,10 @@ return max(0, minimal_player_age - C.player_age) /datum/job/proc/config_check() - return 1 \ No newline at end of file + return 1 + +/datum/job/proc/announce_head(var/datum/mind/o_mind, var/channels) //tells the given channel that the given mind is the new department head. See communications.dm for valid channels. + spawn(4) //to allow some initialization + if(announcement_systems.len) + var/obj/machinery/announcement_system/announcer = pick(announcement_systems) + announcer.announce("NEWHEAD", o_mind.name, o_mind.assigned_role, channels) diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm index 083aedb3ac2..7485f8442ca 100644 --- a/code/game/jobs/job/medical.dm +++ b/code/game/jobs/job/medical.dm @@ -35,6 +35,8 @@ Chief Medical Officer H.equip_to_slot_or_del(new /obj/item/device/flashlight/pen(H), slot_s_store) H.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(H), slot_in_backpack) + announce_head(H.mind, list("Medical")) //tell underlings (medical radio) they have a head + /* Medical Doctor */ diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm index 518813f2990..9f571c85ea2 100644 --- a/code/game/jobs/job/science.dm +++ b/code/game/jobs/job/science.dm @@ -37,6 +37,8 @@ Research Director H.equip_to_slot_or_del(new /obj/item/device/laser_pointer(H), slot_l_store) H.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(H), slot_in_backpack) + announce_head(H.mind, list("Science")) //tell underlings (science radio) they have a head + /* Scientist */ diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index 9adfaef00ca..2d8bdefcbde 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -52,6 +52,8 @@ Head of Security L.implanted = 1 H.sec_hud_set_implants() + announce_head(H.mind, list("Security")) //tell underlings (security radio) they have a head + /* Warden */ diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm new file mode 100644 index 00000000000..e69df9c883c --- /dev/null +++ b/code/game/machinery/announcement_system.dm @@ -0,0 +1,196 @@ +var/list/announcement_systems = list() + +/obj/machinery/announcement_system + density = 1 + anchored = 1 + name = "\improper Automated Announcement System" + desc = "An automated announcement system that handles minor announcements over the radio." + icon = 'icons/obj/machines/telecomms.dmi' + icon_state = "AAS_On" + var/obj/item/device/radio/headset/radio + + verb_say = "coldly states" + verb_ask = "queries" + verb_exclaim = "alarms" + + var/broken = 0 + + idle_power_usage = 20 + active_power_usage = 50 + + var/arrival = "%PERSON has signed up as %RANK" + var/arrivalToggle = 1 + var/newhead = "%PERSON, %RANK, is the department head." + var/newheadToggle = 1 + + var/greenlight = "Light_Green" + var/pinklight = "Light_Pink" + var/errorlight = "Error_Red" + +/obj/machinery/announcement_system/New() + ..() + announcement_systems += src + radio = new /obj/item/device/radio/headset/ai(src) + + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/announcement_system(null) + component_parts += new /obj/item/stack/cable_coil(null, 2) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + RefreshParts() + + update_icon() + +/obj/machinery/announcement_system/update_icon() + if(is_operational()) + icon_state = (panel_open ? "AAS_On_Open" : "AAS_On") + else + icon_state = (panel_open ? "AAS_Off_Open" : "AAS_Off") + + + overlays.Cut() + if(arrivalToggle) + overlays |= greenlight + else + overlays -= greenlight + + if(newheadToggle) + overlays |= pinklight + else + overlays -= pinklight + + if(broken) + overlays |= errorlight + else + overlays -= errorlight + +/obj/machinery/announcement_system/Destroy() + announcement_systems -= src //"OH GOD WHY ARE THERE 100,000 LISTED ANNOUNCEMENT SYSTEMS?!!" + +/obj/machinery/announcement_system/power_change() + ..() + update_icon() + +/obj/machinery/announcement_system/attackby(obj/item/P, mob/user, params) + if(istype(P, /obj/item/weapon/screwdriver)) + if(!panel_open) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + user << "You open the maintenance hatch of [src]." + panel_open = 1 + else + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + user << "You close the maintenance hatch of [src]." + panel_open = 0 + update_icon() + return + + if(panel_open) + default_deconstruction_crowbar(P) + if(istype(P, /obj/item/device/multitool) && broken) + user << "You reset [src]'s firmware." + broken = 0 + update_icon() + +/obj/machinery/announcement_system/attack_hand(mob/user) + if(can_be_used_by(user)) + Interact(user) + +/obj/machinery/announcement_system/proc/CompileText(str, user, rank) //replaces user-given variables with actual thingies. + str = replacetext(str, "%PERSON", "[user]") + str = replacetext(str, "%RANK", "[rank]") + return str + +/obj/machinery/announcement_system/proc/announce(message_type, user, rank, list/channels) + if(!is_operational()) + return + + var/message + + if(message_type == "ARRIVAL" && arrivalToggle) + message = CompileText(arrival, user, rank) + + else if(message_type == "NEWHEAD" && newheadToggle) + message = CompileText(newhead, user, rank) + + if(channels.len == 0) + radio.talk_into(src, message, null, list(SPAN_ROBOT)) + else + for(var/channel in channels) + radio.talk_into(src, message, channel, list(SPAN_ROBOT)) + +//config stuff + +/obj/machinery/announcement_system/proc/Interact(mob/user) + if(!can_be_used_by(user)) + return + + if(broken) + visible_message("[src] buzzes.", "You hear a faint buzz.") + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1) + return + + + var/contents = "Arrival Announcement: ([(arrivalToggle ? "On" : "Off")])
\n[arrival]

\n" + contents += "Departmental Head Announcement: ([(newheadToggle ? "On" : "Off")])
\n[newhead]

\n" + + var/datum/browser/popup = new(user, "announcement_config", "Automated Announcement Configuration", 370, 220) + popup.set_content(contents) + popup.open() + +/obj/machinery/announcement_system/Topic(href, href_list) + if(!can_be_used_by(usr) || usr.lying || usr.stat || usr.stunned) + return + if(broken) + visible_message("[src] buzzes.", "You hear a faint buzz.") + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1) + return + + if(href_list["ArrivalTopic"]) + var/NewMessage = stripped_input(usr, "Enter in the arrivals announcement configuration.", "Arrivals Announcement Config", arrival) + if(!in_range(src, usr) && src.loc != usr && !isAI(usr)) + return + if(NewMessage) + arrival = NewMessage + else if(href_list["NewheadTopic"]) + var/NewMessage = stripped_input(usr, "Enter in the departmental head announcement configuration.", "Head Departmental Announcement Config", newhead) + if(!in_range(src, usr) && src.loc != usr && !isAI(usr)) + return + if(NewMessage) + newhead = NewMessage + + else if(href_list["NewheadT-Topic"]) + newheadToggle = !newheadToggle + update_icon() + else if(href_list["ArrivalT-Topic"]) + arrivalToggle = !arrivalToggle + update_icon() + + add_fingerprint(usr) + Interact(usr) + return + +/obj/machinery/announcement_system/attack_ai(mob/living/silicon/ai/user) + if(!isAI(user)) + return + if(broken) + user << "[src]'s firmware appears to be malfunctioning!" + return + Interact(user) + +/obj/machinery/announcement_system/proc/act_up() //does funny breakage stuff + broken = 1 + update_icon() + + arrival = pick("#!@%ERR-34%2 CANNOT LOCAT@# JO# F*LE!", "CRITICAL ERROR 99.", "ERR)#: DA#AB@#E NOT F(*ND!") + newhead = pick("OV#RL()D: \[UNKNOWN??\] DET*#CT)D!", "ER)#R - B*@ TEXT F*O(ND!", "AAS.exe is not responding. NanoOS is searching for a solution to the problem.") + +/obj/machinery/announcement_system/emp_act(severity) + if(stat & (NOPOWER|BROKEN)) + ..(severity) + return + act_up() + ..(severity) + +/obj/machinery/announcement_system/emag_act() + ..() + emagged = 1 + act_up() \ No newline at end of file diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index d351c5f7ec4..4288620d25e 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -254,6 +254,15 @@ to destroy them and players will be able to make replacements. user << "You set the board to [names_paths[build_path]]." req_components = list(text2path("/obj/item/weapon/vending_refill/[copytext("[build_path]", 24)]") = 3) //Never before has i used a method as horrible as this one, im so sorry +/obj/item/weapon/circuitboard/announcement_system + name = "circuit board (Announcement System)" + build_path = /obj/machinery/announcement_system + board_type = "machine" + origin_tech = "programming=3;bluespace=2" + req_components = list( + /obj/item/stack/cable_coil = 2, + /obj/item/weapon/stock_parts/console_screen = 1) + /obj/item/weapon/circuitboard/smes name = "circuit board (SMES)" build_path = /obj/machinery/power/smes diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 0b5158f6085..2b4776c12b7 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -300,14 +300,11 @@ /mob/new_player/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank) if (ticker.current_state == GAME_STATE_PLAYING) - var/ailist[] = list() - for (var/mob/living/silicon/ai/A in living_mob_list) - ailist += A - if (ailist.len) - var/mob/living/silicon/ai/announcer = pick(ailist) + if(announcement_systems.len) if(character.mind) if((character.mind.assigned_role != "Cyborg") && (character.mind.assigned_role != character.mind.special_role)) - announcer.say("[announcer.radiomod] [character.real_name] has signed up as [rank].") + var/obj/machinery/announcement_system/announcer = pick(announcement_systems) + announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common /mob/new_player/proc/LateChoices() var/mills = world.time // 1/10 of a second, not real milliseconds but whatever diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 8c0cfe30ea1..75202c87387 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -12,6 +12,16 @@ build_path = /obj/item/weapon/circuitboard/smes category = list ("Engineering Machinery") +/datum/design/announcement_system + name = "Machine Design (Automated Announcement System Board)" + desc = "The circuit board for an automated announcement system." + id = "automated_announcement" + req_tech = list("programming" = 3, "bluespace" = 2) + build_type = IMPRINTER + materials = list(MAT_GLASS = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/announcement_system + category = list("Subspace Telecomms") + /datum/design/turbine_computer name = "Computer Design (Power Turbine Console Board)" desc = "The circuit board for a power turbine console." diff --git a/html/changelogs/Chiefwaffles-Obsolete_AI_2016.yml b/html/changelogs/Chiefwaffles-Obsolete_AI_2016.yml new file mode 100644 index 00000000000..3a38249e8bb --- /dev/null +++ b/html/changelogs/Chiefwaffles-Obsolete_AI_2016.yml @@ -0,0 +1,8 @@ +author: Chiefwaffles + +delete-after: True + +changes: + - rscadd: "After realizing how often AIs tend to 'disappear', Central Command has authorized the shipment of the Automated Announcement System to take over the AI's responsibility of announcing new arrivals." + - rscadd: "In addition, users are able to configure the messages to their liking. Early testing has shown that this feature may be vulnerable to malicious external elements!" + - rscadd: "The station's R&D software has been updated so it can now succesfully create its own prototype AAS board once the prerequisite levels have been met." diff --git a/icons/obj/machines/telecomms.dmi b/icons/obj/machines/telecomms.dmi index f47fcc63f87..7f5f05e3aff 100644 Binary files a/icons/obj/machines/telecomms.dmi and b/icons/obj/machines/telecomms.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 56abaadb801..3aeb99ee87f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -381,6 +381,7 @@ #include "code\game\machinery\ai_slipper.dm" #include "code\game\machinery\airlock_control.dm" #include "code\game\machinery\alarm.dm" +#include "code\game\machinery\announcement_system.dm" #include "code\game\machinery\atmo_control.dm" #include "code\game\machinery\autolathe.dm" #include "code\game\machinery\Beacon.dm"