Files
wwdpublic/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs
sleepyyapril 67ea5d8c3e Station AI Features and Fixes (Also General Fixes) (#1525)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->

# Description

<!--
Explain this PR in as much detail as applicable

Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->

Check the changelog for the full list.

---

# Changelog

<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

🆑
- add: Added Holopads (unmapped)
- add: Intellicards are now useful for removing/adding a Station AI's
brain.
- add: Added the Communications Console to Station AI actions.
- add: AI now has a warp point.
- add: Added more things for the AI to press.
- add: More AI laws have been added.
- fix: Fixed the mail system
- fix: Fixed AI actions
- fix: Fixed invalid spawns for station AI breaking and ruining your
ability to play it.
- fix: The Station AI's name will now properly send in "arrived to the
station" announcements.
- fix: Changed the CPR sound to simply not loop until fixed.
- fix: Fixed unlocalized messages being sent for the random sentience
event.

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Co-authored-by: Zachary Higgs <compgeek223@gmail.com>
Co-authored-by: MendaxxDev <153332064+MendaxxDev@users.noreply.github.com>
Co-authored-by: chromiumboy <50505512+chromiumboy@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

(cherry picked from commit 3e8a7d9b00e19e160321eb81d69a884189dfa4e6)
2025-01-15 00:12:29 +03:00

110 lines
4.1 KiB
C#

using Content.Server.Chat.Systems;
using Content.Server.Speech;
using Content.Server.Speech.Components;
using Content.Shared.Whitelist;
using Robust.Shared.Player;
using static Content.Server.Chat.Systems.ChatSystem;
namespace Content.Server.SurveillanceCamera;
public sealed class SurveillanceCameraMicrophoneSystem : EntitySystem
{
[Dependency] private readonly SharedTransformSystem _xforms = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SurveillanceCameraMicrophoneComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<SurveillanceCameraMicrophoneComponent, ListenEvent>(RelayEntityMessage);
SubscribeLocalEvent<SurveillanceCameraMicrophoneComponent, ListenAttemptEvent>(CanListen);
SubscribeLocalEvent<ExpandICChatRecipientsEvent>(OnExpandRecipients);
}
private void OnExpandRecipients(ExpandICChatRecipientsEvent ev)
{
var xformQuery = GetEntityQuery<TransformComponent>();
var sourceXform = Transform(ev.Source);
var sourcePos = _xforms.GetWorldPosition(sourceXform, xformQuery);
// This function ensures that chat popups appear on camera views that have connected microphones.
foreach (var (_, __, camera, xform) in EntityQuery<SurveillanceCameraMicrophoneComponent, ActiveListenerComponent, SurveillanceCameraComponent, TransformComponent>())
{
if (camera.ActiveViewers.Count == 0)
continue;
// get range to camera. This way wispers will still appear as obfuscated if they are too far from the camera's microphone
var range = (xform.MapID != sourceXform.MapID)
? -1
: (sourcePos - _xforms.GetWorldPosition(xform, xformQuery)).Length();
if (range < 0 || range > ev.VoiceRange)
continue;
foreach (var viewer in camera.ActiveViewers)
{
// if the player has not already received the chat message, send it to them but don't log it to the chat
// window. This is simply so that it appears in camera.
if (TryComp(viewer, out ActorComponent? actor))
ev.Recipients.TryAdd(actor.PlayerSession, new ICChatRecipientData(range, false, true));
}
}
}
private void OnInit(EntityUid uid, SurveillanceCameraMicrophoneComponent component, ComponentInit args)
{
if (component.Enabled)
EnsureComp<ActiveListenerComponent>(uid).Range = component.Range;
else
RemCompDeferred<ActiveListenerComponent>(uid);
}
public void CanListen(EntityUid uid, SurveillanceCameraMicrophoneComponent microphone, ListenAttemptEvent args)
{
// TODO maybe just make this a part of ActiveListenerComponent?
if (_whitelistSystem.IsBlacklistPass(microphone.Blacklist, args.Source))
args.Cancel();
}
public void RelayEntityMessage(EntityUid uid, SurveillanceCameraMicrophoneComponent component, ListenEvent args)
{
if (!TryComp(uid, out SurveillanceCameraComponent? camera))
return;
var ev = new SurveillanceCameraSpeechSendEvent(args.Source, args.Message);
foreach (var monitor in camera.ActiveMonitors)
{
RaiseLocalEvent(monitor, ev);
}
}
public void SetEnabled(EntityUid uid, bool value, SurveillanceCameraMicrophoneComponent? microphone = null)
{
if (!Resolve(uid, ref microphone))
return;
if (value == microphone.Enabled)
return;
microphone.Enabled = value;
if (value)
EnsureComp<ActiveListenerComponent>(uid).Range = microphone.Range;
else
RemCompDeferred<ActiveListenerComponent>(uid);
}
}
public sealed class SurveillanceCameraSpeechSendEvent : EntityEventArgs
{
public EntityUid Speaker { get; }
public string Message { get; }
public SurveillanceCameraSpeechSendEvent(EntityUid speaker, string message)
{
Speaker = speaker;
Message = message;
}
}