diff --git a/Content.Shared/EntityEffects/Effects/StatusEffects/GenericStatusEffect.cs b/Content.Shared/EntityEffects/Effects/StatusEffects/GenericStatusEffect.cs index b770023604..652c1b90a1 100644 --- a/Content.Shared/EntityEffects/Effects/StatusEffects/GenericStatusEffect.cs +++ b/Content.Shared/EntityEffects/Effects/StatusEffects/GenericStatusEffect.cs @@ -69,6 +69,7 @@ public sealed partial class GenericStatusEffect : EntityEffect public enum StatusEffectMetabolismType { + Update, Add, Remove, Set diff --git a/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyKnockdown.cs b/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyKnockdown.cs new file mode 100644 index 0000000000..59ca5da0f7 --- /dev/null +++ b/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyKnockdown.cs @@ -0,0 +1,99 @@ +using Content.Shared.Stunnable; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityEffects.Effects.StatusEffects; + +/// +/// Changes the knockdown timer on an entity or causes knockdown. +/// +[UsedImplicitly] +public sealed partial class ModifyKnockdown : EntityEffect +{ + /// + /// Should we only affect those with crawler component? Note if this is false, it will paralyze non-crawler's instead. + /// + [DataField] + public bool Crawling; + + /// + /// Should we drop items when we fall? + /// + [DataField] + public bool Drop; + + /// + /// Time for which knockdown should be applied. Behaviour changes according to . + /// + [DataField] + public TimeSpan Time = TimeSpan.FromSeconds(0.5); + + /// + /// Should this effect add the status effect, remove time from it, or set its cooldown? + /// + [DataField] + public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Add; + + /// + /// Should this effect add knockdown?, remove time from it?, or set its cooldown? + /// + [DataField] + public bool Refresh = true; + + /// + public override void Effect(EntityEffectBaseArgs args) + { + var stunSys = args.EntityManager.EntitySysManager.GetEntitySystem(); + + var time = Time; + if (args is EntityEffectReagentArgs reagentArgs) + time *= reagentArgs.Scale.Float(); + + switch (Type) + { + case StatusEffectMetabolismType.Update: + if (Crawling) + { + stunSys.TryCrawling(args.TargetEntity, time, drop: Drop); + } + else + { + stunSys.TryKnockdown(args.TargetEntity, time, drop: Drop); + } + break; + case StatusEffectMetabolismType.Add: + if (Crawling) + { + stunSys.TryCrawling(args.TargetEntity, time, false, drop: Drop); + } + else + { + stunSys.TryKnockdown(args.TargetEntity, time, false, drop: Drop); + } + break; + case StatusEffectMetabolismType.Remove: + stunSys.AddKnockdownTime(args.TargetEntity, -time); + break; + case StatusEffectMetabolismType.Set: + if (Crawling) + { + stunSys.TryCrawling(args.TargetEntity, time, drop: Drop); + } + else + { + stunSys.TryKnockdown(args.TargetEntity, time, drop: Drop); + } + stunSys.SetKnockdownTime(args.TargetEntity, time); + break; + } + } + + /// + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString( + "reagent-effect-guidebook-knockdown", + ("chance", Probability), + ("type", Type), + ("time", Time.TotalSeconds) + ); +} diff --git a/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs b/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs index cb010b648c..d7bf6482bd 100644 --- a/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs +++ b/Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs @@ -25,12 +25,6 @@ public sealed partial class ModifyStatusEffect : EntityEffect [DataField] public float Delay = 0f; - /// - /// true - refresh status effect time (update to greater value), false - accumulate status effect time. - /// - [DataField] - public bool Refresh = true; - /// /// Should this effect add the status effect, remove time from it, or set its cooldown? /// @@ -49,11 +43,11 @@ public sealed partial class ModifyStatusEffect : EntityEffect var duration = TimeSpan.FromSeconds(time); switch (Type) { + case StatusEffectMetabolismType.Update: + statusSys.TryUpdateStatusEffectDuration(args.TargetEntity, EffectProto, duration, Delay > 0 ? TimeSpan.FromSeconds(Delay) : null); + break; case StatusEffectMetabolismType.Add: - if (Refresh) - statusSys.TryUpdateStatusEffectDuration(args.TargetEntity, EffectProto, duration, Delay > 0 ? TimeSpan.FromSeconds(Delay) : null); - else - statusSys.TryAddStatusEffectDuration(args.TargetEntity, EffectProto, duration, Delay > 0 ? TimeSpan.FromSeconds(Delay) : null); + statusSys.TryAddStatusEffectDuration(args.TargetEntity, EffectProto, duration, Delay > 0 ? TimeSpan.FromSeconds(Delay) : null); break; case StatusEffectMetabolismType.Remove: statusSys.TryAddTime(args.TargetEntity, EffectProto, -duration); diff --git a/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs b/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs index 3646dc8f28..f484bd012e 100644 --- a/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs +++ b/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs @@ -95,7 +95,7 @@ public abstract partial class SharedStunSystem private void OnRejuvenate(Entity entity, ref RejuvenateEvent args) { - SetKnockdownTime(entity, GameTiming.CurTime); + SetKnockdownNextUpdate((entity, entity), GameTiming.CurTime); if (entity.Comp.AutoStand) RemComp(entity); @@ -156,6 +156,19 @@ public abstract partial class SharedStunSystem DirtyField(entity, entity.Comp, nameof(KnockedDownComponent.DoAfterId)); } + /// + /// Sets the time left of the knockdown timer to the inputted value. + /// + /// Entity who's knockdown time we're updating. + /// The time we're updating with. + public void SetKnockdownTime(Entity entity, TimeSpan time) + { + if (!Resolve(entity, ref entity.Comp, false)) + return; + + SetKnockdownNextUpdate(entity, GameTiming.CurTime + time); + } + /// /// Updates the knockdown timer of a knocked down entity with a given inputted time, then dirties the time. /// @@ -170,18 +183,6 @@ public abstract partial class SharedStunSystem AddKnockdownTime(entity, time); } - /// - /// Sets the next update datafield of an entity's to a specific time. - /// - /// Entity whose timer we're updating - /// The exact time we're setting the next update to. - public void SetKnockdownTime(Entity entity, TimeSpan time) - { - entity.Comp.NextUpdate = time; - DirtyField(entity, entity.Comp, nameof(KnockedDownComponent.NextUpdate)); - Alerts.ShowAlert(entity.Owner, KnockdownAlert, null, (GameTiming.CurTime, entity.Comp.NextUpdate)); - } - /// /// Refreshes the amount of time an entity is knocked down to the inputted time, if it is greater than /// the current time left. @@ -195,7 +196,7 @@ public abstract partial class SharedStunSystem var knockedTime = GameTiming.CurTime + time; if (entity.Comp.NextUpdate < knockedTime) - SetKnockdownTime((entity, entity.Comp), knockedTime); + SetKnockdownNextUpdate((entity, entity.Comp), knockedTime); } /// @@ -210,19 +211,35 @@ public abstract partial class SharedStunSystem if (entity.Comp.NextUpdate < GameTiming.CurTime) { - SetKnockdownTime((entity, entity.Comp), GameTiming.CurTime + time); + SetKnockdownNextUpdate((entity, entity.Comp), GameTiming.CurTime + time); return; } - entity.Comp.NextUpdate += time; - DirtyField(entity, entity.Comp, nameof(KnockedDownComponent.NextUpdate)); - Alerts.ShowAlert(entity.Owner, KnockdownAlert, null, (GameTiming.CurTime, entity.Comp.NextUpdate)); + SetKnockdownNextUpdate((entity, entity.Comp), entity.Comp.NextUpdate + time); } #endregion #region Knockdown Logic + /// + /// Sets the next update datafield of an entity's to a specific time. + /// + /// Entity whose timer we're updating + /// The exact time we're setting the next update to. + private void SetKnockdownNextUpdate(Entity entity, TimeSpan time) + { + if (!Resolve(entity, ref entity.Comp, false)) + return; + + if (GameTiming.CurTime > time) + time = GameTiming.CurTime; + + entity.Comp.NextUpdate = time; + DirtyField(entity, entity.Comp, nameof(KnockedDownComponent.NextUpdate)); + Alerts.UpdateAlert(entity.Owner, KnockdownAlert, null, entity.Comp.NextUpdate); + } + private void HandleToggleKnockdown(ICommonSession? session) { if (session is not { } playerSession) diff --git a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl index 1ab89f89a3..07c908c035 100644 --- a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl +++ b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl @@ -104,6 +104,10 @@ reagent-effect-guidebook-even-health-change = reagent-effect-guidebook-status-effect = { $type -> + [update]{ $chance -> + [1] Causes + *[other] cause + } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation [add] { $chance -> [1] Causes *[other] cause @@ -134,6 +138,26 @@ reagent-effect-guidebook-status-effect-delay = } {NATURALFIXED($time, 3)} {MANY("second", $time)} of {LOC($key)} } after a {NATURALFIXED($delay, 3)} second delay +reagent-effect-guidebook-knockdown = + { $type -> + [update]{ $chance -> + [1] Causes + *[other] cause + } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation + [add] { $chance -> + [1] Causes + *[other] cause + } knockdown for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} with accumulation + *[set] { $chance -> + [1] Causes + *[other] cause + } knockdown for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation + [remove]{ $chance -> + [1] Removes + *[other] remove + } {NATURALFIXED($time, 3)} {MANY("second", $time)} of knockdown + } + reagent-effect-guidebook-set-solution-temperature-effect = { $chance -> [1] Sets diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml index 741108cca1..9bd5bb195f 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml @@ -34,7 +34,6 @@ min: 10 type: Add time: 5 - refresh: false - !type:PopupMessage type: Local messages: diff --git a/Resources/Prototypes/Reagents/cleaning.yml b/Resources/Prototypes/Reagents/cleaning.yml index d03fff1941..2ebd213fec 100644 --- a/Resources/Prototypes/Reagents/cleaning.yml +++ b/Resources/Prototypes/Reagents/cleaning.yml @@ -114,7 +114,6 @@ effectProto: StatusEffectSeeingRainbow time: 5 type: Add - refresh: false Drink: effects: - !type:GenericStatusEffect diff --git a/Resources/Prototypes/Reagents/gases.yml b/Resources/Prototypes/Reagents/gases.yml index b3a533d747..3d65931f19 100644 --- a/Resources/Prototypes/Reagents/gases.yml +++ b/Resources/Prototypes/Reagents/gases.yml @@ -372,7 +372,7 @@ shouldHave: false effectProto: StatusEffectForcedSleeping time: 3 - type: Add + type: Update - !type:HealthChange conditions: - !type:ReagentThreshold @@ -412,7 +412,6 @@ effectProto: StatusEffectSeeingRainbow type: Add time: 15 - refresh: false - !type:Drunk boozePower: 15 - !type:PopupMessage @@ -452,7 +451,6 @@ effectProto: StatusEffectSeeingRainbow type: Add time: 500 - refresh: false - !type:Drunk boozePower: 500 conditions: diff --git a/Resources/Prototypes/Reagents/medicine.yml b/Resources/Prototypes/Reagents/medicine.yml index bfbb8242fd..71ae11dad9 100644 --- a/Resources/Prototypes/Reagents/medicine.yml +++ b/Resources/Prototypes/Reagents/medicine.yml @@ -89,7 +89,6 @@ effectProto: StatusEffectDrowsiness time: 1.5 type: Add - refresh: false - !type:HealthChange damage: types: @@ -364,12 +363,11 @@ min: 1 reagent: Histamine amount: 4 - - !type:GenericStatusEffect - key: Stun + - !type:ModifyStatusEffect + effectProto: StatusEffectStunned time: 0.75 type: Remove - - !type:GenericStatusEffect - key: KnockedDown + - !type:ModifyKnockdown time: 0.75 type: Remove - !type:GenericStatusEffect @@ -744,12 +742,11 @@ damage: types: Poison: 2 - - !type:GenericStatusEffect - key: Stun + - !type:ModifyStatusEffect + effectProto: StatusEffectStunned time: 3.0 type: Remove - - !type:GenericStatusEffect - key: KnockedDown + - !type:ModifyKnockdown time: 3.0 type: Remove - !type:ModifyStatusEffect @@ -1354,7 +1351,6 @@ min: 30 type: Add time: 8 - refresh: false - !type:GenericStatusEffect key: Jitter time: 2.0 @@ -1416,7 +1412,6 @@ effectProto: StatusEffectDrowsiness time: 4 type: Add - refresh: false - !type:GenericStatusEffect key: Jitter time: 4.0 diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml index 3658a50f50..a1b1033a4b 100644 --- a/Resources/Prototypes/Reagents/narcotics.yml +++ b/Resources/Prototypes/Reagents/narcotics.yml @@ -33,12 +33,11 @@ key: Stutter component: StutteringAccent - !type:Jitter - - !type:GenericStatusEffect - key: Stun + - !type:ModifyStatusEffect + effectProto: StatusEffectStunned time: 3 type: Remove - - !type:GenericStatusEffect - key: KnockedDown + - !type:ModifyKnockdown time: 3 type: Remove - !type:ModifyStatusEffect @@ -82,12 +81,11 @@ Poison: 2 # this is added to the base damage of the meth. Asphyxiation: 2 - !type:Jitter - - !type:GenericStatusEffect - key: Stun + - !type:ModifyStatusEffect + effectProto: StatusEffectStunned time: 1 type: Remove - - !type:GenericStatusEffect - key: KnockedDown + - !type:ModifyKnockdown time: 1 type: Remove - !type:ModifyStatusEffect @@ -142,12 +140,11 @@ min: 1 reagent: ChloralHydrate amount: -10 - - !type:GenericStatusEffect - key: Stun + - !type:ModifyStatusEffect + effectProto: StatusEffectStunned time: 3 type: Remove - - !type:GenericStatusEffect - key: KnockedDown + - !type:ModifyKnockdown time: 3 type: Remove - !type:GenericStatusEffect @@ -205,7 +202,6 @@ effectProto: StatusEffectSeeingRainbow time: 16 type: Add - refresh: false - type: reagent id: Nicotine @@ -243,7 +239,6 @@ effectProto: StatusEffectSeeingRainbow time: 10 type: Add - refresh: false - !type:ChemVomit # Vomiting is a symptom of brain damage probability: 0.05 - !type:Drunk # Headaches and slurring are major symptoms of brain damage, this is close enough @@ -264,7 +259,6 @@ effectProto: StatusEffectSeeingRainbow type: Add time: 5 - refresh: false - type: reagent id: Bananadine @@ -281,7 +275,6 @@ effectProto: StatusEffectSeeingRainbow type: Add time: 5 - refresh: false # Probably replace this one with sleeping chem when putting someone in a comatose state is easier - type: reagent @@ -325,7 +318,6 @@ component: Muted type: Add time: 10 - refresh: false - type: reagent id: NorepinephricAcid @@ -477,4 +469,3 @@ effectProto: StatusEffectSeeingRainbow type: Add time: 5 - refresh: false diff --git a/Resources/Prototypes/Reagents/toxins.yml b/Resources/Prototypes/Reagents/toxins.yml index e94d13a891..33a94c0792 100644 --- a/Resources/Prototypes/Reagents/toxins.yml +++ b/Resources/Prototypes/Reagents/toxins.yml @@ -74,7 +74,6 @@ effectProto: StatusEffectDrowsiness time: 4 type: Add - refresh: false - !type:HealthChange conditions: - !type:ReagentThreshold @@ -359,7 +358,6 @@ effectProto: StatusEffectSeeingRainbow type: Add time: 10 - refresh: false # TODO: PROPER hallucinations - type: reagent