Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Lobotomy #1306

Merged
merged 8 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 3 additions & 2 deletions Content.Shared/Body/Organ/OrganComponent.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using Content.Shared.Body.Systems;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Content.Shared.Medical.Surgery;
using Content.Shared.Medical.Surgery.Tools;
using Robust.Shared.Prototypes;

namespace Content.Shared.Body.Organ;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(SharedBodySystem))]
[Access(typeof(SharedBodySystem), typeof(SharedSurgerySystem))]
public sealed partial class OrganComponent : Component, ISurgeryToolComponent
{
/// <summary>
Expand Down Expand Up @@ -50,7 +51,7 @@ public sealed partial class OrganComponent : Component, ISurgeryToolComponent
public ComponentRegistry? OnAdd;

/// <summary>
/// When removed, the organ will ensure these components on the entity, and add them on removal.
/// When removed, the organ will ensure these components on the entity, and delete them on insertion.
/// </summary>
[DataField]
public ComponentRegistry? OnRemove;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Content.Shared.Body.Part;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared.Medical.Surgery.Conditions;

// <summary>
// What components are necessary in the body for the surgery to be valid.
// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class SurgeryBodyComponentConditionComponent : Component
{
// <summary>
// The components to check for.
// </summary>
[DataField(required: true)]
public ComponentRegistry Components;

// <summary>
// If true, the lack of these components will instead make the surgery valid.
// </summary>
[DataField]
public bool Inverse = false;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Content.Shared.Body.Part;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared.Medical.Surgery.Conditions;

// <summary>
// What components are necessary in the part's organs' OnAdd fields for the surgery to be valid.
//
// Not all components need to be present (or missing for Inverse = true). At least one component matching (or missing) can make the surgery valid.
// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class SurgeryOrganOnAddConditionComponent : Component
{
// <summary>
// The components to check for on each organ, with the key being the organ's SlotId.
// </summary>
[DataField(required: true)]
public Dictionary<string, ComponentRegistry> Components;

// <summary>
// If true, the lack of these components will instead make the surgery valid.
// </summary>
[DataField]
public bool Inverse = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Content.Shared.Body.Part;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared.Medical.Surgery.Conditions;

// <summary>
// What components are necessary in the targeted body part for the surgery to be valid.
// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class SurgeryPartComponentConditionComponent : Component
{
// <summary>
// The components to check for.
// </summary>
[DataField(required: true)]
public ComponentRegistry Components;

// <summary>
// If true, the lack of these components will instead make the surgery valid.
// </summary>
[DataField]
public bool Inverse = false;
}
72 changes: 72 additions & 0 deletions Content.Shared/Medical/Surgery/SharedSurgerySystem.Steps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Content.Shared.Body.Part;
using Content.Shared.Body.Organ;
using Content.Shared.Body.Events;
using Content.Shared.BodyEffects;
using Content.Shared.Buckle.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Damage;
Expand Down Expand Up @@ -120,6 +121,45 @@ private void OnToolStep(Entity<SurgeryStepComponent> ent, ref SurgeryStepEvent a
}
}

if (ent.Comp.AddOrganOnAdd != null)
sleepyyapril marked this conversation as resolved.
Show resolved Hide resolved
{
var organSlotIdToOrgan = _body.GetPartOrgans(args.Part).ToDictionary(o => o.Item2.SlotId, o => o);

foreach (var (organSlotId, compsToAdd) in ent.Comp.AddOrganOnAdd)
{
if (!organSlotIdToOrgan.TryGetValue(organSlotId, out var organValue))
continue;
var (organId, organ) = organValue;

organ.OnAdd ??= new();

foreach (var (key, compToAdd) in compsToAdd)
organ.OnAdd[key] = compToAdd;

EnsureComp<OrganEffectComponent>(organId);
RaiseLocalEvent(organId, new OrganComponentsModifyEvent(args.Body, true));
}
}

if (ent.Comp.RemoveOrganOnAdd != null)
{
var organSlotIdToOrgan = _body.GetPartOrgans(args.Part).ToDictionary(o => o.Item2.SlotId, o => o);

foreach (var (organSlotId, compsToRemove) in ent.Comp.RemoveOrganOnAdd)
{
if (!organSlotIdToOrgan.TryGetValue(organSlotId, out var organValue) ||
organValue.Item2.OnAdd == null)
continue;
var (organId, organ) = organValue;

// Need to raise this event first before removing the component entries so
// OrganEffectSystem still knows which components on the body to remove
RaiseLocalEvent(organId, new OrganComponentsModifyEvent(args.Body, false));
foreach (var key in compsToRemove.Keys)
organ.OnAdd.Remove(key);
}
}

if (!HasComp<ForcedSleepingComponent>(args.Body))
RaiseLocalEvent(args.Body, new MoodEffectEvent("SurgeryPain"));

Expand Down Expand Up @@ -182,6 +222,38 @@ private void OnToolCheck(Entity<SurgeryStepComponent> ent, ref SurgeryStepComple
}
}
}

if (ent.Comp.AddOrganOnAdd != null)
{
var organSlotIdToOrgan = _body.GetPartOrgans(args.Part).ToDictionary(o => o.Item2.SlotId, o => o.Item2);
foreach (var (organSlotId, compsToAdd) in ent.Comp.AddOrganOnAdd)
{
if (!organSlotIdToOrgan.TryGetValue(organSlotId, out var organ))
continue;

if (organ.OnAdd == null || compsToAdd.Keys.Any(key => !organ.OnAdd.ContainsKey(key)))
{
args.Cancelled = true;
return;
}
}
}

if (ent.Comp.RemoveOrganOnAdd != null)
{
var organSlotIdToOrgan = _body.GetPartOrgans(args.Part).ToDictionary(o => o.Item2.SlotId, o => o.Item2);
foreach (var (organSlotId, compsToRemove) in ent.Comp.RemoveOrganOnAdd)
{
if (!organSlotIdToOrgan.TryGetValue(organSlotId, out var organ) || organ.OnAdd == null)
continue;

if (compsToRemove.Keys.Any(key => organ.OnAdd.ContainsKey(key)))
{
args.Cancelled = true;
return;
}
}
}
}

private void OnToolCanPerform(Entity<SurgeryStepComponent> ent, ref SurgeryCanPerformStepEvent args)
Expand Down
61 changes: 58 additions & 3 deletions Content.Shared/Medical/Surgery/SharedSurgerySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@ public override void Initialize()
SubscribeLocalEvent<SurgeryTargetComponent, SurgeryDoAfterEvent>(OnTargetDoAfter);
SubscribeLocalEvent<SurgeryCloseIncisionConditionComponent, SurgeryValidEvent>(OnCloseIncisionValid);
//SubscribeLocalEvent<SurgeryLarvaConditionComponent, SurgeryValidEvent>(OnLarvaValid);
SubscribeLocalEvent<SurgeryComponentConditionComponent, SurgeryValidEvent>(OnComponentConditionValid);
SubscribeLocalEvent<SurgeryBodyComponentConditionComponent, SurgeryValidEvent>(OnBodyComponentConditionValid);
SubscribeLocalEvent<SurgeryPartComponentConditionComponent, SurgeryValidEvent>(OnPartComponentConditionValid);
SubscribeLocalEvent<SurgeryPartConditionComponent, SurgeryValidEvent>(OnPartConditionValid);
SubscribeLocalEvent<SurgeryOrganConditionComponent, SurgeryValidEvent>(OnOrganConditionValid);
SubscribeLocalEvent<SurgeryOrganOnAddConditionComponent, SurgeryValidEvent>(OnOrganOnAddConditionValid);
SubscribeLocalEvent<SurgeryWoundedConditionComponent, SurgeryValidEvent>(OnWoundedValid);
SubscribeLocalEvent<SurgeryPartRemovedConditionComponent, SurgeryValidEvent>(OnPartRemovedConditionValid);
SubscribeLocalEvent<SurgeryPartPresentConditionComponent, SurgeryValidEvent>(OnPartPresentConditionValid);
Expand Down Expand Up @@ -129,10 +131,24 @@ private void OnWoundedValid(Entity<SurgeryWoundedConditionComponent> ent, ref Su
args.Cancelled = true;
}*/

private void OnComponentConditionValid(Entity<SurgeryComponentConditionComponent> ent, ref SurgeryValidEvent args)
private void OnBodyComponentConditionValid(Entity<SurgeryBodyComponentConditionComponent> ent, ref SurgeryValidEvent args)
{
var present = true;
foreach (var reg in ent.Comp.Component.Values)
foreach (var reg in ent.Comp.Components.Values)
{
var compType = reg.Component.GetType();
if (!HasComp(args.Body, compType))
present = false;
}

if (ent.Comp.Inverse ? present : !present)
args.Cancelled = true;
}

private void OnPartComponentConditionValid(Entity<SurgeryPartComponentConditionComponent> ent, ref SurgeryValidEvent args)
{
var present = true;
foreach (var reg in ent.Comp.Components.Values)
{
var compType = reg.Component.GetType();
if (!HasComp(args.Part, compType))
Expand Down Expand Up @@ -185,6 +201,45 @@ private void OnOrganConditionValid(Entity<SurgeryOrganConditionComponent> ent, r
}
}

// This is literally a duplicate of the checks in OnToolCheck for SurgeryStepComponent.AddOrganOnAdd
private void OnOrganOnAddConditionValid(Entity<SurgeryOrganOnAddConditionComponent> ent, ref SurgeryValidEvent args)
{
if (!TryComp<BodyPartComponent>(args.Part, out var part)
|| part.Body != args.Body)
{
args.Cancelled = true;
return;
}

var organSlotIdToOrgan = _body.GetPartOrgans(args.Part, part).ToDictionary(o => o.Item2.SlotId, o => o.Item2);

var allOnAddFound = true;
var zeroOnAddFound = true;

foreach (var (organSlotId, components) in ent.Comp.Components)
{
if (!organSlotIdToOrgan.TryGetValue(organSlotId, out var organ))
continue;

if (organ.OnAdd == null)
{
allOnAddFound = false;
continue;
}

foreach (var key in components.Keys)
{
if (!organ.OnAdd.ContainsKey(key))
allOnAddFound = false;
else
zeroOnAddFound = false;
}
}

if (ent.Comp.Inverse ? allOnAddFound : zeroOnAddFound)
args.Cancelled = true;
}

private void OnPartRemovedConditionValid(Entity<SurgeryPartRemovedConditionComponent> ent, ref SurgeryValidEvent args)
{
if (!_body.CanAttachToSlot(args.Part, ent.Comp.Connection))
Expand Down
18 changes: 18 additions & 0 deletions Content.Shared/Medical/Surgery/Steps/SurgeryStepComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ public sealed partial class SurgeryStepComponent : Component
[DataField]
public ComponentRegistry? BodyRemove;

/// <summary>
/// These components will be added to the body part's organs' OnAdd field.
/// Each key is the SlotId of the organ to look for.
///
/// Used to make organs add components to whatever body it's residing in.
/// </summary>
[DataField]
public Dictionary<string, ComponentRegistry>? AddOrganOnAdd;

/// <summary>
/// These components will be removed from the body part's organs' OnAdd field.
/// Each key is the SlotId of the organ to look for.
///
/// Used to stop organs from adding components to whatever body it's residing in.
/// </summary>
[DataField]
public Dictionary<string, ComponentRegistry>? RemoveOrganOnAdd;

[DataField]
public float Duration = 2f;
}
3 changes: 3 additions & 0 deletions Resources/Locale/en-US/surgery/surgery-popup.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ surgery-popup-step-SurgeryStepInsertHeart = {$user} is inserting a heart into {$
surgery-popup-step-SurgeryStepInsertStomach = {$user} is inserting a stomach into {$target}'s {$part}!

surgery-popup-step-SurgeryStepSealOrganWound = {$user} is sealing the wounds on {$target}'s {$part}.

surgery-popup-step-SurgeryStepLobotomize = {$user} is lobotomizing {$target}!
surgery-popup-step-SurgeryStepMendBrainTissue = {$user} is mending the brain tissue on {$target}'s {$part}.
32 changes: 25 additions & 7 deletions Resources/Prototypes/Entities/Surgery/surgeries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,21 @@
steps:
- SurgeryStepLobotomize
- SurgeryStepCloseIncision
- type: SurgeryComponentCondition
component:
- type: OhioAccent
inverse: true
- type: SurgeryPartCondition
part: Head
- type: SurgeryOrganCondition
organ:
- type: Brain
- type: SurgeryOrganOnAddCondition
components:
brain:
- type: OhioAccent
- type: RatvarianLanguage
- type: Clumsy
clumsyDamage: # Placeholder values to be able to initialize the component
types:
Blunt: 0
inverse: true

- type: entity
parent: SurgeryBase
Expand All @@ -72,11 +81,20 @@
steps:
- SurgeryStepMendBrainTissue
- SurgeryStepCloseIncision
- type: SurgeryComponentCondition
component:
- type: OhioAccent
- type: SurgeryPartCondition
part: Head
- type: SurgeryOrganCondition
organ:
- type: Brain
- type: SurgeryOrganOnAddCondition
components:
brain:
- type: OhioAccent
- type: RatvarianLanguage
- type: Clumsy
clumsyDamage:
types:
Blunt: 0

- type: entity
parent: SurgeryBase
Expand Down
Loading
Loading