From 2f1b2c6d16a078eeaf5970a2d1614ab28ceda2e2 Mon Sep 17 00:00:00 2001 From: Milon Date: Sat, 9 Nov 2024 03:12:47 +0100 Subject: [PATCH] this is an insult to my sanity --- .../Metempsychosis/MetempsychosisTest.cs | 18 +- .../Cloning/CloningSystem.Metempsychosis.cs | 172 ++++++++++++++++++ Content.Server/Cloning/CloningSystem.cs | 114 ++---------- .../DeltaV/Chapel/SacrificialAltarSystem.cs | 2 +- .../Cloning/MetempsychosisKarmaComponent.cs | 11 ++ .../Cloning/MetempsychoticMachineComponent.cs | 21 +++ .../Cloning/MetempsychosisKarmaComponent.cs | 12 -- .../Cloning/MetempsychoticMachineComponent.cs | 22 --- .../Cloning/MetempsychoticMachineSystem.cs | 47 ----- 9 files changed, 231 insertions(+), 188 deletions(-) create mode 100644 Content.Server/Cloning/CloningSystem.Metempsychosis.cs create mode 100644 Content.Server/DeltaV/Cloning/MetempsychosisKarmaComponent.cs create mode 100644 Content.Server/DeltaV/Cloning/MetempsychoticMachineComponent.cs delete mode 100644 Content.Server/Nyanotrasen/Cloning/MetempsychosisKarmaComponent.cs delete mode 100644 Content.Server/Nyanotrasen/Cloning/MetempsychoticMachineComponent.cs delete mode 100644 Content.Server/Nyanotrasen/Cloning/MetempsychoticMachineSystem.cs diff --git a/Content.IntegrationTests/Tests/Nyanotrasen/Metempsychosis/MetempsychosisTest.cs b/Content.IntegrationTests/Tests/Nyanotrasen/Metempsychosis/MetempsychosisTest.cs index cd6a4b4c2b..27e8a007b9 100644 --- a/Content.IntegrationTests/Tests/Nyanotrasen/Metempsychosis/MetempsychosisTest.cs +++ b/Content.IntegrationTests/Tests/Nyanotrasen/Metempsychosis/MetempsychosisTest.cs @@ -28,13 +28,17 @@ public sealed class MetempsychosisTest prototypeManager.TryIndex(metemComponent.MetempsychoticNonHumanoidPool, out var nonHumanoidPool); - Assert.That(humanoidPool, Is.Not.Null, "MetempsychoticHumanoidPool is null!"); - Assert.That(nonHumanoidPool, Is.Not.Null, "MetempsychoticNonHumanoidPool is null!"); - - Assert.That(humanoidPool.Weights, Is.Not.Empty, - "MetempsychoticHumanoidPool has no valid prototypes!"); - Assert.That(nonHumanoidPool.Weights, Is.Not.Empty, - "MetempsychoticNonHumanoidPool has no valid prototypes!"); + Assert.Multiple(() => + { + Assert.That(humanoidPool, Is.Not.Null, "MetempsychoticHumanoidPool is null!"); + Assert.That(nonHumanoidPool, Is.Not.Null, "MetempsychoticNonHumanoidPool is null!"); + Assert.That(humanoidPool.Weights, + Is.Not.Empty, + "MetempsychoticHumanoidPool has no valid prototypes!"); + Assert.That(nonHumanoidPool.Weights, + Is.Not.Empty, + "MetempsychoticNonHumanoidPool has no valid prototypes!"); + }); foreach (var key in humanoidPool.Weights.Keys) { diff --git a/Content.Server/Cloning/CloningSystem.Metempsychosis.cs b/Content.Server/Cloning/CloningSystem.Metempsychosis.cs new file mode 100644 index 0000000000..2c14dc37ac --- /dev/null +++ b/Content.Server/Cloning/CloningSystem.Metempsychosis.cs @@ -0,0 +1,172 @@ +using Content.Server.DeltaV.Cloning; +using Content.Shared.Humanoid; +using Content.Shared.Humanoid.Prototypes; +using Content.Shared.Preferences; +using Content.Shared.Speech; +using Content.Shared.Emoting; +using Content.Shared.Damage.ForceSay; +using Content.Shared.SSDIndicator; +using Content.Server.Speech.Components; +using Content.Server.Ghost.Roles.Components; +using Content.Server.StationEvents.Components; +using Content.Server.Psionics; +using Robust.Shared.Random; +using Content.Shared.Mind.Components; +using Content.Shared.Tag; +using Content.Shared.Cloning; +using Content.Shared.Random.Helpers; +using Robust.Shared.GameObjects.Components.Localization; + +namespace Content.Server.Cloning; + +public sealed partial class CloningSystem +{ + [Dependency] private readonly TagSystem _tag = default!; + [Dependency] private readonly GrammarSystem _grammar = default!; + + /// + /// Gets the entity prototype to spawn for a clone based on karma and chance calculations. + /// + private string GetSpawnEntity(Entity ent, float karmaBonus, SpeciesPrototype oldSpecies, out SpeciesPrototype? species, int karma = 0) + { + // First time being cloned - return original species + if (karma == 0) + { + species = oldSpecies; + return oldSpecies.Prototype; + } + + var chance = ent.Comp.HumanoidBaseChance + karmaBonus; + chance -= ((1 - ent.Comp.HumanoidBaseChance) * karma); + + // Perfect clone chance + if (chance > 1 && _robustRandom.Prob(chance - 1)) + { + species = oldSpecies; + return oldSpecies.Prototype; + } + + // Roll for humanoid vs non-humanoid + chance = Math.Clamp(chance, 0, 1); + if (_robustRandom.Prob(chance)) + { + if (_prototype.TryIndex(ent.Comp.MetempsychoticHumanoidPool, out var humanoidPool)) + { + var protoId = humanoidPool.Pick(); + if (_prototype.TryIndex(protoId, out var speciesPrototype)) + { + species = speciesPrototype; + return speciesPrototype.Prototype; + } + } + } + else if (_prototype.TryIndex(ent.Comp.MetempsychoticNonHumanoidPool, out var nonHumanoidPool)) + { + // For non-humanoids, return the entity prototype directly + species = null; + return nonHumanoidPool.Pick(); + } + + // Fallback to original species if prototype indexing fails + _sawmill.Error("Failed to get valid clone type - falling back to original species"); + species = oldSpecies; + return oldSpecies.Prototype; + } + + /// + /// Handles fetching the mob and managing appearance for cloning with metempsychosis mechanics + /// + private EntityUid FetchAndSpawnMob( + Entity pod, + HumanoidCharacterProfile pref, + SpeciesPrototype speciesPrototype, + HumanoidAppearanceComponent humanoid, + EntityUid bodyToClone, + float karmaBonus) + { + List sexes = []; + var switchingSpecies = false; + var applyKarma = false; + var toSpawn = speciesPrototype.Prototype; + + // Get existing karma score or start at 0 + var karmaScore = 0; + if (TryComp(bodyToClone, out var oldKarma)) + { + karmaScore = oldKarma.Score; + } + + if (TryComp(pod.Owner, out var metem)) + { + var metemEntity = new Entity(pod.Owner, metem); + toSpawn = GetSpawnEntity(metemEntity, karmaBonus, speciesPrototype, out var newSpecies, karmaScore); + applyKarma = true; + + if (newSpecies != null) + { + sexes = newSpecies.Sexes; + speciesPrototype = newSpecies; + + if (speciesPrototype.ID != newSpecies.ID) + switchingSpecies = true; + } + } + + var mob = Spawn(toSpawn, _transformSystem.GetMapCoordinates(pod.Owner)); + + // Only try to handle humanoid appearance if we have a humanoid component + if (TryComp(mob, out var newHumanoid)) + { + if (switchingSpecies || HasComp(bodyToClone)) + { + pref = HumanoidCharacterProfile.RandomWithSpecies(newHumanoid.Species); + if (sexes.Contains(humanoid.Sex)) + pref = pref.WithSex(humanoid.Sex); + + pref = pref.WithGender(humanoid.Gender); + pref = pref.WithAge(humanoid.Age); + } + + _humanoidSystem.LoadProfile(mob, pref); + } + + if (applyKarma) + { + var karma = EnsureComp(mob); + karma.Score = karmaScore + 1; // Increment karma score + } + + var ev = new CloningEvent(bodyToClone, mob); + RaiseLocalEvent(bodyToClone, ref ev); + + if (!ev.NameHandled) + _metaSystem.SetEntityName(mob, MetaData(bodyToClone).EntityName); + + var grammar = EnsureComp(mob); + var grammarEnt = new Entity(mob, grammar); + _grammar.SetProperNoun(grammarEnt, true); + _grammar.SetGender(grammarEnt, humanoid.Gender); + Dirty(mob, grammar); + + SetupBasicComponents(mob); + + return mob; + } + + // I hate this + private void SetupBasicComponents(EntityUid mob) + { + EnsureComp(mob); + EnsureComp(mob); + EnsureComp(mob); + EnsureComp(mob); + EnsureComp(mob); + EnsureComp(mob); + RemComp(mob); + RemComp(mob); + RemComp(mob); + RemComp(mob); + + _tag.AddTag(mob, "DoorBumpOpener"); + } +} diff --git a/Content.Server/Cloning/CloningSystem.cs b/Content.Server/Cloning/CloningSystem.cs index 0eafad3586..d3c56d1bdb 100644 --- a/Content.Server/Cloning/CloningSystem.cs +++ b/Content.Server/Cloning/CloningSystem.cs @@ -9,6 +9,8 @@ using Content.Server.Jobs; using Content.Server.Materials; using Content.Server.Popups; using Content.Server.Power.EntitySystems; +using Content.Server.Psionics; // DeltaV +using Content.Server.Traits.Assorted; // DeltaV using Content.Shared.Atmos; using Content.Shared.CCVar; using Content.Shared.Chemistry.Components; @@ -33,26 +35,10 @@ using Robust.Shared.Containers; using Robust.Shared.Physics.Components; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Content.Server.Traits.Assorted; //Nyano - Summary: allows the potential psionic ability to be written to the character. -using Content.Server.Psionics; //DeltaV needed for Psionic Systems -using Content.Shared.Speech; //DeltaV Start Metem Usings -using Content.Shared.Tag; -using Content.Shared.Preferences; -using Content.Shared.Emoting; -using Content.Server.Speech.Components; -using Content.Server.StationEvents.Components; -using Content.Server.Ghost.Roles.Components; -using Content.Server.Nyanotrasen.Cloning; -using Content.Shared.Humanoid.Prototypes; -using Robust.Shared.GameObjects.Components.Localization; //DeltaV End Metem Usings -using Content.Server.EntityList; -using Content.Shared.SSDIndicator; -using Content.Shared.Damage.ForceSay; -using Content.Server.Polymorph.Components; namespace Content.Server.Cloning { - public sealed class CloningSystem : EntitySystem + public sealed partial class CloningSystem : EntitySystem { [Dependency] private readonly DeviceLinkSystem _signalSystem = default!; [Dependency] private readonly IPlayerManager _playerManager = null!; @@ -76,8 +62,9 @@ namespace Content.Server.Cloning [Dependency] private readonly SharedMindSystem _mindSystem = default!; [Dependency] private readonly MetaDataSystem _metaSystem = default!; [Dependency] private readonly SharedJobSystem _jobs = default!; - [Dependency] private readonly MetempsychoticMachineSystem _metem = default!; //DeltaV - [Dependency] private readonly TagSystem _tag = default!; //DeltaV + [Dependency] private readonly ILogManager _log = default!; // DeltaV + + private ISawmill _sawmill = default!; // DeltaV public readonly Dictionary ClonesWaitingForMind = new(); public const float EasyModeCloningCost = 0.7f; @@ -86,6 +73,8 @@ namespace Content.Server.Cloning { base.Initialize(); + _sawmill = _log.GetSawmill("cloning"); // DeltaV + SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(Reset); SubscribeLocalEvent(HandleMindAdded); @@ -158,6 +147,10 @@ namespace Content.Server.Cloning if (!Resolve(uid, ref clonePod)) return false; + // DeltaV - This method should use Entity pod instead + // But I don't want to completely mangle it so we do this here + var podEnt = new Entity(uid, clonePod); + if (HasComp(uid)) return false; @@ -248,9 +241,10 @@ namespace Content.Server.Cloning } // end of genetic damage checks - var mob = FetchAndSpawnMob(clonePod, pref, speciesPrototype, humanoid, bodyToClone, karmaBonus); //DeltaV Replaces CloneAppearance with Metem/Clone via FetchAndSpawnMob + // DeltaV - Replaces CloneAppearance with Metem/Clone via FetchAndSpawnMob + var mob = FetchAndSpawnMob(podEnt, pref, speciesPrototype, humanoid, bodyToClone, karmaBonus); - ///Nyano - Summary: adds the potential psionic trait to the reanimated mob. + // Nyano - Summary: adds the potential psionic trait to the reanimated mob. EnsureComp(mob); var ev = new CloningEvent(bodyToClone, mob); @@ -375,84 +369,6 @@ namespace Content.Server.Cloning RemCompDeferred(uid); } - /// - /// Start Nyano Code: Handles fetching the mob and any appearance stuff... - /// - private EntityUid FetchAndSpawnMob(CloningPodComponent clonePod, HumanoidCharacterProfile pref, SpeciesPrototype speciesPrototype, HumanoidAppearanceComponent humanoid, EntityUid bodyToClone, float karmaBonus) - { - List sexes = new(); - bool switchingSpecies = false; - bool applyKarma = false; - var toSpawn = speciesPrototype.Prototype; - TryComp(bodyToClone, out var oldKarma); - - if (TryComp(clonePod.Owner, out var metem)) - { - toSpawn = _metem.GetSpawnEntity(clonePod.Owner, karmaBonus, metem, speciesPrototype, out var newSpecies, oldKarma?.Score); - applyKarma = true; - - if (newSpecies != null) - { - sexes = newSpecies.Sexes; - - if (speciesPrototype.ID != newSpecies.ID) - switchingSpecies = true; - - speciesPrototype = newSpecies; - } - } - - var mob = Spawn(toSpawn, _transformSystem.GetMapCoordinates(clonePod.Owner)); - if (TryComp(mob, out var newHumanoid)) - { - if (switchingSpecies || HasComp(bodyToClone)) - { - pref = HumanoidCharacterProfile.RandomWithSpecies(newHumanoid.Species); - if (sexes.Contains(humanoid.Sex)) - pref = pref.WithSex(humanoid.Sex); - - pref = pref.WithGender(humanoid.Gender); - pref = pref.WithAge(humanoid.Age); - - } - _humanoidSystem.LoadProfile(mob, pref); - } - - if (applyKarma) - { - var karma = EnsureComp(mob); - karma.Score++; - if (oldKarma != null) - karma.Score += oldKarma.Score; - } - - var ev = new CloningEvent(bodyToClone, mob); - RaiseLocalEvent(bodyToClone, ref ev); - - if (!ev.NameHandled) - _metaSystem.SetEntityName(mob, MetaData(bodyToClone).EntityName); - - var grammar = EnsureComp(mob); - grammar.ProperNoun = true; - grammar.Gender = humanoid.Gender; - Dirty(mob, grammar); - - EnsureComp(mob); - EnsureComp(mob); - EnsureComp(mob); - EnsureComp(mob); - EnsureComp(mob); - EnsureComp(mob); - RemComp(mob); - RemComp(mob); - RemComp(mob); - RemComp(mob); - - _tag.AddTag(mob, "DoorBumpOpener"); - - return mob; - } - //End Nyano Code public void Reset(RoundRestartCleanupEvent ev) { ClonesWaitingForMind.Clear(); diff --git a/Content.Server/DeltaV/Chapel/SacrificialAltarSystem.cs b/Content.Server/DeltaV/Chapel/SacrificialAltarSystem.cs index a903d4124d..8d28297cf6 100644 --- a/Content.Server/DeltaV/Chapel/SacrificialAltarSystem.cs +++ b/Content.Server/DeltaV/Chapel/SacrificialAltarSystem.cs @@ -1,5 +1,5 @@ using Content.Server.Bible.Components; -using Content.Server.Nyanotrasen.Cloning; +using Content.Server.DeltaV.Cloning; using Content.Shared.Abilities.Psionics; using Content.Shared.Administration.Logs; using Content.Shared.Body.Components; diff --git a/Content.Server/DeltaV/Cloning/MetempsychosisKarmaComponent.cs b/Content.Server/DeltaV/Cloning/MetempsychosisKarmaComponent.cs new file mode 100644 index 0000000000..802f24297b --- /dev/null +++ b/Content.Server/DeltaV/Cloning/MetempsychosisKarmaComponent.cs @@ -0,0 +1,11 @@ +namespace Content.Server.DeltaV.Cloning; + +/// +/// This tracks how many times you have already been cloned and lowers your chance of getting a humanoid each time. +/// +[RegisterComponent] +public sealed partial class MetempsychosisKarmaComponent : Component +{ + [DataField] + public int Score; +} diff --git a/Content.Server/DeltaV/Cloning/MetempsychoticMachineComponent.cs b/Content.Server/DeltaV/Cloning/MetempsychoticMachineComponent.cs new file mode 100644 index 0000000000..c00fc2120d --- /dev/null +++ b/Content.Server/DeltaV/Cloning/MetempsychoticMachineComponent.cs @@ -0,0 +1,21 @@ +using Content.Shared.Random; +using Robust.Shared.Prototypes; + +namespace Content.Server.DeltaV.Cloning; + +[RegisterComponent] +public sealed partial class MetempsychoticMachineComponent : Component +{ + /// + /// Chance you will spawn as a humanoid instead of a non humanoid. + /// + [DataField] + public float HumanoidBaseChance = 0.75f; + + [DataField] + public ProtoId MetempsychoticHumanoidPool = "MetempsychoticHumanoidPool"; + + [DataField] + public ProtoId MetempsychoticNonHumanoidPool = "MetempsychoticNonhumanoidPool"; +} + diff --git a/Content.Server/Nyanotrasen/Cloning/MetempsychosisKarmaComponent.cs b/Content.Server/Nyanotrasen/Cloning/MetempsychosisKarmaComponent.cs deleted file mode 100644 index 246495cee0..0000000000 --- a/Content.Server/Nyanotrasen/Cloning/MetempsychosisKarmaComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Content.Server.Nyanotrasen.Cloning -{ - /// - /// This tracks how many times you have already been cloned and lowers your chance of getting a humanoid each time. - /// - [RegisterComponent] - public sealed partial class MetempsychosisKarmaComponent : Component - { - [DataField("score")] - public int Score = 0; - } -} diff --git a/Content.Server/Nyanotrasen/Cloning/MetempsychoticMachineComponent.cs b/Content.Server/Nyanotrasen/Cloning/MetempsychoticMachineComponent.cs deleted file mode 100644 index 0adcc9b5b2..0000000000 --- a/Content.Server/Nyanotrasen/Cloning/MetempsychoticMachineComponent.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Content.Shared.Random; - -namespace Content.Server.Nyanotrasen.Cloning -{ - [RegisterComponent] - public sealed partial class MetempsychoticMachineComponent : Component - { - /// - /// Chance you will spawn as a humanoid instead of a non humanoid. - /// - [DataField("humanoidBaseChance")] - public float HumanoidBaseChance = 0.75f; - - [ValidatePrototypeId] - [DataField("metempsychoticHumanoidPool")] - public string MetempsychoticHumanoidPool = "MetempsychoticHumanoidPool"; - - [ValidatePrototypeId] - [DataField("metempsychoticNonHumanoidPool")] - public string MetempsychoticNonHumanoidPool = "MetempsychoticNonhumanoidPool"; - } -} diff --git a/Content.Server/Nyanotrasen/Cloning/MetempsychoticMachineSystem.cs b/Content.Server/Nyanotrasen/Cloning/MetempsychoticMachineSystem.cs deleted file mode 100644 index 62dc1b078e..0000000000 --- a/Content.Server/Nyanotrasen/Cloning/MetempsychoticMachineSystem.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Content.Shared.Humanoid.Prototypes; -using Content.Shared.Random; -using Content.Shared.Random.Helpers; -using Robust.Shared.Random; -using Robust.Shared.Prototypes; - -namespace Content.Server.Nyanotrasen.Cloning -{ - public sealed class MetempsychoticMachineSystem : EntitySystem - { - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - - private ISawmill _sawmill = default!; - - public string GetSpawnEntity(EntityUid uid, float karmaBonus, MetempsychoticMachineComponent component, SpeciesPrototype oldSpecies, out SpeciesPrototype? species, int? karma = null) - { - var chance = component.HumanoidBaseChance + karmaBonus; - - if (karma != null) - chance -= ((1 - component.HumanoidBaseChance) * (float) karma); - - if (chance > 1 && _random.Prob(chance - 1)) - { - species = oldSpecies; - return oldSpecies.Prototype; - } - else - chance = 1; - - chance = Math.Clamp(chance, 0, 1); - if (_random.Prob(chance) && - _prototypeManager.TryIndex(component.MetempsychoticHumanoidPool, out var humanoidPool) && - _prototypeManager.TryIndex(humanoidPool.Pick(), out var speciesPrototype)) - { - species = speciesPrototype; - return speciesPrototype.Prototype; - } - else - { - species = null; - _sawmill.Error("Could not index species for metempsychotic machine..."); - return "MobHuman"; - } - } - } -}