@@ -9,6 +9,7 @@ using Content.Shared.Movement.Components;
|
|||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Speech;
|
using Content.Shared.Speech;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
|
using Content.Shared.Weapons.Melee;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
|
|
||||||
@@ -145,7 +146,7 @@ namespace Content.Shared.ActionBlocker
|
|||||||
return !ev.Cancelled;
|
return !ev.Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanAttack(EntityUid uid, EntityUid? target = null)
|
public bool CanAttack(EntityUid uid, EntityUid? target = null, Entity<MeleeWeaponComponent>? weapon = null, bool disarm = false)
|
||||||
{
|
{
|
||||||
_container.TryGetOuterContainer(uid, Transform(uid), out var outerContainer);
|
_container.TryGetOuterContainer(uid, Transform(uid), out var outerContainer);
|
||||||
if (target != null && target != outerContainer?.Owner && _container.IsEntityInContainer(uid))
|
if (target != null && target != outerContainer?.Owner && _container.IsEntityInContainer(uid))
|
||||||
@@ -155,7 +156,7 @@ namespace Content.Shared.ActionBlocker
|
|||||||
return containerEv.CanAttack;
|
return containerEv.CanAttack;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ev = new AttackAttemptEvent(uid, target);
|
var ev = new AttackAttemptEvent(uid, target, weapon, disarm);
|
||||||
RaiseLocalEvent(uid, ev);
|
RaiseLocalEvent(uid, ev);
|
||||||
|
|
||||||
if (ev.Cancelled)
|
if (ev.Cancelled)
|
||||||
|
|||||||
@@ -1,50 +1,24 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Throwing;
|
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;
|
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
|
public sealed class PacificationSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||||
[Dependency] private readonly SharedCombatModeSystem _combatSystem = default!;
|
[Dependency] private readonly SharedCombatModeSystem _combatSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -53,10 +27,78 @@ public sealed class PacificationSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<PacifiedComponent, ComponentShutdown>(OnShutdown);
|
SubscribeLocalEvent<PacifiedComponent, ComponentShutdown>(OnShutdown);
|
||||||
SubscribeLocalEvent<PacifiedComponent, BeforeThrowEvent>(OnBeforeThrow);
|
SubscribeLocalEvent<PacifiedComponent, BeforeThrowEvent>(OnBeforeThrow);
|
||||||
SubscribeLocalEvent<PacifiedComponent, AttackAttemptEvent>(OnAttackAttempt);
|
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)
|
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();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,11 +107,15 @@ public sealed class PacificationSystem : EntitySystem
|
|||||||
if (!TryComp<CombatModeComponent>(uid, out var combatMode))
|
if (!TryComp<CombatModeComponent>(uid, out var combatMode))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (combatMode.CanDisarm != null)
|
if (component.DisallowDisarm && combatMode.CanDisarm != null)
|
||||||
_combatSystem.SetCanDisarm(uid, false, combatMode);
|
_combatSystem.SetCanDisarm(uid, false, combatMode);
|
||||||
|
|
||||||
_combatSystem.SetInCombatMode(uid, false, combatMode);
|
if (component.DisallowAllCombat)
|
||||||
_actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false);
|
{
|
||||||
|
_combatSystem.SetInCombatMode(uid, false, combatMode);
|
||||||
|
_actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false);
|
||||||
|
}
|
||||||
|
|
||||||
_alertsSystem.ShowAlert(uid, AlertType.Pacified);
|
_alertsSystem.ShowAlert(uid, AlertType.Pacified);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,4 +149,51 @@ public sealed class PacificationSystem : EntitySystem
|
|||||||
var cannotThrowMessage = ev.CancelReasonMessageId ?? "pacified-cannot-throw";
|
var cannotThrowMessage = ev.CancelReasonMessageId ?? "pacified-cannot-throw";
|
||||||
_popup.PopupEntity(Loc.GetString(cannotThrowMessage, ("projectile", itemName)), ent, ent);
|
_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");
|
||||||
|
|||||||
@@ -3,11 +3,42 @@ using Robust.Shared.GameStates;
|
|||||||
namespace Content.Shared.CombatMode.Pacification;
|
namespace Content.Shared.CombatMode.Pacification;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Status effect that disables combat mode and restricts aggressive actions.
|
/// Status effect that disallows harming living things and restricts aggressive actions.
|
||||||
|
///
|
||||||
|
/// There is a caveat with pacifism. It's not intended to be wholly encompassing: there are ways of harming people
|
||||||
|
/// while pacified--plenty of them, even! The goal is to restrict the obvious ones to make gameplay more interesting
|
||||||
|
/// while not overly limiting.
|
||||||
|
///
|
||||||
|
/// If you want full-pacifism (no combat mode at all), you can simply set <see cref="DisallowAllCombat"/> before adding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
[Access(typeof(PacificationSystem))]
|
[Access(typeof(PacificationSystem))]
|
||||||
public sealed partial class PacifiedComponent : Component
|
public sealed partial class PacifiedComponent : Component
|
||||||
{
|
{
|
||||||
|
[DataField]
|
||||||
|
public bool DisallowDisarm = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, this will disable combat entirely instead of only disallowing attacking living creatures and harmful things.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public bool DisallowAllCombat = false;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When attempting attack against the same entity multiple times,
|
||||||
|
/// don't spam popups every frame and instead have a cooldown.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan PopupCooldown = TimeSpan.FromSeconds(3.0);
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan? NextPopupTime = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The last entity attacked, used for popup purposes (avoid spam)
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public EntityUid? LastAttackedEntity = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.CombatMode.Pacification;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for marking entities which could cause serious harm if attacked and should not be able to be harmed by
|
||||||
|
/// pacifists.
|
||||||
|
/// TODO ideally destructible is shared + converted to components so we can just check for a harmful damage trigger instead of this.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class PacifismDangerousAttackComponent : Component
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Content.Shared.Weapons.Melee;
|
||||||
|
|
||||||
namespace Content.Shared.Interaction.Events
|
namespace Content.Shared.Interaction.Events
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -12,10 +14,19 @@ namespace Content.Shared.Interaction.Events
|
|||||||
public EntityUid Uid { get; }
|
public EntityUid Uid { get; }
|
||||||
public EntityUid? Target { get; }
|
public EntityUid? Target { get; }
|
||||||
|
|
||||||
public AttackAttemptEvent(EntityUid uid, EntityUid? target = null)
|
public Entity<MeleeWeaponComponent>? Weapon { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If this attempt is a disarm as opposed to an actual attack, for things that care about the difference.
|
||||||
|
/// </summary>
|
||||||
|
public bool Disarm { get; }
|
||||||
|
|
||||||
|
public AttackAttemptEvent(EntityUid uid, EntityUid? target = null, Entity<MeleeWeaponComponent>? weapon = null, bool disarm = false)
|
||||||
{
|
{
|
||||||
Uid = uid;
|
Uid = uid;
|
||||||
Target = target;
|
Target = target;
|
||||||
|
Weapon = weapon;
|
||||||
|
Disarm = disarm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Bed.Sleep;
|
using Content.Shared.Bed.Sleep;
|
||||||
|
using Content.Shared.CombatMode.Pacification;
|
||||||
using Content.Shared.Damage.ForceSay;
|
using Content.Shared.Damage.ForceSay;
|
||||||
using Content.Shared.Emoting;
|
using Content.Shared.Emoting;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
@@ -39,6 +40,7 @@ public partial class MobStateSystem
|
|||||||
SubscribeLocalEvent<MobStateComponent, StandAttemptEvent>(CheckAct);
|
SubscribeLocalEvent<MobStateComponent, StandAttemptEvent>(CheckAct);
|
||||||
SubscribeLocalEvent<MobStateComponent, TryingToSleepEvent>(OnSleepAttempt);
|
SubscribeLocalEvent<MobStateComponent, TryingToSleepEvent>(OnSleepAttempt);
|
||||||
SubscribeLocalEvent<MobStateComponent, CombatModeShouldHandInteractEvent>(OnCombatModeShouldHandInteract);
|
SubscribeLocalEvent<MobStateComponent, CombatModeShouldHandInteractEvent>(OnCombatModeShouldHandInteract);
|
||||||
|
SubscribeLocalEvent<MobStateComponent, AttemptPacifiedAttackEvent>(OnAttemptPacifiedAttack);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStateExitSubscribers(EntityUid target, MobStateComponent component, MobState state)
|
private void OnStateExitSubscribers(EntityUid target, MobStateComponent component, MobState state)
|
||||||
@@ -166,5 +168,10 @@ public partial class MobStateSystem
|
|||||||
args.Cancelled = true;
|
args.Cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnAttemptPacifiedAttack(Entity<MobStateComponent> ent, ref AttemptPacifiedAttackEvent args)
|
||||||
|
{
|
||||||
|
args.Cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ using Robust.Shared.Physics.Systems;
|
|||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Toolshed.Syntax;
|
||||||
|
|
||||||
namespace Content.Shared.Weapons.Melee;
|
namespace Content.Shared.Weapons.Melee;
|
||||||
|
|
||||||
@@ -350,7 +351,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
case LightAttackEvent light:
|
case LightAttackEvent light:
|
||||||
var lightTarget = GetEntity(light.Target);
|
var lightTarget = GetEntity(light.Target);
|
||||||
|
|
||||||
if (!Blocker.CanAttack(user, lightTarget))
|
if (!Blocker.CanAttack(user, lightTarget, (weaponUid, weapon)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Can't self-attack if you're the weapon
|
// Can't self-attack if you're the weapon
|
||||||
@@ -361,11 +362,11 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
case DisarmAttackEvent disarm:
|
case DisarmAttackEvent disarm:
|
||||||
var disarmTarget = GetEntity(disarm.Target);
|
var disarmTarget = GetEntity(disarm.Target);
|
||||||
|
|
||||||
if (!Blocker.CanAttack(user, disarmTarget))
|
if (!Blocker.CanAttack(user, disarmTarget, (weaponUid, weapon), true))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!Blocker.CanAttack(user))
|
if (!Blocker.CanAttack(user, weapon: (weaponUid, weapon)))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -642,20 +643,27 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
|
|
||||||
foreach (var entity in targets)
|
foreach (var entity in targets)
|
||||||
{
|
{
|
||||||
|
// We raise an attack attempt here as well,
|
||||||
|
// primarily because this was an untargeted wideswing: if a subscriber to that event cared about
|
||||||
|
// the potential target (such as for pacifism), they need to be made aware of the target here.
|
||||||
|
// In that case, just continue.
|
||||||
|
if (!Blocker.CanAttack(user, entity, (weapon, component)))
|
||||||
|
continue;
|
||||||
|
|
||||||
var attackedEvent = new AttackedEvent(meleeUid, user, GetCoordinates(ev.Coordinates));
|
var attackedEvent = new AttackedEvent(meleeUid, user, GetCoordinates(ev.Coordinates));
|
||||||
RaiseLocalEvent(entity, attackedEvent);
|
RaiseLocalEvent(entity, attackedEvent);
|
||||||
var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
|
var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
|
||||||
|
|
||||||
var damageResult = Damageable.TryChangeDamage(entity, modifiedDamage, origin:user);
|
var damageResult = Damageable.TryChangeDamage(entity, modifiedDamage, origin:user);
|
||||||
|
|
||||||
if (damageResult != null && damageResult.Total > FixedPoint2.Zero)
|
if (damageResult != null && damageResult.GetTotal() > FixedPoint2.Zero)
|
||||||
{
|
{
|
||||||
appliedDamage += damageResult;
|
appliedDamage += damageResult;
|
||||||
|
|
||||||
if (meleeUid == user)
|
if (meleeUid == user)
|
||||||
{
|
{
|
||||||
AdminLogger.Add(LogType.MeleeHit, LogImpact.Medium,
|
AdminLogger.Add(LogType.MeleeHit, LogImpact.Medium,
|
||||||
$"{ToPrettyString(user):actor} melee attacked (heavy) {ToPrettyString(entity):subject} using their hands and dealt {damageResult.Total:damage} damage");
|
$"{ToPrettyString(user):actor} melee attacked (heavy) {ToPrettyString(entity):subject} using their hands and dealt {damageResult.GetTotal():damage} damage");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -667,7 +675,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
|
|
||||||
if (entities.Count != 0)
|
if (entities.Count != 0)
|
||||||
{
|
{
|
||||||
if (appliedDamage.Total > FixedPoint2.Zero)
|
if (appliedDamage.GetTotal() > FixedPoint2.Zero)
|
||||||
{
|
{
|
||||||
var target = entities.First();
|
var target = entities.First();
|
||||||
PlayHitSound(target, user, GetHighestDamageSound(appliedDamage, _protoManager), hitEvent.HitSoundOverride, component.HitSound);
|
PlayHitSound(target, user, GetHighestDamageSound(appliedDamage, _protoManager), hitEvent.HitSoundOverride, component.HitSound);
|
||||||
@@ -685,7 +693,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appliedDamage.Total > FixedPoint2.Zero)
|
if (appliedDamage.GetTotal() > FixedPoint2.Zero)
|
||||||
{
|
{
|
||||||
DoDamageEffect(targets, user, Transform(targets[0]));
|
DoDamageEffect(targets, user, Transform(targets[0]));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ alerts-bleed-name = [color=red]Bleed[/color]
|
|||||||
alerts-bleed-desc = You're [color=red]bleeding[/color].
|
alerts-bleed-desc = You're [color=red]bleeding[/color].
|
||||||
|
|
||||||
alerts-pacified-name = [color=green]Pacified[/color]
|
alerts-pacified-name = [color=green]Pacified[/color]
|
||||||
alerts-pacified-desc = You're pacified; you won't be able to attack anyone directly.
|
alerts-pacified-desc = You're pacified; you won't be able to harm living creatures.
|
||||||
|
|
||||||
alerts-suit-power-name = Suit Power
|
alerts-suit-power-name = Suit Power
|
||||||
alerts-suit-power-desc = How much power your space ninja suit has.
|
alerts-suit-power-desc = How much power your space ninja suit has.
|
||||||
|
|||||||
@@ -2,10 +2,14 @@
|
|||||||
## Messages shown to Pacified players when they try to do violence:
|
## Messages shown to Pacified players when they try to do violence:
|
||||||
|
|
||||||
# With projectiles:
|
# With projectiles:
|
||||||
pacified-cannot-throw = You can't bring yourself to throw { THE($projectile) }, that could hurt someone!
|
pacified-cannot-throw = I can't bring myself to throw { THE($projectile) }, that could hurt someone!
|
||||||
# With embedding projectiles:
|
# With embedding projectiles:
|
||||||
pacified-cannot-throw-embed = No way you can throw { THE($projectile) }, that could get lodged inside someone!
|
pacified-cannot-throw-embed = No way I could throw { THE($projectile) }, that could get lodged inside someone!
|
||||||
# With liquid-spilling projectiles:
|
# With liquid-spilling projectiles:
|
||||||
pacified-cannot-throw-spill = You can't possibly throw { THE($projectile) }, that could spill nasty stuff on someone!
|
pacified-cannot-throw-spill = I can't possibly throw { THE($projectile) }, that could spill nasty stuff on someone!
|
||||||
# With bolas and snares:
|
# With bolas and snares:
|
||||||
pacified-cannot-throw-snare = You can't throw { THE($projectile) }, what if someone trips?!
|
pacified-cannot-throw-snare = I can't throw { THE($projectile) }, what if someone trips?!
|
||||||
|
|
||||||
|
pacified-cannot-harm-directly = I can't bring myself to hurt { THE($entity) }!
|
||||||
|
pacified-cannot-harm-indirect = I can't damage { THE($entity) }, it could hurt someone!
|
||||||
|
pacified-cannot-fire-gun = I can't fire { THE($entity) }, it could hurt someone!
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
damageModifierSet: Metallic
|
damageModifierSet: Metallic
|
||||||
|
- type: PacifismDangerousAttack
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
damageModifierSet: StrongMetallic
|
damageModifierSet: StrongMetallic
|
||||||
|
- type: PacifismDangerousAttack
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
@@ -191,6 +192,7 @@
|
|||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
damageModifierSet: Metallic
|
damageModifierSet: Metallic
|
||||||
|
- type: PacifismDangerousAttack
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
weldingDamage:
|
weldingDamage:
|
||||||
types:
|
types:
|
||||||
Heat: 10
|
Heat: 10
|
||||||
|
- type: PacifismDangerousAttack
|
||||||
- type: Explosive
|
- type: Explosive
|
||||||
explosionType: Default
|
explosionType: Default
|
||||||
totalIntensity: 120 # ~ 5 tile radius
|
totalIntensity: 120 # ~ 5 tile radius
|
||||||
|
|||||||
Reference in New Issue
Block a user