@@ -1,50 +1,24 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.CombatMode.Pacification;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a Pacified entity attempts to throw something.
|
||||
/// The throw is only permitted if this event is not cancelled.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public struct AttemptPacifiedThrowEvent
|
||||
{
|
||||
public EntityUid ItemUid;
|
||||
public EntityUid PlayerUid;
|
||||
|
||||
public AttemptPacifiedThrowEvent(EntityUid itemUid, EntityUid playerUid)
|
||||
{
|
||||
ItemUid = itemUid;
|
||||
PlayerUid = playerUid;
|
||||
}
|
||||
|
||||
public bool Cancelled { get; private set; } = false;
|
||||
public string? CancelReasonMessageId { get; private set; }
|
||||
|
||||
/// <param name="reasonMessageId">
|
||||
/// Localization string ID for the reason this event has been cancelled.
|
||||
/// If null, a generic message will be shown to the player.
|
||||
/// Note that any supplied localization string MUST accept a '$projectile'
|
||||
/// parameter specifying the name of the thrown entity.
|
||||
/// </param>
|
||||
public void Cancel(string? reasonMessageId = null)
|
||||
{
|
||||
Cancelled = true;
|
||||
CancelReasonMessageId = reasonMessageId;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PacificationSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||
[Dependency] private readonly SharedCombatModeSystem _combatSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -53,10 +27,78 @@ public sealed class PacificationSystem : EntitySystem
|
||||
SubscribeLocalEvent<PacifiedComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<PacifiedComponent, BeforeThrowEvent>(OnBeforeThrow);
|
||||
SubscribeLocalEvent<PacifiedComponent, AttackAttemptEvent>(OnAttackAttempt);
|
||||
SubscribeLocalEvent<PacifiedComponent, ShotAttemptedEvent>(OnShootAttempt);
|
||||
SubscribeLocalEvent<PacifiedComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||
SubscribeLocalEvent<PacifismDangerousAttackComponent, AttemptPacifiedAttackEvent>(OnPacifiedDangerousAttack);
|
||||
}
|
||||
|
||||
private void OnUnpaused(Entity<PacifiedComponent> ent, ref EntityUnpausedEvent args)
|
||||
{
|
||||
if (ent.Comp.NextPopupTime != null)
|
||||
ent.Comp.NextPopupTime = ent.Comp.NextPopupTime.Value + args.PausedTime;
|
||||
}
|
||||
|
||||
private bool PacifiedCanAttack(EntityUid user, EntityUid target, [NotNullWhen(false)] out string? reason)
|
||||
{
|
||||
var ev = new AttemptPacifiedAttackEvent(user);
|
||||
|
||||
RaiseLocalEvent(target, ref ev);
|
||||
|
||||
if (ev.Cancelled)
|
||||
{
|
||||
reason = ev.Reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
reason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ShowPopup(Entity<PacifiedComponent> user, EntityUid target, string reason)
|
||||
{
|
||||
// Popup logic.
|
||||
// Cooldown is needed because the input events for melee/shooting etc. will fire continuously
|
||||
if (target == user.Comp.LastAttackedEntity
|
||||
&& !(_timing.CurTime > user.Comp.NextPopupTime))
|
||||
return;
|
||||
|
||||
_popup.PopupClient(Loc.GetString(reason, ("entity", target)), user, user);
|
||||
user.Comp.NextPopupTime = _timing.CurTime + user.Comp.PopupCooldown;
|
||||
user.Comp.LastAttackedEntity = target;
|
||||
}
|
||||
|
||||
private void OnShootAttempt(Entity<PacifiedComponent> ent, ref ShotAttemptedEvent args)
|
||||
{
|
||||
// Disallow firing guns in all cases.
|
||||
ShowPopup(ent, args.Used, "pacified-cannot-fire-gun");
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnAttackAttempt(EntityUid uid, PacifiedComponent component, AttackAttemptEvent args)
|
||||
{
|
||||
if (component.DisallowAllCombat || args.Disarm && component.DisallowDisarm)
|
||||
{
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's a disarm, let it go through (unless we disallow them, which is handled earlier)
|
||||
if (args.Disarm)
|
||||
return;
|
||||
|
||||
// Allow attacking with no target. This should be fine.
|
||||
// If it's a wide swing, that will be handled with a later AttackAttemptEvent raise.
|
||||
if (args.Target == null)
|
||||
return;
|
||||
|
||||
// If we would do zero damage, it should be fine.
|
||||
if (args.Weapon != null && args.Weapon.Value.Comp.Damage.GetTotal() == FixedPoint2.Zero)
|
||||
return;
|
||||
|
||||
if (PacifiedCanAttack(uid, args.Target.Value, out var reason))
|
||||
return;
|
||||
|
||||
ShowPopup((uid, component), args.Target.Value, reason);
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
@@ -65,11 +107,15 @@ public sealed class PacificationSystem : EntitySystem
|
||||
if (!TryComp<CombatModeComponent>(uid, out var combatMode))
|
||||
return;
|
||||
|
||||
if (combatMode.CanDisarm != null)
|
||||
if (component.DisallowDisarm && combatMode.CanDisarm != null)
|
||||
_combatSystem.SetCanDisarm(uid, false, combatMode);
|
||||
|
||||
_combatSystem.SetInCombatMode(uid, false, combatMode);
|
||||
_actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false);
|
||||
if (component.DisallowAllCombat)
|
||||
{
|
||||
_combatSystem.SetInCombatMode(uid, false, combatMode);
|
||||
_actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false);
|
||||
}
|
||||
|
||||
_alertsSystem.ShowAlert(uid, AlertType.Pacified);
|
||||
}
|
||||
|
||||
@@ -103,4 +149,51 @@ public sealed class PacificationSystem : EntitySystem
|
||||
var cannotThrowMessage = ev.CancelReasonMessageId ?? "pacified-cannot-throw";
|
||||
_popup.PopupEntity(Loc.GetString(cannotThrowMessage, ("projectile", itemName)), ent, ent);
|
||||
}
|
||||
|
||||
private void OnPacifiedDangerousAttack(Entity<PacifismDangerousAttackComponent> ent, ref AttemptPacifiedAttackEvent args)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
args.Reason = "pacified-cannot-harm-indirect";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a Pacified entity attempts to throw something.
|
||||
/// The throw is only permitted if this event is not cancelled.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public struct AttemptPacifiedThrowEvent
|
||||
{
|
||||
public EntityUid ItemUid;
|
||||
public EntityUid PlayerUid;
|
||||
|
||||
public AttemptPacifiedThrowEvent(EntityUid itemUid, EntityUid playerUid)
|
||||
{
|
||||
ItemUid = itemUid;
|
||||
PlayerUid = playerUid;
|
||||
}
|
||||
|
||||
public bool Cancelled { get; private set; } = false;
|
||||
public string? CancelReasonMessageId { get; private set; }
|
||||
|
||||
/// <param name="reasonMessageId">
|
||||
/// Localization string ID for the reason this event has been cancelled.
|
||||
/// If null, a generic message will be shown to the player.
|
||||
/// Note that any supplied localization string MUST accept a '$projectile'
|
||||
/// parameter specifying the name of the thrown entity.
|
||||
/// </param>
|
||||
public void Cancel(string? reasonMessageId = null)
|
||||
{
|
||||
Cancelled = true;
|
||||
CancelReasonMessageId = reasonMessageId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised ref directed on an entity when a pacified user is attempting to attack it.
|
||||
/// If <see cref="Cancelled"/> is true, don't allow attacking.
|
||||
/// <see cref="Reason"/> should be a loc string, if there needs to be special text for why the user isn't able to attack this.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct AttemptPacifiedAttackEvent(EntityUid User, bool Cancelled = false, string Reason = "pacified-cannot-harm-directly");
|
||||
|
||||
Reference in New Issue
Block a user