Skip to content

Commit

Permalink
Proof of concept for woundmed/ailmentmed
Browse files Browse the repository at this point in the history
  • Loading branch information
sowelipililimute committed Feb 10, 2025
1 parent d0a2d62 commit a087210
Show file tree
Hide file tree
Showing 19 changed files with 802 additions and 1 deletion.
18 changes: 17 additions & 1 deletion Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Linq;
using System.Numerics;
using Content.Client.Message;
using Content.Shared._DV.Ailments; // DeltaV
using Content.Shared._DV.Traits.Assorted; // DeltaV
using Content.Shared.Atmos;
using Content.Client.UserInterface.Controls;
Expand Down Expand Up @@ -38,6 +39,7 @@ public sealed partial class HealthAnalyzerWindow : FancyWindow
private readonly IPrototypeManager _prototypes;
private readonly IResourceCache _cache;
private readonly UnborgableSystem _unborgable; // DeltaV
private readonly SharedAilmentSystem _ailments; // DeltaV

// Shitmed Change Start
public event Action<TargetBodyPart?, EntityUid>? OnBodyPartSelected;
Expand All @@ -60,6 +62,7 @@ public HealthAnalyzerWindow()
_prototypes = dependencies.Resolve<IPrototypeManager>();
_cache = dependencies.Resolve<IResourceCache>();
_unborgable = _entityManager.System<UnborgableSystem>(); // DeltaV
_ailments = _entityManager.System<SharedAilmentSystem>(); // DeltaV
// Shitmed Change Start
_bodyPartControls = new Dictionary<TargetBodyPart, TextureButton>
{
Expand Down Expand Up @@ -187,8 +190,9 @@ public void Populate(HealthAnalyzerScannedUserMessage msg)

// Alerts

var ailments = _ailments.HealthAnalyzerMessages(part is {} partId ? partId : _target.Value); // DeltaV: ailments
var unborgable = _unborgable.IsUnborgable(_target.Value); // DeltaV
var showAlerts = msg.Unrevivable == true || msg.Bleeding == true || unborgable;
var showAlerts = msg.Unrevivable == true || msg.Bleeding == true || unborgable || ailments.Count > 0;

AlertsDivider.Visible = showAlerts;
AlertsContainer.Visible = showAlerts;
Expand Down Expand Up @@ -220,6 +224,18 @@ public void Populate(HealthAnalyzerScannedUserMessage msg)
MaxWidth = 300
});

// Begin DeltaV: ailments
foreach (var ailment in ailments)
{
AlertsContainer.AddChild(new RichTextLabel
{
Text = ailment,
Margin = new Thickness(0, 4),
MaxWidth = 300
});
}
// End DeltaV: ailments

// Damage Groups

var damageSortedGroups =
Expand Down
5 changes: 5 additions & 0 deletions Content.Client/_DV/Ailments/AilmentSurgerySystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Content.Shared._DV.Ailments;

namespace Content.Client._DV.Ailments;

public partial class AilmentSurgerySystem : SharedAilmentSurgerySystem;
5 changes: 5 additions & 0 deletions Content.Client/_DV/Ailments/AilmentSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Content.Shared._DV.Ailments;

namespace Content.Client._DV.Ailments;

public partial class AilmentSystem : SharedAilmentSystem;
5 changes: 5 additions & 0 deletions Content.Server/_DV/Ailments/AilmentSurgerySystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Content.Shared._DV.Ailments;

namespace Content.Server._DV.Ailments;

public partial class AilmentSurgerySystem : SharedAilmentSurgerySystem;
5 changes: 5 additions & 0 deletions Content.Server/_DV/Ailments/AilmentSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Content.Shared._DV.Ailments;

namespace Content.Server._DV.Ailments;

public partial class AilmentSystem : SharedAilmentSystem;
67 changes: 67 additions & 0 deletions Content.Server/_DV/EntityEffects/Conditions/TypeDamage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Content.Shared.EntityEffects;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;

namespace Content.Server._DV.EntityEffects.EffectConditions;

public sealed partial class TypeDamage : EntityEffectCondition
{
[DataField]
public FixedPoint2 Max = FixedPoint2.MaxValue;

[DataField]
public FixedPoint2 Min = FixedPoint2.Zero;

[DataField]
public ProtoId<DamageGroupPrototype>? DamageGroup;

[DataField]
public ProtoId<DamageTypePrototype>? DamageType;

public override bool Condition(EntityEffectBaseArgs args)
{
if (args.EntityManager.TryGetComponent(args.TargetEntity, out DamageableComponent? damage))
{
FixedPoint2 total;
if (DamageGroup is { } group)
total = damage.DamagePerGroup.GetValueOrDefault(group, FixedPoint2.Zero);
else if (DamageType is { } kind)
total = damage.Damage.DamageDict.GetValueOrDefault(kind, FixedPoint2.Zero);
else
total = damage.TotalDamage;

if (total >= Min && total <= Max)
return true;
}

return false;
}

public override string GuidebookExplanation(IPrototypeManager prototype)
{
if (DamageGroup is { } group)
{
var name = prototype.Index(group).LocalizedName;
return Loc.GetString("reagent-effect-condition-guidebook-group-damage",
("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
("min", Min.Float()),
("group", name));
}
else if (DamageType is { } kind)
{
var name = prototype.Index(kind).LocalizedName;
return Loc.GetString("reagent-effect-condition-guidebook-type-damage",
("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
("min", Min.Float()),
("type", name));
}
else
{
return Loc.GetString("reagent-effect-condition-guidebook-total-damage",
("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
("min", Min.Float()));
}
}
}
19 changes: 19 additions & 0 deletions Content.Shared/_DV/Ailments/AilmentComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Content.Shared._DV.Ailments;
using Robust.Shared.Analyzers;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared._DV.Ailments;

/// <summary>
/// Contains the set of possible ailment packs & the currently active ailments in those packs, similar to a damage container
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class AilmentComponent : Component
{
[DataField, ViewVariables, AutoNetworkedField]
public List<ProtoId<AilmentPackPrototype>> Packs = default!;

[DataField, ViewVariables, AutoNetworkedField]
public Dictionary<ProtoId<AilmentPackPrototype>, ProtoId<AilmentPrototype>?> ActiveAilments = new();
}
140 changes: 140 additions & 0 deletions Content.Shared/_DV/Ailments/AilmentPrototype.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
using Content.Shared.EntityEffects;

namespace Content.Shared._DV.Ailments;

/// <summary>
/// Represents some condition on the body that isn't numerical damage
/// </summary>
[Prototype]
public sealed partial class AilmentPrototype : IPrototype, IInheritingPrototype
{
/// <inheritdoc/>
[IdDataField]
[ViewVariables]
public string ID { get; private set; } = default!;

/// <summary>
/// What this ailment shows up as on the health scanner, if anything
/// </summary>
[DataField]
public LocId? HealthAnalyzerDescription { get; set; } = default!;

[ViewVariables(VVAccess.ReadOnly)]
public string? LocalizedHealthAnalyzerDescription => HealthAnalyzerDescription is null ? null : Loc.GetString(HealthAnalyzerDescription);

/// <inheritdoc/>
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<AilmentPrototype>))]
[ViewVariables]
public string[]? Parents { get; private set; } = default!;

[NeverPushInheritance]
[AbstractDataField]
[ViewVariables]
public bool Abstract { get; private set; } = default!;

/// <summary>
/// Entity effects to run when this ailment becomes active
/// </summary>
[DataField(serverOnly: true)]
[ViewVariables]
public EntityEffect[] Mount { get; private set; } = default!;

/// <summary>
/// Entity effects to run when this ailment becomes inactive
/// </summary>
[DataField(serverOnly: true)]
[ViewVariables]
public EntityEffect[] Unmount { get; private set; } = default!;

/// <summary>
/// Entity effects to run twice per second when this ailment is active
/// </summary>
[DataField(serverOnly: true)]
[ViewVariables]
public EntityEffect[] Periodic { get; private set; } = default!;
}

/// <summary>
/// Represents a transition from one ailment to another, e.g. from being fine to having a minor bone fracture
/// </summary>
[Prototype]
public sealed partial class AilmentTransitionPrototype : IPrototype, IInheritingPrototype
{
/// <inheritdoc/>
[IdDataField]
[ViewVariables]
public string ID { get; private set; } = default!;

/// <inheritdoc/>
[ParentDataField(typeof(AbstractPrototypeIdArraySerializer<AilmentTransitionPrototype>))]
[ViewVariables]
public string[]? Parents { get; private set; } = default!;

[NeverPushInheritance]
[AbstractDataField]
[ViewVariables]
public bool Abstract { get; private set; } = default!;

/// <summary>
/// The chance for the transition to trigger if the trigger conditions are met
/// </summary>
[ViewVariables]
public float TriggerChance { get; private set; } = 1f;

/// <summary>
/// Conditions for the transition, that when met, will cause the transition to fire without outside intervention
/// </summary>
[DataField(serverOnly: true)]
[ViewVariables]
public EntityEffectCondition[]? Triggers { get; private set; } = default!;

/// <summary>
/// Conditions for the transition, that are required but don't cause a transition without outside intervention
/// </summary>
[DataField(serverOnly: true)]
[ViewVariables]
public EntityEffectCondition[] Conditions { get; private set; } = new EntityEffectCondition[] {};

/// <summary>
/// Effects that run when this transition is taken
/// </summary>
[DataField(serverOnly: true)]
[ViewVariables]
public EntityEffect[]? Effects { get; private set; } = default!;

/// <summary>
/// Which ailment we're transitioning from
/// </summary>
[DataField(required: true)]
[ViewVariables]
public ProtoId<AilmentPrototype>? Start { get; private set; } = default!;

/// <summary>
/// Which ailment we're transitioning to
/// </summary>
[DataField(required: true)]
[ViewVariables]
public ProtoId<AilmentPrototype>? End { get; private set; } = default!;
}

/// <summary>
/// A collection of ailments and transitions between them. Only one ailment in a pack can be active at a time.
/// </summary>
[Prototype]
public sealed partial class AilmentPackPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
[ViewVariables]
public string ID { get; private set; } = default!;

[DataField]
[ViewVariables]
public ProtoId<AilmentPrototype>[] Ailments { get; private set; } = default!;

[DataField]
[ViewVariables]
public ProtoId<AilmentTransitionPrototype>[] Transitions { get; private set; } = default!;
}
52 changes: 52 additions & 0 deletions Content.Shared/_DV/Ailments/SharedAilmentSurgerySystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Content.Shared._Shitmed.Medical.Surgery.Conditions;
using Content.Shared._Shitmed.Medical.Surgery.Steps;
using Content.Shared._Shitmed.Medical.Surgery;
using Content.Shared.EntityEffects;
using Robust.Shared.Prototypes;

namespace Content.Shared._DV.Ailments;

public abstract partial class SharedAilmentSurgerySystem : EntitySystem
{
[Dependency] private readonly SharedAilmentSystem _ailments = default!;

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

SubscribeLocalEvent<SurgeryHasAilmentConditionComponent, SurgeryValidEvent>(OnAilmentConditionValid);
SubscribeLocalEvent<SurgeryStepAilmentTransitionComponent, SurgeryStepCompleteCheckEvent>(OnCheckTransitionComplete);
SubscribeLocalEvent<SurgeryStepAilmentTransitionComponent, SurgeryStepEvent>(OnAilmentTransition);
}

private void OnAilmentConditionValid(Entity<SurgeryHasAilmentConditionComponent> ent, ref SurgeryValidEvent args)
{
if (!TryComp<AilmentComponent>(args.Part, out var comp))
{
args.Cancelled = true;
return;
}

var hasAilment = comp.ActiveAilments.GetValueOrDefault(ent.Comp.Pack) == ent.Comp.Ailment;
args.Cancelled = !hasAilment;
}

private void OnCheckTransitionComplete(Entity<SurgeryStepAilmentTransitionComponent> ent, ref SurgeryStepCompleteCheckEvent args)
{
if (!TryComp<AilmentComponent>(args.Part, out var ailments))
return;

var eeba = new EntityEffectBaseArgs(args.Body, EntityManager);
var canTakeTransition = _ailments.ValidateTransition(new Entity<AilmentComponent>(args.Part, ailments), ent.Comp.Pack, ent.Comp.Transition, eeba);
args.Cancelled = canTakeTransition;
}

private void OnAilmentTransition(Entity<SurgeryStepAilmentTransitionComponent> ent, ref SurgeryStepEvent args)
{
if (!TryComp<AilmentComponent>(args.Part, out var ailments))
return;

var eeba = new EntityEffectBaseArgs(args.Body, EntityManager);
_ailments.TryTransition(new Entity<AilmentComponent>(args.Part, ailments), ent.Comp.Pack, ent.Comp.Transition, eeba);
}
}
Loading

0 comments on commit a087210

Please sign in to comment.