Merge remote-tracking branch 'upstream/stable' into ed-30-04-2025-upstream-sync
# Conflicts: # Content.Client/Parallax/ParallaxControl.cs # Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs # Content.IntegrationTests/Tests/PostMapInitTest.cs # Content.Server/Chat/Managers/ChatManager.cs # Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs # Content.Server/Labels/Label/LabelSystem.cs # Content.Shared/Actions/SharedActionsSystem.cs # Content.Shared/Fluids/Components/EvaporationComponent.cs # Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs # README.md # Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml # Resources/Prototypes/Maps/Pools/deathmatch.yml # Resources/Prototypes/Maps/arenas.yml
This commit is contained in:
@@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Actions.Events;
|
||||
using Content.Shared.Administration.Components;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.CombatMode;
|
||||
using Content.Shared.Damage;
|
||||
@@ -10,22 +12,30 @@ using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Inventory.VirtualItem;
|
||||
using Content.Shared.Item.ItemToggle.Components;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.Weapons.Melee.Components;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using ItemToggleMeleeWeaponComponent = Content.Shared.Item.ItemToggle.Components.ItemToggleMeleeWeaponComponent;
|
||||
|
||||
@@ -33,20 +43,24 @@ namespace Content.Shared.Weapons.Melee;
|
||||
|
||||
public abstract class SharedMeleeWeaponSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!;
|
||||
[Dependency] protected readonly ActionBlockerSystem Blocker = default!;
|
||||
[Dependency] protected readonly SharedCombatModeSystem CombatMode = default!;
|
||||
[Dependency] protected readonly DamageableSystem Damageable = default!;
|
||||
[Dependency] protected readonly SharedInteractionSystem Interaction = default!;
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
[Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
|
||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly MeleeSoundSystem _meleeSound = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
[Dependency] private readonly StaminaSystem _stamina = default!;
|
||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
[Dependency] private readonly INetManager _netMan = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!;
|
||||
[Dependency] protected readonly ActionBlockerSystem Blocker = default!;
|
||||
[Dependency] protected readonly DamageableSystem Damageable = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly MeleeSoundSystem _meleeSound = default!;
|
||||
[Dependency] protected readonly MobStateSystem MobState = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] protected readonly SharedCombatModeSystem CombatMode = default!;
|
||||
[Dependency] protected readonly SharedInteractionSystem Interaction = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
|
||||
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
|
||||
[Dependency] private readonly StaminaSystem _stamina = default!;
|
||||
|
||||
private const int AttackMask = (int) (CollisionGroup.MobMask | CollisionGroup.Opaque);
|
||||
|
||||
@@ -788,7 +802,25 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
||||
return highestDamageType;
|
||||
}
|
||||
|
||||
protected virtual bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid meleeUid, MeleeWeaponComponent component, ICommonSession? session)
|
||||
private float CalculateDisarmChance(EntityUid disarmer, EntityUid disarmed, EntityUid? inTargetHand, CombatModeComponent disarmerComp)
|
||||
{
|
||||
if (HasComp<DisarmProneComponent>(disarmer))
|
||||
return 1.0f;
|
||||
|
||||
if (HasComp<DisarmProneComponent>(disarmed))
|
||||
return 0.0f;
|
||||
|
||||
var chance = disarmerComp.BaseDisarmFailChance;
|
||||
|
||||
if (inTargetHand != null && TryComp<DisarmMalusComponent>(inTargetHand, out var malus))
|
||||
{
|
||||
chance += malus.Malus;
|
||||
}
|
||||
|
||||
return Math.Clamp(chance, 0f, 1f);
|
||||
}
|
||||
|
||||
private bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid meleeUid, MeleeWeaponComponent component, ICommonSession? session)
|
||||
{
|
||||
var target = GetEntity(ev.Target);
|
||||
|
||||
@@ -798,8 +830,110 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
||||
return false;
|
||||
}
|
||||
|
||||
// Play a sound to give instant feedback; same with playing the animations
|
||||
_meleeSound.PlaySwingSound(user, meleeUid, component);
|
||||
|
||||
if (MobState.IsIncapacitated(target.Value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryComp<CombatModeComponent>(user, out var combatMode) ||
|
||||
combatMode.CanDisarm != true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Need hands or to be able to be shoved over.
|
||||
if (!TryComp<HandsComponent>(target, out var targetHandsComponent))
|
||||
{
|
||||
if (!TryComp<StatusEffectsComponent>(target, out var status) ||
|
||||
!status.AllowedEffects.Contains("KnockedDown"))
|
||||
{
|
||||
// Notify disarmable
|
||||
if (HasComp<MobStateComponent>(target.Value))
|
||||
PopupSystem.PopupClient(Loc.GetString("disarm-action-disarmable", ("targetName", target.Value)), target.Value);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!InRange(user, target.Value, component.Range, session))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityUid? inTargetHand = null;
|
||||
|
||||
if (targetHandsComponent?.ActiveHand is { IsEmpty: false })
|
||||
{
|
||||
inTargetHand = targetHandsComponent.ActiveHand.HeldEntity!.Value;
|
||||
}
|
||||
|
||||
var attemptEvent = new DisarmAttemptEvent(target.Value, user, inTargetHand);
|
||||
|
||||
if (inTargetHand != null)
|
||||
{
|
||||
RaiseLocalEvent(inTargetHand.Value, ref attemptEvent);
|
||||
}
|
||||
|
||||
RaiseLocalEvent(target.Value, ref attemptEvent);
|
||||
|
||||
if (attemptEvent.Cancelled)
|
||||
return false;
|
||||
|
||||
var chance = CalculateDisarmChance(user, target.Value, inTargetHand, combatMode);
|
||||
|
||||
// At this point we diverge
|
||||
if (_netMan.IsClient)
|
||||
{
|
||||
// Play a sound to give instant feedback; same with playing the animations
|
||||
_meleeSound.PlaySwingSound(user, meleeUid, component);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_random.Prob(chance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var eventArgs = new DisarmedEvent(target.Value, user, 1 - chance);
|
||||
RaiseLocalEvent(target.Value, ref eventArgs);
|
||||
|
||||
// Nothing handled it so abort.
|
||||
if (!eventArgs.Handled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Interaction.DoContactInteraction(user, target);
|
||||
AdminLogger.Add(LogType.DisarmedAction, $"{ToPrettyString(user):user} used disarm on {ToPrettyString(target):target}");
|
||||
|
||||
AdminLogger.Add(LogType.DisarmedAction, $"{ToPrettyString(user):user} used disarm on {ToPrettyString(target):target}");
|
||||
|
||||
_audio.PlayPvs(combatMode.DisarmSuccessSound, target.Value, AudioParams.Default.WithVariation(0.025f).WithVolume(5f));
|
||||
var targetEnt = Identity.Entity(target.Value, EntityManager);
|
||||
var userEnt = Identity.Entity(user, EntityManager);
|
||||
|
||||
var msgOther = Loc.GetString(
|
||||
eventArgs.PopupPrefix + "popup-message-other-clients",
|
||||
("performerName", userEnt),
|
||||
("targetName", targetEnt));
|
||||
|
||||
var msgUser = Loc.GetString(eventArgs.PopupPrefix + "popup-message-cursor", ("targetName", targetEnt));
|
||||
|
||||
var filterOther = Filter.PvsExcept(user, entityManager: EntityManager);
|
||||
|
||||
PopupSystem.PopupEntity(msgOther, user, filterOther, true);
|
||||
PopupSystem.PopupEntity(msgUser, target.Value, user);
|
||||
|
||||
if (eventArgs.IsStunned)
|
||||
{
|
||||
|
||||
PopupSystem.PopupEntity(Loc.GetString("stunned-component-disarm-success-others", ("source", userEnt), ("target", targetEnt)), targetEnt, Filter.PvsExcept(user), true, PopupType.LargeCaution);
|
||||
PopupSystem.PopupCursor(Loc.GetString("stunned-component-disarm-success", ("target", targetEnt)), user, PopupType.Large);
|
||||
|
||||
AdminLogger.Add(LogType.DisarmedKnockdown, LogImpact.Medium, $"{ToPrettyString(user):user} knocked down {ToPrettyString(target):target}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user