diff --git a/code/controllers/subsystem/sounds.dm b/code/controllers/subsystem/sounds.dm index 7dc4c0624ce5..4e05d0f1e637 100644 --- a/code/controllers/subsystem/sounds.dm +++ b/code/controllers/subsystem/sounds.dm @@ -144,7 +144,8 @@ SUBSYSTEM_DEF(sounds) PRIVATE_PROC(TRUE) using_channels_by_datum -= D - UnregisterSignal(D, COMSIG_PARENT_QDELETING) + if(D != DATUMLESS) + UnregisterSignal(D, COMSIG_PARENT_QDELETING) /// Handles a tracked datum being deleted, automatically freeing the channels. /datum/controller/subsystem/sounds/proc/tracked_datum_deleted(datum/source) diff --git a/code/datums/sound_token.dm b/code/datums/sound_token.dm index e00c562dd791..b54132560de1 100644 --- a/code/datums/sound_token.dm +++ b/code/datums/sound_token.dm @@ -93,7 +93,7 @@ var/is_muted = listeners[M] & SOUND_MUTE var/should_be_muted = FALSE - if(!source_turf || !listener_turf) + if(!(source_turf && listener_turf) || source_turf.z != listener_turf.z) should_be_muted = TRUE if(should_be_muted && is_muted) return diff --git a/code/modules/flockmind/actions/narrowbeam_transmission.dm b/code/modules/flockmind/actions/narrowbeam_transmission.dm new file mode 100644 index 000000000000..c7bc8a742e23 --- /dev/null +++ b/code/modules/flockmind/actions/narrowbeam_transmission.dm @@ -0,0 +1,64 @@ +/datum/action/cooldown/flock/radio_talk + name = "Narrowbeam Transmission" + desc = "Hijack a radio headset of a target to broadcast a message." + button_icon_state = "talk" + cooldown_time = 2 SECONDS + click_to_activate = TRUE + +/datum/action/cooldown/flock/radio_talk/Activate(atom/target) + var/obj/item/radio/radio_target + + if(!ishuman(target) && !istype(target, /obj/item/radio)) + to_chat(owner, span_warning("[target] is not a valid target.")) + return FALSE + + if(istype(target, /obj/item/radio)) + radio_target = target + if(!radio_target.get_listening()) + to_chat(owner, span_warning("[target] is not turned on.")) + return FALSE + + if(radio_target.canhear_range == -1) + to_chat(owner, span_warning("[target] is not a valid target.")) + return FALSE + + if(ishuman(target)) + var/mob/living/carbon/human/schmuck = target + for(var/obj/item/I in schmuck.get_contents()) + if(istype(I, /obj/item/radio)) + radio_target = I + break + + if(!istype(radio_target) || !radio_target.get_listening() || radio_target.canhear_range == -1) + to_chat(owner, span_warning("[target] does not have a working radio.")) + return FALSE + + var/msg = uppertext(tgui_input_text(usr, "What do you wish to broadcast?", "Narrowbeam Transmission", "")) + if(!msg) + return FALSE + + . = ..() + + playsound(get_turf(radio_target), pick('goon/sounds/radio_sweep1.ogg','goon/sounds/radio_sweep2.ogg','goon/sounds/radio_sweep3.ogg','goon/sounds/radio_sweep4.ogg','goon/sounds/radio_sweep5.ogg'), 20, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + to_chat(owner, span_notice("You transmit a message through [radio_target].")) + + if(radio_target == target) + msg = Gibberish(msg, 70, 50) + + var/atom/movable/virtualspeaker/speaker = new(null, null) + speaker.name = "Unknown" + + var/rendered = speaker.compose_message(speaker, GET_LANGUAGE_DATUM(/datum/language/common), msg, FREQ_COMMON, list("flocksay", SPAN_ITALICS), list()) + + for(var/atom/movable/hearer in get_hearers_in_LOS(radio_target.canhear_range, radio_target)) + hearer.Hear( + rendered, + speaker, + GET_LANGUAGE_DATUM(/datum/language/common), + msg, + FREQ_COMMON, + list("flocksay", SPAN_ITALICS), // spans + list(), // message mods + sound_loc = radio_target.speaker_location(), + message_range = INFINITY + ) diff --git a/code/modules/flockmind/actions/radio_blast.dm b/code/modules/flockmind/actions/radio_blast.dm index 386253819e13..7fcfb5f59b0f 100644 --- a/code/modules/flockmind/actions/radio_blast.dm +++ b/code/modules/flockmind/actions/radio_blast.dm @@ -31,7 +31,7 @@ for(var/mob/living/carbon/human/guy as anything in targets) to_chat(guy, span_alert("Horrifying static bursts into your headset, disorienting you severely!")) - playsound(guy, "sound/effects/radio_sweep[rand(1,5)].ogg", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(guy, pick('goon/sounds/radio_sweep1.ogg','goon/sounds/radio_sweep2.ogg','goon/sounds/radio_sweep3.ogg','goon/sounds/radio_sweep4.ogg','goon/sounds/radio_sweep5.ogg'), 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) guy.Knockdown(3 SECONDS) guy.set_confusion_if_lower(20 SECONDS) guy.do_jitter_animation(10) diff --git a/code/modules/flockmind/ai_behaviors/flock_wander.dm b/code/modules/flockmind/ai_behaviors/flock_wander.dm index b39d65577665..9dc2d351a04b 100644 --- a/code/modules/flockmind/ai_behaviors/flock_wander.dm +++ b/code/modules/flockmind/ai_behaviors/flock_wander.dm @@ -61,6 +61,11 @@ . = ..() controller.set_blackboard_key(BB_PATH_MAX_LENGTH, 4) +/datum/ai_behavior/move_to_target/flock_wander/perform(delta_time, datum/ai_controller/controller) + . = ..() + var/mob/living/simple_animal/flock/drone/bird = controller.pawn + bird.set_task_desc("wandering") + /datum/ai_behavior/move_to_target/flock_wander/finish_action(datum/ai_controller/controller, succeeded, ...) . = ..() controller.clear_blackboard_key(BB_FLOCK_WANDER_FRUSTRATION) diff --git a/code/modules/flockmind/flock_camera/_flock_camera.dm b/code/modules/flockmind/flock_camera/_flock_camera.dm index 99bf5b0607b6..1432873012df 100644 --- a/code/modules/flockmind/flock_camera/_flock_camera.dm +++ b/code/modules/flockmind/flock_camera/_flock_camera.dm @@ -22,6 +22,9 @@ move_on_shuttle = FALSE movement_type = PHASING + chat_color = "#6fbbac" + chat_color_darkened = "#6fbbac" + var/datum/flock/flock var/list/actions_to_grant = list() diff --git a/code/modules/flockmind/flock_camera/flock_overmind.dm b/code/modules/flockmind/flock_camera/flock_overmind.dm index 3bcc3e657d78..d0e170866483 100644 --- a/code/modules/flockmind/flock_camera/flock_overmind.dm +++ b/code/modules/flockmind/flock_camera/flock_overmind.dm @@ -24,6 +24,7 @@ /datum/action/cooldown/flock/ping, /datum/action/cooldown/flock/radio_blast, /datum/action/cooldown/flock/gatecrash, + /datum/action/cooldown/flock/radio_talk ) /mob/camera/flock/overmind/Initialize(mapload, join_flock) diff --git a/code/modules/flockmind/flock_controller/_flock_controller.dm b/code/modules/flockmind/flock_controller/_flock_controller.dm index b9d8d5f62a15..39e171767a7b 100644 --- a/code/modules/flockmind/flock_controller/_flock_controller.dm +++ b/code/modules/flockmind/flock_controller/_flock_controller.dm @@ -409,7 +409,7 @@ /// Pings a location, alerting all flocktraces. /datum/flock/proc/ping(turf/T, mob/camera/flock/pinger) var/message = "System interrupt. Designating new target: [T] in [get_area(T)]." - flock_talk(pinger, message, src, TRUE, list("italics")) + flock_talk(pinger, message, src, TRUE, list("italics"), runechat = FALSE) T.AddComponent(/datum/component/flock_ping, 5 SECONDS) for(var/mob/camera/flock/ghost_bird in (traces + overmind)) diff --git a/code/modules/flockmind/flock_mob/flock_mob.dm b/code/modules/flockmind/flock_mob/flock_mob.dm index 29b2f331a7c4..8d8d81e48a55 100644 --- a/code/modules/flockmind/flock_mob/flock_mob.dm +++ b/code/modules/flockmind/flock_mob/flock_mob.dm @@ -116,7 +116,7 @@ language = GET_LANGUAGE_DATUM(language) || get_selected_language() if(flock && istype(language, /datum/language/flock)) - flock_talk(src, message, flock, forced) + flock_talk(src, message, flock, forced, runechat = FALSE) // changing the default arg value here /mob/living/simple_animal/flock/treat_message(message, correct_grammar = FALSE) diff --git a/code/modules/flockmind/flock_say.dm b/code/modules/flockmind/flock_say.dm index ae4d618d2c81..0cf681edd1dd 100644 --- a/code/modules/flockmind/flock_say.dm +++ b/code/modules/flockmind/flock_say.dm @@ -34,14 +34,17 @@ avoid_highlighting = speaker == src ) -/proc/flock_talk(atom/speaker, message, datum/flock/flock, involuntary, list/inner_spans) +/proc/flock_talk(atom/speaker, raw_message, datum/flock/flock, involuntary, list/inner_spans, runechat = TRUE) - message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)) - if (!message) + raw_message = trim(copytext_char(sanitize(raw_message), 1, MAX_MESSAGE_LEN)) + if (!raw_message) return + var/message = raw_message + var/silicon_message = stars(raw_message, 50) if(inner_spans) message = attach_spans(message, inner_spans) + silicon_message = attach_spans(silicon_message, inner_spans) var/used_name = "" var/list/spans = list("flocksay") @@ -80,7 +83,6 @@ var/mob/camera/flock/overmind/ghost_bird = speaker used_name = ghost_bird.real_name - var/silicon_message = stars(message, 50) if(mob_speaker) var/say_verb = pick("sings", "clicks", "whistles", "intones", "transmits", "submits", "uploads") message = "[say_verb], \"[message]\"" @@ -95,12 +97,17 @@ for(var/mob/player as anything in GLOB.player_list) if(isflockmob(player)) to_chat(player, flock_message) + if(speaker && runechat && (mob_speaker ? player.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat) : player.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat_non_mobs))) + player.create_chat_message(speaker, GET_LANGUAGE_DATUM(/datum/language/flock), raw_message) continue if(isobserver(player) && !involuntary) to_chat(player, flock_message) + if(speaker && runechat && (mob_speaker ? player.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat) : player.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat_non_mobs))) + player.create_chat_message(speaker, GET_LANGUAGE_DATUM(/datum/language/flock), raw_message) continue + // Snooping in-round mobs don't get the runechat. if(player.can_hear() && player.binarycheck() && (!involuntary && speaker || prob(30))) to_chat(player, silicon_message) continue diff --git a/daedalus.dme b/daedalus.dme index e739399c5fd0..795a2f60b01e 100644 --- a/daedalus.dme +++ b/daedalus.dme @@ -3196,6 +3196,7 @@ #include "code\modules\flockmind\actions\diffract_drone.dm" #include "code\modules\flockmind\actions\gatecrash.dm" #include "code\modules\flockmind\actions\heal.dm" +#include "code\modules\flockmind\actions\narrowbeam_transmission.dm" #include "code\modules\flockmind\actions\nest.dm" #include "code\modules\flockmind\actions\partition_mind.dm" #include "code\modules\flockmind\actions\ping.dm"