Skip to content

Commit

Permalink
feat: proper mirror shield
Browse files Browse the repository at this point in the history
Signed-off-by: Remuchi <[email protected]>
  • Loading branch information
Remuchi committed Nov 22, 2024
1 parent 1975775 commit 07a8d44
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 173 deletions.
56 changes: 32 additions & 24 deletions Content.Server/Stunnable/Components/StunOnCollideComponent.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,40 @@
namespace Content.Server.Stunnable.Components
using Content.Server.Stunnable.Systems;
using Content.Shared.Whitelist;

namespace Content.Server.Stunnable.Components;

/// <summary>
/// Adds stun when it collides with an entity
/// </summary>
[RegisterComponent, Access(typeof(StunOnCollideSystem))]
public sealed partial class StunOnCollideComponent : Component
{
/// <summary>
/// Adds stun when it collides with an entity
/// </summary>
[RegisterComponent, Access(typeof(StunOnCollideSystem))]
public sealed partial class StunOnCollideComponent : Component
{
// TODO: Can probably predict this.
// TODO: Can probably predict this.

// See stunsystem for what these do
[DataField("stunAmount")]
public int StunAmount;
[DataField]
public TimeSpan StunAmount = TimeSpan.FromSeconds(5);

[DataField("knockdownAmount")]
public int KnockdownAmount;
[DataField]
public TimeSpan KnockdownAmount = TimeSpan.FromSeconds(5);

[DataField("slowdownAmount")]
public int SlowdownAmount;
[DataField]
public TimeSpan SlowdownAmount = TimeSpan.FromSeconds(10);

[DataField("walkSpeedMultiplier")]
public float WalkSpeedMultiplier = 1f;
[DataField]
public float WalkSpeedMultiplier = 1f;

[DataField("runSpeedMultiplier")]
public float RunSpeedMultiplier = 1f;
[DataField]
public float RunSpeedMultiplier = 1f;

/// <summary>
/// Fixture we track for the collision.
/// </summary>
[DataField("fixture")] public string FixtureID = "projectile";
}
/// <summary>
/// Fixture we track for the collision.
/// </summary>
[DataField]
public string FixtureId = "projectile";

/// <summary>
/// Entities excluded from collision check.
/// </summary>
[DataField]
public EntityWhitelist? Blacklist;
}
81 changes: 41 additions & 40 deletions Content.Server/Stunnable/Systems/StunOnCollideSystem.cs
Original file line number Diff line number Diff line change
@@ -1,50 +1,51 @@
using Content.Server.Stunnable.Components;
using Content.Shared.Standing;
using Content.Shared.StatusEffect;
using JetBrains.Annotations;
using Robust.Shared.Physics.Dynamics;
using Content.Shared.Throwing;
using Content.Shared.Whitelist;
using Robust.Shared.Physics.Events;

namespace Content.Server.Stunnable
namespace Content.Server.Stunnable.Systems;

[UsedImplicitly]
internal sealed class StunOnCollideSystem : EntitySystem
{
[UsedImplicitly]
internal sealed class StunOnCollideSystem : EntitySystem
[Dependency] private readonly StunSystem _stunSystem = default!;
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StunOnCollideComponent, StartCollideEvent>(HandleCollide);
SubscribeLocalEvent<StunOnCollideComponent, ThrowDoHitEvent>(HandleThrow);
}

private void TryDoCollideStun(Entity<StunOnCollideComponent> ent, EntityUid target)
{
[Dependency] private readonly StunSystem _stunSystem = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StunOnCollideComponent, StartCollideEvent>(HandleCollide);
SubscribeLocalEvent<StunOnCollideComponent, ThrowDoHitEvent>(HandleThrow);
}

private void TryDoCollideStun(EntityUid uid, StunOnCollideComponent component, EntityUid target)
{

if (EntityManager.TryGetComponent<StatusEffectsComponent>(target, out var status))
{
_stunSystem.TryStun(target, TimeSpan.FromSeconds(component.StunAmount), true, status);

_stunSystem.TryKnockdown(target, TimeSpan.FromSeconds(component.KnockdownAmount), true,
status);

_stunSystem.TrySlowdown(target, TimeSpan.FromSeconds(component.SlowdownAmount), true,
component.WalkSpeedMultiplier, component.RunSpeedMultiplier, status);
}
}
private void HandleCollide(EntityUid uid, StunOnCollideComponent component, ref StartCollideEvent args)
{
if (args.OurFixtureId != component.FixtureID)
return;

TryDoCollideStun(uid, component, args.OtherEntity);
}

private void HandleThrow(EntityUid uid, StunOnCollideComponent component, ThrowDoHitEvent args)
{
TryDoCollideStun(uid, component, args.Target);
}
if (!EntityManager.TryGetComponent<StatusEffectsComponent>(target, out var status) ||
ent.Comp.Blacklist is { } blacklist && _entityWhitelist.IsValid(blacklist, target))
return;

_stunSystem.TryStun(target, ent.Comp.StunAmount, true, status);
_stunSystem.TryKnockdown(target, ent.Comp.KnockdownAmount, true, status);

_stunSystem.TrySlowdown(
target,
ent.Comp.SlowdownAmount,
true,
ent.Comp.WalkSpeedMultiplier,
ent.Comp.RunSpeedMultiplier,
status);
}

private void HandleCollide(Entity<StunOnCollideComponent> ent, ref StartCollideEvent args)
{
if (args.OurFixtureId != ent.Comp.FixtureId)
return;

TryDoCollideStun(ent, args.OtherEntity);
}

private void HandleThrow(Entity<StunOnCollideComponent> ent, ref ThrowDoHitEvent args) =>
TryDoCollideStun(ent, args.Target);
}
46 changes: 22 additions & 24 deletions Content.Shared/Blocking/BlockingSystem.User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ private void OnParentChanged(EntityUid uid, BlockingUserComponent component, ref
UserStopBlocking(uid, component);
}

private void OnInsertAttempt(EntityUid uid, BlockingUserComponent component, ContainerGettingInsertedAttemptEvent args)
private void OnInsertAttempt(
EntityUid uid,
BlockingUserComponent component,
ContainerGettingInsertedAttemptEvent args
)
{
UserStopBlocking(uid, component);
}
Expand All @@ -42,32 +46,27 @@ private void OnAnchorChanged(EntityUid uid, BlockingUserComponent component, ref

private void OnUserDamageModified(EntityUid uid, BlockingUserComponent component, DamageModifyEvent args)
{
if (TryComp<BlockingComponent>(component.BlockingItem, out var blocking))
{
if (args.Damage.GetTotal() <= 0)
return;

// A shield should only block damage it can itself absorb. To determine that we need the Damageable component on it.
if (!TryComp<DamageableComponent>(component.BlockingItem, out var dmgComp))
return;
// A shield should only block damage it can itself absorb. To determine that we need the Damageable component on it.
if (!TryComp<BlockingComponent>(component.BlockingItem, out var blocking) || args.Damage.GetTotal() <= 0 ||
!TryComp<DamageableComponent>(component.BlockingItem, out var dmgComp))
return;

var blockFraction = blocking.IsBlocking ? blocking.ActiveBlockFraction : blocking.PassiveBlockFraction;
blockFraction = Math.Clamp(blockFraction, 0, 1);
_damageable.TryChangeDamage(component.BlockingItem, blockFraction * args.OriginalDamage);
var ev = new BeforeBlockingEvent(uid, args.Origin);
RaiseLocalEvent(component.BlockingItem.Value, ev);
if (ev.Cancelled)
return;

var modify = new DamageModifierSet();
foreach (var key in dmgComp.Damage.DamageDict.Keys)
{
modify.Coefficients.TryAdd(key, 1 - blockFraction);
}
var blockFraction = blocking.IsBlocking ? blocking.ActiveBlockFraction : blocking.PassiveBlockFraction;
blockFraction = Math.Clamp(blockFraction, 0, 1);
_damageable.TryChangeDamage(component.BlockingItem, blockFraction * args.OriginalDamage);

args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, modify);
var modify = new DamageModifierSet();
foreach (var key in dmgComp.Damage.DamageDict.Keys)
modify.Coefficients.TryAdd(key, 1 - blockFraction);

if (blocking.IsBlocking && !args.Damage.Equals(args.OriginalDamage))
{
_audio.PlayPvs(blocking.BlockSound, uid);
}
}
args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, modify);
if (blocking.IsBlocking && !args.Damage.Equals(args.OriginalDamage))
_audio.PlayPvs(blocking.BlockSound, uid);
}

private void OnDamageModified(EntityUid uid, BlockingComponent component, DamageModifyEvent args)
Expand All @@ -87,7 +86,6 @@ private void OnEntityTerminating(EntityUid uid, BlockingUserComponent component,
return;

StopBlockingHelper(component.BlockingItem.Value, blockingComponent, uid);

}

/// <summary>
Expand Down
9 changes: 9 additions & 0 deletions Content.Shared/Blocking/Components/BlockingComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,12 @@ public sealed partial class BlockingComponent : Component
[DataField("activeBlockFraction"), ViewVariables(VVAccess.ReadWrite)]
public float ActiveBlockFraction = 1.0f;
}

/// <summary>
/// Raised directed on the blocking object when attempting to block.
/// </summary>
public sealed class BeforeBlockingEvent(EntityUid user, EntityUid? origin) : CancellableEntityEventArgs
{
public EntityUid User = user;
public EntityUid? Origin = origin;
}
17 changes: 11 additions & 6 deletions Content.Shared/Weapons/Reflect/ReflectSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
using Content.Shared.Standing;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.WhiteDream.BloodCult.BloodCultist;
using Content.Shared.WhiteDream.BloodCult.Items;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Network;
using Robust.Shared.Physics.Components;
Expand Down Expand Up @@ -112,6 +114,10 @@ private bool TryReflectProjectile(EntityUid user, EntityUid reflector, EntityUid
)
return false;

// Non cultists can't use cult items to reflect anything.
if (HasComp<CultItemComponent>(reflector) && !HasComp<BloodCultistComponent>(user))
return false;

if (!_random.Prob(CalcReflectChance(reflector, reflect)))
return false;

Expand Down Expand Up @@ -202,20 +208,19 @@ private bool TryReflectHitscan(
Vector2 direction,
[NotNullWhen(true)] out Vector2? newDirection)
{
newDirection = null;
if (!TryComp<ReflectComponent>(reflector, out var reflect) ||
!reflect.Enabled ||
TryComp<StaminaComponent>(reflector, out var staminaComponent) && staminaComponent.Critical ||
_standing.IsDown(reflector))
{
newDirection = null;
return false;
}

// Non cultists can't use cult items to reflect anything.
if (HasComp<CultItemComponent>(reflector) && !HasComp<BloodCultistComponent>(user))
return false;

if (!_random.Prob(CalcReflectChance(reflector, reflect)))
{
newDirection = null;
return false;
}

if (_netManager.IsServer)
{
Expand Down
28 changes: 17 additions & 11 deletions Content.Shared/WhiteDream/BloodCult/Items/CultItemSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Content.Shared.Ghost;
using Content.Shared.Blocking;
using Content.Shared.Ghost;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Inventory.Events;
Expand All @@ -18,12 +19,11 @@ public sealed class CultItemSystem : EntitySystem

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<CultItemComponent, ActivateInWorldEvent>(OnActivate);
SubscribeLocalEvent<CultItemComponent, BeforeThrowEvent>(OnBeforeThrow);
SubscribeLocalEvent<CultItemComponent, BeingEquippedAttemptEvent>(OnEquipAttempt);
SubscribeLocalEvent<CultItemComponent, AttemptMeleeEvent>(OnMeleeAttempt);
SubscribeLocalEvent<CultItemComponent, BeforeBlockingEvent>(OnBeforeBlocking);
}

private void OnActivate(Entity<CultItemComponent> item, ref ActivateInWorldEvent args)
Expand All @@ -35,6 +35,15 @@ private void OnActivate(Entity<CultItemComponent> item, ref ActivateInWorldEvent
KnockdownAndDropItem(item, args.User, Loc.GetString("cult-item-component-generic"));
}

private void OnBeforeThrow(Entity<CultItemComponent> item, ref BeforeThrowEvent args)
{
if (CanUse(args.PlayerUid))
return;

args.Cancelled = true;
KnockdownAndDropItem(item, args.PlayerUid, Loc.GetString("cult-item-component-throw-fail"));
}

private void OnEquipAttempt(Entity<CultItemComponent> item, ref BeingEquippedAttemptEvent args)
{
if (CanUse(args.EquipTarget))
Expand All @@ -53,13 +62,13 @@ private void OnMeleeAttempt(Entity<CultItemComponent> item, ref AttemptMeleeEven
KnockdownAndDropItem(item, args.PlayerUid, Loc.GetString("cult-item-component-attack-fail"));
}

private void OnBeforeThrow(Entity<CultItemComponent> item, ref BeforeThrowEvent args)
private void OnBeforeBlocking(Entity<CultItemComponent> item, ref BeforeBlockingEvent args)
{
if (CanUse(args.PlayerUid))
if (CanUse(args.User))
return;

args.Cancelled = true;
KnockdownAndDropItem(item, args.PlayerUid, Loc.GetString("cult-item-component-throw-fail"));
args.Cancel();
KnockdownAndDropItem(item, args.User, Loc.GetString("cult-item-component-block-fail"));
}

private void KnockdownAndDropItem(Entity<CultItemComponent> item, EntityUid user, string message)
Expand All @@ -69,8 +78,5 @@ private void KnockdownAndDropItem(Entity<CultItemComponent> item, EntityUid user
_hands.TryDrop(user);
}

private bool CanUse(EntityUid? uid)
{
return HasComp<BloodCultistComponent>(uid) || HasComp<GhostComponent>(uid);
}
private bool CanUse(EntityUid? uid) => HasComp<BloodCultistComponent>(uid) || HasComp<GhostComponent>(uid);
}
1 change: 1 addition & 0 deletions Resources/Locale/en-US/white-dream/cult/items/general.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
cult-item-component-attack-fail = The weapon refuses to obey your will. You can't attack with it.
cult-item-component-equip-fail = The armor refuses to obey your will. You can't equip it.
cult-item-component-throw-fail = The weapon refuses to obey your will. You can't throw it.
cult-item-component-block-fail = The shield betrays you!
soul-shard-try-insert-no-soul = The shard has no soul.
soul-shard-selector-form = Select form.
Expand Down
Loading

0 comments on commit 07a8d44

Please sign in to comment.