Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
<Label Name="BloodLabel" />
<Label Text="{Loc 'health-analyzer-window-entity-damage-total-text'}" />
<Label Name="DamageLabel" />
<!-- ADT-Tweak-Start -->
<Label Name="AllergyText" Text="{Loc 'health-analyzer-window-entity-allergy-text'}" />
<!-- ADT-Tweak-End -->
</GridContainer>
</BoxContainer>

Expand Down
6 changes: 6 additions & 0 deletions Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using Robust.Client.ResourceManagement;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using Content.Shared.ADT.Body.Allergies;

namespace Content.Client.HealthAnalyzer.UI
{
Expand Down Expand Up @@ -131,6 +132,11 @@ public void Populate(HealthAnalyzerScannedUserMessage msg)

DamageLabel.Text = damageable.TotalDamage.ToString();

// ADT-Tweak-Start
bool allergic = _entityManager.HasComponent<AllergicComponent>(target.Value);
AllergyText.Visible = allergic;
// ADT-Tweak-End

// Alerts

var showAlerts = msg.Unrevivable == true || msg.Bleeding == true;
Expand Down
16 changes: 16 additions & 0 deletions Content.Server/ADT/Body/AllergicEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Prototypes;

namespace Content.Server.ADT.Body;

/// <summary>
/// When allergy triggered by allergens in bloodstream.
/// </summary>
[ByRefEvent]
public struct AllergyTriggeredEvent;

/// <summary>
/// When allergy stack has faded to zero.
/// </summary>
[ByRefEvent]
public struct AllergyFadedEvent;
62 changes: 62 additions & 0 deletions Content.Server/ADT/Body/AllergicSystem.Shock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Linq;
using Content.Shared.ADT.Body.Allergies;
using Content.Shared.ADT.Body.Allergies.Prototypes;
using Content.Shared.EntityEffects;
using Robust.Shared.Timing;

namespace Content.Server.ADT.Body;

public sealed partial class AllergicSystem : EntitySystem
{
private List<AllergicReactionPrototype> _reactions = new();

[Dependency] private IGameTiming _timing = default!;
[Dependency] private SharedEntityEffectsSystem _effectSystem = default!;

public void InitializeShock()
{
SubscribeLocalEvent<AllergicComponent, AllergyFadedEvent>(Unshock);
_reactions = _proto.EnumeratePrototypes<AllergicReactionPrototype>().ToList();
}

private void Unshock(EntityUid uid, AllergicComponent allergic, ref AllergyFadedEvent ev)
{
allergic.NextShockEvent = TimeSpan.Zero;
}

private void AssignNextShockTiming(AllergicComponent allergic)
{
allergic.NextShockEvent = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(allergic.MinimumTimeTilNextShockEvent, allergic.MaximumTimeTilNextShockEvent));
}

private void UpdateShock(EntityUid uid, AllergicComponent allergic)
{
if (allergic.AllergyStack <= 0)
return;

if (allergic.NextShockEvent == TimeSpan.Zero)
{
AssignNextShockTiming(allergic);
return;
}

if (allergic.NextShockEvent > _timing.CurTime)
return;

AllergicReactionPrototype? picked = null;

foreach (var reaction in _reactions)
{
if (allergic.AllergyStack >= reaction.StackThreshold)
picked = reaction;
}

if (picked != null)
{
EntityEffect effect = picked.Effects[_random.Next(0, picked.Effects.Count())];
_effectSystem.ApplyEffect(uid, effect);
}

AssignNextShockTiming(allergic);
}
}
62 changes: 62 additions & 0 deletions Content.Server/ADT/Body/AllergicSystem.Stacks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Linq;
using Content.Shared.ADT.Body.Allergies;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Prototypes;

namespace Content.Server.ADT.Body;

public sealed partial class AllergicSystem : EntitySystem
{
#region Events

private void IncrementStackOnTrigger(EntityUid uid, AllergicComponent allergic, ref AllergyTriggeredEvent ev)
{
AdjustAllergyStack(uid, allergic.StackGrow, allergic);
}

#endregion

#region Flow

private void UpdateStack(EntityUid uid, AllergicComponent allergic)
{
if (allergic.AllergyStack <= 0)
return;

if (allergic.NextStackFade > _timing.CurTime)
return;

float newStack = allergic.AllergyStack + allergic.StackFade;
SetAllergyStack(uid, newStack, allergic);

if (newStack <= 0)
{
var faded = new AllergyFadedEvent();
RaiseLocalEvent(uid, ref faded);
}

allergic.NextStackFade = allergic.NextStackFade + allergic.StackFadeRate;
}

#endregion

#region API

public void AdjustAllergyStack(EntityUid uid, float relativeStack, AllergicComponent? allergic = null)
{
if (!Resolve(uid, ref allergic))
return;

SetAllergyStack(uid, allergic.AllergyStack + relativeStack, allergic);
}

public void SetAllergyStack(EntityUid uid, float stack, AllergicComponent? allergic = null)
{
if (!Resolve(uid, ref allergic))
return;

allergic.AllergyStack = MathF.Min(MathF.Max(0, stack), allergic.MaximumStack);
}

#endregion
}
105 changes: 105 additions & 0 deletions Content.Server/ADT/Body/AllergicSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System.Linq;
using Content.Server.Body.Systems;
using Content.Shared.ADT.Body.Allergies;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.EntityEffects.Effects;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;

namespace Content.Server.ADT.Body;

public sealed partial class AllergicSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;

private ProtoId<DamageTypePrototype> _allergyDamageType = "Poison";
private DamageTypePrototype? _allergyDamageTypeProto;

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

SubscribeLocalEvent<AllergicComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<AllergicComponent, GetReagentEffectsEvent>(OnGetReagentEffects);

SubscribeLocalEvent<AllergicComponent, AllergyTriggeredEvent>(OnAllergyTriggered);

InitializeShock();

_allergyDamageTypeProto = _proto.Index<DamageTypePrototype>(_allergyDamageType);
}

public void OnInit(EntityUid uid, AllergicComponent component, ComponentInit args)
{
component.Triggers = GetRandomAllergies(component.Min, component.Max);
}

public void OnGetReagentEffects(EntityUid uid, AllergicComponent component, ref GetReagentEffectsEvent ev)
{
if (!component.Triggers.Contains(ev.Reagent.Prototype))
return;

var damageSpecifier = new DamageSpecifier(_allergyDamageTypeProto!, 0.25);
var damageEffect = new HealthChange
{
Damage = damageSpecifier
};

AllergyTriggeredEvent triggered = new();
RaiseLocalEvent(uid, ref triggered);

ev.Effects = ev.Effects.Append(damageEffect).ToArray();
}

private void OnAllergyTriggered(EntityUid uid, AllergicComponent allergic, ref AllergyTriggeredEvent ev)
{
IncrementStackOnTrigger(uid, allergic, ref ev);
}

private List<ProtoId<ReagentPrototype>> GetRandomAllergies(int min, int max)
{
int reagentsCount = _proto.Count<ReagentPrototype>();

if (reagentsCount == 0)
return new();

int safeMin = Math.Clamp(min, 0, reagentsCount);
int safeMax = Math.Clamp(max, safeMin, reagentsCount);
int allergiesCount = _random.Next(safeMin, safeMax + 1);

var picked = new HashSet<int>();
while (picked.Count < allergiesCount)
{
picked.Add(_random.Next(reagentsCount));
}

int index = 0;
List<ProtoId<ReagentPrototype>> allergies = new();

foreach (var proto in _proto.EnumeratePrototypes<ReagentPrototype>())
{
if (picked.Contains(index))
allergies.Add(proto.ID);
index++;
}

return allergies;
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var query = EntityQueryEnumerator<AllergicComponent>();

while (query.MoveNext(out var uid, out var allergic))
{
UpdateStack(uid, allergic);
UpdateShock(uid, allergic);
}
}
}
Loading
Loading