using Content.Server.Popups; using Content.Shared.Abilities.Mime; using Content.Shared.Actions; using Content.Shared.Actions.Events; using Content.Shared.Alert; using Content.Shared.Coordinates.Helpers; using Content.Shared.Maps; using Content.Shared.Paper; using Content.Shared.Physics; using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Timing; using Content.Shared.Speech.Muting; namespace Content.Server.Abilities.Mime { public sealed class MimePowersSystem : EntitySystem { [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] private readonly AlertsSystem _alertsSystem = default!; [Dependency] private readonly TurfSystem _turf = default!; [Dependency] private readonly IMapManager _mapMan = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly IGameTiming _timing = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(OnInvisibleWall); SubscribeLocalEvent(OnBreakVowAlert); SubscribeLocalEvent(OnRetakeVowAlert); } public override void Update(float frameTime) { base.Update(frameTime); // Queue to track whether mimes can retake vows yet var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var mime)) { if (!mime.VowBroken || mime.ReadyToRepent) continue; if (_timing.CurTime < mime.VowRepentTime) continue; mime.ReadyToRepent = true; _popupSystem.PopupEntity(Loc.GetString("mime-ready-to-repent"), uid, uid); } } private void OnComponentInit(EntityUid uid, MimePowersComponent component, ComponentInit args) { EnsureComp(uid); if (component.PreventWriting) { EnsureComp(uid, out var illiterateComponent); illiterateComponent.FailWriteMessage = component.FailWriteMessage; Dirty(uid, illiterateComponent); } _alertsSystem.ShowAlert(uid, component.VowAlert); _actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid); } /// /// Creates an invisible wall in a free space after some checks. /// private void OnInvisibleWall(EntityUid uid, MimePowersComponent component, InvisibleWallActionEvent args) { if (!component.Enabled) return; if (_container.IsEntityOrParentInContainer(uid)) return; var xform = Transform(uid); // Get the tile in front of the mime var offsetValue = xform.LocalRotation.ToWorldVec(); var coords = xform.Coordinates.Offset(offsetValue).SnapToGrid(EntityManager, _mapMan); var tile = coords.GetTileRef(EntityManager, _mapMan); if (tile == null) return; // Check if the tile is blocked by a wall or mob, and don't create the wall if so if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable | CollisionGroup.Opaque)) { _popupSystem.PopupEntity(Loc.GetString("mime-invisible-wall-failed"), uid, uid); return; } _popupSystem.PopupEntity(Loc.GetString("mime-invisible-wall-popup", ("mime", uid)), uid); // Make sure we set the invisible wall to despawn properly Spawn(component.WallPrototype, _turf.GetTileCenter(tile.Value)); // Handle args so cooldown works args.Handled = true; } private void OnBreakVowAlert(Entity ent, ref BreakVowAlertEvent args) { if (args.Handled) return; BreakVow(ent, ent); args.Handled = true; } private void OnRetakeVowAlert(Entity ent, ref RetakeVowAlertEvent args) { if (args.Handled) return; RetakeVow(ent, ent); args.Handled = true; } /// /// Break this mime's vow to not speak. /// public void BreakVow(EntityUid uid, MimePowersComponent? mimePowers = null) { if (!Resolve(uid, ref mimePowers)) return; if (mimePowers.VowBroken) return; mimePowers.Enabled = false; mimePowers.VowBroken = true; mimePowers.VowRepentTime = _timing.CurTime + mimePowers.VowCooldown; RemComp(uid); if (mimePowers.PreventWriting) RemComp(uid); _alertsSystem.ClearAlert(uid, mimePowers.VowAlert); _alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert); _actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity); } /// /// Retake this mime's vow to not speak. /// public void RetakeVow(EntityUid uid, MimePowersComponent? mimePowers = null) { if (!Resolve(uid, ref mimePowers)) return; if (!mimePowers.ReadyToRepent) { _popupSystem.PopupEntity(Loc.GetString("mime-not-ready-repent"), uid, uid); return; } mimePowers.Enabled = true; mimePowers.ReadyToRepent = false; mimePowers.VowBroken = false; AddComp(uid); if (mimePowers.PreventWriting) { EnsureComp(uid, out var illiterateComponent); illiterateComponent.FailWriteMessage = mimePowers.FailWriteMessage; Dirty(uid, illiterateComponent); } _alertsSystem.ClearAlert(uid, mimePowers.VowBrokenAlert); _alertsSystem.ShowAlert(uid, mimePowers.VowAlert); _actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid); } } }