fix reflected projectiles dealing stamina damage (#17648)

This commit is contained in:
Slava0135
2023-08-06 16:44:41 +03:00
committed by GitHub
parent c6f80b2efb
commit b49f0df05e
5 changed files with 46 additions and 54 deletions

View File

@@ -31,55 +31,52 @@ public sealed class ProjectileSystem : SharedProjectileSystem
if (args.OurFixture.ID != ProjectileFixture || !args.OtherFixture.Hard || component.DamagedEntity) if (args.OurFixture.ID != ProjectileFixture || !args.OtherFixture.Hard || component.DamagedEntity)
return; return;
var otherEntity = args.OtherEntity; var target = args.OtherEntity;
// it's here so this check is only done once before possible hit // it's here so this check is only done once before possible hit
var attemptEv = new ProjectileReflectAttemptEvent(uid, component, false); var attemptEv = new ProjectileReflectAttemptEvent(uid, component, false);
RaiseLocalEvent(otherEntity, ref attemptEv); RaiseLocalEvent(target, ref attemptEv);
if (attemptEv.Cancelled) if (attemptEv.Cancelled)
{ {
SetShooter(component, otherEntity); SetShooter(component, target);
return; return;
} }
var otherName = ToPrettyString(otherEntity); var ev = new ProjectileHitEvent(target);
RaiseLocalEvent(uid, ref ev);
var otherName = ToPrettyString(target);
var direction = args.OurBody.LinearVelocity.Normalized(); var direction = args.OurBody.LinearVelocity.Normalized();
var modifiedDamage = _damageableSystem.TryChangeDamage(otherEntity, component.Damage, component.IgnoreResistances, origin: component.Shooter); var modifiedDamage = _damageableSystem.TryChangeDamage(target, component.Damage, component.IgnoreResistances, origin: component.Shooter);
var deleted = Deleted(otherEntity); var deleted = Deleted(target);
if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter)) if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter))
{ {
if (modifiedDamage.Total > FixedPoint2.Zero && !deleted) if (modifiedDamage.Total > FixedPoint2.Zero && !deleted)
{ {
RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Red, new List<EntityUid> { otherEntity }), Filter.Pvs(otherEntity, entityManager: EntityManager)); RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Red, new List<EntityUid> { target }), Filter.Pvs(target, entityManager: EntityManager));
} }
_adminLogger.Add(LogType.BulletHit, _adminLogger.Add(LogType.BulletHit,
HasComp<ActorComponent>(otherEntity) ? LogImpact.Extreme : LogImpact.High, HasComp<ActorComponent>(target) ? LogImpact.Extreme : LogImpact.High,
$"Projectile {ToPrettyString(uid):projectile} shot by {ToPrettyString(component.Shooter):user} hit {otherName:target} and dealt {modifiedDamage.Total:damage} damage"); $"Projectile {ToPrettyString(uid):projectile} shot by {ToPrettyString(component.Shooter):user} hit {otherName:target} and dealt {modifiedDamage.Total:damage} damage");
} }
if (!deleted) if (!deleted)
{ {
_guns.PlayImpactSound(otherEntity, modifiedDamage, component.SoundHit, component.ForceSound); _guns.PlayImpactSound(target, modifiedDamage, component.SoundHit, component.ForceSound);
_sharedCameraRecoil.KickCamera(otherEntity, direction); _sharedCameraRecoil.KickCamera(target, direction);
} }
var ev = new ProjectileCollideEvent(uid, false); component.DamagedEntity = true;
RaiseLocalEvent(args.OtherEntity, ref ev);
if (!ev.Cancelled) if (component.DeleteOnCollide)
{ {
component.DamagedEntity = true; QueueDel(uid);
}
if (component.DeleteOnCollide) if (component.ImpactEffect != null && TryComp<TransformComponent>(uid, out var xform))
{ {
QueueDel(uid); RaiseNetworkEvent(new ImpactEffectEvent(component.ImpactEffect, xform.Coordinates), Filter.Pvs(xform.Coordinates, entityMan: EntityManager));
}
if (component.ImpactEffect != null && TryComp<TransformComponent>(uid, out var xform))
{
RaiseNetworkEvent(new ImpactEffectEvent(component.ImpactEffect, xform.Coordinates), Filter.Pvs(xform.Coordinates, entityMan: EntityManager));
}
} }
} }
} }

View File

@@ -7,13 +7,13 @@ using Content.Shared.Damage.Events;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Projectiles;
using Content.Shared.Rejuvenate; using Content.Shared.Rejuvenate;
using Content.Shared.Rounding; using Content.Shared.Rounding;
using Content.Shared.Stunnable; using Content.Shared.Stunnable;
using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Melee.Events;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
@@ -31,8 +31,6 @@ public sealed partial class StaminaSystem : EntitySystem
[Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!;
private const string CollideFixture = "projectile";
/// <summary> /// <summary>
/// How much of a buffer is there between the stun duration and when stuns can be re-applied. /// How much of a buffer is there between the stun duration and when stuns can be re-applied.
/// </summary> /// </summary>
@@ -52,7 +50,7 @@ public sealed partial class StaminaSystem : EntitySystem
SubscribeLocalEvent<StaminaComponent, DisarmedEvent>(OnDisarmed); SubscribeLocalEvent<StaminaComponent, DisarmedEvent>(OnDisarmed);
SubscribeLocalEvent<StaminaComponent, RejuvenateEvent>(OnRejuvenate); SubscribeLocalEvent<StaminaComponent, RejuvenateEvent>(OnRejuvenate);
SubscribeLocalEvent<StaminaDamageOnCollideComponent, StartCollideEvent>(OnCollide); SubscribeLocalEvent<StaminaDamageOnCollideComponent, ProjectileHitEvent>(OnCollide);
SubscribeLocalEvent<StaminaDamageOnHitComponent, MeleeHitEvent>(OnHit); SubscribeLocalEvent<StaminaDamageOnHitComponent, MeleeHitEvent>(OnHit);
} }
@@ -144,7 +142,7 @@ public sealed partial class StaminaSystem : EntitySystem
return; return;
var damage = args.PushProbability * component.CritThreshold; var damage = args.PushProbability * component.CritThreshold;
TakeStaminaDamage(uid, damage, component, source:args.Source); TakeStaminaDamage(uid, damage, component, source: args.Source);
// We need a better method of getting if the entity is going to resist stam damage, both this and the lines in the foreach at the end of OnHit() are awful // We need a better method of getting if the entity is going to resist stam damage, both this and the lines in the foreach at the end of OnHit() are awful
if (!component.Critical) if (!component.Critical)
@@ -204,7 +202,7 @@ public sealed partial class StaminaSystem : EntitySystem
foreach (var (ent, comp) in toHit) foreach (var (ent, comp) in toHit)
{ {
var oldDamage = comp.StaminaDamage; var oldDamage = comp.StaminaDamage;
TakeStaminaDamage(ent, damage / toHit.Count, comp, source:args.User, with:args.Weapon); TakeStaminaDamage(ent, damage / toHit.Count, comp, source: args.User, with: args.Weapon);
if (comp.StaminaDamage.Equals(oldDamage)) if (comp.StaminaDamage.Equals(oldDamage))
{ {
_popup.PopupClient(Loc.GetString("stamina-resist"), ent, args.User); _popup.PopupClient(Loc.GetString("stamina-resist"), ent, args.User);
@@ -212,11 +210,9 @@ public sealed partial class StaminaSystem : EntitySystem
} }
} }
private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component, ref StartCollideEvent args) private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component, ref ProjectileHitEvent args)
{ {
if (!args.OurFixture.ID.Equals(CollideFixture)) return; TakeStaminaDamage(args.Target, component.Damage, source: uid);
TakeStaminaDamage(args.OtherEntity, component.Damage, source:args.OurEntity);
} }
private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null) private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null)
@@ -413,4 +409,4 @@ public sealed partial class StaminaSystem : EntitySystem
/// Raised before stamina damage is dealt to allow other systems to cancel it. /// Raised before stamina damage is dealt to allow other systems to cancel it.
/// </summary> /// </summary>
[ByRefEvent] [ByRefEvent]
public record struct BeforeStaminaDamageEvent(float Value, bool Cancelled=false); public record struct BeforeStaminaDamageEvent(float Value, bool Cancelled = false);

View File

@@ -1,7 +0,0 @@
namespace Content.Shared.Projectiles;
/// <summary>
/// Raised directed on what a projectile collides with. Can have its deletion cancelled.
/// </summary>
[ByRefEvent]
public record struct ProjectileCollideEvent(EntityUid OtherEntity, bool Cancelled);

View File

@@ -28,7 +28,7 @@ namespace Content.Shared.Projectiles
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<ProjectileComponent, PreventCollideEvent>(PreventCollision); SubscribeLocalEvent<ProjectileComponent, PreventCollideEvent>(PreventCollision);
SubscribeLocalEvent<EmbeddableProjectileComponent, ProjectileCollideEvent>(OnEmbedProjectileCollide); SubscribeLocalEvent<EmbeddableProjectileComponent, ProjectileHitEvent>(OnEmbedProjectileHit);
SubscribeLocalEvent<EmbeddableProjectileComponent, ThrowDoHitEvent>(OnEmbedThrowDoHit); SubscribeLocalEvent<EmbeddableProjectileComponent, ThrowDoHitEvent>(OnEmbedThrowDoHit);
SubscribeLocalEvent<EmbeddableProjectileComponent, ActivateInWorldEvent>(OnEmbedActivate); SubscribeLocalEvent<EmbeddableProjectileComponent, ActivateInWorldEvent>(OnEmbedActivate);
SubscribeLocalEvent<EmbeddableProjectileComponent, RemoveEmbeddedProjectileEvent>(OnEmbedRemove); SubscribeLocalEvent<EmbeddableProjectileComponent, RemoveEmbeddedProjectileEvent>(OnEmbedRemove);
@@ -80,14 +80,14 @@ namespace Content.Shared.Projectiles
Embed(uid, args.Target, component); Embed(uid, args.Target, component);
} }
private void OnEmbedProjectileCollide(EntityUid uid, EmbeddableProjectileComponent component, ref ProjectileCollideEvent args) private void OnEmbedProjectileHit(EntityUid uid, EmbeddableProjectileComponent component, ref ProjectileHitEvent args)
{ {
Embed(uid, args.OtherEntity, component); Embed(uid, args.Target, component);
// Raise a specific event for projectiles. // Raise a specific event for projectiles.
if (TryComp<ProjectileComponent>(uid, out var projectile)) if (TryComp<ProjectileComponent>(uid, out var projectile))
{ {
var ev = new ProjectileEmbedEvent(projectile.Shooter, projectile.Weapon, args.OtherEntity); var ev = new ProjectileEmbedEvent(projectile.Shooter, projectile.Weapon, args.Target);
RaiseLocalEvent(uid, ref ev); RaiseLocalEvent(uid, ref ev);
} }
} }
@@ -142,10 +142,16 @@ namespace Content.Shared.Projectiles
Coordinates = coordinates; Coordinates = coordinates;
} }
} }
}
/// <summary> /// <summary>
/// Raised when entity is just about to be hit with projectile but can reflect it /// Raised when entity is just about to be hit with projectile but can reflect it
/// </summary> /// </summary>
[ByRefEvent] [ByRefEvent]
public record struct ProjectileReflectAttemptEvent(EntityUid ProjUid, ProjectileComponent Component, bool Cancelled); public record struct ProjectileReflectAttemptEvent(EntityUid ProjUid, ProjectileComponent Component, bool Cancelled);
/// <summary>
/// Raised when projectile hits other entity
/// </summary>
[ByRefEvent]
public readonly record struct ProjectileHitEvent(EntityUid Target);
}

View File

@@ -38,21 +38,21 @@ public abstract class SharedReflectSystem : EntitySystem
SubscribeLocalEvent<HandsComponent, ProjectileReflectAttemptEvent>(OnHandReflectProjectile); SubscribeLocalEvent<HandsComponent, ProjectileReflectAttemptEvent>(OnHandReflectProjectile);
SubscribeLocalEvent<HandsComponent, HitScanReflectAttemptEvent>(OnHandsReflectHitscan); SubscribeLocalEvent<HandsComponent, HitScanReflectAttemptEvent>(OnHandsReflectHitscan);
SubscribeLocalEvent<ReflectComponent, ProjectileCollideEvent>(OnReflectCollide); SubscribeLocalEvent<ReflectComponent, ProjectileReflectAttemptEvent>(OnReflectCollide);
SubscribeLocalEvent<ReflectComponent, HitScanReflectAttemptEvent>(OnReflectHitscan); SubscribeLocalEvent<ReflectComponent, HitScanReflectAttemptEvent>(OnReflectHitscan);
SubscribeLocalEvent<ReflectComponent, GotEquippedEvent>(OnReflectEquipped); SubscribeLocalEvent<ReflectComponent, GotEquippedEvent>(OnReflectEquipped);
SubscribeLocalEvent<ReflectComponent, GotUnequippedEvent>(OnReflectUnequipped); SubscribeLocalEvent<ReflectComponent, GotUnequippedEvent>(OnReflectUnequipped);
} }
private void OnReflectCollide(EntityUid uid, ReflectComponent component, ref ProjectileCollideEvent args) private void OnReflectCollide(EntityUid uid, ReflectComponent component, ref ProjectileReflectAttemptEvent args)
{ {
if (args.Cancelled) if (args.Cancelled)
{ {
return; return;
} }
if (TryReflectProjectile(uid, args.OtherEntity, reflect: component)) if (TryReflectProjectile(uid, args.ProjUid, reflect: component))
args.Cancelled = true; args.Cancelled = true;
} }