From 6cebc2d73368063c20cdadfa233391c59f0ac2f8 Mon Sep 17 00:00:00 2001 From: corentt <36075110+corentt@users.noreply.github.com> Date: Mon, 23 Jan 2023 00:36:03 +0100 Subject: [PATCH] Zombie cloning fix (#12520) --- .../Cloning/CloningConsoleSystem.cs | 7 +++- Content.Server/Cloning/CloningSystem.cs | 24 ++++++++++++- Content.Server/Zombies/ZombieSystem.cs | 35 +++++++++++++++++++ .../Zombies/ZombifyOnDeathSystem.cs | 5 +++ Content.Shared/Zombies/ZombieComponent.cs | 19 ++++++++++ 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/Content.Server/Cloning/CloningConsoleSystem.cs b/Content.Server/Cloning/CloningConsoleSystem.cs index 5efb34f3d6..eb8e2b80cb 100644 --- a/Content.Server/Cloning/CloningConsoleSystem.cs +++ b/Content.Server/Cloning/CloningConsoleSystem.cs @@ -1,5 +1,7 @@ using System.Linq; using JetBrains.Annotations; +using Robust.Shared.Timing; +using Content.Server.Administration.Logs; using Content.Server.Medical.Components; using Content.Server.Cloning.Components; using Content.Server.MachineLinking.Components; @@ -13,6 +15,7 @@ using Robust.Server.GameObjects; using Robust.Server.Player; using Content.Shared.Cloning.CloningConsole; using Content.Shared.Cloning; +using Content.Shared.Database; using Content.Shared.MachineLinking.Events; using Content.Shared.IdentityManagement; using Content.Shared.Mobs.Components; @@ -24,6 +27,7 @@ namespace Content.Server.Cloning public sealed class CloningConsoleSystem : EntitySystem { [Dependency] private readonly SignalLinkerSystem _signalSystem = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly CloningSystem _cloningSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; @@ -168,7 +172,8 @@ namespace Content.Server.Cloning if (mind == null || mind.UserId.HasValue == false || mind.Session == null) return; - _cloningSystem.TryCloning(cloningPodUid, body.Value, mind, cloningPod, scannerComp.CloningFailChanceMultiplier); + if (_cloningSystem.TryCloning(cloningPodUid, body.Value, mind, cloningPod, scannerComp.CloningFailChanceMultiplier)) + _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(uid)} successfully cloned {ToPrettyString(body.Value)}."); } public void RecheckConnections(EntityUid console, EntityUid? cloningPod, EntityUid? scanner, CloningConsoleComponent? consoleComp = null) diff --git a/Content.Server/Cloning/CloningSystem.cs b/Content.Server/Cloning/CloningSystem.cs index 76460153de..df4d3bb86d 100644 --- a/Content.Server/Cloning/CloningSystem.cs +++ b/Content.Server/Cloning/CloningSystem.cs @@ -21,6 +21,7 @@ using Content.Server.Stack; using Content.Server.Jobs; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Prototypes; +using Content.Shared.Zombies; using Content.Shared.Mobs.Systems; using Robust.Server.GameObjects; using Robust.Server.Containers; @@ -220,7 +221,11 @@ namespace Content.Server.Cloning var mob = Spawn(speciesPrototype.Prototype, Transform(clonePod.Owner).MapPosition); _humanoidSystem.CloneAppearance(bodyToClone, mob); - MetaData(mob).EntityName = MetaData(bodyToClone).EntityName; + var ev = new CloningEvent(bodyToClone, mob); + RaiseLocalEvent(bodyToClone, ref ev); + + if (!ev.NameHandled) + MetaData(mob).EntityName = MetaData(bodyToClone).EntityName; var cloneMindReturn = EntityManager.AddComponent(mob); cloneMindReturn.Mind = mind; @@ -323,4 +328,21 @@ namespace Content.Server.Cloning ClonesWaitingForMind.Clear(); } } + + /// + /// Raised after a new mob got spawned when cloning a humanoid + /// + [ByRefEvent] + public struct CloningEvent + { + public bool NameHandled = false; + + public readonly EntityUid Source; + public readonly EntityUid Target; + + public CloningEvent(EntityUid source, EntityUid target) { + Source = source; + Target = target; + } + } } diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs index c1be8c5975..e9ffc851c9 100644 --- a/Content.Server/Zombies/ZombieSystem.cs +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -1,9 +1,11 @@ using System.Linq; using Content.Server.Body.Systems; using Content.Server.Chat.Systems; +using Content.Server.Cloning; using Content.Server.Disease; using Content.Server.Disease.Components; using Content.Server.Drone.Components; +using Content.Server.Humanoid; using Content.Server.Inventory; using Content.Server.Speech; using Content.Shared.Bed.Sleep; @@ -32,6 +34,7 @@ namespace Content.Server.Zombies [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; + [Dependency] private readonly HumanoidSystem _humanoidSystem = default!; public override void Initialize() { @@ -39,6 +42,7 @@ namespace Content.Server.Zombies SubscribeLocalEvent(OnMeleeHit); SubscribeLocalEvent(OnMobState); + SubscribeLocalEvent(OnZombieCloning); SubscribeLocalEvent(OnDamage); SubscribeLocalEvent(OnSneeze); SubscribeLocalEvent(OnSleepAttempt); @@ -176,5 +180,36 @@ namespace Content.Server.Zombies DoGroan(zombiecomp.Owner, zombiecomp); } } + + /// + /// This is the function to call if you want to unzombify an entity. + /// + /// the entity having the ZombieComponent + /// the entity you want to unzombify (different from source in case of cloning, for example) + /// + /// this currently only restore the name and skin/eye color from before zombified + /// TODO: reverse everything else done in ZombifyEntity + /// + public bool UnZombify(EntityUid source, EntityUid target, ZombieComponent? zombiecomp) + { + if (!Resolve(source, ref zombiecomp)) + return false; + + foreach (var (layer, info) in zombiecomp.BeforeZombifiedCustomBaseLayers) + { + _humanoidSystem.SetBaseLayerColor(target, layer, info.Color); + _humanoidSystem.SetBaseLayerId(target, layer, info.ID); + } + _humanoidSystem.SetSkinColor(target, zombiecomp.BeforeZombifiedSkinColor); + + MetaData(target).EntityName = zombiecomp.BeforeZombifiedEntityName; + return true; + } + + private void OnZombieCloning(EntityUid uid, ZombieComponent zombiecomp, ref CloningEvent args) + { + if (UnZombify(args.Source, args.Target, zombiecomp)) + args.NameHandled = true; + } } } diff --git a/Content.Server/Zombies/ZombifyOnDeathSystem.cs b/Content.Server/Zombies/ZombifyOnDeathSystem.cs index 31fa840d9b..aad882dab5 100644 --- a/Content.Server/Zombies/ZombifyOnDeathSystem.cs +++ b/Content.Server/Zombies/ZombifyOnDeathSystem.cs @@ -127,6 +127,10 @@ namespace Content.Server.Zombies //We have specific stuff for humanoid zombies because they matter more if (TryComp(target, out var huApComp)) //huapcomp { + //store some values before changing them in case the humanoid get cloned later + zombiecomp.BeforeZombifiedSkinColor = huApComp.SkinColor; + zombiecomp.BeforeZombifiedCustomBaseLayers = new(huApComp.CustomBaseLayers); + _sharedHuApp.SetSkinColor(target, zombiecomp.SkinColor, humanoid: huApComp); _sharedHuApp.SetBaseLayerColor(target, HumanoidVisualLayers.Eyes, zombiecomp.EyeColor, humanoid: huApComp); @@ -172,6 +176,7 @@ namespace Content.Server.Zombies //gives it the funny "Zombie ___" name. var meta = MetaData(target); + zombiecomp.BeforeZombifiedEntityName = meta.EntityName; meta.EntityName = Loc.GetString("zombie-name-prefix", ("target", meta.EntityName)); _identity.QueueIdentityUpdate(target); diff --git a/Content.Shared/Zombies/ZombieComponent.cs b/Content.Shared/Zombies/ZombieComponent.cs index 368083360a..3f6a1804b3 100644 --- a/Content.Shared/Zombies/ZombieComponent.cs +++ b/Content.Shared/Zombies/ZombieComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Roles; +using Content.Shared.Humanoid; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -60,5 +61,23 @@ namespace Content.Shared.Zombies /// [DataField("zombieRoleId", customTypeSerializer: typeof(PrototypeIdSerializer))] public readonly string ZombieRoleId = "Zombie"; + + /// + /// The EntityName of the humanoid to restore in case of cloning + /// + [DataField("beforeZombifiedEntityName"), ViewVariables(VVAccess.ReadOnly)] + public string BeforeZombifiedEntityName = String.Empty; + + /// + /// The CustomBaseLayers of the humanoid to restore in case of cloning + /// + [DataField("beforeZombifiedCustomBaseLayers")] + public Dictionary BeforeZombifiedCustomBaseLayers = new (); + + /// + /// The skin color of the humanoid to restore in case of cloning + /// + [DataField("beforeZombifiedSkinColor")] + public Color BeforeZombifiedSkinColor; } }