From 30af1871090a5550d453718a614f7d74ec0584fb Mon Sep 17 00:00:00 2001 From: Eugeny Date: Fri, 19 Apr 2024 23:11:06 +0400 Subject: [PATCH] =?UTF-8?q?=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D0=B0=D0=B2?= =?UTF-8?q?=D1=80=D0=B8=D1=82=D0=B0=20=D0=B8=D0=B7=20=D0=BC=D0=B0=D0=BF?= =?UTF-8?q?=D0=BF=D1=83=D0=BB=D0=B0,=20=D0=B2=D0=B2=D0=BE=D0=B4=20=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D1=82=D1=8B=20=D0=B2=D0=B7=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Content.Client/Mech/MechSystem.cs | 28 ++++- .../Components/MechArmorComponent.cs | 17 +++ .../Components/MechGrabberComponent.cs | 14 ++- .../Equipment/Components/MechGunComponent.cs | 20 ++++ .../EntitySystems/MechArmorSystem.cs | 78 ++++++++++++ .../EntitySystems/MechGrabberSystem.cs | 39 +++++- .../Equipment/EntitySystems/MechGunSystem.cs | 80 +++++++++++++ Content.Server/Mech/Systems/MechSystem.cs | 111 +++++++++++------- .../Projectiles/ProjectileSystem.cs | 5 + .../Weapons/Ranged/Systems/GunSystem.cs | 17 ++- .../FriendlyFireToggleableComponent.cs | 13 ++ .../FriendlyFire/FriendlyFireComponent.cs | 8 ++ .../FriendlyFireSystem.Toggleable.cs | 42 +++++++ .../FriendlyFire/FriendlyFireSystem.cs | 101 ++++++++++++++++ .../Mech/Components/MechComponent.cs | 62 +++++++++- .../Mech/Components/MechOverloadComponent.cs | 31 +++++ .../Mech/EntitySystems/MechOverloadSystem.cs | 80 +++++++++++++ .../Mech/EntitySystems/SharedMechSystem.cs | 38 +++++- .../Components/MechEquipmentComponent.cs | 1 + Content.Shared/Mech/SharedMech.cs | 12 ++ .../Projectiles/SharedProjectileSystem.cs | 15 +++ .../Weapons/Ranged/Systems/SharedGunSystem.cs | 77 ++++++------ Resources/Prototypes/Maps/Pools/default.yml | 4 +- 23 files changed, 787 insertions(+), 106 deletions(-) create mode 100644 Content.Server/Mech/Equipment/Components/MechArmorComponent.cs create mode 100644 Content.Server/Mech/Equipment/Components/MechGunComponent.cs create mode 100644 Content.Server/Mech/Equipment/EntitySystems/MechArmorSystem.cs create mode 100644 Content.Server/Mech/Equipment/EntitySystems/MechGunSystem.cs create mode 100644 Content.Server/_TornadoTech/FriendlyFire/Actions/FriendlyFireToggleableComponent.cs create mode 100644 Content.Server/_TornadoTech/FriendlyFire/FriendlyFireComponent.cs create mode 100644 Content.Server/_TornadoTech/FriendlyFire/FriendlyFireSystem.Toggleable.cs create mode 100644 Content.Server/_TornadoTech/FriendlyFire/FriendlyFireSystem.cs create mode 100644 Content.Shared/Mech/Components/MechOverloadComponent.cs create mode 100644 Content.Shared/Mech/EntitySystems/MechOverloadSystem.cs diff --git a/Content.Client/Mech/MechSystem.cs b/Content.Client/Mech/MechSystem.cs index ba4e29951d1..79a8b17aa7d 100644 --- a/Content.Client/Mech/MechSystem.cs +++ b/Content.Client/Mech/MechSystem.cs @@ -3,6 +3,8 @@ using Content.Shared.Mech.EntitySystems; using Robust.Client.GameObjects; using DrawDepth = Content.Shared.DrawDepth.DrawDepth; +using Robust.Shared.Audio.Systems; +using Robust.Client.Player; namespace Content.Client.Mech; @@ -10,13 +12,17 @@ namespace Content.Client.Mech; public sealed class MechSystem : SharedMechSystem { [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; /// public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAppearanceChanged); + SubscribeLocalEvent(OnMechEntry); + SubscribeLocalEvent(OnEquipmentDestroyed); } private void OnAppearanceChanged(EntityUid uid, MechComponent component, ref AppearanceChangeEvent args) @@ -43,4 +49,24 @@ private void OnAppearanceChanged(EntityUid uid, MechComponent component, ref App layer.SetState(state); args.Sprite.DrawDepth = (int) drawDepth; } + private void OnMechEntry(EntityUid uid, MechComponent component, MechEntryEvent args) + { + var player = _playerManager.LocalPlayer; + var playerEntity = player?.ControlledEntity; + if (playerEntity == null) + { + return; + } + _audio.PlayPredicted(component.MechEntrySound, uid, playerEntity); + } + private void OnEquipmentDestroyed(EntityUid uid, MechComponent component, MechEquipmentDestroyedEvent args) + { + var player = _playerManager.LocalPlayer; + var playerEntity = player?.ControlledEntity; + if (playerEntity == null) + { + return; + } + _audio.PlayPredicted(component.MechEntrySound, uid, playerEntity); + } } diff --git a/Content.Server/Mech/Equipment/Components/MechArmorComponent.cs b/Content.Server/Mech/Equipment/Components/MechArmorComponent.cs new file mode 100644 index 00000000000..83db723b290 --- /dev/null +++ b/Content.Server/Mech/Equipment/Components/MechArmorComponent.cs @@ -0,0 +1,17 @@ +using Content.Shared.Damage; + +namespace Content.Server.Mech.Equipment.Components; + +/// +/// A piece of mech equipment that grabs entities and stores them +/// inside of a container so large objects can be moved. +/// +[RegisterComponent] +public sealed partial class MechArmorComponent : Component +{ + /// + /// damage modifiers to add + /// + [DataField(required: true)] + public DamageModifierSet Modifiers = default!; +} diff --git a/Content.Server/Mech/Equipment/Components/MechGrabberComponent.cs b/Content.Server/Mech/Equipment/Components/MechGrabberComponent.cs index f4b3a985bfc..ae53c71c26e 100644 --- a/Content.Server/Mech/Equipment/Components/MechGrabberComponent.cs +++ b/Content.Server/Mech/Equipment/Components/MechGrabberComponent.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using System.Threading; using Content.Shared.DoAfter; using Robust.Shared.Audio; @@ -38,6 +38,18 @@ public sealed partial class MechGrabberComponent : Component [DataField("maxContents")] public int MaxContents = 10; + /// + /// is it possible to grab a mob? + /// + [DataField("grabmobs")] + public bool GrabMobs = false; + + /// + /// is it slow mob's metabolism? + /// + [DataField("creo")] + public bool SlowMetabolism = false; + /// /// The sound played when a mech is grabbing something /// diff --git a/Content.Server/Mech/Equipment/Components/MechGunComponent.cs b/Content.Server/Mech/Equipment/Components/MechGunComponent.cs new file mode 100644 index 00000000000..bbe8ea4c79d --- /dev/null +++ b/Content.Server/Mech/Equipment/Components/MechGunComponent.cs @@ -0,0 +1,20 @@ +namespace Content.Shared.Mech.Equipment.Components; + +/// +/// A piece of mech equipment that grabs entities and stores them +/// inside of a container so large objects can be moved. +/// +[RegisterComponent] +public sealed partial class MechGunComponent : Component +{ +} +public sealed class MechShootEvent : CancellableEntityEventArgs +{ + public EntityUid User; + + public MechShootEvent(EntityUid user) + { + User = user; + } +} + diff --git a/Content.Server/Mech/Equipment/EntitySystems/MechArmorSystem.cs b/Content.Server/Mech/Equipment/EntitySystems/MechArmorSystem.cs new file mode 100644 index 00000000000..7c5eeb25063 --- /dev/null +++ b/Content.Server/Mech/Equipment/EntitySystems/MechArmorSystem.cs @@ -0,0 +1,78 @@ +using System.Linq; +using Content.Server.Interaction; +using Content.Server.Mech.Equipment.Components; +using Content.Server.Mech.Systems; +using Content.Shared.DoAfter; +using Content.Shared.Interaction; +using Content.Shared.Mech; +using Content.Shared.Mech.Components; +using Content.Shared.Mech.Equipment.Components; +using Content.Shared.Mobs.Components; +using Content.Shared.Wall; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Content.Shared.Damage; + +namespace Content.Server.Mech.Equipment.EntitySystems; + +public sealed class MechArmorSystem : EntitySystem +{ + /// + public override void Initialize() + { + SubscribeLocalEvent(OnEquipmentInstalled); + SubscribeLocalEvent(OnEquipmentRemoved); + } + + private void OnEquipmentInstalled(EntityUid uid, MechArmorComponent component, ref MechEquipmentInsertedEvent args) + { + if (!TryComp(args.Mech, out var mech)) + return; + mech.Modifiers = SumModifierSets(mech.Modifiers, component.Modifiers); + } + + private void OnEquipmentRemoved(EntityUid uid, MechArmorComponent component, ref MechEquipmentRemovedEvent args) + { + if (!TryComp(args.Mech, out var mech)) + return; + mech.Modifiers = MinodifierSets(mech.Modifiers, component.Modifiers); + } + + private DamageModifierSet SumModifierSets(DamageModifierSet modifier1, DamageModifierSet modifier2) + { + var modifier3 = modifier2; + + foreach (var item in modifier1.FlatReduction) { + if (modifier3.FlatReduction.TryGetValue(item.Key, out _) && modifier3.Coefficients[item.Key] <= item.Value){ + modifier3.FlatReduction[item.Key] += item.Value; + } + } + foreach (var item in modifier1.Coefficients) { + if (modifier3.Coefficients.TryGetValue(item.Key, out _) && modifier3.Coefficients[item.Key] <= item.Value){ + modifier3.Coefficients[item.Key] += item.Value; + } + } + return modifier3; + } + private DamageModifierSet MinodifierSets(DamageModifierSet modifier1, DamageModifierSet modifier2) + { + var modifier3 = modifier2; + + foreach (var item in modifier1.FlatReduction) { + if (modifier3.FlatReduction.TryGetValue(item.Key, out _)){ + modifier3.FlatReduction[item.Key] -= item.Value; + } + } + foreach (var item in modifier1.Coefficients) { + if (modifier3.Coefficients.TryGetValue(item.Key, out _)){ + modifier3.Coefficients[item.Key] -= item.Value; + } + } + return modifier3; + } +} diff --git a/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs b/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs index fa46792d2af..de7dd3827d1 100644 --- a/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs +++ b/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs @@ -16,6 +16,22 @@ using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; +using Content.Shared.Mobs.Systems; +using Content.Server.Actions; +using Content.Server.Bed.Components; +using Content.Server.Bed.Sleep; +using Content.Server.Body.Systems; +using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Shared.Bed; +using Content.Shared.Bed.Sleep; +using Content.Shared.Body.Components; +using Content.Shared.Buckle.Components; +using Content.Shared.Damage; +using Content.Shared.Emag.Systems; +using Content.Shared.Mobs.Systems; +using Robust.Shared.Timing; +using Content.Shared.SimpleStation14.Silicon.Components; namespace Content.Server.Mech.Equipment.EntitySystems; @@ -83,7 +99,12 @@ public void RemoveItem(EntityUid uid, EntityUid mech, EntityUid toRemove, MechGr var xform = Transform(toRemove); _transform.AttachToGridOrMap(toRemove, xform); var (mechPos, mechRot) = _transform.GetWorldPositionRotation(mechxform); - + if (component.SlowMetabolism) + { + var metabolicEvent = new ApplyMetabolicMultiplierEvent + {Uid = toRemove, Multiplier = 1f}; + RaiseLocalEvent(toRemove, metabolicEvent); + } var offset = mechPos + mechRot.RotateVec(component.DepositOffset); _transform.SetWorldPositionRotation(xform, offset, Angle.Zero); _mech.UpdateUserInterface(mech); @@ -131,13 +152,17 @@ private void OnInteract(EntityUid uid, MechGrabberComponent component, InteractN if (args.Target == args.User || component.DoAfter != null) return; - if (TryComp(target, out var physics) && physics.BodyType == BodyType.Static || + if (!component.GrabMobs && + TryComp(target, out var physics) && physics.BodyType == BodyType.Static || HasComp(target) || HasComp(target)) { - return; + if (component.GrabMobs && + !HasComp(target)) + { + return; + } } - if (Transform(target).Anchored) return; @@ -183,6 +208,12 @@ private void OnMechGrab(EntityUid uid, MechGrabberComponent component, DoAfterEv return; _container.Insert(args.Args.Target.Value, component.ItemContainer); + if (component.SlowMetabolism) + { + var metabolicEvent = new ApplyMetabolicMultiplierEvent + {Uid = args.Args.Target.Value, Multiplier = 0.4f}; + RaiseLocalEvent(args.Args.Target.Value, metabolicEvent); + } _mech.UpdateUserInterface(equipmentComponent.EquipmentOwner.Value); args.Handled = true; diff --git a/Content.Server/Mech/Equipment/EntitySystems/MechGunSystem.cs b/Content.Server/Mech/Equipment/EntitySystems/MechGunSystem.cs new file mode 100644 index 00000000000..c43e0c0087d --- /dev/null +++ b/Content.Server/Mech/Equipment/EntitySystems/MechGunSystem.cs @@ -0,0 +1,80 @@ +using Content.Server.Mech.Systems; +using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Shared.Mech.Components; +using Content.Shared.Mech.Equipment.Components; +using Content.Shared.Throwing; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Shared.Random; +using Content.Shared.Stunnable; + +namespace Content.Server.Mech.Equipment.EntitySystems; +public sealed class MechGunSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; + [Dependency] private readonly MechSystem _mech = default!; + [Dependency] private readonly BatterySystem _battery = default!; + [Dependency] private readonly SharedGunSystem _guns = default!; + [Dependency] private readonly SharedStunSystem _stun = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(MechGunShot); + } + + private void MechGunShot(EntityUid uid, MechEquipmentComponent component, ref GunShotEvent args) + { + if (!component.EquipmentOwner.HasValue) + { + _stun.TryParalyze(args.User, TimeSpan.FromSeconds(10), true); + _throwing.TryThrow(args.User, _random.NextVector2(), _random.Next(50)); + return; + } + if (!TryComp(component.EquipmentOwner.Value, out var mech)) + { + return; + } + if (TryComp(uid, out var battery)) + { + ChargeGunBattery(uid, battery); + return; + } + // In most guns the ammo itself isn't shot but turned into cassings + // and a new projectile is spawned instead, meaning that args.Ammo + // is most likely inside the equipment container (for some odd reason) + + // I'm not even sure why this is needed since GunSystem.Shoot() has a + // container check before ejecting, but yet it still puts the spent ammo inside the mech + foreach (var (ent, _) in args.Ammo) + { + if (ent.HasValue && mech.EquipmentContainer.Contains(ent.Value)) + { + _throwing.TryThrow(ent.Value, _random.NextVector2(), _random.Next(5)); + } + } + } + + private void ChargeGunBattery(EntityUid uid, BatteryComponent component) + { + if (!TryComp(uid, out var mechEquipment) || !mechEquipment.EquipmentOwner.HasValue) + return; + + if (!TryComp(mechEquipment.EquipmentOwner.Value, out var mech)) + return; + + var maxCharge = component.MaxCharge; + var currentCharge = component.CurrentCharge; + + var chargeDelta = maxCharge - currentCharge; + + if (chargeDelta <= 0 || mech.Energy - chargeDelta < 0) + return; + + if (!_mech.TryChangeEnergy(mechEquipment.EquipmentOwner.Value, -chargeDelta, mech)) + return; + + _battery.SetCharge(uid, component.MaxCharge, component); + } +} diff --git a/Content.Server/Mech/Systems/MechSystem.cs b/Content.Server/Mech/Systems/MechSystem.cs index eef9bcb8ecd..c8e2cc952b8 100644 --- a/Content.Server/Mech/Systems/MechSystem.cs +++ b/Content.Server/Mech/Systems/MechSystem.cs @@ -22,12 +22,19 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Player; +using Robust.Shared.Audio.Systems; +using Content.Shared.Access.Systems; +using Content.Shared.Access.Components; +using Content.Server.Emp; +using Robust.Shared.Random; +using Robust.Shared.Audio; namespace Content.Server.Mech.Systems; /// public sealed partial class MechSystem : SharedMechSystem { + [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; [Dependency] private readonly AtmosphereSystem _atmosphere = default!; [Dependency] private readonly BatterySystem _battery = default!; @@ -38,8 +45,11 @@ public sealed partial class MechSystem : SharedMechSystem [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; - + [Dependency] private readonly AccessReaderSystem _accessReader = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPointLightSystem _lights = default!; private ISawmill _sawmill = default!; + private float _timer; /// public override void Initialize() @@ -54,17 +64,20 @@ public override void Initialize() SubscribeLocalEvent>(OnAlternativeVerb); SubscribeLocalEvent(OnOpenUi); SubscribeLocalEvent(OnRemoveBattery); - SubscribeLocalEvent(OnMechEntry); SubscribeLocalEvent(OnMechExit); + SubscribeLocalEvent(OnTurnLightsEvent); + SubscribeLocalEvent(OnMechEntry); - SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnEmpPulse); SubscribeLocalEvent(OnRemoveEquipmentMessage); + SubscribeLocalEvent(OnDamageModify); + SubscribeLocalEvent(OnEquipmentDestroyed); SubscribeLocalEvent(OnMechCanMoveEvent); SubscribeLocalEvent(OnToolUseAttempt); - SubscribeLocalEvent(OnInhale); + SubscribeLocalEvent(OnToggleInhale); SubscribeLocalEvent(OnExhale); SubscribeLocalEvent(OnExpose); @@ -105,7 +118,6 @@ private void OnInteractUsing(EntityUid uid, MechComponent component, InteractUsi _doAfter.TryStartDoAfter(doAfterEventArgs); } } - private void OnInsertBattery(EntityUid uid, MechComponent component, EntInsertedIntoContainerMessage args) { if (args.Container != component.BatterySlot || !TryComp(args.Entity, out var battery)) @@ -114,10 +126,30 @@ private void OnInsertBattery(EntityUid uid, MechComponent component, EntInserted component.Energy = battery.CurrentCharge; component.MaxEnergy = battery.MaxCharge; - Dirty(component); + Dirty(uid, component); _actionBlocker.UpdateCanMove(uid); } + private void OnMechEntry(EntityUid uid, MechComponent component, MechEntryEvent args) + { + if (args.Cancelled || args.Handled) + return; + + if (component.PilotWhitelist != null && !component.PilotWhitelist.IsValid(args.User)) + { + _popup.PopupEntity(Loc.GetString("mech-no-enter", ("item", uid)), args.User); + return; + } + if (TryComp(uid, out var accesscomponent) && !_accessReader.IsAllowed(args.User, uid, accesscomponent)) + { + _popup.PopupEntity(Loc.GetString("gateway-access-denied"), args.User); + _audio.PlayPvs(component.AccessDeniedSound, uid); + return; + } + TryInsert(uid, args.Args.User, component); + _actionBlocker.UpdateCanMove(uid); + args.Handled = true; + } private void OnRemoveBattery(EntityUid uid, MechComponent component, RemoveBatteryEvent args) { if (args.Cancelled || args.Handled) @@ -144,9 +176,12 @@ private void OnMapInit(EntityUid uid, MechComponent component, MapInitEvent args component.Energy = component.MaxEnergy; _actionBlocker.UpdateCanMove(uid); - Dirty(component); + Dirty(uid, component); + } + private void OnDamageModify(EntityUid uid, MechComponent component, DamageModifyEvent args) + { + args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, component.Modifiers); } - private void OnRemoveEquipmentMessage(EntityUid uid, MechComponent component, MechEquipmentRemoveMessage args) { var equip = GetEntity(args.Equipment); @@ -227,22 +262,6 @@ private void OnAlternativeVerb(EntityUid uid, MechComponent component, GetVerbsE } } - private void OnMechEntry(EntityUid uid, MechComponent component, MechEntryEvent args) - { - if (args.Cancelled || args.Handled) - return; - - if (component.PilotWhitelist != null && !component.PilotWhitelist.IsValid(args.User)) - { - _popup.PopupEntity(Loc.GetString("mech-no-enter", ("item", uid)), args.User); - return; - } - - TryInsert(uid, args.Args.User, component); - _actionBlocker.UpdateCanMove(uid); - - args.Handled = true; - } private void OnMechExit(EntityUid uid, MechComponent component, MechExitEvent args) { @@ -254,20 +273,30 @@ private void OnMechExit(EntityUid uid, MechComponent component, MechExitEvent ar args.Handled = true; } - private void OnDamageChanged(EntityUid uid, MechComponent component, DamageChangedEvent args) + private void OnTurnLightsEvent(EntityUid uid, MechComponent component, MechTurnLightsEvent args) { - var integrity = component.MaxIntegrity - args.Damageable.TotalDamage; - SetIntegrity(uid, integrity, component); - - if (args.DamageIncreased && - args.DamageDelta != null && - component.PilotSlot.ContainedEntity != null) + if (HasComp(uid)) + { + RemComp(uid); + _audio.PlayPvs(component.MechLightsOffSound, uid); + } + else { - var damage = args.DamageDelta * component.MechToPilotDamageMultiplier; - _damageable.TryChangeDamage(component.PilotSlot.ContainedEntity, damage); + AddComp(uid); + _audio.PlayPvs(component.MechLightsOnSound, uid); } } + private void OnEquipmentDestroyed(EntityUid uid, MechComponent component, MechEquipmentDestroyedEvent args) + { + Spawn("EffectSparks", Transform(uid).Coordinates); + QueueDel(component.CurrentSelectedEquipment); + _audio.PlayPvs(component.EquipmentDestroyedSound, uid); + } + private void OnEmpPulse(EntityUid uid, MechComponent comp, ref EmpPulseEvent args) + { + TryChangeEnergy(uid, -FixedPoint2.Min(comp.Energy, comp.EMPDamage), comp); + } private void ToggleMechUi(EntityUid uid, MechComponent? component = null, EntityUid? user = null) { if (!Resolve(uid, ref component)) @@ -345,7 +374,7 @@ public override bool TryChangeEnergy(EntityUid uid, FixedPoint2 delta, MechCompo { _sawmill.Debug($"Battery charge was not equal to mech charge. Battery {batteryComp.CurrentCharge}. Mech {component.Energy}"); component.Energy = batteryComp.CurrentCharge; - Dirty(component); + Dirty(uid, component); } _actionBlocker.UpdateCanMove(uid); return true; @@ -365,7 +394,7 @@ public void InsertBattery(EntityUid uid, EntityUid toInsert, MechComponent? comp _actionBlocker.UpdateCanMove(uid); - Dirty(component); + Dirty(uid, component); UpdateUserInterface(uid, component); } @@ -380,21 +409,19 @@ public void RemoveBattery(EntityUid uid, MechComponent? component = null) _actionBlocker.UpdateCanMove(uid); - Dirty(component); + Dirty(uid, component); UpdateUserInterface(uid, component); } #region Atmos Handling - private void OnInhale(EntityUid uid, MechPilotComponent component, InhaleLocationEvent args) + private void OnToggleInhale(EntityUid uid, MechComponent component, MechInhaleEvent args) { - if (!TryComp(component.Mech, out var mech) || - !TryComp(component.Mech, out var mechAir)) + if (component.Airtight) { + component.Airtight = false; return; } - - if (mech.Airtight) - args.Gas = mechAir.Air; + component.Airtight = true; } private void OnExhale(EntityUid uid, MechPilotComponent component, ExhaleLocationEvent args) diff --git a/Content.Server/Projectiles/ProjectileSystem.cs b/Content.Server/Projectiles/ProjectileSystem.cs index 0061b16e47c..7234e50a0b0 100644 --- a/Content.Server/Projectiles/ProjectileSystem.cs +++ b/Content.Server/Projectiles/ProjectileSystem.cs @@ -41,6 +41,11 @@ private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref St return; } + var hitAttempt = new ProjectileHitAttemptEvent(component.Damage, target, component.Shooter); + RaiseLocalEvent(target, hitAttempt); + if (hitAttempt.Cancelled) + return; + var ev = new ProjectileHitEvent(component.Damage, target, component.Shooter); RaiseLocalEvent(uid, ref ev); diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index b8f8f122111..bd9b210bc48 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -198,9 +198,20 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? for (var reflectAttempt = 0; reflectAttempt < 3; reflectAttempt++) { var ray = new CollisionRay(from.Position, dir, hitscan.CollisionMask); - var rayCastResults = - Physics.IntersectRay(from.MapId, ray, hitscan.MaxLength, lastUser, false).ToList(); - if (!rayCastResults.Any()) + var rayCastResults = new List(); + + foreach (var rayCastResult in Physics.IntersectRay(from.MapId, ray, hitscan.MaxLength, lastUser, false)) + { + var attemptEvent = new HitScanHitAttemptEvent(user, rayCastResult.HitEntity, gunUid); + RaiseLocalEvent(rayCastResult.HitEntity, attemptEvent); + + if (attemptEvent.Cancelled) + continue; + + rayCastResults.Add(rayCastResult); + } + + if (rayCastResults.Count == 0) break; var result = rayCastResults[0]; diff --git a/Content.Server/_TornadoTech/FriendlyFire/Actions/FriendlyFireToggleableComponent.cs b/Content.Server/_TornadoTech/FriendlyFire/Actions/FriendlyFireToggleableComponent.cs new file mode 100644 index 00000000000..f1843680c7a --- /dev/null +++ b/Content.Server/_TornadoTech/FriendlyFire/Actions/FriendlyFireToggleableComponent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Prototypes; + +namespace Content.Server._TornadoTech.FriendlyFire.Actions; + +[RegisterComponent] +public sealed partial class FriendlyFireToggleableComponent : Component +{ + [DataField] + public EntProtoId Prototype = "ActionToggleFriendlyFire"; + + [DataField] + public EntityUid? Action; +} diff --git a/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireComponent.cs b/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireComponent.cs new file mode 100644 index 00000000000..aacc5c37103 --- /dev/null +++ b/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireComponent.cs @@ -0,0 +1,8 @@ +namespace Content.Server._TornadoTech.FriendlyFire; + +[RegisterComponent] +public sealed partial class FriendlyFireComponent : Component +{ + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool Enabled; +} diff --git a/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireSystem.Toggleable.cs b/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireSystem.Toggleable.cs new file mode 100644 index 00000000000..7320e250fce --- /dev/null +++ b/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireSystem.Toggleable.cs @@ -0,0 +1,42 @@ +using Content.Server._TornadoTech.FriendlyFire.Actions; +using Content.Server.Actions; +using Content.Shared.Toggleable; + +namespace Content.Server._TornadoTech.FriendlyFire; + +public sealed partial class FriendlyFireSystem +{ + [Dependency] private readonly ActionsSystem _actions = default!; + + private void ToggleableInitialize() + { + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnRemove); + SubscribeLocalEvent(OnToggleAction); + } + + private void OnStartup(Entity toggleable, ref ComponentStartup args) + { + toggleable.Comp.Action = _actions.AddAction(toggleable, toggleable.Comp.Prototype); + _actions.SetToggled(toggleable.Comp.Action, GetState(toggleable)); + } + + private void OnRemove(Entity toggleable, ref ComponentRemove args) + { + if (toggleable.Comp.Action is not { } action) + return; + + _actions.RemoveAction(toggleable, action); + } + + private void OnToggleAction(Entity toggleable, ref ToggleActionEvent args) + { + if (args.Handled) + return; + + Toggle(toggleable); + _actions.SetToggled(toggleable.Comp.Action, GetState(toggleable)); + + args.Handled = true; + } +} diff --git a/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireSystem.cs b/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireSystem.cs new file mode 100644 index 00000000000..3c54403789b --- /dev/null +++ b/Content.Server/_TornadoTech/FriendlyFire/FriendlyFireSystem.cs @@ -0,0 +1,101 @@ +using Content.Server.NPC.Components; +using Content.Server.NPC.Systems; +using Content.Shared.Projectiles; +using Content.Shared.Weapons.Ranged.Events; + +namespace Content.Server._TornadoTech.FriendlyFire; + +public sealed partial class FriendlyFireSystem : EntitySystem +{ + [Dependency] private readonly NpcFactionSystem _faction = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHitProjectileAttempt); + SubscribeLocalEvent(OnHitHitScanAttempt); + + ToggleableInitialize(); + } + + private void OnHitProjectileAttempt(Entity friendlyFire, ref ProjectileHitAttemptEvent args) + { + if (HitAttempt(friendlyFire, args.Shooter)) + return; + + args.Cancel(); + } + + private void OnHitHitScanAttempt(Entity friendlyFire, ref HitScanHitAttemptEvent args) + { + if (HitAttempt(friendlyFire, args.Shooter)) + return; + + args.Cancel(); + } + + private bool HitAttempt(Entity friendlyFire, EntityUid? shooter) + { + return shooter is { } uid && HitAttempt(friendlyFire, uid); + } + + private bool HitAttempt(Entity friendlyFire, EntityUid shooter) + { + if (!TryComp(shooter, out var shooterFriendlyFire)) + return true; + + if (!shooterFriendlyFire.Enabled) + return true; + + if (!TryComp(shooter, out var factionShooter)) + return true; + + if (!TryComp(friendlyFire, out var faction)) + return true; + + if (!_faction.IsEntityFriendly(friendlyFire, shooter, faction, factionShooter)) + return true; + + return false; + } + + public void Toggle(EntityUid uid) + { + if (!TryComp(uid, out var friendlyFire)) + return; + + Toggle((uid, friendlyFire)); + } + + public void Toggle(Entity friendlyFire) + { + SetState(friendlyFire, !friendlyFire.Comp.Enabled); + } + + public void SetState(EntityUid uid, bool state) + { + if (!TryComp(uid, out var friendlyFire)) + return; + + SetState((uid, friendlyFire), state); + } + + public void SetState(Entity friendlyFire, bool state) + { + friendlyFire.Comp.Enabled = state; + } + + public bool GetState(EntityUid uid) + { + if (!TryComp(uid, out var friendlyFire)) + return false; + + return friendlyFire.Enabled; + } + + public bool GetState(Entity friendlyFire) + { + return friendlyFire.Comp.Enabled; + } +} diff --git a/Content.Shared/Mech/Components/MechComponent.cs b/Content.Shared/Mech/Components/MechComponent.cs index d63de91d89c..db98fc26cd5 100644 --- a/Content.Shared/Mech/Components/MechComponent.cs +++ b/Content.Shared/Mech/Components/MechComponent.cs @@ -3,6 +3,7 @@ using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; +using Robust.Shared.Audio; using Content.Shared.Damage; namespace Content.Shared.Mech.Components; @@ -15,15 +16,47 @@ namespace Content.Shared.Mech.Components; public sealed partial class MechComponent : Component { /// - /// damage modifiers on hit + /// sound if access denied /// - [DataField(required: true)] - public DamageModifierSet Modifiers = default!; + [DataField("accessDeniedSound")] + public SoundSpecifier AccessDeniedSound = new SoundPathSpecifier("/Audio/Machines/Nuke/angry_beep.ogg"); + /// + /// sound on equipment destroyed + /// + [DataField] + public SoundSpecifier EquipmentDestroyedSound = new SoundCollectionSpecifier("MetalBreak"); + /// + /// sound on entry mech + /// + [DataField("mechentrysound")] + public SoundSpecifier MechEntrySound = new SoundPathSpecifier("/Audio/Mecha/nominal.ogg"); + /// + /// sound on turn lights + /// + [DataField("mechlightoffsound")] + public SoundSpecifier MechLightsOnSound = new SoundPathSpecifier("/Audio/Mecha/mechlignton.ogg"); + [DataField("mechlightonsound")] + public SoundSpecifier MechLightsOffSound = new SoundPathSpecifier("/Audio/Mecha/mechlightoff.ogg"); + /// + /// sound on destroy equipment + /// + [DataField("mechequipmentdestr")] + public SoundSpecifier MechEquipmentDestr = new SoundPathSpecifier("/Audio/Mecha/weapdestr.ogg"); /// /// How much "health" the mech has left. /// [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public FixedPoint2 Integrity; + /// + /// How much "health" the mech need to destroy equipment. + /// + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public FixedPoint2 DamageToDesEqi = 75; + /// + /// How much "health" the mech has left. + /// + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public float EMPDamage = 700; /// /// The maximum amount of damage the mech can take. @@ -37,7 +70,11 @@ public sealed partial class MechComponent : Component /// [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public FixedPoint2 Energy = 0; - + /// + /// damage modifiers on hit + /// + [DataField(required: true)] + public DamageModifierSet Modifiers = default!; /// /// The maximum amount of energy the mech can have. /// Derived from the currently inserted battery. @@ -60,7 +97,12 @@ public sealed partial class MechComponent : Component /// [DataField, ViewVariables(VVAccess.ReadWrite)] public float MechToPilotDamageMultiplier; - + /// + /// A multiplier used to calculate how much of the damage done to a mech + /// is transfered to the pilot + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float MechEnergyWaste = 10; /// /// Whether the mech has been destroyed and is no longer pilotable. /// @@ -112,7 +154,11 @@ public sealed partial class MechComponent : Component /// [DataField, ViewVariables(VVAccess.ReadWrite)] public float EntryDelay = 3; - + /// + /// How long it takes to enter the mech. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool LightsToggle = false; /// /// How long it takes to pull *another person* /// outside of the mech. You can exit instantly yourself. @@ -150,6 +196,8 @@ public sealed partial class MechComponent : Component public EntProtoId MechUiAction = "ActionMechOpenUI"; [DataField] public EntProtoId MechEjectAction = "ActionMechEject"; + public EntProtoId MechTurnLightsAction = "ActionMechTurnLights"; + public EntProtoId MechInhaleAction = "ActionMechInhale"; #endregion #region Visualizer States @@ -164,4 +212,6 @@ public sealed partial class MechComponent : Component [DataField] public EntityUid? MechCycleActionEntity; [DataField] public EntityUid? MechUiActionEntity; [DataField] public EntityUid? MechEjectActionEntity; + [DataField] public EntityUid? MechInhaleActionEntity; + [DataField] public EntityUid? MechTurnLightsActionEntity; } diff --git a/Content.Shared/Mech/Components/MechOverloadComponent.cs b/Content.Shared/Mech/Components/MechOverloadComponent.cs new file mode 100644 index 00000000000..557bde5641b --- /dev/null +++ b/Content.Shared/Mech/Components/MechOverloadComponent.cs @@ -0,0 +1,31 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Audio; +using Content.Shared.Damage; +using Content.Shared.FixedPoint; + +namespace Content.Shared.Mech.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class MechOverloadComponent : Component +{ + [DataField] public EntityUid? MechOverloadActionEntity; + public EntProtoId MechOverloadAction = "ActionMechOverload"; + public bool Overload = false; + /// + /// damage every x seconds if mech overloaded. + /// + + [DataField("damage", required: true)] + [ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier DamagePerSpeed = default!; + /// + /// How much "health" the mech has left. + /// + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public FixedPoint2 MinIng; + [DataField(required: true), AutoNetworkedField] + public SoundSpecifier FootstepSoundOverload = default!; + [DataField(required: true), AutoNetworkedField] + public SoundSpecifier FootstepSoundNormal = default!; +} diff --git a/Content.Shared/Mech/EntitySystems/MechOverloadSystem.cs b/Content.Shared/Mech/EntitySystems/MechOverloadSystem.cs new file mode 100644 index 00000000000..688664ed9d4 --- /dev/null +++ b/Content.Shared/Mech/EntitySystems/MechOverloadSystem.cs @@ -0,0 +1,80 @@ +using Content.Shared.Actions; +using Content.Shared.Mech.Components; +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Systems; +using Content.Shared.Damage; +using Content.Shared.Destructible; + +namespace Content.Shared.Mech.EntitySystems; + +/// +/// Handles all of the interactions, UI handling, and items shennanigans for +/// +public sealed class MechOverloadSystem : EntitySystem +{ + private float _timer; + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!; + /// + public override void Initialize() + { + SubscribeLocalEvent(OnToggleOverload); + SubscribeLocalEvent(OnDamage); + } + + private void OnToggleOverload(EntityUid uid, MechOverloadComponent comp, MechOverloadEvent args) + { + var movementSpeed = EnsureComp(uid); + if (!TryComp(uid, out var mech)) + return; + if (mech.Integrity <= comp.MinIng) + return; + if (comp.Overload == false) + { + _movementSpeedModifierSystem?.ChangeBaseSpeed(uid, 6, 6, 40, movementSpeed); + mech.MechEnergyWaste += 20; + comp.Overload = true; + Spawn("EffectSparks", Transform(uid).Coordinates); + _damageable.TryChangeDamage(uid, comp.DamagePerSpeed, ignoreResistances: true); + } + else + { + _movementSpeedModifierSystem?.ChangeBaseSpeed(uid, 3, 4, 40, movementSpeed); + mech.MechEnergyWaste -= 20; + comp.Overload = false; + } + } + private void OnDamage(EntityUid uid, MechOverloadComponent component, DamageChangedEvent args) + { + var movementSpeed = EnsureComp(uid); + if (!TryComp(uid, out var mech)) + return; + if (mech.Integrity > component.MinIng) + return; + _movementSpeedModifierSystem?.ChangeBaseSpeed(uid, 3, 4, 40, movementSpeed); + mech.MechEnergyWaste -= 20; + component.Overload = false; + } + public override void Update(float frameTime) + { + base.Update(frameTime); + _timer += frameTime; + if (_timer < 1) return; + _timer -= 1; + + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var overload, out var mech)) + { + if (overload.Overload) + { + _damageable.TryChangeDamage(uid, overload.DamagePerSpeed, ignoreResistances: true); + } + } + } +} + +public sealed partial class MechOverloadEvent : InstantActionEvent +{ +} + diff --git a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs index 7e44dea5078..6572535051f 100644 --- a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs +++ b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs @@ -19,6 +19,10 @@ using Robust.Shared.Network; using Robust.Shared.Serialization; using Robust.Shared.Timing; +using Robust.Shared.Audio.Systems; +using Content.Shared.Access.Systems; +using Content.Shared.Damage; +using Robust.Shared.Random; namespace Content.Shared.Mech.EntitySystems; @@ -27,6 +31,7 @@ namespace Content.Shared.Mech.EntitySystems; /// public abstract class SharedMechSystem : EntitySystem { + [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; @@ -37,7 +42,9 @@ public abstract class SharedMechSystem : EntitySystem [Dependency] private readonly SharedMoverController _mover = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; - + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly AccessReaderSystem _accessReader = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; /// public override void Initialize() { @@ -49,6 +56,7 @@ public override void Initialize() SubscribeLocalEvent(OnGetAdditionalAccess); SubscribeLocalEvent(OnDragDrop); SubscribeLocalEvent(OnCanDragDrop); + SubscribeLocalEvent(OnDamageChanged); SubscribeLocalEvent(OnGetMeleeWeapon); SubscribeLocalEvent(OnCanAttackFromContainer); @@ -99,7 +107,17 @@ private void OnDestruction(EntityUid uid, MechComponent component, DestructionEv { BreakMech(uid, component); } + private void OnDamageChanged(EntityUid uid, MechComponent component, DamageChangedEvent args) + { + var integrity = component.MaxIntegrity - args.Damageable.TotalDamage; + SetIntegrity(uid, integrity, component); + if (component.Integrity <= component.DamageToDesEqi && !component.Broken && _random.Prob(0.5f) && component.CurrentSelectedEquipment != null) + { + var ev = new MechEquipmentDestroyedEvent(); + RaiseLocalEvent(uid, ev); + } + } private void OnGetAdditionalAccess(EntityUid uid, MechComponent component, ref GetAdditionalAccessEvent args) { var pilot = component.PilotSlot.ContainedEntity; @@ -130,6 +148,10 @@ private void SetupUser(EntityUid mech, EntityUid pilot, MechComponent? component _actions.AddAction(pilot, ref component.MechCycleActionEntity, component.MechCycleAction, mech); _actions.AddAction(pilot, ref component.MechUiActionEntity, component.MechUiAction, mech); _actions.AddAction(pilot, ref component.MechEjectActionEntity, component.MechEjectAction, mech); + _actions.AddAction(pilot, ref component.MechInhaleActionEntity, component.MechInhaleAction, mech); + _actions.AddAction(pilot, ref component.MechTurnLightsActionEntity, component.MechTurnLightsAction, mech); + if (TryComp(mech, out var overload)) + _actions.AddAction(pilot, ref overload.MechOverloadActionEntity, overload.MechOverloadAction, mech); } private void RemoveUser(EntityUid mech, EntityUid pilot) @@ -186,7 +208,13 @@ public void CycleEquipment(EntityUid uid, MechComponent? component = null) component.CurrentSelectedEquipment = equipmentIndex >= allEquipment.Count ? null : allEquipment[equipmentIndex]; - + while (TryComp(component.CurrentSelectedEquipment, out var equipment) && equipment.CanBeUsed == false) + { + equipmentIndex++; + component.CurrentSelectedEquipment = equipmentIndex >= allEquipment.Count + ? null + : allEquipment[equipmentIndex]; + } var popupString = component.CurrentSelectedEquipment != null ? Loc.GetString("mech-equipment-select-popup", ("item", component.CurrentSelectedEquipment)) : Loc.GetString("mech-equipment-select-none-popup"); @@ -194,7 +222,7 @@ public void CycleEquipment(EntityUid uid, MechComponent? component = null) if (_net.IsServer) _popup.PopupEntity(popupString, uid); - Dirty(component); + Dirty(uid, component); } /// @@ -278,7 +306,7 @@ public virtual bool TryChangeEnergy(EntityUid uid, FixedPoint2 delta, MechCompon return false; component.Energy = FixedPoint2.Clamp(component.Energy + delta, 0, component.MaxEnergy); - Dirty(component); + Dirty(uid, component); UpdateUserInterface(uid, component); return true; } @@ -306,7 +334,7 @@ public void SetIntegrity(EntityUid uid, FixedPoint2 value, MechComponent? compon UpdateAppearance(uid, component); } - Dirty(component); + Dirty(uid, component); UpdateUserInterface(uid, component); } diff --git a/Content.Shared/Mech/Equipment/Components/MechEquipmentComponent.cs b/Content.Shared/Mech/Equipment/Components/MechEquipmentComponent.cs index 3933f122847..1daf4e9b758 100644 --- a/Content.Shared/Mech/Equipment/Components/MechEquipmentComponent.cs +++ b/Content.Shared/Mech/Equipment/Components/MechEquipmentComponent.cs @@ -19,6 +19,7 @@ public sealed partial class MechEquipmentComponent : Component /// The mech that the equipment is inside of. /// [ViewVariables] public EntityUid? EquipmentOwner; + [DataField("canbeused")] public bool CanBeUsed = true; } /// diff --git a/Content.Shared/Mech/SharedMech.cs b/Content.Shared/Mech/SharedMech.cs index 94af4453d48..23b805ef971 100644 --- a/Content.Shared/Mech/SharedMech.cs +++ b/Content.Shared/Mech/SharedMech.cs @@ -60,3 +60,15 @@ public sealed partial class MechOpenUiEvent : InstantActionEvent public sealed partial class MechEjectPilotEvent : InstantActionEvent { } + +public sealed partial class MechInhaleEvent : InstantActionEvent +{ +} + +public sealed partial class MechTurnLightsEvent : InstantActionEvent +{ +} + +public sealed partial class MechEquipmentDestroyedEvent : InstantActionEvent +{ +} diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index f40a7a0363b..40e7593c249 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -188,3 +188,18 @@ public record struct ProjectileReflectAttemptEvent(EntityUid ProjUid, Projectile /// [ByRefEvent] public record struct ProjectileHitEvent(DamageSpecifier Damage, EntityUid Target, EntityUid? Shooter = null); + +public sealed class ProjectileHitAttemptEvent(DamageSpecifier damage, EntityUid target, EntityUid? shooter = null) + : CancellableEntityEventArgs +{ + public DamageSpecifier Damage { get; } = damage; + public EntityUid Target { get; } = target; + public EntityUid? Shooter { get; } = shooter; +} + +public sealed class HitScanHitAttemptEvent(EntityUid? shooter, EntityUid target, EntityUid sourceItem) : CancellableEntityEventArgs +{ + public readonly EntityUid? Shooter = shooter; + public readonly EntityUid Target = target; + public readonly EntityUid SourceItem = sourceItem; +} diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 76015b8f9df..a6c48c07363 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -11,7 +11,6 @@ using Content.Shared.Gravity; using Content.Shared.Hands; using Content.Shared.Hands.Components; -using Content.Shared.Mobs.Components; using Content.Shared.Popups; using Content.Shared.Projectiles; using Content.Shared.Tag; @@ -23,7 +22,6 @@ using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Network; @@ -34,28 +32,30 @@ using Robust.Shared.Serialization; using Robust.Shared.Timing; using Robust.Shared.Utility; +using Content.Shared.Mech.Components; +using Robust.Shared.Audio.Systems; namespace Content.Shared.Weapons.Ranged.Systems; public abstract partial class SharedGunSystem : EntitySystem { - [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] protected readonly IMapManager MapManager = default!; - [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly INetManager _netManager = default!; [Dependency] protected readonly IPrototypeManager ProtoManager = default!; [Dependency] protected readonly IRobustRandom Random = default!; [Dependency] protected readonly ISharedAdminLogManager Logs = default!; [Dependency] protected readonly DamageableSystem Damageable = default!; [Dependency] protected readonly ExamineSystemShared Examine = default!; - [Dependency] private readonly ItemSlotsSystem _slots = default!; - [Dependency] private readonly RechargeBasicEntityAmmoSystem _recharge = default!; + [Dependency] private readonly ItemSlotsSystem _slots = default!; + [Dependency] private readonly RechargeBasicEntityAmmoSystem _recharge = default!; [Dependency] protected readonly SharedActionsSystem Actions = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!; - [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; + [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; [Dependency] protected readonly SharedContainerSystem Containers = default!; - [Dependency] private readonly SharedGravitySystem _gravity = default!; + [Dependency] private readonly SharedGravitySystem _gravity = default!; [Dependency] protected readonly SharedPointLightSystem Lights = default!; [Dependency] protected readonly SharedPopupSystem PopupSystem = default!; [Dependency] protected readonly SharedPhysicsSystem Physics = default!; @@ -63,7 +63,7 @@ public abstract partial class SharedGunSystem : EntitySystem [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; [Dependency] protected readonly TagSystem TagSystem = default!; [Dependency] protected readonly ThrowingSystem ThrowingSystem = default!; - [Dependency] private readonly UseDelaySystem _useDelay = default!; + [Dependency] private readonly UseDelaySystem _useDelay = default!; private const float InteractNextFire = 0.3f; private const double SafetyNextFire = 0.5; @@ -122,20 +122,25 @@ private void OnGunMelee(EntityUid uid, GunComponent component, MeleeHitEvent arg } } + private void OnShootRequest(RequestShootEvent msg, EntitySessionEventArgs args) { var user = args.SenderSession.AttachedEntity; - if (user == null || - !_combatMode.IsInCombatMode(user) || - !TryGetGun(user.Value, out var ent, out var gun)) - { + if (user == null || !_combatMode.IsInCombatMode(user)) + return; + + if (!TryGetGun(user.Value, out var ent, out var gun)) return; - } if (ent != GetEntity(msg.Gun)) return; + if (TryComp(user.Value, out var mechPilot)) + { + user = mechPilot.Mech; + } + gun.ShootCoordinates = GetCoordinates(msg.Coordinates); Log.Debug($"Set shoot coordinates to {gun.ShootCoordinates}"); AttemptShoot(user.Value, ent, gun); @@ -143,16 +148,16 @@ private void OnShootRequest(RequestShootEvent msg, EntitySessionEventArgs args) private void OnStopShootRequest(RequestStopShootEvent ev, EntitySessionEventArgs args) { + var user = args.SenderSession.AttachedEntity; var gunUid = GetEntity(ev.Gun); - if (args.SenderSession.AttachedEntity == null || - !TryComp(gunUid, out var gun) || - !TryGetGun(args.SenderSession.AttachedEntity.Value, out _, out var userGun)) - { + if (user == null || !_combatMode.IsInCombatMode(user)) return; - } - if (userGun != gun) + if (TryComp(user.Value, out var mechPilot)) + user = mechPilot.Mech; + + if (!TryGetGun(user.Value, out var ent, out var gun)) return; StopShooting(gunUid, gun); @@ -180,15 +185,16 @@ hands.ActiveHandEntity is { } held && return true; } - /// ADT gloves gun start - if (_inventory.TryGetSlotEntity(entity, "gloves", out var gloves) && - TryComp(gloves, out var glovesMelee)) + if (TryComp(entity, out var mechPilot) && + TryComp(mechPilot.Mech, out var mech) && + mech.CurrentSelectedEquipment.HasValue && + TryComp(mech.CurrentSelectedEquipment.Value, out var mechGun)) { - gunEntity = gloves.Value; - gunComp = glovesMelee; + gunEntity = mech.CurrentSelectedEquipment.Value; + gunComp = mechGun; return true; } - /// ADT gloves gun end + // Last resort is check if the entity itself is a gun. if (TryComp(entity, out gun)) { @@ -197,6 +203,7 @@ hands.ActiveHandEntity is { } held && return true; } + return false; } @@ -237,20 +244,6 @@ private void AttemptShoot(EntityUid user, EntityUid gunUid, GunComponent gun) if (gun.FireRateModified <= 0f || !_actionBlockerSystem.CanAttack(user)) return; - ///ADT-Personal-Gun block start - if (gun.Personable) - { - if (gun.GunOwner?.Id != user.Id) - return; - } - ///ADT-Personal-Gun block end - - /// ADT gloves gun start - if (EntityManager.TryGetComponent(user, out HandsComponent? hands) && hands != null && hands.ActiveHandEntity != null && _inventory.TryGetSlotEntity(user, "gloves", out var gloves) && gloves.Value == gunUid) - { - return; - } - /// ADT gloves gun end var toCoordinates = gun.ShootCoordinates; @@ -429,7 +422,7 @@ public void ShootProjectile(EntityUid uid, Vector2 direction, Vector2 gunVelocit /// /// Call this whenever the ammo count for a gun changes. /// - protected virtual void UpdateAmmoCount(EntityUid uid, bool prediction = true) {} + protected virtual void UpdateAmmoCount(EntityUid uid, bool prediction = true) { } protected void SetCartridgeSpent(EntityUid uid, CartridgeAmmoComponent cartridge, bool spent) { @@ -508,7 +501,7 @@ public void CauseImpulse(EntityCoordinates fromCoordinates, EntityCoordinates to var shotDirection = (toMap - fromMap).Normalized(); const float impulseStrength = 25.0f; - var impulseVector = shotDirection * impulseStrength; + var impulseVector = shotDirection * impulseStrength; Physics.ApplyLinearImpulse(user, -impulseVector, body: userPhysics); } diff --git a/Resources/Prototypes/Maps/Pools/default.yml b/Resources/Prototypes/Maps/Pools/default.yml index 1e5e14891d3..7a67b08127e 100644 --- a/Resources/Prototypes/Maps/Pools/default.yml +++ b/Resources/Prototypes/Maps/Pools/default.yml @@ -15,8 +15,8 @@ # - Saltern # - Packed #- Reach - # - CorvaxDelta - - CorvaxAvrite + - CorvaxDelta + # - CorvaxAvrite - ADTAtlas - ADTBagel - ADTBox