Stunnable New Status and Cleanup (#38618)
Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
This commit is contained in:
committed by
GitHub
parent
2b2b9b11b8
commit
e85bc1bb8c
@@ -1,4 +1,4 @@
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -17,9 +17,7 @@ namespace Content.IntegrationTests.Tests
|
||||
components:
|
||||
- type: Inventory
|
||||
- type: ContainerContainer
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- Stun
|
||||
- type: MobState
|
||||
|
||||
- type: entity
|
||||
name: InventoryJumpsuitJanitorDummy
|
||||
@@ -70,7 +68,7 @@ namespace Content.IntegrationTests.Tests
|
||||
});
|
||||
#pragma warning restore NUnit2045
|
||||
|
||||
systemMan.GetEntitySystem<StunSystem>().TryStun(human, TimeSpan.FromSeconds(1f), true);
|
||||
systemMan.GetEntitySystem<StunSystem>().TryUpdateStunDuration(human, TimeSpan.FromSeconds(1f));
|
||||
|
||||
#pragma warning disable NUnit2045
|
||||
// Since the mob is stunned, they can't equip this.
|
||||
|
||||
@@ -96,7 +96,7 @@ public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
|
||||
|
||||
EntityManager.AddComponents(ent, injectedAnom.Components);
|
||||
|
||||
_stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true);
|
||||
_stun.TryUpdateParalyzeDuration(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration));
|
||||
_jitter.DoJitter(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true);
|
||||
|
||||
if (ent.Comp.StartSound is not null)
|
||||
@@ -125,7 +125,7 @@ public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
|
||||
|
||||
private void OnAnomalyPulse(Entity<InnerBodyAnomalyComponent> ent, ref AnomalyPulseEvent args)
|
||||
{
|
||||
_stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration / 2 * args.Severity), true);
|
||||
_stun.TryUpdateParalyzeDuration(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration / 2 * args.Severity));
|
||||
_jitter.DoJitter(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration / 2 * args.Severity), true);
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
|
||||
if (_proto.TryIndex(ent.Comp.InjectionProto, out var injectedAnom))
|
||||
EntityManager.RemoveComponents(ent, injectedAnom.Components);
|
||||
|
||||
_stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true);
|
||||
_stun.TryUpdateParalyzeDuration(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration));
|
||||
|
||||
if (ent.Comp.EndMessage is not null &&
|
||||
_mind.TryGetMind(ent, out _, out var mindComponent) &&
|
||||
|
||||
@@ -394,7 +394,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
flammable.Resisting = true;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("flammable-component-resist-message"), uid, uid);
|
||||
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(2f), true);
|
||||
_stunSystem.TryUpdateParalyzeDuration(uid, TimeSpan.FromSeconds(2f));
|
||||
|
||||
// TODO FLAMMABLE: Make this not use TimerComponent...
|
||||
uid.SpawnTimer(2000, () =>
|
||||
|
||||
@@ -101,7 +101,7 @@ public sealed class CluwneSystem : EntitySystem
|
||||
else if (_robustRandom.Prob(component.KnockChance))
|
||||
{
|
||||
_audio.PlayPvs(component.KnockSound, uid);
|
||||
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(component.ParalyzeTime), true);
|
||||
_stunSystem.TryUpdateParalyzeDuration(uid, TimeSpan.FromSeconds(component.ParalyzeTime));
|
||||
_chat.TrySendInGameICMessage(uid, "spasms", InGameICChatType.Emote, ChatTransmitRange.Normal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Drowsiness;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
|
||||
@@ -397,7 +397,12 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
||||
var shouldStun = siemensCoefficient > 0.5f;
|
||||
|
||||
if (shouldStun)
|
||||
_stun.TryParalyze(uid, time * ParalyzeTimeMultiplier, refresh, statusEffects);
|
||||
{
|
||||
_ = refresh
|
||||
? _stun.TryUpdateParalyzeDuration(uid, time * ParalyzeTimeMultiplier)
|
||||
: _stun.TryAddParalyzeDuration(uid, time * ParalyzeTimeMultiplier);
|
||||
}
|
||||
|
||||
|
||||
// TODO: Sparks here.
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ public sealed class RevolutionaryRuleSystem : GameRuleSystem<RevolutionaryRuleCo
|
||||
continue;
|
||||
|
||||
_npcFaction.RemoveFaction(uid, RevolutionaryNpcFaction);
|
||||
_stun.TryParalyze(uid, stunTime, true);
|
||||
_stun.TryUpdateParalyzeDuration(uid, stunTime);
|
||||
RemCompDeferred<RevolutionaryComponent>(uid);
|
||||
_popup.PopupEntity(Loc.GetString("rev-break-control", ("name", Identity.Entity(uid, EntityManager))), uid);
|
||||
_adminLogManager.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(uid)} was deconverted due to all Head Revolutionaries dying.");
|
||||
|
||||
@@ -461,7 +461,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
|
||||
{
|
||||
if (instrument.InstrumentPlayer is {Valid: true} mob)
|
||||
{
|
||||
_stuns.TryParalyze(mob, TimeSpan.FromSeconds(1), true);
|
||||
_stuns.TryUpdateParalyzeDuration(mob, TimeSpan.FromSeconds(1));
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("instrument-component-finger-cramps-max-message"),
|
||||
uid, mob, PopupType.LargeCaution);
|
||||
|
||||
@@ -2,16 +2,15 @@ using Content.Server.Body.Systems;
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Server.Forensics;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Systems;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -27,7 +26,7 @@ namespace Content.Server.Medical
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly PuddleSystem _puddle = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
||||
[Dependency] private readonly StunSystem _stun = default!;
|
||||
[Dependency] private readonly MovementModStatusSystem _movementMod = default!;
|
||||
[Dependency] private readonly ThirstSystem _thirst = default!;
|
||||
[Dependency] private readonly ForensicsSystem _forensics = default!;
|
||||
[Dependency] private readonly BloodstreamSystem _bloodstream = default!;
|
||||
@@ -57,8 +56,7 @@ namespace Content.Server.Medical
|
||||
// It fully empties the stomach, this amount from the chem stream is relatively small
|
||||
var solutionSize = (MathF.Abs(thirstAdded) + MathF.Abs(hungerAdded)) / 6;
|
||||
// Apply a bit of slowdown
|
||||
if (TryComp<StatusEffectsComponent>(uid, out var status))
|
||||
_stun.TrySlowdown(uid, TimeSpan.FromSeconds(solutionSize), true, 0.5f, 0.5f, status);
|
||||
_movementMod.TryUpdateMovementSpeedModDuration(uid, MovementModStatusSystem.VomitingSlowdown, TimeSpan.FromSeconds(solutionSize), 0.5f);
|
||||
|
||||
// TODO: Need decals
|
||||
var solution = new Solution();
|
||||
|
||||
@@ -63,7 +63,7 @@ public sealed class StunProviderSystem : SharedStunProviderSystem
|
||||
_audio.PlayPvs(comp.Sound, target);
|
||||
|
||||
_damageable.TryChangeDamage(target, comp.StunDamage, false, true, null, origin: uid);
|
||||
_stun.TryParalyze(target, comp.StunTime, refresh: false);
|
||||
_stun.TryAddParalyzeDuration(target, comp.StunTime);
|
||||
|
||||
// short cooldown to prevent instant stunlocking
|
||||
_useDelay.SetLength((uid, useDelay), comp.Cooldown, id: comp.DelayId);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Server.Stunnable;
|
||||
@@ -7,7 +6,6 @@ using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.PneumaticCannon;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.Tools.Systems;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
@@ -80,10 +78,9 @@ public sealed class PneumaticCannonSystem : SharedPneumaticCannonSystem
|
||||
if (gas == null && component.GasUsage > 0f)
|
||||
return;
|
||||
|
||||
if (TryComp<StatusEffectsComponent>(args.User, out var status)
|
||||
&& component.Power == PneumaticCannonPower.High)
|
||||
if (component.Power == PneumaticCannonPower.High
|
||||
&& _stun.TryUpdateParalyzeDuration(args.User, TimeSpan.FromSeconds(component.HighPowerStunTime)))
|
||||
{
|
||||
_stun.TryParalyze(args.User, TimeSpan.FromSeconds(component.HighPowerStunTime), true, status);
|
||||
Popup.PopupEntity(Loc.GetString("pneumatic-cannon-component-power-stun",
|
||||
("cannon", uid)), cannon, args.User);
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ public sealed partial class RevenantSystem : EntitySystem
|
||||
ChangeEssenceAmount(uid, -abilityCost, component, false);
|
||||
|
||||
_statusEffects.TryAddStatusEffect<CorporealComponent>(uid, "Corporeal", TimeSpan.FromSeconds(debuffs.Y), false);
|
||||
_stun.TryStun(uid, TimeSpan.FromSeconds(debuffs.X), false);
|
||||
_stun.TryAddStunDuration(uid, TimeSpan.FromSeconds(debuffs.X));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -616,10 +616,7 @@ public sealed partial class ShuttleSystem
|
||||
{
|
||||
foreach (var child in toKnock)
|
||||
{
|
||||
if (!_statusQuery.TryGetComponent(child, out var status))
|
||||
continue;
|
||||
|
||||
_stuns.TryParalyze(child, _hyperspaceKnockdownTime, true, status);
|
||||
_stuns.TryUpdateParalyzeDuration(child, _hyperspaceKnockdownTime);
|
||||
|
||||
// If the guy we knocked down is on a spaced tile, throw them too
|
||||
if (grid != null)
|
||||
|
||||
@@ -249,7 +249,7 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
if (direction.LengthSquared() > minsq)
|
||||
{
|
||||
_stuns.TryKnockdown(uid, knockdownTime, true);
|
||||
_stuns.TryUpdateKnockdownDuration(uid, knockdownTime);
|
||||
_throwing.TryThrow(uid, direction, physics, Transform(uid), _projQuery, direction.Length(), playSound: false);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using Content.Server.Stunnable.Components;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Physics.Dynamics;
|
||||
using Content.Shared.Throwing;
|
||||
using Robust.Shared.Physics.Events;
|
||||
|
||||
@@ -12,6 +10,7 @@ namespace Content.Server.Stunnable
|
||||
internal sealed class StunOnCollideSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly StunSystem _stunSystem = default!;
|
||||
[Dependency] private readonly MovementModStatusSystem _movementMod = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -22,15 +21,19 @@ namespace Content.Server.Stunnable
|
||||
|
||||
private void TryDoCollideStun(EntityUid uid, StunOnCollideComponent component, EntityUid target)
|
||||
{
|
||||
if (!TryComp<StatusEffectsComponent>(target, out var status))
|
||||
return;
|
||||
_stunSystem.TryUpdateStunDuration(target, component.StunAmount);
|
||||
|
||||
_stunSystem.TryStun(target, component.StunAmount, component.Refresh, status);
|
||||
_stunSystem.TryKnockdown(target, component.KnockdownAmount, component.Refresh, component.AutoStand, force: true);
|
||||
|
||||
_stunSystem.TryKnockdown(target, component.KnockdownAmount, component.Refresh, component.AutoStand);
|
||||
|
||||
_stunSystem.TrySlowdown(target, component.SlowdownAmount, component.Refresh, component.WalkSpeedModifier, component.SprintSpeedModifier, status);
|
||||
_movementMod.TryUpdateMovementSpeedModDuration(
|
||||
target,
|
||||
MovementModStatusSystem.TaserSlowdown,
|
||||
component.SlowdownAmount,
|
||||
component.WalkSpeedModifier,
|
||||
component.SprintSpeedModifier
|
||||
);
|
||||
}
|
||||
|
||||
private void HandleCollide(EntityUid uid, StunOnCollideComponent component, ref StartCollideEvent args)
|
||||
{
|
||||
if (args.OurFixtureId != component.FixtureID)
|
||||
|
||||
@@ -34,7 +34,7 @@ public sealed class GoliathTentacleSystem : EntitySystem
|
||||
// TODO: animation
|
||||
|
||||
_popup.PopupPredicted(Loc.GetString("tentacle-ability-use-popup", ("entity", args.Performer)), args.Performer, args.Performer, type: PopupType.SmallCaution);
|
||||
_stun.TryStun(args.Performer, TimeSpan.FromSeconds(0.8f), false);
|
||||
_stun.TryAddStunDuration(args.Performer, TimeSpan.FromSeconds(0.8f));
|
||||
|
||||
var coords = args.Target;
|
||||
List<EntityCoordinates> spawnPos = new();
|
||||
|
||||
@@ -18,7 +18,6 @@ using Content.Shared.Slippery;
|
||||
using Content.Shared.Sound;
|
||||
using Content.Shared.Sound.Components;
|
||||
using Content.Shared.Speech;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Traits.Assorted;
|
||||
@@ -38,8 +37,8 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedEmitSoundSystem _emitSound = default!;
|
||||
[Dependency] private readonly StatusEffect.StatusEffectsSystem _statusEffectOld = default!;
|
||||
[Dependency] private readonly StatusEffectNew.StatusEffectsSystem _statusEffectNew = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffect = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||
|
||||
public static readonly EntProtoId SleepActionId = "ActionSleep";
|
||||
public static readonly EntProtoId WakeActionId = "ActionWake";
|
||||
@@ -67,6 +66,8 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
SubscribeLocalEvent<SleepingComponent, ExaminedEvent>(OnExamined);
|
||||
SubscribeLocalEvent<SleepingComponent, GetVerbsEvent<AlternativeVerb>>(AddWakeVerb);
|
||||
SubscribeLocalEvent<SleepingComponent, InteractHandEvent>(OnInteractHand);
|
||||
SubscribeLocalEvent<SleepingComponent, StunEndAttemptEvent>(OnStunEndAttempt);
|
||||
SubscribeLocalEvent<SleepingComponent, StandUpAttemptEvent>(OnStandUpAttempt);
|
||||
|
||||
SubscribeLocalEvent<ForcedSleepingStatusEffectComponent, StatusEffectAppliedEvent>(OnStatusEffectApplied);
|
||||
SubscribeLocalEvent<SleepingComponent, UnbuckleAttemptEvent>(OnUnbuckleAttempt);
|
||||
@@ -106,9 +107,7 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
{
|
||||
if (args.FellAsleep)
|
||||
{
|
||||
// Expiring status effects would remove the components needed for sleeping
|
||||
_statusEffectOld.TryRemoveStatusEffect(ent.Owner, "Stun");
|
||||
|
||||
// Just in case we're not using the sleeping status
|
||||
EnsureComp<StunnedComponent>(ent);
|
||||
EnsureComp<KnockedDownComponent>(ent);
|
||||
|
||||
@@ -128,8 +127,9 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
RemComp<StunnedComponent>(ent);
|
||||
RemComp<KnockedDownComponent>(ent);
|
||||
_stun.TryUnstun(ent.Owner);
|
||||
_stun.TryStanding(ent.Owner, out _);
|
||||
|
||||
RemComp<SpamEmitSoundComponent>(ent);
|
||||
}
|
||||
|
||||
@@ -174,6 +174,17 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnStunEndAttempt(Entity<SleepingComponent> ent, ref StunEndAttemptEvent args)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnStandUpAttempt(Entity<SleepingComponent> ent, ref StandUpAttemptEvent args)
|
||||
{
|
||||
// Shh the Urist McHands is sleeping...
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<SleepingComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (args.IsInDetailsRange)
|
||||
@@ -187,7 +198,6 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
if (!args.CanInteract || !args.CanAccess)
|
||||
return;
|
||||
|
||||
var target = args.Target;
|
||||
var user = args.User;
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
@@ -309,7 +319,7 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
if (!force && _statusEffectNew.HasEffectComp<ForcedSleepingStatusEffectComponent>(ent))
|
||||
if (!force && _statusEffect.HasEffectComp<ForcedSleepingStatusEffectComponent>(ent))
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
|
||||
@@ -571,7 +571,7 @@ public sealed partial class ClimbSystem : VirtualController
|
||||
|
||||
_damageableSystem.TryChangeDamage(args.Climber, component.ClimberDamage, origin: args.Climber);
|
||||
_damageableSystem.TryChangeDamage(uid, component.TableDamage, origin: args.Climber);
|
||||
_stunSystem.TryParalyze(args.Climber, TimeSpan.FromSeconds(component.StunTime), true);
|
||||
_stunSystem.TryUpdateParalyzeDuration(args.Climber, TimeSpan.FromSeconds(component.StunTime));
|
||||
|
||||
// Not shown to the user, since they already get a 'you climb on the glass table' popup
|
||||
_popupSystem.PopupEntity(
|
||||
|
||||
@@ -129,7 +129,7 @@ public sealed class ClumsySystem : EntitySystem
|
||||
if (ent.Comp.GunShootFailDamage != null)
|
||||
_damageable.TryChangeDamage(ent, ent.Comp.GunShootFailDamage, origin: ent);
|
||||
|
||||
_stun.TryParalyze(ent, ent.Comp.GunShootFailStunTime, true);
|
||||
_stun.TryUpdateParalyzeDuration(ent, ent.Comp.GunShootFailStunTime);
|
||||
|
||||
// Apply salt to the wound ("Honk!") (No idea what this comment means)
|
||||
_audio.PlayPvs(ent.Comp.GunShootFailSound, ent);
|
||||
@@ -202,7 +202,7 @@ public sealed class ClumsySystem : EntitySystem
|
||||
_damageable.TryChangeDamage(target, bonkComp.BonkDamage, true);
|
||||
}
|
||||
|
||||
_stun.TryParalyze(target, stunTime, true);
|
||||
_stun.TryUpdateParalyzeDuration(target, stunTime);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public sealed class DamageOnHighSpeedImpactSystem : EntitySystem
|
||||
component.LastHit = _gameTiming.CurTime;
|
||||
|
||||
if (_robustRandom.Prob(component.StunChance))
|
||||
_stun.TryStun(uid, TimeSpan.FromSeconds(component.StunSeconds), true);
|
||||
_stun.TryUpdateStunDuration(uid, TimeSpan.FromSeconds(component.StunSeconds));
|
||||
|
||||
var damageScale = component.SpeedDamageFactor * speed / component.MinimumSpeed;
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ public sealed class DamageOnInteractSystem : EntitySystem
|
||||
|
||||
// Attempt to paralyze the user after they have taken damage
|
||||
if (_random.Prob(entity.Comp.StunChance))
|
||||
_stun.TryParalyze(args.User, TimeSpan.FromSeconds(entity.Comp.StunSeconds), true);
|
||||
_stun.TryUpdateParalyzeDuration(args.User, TimeSpan.FromSeconds(entity.Comp.StunSeconds));
|
||||
}
|
||||
// Check if the entity's Throw bool is false, or if the entity has the PullableComponent, then if the entity is currently being pulled.
|
||||
// BeingPulled must be checked because the entity will be spastically thrown around without this.
|
||||
|
||||
@@ -8,9 +8,12 @@ using Content.Shared.Damage.Events;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Effects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Projectiles;
|
||||
using Content.Shared.Rejuvenate;
|
||||
using Content.Shared.Rounding;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
@@ -20,6 +23,7 @@ using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -27,15 +31,19 @@ namespace Content.Shared.Damage.Systems;
|
||||
|
||||
public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
{
|
||||
public static readonly EntProtoId StaminaLow = "StatusEffectStaminaLow";
|
||||
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
||||
[Dependency] protected readonly SharedStunSystem StunSystem = default!;
|
||||
[Dependency] private readonly MovementModStatusSystem _movementMod = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _status = default!;
|
||||
[Dependency] protected readonly SharedStunSystem StunSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// How much of a buffer is there between the stun duration and when stuns can be re-applied.
|
||||
@@ -113,8 +121,9 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
}
|
||||
|
||||
entity.Comp.StaminaDamage = 0;
|
||||
AdjustSlowdown(entity.Owner);
|
||||
AdjustStatus(entity.Owner);
|
||||
RemComp<ActiveStaminaComponent>(entity);
|
||||
_status.TryRemoveStatusEffect(entity, StaminaLow);
|
||||
UpdateStaminaVisuals(entity);
|
||||
Dirty(entity);
|
||||
}
|
||||
@@ -284,7 +293,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
component.NextUpdate = nextUpdate;
|
||||
}
|
||||
|
||||
AdjustSlowdown(uid);
|
||||
AdjustStatus(uid);
|
||||
|
||||
UpdateStaminaVisuals((uid, component));
|
||||
|
||||
@@ -292,6 +301,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
if (component.AfterCritical && oldDamage > component.StaminaDamage && component.StaminaDamage <= 0f)
|
||||
{
|
||||
component.AfterCritical = false; // Since the recovery from the crit has been completed, we are no longer 'after crit'
|
||||
_status.TryRemoveStatusEffect(uid, StaminaLow);
|
||||
}
|
||||
|
||||
if (!component.Critical)
|
||||
@@ -384,7 +394,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
component.Critical = true;
|
||||
component.StaminaDamage = component.CritThreshold;
|
||||
|
||||
if (StunSystem.TryParalyze(uid, component.StunTime, true))
|
||||
if (StunSystem.TryUpdateParalyzeDuration(uid, component.StunTime))
|
||||
StunSystem.TrySeeingStars(uid);
|
||||
|
||||
// Give them buffer before being able to be re-stunned
|
||||
@@ -412,18 +422,19 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the movement speed of an entity based on its current <see cref="StaminaComponent.StaminaDamage"/> value.
|
||||
/// If the entity has a <see cref="SlowOnDamageComponent"/>, its custom damage-to-speed thresholds are used,
|
||||
/// otherwise, a default set of thresholds is applied.
|
||||
/// The method determines the closest applicable damage threshold below the crit limit and applies the corresponding
|
||||
/// speed modifier using the stun system. If no threshold is met then the entity's speed is restored to normal.
|
||||
/// Adjusts the modifiers of the <see cref="StaminaLow"/> status effect entity and applies relevant statuses.
|
||||
/// System iterates through the <see cref="StaminaComponent.StunModifierThresholds"/> to find correct movement modifer.
|
||||
/// This modifier is saved to the Stamina Low Status Effect entity's <see cref="MovementModStatusEffectComponent"/>.
|
||||
/// </summary>
|
||||
/// <param name="ent">Entity to update</param>
|
||||
private void AdjustSlowdown(Entity<StaminaComponent?> ent)
|
||||
private void AdjustStatus(Entity<StaminaComponent?> ent)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return;
|
||||
|
||||
if (!_status.TrySetStatusEffectDuration(ent, StaminaLow, out var status))
|
||||
return;
|
||||
|
||||
var closest = FixedPoint2.Zero;
|
||||
|
||||
// Iterate through the dictionary in the similar way as in Damage.SlowOnDamageSystem.OnRefreshMovespeed
|
||||
@@ -435,7 +446,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
closest = thres.Key;
|
||||
}
|
||||
|
||||
StunSystem.UpdateStunModifiers(ent, ent.Comp.StunModifierThresholds[closest]);
|
||||
_movementMod.TryUpdateMovementStatus(ent.Owner, status.Value, ent.Comp.StunModifierThresholds[closest]);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -534,7 +534,7 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
||||
if (door.CrushDamage != null)
|
||||
_damageableSystem.TryChangeDamage(entity, door.CrushDamage, origin: uid);
|
||||
|
||||
_stunSystem.TryParalyze(entity, stunTime, true);
|
||||
_stunSystem.TryUpdateParalyzeDuration(entity, stunTime);
|
||||
}
|
||||
|
||||
if (door.CurrentlyCrushing.Count == 0)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Stunnable;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -14,9 +13,11 @@ public sealed partial class Paralyze : EntityEffect
|
||||
[DataField] public bool Refresh = true;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-paralyze",
|
||||
=> Loc.GetString(
|
||||
"reagent-effect-guidebook-paralyze",
|
||||
("chance", Probability),
|
||||
("time", ParalyzeTime));
|
||||
("time", ParalyzeTime)
|
||||
);
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
@@ -27,7 +28,10 @@ public sealed partial class Paralyze : EntityEffect
|
||||
paralyzeTime *= (double)reagentArgs.Scale;
|
||||
}
|
||||
|
||||
args.EntityManager.System<SharedStunSystem>().TryParalyze(args.TargetEntity, TimeSpan.FromSeconds(paralyzeTime), Refresh);
|
||||
var stunSystem = args.EntityManager.System<SharedStunSystem>();
|
||||
_ = Refresh
|
||||
? stunSystem.TryUpdateParalyzeDuration(args.TargetEntity, TimeSpan.FromSeconds(paralyzeTime))
|
||||
: stunSystem.TryAddParalyzeDuration(args.TargetEntity, TimeSpan.FromSeconds(paralyzeTime));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Linq;
|
||||
using Content.Shared.Movement.Systems;
|
||||
|
||||
namespace Content.Shared.Flash;
|
||||
|
||||
@@ -33,6 +34,7 @@ public abstract class SharedFlashSystem : EntitySystem
|
||||
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||
[Dependency] private readonly MovementModStatusSystem _movementMod = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
@@ -163,9 +165,9 @@ public abstract class SharedFlashSystem : EntitySystem
|
||||
return;
|
||||
|
||||
if (stunDuration != null)
|
||||
_stun.TryParalyze(target, stunDuration.Value, true);
|
||||
_stun.TryUpdateParalyzeDuration(target, stunDuration.Value);
|
||||
else
|
||||
_stun.TrySlowdown(target, flashDuration, true, slowTo, slowTo);
|
||||
_movementMod.TryUpdateMovementSpeedModDuration(target, MovementModStatusSystem.FlashSlowdown, flashDuration, slowTo);
|
||||
|
||||
if (displayPopup && user != null && target != user && Exists(user.Value))
|
||||
{
|
||||
|
||||
@@ -510,8 +510,8 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||
_mind.TransferTo(tarMind, ev.Performer);
|
||||
}
|
||||
|
||||
_stun.TryParalyze(ev.Target, ev.TargetStunDuration, true);
|
||||
_stun.TryParalyze(ev.Performer, ev.PerformerStunDuration, true);
|
||||
_stun.TryUpdateParalyzeDuration(ev.Target, ev.TargetStunDuration);
|
||||
_stun.TryUpdateParalyzeDuration(ev.Performer, ev.PerformerStunDuration);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Movement.Components;
|
||||
|
||||
/// <summary>
|
||||
/// This is used to store a movement speed modifier attached to a status effect entity so it can be applied via statuses.
|
||||
/// To be used in conjunction with <see cref="MovementModStatusSystem"/>.
|
||||
/// See <see cref="MovementModStatusComponent"/> for the component applied to the entity.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(MovementModStatusSystem))]
|
||||
public sealed partial class MovementModStatusEffectComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Multiplicative sprint modifier, with bounds of [0, 1)
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float SprintSpeedModifier = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplicative walk modifier, with bounds of [0, 1)
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float WalkSpeedModifier = 0.5f;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -6,23 +6,54 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.Shared.Movement.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// This handles the application of movement and friction modifiers to an entity as status effects.
|
||||
/// This handles the slowed status effect and other movement status effects.
|
||||
/// <see cref="MovementModStatusEffectComponent"/> holds a modifier for a status effect which is relayed to a mob's
|
||||
/// All effects of this kinda are multiplicative.
|
||||
/// Each 'source' of speed modification usually should have separate effect prototype.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Movement modifying status effects should by default be separate effect prototypes, and their effects
|
||||
/// should stack with each other (multiply). In case multiplicative effect is undesirable - such effects
|
||||
/// could occupy same prototype, but be aware that this will make controlling duration of effect
|
||||
/// extra 'challenging', as it will be shared too.
|
||||
/// </remarks>
|
||||
public sealed class MovementModStatusSystem : EntitySystem
|
||||
{
|
||||
public static readonly EntProtoId VomitingSlowdown = "VomitingSlowdownStatusEffect";
|
||||
public static readonly EntProtoId TaserSlowdown = "TaserSlowdownStatusEffect";
|
||||
public static readonly EntProtoId FlashSlowdown = "FlashSlowdownStatusEffect";
|
||||
public static readonly EntProtoId StatusEffectFriction = "StatusEffectFriction";
|
||||
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _status = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<MovementModStatusEffectComponent, StatusEffectRemovedEvent>(OnMovementModRemoved);
|
||||
SubscribeLocalEvent<MovementModStatusEffectComponent, StatusEffectRelayedEvent<RefreshMovementSpeedModifiersEvent>>(OnRefreshRelay);
|
||||
SubscribeLocalEvent<FrictionStatusEffectComponent, StatusEffectRemovedEvent>(OnFrictionStatusEffectRemoved);
|
||||
SubscribeLocalEvent<FrictionStatusEffectComponent, StatusEffectRelayedEvent<RefreshFrictionModifiersEvent>>(OnRefreshFrictionStatus);
|
||||
SubscribeLocalEvent<FrictionStatusEffectComponent, StatusEffectRelayedEvent<TileFrictionEvent>>(OnRefreshTileFrictionStatus);
|
||||
}
|
||||
|
||||
private void OnMovementModRemoved(Entity<MovementModStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
|
||||
{
|
||||
TryUpdateMovementStatus(args.Target, (ent, ent), 1f);
|
||||
}
|
||||
|
||||
private void OnFrictionStatusEffectRemoved(Entity<FrictionStatusEffectComponent> entity, ref StatusEffectRemovedEvent args)
|
||||
{
|
||||
TrySetFrictionStatus(entity!, 1f, args.Target);
|
||||
}
|
||||
|
||||
private void OnRefreshRelay(
|
||||
Entity<MovementModStatusEffectComponent> entity,
|
||||
ref StatusEffectRelayedEvent<RefreshMovementSpeedModifiersEvent> args
|
||||
)
|
||||
{
|
||||
args.Args.ModifySpeed(entity.Comp.WalkSpeedModifier, entity.Comp.WalkSpeedModifier);
|
||||
}
|
||||
|
||||
private void OnRefreshFrictionStatus(Entity<FrictionStatusEffectComponent> ent, ref StatusEffectRelayedEvent<RefreshFrictionModifiersEvent> args)
|
||||
{
|
||||
var ev = args.Args;
|
||||
@@ -39,27 +70,168 @@ public sealed class MovementModStatusSystem : EntitySystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a friction de-buff to the player.
|
||||
/// Apply mob's walking/running speed modifier with provided duration, or increment duration of existing.
|
||||
/// </summary>
|
||||
public bool TryFriction(EntityUid uid,
|
||||
TimeSpan time,
|
||||
bool refresh,
|
||||
float friction,
|
||||
float acceleration)
|
||||
/// <param name="uid">Target entity, for which speed should be modified.</param>
|
||||
/// <param name="effectProtoId">Slowdown effect to be used.</param>
|
||||
/// <param name="duration">Duration of speed modifying effect.</param>
|
||||
/// <param name="speedModifier">Multiplier by which walking/sprinting speed should be modified.</param>
|
||||
/// <returns>True if entity have slowdown effect applied now or previously and duration was modified.</returns>
|
||||
public bool TryAddMovementSpeedModDuration(
|
||||
EntityUid uid,
|
||||
EntProtoId effectProtoId,
|
||||
TimeSpan duration,
|
||||
float speedModifier
|
||||
)
|
||||
{
|
||||
if (time <= TimeSpan.Zero)
|
||||
return TryAddMovementSpeedModDuration(uid, effectProtoId, duration, speedModifier, speedModifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply mob's walking/running speed modifier with provided duration, or increment duration of existing.
|
||||
/// </summary>
|
||||
/// <param name="uid">Target entity, for which speed should be modified.</param>
|
||||
/// <param name="effectProtoId">Slowdown effect to be used.</param>
|
||||
/// <param name="duration">Duration of speed modifying effect.</param>
|
||||
/// <param name="walkSpeedModifier">Multiplier by which walking speed should be modified.</param>
|
||||
/// <param name="sprintSpeedModifier">Multiplier by which sprinting speed should be modified.</param>
|
||||
/// <returns>True if entity have slowdown effect applied now or previously and duration was modified.</returns>
|
||||
public bool TryAddMovementSpeedModDuration(
|
||||
EntityUid uid,
|
||||
EntProtoId effectProtoId,
|
||||
TimeSpan duration,
|
||||
float walkSpeedModifier,
|
||||
float sprintSpeedModifier
|
||||
)
|
||||
{
|
||||
return _status.TryAddStatusEffectDuration(uid, effectProtoId, out var status, duration)
|
||||
&& TryUpdateMovementStatus(uid, status!.Value, walkSpeedModifier, sprintSpeedModifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply mob's walking/running speed modifier with provided duration,
|
||||
/// or update duration of existing if it is lesser than provided duration.
|
||||
/// </summary>
|
||||
/// <param name="uid">Target entity, for which speed should be modified.</param>
|
||||
/// <param name="effectProtoId">Slowdown effect to be used.</param>
|
||||
/// <param name="duration">Duration of speed modifying effect.</param>
|
||||
/// <param name="speedModifier">Multiplier by which walking/sprinting speed should be modified.</param>
|
||||
/// <returns>True if entity have slowdown effect applied now or previously and duration was modified.</returns>
|
||||
public bool TryUpdateMovementSpeedModDuration(
|
||||
EntityUid uid,
|
||||
EntProtoId effectProtoId,
|
||||
TimeSpan duration,
|
||||
float speedModifier
|
||||
)
|
||||
{
|
||||
return TryUpdateMovementSpeedModDuration(uid, effectProtoId, duration, speedModifier, speedModifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply mob's walking/running speed modifier with provided duration,
|
||||
/// or update duration of existing if it is lesser than provided duration.
|
||||
/// </summary>
|
||||
/// <param name="uid">Target entity, for which speed should be modified.</param>
|
||||
/// <param name="effectProtoId">Slowdown effect to be used.</param>
|
||||
/// <param name="duration">Duration of speed modifying effect.</param>
|
||||
/// <param name="walkSpeedModifier">Multiplier by which walking speed should be modified.</param>
|
||||
/// <param name="sprintSpeedModifier">Multiplier by which sprinting speed should be modified.</param>
|
||||
/// <returns>True if entity have slowdown effect applied now or previously and duration was modified.</returns>
|
||||
public bool TryUpdateMovementSpeedModDuration(
|
||||
EntityUid uid,
|
||||
EntProtoId effectProtoId,
|
||||
TimeSpan? duration,
|
||||
float walkSpeedModifier,
|
||||
float sprintSpeedModifier
|
||||
)
|
||||
{
|
||||
return _status.TryUpdateStatusEffectDuration(uid, effectProtoId, out var status, duration)
|
||||
&& TryUpdateMovementStatus(uid, status!.Value, walkSpeedModifier, sprintSpeedModifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates entity's movement speed using <see cref="MovementModStatusEffectComponent"/> to provided values.
|
||||
/// Then refreshes the movement speed of the entity.
|
||||
/// </summary>
|
||||
/// <param name="uid">Entity whose component we're updating</param>
|
||||
/// <param name="status">Status effect entity whose modifiers we are updating</param>
|
||||
/// <param name="walkSpeedModifier">New walkSpeedModifer we're applying</param>
|
||||
/// <param name="sprintSpeedModifier">New sprintSpeedModifier we're applying</param>
|
||||
public bool TryUpdateMovementStatus(
|
||||
EntityUid uid,
|
||||
Entity<MovementModStatusEffectComponent?> status,
|
||||
float walkSpeedModifier,
|
||||
float sprintSpeedModifier
|
||||
)
|
||||
{
|
||||
if (!Resolve(status, ref status.Comp))
|
||||
return false;
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
return _status.TryUpdateStatusEffectDuration(uid, StatusEffectFriction, out var status, time)
|
||||
status.Comp.SprintSpeedModifier = sprintSpeedModifier;
|
||||
status.Comp.WalkSpeedModifier = walkSpeedModifier;
|
||||
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates entity's movement speed using <see cref="MovementModStatusEffectComponent"/> to provided value.
|
||||
/// Then refreshes the movement speed of the entity.
|
||||
/// </summary>
|
||||
/// <param name="uid">Entity whose component we're updating</param>
|
||||
/// <param name="status">Status effect entity whose modifiers we are updating</param>
|
||||
/// <param name="speedModifier">
|
||||
/// Multiplier by which speed should be modified.
|
||||
/// Will be applied to both walking and running speed.
|
||||
/// </param>
|
||||
public bool TryUpdateMovementStatus(
|
||||
EntityUid uid,
|
||||
Entity<MovementModStatusEffectComponent?> status,
|
||||
float speedModifier
|
||||
)
|
||||
{
|
||||
return TryUpdateMovementStatus(uid, status, speedModifier, speedModifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply friction modifier with provided duration,
|
||||
/// or incrementing duration of existing.
|
||||
/// </summary>
|
||||
/// <param name="uid">Target entity, for which friction modifier should be applied.</param>
|
||||
/// <param name="duration">Duration of speed modifying effect.</param>
|
||||
/// <param name="friction">Multiplier by which walking speed should be modified.</param>
|
||||
/// <param name="acceleration">Multiplier by which sprinting speed should be modified.</param>
|
||||
/// <returns>True if entity have slowdown effect applied now or previously and duration was modified.</returns>
|
||||
public bool TryAddFrictionModDuration(
|
||||
EntityUid uid,
|
||||
TimeSpan duration,
|
||||
float friction,
|
||||
float acceleration
|
||||
)
|
||||
{
|
||||
return _status.TryAddStatusEffectDuration(uid, StatusEffectFriction, out var status, duration)
|
||||
&& TrySetFrictionStatus(status.Value, friction, acceleration, uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _status.TryAddStatusEffectDuration(uid, StatusEffectFriction, out var status, time)
|
||||
&& TrySetFrictionStatus(status.Value, friction, acceleration, uid);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply friction modifier with provided duration,
|
||||
/// or update duration of existing if it is lesser than provided duration.
|
||||
/// </summary>
|
||||
/// <param name="uid">Target entity, for which friction modifier should be applied.</param>
|
||||
/// <param name="duration">Duration of speed modifying effect.</param>
|
||||
/// <param name="friction">Multiplier by which walking speed should be modified.</param>
|
||||
/// <param name="acceleration">Multiplier by which sprinting speed should be modified.</param>
|
||||
/// <returns>True if entity have slowdown effect applied now or previously and duration was modified.</returns>
|
||||
public bool TryUpdateFrictionModDuration(
|
||||
EntityUid uid,
|
||||
TimeSpan duration,
|
||||
float friction,
|
||||
float acceleration
|
||||
)
|
||||
{
|
||||
return _status.TryUpdateStatusEffectDuration(uid, StatusEffectFriction, out var status, duration)
|
||||
&& TrySetFrictionStatus(status.Value, friction, acceleration, uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -92,9 +264,4 @@ public sealed class MovementModStatusSystem : EntitySystem
|
||||
_movementSpeedModifier.RefreshFrictionModifiers(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnFrictionStatusEffectRemoved(Entity<FrictionStatusEffectComponent> entity, ref StatusEffectRemovedEvent args)
|
||||
{
|
||||
TrySetFrictionStatus(entity!, 1f, args.Target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Content.Shared.Nutrition.EntitySystems
|
||||
|
||||
CreamedEntity(uid, creamPied, args);
|
||||
|
||||
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(creamPie.ParalyzeTime), true);
|
||||
_stunSystem.TryUpdateParalyzeDuration(uid, TimeSpan.FromSeconds(creamPie.ParalyzeTime));
|
||||
}
|
||||
|
||||
protected virtual void CreamedEntity(EntityUid uid, CreamPiedComponent creamPied, ThrowHitByEvent args) {}
|
||||
|
||||
@@ -42,7 +42,7 @@ public abstract class SharedRevolutionarySystem : EntitySystem
|
||||
var stunTime = TimeSpan.FromSeconds(4);
|
||||
var name = Identity.Entity(uid, EntityManager);
|
||||
RemComp<RevolutionaryComponent>(uid);
|
||||
_sharedStun.TryParalyze(uid, stunTime, true);
|
||||
_sharedStun.TryUpdateParalyzeDuration(uid, stunTime);
|
||||
_popupSystem.PopupEntity(Loc.GetString("rev-break-control", ("name", name)), uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Silicons.Laws.Components;
|
||||
@@ -57,7 +57,7 @@ public abstract partial class SharedSiliconLawSystem : EntitySystem
|
||||
if(_mind.TryGetMind(uid, out var mindId, out _))
|
||||
EnsureSubvertedSiliconRole(mindId);
|
||||
|
||||
_stunSystem.TryParalyze(uid, component.StunTime, true);
|
||||
_stunSystem.TryUpdateParalyzeDuration(uid, component.StunTime);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Shared.Network;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.StepTrigger.Systems;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Throwing;
|
||||
@@ -16,7 +14,6 @@ using Robust.Shared.Containers;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Slippery;
|
||||
|
||||
@@ -27,8 +24,8 @@ public sealed class SlipperySystem : EntitySystem
|
||||
[Dependency] private readonly MovementModStatusSystem _movementMod = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _status = default!;
|
||||
[Dependency] private readonly SharedStaminaSystem _stamina = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SpeedModifierContactsSystem _speedModifier = default!;
|
||||
@@ -90,7 +87,7 @@ public sealed class SlipperySystem : EntitySystem
|
||||
private bool CanSlip(EntityUid uid, EntityUid toSlip)
|
||||
{
|
||||
return !_container.IsEntityInContainer(uid)
|
||||
&& _statusEffects.CanApplyEffect(toSlip, "Stun"); //Should be KnockedDown instead?
|
||||
&& _status.CanAddStatusEffect(toSlip, SharedStunSystem.StunId); //Should be KnockedDown instead?
|
||||
}
|
||||
|
||||
public void TrySlip(EntityUid uid, SlipperyComponent component, EntityUid other, bool requiresContact = true)
|
||||
@@ -125,12 +122,18 @@ public sealed class SlipperySystem : EntitySystem
|
||||
// Preventing from playing the slip sound and stunning when you are already knocked down.
|
||||
if (!HasComp<KnockedDownComponent>(other))
|
||||
{
|
||||
_stun.TryStun(other, component.SlipData.StunTime, true);
|
||||
_stun.TryUpdateStunDuration(other, component.SlipData.StunTime);
|
||||
_stamina.TakeStaminaDamage(other, component.StaminaDamage); // Note that this can stamCrit
|
||||
_movementMod.TryFriction(other, component.FrictionStatusTime, true, component.SlipData.SlipFriction, component.SlipData.SlipFriction);
|
||||
_movementMod.TryUpdateFrictionModDuration(
|
||||
other,
|
||||
component.FrictionStatusTime,
|
||||
component.SlipData.SlipFriction,
|
||||
component.SlipData.SlipFriction
|
||||
);
|
||||
_audio.PlayPredicted(component.SlipSound, other, other);
|
||||
}
|
||||
_stun.TryKnockdown(other, component.SlipData.KnockdownTime, true, true);
|
||||
|
||||
_stun.TryKnockdown(other, component.SlipData.KnockdownTime, true, force: true);
|
||||
|
||||
_adminLogger.Add(LogType.Slip, LogImpact.Low, $"{ToPrettyString(other):mob} slipped on collision with {ToPrettyString(uid):entity}");
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public sealed partial class ReformSystem : EntitySystem
|
||||
{
|
||||
// Stun them when they use the action for the amount of reform time.
|
||||
if (comp.ShouldStun)
|
||||
_stunSystem.TryStun(uid, TimeSpan.FromSeconds(comp.ReformTime), true);
|
||||
_stunSystem.TryUpdateStunDuration(uid, TimeSpan.FromSeconds(comp.ReformTime));
|
||||
_popupSystem.PopupClient(Loc.GetString(comp.PopupText, ("name", uid)), uid, uid);
|
||||
|
||||
// Create a doafter & start it
|
||||
|
||||
@@ -31,7 +31,7 @@ public sealed partial class StatusEffectsSystem
|
||||
}
|
||||
|
||||
|
||||
///<inheritdoc cref="TryAddStatusEffectDuration(Robust.Shared.GameObjects.EntityUid,Robust.Shared.Prototypes.EntProtoId,out Robust.Shared.GameObjects.EntityUid?,System.TimeSpan)"/>
|
||||
///<inheritdoc cref="TryAddStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan)"/>
|
||||
public bool TryAddStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan duration)
|
||||
{
|
||||
return TryAddStatusEffectDuration(target, effectProto, out _, duration);
|
||||
@@ -61,7 +61,7 @@ public sealed partial class StatusEffectsSystem
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="TrySetStatusEffectDuration(Robust.Shared.GameObjects.EntityUid,Robust.Shared.Prototypes.EntProtoId,out Robust.Shared.GameObjects.EntityUid?,System.TimeSpan?)"/>
|
||||
/// <inheritdoc cref="TrySetStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan?)"/>
|
||||
public bool TrySetStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan? duration = null)
|
||||
{
|
||||
return TrySetStatusEffectDuration(target, effectProto, out _, duration);
|
||||
@@ -91,7 +91,7 @@ public sealed partial class StatusEffectsSystem
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="TryUpdateStatusEffectDuration(Robust.Shared.GameObjects.EntityUid,Robust.Shared.Prototypes.EntProtoId,out Robust.Shared.GameObjects.EntityUid?,System.TimeSpan?)"/>
|
||||
/// <inheritdoc cref="TryUpdateStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan?)"/>
|
||||
public bool TryUpdateStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan? duration = null)
|
||||
{
|
||||
return TryUpdateStatusEffectDuration(target, effectProto, out _, duration);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Content.Shared.Stunnable;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Shared.StatusEffectNew;
|
||||
@@ -12,8 +13,14 @@ public sealed partial class StatusEffectsSystem
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, LocalPlayerAttachedEvent>(RelayStatusEffectEvent);
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, LocalPlayerDetachedEvent>(RelayStatusEffectEvent);
|
||||
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, RefreshMovementSpeedModifiersEvent>(RelayStatusEffectEvent);
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, UpdateCanMoveEvent>(RelayStatusEffectEvent);
|
||||
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, RefreshFrictionModifiersEvent>(RefRelayStatusEffectEvent);
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, TileFrictionEvent>(RefRelayStatusEffectEvent);
|
||||
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, StandUpAttemptEvent>(RefRelayStatusEffectEvent);
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, StunEndAttemptEvent>(RefRelayStatusEffectEvent);
|
||||
}
|
||||
|
||||
private void RefRelayStatusEffectEvent<T>(EntityUid uid, StatusEffectContainerComponent component, ref T args) where T : struct
|
||||
|
||||
@@ -156,7 +156,7 @@ public sealed partial class StatusEffectsSystem : EntitySystem
|
||||
Dirty(effect, effectComp);
|
||||
}
|
||||
|
||||
private bool CanAddStatusEffect(EntityUid uid, EntProtoId effectProto)
|
||||
public bool CanAddStatusEffect(EntityUid uid, EntProtoId effectProto)
|
||||
{
|
||||
if (!_proto.TryIndex(effectProto, out var effectProtoData))
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Stunnable;
|
||||
|
||||
/// <summary>
|
||||
/// Knockdown as a status effect.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedStunSystem))]
|
||||
public sealed partial class KnockdownStatusEffectComponent : Component;
|
||||
@@ -51,7 +51,7 @@ public abstract partial class SharedStunSystem
|
||||
|
||||
// Action blockers
|
||||
SubscribeLocalEvent<KnockedDownComponent, BuckleAttemptEvent>(OnBuckleAttempt);
|
||||
SubscribeLocalEvent<KnockedDownComponent, StandAttemptEvent>(OnStandUpAttempt);
|
||||
SubscribeLocalEvent<KnockedDownComponent, StandAttemptEvent>(OnStandAttempt);
|
||||
|
||||
// Updating movement a friction
|
||||
SubscribeLocalEvent<KnockedDownComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshKnockedSpeed);
|
||||
@@ -452,7 +452,7 @@ public abstract partial class SharedStunSystem
|
||||
|
||||
#region Action Blockers
|
||||
|
||||
private void OnStandUpAttempt(Entity<KnockedDownComponent> entity, ref StandAttemptEvent args)
|
||||
private void OnStandAttempt(Entity<KnockedDownComponent> entity, ref StandAttemptEvent args)
|
||||
{
|
||||
if (entity.Comp.LifeStage <= ComponentLifeStage.Running)
|
||||
args.Cancel();
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Shared.Alert;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DoAfter;
|
||||
@@ -14,35 +13,35 @@ using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Stunnable;
|
||||
|
||||
public abstract partial class SharedStunSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly ActionBlockerSystem Blocker = default!;
|
||||
[Dependency] protected readonly AlertsSystem Alerts = default!;
|
||||
public static readonly EntProtoId StunId = "StatusEffectStunned";
|
||||
public static readonly EntProtoId KnockdownId = "StatusEffectKnockdown";
|
||||
|
||||
[Dependency] protected readonly IGameTiming GameTiming = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] protected readonly ActionBlockerSystem Blocker = default!;
|
||||
[Dependency] protected readonly AlertsSystem Alerts = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
||||
[Dependency] protected readonly SharedDoAfterSystem DoAfter = default!;
|
||||
[Dependency] protected readonly SharedStaminaSystem Stamina = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffect = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _status = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<SlowedDownComponent, ComponentInit>(OnSlowInit);
|
||||
SubscribeLocalEvent<SlowedDownComponent, ComponentShutdown>(OnSlowRemove);
|
||||
SubscribeLocalEvent<SlowedDownComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||
|
||||
SubscribeLocalEvent<StunnedComponent, ComponentStartup>(UpdateCanMove);
|
||||
SubscribeLocalEvent<StunnedComponent, ComponentShutdown>(OnStunShutdown);
|
||||
|
||||
@@ -61,6 +60,14 @@ public abstract partial class SharedStunSystem : EntitySystem
|
||||
SubscribeLocalEvent<StunnedComponent, IsUnequippingAttemptEvent>(OnUnequipAttempt);
|
||||
SubscribeLocalEvent<MobStateComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
|
||||
// New Status Effect subscriptions
|
||||
SubscribeLocalEvent<StunnedStatusEffectComponent, StatusEffectAppliedEvent>(OnStunEffectApplied);
|
||||
SubscribeLocalEvent<StunnedStatusEffectComponent, StatusEffectRemovedEvent>(OnStunStatusRemoved);
|
||||
SubscribeLocalEvent<StunnedStatusEffectComponent, StatusEffectRelayedEvent<StunEndAttemptEvent>>(OnStunEndAttempt);
|
||||
|
||||
SubscribeLocalEvent<KnockdownStatusEffectComponent, StatusEffectRelayedEvent<StandUpAttemptEvent>>(OnStandUpAttempt);
|
||||
|
||||
// Stun Appearance Data
|
||||
InitializeKnockdown();
|
||||
InitializeAppearance();
|
||||
}
|
||||
@@ -72,10 +79,6 @@ public abstract partial class SharedStunSystem : EntitySystem
|
||||
|
||||
private void OnMobStateChanged(EntityUid uid, MobStateComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
if (!TryComp<StatusEffectsComponent>(uid, out var status))
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (args.NewMobState)
|
||||
{
|
||||
case MobState.Alive:
|
||||
@@ -84,12 +87,12 @@ public abstract partial class SharedStunSystem : EntitySystem
|
||||
}
|
||||
case MobState.Critical:
|
||||
{
|
||||
_statusEffect.TryRemoveStatusEffect(uid, "Stun");
|
||||
_status.TryRemoveStatusEffect(uid, StunId);
|
||||
break;
|
||||
}
|
||||
case MobState.Dead:
|
||||
{
|
||||
_statusEffect.TryRemoveStatusEffect(uid, "Stun");
|
||||
_status.TryRemoveStatusEffect(uid, StunId);
|
||||
break;
|
||||
}
|
||||
case MobState.Invalid:
|
||||
@@ -119,71 +122,95 @@ public abstract partial class SharedStunSystem : EntitySystem
|
||||
if (_entityWhitelist.IsBlacklistPass(ent.Comp.Blacklist, args.OtherEntity))
|
||||
return;
|
||||
|
||||
if (!TryComp<StatusEffectsComponent>(args.OtherEntity, out var status))
|
||||
return;
|
||||
|
||||
TryStun(args.OtherEntity, ent.Comp.Duration, true, status);
|
||||
TryKnockdown(args.OtherEntity, ent.Comp.Duration, ent.Comp.Refresh, ent.Comp.AutoStand);
|
||||
}
|
||||
|
||||
private void OnSlowInit(EntityUid uid, SlowedDownComponent component, ComponentInit args)
|
||||
{
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
|
||||
}
|
||||
|
||||
private void OnSlowRemove(EntityUid uid, SlowedDownComponent component, ComponentShutdown args)
|
||||
{
|
||||
component.SprintSpeedModifier = 1f;
|
||||
component.WalkSpeedModifier = 1f;
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
|
||||
TryUpdateStunDuration(args.OtherEntity, ent.Comp.Duration);
|
||||
TryKnockdown(args.OtherEntity, ent.Comp.Duration, true, force: true);
|
||||
}
|
||||
|
||||
// TODO STUN: Make events for different things. (Getting modifiers, attempt events, informative events...)
|
||||
|
||||
/// <summary>
|
||||
/// Stuns the entity, disallowing it from doing many interactions temporarily.
|
||||
/// </summary>
|
||||
public bool TryStun(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null)
|
||||
public bool TryAddStunDuration(EntityUid uid, TimeSpan duration)
|
||||
{
|
||||
if (time <= TimeSpan.Zero)
|
||||
if (!_status.TryAddStatusEffectDuration(uid, StunId, duration))
|
||||
return false;
|
||||
|
||||
if (!Resolve(uid, ref status, false))
|
||||
OnStunnedSuccessfully(uid, duration);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryUpdateStunDuration(EntityUid uid, TimeSpan? duration)
|
||||
{
|
||||
if (!_status.TryUpdateStatusEffectDuration(uid, StunId, duration))
|
||||
return false;
|
||||
|
||||
if (!_statusEffect.TryAddStatusEffect<StunnedComponent>(uid, "Stun", time, refresh))
|
||||
return false;
|
||||
OnStunnedSuccessfully(uid, duration);
|
||||
return true;
|
||||
}
|
||||
|
||||
var ev = new StunnedEvent();
|
||||
private void OnStunnedSuccessfully(EntityUid uid, TimeSpan? duration)
|
||||
{
|
||||
var ev = new StunnedEvent(); // todo: rename event or change how it is raised - this event is raised each time duration of stun was externally changed
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} stunned for {time.Seconds} seconds");
|
||||
var timeForLogs = duration.HasValue
|
||||
? duration.Value.Seconds.ToString()
|
||||
: "Infinite";
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} stunned for {timeForLogs} seconds");
|
||||
}
|
||||
|
||||
public bool TryAddKnockdownDuration(EntityUid uid, TimeSpan duration)
|
||||
{
|
||||
if (!_status.TryAddStatusEffectDuration(uid, KnockdownId, duration))
|
||||
return false;
|
||||
|
||||
TryKnockdown(uid, duration, true, force: true);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public bool TryUpdateKnockdownDuration(EntityUid uid, TimeSpan? duration)
|
||||
{
|
||||
if (!_status.TryUpdateStatusEffectDuration(uid, KnockdownId, duration))
|
||||
return false;
|
||||
|
||||
return TryKnockdown(uid, duration, true, force: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Knocks down the entity, making it fall to the ground.
|
||||
/// </summary>
|
||||
public bool TryKnockdown(EntityUid uid, TimeSpan time, bool refresh, bool autoStand = true, bool drop = true)
|
||||
public bool TryKnockdown(Entity<StandingStateComponent?> entity, TimeSpan? time, bool refresh, bool autoStand = true, bool drop = true, bool force = false)
|
||||
{
|
||||
if (time <= TimeSpan.Zero)
|
||||
return false;
|
||||
|
||||
// Can't fall down if you can't actually be downed.
|
||||
if (!HasComp<StandingStateComponent>(uid))
|
||||
if (!Resolve(entity, ref entity.Comp, false))
|
||||
return false;
|
||||
|
||||
var evAttempt = new KnockDownAttemptEvent(autoStand, drop);
|
||||
RaiseLocalEvent(uid, ref evAttempt);
|
||||
|
||||
if (evAttempt.Cancelled)
|
||||
return false;
|
||||
|
||||
// Initialize our component with the relevant data we need if we don't have it
|
||||
if (EnsureComp<KnockedDownComponent>(uid, out var component))
|
||||
if (!force)
|
||||
{
|
||||
RefreshKnockedMovement((uid, component));
|
||||
CancelKnockdownDoAfter((uid, component));
|
||||
var evAttempt = new KnockDownAttemptEvent(autoStand, drop);
|
||||
RaiseLocalEvent(entity, ref evAttempt);
|
||||
|
||||
if (evAttempt.Cancelled)
|
||||
return false;
|
||||
|
||||
autoStand = evAttempt.AutoStand;
|
||||
drop = evAttempt.Drop;
|
||||
}
|
||||
|
||||
Knockdown(entity!, time, autoStand, drop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Knockdown(Entity<StandingStateComponent> entity, TimeSpan? time, bool refresh, bool autoStand = true, bool drop = true)
|
||||
{
|
||||
// Initialize our component with the relevant data we need if we don't have it
|
||||
if (EnsureComp<KnockedDownComponent>(entity, out var component))
|
||||
{
|
||||
RefreshKnockedMovement((entity, component));
|
||||
CancelKnockdownDoAfter((entity, component));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -191,127 +218,87 @@ public abstract partial class SharedStunSystem : EntitySystem
|
||||
if (drop)
|
||||
{
|
||||
var ev = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
RaiseLocalEvent(entity, ref ev);
|
||||
}
|
||||
|
||||
// Only update Autostand value if it's our first time being knocked down...
|
||||
SetAutoStand((uid, component), evAttempt.AutoStand);
|
||||
SetAutoStand((entity, component), autoStand);
|
||||
}
|
||||
|
||||
var knockedEv = new KnockedDownEvent(time);
|
||||
RaiseLocalEvent(uid, ref knockedEv);
|
||||
RaiseLocalEvent(entity, ref knockedEv);
|
||||
|
||||
UpdateKnockdownTime((uid, component), knockedEv.Time, refresh);
|
||||
|
||||
Alerts.ShowAlert(uid, KnockdownAlert, null, (GameTiming.CurTime, component.NextUpdate));
|
||||
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} knocked down for {time.Seconds} seconds");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies knockdown and stun to the entity temporarily.
|
||||
/// </summary>
|
||||
public bool TryParalyze(EntityUid uid, TimeSpan time, bool refresh,
|
||||
StatusEffectsComponent? status = null)
|
||||
{
|
||||
if (!Resolve(uid, ref status, false))
|
||||
return false;
|
||||
|
||||
return TryKnockdown(uid, time, refresh) && TryStun(uid, time, refresh, status);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slows down the mob's walking/running speed temporarily
|
||||
/// </summary>
|
||||
public bool TrySlowdown(EntityUid uid, TimeSpan time, bool refresh,
|
||||
float walkSpeedMod = 1f, float sprintSpeedMod = 1f,
|
||||
StatusEffectsComponent? status = null)
|
||||
{
|
||||
if (!Resolve(uid, ref status, false))
|
||||
return false;
|
||||
|
||||
if (time <= TimeSpan.Zero)
|
||||
return false;
|
||||
|
||||
if (_statusEffect.TryAddStatusEffect<SlowedDownComponent>(uid, "SlowedDown", time, refresh, status))
|
||||
if (time != null)
|
||||
{
|
||||
var slowed = Comp<SlowedDownComponent>(uid);
|
||||
// Doesn't make much sense to have the "TrySlowdown" method speed up entities now does it?
|
||||
walkSpeedMod = Math.Clamp(walkSpeedMod, 0f, 1f);
|
||||
sprintSpeedMod = Math.Clamp(sprintSpeedMod, 0f, 1f);
|
||||
UpdateKnockdownTime((entity, component), time.Value, refresh);
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(entity):user} knocked down for {time.Value.Seconds} seconds");
|
||||
}
|
||||
else
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(entity):user} knocked down for an indefinite amount of time");
|
||||
|
||||
slowed.WalkSpeedModifier *= walkSpeedMod;
|
||||
slowed.SprintSpeedModifier *= sprintSpeedMod;
|
||||
Alerts.ShowAlert(entity, KnockdownAlert, null, (GameTiming.CurTime, component.NextUpdate));
|
||||
}
|
||||
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
|
||||
public bool TryAddParalyzeDuration(EntityUid uid, TimeSpan duration)
|
||||
{
|
||||
var knockdown = TryAddKnockdownDuration(uid, duration);
|
||||
var stunned = TryAddStunDuration(uid, duration);
|
||||
|
||||
return knockdown || stunned;
|
||||
}
|
||||
|
||||
public bool TryUpdateParalyzeDuration(EntityUid uid, TimeSpan? duration)
|
||||
{
|
||||
var knockdown = TryUpdateKnockdownDuration(uid, duration);
|
||||
var stunned = TryUpdateStunDuration(uid, duration);
|
||||
|
||||
return knockdown || stunned;
|
||||
}
|
||||
|
||||
public bool TryUnstun(Entity<StunnedComponent?> entity)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp, logMissing: false))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
var ev = new StunEndAttemptEvent();
|
||||
RaiseLocalEvent(entity, ref ev);
|
||||
|
||||
return !ev.Cancelled && RemComp<StunnedComponent>(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the movement speed modifiers of an entity by applying or removing the <see cref="SlowedDownComponent"/>.
|
||||
/// If both walk and run modifiers are approximately 1 (i.e. normal speed) and <see cref="StaminaComponent.StaminaDamage"/> is 0,
|
||||
/// or if the both modifiers are 0, the slowdown component is removed to restore normal movement.
|
||||
/// Otherwise, the slowdown component is created or updated with the provided modifiers,
|
||||
/// and the movement speed is refreshed accordingly.
|
||||
/// </summary>
|
||||
/// <param name="ent">Entity whose movement speed should be updated.</param>
|
||||
/// <param name="walkSpeedModifier">New walk speed modifier. Default is 1f (normal speed).</param>
|
||||
/// <param name="runSpeedModifier">New run (sprint) speed modifier. Default is 1f (normal speed).</param>
|
||||
public void UpdateStunModifiers(Entity<StaminaComponent?> ent,
|
||||
float walkSpeedModifier = 1f,
|
||||
float runSpeedModifier = 1f)
|
||||
private void OnStunEffectApplied(Entity<StunnedStatusEffectComponent> entity, ref StatusEffectAppliedEvent args)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
if (GameTiming.ApplyingState)
|
||||
return;
|
||||
|
||||
if (
|
||||
(MathHelper.CloseTo(walkSpeedModifier, 1f) && MathHelper.CloseTo(runSpeedModifier, 1f) && ent.Comp.StaminaDamage == 0f) ||
|
||||
(walkSpeedModifier == 0f && runSpeedModifier == 0f)
|
||||
)
|
||||
{
|
||||
RemComp<SlowedDownComponent>(ent);
|
||||
EnsureComp<StunnedComponent>(args.Target);
|
||||
}
|
||||
|
||||
private void OnStunStatusRemoved(Entity<StunnedStatusEffectComponent> entity, ref StatusEffectRemovedEvent args)
|
||||
{
|
||||
TryUnstun(args.Target);
|
||||
}
|
||||
|
||||
private void OnStunEndAttempt(Entity<StunnedStatusEffectComponent> entity, ref StatusEffectRelayedEvent<StunEndAttemptEvent> args)
|
||||
{
|
||||
if (args.Args.Cancelled)
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureComp<SlowedDownComponent>(ent, out var comp);
|
||||
|
||||
comp.WalkSpeedModifier = walkSpeedModifier;
|
||||
|
||||
comp.SprintSpeedModifier = runSpeedModifier;
|
||||
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(ent);
|
||||
|
||||
Dirty(ent);
|
||||
var ev = args.Args;
|
||||
ev.Cancelled = true;
|
||||
args.Args = ev;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A convenience overload of <see cref="UpdateStunModifiers(EntityUid, float, float, StaminaComponent?)"/> that sets both
|
||||
/// walk and run speed modifiers to the same value.
|
||||
/// </summary>
|
||||
/// <param name="ent">Entity whose movement speed should be updated.</param>
|
||||
/// <param name="speedModifier">New walk and run speed modifier. Default is 1f (normal speed).</param>
|
||||
/// <param name="component">
|
||||
/// Optional <see cref="StaminaComponent"/> of the entity.
|
||||
/// </param>
|
||||
public void UpdateStunModifiers(Entity<StaminaComponent?> ent, float speedModifier = 1f)
|
||||
private void OnStandUpAttempt(Entity<KnockdownStatusEffectComponent> entity, ref StatusEffectRelayedEvent<StandUpAttemptEvent> args)
|
||||
{
|
||||
UpdateStunModifiers(ent, speedModifier, speedModifier);
|
||||
if (args.Args.Cancelled)
|
||||
return;
|
||||
|
||||
var ev = args.Args;
|
||||
ev.Cancelled = true;
|
||||
args.Args = ev;
|
||||
}
|
||||
|
||||
#region friction and movement listeners
|
||||
|
||||
private void OnRefreshMovespeed(EntityUid ent, SlowedDownComponent comp, RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
args.ModifySpeed(comp.WalkSpeedModifier, comp.SprintSpeedModifier);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Attempt Event Handling
|
||||
|
||||
private void OnMoveAttempt(EntityUid uid, StunnedComponent stunned, UpdateCanMoveEvent args)
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Stunnable;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedStunSystem))]
|
||||
public sealed partial class SlowedDownComponent : Component
|
||||
{
|
||||
[ViewVariables, DataField("sprintSpeedModifier"), AutoNetworkedField]
|
||||
public float SprintSpeedModifier = 0.5f;
|
||||
|
||||
[ViewVariables, DataField("walkSpeedModifier"), AutoNetworkedField]
|
||||
public float WalkSpeedModifier = 0.5f;
|
||||
}
|
||||
@@ -15,6 +15,12 @@ namespace Content.Shared.Stunnable;
|
||||
[ByRefEvent]
|
||||
public record struct StunnedEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Raised on a stunned entity when something wants to remove the stunned component.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct StunEndAttemptEvent(bool Cancelled);
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed on an entity before it is knocked down to see if it should be cancelled, and to determine
|
||||
/// knocked down arguments.
|
||||
@@ -29,7 +35,7 @@ public record struct KnockDownAttemptEvent(bool AutoStand, bool Drop)
|
||||
/// Raised directed on an entity when it is knocked down.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct KnockedDownEvent(TimeSpan Time);
|
||||
public record struct KnockedDownEvent(TimeSpan? Time);
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity that needs to refresh its knockdown modifiers
|
||||
|
||||
@@ -2,5 +2,8 @@ using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Stunnable;
|
||||
|
||||
/// <summary>
|
||||
/// This is used to temporarily prevent an entity from moving or acting.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedStunSystem))]
|
||||
public sealed partial class StunnedComponent : Component;
|
||||
|
||||
9
Content.Shared/Stunnable/StunnedStatusEffectComponent.cs
Normal file
9
Content.Shared/Stunnable/StunnedStatusEffectComponent.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Stunnable;
|
||||
|
||||
/// <summary>
|
||||
/// Stun as a status effect.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedStunSystem))]
|
||||
public sealed partial class StunnedStatusEffectComponent : Component;
|
||||
@@ -97,7 +97,7 @@ public sealed class MeleeThrowOnHitSystem : EntitySystem
|
||||
RaiseLocalEvent(target, ref startEvent);
|
||||
|
||||
if (ent.Comp.StunTime != null)
|
||||
_stun.TryParalyze(target, ent.Comp.StunTime.Value, false);
|
||||
_stun.TryAddParalyzeDuration(target, ent.Comp.StunTime.Value);
|
||||
|
||||
if (direction == Vector2.Zero)
|
||||
return;
|
||||
|
||||
@@ -143,8 +143,6 @@
|
||||
- type: Body
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- Stun
|
||||
- SlowedDown
|
||||
- Flashed
|
||||
- type: TypingIndicator
|
||||
proto: robot
|
||||
|
||||
@@ -19,9 +19,7 @@
|
||||
group: GenericNumber
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Stun
|
||||
- Electrocution
|
||||
- TemporaryBlindness
|
||||
- RadiationProtection
|
||||
|
||||
@@ -35,8 +35,6 @@
|
||||
bodyType: KinematicController # Same for all inheritors
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- Stun
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- type: Pullable
|
||||
@@ -385,7 +383,6 @@
|
||||
chemicalMaxVolume: 100
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- SlowedDown
|
||||
- Electrocution
|
||||
- type: MeleeWeapon
|
||||
soundHit:
|
||||
@@ -408,6 +405,7 @@
|
||||
- FootstepSound
|
||||
- CannotSuicide
|
||||
- DoorBumpOpener
|
||||
- StunImmune
|
||||
- type: NoSlip
|
||||
- type: ZombieImmune
|
||||
- type: ExaminableSolution
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
BaseUnshaded: dead_glow
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- Stun
|
||||
- Corporeal
|
||||
- Electrocution
|
||||
- StaminaModifier
|
||||
@@ -91,6 +90,7 @@
|
||||
- type: Tag
|
||||
tags:
|
||||
- FootstepSound
|
||||
- SlowImmune
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
- state: active
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- Stun
|
||||
- Corporeal
|
||||
- type: Damageable
|
||||
damageContainer: ManifestedSpirit
|
||||
@@ -83,3 +82,7 @@
|
||||
- type: Reactive
|
||||
groups:
|
||||
Acidic: [Touch]
|
||||
- type: Tag
|
||||
tags:
|
||||
- SlowImmune
|
||||
- KnockdownImmune
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
bodyType: KinematicController # Same for all inheritors
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- Stun
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- type: Repairable
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
baseSprintSpeed : 4
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- TemporaryBlindness
|
||||
@@ -32,6 +31,7 @@
|
||||
- type: Tag
|
||||
tags:
|
||||
- DoorBumpOpener
|
||||
- StunImmune
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
@@ -93,8 +93,6 @@
|
||||
baseDecayRate: 0.04
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- Stun
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- TemporaryBlindness
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
types: {}
|
||||
- type: StatusEffects # Overwriting basesimplemob to remove flash, getting flashed as dragon just feelsbad
|
||||
allowed:
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- TemporaryBlindness
|
||||
@@ -154,6 +153,7 @@
|
||||
tags:
|
||||
- CannotSuicide
|
||||
- DoorBumpOpener
|
||||
- StunImmune
|
||||
- type: Puller
|
||||
needsHands: false
|
||||
- type: RandomMetadata
|
||||
|
||||
@@ -119,9 +119,6 @@
|
||||
- !type:WashCreamPieReaction
|
||||
- type: StatusEffects
|
||||
allowed:
|
||||
- Stun
|
||||
- Friction
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- Drunk
|
||||
|
||||
@@ -19,6 +19,21 @@
|
||||
components:
|
||||
- MobState
|
||||
|
||||
- type: entity
|
||||
parent: StatusEffectBase
|
||||
id: MobStandStatusEffectBase
|
||||
abstract: true
|
||||
components:
|
||||
- type: StatusEffect
|
||||
whitelist:
|
||||
components:
|
||||
- MobState
|
||||
- StandingState
|
||||
requireAll: true
|
||||
blacklist: # This blacklist exists because mob prototypes are smelly and everything needs a standing state component.
|
||||
tags:
|
||||
- KnockdownImmune
|
||||
|
||||
# The creature sleeps so heavily that nothing can wake him up. Not even its own death.
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
@@ -26,6 +41,8 @@
|
||||
name: forced sleep
|
||||
components:
|
||||
- type: ForcedSleepingStatusEffect
|
||||
- type: StunnedStatusEffect
|
||||
- type: KnockdownStatusEffect
|
||||
|
||||
# This creature is asleep because it's disconnected from the game.
|
||||
- type: entity
|
||||
@@ -34,6 +51,8 @@
|
||||
name: forced sleep
|
||||
components:
|
||||
- type: ForcedSleepingStatusEffect
|
||||
- type: StunnedStatusEffect
|
||||
- type: KnockdownStatusEffect
|
||||
|
||||
# Blurs your vision and makes you randomly fall asleep
|
||||
- type: entity
|
||||
@@ -43,14 +62,6 @@
|
||||
components:
|
||||
- type: DrowsinessStatusEffect
|
||||
|
||||
# Makes you more slippery, or perhaps less slippery.
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
id: StatusEffectFriction
|
||||
name: friction
|
||||
components:
|
||||
- type: FrictionStatusEffect
|
||||
|
||||
# Adds drugs overlay
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
|
||||
67
Resources/Prototypes/Entities/StatusEffects/movement.yml
Normal file
67
Resources/Prototypes/Entities/StatusEffects/movement.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
id: StatusEffectSlowdown
|
||||
abstract: true
|
||||
name: slowdown
|
||||
components:
|
||||
- type: StatusEffect
|
||||
whitelist:
|
||||
components:
|
||||
- MobState
|
||||
blacklist:
|
||||
tags:
|
||||
- SlowImmune
|
||||
- type: MovementModStatusEffect
|
||||
|
||||
- type: entity
|
||||
parent: StatusEffectSlowdown
|
||||
id: VomitingSlowdownStatusEffect
|
||||
name: vomiting slowdown
|
||||
|
||||
- type: entity
|
||||
parent: StatusEffectSlowdown
|
||||
id: TaserSlowdownStatusEffect
|
||||
name: shot by taser slowdown
|
||||
|
||||
- type: entity
|
||||
parent: StatusEffectSlowdown
|
||||
id: FlashSlowdownStatusEffect
|
||||
name: affected by flash slowdown
|
||||
|
||||
- type: entity
|
||||
parent: StatusEffectSlowdown
|
||||
id: StatusEffectStaminaLow
|
||||
name: stamina low
|
||||
|
||||
# Makes you more slippery, or perhaps less slippery.
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
id: StatusEffectFriction
|
||||
name: friction
|
||||
components:
|
||||
- type: FrictionStatusEffect
|
||||
|
||||
# Stunnable Status Effect
|
||||
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
id: StatusEffectStunned
|
||||
name: stunned
|
||||
components:
|
||||
- type: StatusEffect
|
||||
whitelist:
|
||||
components:
|
||||
- MobState
|
||||
blacklist:
|
||||
tags:
|
||||
- StunImmune
|
||||
- type: StatusEffectAlert
|
||||
alert: Stun
|
||||
- type: StunnedStatusEffect
|
||||
|
||||
- type: entity
|
||||
parent: MobStandStatusEffectBase
|
||||
id: StatusEffectKnockdown
|
||||
name: knocked down
|
||||
components:
|
||||
- type: KnockdownStatusEffect
|
||||
@@ -831,6 +831,9 @@
|
||||
- type: Tag
|
||||
id: Knife
|
||||
|
||||
- type: Tag
|
||||
id: KnockdownImmune
|
||||
|
||||
- type: Tag
|
||||
id: LavaBrig
|
||||
|
||||
@@ -1268,6 +1271,9 @@
|
||||
- type: Tag
|
||||
id: Slice # sliced fruit, vegetables, pizza etc.
|
||||
|
||||
- type: Tag
|
||||
id: SlowImmune
|
||||
|
||||
- type: Tag
|
||||
id: SmallAIChip
|
||||
|
||||
@@ -1331,6 +1337,9 @@
|
||||
- type: Tag
|
||||
id: StringInstrument
|
||||
|
||||
- type: Tag
|
||||
id: StunImmune
|
||||
|
||||
- type: Tag
|
||||
id: SubdermalImplant
|
||||
|
||||
|
||||
Reference in New Issue
Block a user