From f74eb1488f8c0e30788899c3b9e969edc2930c28 Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Wed, 27 May 2026 14:39:14 +0200 Subject: [PATCH 01/10] basic layout --- .../_Floof/Vore/DevouredComponent.cs | 202 ++++++++++++++++++ Content.Server/_Floof/Vore/VoreSystem.cs | 93 +------- .../_Floof/Vore/DevouredComponent.cs | 8 + Content.Shared/_Floof/Vore/VoreComponent.cs | 8 - 4 files changed, 221 insertions(+), 90 deletions(-) create mode 100644 Content.Server/_Floof/Vore/DevouredComponent.cs create mode 100644 Content.Shared/_Floof/Vore/DevouredComponent.cs diff --git a/Content.Server/_Floof/Vore/DevouredComponent.cs b/Content.Server/_Floof/Vore/DevouredComponent.cs new file mode 100644 index 00000000000..7b8a360bdbf --- /dev/null +++ b/Content.Server/_Floof/Vore/DevouredComponent.cs @@ -0,0 +1,202 @@ +using Content.Server.Atmos.Components; +using Content.Shared._Shitmed.Body.Components; +using Content.Shared._DV.CosmicCult.Components; +using Content.Shared._Floof.Vore; +using Content.Shared.Body.Events; +using Content.Shared.Damage.Systems; +using Content.Shared.Flash.Components; +using Content.Shared.Medical.SuitSensor; +using Content.Shared.Medical.SuitSensors; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; +using Content.Shared.Mobs.Systems; +using Robust.Shared.Containers; +using Content.Shared.Flash.Components; +using Content.Shared.Damage.Systems; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Content.Shared.Movement.Events; +using Content.Shared.Movement.Components; +using Content.Shared.Movement; +namespace Content.Server._Floof.Vore; + +public sealed class VoreImmunitySystem : EntitySystem +{ + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly SharedSuitSensorSystem _suitSensorSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + private readonly HashSet _pendingImmunityUpdates = new(); + + public override void Initialize() + { + SubscribeLocalEvent(OnPreyRemovedFromContainer); + + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent>(OnGetVerbs); + SubscribeLocalEvent(OnPreyMobStateChanged); + SubscribeLocalEvent(OnRelayMovement); + } + + public override void Update(float frameTime){ + base.Update(frameTime); + + foreach (var uid in _pendingImmunityUpdates) + { + RemoveStomachImmunities(uid); + } + + _pendingImmunityUpdates.Clear(); + } + + private void OnStartup(EntityUid uid, DevouredComponent comp, ComponentStartup args){ + ApplyStomachImmunities(uid); + } + + /// + /// responsible for removing components and immunities + /// + private void OnPreyRemovedFromContainer(EntityUid uid, VoreComponent comp, EntRemovedFromContainerMessage args){ + if (TryComp(args.Entity, out _)) + _pendingImmunityUpdates.Add(args.Entity); + } + + /// + /// alternative way of escaping + /// + private void OnGetVerbs(EntityUid uid, DevouredComponent comp, GetVerbsEvent args){ + if (!_containerSystem.TryGetContainingContainer(uid, out var container)) + return; + var prey = uid; + var pred = container.Owner; + + if (args.User != prey && args.User != pred) + return; + + args.Verbs.Add(new Verb + { + Text = "Struggle Free", + Act = () => + { + _popupSystem.PopupEntity("You struggle free!", prey, prey); + _popupSystem.PopupEntity("Your prey escaped!", pred, pred); + _containerSystem.Remove(uid, container); + } + }); + + } + + /// + /// in case the prey died/crit they need to be ejected from ALL vorecontainers + /// this way a para wont accidentally stumble on a scene and the corpse wont rot + /// + private void OnPreyMobStateChanged(EntityUid uid, DevouredComponent comp, ref MobStateChangedEvent args){ + if (args.NewMobState != MobState.Dead && args.NewMobState != MobState.Critical) + return; + + if (!TryComp(uid, out var vore)) + return; + + while (_containerSystem.TryGetContainingContainer(uid, out var container) && container.ID == vore.ContainerId){ + _containerSystem.Remove(uid, container); + } + } + + /// + /// removes the ability to escape by moving when inside a vore container in order to prevent accidentally escapes + /// + private void OnRelayMovement(EntityUid uid, DevouredComponent comp, ref MoveInputEvent args){ + if (!IsInVoreContainer(uid)) + return; + args.Entity.Comp.HeldMoveButtons = default; + } + + /// + /// checks if an entity is inside a vore container + /// + /// + /// true if the entity is inside a vore container + /// + private bool IsInVoreContainer(EntityUid uid){ + if (!TryComp(uid, out var comp)) + return false; + return _containerSystem.TryGetContainingContainer(uid, out var container) && + container.ID == comp.ContainerId; + } + + /// + /// the prey needs to have certain components such as pressure immunity + /// for consent purposes -> having others avoid stumbling on scenarios + /// + private void ApplyStomachImmunities(EntityUid prey){ + /*double check making sure they are inside the container + should prevent possible exploitation of the system*/ + if (!IsInVoreContainer(prey)) + return; + if (!TryComp(prey, out var tracker)) + return; + + if (!HasComp(prey)){ + EnsureComp(prey); + tracker.AddedPressure = true; + } + + if (!HasComp(prey)){ + EnsureComp(prey); + tracker.AddedBreathing = true; + } + + if (!HasComp(prey)){ + EnsureComp(prey); + tracker.AddedTemperature = true; + } + + if (!HasComp(prey)){ + EnsureComp(prey); + tracker.AddedFlash = true; + } + + if(!HasComp(prey)){ + EnsureComp(prey); + tracker.AddedRadiation = true; + } + + _suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorOff); + } + + /// + /// the removal of the devouredcomponent and immunities after leaving a container + /// to avoid intentional and accidental exploitation + /// + private void RemoveStomachImmunities(EntityUid prey){ + // if still in a container skip alltogether for example release from multi vore + if (IsInVoreContainer(prey)) + return; + if (!TryComp(prey, out var tracker)) + return; + + if (tracker.AddedPressure){ + RemComp(prey); + tracker.AddedPressure = false; + } + if (tracker.AddedBreathing){ + RemComp(prey); + tracker.AddedBreathing = false; + } + if (tracker.AddedTemperature){ + RemComp(prey); + tracker.AddedTemperature = false; + } + if (tracker.AddedFlash){ + RemComp(prey); + tracker.AddedFlash = false; + } + if (tracker.AddedRadiation){ + RemComp(prey); + tracker.AddedRadiation = false; + } + _suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorCords); + RemComp(prey); + } +} \ No newline at end of file diff --git a/Content.Server/_Floof/Vore/VoreSystem.cs b/Content.Server/_Floof/Vore/VoreSystem.cs index 38f740473ef..f9ad45ee944 100644 --- a/Content.Server/_Floof/Vore/VoreSystem.cs +++ b/Content.Server/_Floof/Vore/VoreSystem.cs @@ -8,10 +8,6 @@ using Content.Shared.Popups; using Content.Shared.FloofStation; using Content.Shared._Floof.Vore; -using Content.Shared._Shitmed.Body.Components; -using Content.Shared._DV.CosmicCult.Components; -using Content.Server.Radiation.Components; -using Content.Server.Atmos.Components; using Content.Shared.Body.Events; using Content.Shared._Common.Consent; using Content.Shared.Verbs; @@ -35,7 +31,6 @@ public sealed class VoreSystem : EntitySystem public static readonly ProtoId isPrey = "PreyVore"; private readonly HashSet _pendingConsentUpdates = new(); - private readonly HashSet _pendingImmunityUpdates = new(); public override void Initialize() { @@ -61,12 +56,6 @@ public override void Update(float frameTime){ ApplyVoreConsent(uid); } _pendingConsentUpdates.Clear(); - - // processing of immunity updates - foreach (var uid in _pendingImmunityUpdates){ - RemoveStomachImmunities(uid); - } - _pendingImmunityUpdates.Clear(); } /// @@ -97,9 +86,7 @@ private void ApplyVoreConsent(EntityUid uid){ /* in case prey is inside a container immediately release them when they turn off prey consent works as an emergency leave for the prey*/ - if (!hasPrey && - TryComp(uid, out var comp) && - IsInVoreContainer(uid, comp) && + if (!hasPrey && IsInVoreContainer(uid) && _containerSystem.TryGetContainingContainer(uid, out var container)){ _containerSystem.Remove(uid, container); } @@ -152,7 +139,7 @@ private void OnGetVerbs(EntityUid uid, VoreComponent comp, GetVerbsEvent a /* if the user is a pred inside a pred allows them to have interactions with prey inside only if they are in the same container however (not just same type but literally)*/ - if (!IsValidVoreInteraction(user, target, comp)) + if (!IsValidVoreInteraction(user, target)) return; // devour (pred → prey) @@ -317,76 +304,18 @@ private void OnDestroyedRemoveContent(EntityUid uid, VoreComponent comp, Destruc private void OnPolymorphedTransferContent(EntityUid uid, VoreComponent comp, PolymorphedEvent args){ TryReleasePrey(uid, comp); } - - /// - /// the prey needs to have certain components such as pressure immunity - /// for consent purposes -> having others avoid stumbling on scenarios - /// - private void ApplyStomachImmunities(EntityUid prey, VoreComponent comp){ - /*double check making sure they are inside the container - should prevent possible exploitation of the system*/ - if (!IsInVoreContainer(prey, comp)) - return; - - var tracker = EnsureComp(prey); - if (!HasComp(prey)) - { - EnsureComp(prey); - tracker.AddedPressure = true; - } - - if (!HasComp(prey)) - { - EnsureComp(prey); - tracker.AddedBreathing = true; - } - - if (!HasComp(prey)) - { - EnsureComp(prey); - tracker.AddedTemperature = true; - } - /* doesnt fully protect from radiation (given its potassium iodine protection meaning 90 percent reduction of radiation damage) - but will give prey more time to react and escape before radiation starts doing damage */ - if (!HasComp(prey)) - { - EnsureComp(prey); - tracker.AddedRadiation = true; - } - } - - /// - /// the removal of the components after leaving a container - /// to avoid intentional and accidental exploitation - /// - private void RemoveStomachImmunities(EntityUid prey){ - if (!TryComp(prey, out var tracker)) - return; - // if still in a container skip alltogether for example release from multi vore - if (TryComp(prey, out var comp) && IsInVoreContainer(prey, comp)) - return; - - if (tracker.AddedPressure) - RemComp(prey); - if (tracker.AddedBreathing) - RemComp(prey); - if (tracker.AddedTemperature) - RemComp(prey); - if (tracker.AddedRadiation) - RemComp(prey); - - RemComp(prey); - } - + /// /// checks if an entity is inside a vore container /// /// - /// true if the entity is inside any vore container, otherwise false + /// true if the entity is inside a vore container /// - private bool IsInVoreContainer(EntityUid uid, VoreComponent comp){ + private bool IsInVoreContainer(EntityUid uid){ + if (!TryComp(uid, out var comp)) + return false; return _containerSystem.TryGetContainingContainer(uid, out var container) && - container.ID == comp.ContainerId; + container.ID == comp.ContainerId; } /// @@ -395,9 +324,9 @@ private bool IsInVoreContainer(EntityUid uid, VoreComponent comp){ /// /// false if only one is in a vore container or if both are inside another container /// - private bool IsValidVoreInteraction(EntityUid user, EntityUid target, VoreComponent comp){ - var userInVore = IsInVoreContainer(user, comp); - var targetInVore = IsInVoreContainer(target, comp); + private bool IsValidVoreInteraction(EntityUid user, EntityUid target){ + var userInVore = IsInVoreContainer(user); + var targetInVore = IsInVoreContainer(target); // one in vore, one not → invalid if (userInVore != targetInVore) diff --git a/Content.Shared/_Floof/Vore/DevouredComponent.cs b/Content.Shared/_Floof/Vore/DevouredComponent.cs new file mode 100644 index 00000000000..15d7a023d43 --- /dev/null +++ b/Content.Shared/_Floof/Vore/DevouredComponent.cs @@ -0,0 +1,8 @@ +[RegisterComponent] +public sealed partial class DevouredComponent : Component +{ + public bool AddedPressure; + public bool AddedBreathing; + public bool AddedTemperature; + public bool AddedRadiation; +} \ No newline at end of file diff --git a/Content.Shared/_Floof/Vore/VoreComponent.cs b/Content.Shared/_Floof/Vore/VoreComponent.cs index c9c01615bfc..cbb4e8caddd 100644 --- a/Content.Shared/_Floof/Vore/VoreComponent.cs +++ b/Content.Shared/_Floof/Vore/VoreComponent.cs @@ -29,12 +29,4 @@ public OnVoreDoAfter(int maxPrey) { MaxPrey = maxPrey; } -} -[RegisterComponent] -public sealed partial class VoreImmunityTrackerComponent : Component -{ - public bool AddedPressure; - public bool AddedBreathing; - public bool AddedTemperature; - public bool AddedRadiation; } \ No newline at end of file From c267bfa13139bc7aa4c5527108ea765cd4dc1e2f Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Wed, 27 May 2026 15:14:46 +0200 Subject: [PATCH 02/10] layout change for containment --- ...DevouredComponent.cs => DevouredSystem.cs} | 16 +-- Content.Server/_Floof/Vore/VoreSystem.cs | 121 +++++++++--------- Content.Shared/_Floof/Vore/VoreComponent.cs | 4 - 3 files changed, 61 insertions(+), 80 deletions(-) rename Content.Server/_Floof/Vore/{DevouredComponent.cs => DevouredSystem.cs} (93%) diff --git a/Content.Server/_Floof/Vore/DevouredComponent.cs b/Content.Server/_Floof/Vore/DevouredSystem.cs similarity index 93% rename from Content.Server/_Floof/Vore/DevouredComponent.cs rename to Content.Server/_Floof/Vore/DevouredSystem.cs index 7b8a360bdbf..5960271d01b 100644 --- a/Content.Server/_Floof/Vore/DevouredComponent.cs +++ b/Content.Server/_Floof/Vore/DevouredSystem.cs @@ -18,6 +18,7 @@ using Content.Shared.Movement.Events; using Content.Shared.Movement.Components; using Content.Shared.Movement; +using Content.Server.Radiation.Components; namespace Content.Server._Floof.Vore; public sealed class VoreImmunitySystem : EntitySystem @@ -152,13 +153,8 @@ should prevent possible exploitation of the system*/ tracker.AddedTemperature = true; } - if (!HasComp(prey)){ - EnsureComp(prey); - tracker.AddedFlash = true; - } - - if(!HasComp(prey)){ - EnsureComp(prey); + if(!HasComp(prey)){ + EnsureComp(prey); tracker.AddedRadiation = true; } @@ -188,12 +184,8 @@ private void RemoveStomachImmunities(EntityUid prey){ RemComp(prey); tracker.AddedTemperature = false; } - if (tracker.AddedFlash){ - RemComp(prey); - tracker.AddedFlash = false; - } if (tracker.AddedRadiation){ - RemComp(prey); + RemComp(prey); tracker.AddedRadiation = false; } _suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorCords); diff --git a/Content.Server/_Floof/Vore/VoreSystem.cs b/Content.Server/_Floof/Vore/VoreSystem.cs index f9ad45ee944..eb2d6fa51c9 100644 --- a/Content.Server/_Floof/Vore/VoreSystem.cs +++ b/Content.Server/_Floof/Vore/VoreSystem.cs @@ -15,7 +15,8 @@ using Content.Shared.Destructible; using Robust.Shared.Configuration; using Content.Shared._DV.Carrying; -using Robust.Shared.Timing; +using Robust.Server.Player; +using Content.Shared.Mobs.Systems; namespace Content.Server._Floof.Vore; public sealed class VoreSystem : EntitySystem @@ -26,6 +27,8 @@ public sealed class VoreSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly CarryingSystem _carryingSystem = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; public static readonly ProtoId isPred = "PredVore"; public static readonly ProtoId isPrey = "PreyVore"; @@ -39,7 +42,6 @@ public override void Initialize() SubscribeLocalEvent>(OnGetVerbs); SubscribeLocalEvent(OnVoreDoAfter); - SubscribeLocalEvent(OnVoreRemovedFromContainer); SubscribeLocalEvent(OnGibbedRemoveContent); SubscribeLocalEvent(OnDestroyedRemoveContent); SubscribeLocalEvent(OnPolymorphedTransferContent); @@ -53,6 +55,8 @@ public override void Update(float frameTime){ // processing of consent updates foreach (var uid in _pendingConsentUpdates){ + if (!HasComp(uid)) + continue; ApplyVoreConsent(uid); } _pendingConsentUpdates.Clear(); @@ -93,9 +97,7 @@ private void ApplyVoreConsent(EntityUid uid){ //give the mob the needed component to be able to see the verbs if (hasPred || hasPrey){ - // to avoid item ghostroles like trays getting vore components - if (HasComp(uid)) - EnsureComp(uid); + EnsureComp(uid); } else{ RemComp(uid); @@ -109,59 +111,56 @@ private void ApplyVoreConsent(EntityUid uid){ /// only show up when the consent has been selected on both sides /// private void OnGetVerbs(EntityUid uid, VoreComponent comp, GetVerbsEvent args){ - var user = args.User; - var target = args.Target; - // using command to turn on/off verb components if (!_cfg.GetCVar(VoreCVars.VoreEnabled)) return; + // only when reachable & interactable + if (!args.CanInteract || !args.CanAccess) + return; + + BuildVoreContainerVerbs(uid, comp, args); + //TODO LATER ADD VERB CONSTRUCTORS FOR EXAMPLE DIGEST TO AVOID DUPLICATE SUBSCRIPTION TO GETVERBS + } + + /// + /// handles the verbs that control the container such as inserting/removing + /// + private void BuildVoreContainerVerbs(EntityUid uid, VoreComponent comp, GetVerbsEvent args){ + var user = args.User; + var target = args.Target; // no self activation, only there to remove your own prey and not have other intervene or have others see that you have prey if (user == target){ var container = _containerSystem.EnsureContainer(target, comp.ContainerId); if (container.ContainedEntities.Count > 0){ args.Verbs.Add(new Verb { - Text = "Remove Prey", - Act = () =>TryReleasePrey(target, comp) + Text = "Release all prey", + Act = () => TryReleasePrey(target, comp) }); } return; } - - // only when reachable & interactable - if (!args.CanInteract || !args.CanAccess) - return; - // to avoid empty mind NPCs - if (!TryComp(target, out var mindContainer) || mindContainer.Mind == null) - return; - - /* if the user is a pred inside a pred allows them to have interactions with prey inside - only if they are in the same container however (not just same type but literally)*/ - if (!IsValidVoreInteraction(user, target)) - return; - - // devour (pred → prey) - if (_consentSystem.HasConsent(user, isPred) - && _consentSystem.HasConsent(target, isPrey)){ + // 1. devour (pred → prey) + if (IsDevourable(user, target)){ args.Verbs.Add(new Verb { Text = "Devour", Act = () => TryVore(user, target) }); } - // insert self (prey → pred) - if (_consentSystem.HasConsent(user, isPrey) - && _consentSystem.HasConsent(target, isPred)){ - args.Verbs.Add(new Verb - { - Text = "Insert Self", - Act = () => TryVore(target, user) - }); + // 2. insert self (prey → pred) + if (IsDevourable(target, user)){ + args.Verbs.Add(new Verb + { + Text = "Insert Self", + Act = () => TryVore(target, user) + }); } } + /// /// used for after selecting to insert into someone or devour /// will create a slow popup and warning to give both sides time to react on it @@ -211,10 +210,7 @@ private void OnVoreDoAfter(EntityUid uid, VoreComponent comp, OnVoreDoAfter args //moves prey inside the person _containerSystem.Insert(prey, container); - - /*make the prey immune to space+temp+breathing to avoid consent concerns from outside influence - gets removed after escaping or being forcefully ejected by pred*/ - ApplyStomachImmunities(prey, comp); + EnsureComp(prey); } /// @@ -252,38 +248,12 @@ private void TryReleasePrey(EntityUid pred, VoreComponent comp){ var preyList = new List(container.ContainedEntities); //remove everything from people to items foreach (var prey in preyList){ - // in case pred intentionally releases the prey to avoid escape popups - if (TryComp(prey, out var preyComp)) - preyComp.IntentionalRelease = true; - _containerSystem.Remove(prey, container); - _pendingImmunityUpdates.Add(prey); _popupSystem.PopupEntity("You have been released!", prey, prey); } _popupSystem.PopupEntity("You release your prey.", pred, pred); } - /// - /// in case the prey chose to escape themself - /// will remove the buffs such as space immunity for the target - /// - private void OnVoreRemovedFromContainer(EntityUid uid, VoreComponent comp, EntRemovedFromContainerMessage args){ - if (args.Container.ID != comp.ContainerId) - return; - - var prey = args.Entity; - - // Check if this was an intentional release by the pred (not a self-escape) - if (TryComp(prey, out var preyComp) && preyComp.IntentionalRelease){ - preyComp.IntentionalRelease = false; - return; - } - - _pendingImmunityUpdates.Add(prey); - _popupSystem.PopupEntity("You struggle free!", prey, prey); - _popupSystem.PopupEntity("Your prey escaped!", uid, uid); - } - /// /// in case the user gets gibbed need content emptied including prey+items /// @@ -318,6 +288,29 @@ private bool IsInVoreContainer(EntityUid uid){ container.ID == comp.ContainerId; } + /// + /// making sure all the consent toggles and issues are resolved before entering container + /// + /// + /// true if the entity is allowed to be eaten + /// + private bool IsDevourable(EntityUid user, EntityUid target){ + if (user == target) + return false; + if (!_playerManager.TryGetSessionByEntity(user, out _) || !_playerManager.TryGetSessionByEntity(target, out _)) + return false; + if (!HasComp(user) || !HasComp(target)) + return false; + if (!IsValidVoreInteraction(user, target)) + return false; + if (!_consentSystem.HasConsent(user, isPred) || !_consentSystem.HasConsent(target, isPrey)) + return false; + if (_mobStateSystem.IsDead(target) || _mobStateSystem.IsCritical(target)) + return false; + + return true; + } + /// /// checks if prey is inside a vore container to only allow vore in the same container /// diff --git a/Content.Shared/_Floof/Vore/VoreComponent.cs b/Content.Shared/_Floof/Vore/VoreComponent.cs index cbb4e8caddd..347d54af6ba 100644 --- a/Content.Shared/_Floof/Vore/VoreComponent.cs +++ b/Content.Shared/_Floof/Vore/VoreComponent.cs @@ -13,10 +13,6 @@ public sealed partial class VoreComponent : Component //TODO later include customizable containers for different vore types [DataField("containerId")] public string ContainerId = "vore_container"; - /// - /// Set to true when the pred intentionally releases this entity to suppress escape popup - /// - public bool IntentionalRelease = false; } [Serializable, NetSerializable] public sealed partial class OnVoreDoAfter : SimpleDoAfterEvent{ From 9143cfaba772c3a8943473a40999e150da7ed703 Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Wed, 27 May 2026 16:37:27 +0200 Subject: [PATCH 03/10] bugfixes --- Content.Server/_Floof/Vore/DevouredSystem.cs | 23 +++++++++++--------- Content.Server/_Floof/Vore/VoreSystem.cs | 1 - 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Content.Server/_Floof/Vore/DevouredSystem.cs b/Content.Server/_Floof/Vore/DevouredSystem.cs index 5960271d01b..cd004adc8ef 100644 --- a/Content.Server/_Floof/Vore/DevouredSystem.cs +++ b/Content.Server/_Floof/Vore/DevouredSystem.cs @@ -32,6 +32,7 @@ public sealed class VoreImmunitySystem : EntitySystem public override void Initialize() { + SubscribeLocalEvent(OnPreyInsertedIntoContainer); SubscribeLocalEvent(OnPreyRemovedFromContainer); SubscribeLocalEvent(OnStartup); @@ -43,16 +44,18 @@ public override void Initialize() public override void Update(float frameTime){ base.Update(frameTime); - foreach (var uid in _pendingImmunityUpdates) - { + foreach (var uid in _pendingImmunityUpdates){ RemoveStomachImmunities(uid); } _pendingImmunityUpdates.Clear(); } - private void OnStartup(EntityUid uid, DevouredComponent comp, ComponentStartup args){ - ApplyStomachImmunities(uid); + private void OnPreyInsertedIntoContainer(EntityUid uid, VoreComponent comp, EntInsertedIntoContainerMessage args){ + //double check making sure its a vore_container + if (args.Container.ID != comp.ContainerId) + return; + EnsureComp(args.Entity); } /// @@ -63,16 +66,17 @@ private void OnPreyRemovedFromContainer(EntityUid uid, VoreComponent comp, EntRe _pendingImmunityUpdates.Add(args.Entity); } + private void OnStartup(EntityUid uid, DevouredComponent comp, ComponentStartup args){ + ApplyStomachImmunities(uid); + } + /// - /// alternative way of escaping + /// alternative way of escaping instead of using movement keys /// private void OnGetVerbs(EntityUid uid, DevouredComponent comp, GetVerbsEvent args){ if (!_containerSystem.TryGetContainingContainer(uid, out var container)) return; - var prey = uid; - var pred = container.Owner; - - if (args.User != prey && args.User != pred) + if (args.User != args.Target) return; args.Verbs.Add(new Verb @@ -85,7 +89,6 @@ private void OnGetVerbs(EntityUid uid, DevouredComponent comp, GetVerbsEvent diff --git a/Content.Server/_Floof/Vore/VoreSystem.cs b/Content.Server/_Floof/Vore/VoreSystem.cs index eb2d6fa51c9..5bf1c264714 100644 --- a/Content.Server/_Floof/Vore/VoreSystem.cs +++ b/Content.Server/_Floof/Vore/VoreSystem.cs @@ -210,7 +210,6 @@ private void OnVoreDoAfter(EntityUid uid, VoreComponent comp, OnVoreDoAfter args //moves prey inside the person _containerSystem.Insert(prey, container); - EnsureComp(prey); } /// From cd6bab6028cc55ed041d146c9a22eb72e70b85e4 Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Wed, 27 May 2026 17:19:33 +0200 Subject: [PATCH 04/10] more bugfixes and a safety net for while loop --- Content.Server/_Floof/Vore/DevouredSystem.cs | 12 ++++++++++-- Content.Server/_Floof/Vore/VoreSystem.cs | 1 - 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Content.Server/_Floof/Vore/DevouredSystem.cs b/Content.Server/_Floof/Vore/DevouredSystem.cs index cd004adc8ef..f83db84d82a 100644 --- a/Content.Server/_Floof/Vore/DevouredSystem.cs +++ b/Content.Server/_Floof/Vore/DevouredSystem.cs @@ -79,6 +79,10 @@ private void OnGetVerbs(EntityUid uid, DevouredComponent comp, GetVerbsEvent(uid, out var vore)) return; + var safety = 0; while (_containerSystem.TryGetContainingContainer(uid, out var container) && container.ID == vore.ContainerId){ - _containerSystem.Remove(uid, container); + // prevention of possible infinite loop incase failed removal (better safe than sorry) + if (++safety > 10) + break; + if (!_containerSystem.Remove(uid, container)) + break; } } diff --git a/Content.Server/_Floof/Vore/VoreSystem.cs b/Content.Server/_Floof/Vore/VoreSystem.cs index 5bf1c264714..e87a08ecdec 100644 --- a/Content.Server/_Floof/Vore/VoreSystem.cs +++ b/Content.Server/_Floof/Vore/VoreSystem.cs @@ -3,7 +3,6 @@ using Robust.Shared.Serialization; using Robust.Shared.Containers; using Content.Shared.Body.Components; -using Content.Shared.Mind.Components; using Content.Shared.DoAfter; using Content.Shared.Popups; using Content.Shared.FloofStation; From a2341064e63d52ea05da086e11ca6723192b5e1f Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Sun, 31 May 2026 19:32:12 +0200 Subject: [PATCH 05/10] consent toggle deals with containers --- Content.Server/_Floof/Vore/DevouredSystem.cs | 9 +++++++ Content.Server/_Floof/Vore/VoreSystem.cs | 24 ++++++++++++++++--- .../_Floof/Vore/DevouredComponent.cs | 1 + 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Content.Server/_Floof/Vore/DevouredSystem.cs b/Content.Server/_Floof/Vore/DevouredSystem.cs index f83db84d82a..8a2a160805a 100644 --- a/Content.Server/_Floof/Vore/DevouredSystem.cs +++ b/Content.Server/_Floof/Vore/DevouredSystem.cs @@ -19,6 +19,7 @@ using Content.Shared.Movement.Components; using Content.Shared.Movement; using Content.Server.Radiation.Components; +using Content.Shared.Flash.Components; namespace Content.Server._Floof.Vore; public sealed class VoreImmunitySystem : EntitySystem @@ -168,6 +169,10 @@ should prevent possible exploitation of the system*/ EnsureComp(prey); tracker.AddedRadiation = true; } + if (!HasComp(prey)){ + EnsureComp(prey); + tracker.AddedFlash = true; + } _suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorOff); } @@ -199,6 +204,10 @@ private void RemoveStomachImmunities(EntityUid prey){ RemComp(prey); tracker.AddedRadiation = false; } + if (tracker.AddedFlash){ + RemComp(prey); + tracker.AddedFlash = false; + } _suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorCords); RemComp(prey); } diff --git a/Content.Server/_Floof/Vore/VoreSystem.cs b/Content.Server/_Floof/Vore/VoreSystem.cs index 7118592c532..9942ec72296 100644 --- a/Content.Server/_Floof/Vore/VoreSystem.cs +++ b/Content.Server/_Floof/Vore/VoreSystem.cs @@ -90,9 +90,27 @@ private void ApplyVoreConsent(EntityUid uid){ /* in case prey is inside a container immediately release them when they turn off prey consent works as an emergency leave for the prey*/ - if (!hasPrey && IsInVoreContainer(uid) && - _containerSystem.TryGetContainingContainer(uid, out var container)){ - _containerSystem.Remove(uid, container); + if (!hasPrey){ + var safety = 0; + while (_containerSystem.TryGetContainingContainer(uid, out var container)){ + if (++safety > 10) + break; + + if (IsInVoreContainer(uid)){ + _containerSystem.Remove(uid, container); + } + else{ + break; + } + } + } + // same for pred release all current prey + if (!hasPred){ + if (TryComp(uid, out var comp)){ + var container = _containerSystem.EnsureContainer(uid, comp.ContainerId); + if (container.ContainedEntities.Count > 0) + TryReleasePrey(uid, comp); + } } //give the mob the needed component to be able to see the verbs diff --git a/Content.Shared/_Floof/Vore/DevouredComponent.cs b/Content.Shared/_Floof/Vore/DevouredComponent.cs index 15d7a023d43..0dcd94d3ca7 100644 --- a/Content.Shared/_Floof/Vore/DevouredComponent.cs +++ b/Content.Shared/_Floof/Vore/DevouredComponent.cs @@ -5,4 +5,5 @@ public sealed partial class DevouredComponent : Component public bool AddedBreathing; public bool AddedTemperature; public bool AddedRadiation; + public bool AddedFlash; } \ No newline at end of file From 72dedc51bc3b1b632758bcf5c7015163d7af1bd5 Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Wed, 3 Jun 2026 16:24:04 +0200 Subject: [PATCH 06/10] cords are now saved --- Content.Server/_Floof/Vore/DevouredSystem.cs | 20 +++++++++++++++++-- .../_Floof/Vore/DevouredComponent.cs | 6 ++++++ RobustToolbox | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Content.Server/_Floof/Vore/DevouredSystem.cs b/Content.Server/_Floof/Vore/DevouredSystem.cs index 8a2a160805a..54c13ff3a39 100644 --- a/Content.Server/_Floof/Vore/DevouredSystem.cs +++ b/Content.Server/_Floof/Vore/DevouredSystem.cs @@ -20,6 +20,7 @@ using Content.Shared.Movement; using Content.Server.Radiation.Components; using Content.Shared.Flash.Components; +using Content.Shared.Inventory; namespace Content.Server._Floof.Vore; public sealed class VoreImmunitySystem : EntitySystem @@ -28,6 +29,7 @@ public sealed class VoreImmunitySystem : EntitySystem [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly SharedSuitSensorSystem _suitSensorSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; private readonly HashSet _pendingImmunityUpdates = new(); @@ -174,7 +176,15 @@ should prevent possible exploitation of the system*/ tracker.AddedFlash = true; } - _suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorOff); + //_suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorOff); + var slotEnumerator = _inventorySystem.GetSlotEnumerator(prey, SlotFlags.All); + while (slotEnumerator.NextItem(out var item, out var slot)) + { + if (TryComp(item, out var sensorComp)){ + tracker.OriginalSensorModes[slot.Name] = sensorComp.Mode; + _suitSensorSystem.SetSensor((item, sensorComp), SuitSensorMode.SensorOff); + } + } } /// @@ -208,7 +218,13 @@ private void RemoveStomachImmunities(EntityUid prey){ RemComp(prey); tracker.AddedFlash = false; } - _suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorCords); + foreach (var (slotId, originalMode) in tracker.OriginalSensorModes){ + if (!_inventorySystem.TryGetSlotEntity(prey, slotId, out var item)) + continue; + if (TryComp(item, out var sensorComp)) + _suitSensorSystem.SetSensor((item.Value, sensorComp), originalMode); + } + //_suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorCords); RemComp(prey); } } \ No newline at end of file diff --git a/Content.Shared/_Floof/Vore/DevouredComponent.cs b/Content.Shared/_Floof/Vore/DevouredComponent.cs index 0dcd94d3ca7..a9b7e98a9e1 100644 --- a/Content.Shared/_Floof/Vore/DevouredComponent.cs +++ b/Content.Shared/_Floof/Vore/DevouredComponent.cs @@ -1,3 +1,6 @@ +using Content.Shared.Medical.SuitSensor; +namespace Content.Server._Floof.Vore; + [RegisterComponent] public sealed partial class DevouredComponent : Component { @@ -6,4 +9,7 @@ public sealed partial class DevouredComponent : Component public bool AddedTemperature; public bool AddedRadiation; public bool AddedFlash; + + [DataField("originalSensorModes")] + public Dictionary OriginalSensorModes = new(); } \ No newline at end of file diff --git a/RobustToolbox b/RobustToolbox index 68f8d00931d..dbde8023ed2 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 68f8d00931d6b14f3e592d50c47dd44ef09eed1f +Subproject commit dbde8023ed256ac69ae4b419422c936f78361653 From cf36b3a49c3ef799fba46dbd55326165bdbc0d1a Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Thu, 4 Jun 2026 14:20:06 +0200 Subject: [PATCH 07/10] test and port of tracking of cords --- Content.Server/_Floof/Vore/DevouredSystem.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Content.Server/_Floof/Vore/DevouredSystem.cs b/Content.Server/_Floof/Vore/DevouredSystem.cs index 54c13ff3a39..7498aa2b9de 100644 --- a/Content.Server/_Floof/Vore/DevouredSystem.cs +++ b/Content.Server/_Floof/Vore/DevouredSystem.cs @@ -176,7 +176,6 @@ should prevent possible exploitation of the system*/ tracker.AddedFlash = true; } - //_suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorOff); var slotEnumerator = _inventorySystem.GetSlotEnumerator(prey, SlotFlags.All); while (slotEnumerator.NextItem(out var item, out var slot)) { @@ -224,7 +223,6 @@ private void RemoveStomachImmunities(EntityUid prey){ if (TryComp(item, out var sensorComp)) _suitSensorSystem.SetSensor((item.Value, sensorComp), originalMode); } - //_suitSensorSystem.SetAllSensors(prey, SuitSensorMode.SensorCords); RemComp(prey); } } \ No newline at end of file From fb39ab6aceb9c14af403af440b878993a39c85f8 Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Thu, 4 Jun 2026 15:11:08 +0200 Subject: [PATCH 08/10] better tracking of cords using entityuid --- Content.Server/_Floof/Vore/DevouredSystem.cs | 14 ++++++-------- Content.Shared/_Floof/Vore/DevouredComponent.cs | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Content.Server/_Floof/Vore/DevouredSystem.cs b/Content.Server/_Floof/Vore/DevouredSystem.cs index 7498aa2b9de..5d9a0261fa2 100644 --- a/Content.Server/_Floof/Vore/DevouredSystem.cs +++ b/Content.Server/_Floof/Vore/DevouredSystem.cs @@ -141,7 +141,7 @@ private bool IsInVoreContainer(EntityUid uid){ } /// - /// the prey needs to have certain components such as pressure immunity + /// the prey needs to have certain components such as pressure immunity and their cords off /// for consent purposes -> having others avoid stumbling on scenarios /// private void ApplyStomachImmunities(EntityUid prey){ @@ -177,10 +177,9 @@ should prevent possible exploitation of the system*/ } var slotEnumerator = _inventorySystem.GetSlotEnumerator(prey, SlotFlags.All); - while (slotEnumerator.NextItem(out var item, out var slot)) - { + while (slotEnumerator.NextItem(out var item, out var slot)){ if (TryComp(item, out var sensorComp)){ - tracker.OriginalSensorModes[slot.Name] = sensorComp.Mode; + tracker.OriginalSensorModes[item] = sensorComp.Mode; _suitSensorSystem.SetSensor((item, sensorComp), SuitSensorMode.SensorOff); } } @@ -188,6 +187,7 @@ should prevent possible exploitation of the system*/ /// /// the removal of the devouredcomponent and immunities after leaving a container + /// and the reset of their cords to their original state /// to avoid intentional and accidental exploitation /// private void RemoveStomachImmunities(EntityUid prey){ @@ -217,11 +217,9 @@ private void RemoveStomachImmunities(EntityUid prey){ RemComp(prey); tracker.AddedFlash = false; } - foreach (var (slotId, originalMode) in tracker.OriginalSensorModes){ - if (!_inventorySystem.TryGetSlotEntity(prey, slotId, out var item)) - continue; + foreach (var (item, originalMode) in tracker.OriginalSensorModes){ if (TryComp(item, out var sensorComp)) - _suitSensorSystem.SetSensor((item.Value, sensorComp), originalMode); + _suitSensorSystem.SetSensor((item, sensorComp), originalMode); } RemComp(prey); } diff --git a/Content.Shared/_Floof/Vore/DevouredComponent.cs b/Content.Shared/_Floof/Vore/DevouredComponent.cs index a9b7e98a9e1..ec53ba3f92b 100644 --- a/Content.Shared/_Floof/Vore/DevouredComponent.cs +++ b/Content.Shared/_Floof/Vore/DevouredComponent.cs @@ -11,5 +11,5 @@ public sealed partial class DevouredComponent : Component public bool AddedFlash; [DataField("originalSensorModes")] - public Dictionary OriginalSensorModes = new(); + public Dictionary OriginalSensorModes = new(); } \ No newline at end of file From f277862d37276cfbd2385aced719630285a307ec Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Thu, 4 Jun 2026 15:13:02 +0200 Subject: [PATCH 09/10] also clearing the tracker after.. --- Content.Server/_Floof/Vore/DevouredSystem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Content.Server/_Floof/Vore/DevouredSystem.cs b/Content.Server/_Floof/Vore/DevouredSystem.cs index 5d9a0261fa2..cc879f92911 100644 --- a/Content.Server/_Floof/Vore/DevouredSystem.cs +++ b/Content.Server/_Floof/Vore/DevouredSystem.cs @@ -221,6 +221,7 @@ private void RemoveStomachImmunities(EntityUid prey){ if (TryComp(item, out var sensorComp)) _suitSensorSystem.SetSensor((item, sensorComp), originalMode); } + tracker.OriginalSensorModes.Clear(); RemComp(prey); } } \ No newline at end of file From 7892a0fda284daf1f1326e0e5f92f98bcabb0d34 Mon Sep 17 00:00:00 2001 From: JaDiDo Date: Thu, 4 Jun 2026 17:29:18 +0200 Subject: [PATCH 10/10] code logic adjustment --- Content.Server/_Floof/Vore/VoreSystem.cs | 38 +++++++++++------------- RobustToolbox | 2 +- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Content.Server/_Floof/Vore/VoreSystem.cs b/Content.Server/_Floof/Vore/VoreSystem.cs index 9942ec72296..2373214d920 100644 --- a/Content.Server/_Floof/Vore/VoreSystem.cs +++ b/Content.Server/_Floof/Vore/VoreSystem.cs @@ -82,34 +82,32 @@ private void OnConsentStartup(EntityUid uid, ConsentComponent comp, ComponentSta /// /// gives a mob the vore component if they have selected either pred or prey consent and removes it if they have neither + /// also handles container if consent is off but preds container is still full/prey is inside vore container /// private void ApplyVoreConsent(EntityUid uid){ var hasPred = _consentSystem.HasConsent(uid, isPred); var hasPrey = _consentSystem.HasConsent(uid, isPrey); //TODO var for digest - /* in case prey is inside a container immediately release them when they turn off prey consent - works as an emergency leave for the prey*/ - if (!hasPrey){ - var safety = 0; - while (_containerSystem.TryGetContainingContainer(uid, out var container)){ - if (++safety > 10) - break; - - if (IsInVoreContainer(uid)){ - _containerSystem.Remove(uid, container); - } - else{ - break; + if (TryComp(uid, out var comp)){ + /* in case prey is inside a container immediately release them when they turn off prey consent + works as an emergency leave for the prey*/ + if (!hasPrey){ + var safety = 0; + while (_containerSystem.TryGetContainingContainer(uid, out var container) && container.ID == comp.ContainerId){ + if (++safety > 10) + break; + if (!_containerSystem.Remove(uid, container)) + break; } } - } - // same for pred release all current prey - if (!hasPred){ - if (TryComp(uid, out var comp)){ - var container = _containerSystem.EnsureContainer(uid, comp.ContainerId); - if (container.ContainedEntities.Count > 0) - TryReleasePrey(uid, comp); + + // same for pred release all current prey after turning off consent + if (!hasPred){ + if (_containerSystem.TryGetContainer(uid, comp.ContainerId, out var container)){ + _containerSystem.EmptyContainer(container); + _containerSystem.ShutdownContainer(container); + } } } diff --git a/RobustToolbox b/RobustToolbox index dbde8023ed2..68f8d00931d 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit dbde8023ed256ac69ae4b419422c936f78361653 +Subproject commit 68f8d00931d6b14f3e592d50c47dd44ef09eed1f