Skip to content

Commit

Permalink
Merge pull request Simple-Station#11 from Tropica1Owl/Pogmed
Browse files Browse the repository at this point in the history
Surgery situation is crazy
  • Loading branch information
Eagle-0 authored Aug 25, 2024
2 parents 7172fdc + cce64ca commit 7a326d3
Show file tree
Hide file tree
Showing 28 changed files with 512 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Content.Server.Palmtree.CookieClicker
{
[RegisterComponent]
public partial class ClickCounterComponent : Component
{
[DataField("count")]
[ViewVariables(VVAccess.ReadWrite)]
public int count = 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Content.Server.Palmtree.CookieClicker
{
[RegisterComponent]
public partial class IncrementorComponent : Component {}

}
22 changes: 22 additions & 0 deletions Content.Server/Palmtree/CookieClicker/CookieClickerSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Content.Server.Palmtree.CookieClicker;
using Content.Shared.Interaction;

namespace Content.Server.Palmtree.CookieClicker.CounterSystem
{
public class CookieClickerSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<IncrementorComponent, AfterInteractEvent>(OnAfterInteract);
}
private void OnAfterInteract(EntityUid uid, IncrementorComponent component, AfterInteractEvent args)
{
if (!args.CanReach || args.Target == null || args.User == args.Target || !TryComp(args.Target, out ClickCounterComponent? counter))
{
return;
}
counter.count++;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Content.Server.Palmtree.Surgery
{
[RegisterComponent]
public partial class MindExchangerComponent : Component
{
[DataField("Mind")]
[ViewVariables(VVAccess.ReadWrite)]
public EntityUid mind = default!;

[DataField("ContainsMind")]
[ViewVariables(VVAccess.ReadWrite)]
public bool occupied = false;
}
}
12 changes: 12 additions & 0 deletions Content.Server/Palmtree/Surgery/Components/TendWoundComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Content.Shared.Damage;

namespace Content.Server.Palmtree.Surgery
{
[RegisterComponent]
public partial class PTendWoundsComponent : Component
{
[DataField("healThisMuch", required: true)] // Sorry I can't stop making silly names
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier healThisMuch = default!;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;

namespace Content.Server.Palmtree.Surgery
{
[RegisterComponent]
public partial class PPatientComponent : Component //"PPatient" because wizden might add surgery down the line, so I'm doing this to avoid conflicts.
{// I'll make this better later with a proper list of steps, I just need a first version for now
[DataField("incised")]
[ViewVariables(VVAccess.ReadWrite)]
public bool incised = false;

[DataField("retracted")]
[ViewVariables(VVAccess.ReadWrite)]
public bool retracted = false;

[DataField("clamped")]
[ViewVariables(VVAccess.ReadWrite)]
public bool clamped = false;

public List<string> procedures = new List<string>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;

namespace Content.Server.Palmtree.Surgery
{
[RegisterComponent]
public partial class PSurgeryToolComponent : Component
{
[DataField("kind")]
[ViewVariables(VVAccess.ReadWrite)]
public string kind = "scalpel";

[DataField("infectionDamage")]
[ViewVariables(VVAccess.ReadWrite)]
public float infectionDamage = 1.0f;

[DataField("useDelay")]
[ViewVariables(VVAccess.ReadWrite)]
public float useDelay = 3.0f;

[DataField("bleedAmountOnUse")]
[ViewVariables(VVAccess.ReadWrite)]
public float bleedAmountOnUse = 0.0f; // Cutting tools usually are the ones that cause bleed

[DataField("damageOnUse", required: true)] // Tools damage the patient on use except in special cases.
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier damageOnUse = default!;

[DataField("audioStart")]
[ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier? audioStart = null;

[DataField("audioEnd")]
[ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier? audioEnd = null;
}
}
253 changes: 253 additions & 0 deletions Content.Server/Palmtree/Surgery/SurgerySystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
using System.Collections.Generic;
using System.Linq;
using Content.Server.Palmtree.Surgery;
using Content.Server.Body.Systems;
using Content.Server.Popups;
using Content.Server.Mind;
using Content.Shared.Atmos.Rotting;
using Content.Shared.Palmtree.Surgery;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
//using Content.Shared.Players;
using Content.Shared.Standing;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Bed.Sleep;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Timing;

// It's all very crude at the moment, but it actually works now.

/*
* PalmtreeMed surgery by TropicalOwl
* The current code is grotesque, stuff is hardcoded and it looks nothing like how I want it to actually look like in the final version.
* Additionally please do note this was programmed by someone who had very little contact with C# prior to this, if anyone want to make improvements or rework this, don't need to ask for permission, I'm not gonna pretend I know what I'm doing.
*
* This is also a port from a non-ee code, so stuff might break as well.
* You've been warned
*
* On the plus side, it's VERY easy to remove this from the game if someone comes and makes a better system.
*/



namespace Content.Server.Palmtree.Surgery.SurgerySystem
{
public class PSurgerySystem : SharedSurgerySystem
{
// These procedures can be prototypes later, for now I'll hardcode them because I have no idea how to do it otherwise.
// Remind me to try and make them prototypes later, please!
Dictionary<string, string[]> procedures = new Dictionary<string, string[]>
{
{"TendWounds", new string[]{"scalpel"}},
{"FilterBlood", new string[]{"scalpel", "retractor", "saw"}},
{"SawBones", new string[]{"scalpel", "retractor"}}, // This comes before letting people saw bones
{"BrainTransfer", new string[]{"scalpel", "retractor", "saw"}},
{"ReduceRotting", new string[]{"scalpel", "retractor"}},
{"InsertAugment", new string[]{"scapel", "retractor", "saw"}}, // This procedure is used for augments and implants
{"RemoveAugment", new string[]{"scalpel", "retractor", "saw", "drill"}} // This procedure removes a person's augments, breaking them
};

[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedMindSystem _sharedmind = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly StandingStateSystem _standing = default!;
//[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly SharedRottingSystem _rot = default!;
[Dependency] private readonly BloodstreamSystem _blood = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PSurgeryToolComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<PSurgeryToolComponent, SurgeryDoAfterEvent>(OnProcedureFinished);
}
private void OnProcedureFinished(EntityUid uid, PSurgeryToolComponent tool, SurgeryDoAfterEvent args)
{
if (args.Cancelled || args.Target == null || !TryComp(args.Target, out PPatientComponent? patient)) return;
if (patient.procedures.Count == 0)
{
if (tool.kind == "scalpel")
{
_popupSystem.PopupEntity("You successfully perform an incision!", args.User, PopupType.Small);
patient.procedures.Add("scalpel");
_damageableSystem.TryChangeDamage(args.Target, tool.damageOnUse, true, origin: uid);
_blood.TryModifyBleedAmount((EntityUid) args.Target, tool.bleedAmountOnUse);
_audio.PlayPvs(tool.audioEnd, args.User);
}
else
{
_popupSystem.PopupEntity("Perform an incision first!", args.User, PopupType.Small);
}
}
else
{ // Procedure checks go here
bool repeatableProcedure = false; // If it is repeatable it won't add to the "crafting" of the surgery
bool damageOnFinish = true; // Check if it will damage the target by the damage specified in the prototypes
bool failedProcedure = false; // Check if it has failed.
switch(tool.kind)
{
case "scalpel":
_popupSystem.PopupEntity("You perform an incision!", args.User, PopupType.Small);
break;
case "hemostat":
repeatableProcedure = true; // You can pinch people over and over
_popupSystem.PopupEntity("You clamp the patient's bleeders!", args.User, PopupType.Small);
break;
case "retractor":
_popupSystem.PopupEntity("You retract the patient's skin!", args.User, PopupType.Small);
break;
case "saw":
if (patient.procedures.SequenceEqual(procedures["SawBones"]))
{
_popupSystem.PopupEntity("You saw the patient's bones!", args.User, PopupType.Small);
}
else
{
_popupSystem.PopupEntity("You can't saw your patient's bones right now!", args.User, PopupType.Small);
failedProcedure = true;
}
break;
case "cautery":
patient.procedures.Clear();
repeatableProcedure = true; // You can just burn people over and over with a cautery, yeah.
break;
case "brainlink":
if (patient.procedures.SequenceEqual(procedures["BrainTransfer"]))
{
bool targetHasMind = _sharedmind.TryGetMind((EntityUid) args.Target, out var targetMindId, out var targetMind);
if (targetHasMind)
{
_mind.TransferTo(targetMindId, uid, mind: targetMind);
}
}
else
{
failedProcedure = true;
_popupSystem.PopupEntity("You can't take the patient's mind right now.", args.User, PopupType.Small);
}
break;
case "phantomlink": // Upgraded version of the ghost shell, can only be admin spawned
if (patient.procedures.SequenceEqual(procedures["BrainTransfer"]))
{
bool targetHasMind = _sharedmind.TryGetMind((EntityUid) args.Target, out var targetMindId, out var targetMind);
bool deviceHasMind = _sharedmind.TryGetMind(uid, out var deviceMindId, out var deviceMind);
if (targetHasMind && deviceHasMind)
{
failedProcedure = true;
_popupSystem.PopupEntity("You can't take the patient's mind right now, your link is occupied.", args.User, PopupType.Small);
}
else
{
if (targetHasMind)
{
_mind.TransferTo(targetMindId, uid, mind: targetMind);
}
if (deviceHasMind)
{
_mind.TransferTo(deviceMindId, args.Target, mind: deviceMind);
}
}
}
else
{
failedProcedure = true;
_popupSystem.PopupEntity("You can't take the patient's mind right now.", args.User, PopupType.Small);
}
break;
case "bloodfilter":
if (patient.procedures.Contains("retractor"))
{
_popupSystem.PopupEntity("You filter the contaminants from the subject's blood.", args.User, PopupType.Small);
repeatableProcedure = true;
}
else
{
_popupSystem.PopupEntity("You can't filter the patient's blood right now.", args.User, PopupType.Small);
failedProcedure = true;
}
break;
case "antirot":
if (patient.procedures.Contains("retractor"))
{
_popupSystem.PopupEntity("You spray the anti-rot on the patient.", args.User, PopupType.Small);
_rot.ReduceAccumulator((EntityUid) args.Target, TimeSpan.FromSeconds(120));
repeatableProcedure = true;
}
else
{
_popupSystem.PopupEntity("You can't use the spray right now.", args.User, PopupType.Small);
failedProcedure = true;
}
break;
default:
_popupSystem.PopupEntity("If you see this, contact TropicalOwl and tell which tool you used when seeing this, this is an error message.", args.User, PopupType.Small);
break;
}
if (failedProcedure)
{
return;
}
if (!repeatableProcedure)
{
patient.procedures.Add(tool.kind);
}
if (damageOnFinish)
{
_damageableSystem.TryChangeDamage(args.Target, tool.damageOnUse, true, origin: uid);
_blood.TryModifyBleedAmount((EntityUid) args.Target, tool.bleedAmountOnUse);
}
_audio.PlayPvs(tool.audioEnd, args.User);
}
}
private void OnAfterInteract(EntityUid uid, PSurgeryToolComponent tool, AfterInteractEvent args) // Turn this into FTL strings later
{
bool patientHasState = TryComp(args.Target, out MobStateComponent? patientState);
if (!args.CanReach || args.Target == null) // We already check if target is null, it's okay to perform direct conversion to non-nullable
{
return;
}
if (!TryComp(args.Target, out PPatientComponent? patient) && patientHasState)
{
_popupSystem.PopupEntity("You cannot perform surgery on this!", args.User, PopupType.Small);
return;
}
if (!_standing.IsDown((EntityUid) args.Target))
{
_popupSystem.PopupEntity("The patient must be laying down and asleep!", args.User, PopupType.Small);
return;
}
if (!TryComp(args.Target, out SleepingComponent? sleep) && !_mobState.IsIncapacitated((EntityUid) args.Target, patientState))
{
_popupSystem.PopupEntity("The patient must be asleep!", args.User, PopupType.Small);
return;
}
if (args.User == args.Target)
{
_popupSystem.PopupEntity("You cannot operate yourself!", args.User, PopupType.Small);
return;
}
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, tool.useDelay, new SurgeryDoAfterEvent(), uid, target: args.Target)
{
NeedHand = true,
//BreakOnMove = true,
//BreakOnWeightlessMove = true,
};
_audio.PlayPvs(tool.audioStart, args.User);
_doAfter.TryStartDoAfter(doAfterEventArgs);
}
}
}
11 changes: 11 additions & 0 deletions Content.Shared/Palmtree/Surgery/SharedSurgery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Content.Shared.DoAfter;
using Robust.Shared.Serialization;

namespace Content.Shared.Palmtree.Surgery
{
public abstract partial class SharedSurgerySystem : EntitySystem
{
[Serializable, NetSerializable]
protected sealed partial class SurgeryDoAfterEvent : SimpleDoAfterEvent {}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Resources/Audio/Palmtree/Items/Medical/organ1.ogg
Binary file not shown.
Binary file added Resources/Audio/Palmtree/Items/Medical/organ2.ogg
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Resources/Audio/Palmtree/Items/Medical/saw.ogg
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 7a326d3

Please sign in to comment.