From 63fd01f3bb2f0c49303680ca599930c5900a320d Mon Sep 17 00:00:00 2001 From: EmoGarbage404 <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 12 Jun 2022 01:53:13 -0400 Subject: [PATCH] Zombie Rework & Polymorph Expansion (#8413) Co-authored-by: Kara Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- .../Components/DiseaseBuildupComponent.cs | 19 --- .../Disease/Effects/DiseaseAddComponent.cs | 30 ++++ .../Disease/Effects/DiseaseProgression.cs | 45 ------ .../Components/DiseaseZombieComponent.cs | 37 ----- .../Disease/Zombie/DiseaseZombieSystem.cs | 130 ---------------- .../Inventory/ServerInventorySystem.cs | 31 ++++ .../Polymorph/Systems/PolymorphableSystem.cs | 82 +++++++--- .../Systems/PolymorphedEntitySystem.cs | 39 ++++- Content.Server/Speech/VocalSystem.cs | 8 +- .../StationEvents/Events/ZombieOutbreak.cs | 12 +- .../Weapon/Melee/MeleeWeaponSystem.cs | 12 +- .../Components/ZombieTransferComponent.cs | 7 - .../ZombieTransfer/ZombieTransferSystem.cs | 67 -------- Content.Server/Zombies/ZombieComponent.cs | 12 ++ Content.Server/Zombies/ZombieSystem.cs | 62 ++++++++ .../Zombies/ZombifyOnDeathComponent.cs | 15 ++ .../Zombies/ZombifyOnDeathSystem.cs | 147 ++++++++++++++++++ .../Polymorph/PolymorphPrototype.cs | 32 +++- .../en-US/{disease => zombies}/zombie.ftl | 0 .../Prototypes/Diseases/noninfectious.yml | 25 --- Resources/Prototypes/Diseases/zombie.yml | 26 ++++ .../Prototypes/Entities/Mobs/NPCs/animals.yml | 1 - .../Specific/Medical/healthanalyzer.yml | 4 +- .../Objects/Weapons/Melee/zombieclaw.yml | 22 --- Resources/Prototypes/Polymorphs/polymorph.yml | 18 ++- Resources/Prototypes/Reagents/toxins.yml | 2 +- .../Weapons/Melee/zombie_claw.rsi/icon.png | Bin 6932 -> 0 bytes .../Melee/zombie_claw.rsi/inhand-left.png | Bin 5868 -> 0 bytes .../Melee/zombie_claw.rsi/inhand-right.png | Bin 5553 -> 0 bytes .../Weapons/Melee/zombie_claw.rsi/meta.json | 22 --- 30 files changed, 485 insertions(+), 422 deletions(-) delete mode 100644 Content.Server/Disease/Components/DiseaseBuildupComponent.cs create mode 100644 Content.Server/Disease/Effects/DiseaseAddComponent.cs delete mode 100644 Content.Server/Disease/Effects/DiseaseProgression.cs delete mode 100644 Content.Server/Disease/Zombie/Components/DiseaseZombieComponent.cs delete mode 100644 Content.Server/Disease/Zombie/DiseaseZombieSystem.cs delete mode 100644 Content.Server/Weapon/Melee/ZombieTransfer/Components/ZombieTransferComponent.cs delete mode 100644 Content.Server/Weapon/Melee/ZombieTransfer/ZombieTransferSystem.cs create mode 100644 Content.Server/Zombies/ZombieComponent.cs create mode 100644 Content.Server/Zombies/ZombieSystem.cs create mode 100644 Content.Server/Zombies/ZombifyOnDeathComponent.cs create mode 100644 Content.Server/Zombies/ZombifyOnDeathSystem.cs rename Resources/Locale/en-US/{disease => zombies}/zombie.ftl (100%) create mode 100644 Resources/Prototypes/Diseases/zombie.yml delete mode 100644 Resources/Prototypes/Entities/Objects/Weapons/Melee/zombieclaw.yml delete mode 100644 Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/icon.png delete mode 100644 Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/inhand-left.png delete mode 100644 Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/inhand-right.png delete mode 100644 Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/meta.json diff --git a/Content.Server/Disease/Components/DiseaseBuildupComponent.cs b/Content.Server/Disease/Components/DiseaseBuildupComponent.cs deleted file mode 100644 index 8c562b0662..0000000000 --- a/Content.Server/Disease/Components/DiseaseBuildupComponent.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Content.Server.Disease.Components -{ - /// - /// The component which records the buildup/progression of an infection - /// - [RegisterComponent] - public sealed class DiseaseBuildupComponent : Component - { - /// This could be served to be generalized to allow for multiple - /// diseases to build up at once, but it doesn't matter too much. - - /// - /// The current amount of progression that has built up. - /// - [DataField("progression")] - [ViewVariables(VVAccess.ReadWrite)] - public float Progression = 0.00f; - } -} diff --git a/Content.Server/Disease/Effects/DiseaseAddComponent.cs b/Content.Server/Disease/Effects/DiseaseAddComponent.cs new file mode 100644 index 0000000000..7e38480592 --- /dev/null +++ b/Content.Server/Disease/Effects/DiseaseAddComponent.cs @@ -0,0 +1,30 @@ +using JetBrains.Annotations; +using Content.Shared.Disease; + +namespace Content.Server.Disease.Effects +{ + /// + /// Adds a component to the diseased entity + /// + [UsedImplicitly] + public sealed class DiseaseAddComponent : DiseaseEffect + { + /// + /// The component that is added at the end of build up + /// + [DataField("comp")] + public string? Comp = null; + + public override void Effect(DiseaseEffectArgs args) + { + if (Comp == null) + return; + + EntityUid uid = args.DiseasedEntity; + var newComponent = (Component) IoCManager.Resolve().GetComponent(Comp); + newComponent.Owner = uid; + if (!args.EntityManager.HasComponent(uid, newComponent.GetType())) + args.EntityManager.AddComponent(uid, newComponent); + } + } +} diff --git a/Content.Server/Disease/Effects/DiseaseProgression.cs b/Content.Server/Disease/Effects/DiseaseProgression.cs deleted file mode 100644 index db2dcedaca..0000000000 --- a/Content.Server/Disease/Effects/DiseaseProgression.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Content.Server.Disease.Components; -using JetBrains.Annotations; -using Content.Shared.Disease; - -namespace Content.Server.Disease.Effects -{ - /// - /// Handles a disease which incubates over a period of time - /// before adding another component to the infected entity - /// currently used for zombie virus - /// - [UsedImplicitly] - public sealed class DiseaseProgression : DiseaseEffect - { - /// - /// The rate that's increased over time. Defaults to 1% so the probability can be varied in yaml - /// - [DataField("rate")] - [ViewVariables(VVAccess.ReadWrite)] - public float Rate = 0.01f; - - /// - /// The component that is added at the end of build up - /// - [DataField("comp")] - public string? Comp = null; - - public override void Effect(DiseaseEffectArgs args) - { - args.EntityManager.EnsureComponent(args.DiseasedEntity, out var buildup); - if (buildup.Progression < 1) //increases steadily until 100% - { - buildup.Progression += Rate; - } - else if (Comp != null)//adds the component for the later stage of the disease. - { - EntityUid uid = args.DiseasedEntity; - var newComponent = (Component) IoCManager.Resolve().GetComponent(Comp); - newComponent.Owner = uid; - if (!args.EntityManager.HasComponent(uid, newComponent.GetType())) - args.EntityManager.AddComponent(uid, newComponent); - } - } - } -} diff --git a/Content.Server/Disease/Zombie/Components/DiseaseZombieComponent.cs b/Content.Server/Disease/Zombie/Components/DiseaseZombieComponent.cs deleted file mode 100644 index 14cfcf7970..0000000000 --- a/Content.Server/Disease/Zombie/Components/DiseaseZombieComponent.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Content.Server.Disease.Zombie.Components -{ - /// - /// The component which gives an entity zombie traits. - /// - [RegisterComponent] - public sealed class DiseaseZombieComponent : Component - { - /// - /// The probability that a given bite will infect a player. - /// zombie infection is not based on disease resist items like masks or gloves. - /// - [DataField("probability")] - [ViewVariables(VVAccess.ReadWrite)] - public float Probability = 0.33f; - - /// - /// A multiplier on the movement speed that zombies recieve. - /// - [DataField("slowAmount")] - [ViewVariables(VVAccess.ReadWrite)] - public float SlowAmount = 0.75f; - - /// - /// Whether or not the zombie needs all the zombie traits initialized upon component init - /// useful for entities that already are zombies and do not need the additional traits. - /// - [DataField("applyZombieTraits")] - public bool ApplyZombieTraits = true; - - /// - /// The color of the zombie's skin - /// - [DataField("skinColor")] - public readonly Color SkinColor = (0.70f, 0.72f, 0.48f, 1); - } -} diff --git a/Content.Server/Disease/Zombie/DiseaseZombieSystem.cs b/Content.Server/Disease/Zombie/DiseaseZombieSystem.cs deleted file mode 100644 index 08e36317f3..0000000000 --- a/Content.Server/Disease/Zombie/DiseaseZombieSystem.cs +++ /dev/null @@ -1,130 +0,0 @@ -using Robust.Shared.Player; -using Content.Server.Speech.Components; -using Content.Server.Ghost.Roles.Components; -using Content.Server.Disease.Components; -using Content.Server.Disease.Zombie.Components; -using Content.Server.Body.Components; -using Content.Server.Body.Systems; -using Content.Server.Popups; -using Content.Server.Atmos.Components; -using Content.Server.Hands.Components; -using Content.Server.Nutrition.Components; -using Content.Server.Mind.Components; -using Content.Server.Chat.Managers; -using Content.Server.Inventory; -using Content.Shared.Damage; -using Content.Shared.MobState.Components; -using Content.Shared.Hands.EntitySystems; -using Content.Shared.Movement.EntitySystems; -using Content.Shared.CharacterAppearance.Components; -using Content.Shared.CharacterAppearance.Systems; -using Content.Server.Weapons.Melee.ZombieTransfer.Components; - -namespace Content.Server.Disease.Zombie -{ - /// - /// Handles zombie propagation and inherent zombie traits - /// - public sealed class DiseaseZombieSystem : EntitySystem - { - [Dependency] private readonly DamageableSystem _damageable = default!; - [Dependency] private readonly ServerInventorySystem _serverInventory = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly BloodstreamSystem _bloodstream = default!; - [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; - [Dependency] private readonly SharedHandsSystem _sharedHands = default!; - [Dependency] private readonly SharedHumanoidAppearanceSystem _sharedHumanoidAppearance = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnRefreshMovementSpeedModifiers); - } - - /// - /// I would imagine that if this component got assigned to something other than a mob, it would throw hella errors. - /// - private void OnComponentInit(EntityUid uid, DiseaseZombieComponent component, ComponentInit args) - { - if (!component.ApplyZombieTraits || !HasComp(uid)) - return; - - RemComp(uid); - RemComp(uid); - RemComp(uid); - RemComp(uid); - RemComp(uid); - RemComp(uid); - - EntityManager.EnsureComponent(uid, out var bloodstream); //zoms need bloodstream anyway for healing - _bloodstream.SetBloodLossThreshold(uid, 0f, bloodstream); - _bloodstream.TryModifyBleedAmount(uid, -bloodstream.BleedAmount, bloodstream); - _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); - - EntityManager.EnsureComponent(uid).Accent = "zombie"; - - if (TryComp(uid, out var comp)) - { - _damageable.SetDamageModifierSetId(uid, "Zombie", comp); - _damageable.SetAllDamage(comp, 0); - } - - if (TryComp(uid, out var spritecomp)) - { - var oldapp = spritecomp.Appearance; - var newapp = oldapp.WithSkinColor(component.SkinColor); - _sharedHumanoidAppearance.UpdateAppearance(uid, newapp); - - _sharedHumanoidAppearance.ForceAppearanceUpdate(uid); - } - - if (TryComp(uid, out var handcomp)) - { - foreach (var hand in handcomp.Hands) - { - _sharedHands.TrySetActiveHand(uid, hand.Key); - _sharedHands.TryDrop(uid); - - var pos = EntityManager.GetComponent(uid).Coordinates; - var claw = EntityManager.SpawnEntity("ZombieClaw", pos); - _sharedHands.DoPickup(uid, hand.Value, claw); - } - } - else - { - EnsureComp(uid); - } - - if (TryComp(uid, out var servInvComp)) - _serverInventory.TryUnequip(uid, "gloves", true, true, predicted: false, servInvComp); - - _popupSystem.PopupEntity(Loc.GetString("zombie-transform", ("target", uid)), uid, Filter.Pvs(uid)); - - if (TryComp(uid, out var metacomp)) - metacomp.EntityName = Loc.GetString("zombie-name-prefix", ("target", metacomp.EntityName)); - - var mindcomp = EnsureComp(uid); - - if (mindcomp.Mind != null && mindcomp.Mind.TryGetSession(out var session)) - { - var chatMgr = IoCManager.Resolve(); - chatMgr.DispatchServerMessage(session, Loc.GetString("zombie-infection-greeting")); - } - - if (!HasComp(uid) && !mindcomp.HasMind) //this specific component gives build test trouble so pop off, ig - { - EntityManager.EnsureComponent(uid, out var ghostcomp); - ghostcomp.RoleName = Loc.GetString("zombie-generic"); - ghostcomp.RoleDescription = Loc.GetString("zombie-role-desc"); - ghostcomp.RoleRules = Loc.GetString("zombie-role-rules"); - } - } - - private void OnRefreshMovementSpeedModifiers(EntityUid uid, DiseaseZombieComponent component, RefreshMovementSpeedModifiersEvent args) - { - args.ModifySpeed(component.SlowAmount, component.SlowAmount); - } - } -} diff --git a/Content.Server/Inventory/ServerInventorySystem.cs b/Content.Server/Inventory/ServerInventorySystem.cs index 03fba80533..97ecdfd2c7 100644 --- a/Content.Server/Inventory/ServerInventorySystem.cs +++ b/Content.Server/Inventory/ServerInventorySystem.cs @@ -5,6 +5,7 @@ using Content.Server.Temperature.Systems; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; +using Robust.Shared.Containers; using InventoryComponent = Content.Shared.Inventory.InventoryComponent; namespace Content.Server.Inventory @@ -42,5 +43,35 @@ namespace Content.Server.Inventory _storageSystem.OpenStorageUI(entityUid.Value, uid, storageComponent); } } + + public void TransferEntityInventories(EntityUid uid, EntityUid target) + { + if (TryGetContainerSlotEnumerator(uid, out var enumerator)) + { + Dictionary inventoryEntities = new(); + var slots = GetSlots(uid); + while (enumerator.MoveNext(out var containerSlot)) + { + //records all the entities stored in each of the target's slots + foreach (var slot in slots) + { + if (TryGetSlotContainer(target, slot.Name, out var conslot, out var _) && + conslot.ID == containerSlot.ID) + { + inventoryEntities.Add(slot.Name, containerSlot.ContainedEntity); + } + } + //drops everything in the target's inventory on the ground + containerSlot.EmptyContainer(); + } + /// This takes the objects we removed and stored earlier + /// and actually equips all of it to the new entity + foreach (var item in inventoryEntities) + { + if (item.Value != null) + TryEquip(target, item.Value.Value, item.Key, true); + } + } + } } } diff --git a/Content.Server/Polymorph/Systems/PolymorphableSystem.cs b/Content.Server/Polymorph/Systems/PolymorphableSystem.cs index 3b16dcbecc..a2d2771dc7 100644 --- a/Content.Server/Polymorph/Systems/PolymorphableSystem.cs +++ b/Content.Server/Polymorph/Systems/PolymorphableSystem.cs @@ -4,15 +4,16 @@ using Content.Server.Inventory; using Content.Server.Mind.Commands; using Content.Server.Mind.Components; using Content.Server.Polymorph.Components; -using Content.Server.Popups; using Content.Shared.Actions; using Content.Shared.Actions.ActionTypes; +using Content.Shared.CharacterAppearance.Components; +using Content.Shared.CharacterAppearance.Systems; using Content.Shared.Damage; using Content.Shared.Hands.EntitySystems; using Content.Shared.Polymorph; +using Robust.Server.Containers; using Robust.Shared.Containers; using Robust.Shared.Map; -using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -27,8 +28,9 @@ namespace Content.Server.Polymorph.Systems [Dependency] private readonly ServerInventorySystem _inventory = default!; [Dependency] private readonly SharedHandsSystem _sharedHands = default!; [Dependency] private readonly DamageableSystem _damageable = default!; - [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly SharedHumanoidAppearanceSystem _sharedHuApp = default!; + [Dependency] private readonly ContainerSystem _container = default!; public override void Initialize() { @@ -61,15 +63,15 @@ namespace Content.Server.Polymorph.Systems /// /// The entity that will be transformed /// The id of the polymorph prototype - public void PolymorphEntity(EntityUid target, String id) + public EntityUid? PolymorphEntity(EntityUid target, String id) { if (!_proto.TryIndex(id, out var proto)) { _saw.Error("Invalid polymorph prototype"); - return; + return null; } - PolymorphEntity(target, proto); + return PolymorphEntity(target, proto); } /// @@ -77,8 +79,12 @@ namespace Content.Server.Polymorph.Systems /// /// The entity that will be transformed /// The polymorph prototype - public void PolymorphEntity(EntityUid target, PolymorphPrototype proto) + public EntityUid? PolymorphEntity(EntityUid target, PolymorphPrototype proto) { + /// This is the big papa function. This handles the transformation, moving the old entity + /// logic and conditions specified in the prototype, and everything else that may be needed. + /// I am clinically insane - emo + // mostly just for vehicles if (TryComp(target, out var buckle)) buckle.TryUnbuckle(target, true); @@ -93,42 +99,72 @@ namespace Content.Server.Polymorph.Systems comp.Prototype = proto; RaiseLocalEvent(child, new PolymorphComponentSetupEvent()); + var targetXform = Transform(target); + var childXform = Transform(child); + childXform.LocalRotation = targetXform.LocalRotation; + + if (_container.TryGetContainingContainer(target, out var cont)) + cont.Insert(child); + //Transfers all damage from the original to the new one - if (TryComp(child, out var damageParent) && + if (proto.TransferDamage && + TryComp(child, out var damageParent) && _damageable.GetScaledDamage(target, child, out var damage) && damage != null) { _damageable.SetDamage(damageParent, damage); } - if (proto.DropInventory) + if (proto.Inventory == PolymorphInventoryChange.Transfer) { - //drops everything in the user's inventory - if (_inventory.TryGetContainerSlotEnumerator(target, out var enumerator)) - { - while (enumerator.MoveNext(out var containerSlot)) - { - containerSlot.EmptyContainer(); - } - } - //drops everything in the user's hands + _inventory.TransferEntityInventories(target, child); foreach (var hand in _sharedHands.EnumerateHeld(target)) { hand.TryRemoveFromContainer(); + _sharedHands.TryPickupAnyHand(child, hand); } } + else if (proto.Inventory == PolymorphInventoryChange.Drop) + { + if(_inventory.TryGetContainerSlotEnumerator(target, out var enumerator)) + while (enumerator.MoveNext(out var slot)) + slot.EmptyContainer(); + + foreach (var hand in _sharedHands.EnumerateHeld(target)) + hand.TryRemoveFromContainer(); + } + + if (proto.TransferName && + TryComp(target, out var targetMeta) && + TryComp(child, out var childMeta)) + { + childMeta.EntityName = targetMeta.EntityName; + } + + if (proto.TransferHumanoidAppearance && + TryComp(target, out var targetHuApp) && + TryComp(child, out var childHuApp)) + { + _sharedHuApp.UpdateAppearance(child, targetHuApp.Appearance); + _sharedHuApp.ForceAppearanceUpdate(child); + } if (TryComp(target, out var mind) && mind.Mind != null) - mind.Mind.TransferTo(child); + mind.Mind.TransferTo(child); //Ensures a map to banish the entity to EnsurePausesdMap(); - if(PausedMap != null) + if (PausedMap != null) targetTransformComp.AttachParent(Transform(PausedMap.Value)); - - _popup.PopupEntity(Loc.GetString("polymorph-popup-generic", ("parent", target), ("child", child)), child, Filter.Pvs(child)); + + return child; } + /// + /// Creates a sidebar action for an entity to be able to polymorph at will + /// + /// The string of the id of the polymorph action + /// The entity that will be gaining the action public void CreatePolymorphAction(string id, EntityUid target) { if (!_proto.TryIndex(id, out var polyproto)) @@ -136,7 +172,7 @@ namespace Content.Server.Polymorph.Systems _saw.Error("Invalid polymorph prototype"); return; } - + if (!TryComp(target, out var polycomp)) return; diff --git a/Content.Server/Polymorph/Systems/PolymorphedEntitySystem.cs b/Content.Server/Polymorph/Systems/PolymorphedEntitySystem.cs index 94ada93c6a..b14354acef 100644 --- a/Content.Server/Polymorph/Systems/PolymorphedEntitySystem.cs +++ b/Content.Server/Polymorph/Systems/PolymorphedEntitySystem.cs @@ -1,11 +1,16 @@ using Content.Server.Actions; +using Content.Server.Inventory; using Content.Server.Mind.Components; using Content.Server.Polymorph.Components; using Content.Server.Popups; using Content.Shared.Actions; using Content.Shared.Actions.ActionTypes; using Content.Shared.Damage; +using Content.Shared.Hands.EntitySystems; using Content.Shared.MobState.Components; +using Content.Shared.Polymorph; +using Robust.Server.Containers; +using Robust.Shared.Containers; using Robust.Shared.Player; namespace Content.Server.Polymorph.Systems @@ -15,6 +20,9 @@ namespace Content.Server.Polymorph.Systems [Dependency] private readonly ActionsSystem _actions = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly ServerInventorySystem _inventory = default!; + [Dependency] private readonly SharedHandsSystem _sharedHands = default!; + [Dependency] private readonly ContainerSystem _container = default!; public override void Initialize() { @@ -35,22 +43,51 @@ namespace Content.Server.Polymorph.Systems /// The entityuid of the entity being reverted public void Revert(EntityUid uid) { + if (Deleted(uid)) + return; + if (!TryComp(uid, out var component)) return; + var proto = component.Prototype; + var uidXform = Transform(uid); var parentXform = Transform(component.Parent); parentXform.AttachParent(uidXform.ParentUid); parentXform.Coordinates = uidXform.Coordinates; + parentXform.LocalRotation = uidXform.LocalRotation; - if (TryComp(component.Parent, out var damageParent) && + if (_container.TryGetContainingContainer(uid, out var cont)) + cont.Insert(component.Parent); + + if (component.Prototype.TransferDamage && + TryComp(component.Parent, out var damageParent) && _damageable.GetScaledDamage(uid, component.Parent, out var damage) && damage != null) { _damageable.SetDamage(damageParent, damage); } + if (proto.Inventory == PolymorphInventoryChange.Transfer) + { + _inventory.TransferEntityInventories(uid, component.Parent); + foreach (var hand in _sharedHands.EnumerateHeld(component.Parent)) + { + hand.TryRemoveFromContainer(); + _sharedHands.TryPickupAnyHand(component.Parent, hand); + } + } + else if (proto.Inventory == PolymorphInventoryChange.Drop) + { + if (_inventory.TryGetContainerSlotEnumerator(uid, out var enumerator)) + while (enumerator.MoveNext(out var slot)) + slot.EmptyContainer(); + + foreach (var hand in _sharedHands.EnumerateHeld(uid)) + hand.TryRemoveFromContainer(); + } + if (TryComp(uid, out var mind) && mind.Mind != null) { mind.Mind.TransferTo(component.Parent); diff --git a/Content.Server/Speech/VocalSystem.cs b/Content.Server/Speech/VocalSystem.cs index c54f441705..e78c799353 100644 --- a/Content.Server/Speech/VocalSystem.cs +++ b/Content.Server/Speech/VocalSystem.cs @@ -67,9 +67,9 @@ public sealed class VocalSystem : EntitySystem if (!_blocker.CanSpeak(uid)) return false; - // Currently this requires humanoid appearance & doesn't have any sort of fall-back or gender-neutral scream. - if (!TryComp(uid, out HumanoidAppearanceComponent? humanoid)) - return false; + var sex = Sex.Male; //the default is male because requiring humanoid appearance for this is dogshit + if (TryComp(uid, out HumanoidAppearanceComponent? humanoid)) + sex = humanoid.Sex; if (_random.Prob(component.WilhelmProbability)) { @@ -80,7 +80,7 @@ public sealed class VocalSystem : EntitySystem var scale = (float) _random.NextGaussian(1, VocalComponent.Variation); var pitchedParams = component.AudioParams.WithPitchScale(scale); - switch (humanoid.Sex) + switch (sex) { case Sex.Male: SoundSystem.Play(Filter.Pvs(uid), component.MaleScream.GetSound(), uid, pitchedParams); diff --git a/Content.Server/StationEvents/Events/ZombieOutbreak.cs b/Content.Server/StationEvents/Events/ZombieOutbreak.cs index 4eb4b43f53..891171833b 100644 --- a/Content.Server/StationEvents/Events/ZombieOutbreak.cs +++ b/Content.Server/StationEvents/Events/ZombieOutbreak.cs @@ -1,9 +1,10 @@ using Content.Server.Chat; using Robust.Shared.Random; -using Content.Server.Disease.Zombie.Components; +using Content.Server.Chat.Managers; using Content.Server.Station.Systems; using Content.Shared.MobState.Components; using Content.Shared.Sound; +using Content.Server.Zombies; namespace Content.Server.StationEvents.Events { @@ -41,17 +42,20 @@ namespace Content.Server.StationEvents.Events _random.Shuffle(deadList); var toInfect = _random.Next(1, 3); - + + var zombifysys = _entityManager.EntitySysManager.GetEntitySystem(); + // Now we give it to people in the list of dead entities earlier. var entSysMgr = IoCManager.Resolve(); var stationSystem = entSysMgr.GetEntitySystem(); var chatSystem = entSysMgr.GetEntitySystem(); + foreach (var target in deadList) { if (toInfect-- == 0) break; - - _entityManager.EnsureComponent(target.Owner); + + zombifysys.ZombifyEntity(target.Owner); var station = stationSystem.GetOwningStation(target.Owner); if(station == null) continue; diff --git a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs index adc06f82b5..e6ec023ba8 100644 --- a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs @@ -84,7 +84,7 @@ namespace Content.Server.Weapon.Melee if (args.Target is {Valid: true} target) { // Raise event before doing damage so we can cancel damage if the event is handled - var hitEvent = new MeleeHitEvent(new List() { target }, args.User); + var hitEvent = new MeleeHitEvent(new List() { target }, args.User, comp.Damage); RaiseLocalEvent(owner, hitEvent, false); if (!hitEvent.Handled) @@ -152,7 +152,7 @@ namespace Content.Server.Weapon.Melee } // Raise event before doing damage so we can cancel damage if handled - var hitEvent = new MeleeHitEvent(hitEntities, args.User); + var hitEvent = new MeleeHitEvent(hitEntities, args.User, comp.Damage); RaiseLocalEvent(owner, hitEvent, false); SendAnimation(comp.Arc, angle, args.User, owner, hitEntities); @@ -352,6 +352,11 @@ namespace Content.Server.Weapon.Melee /// public sealed class MeleeHitEvent : HandledEntityEventArgs { + /// + /// The base amount of damage dealt by the melee hit. + /// + public readonly DamageSpecifier BaseDamage = new(); + /// /// Modifier sets to apply to the hit event when it's all said and done. /// This should be modified by adding a new entry to the list. @@ -382,10 +387,11 @@ namespace Content.Server.Weapon.Melee /// public EntityUid User { get; } - public MeleeHitEvent(List hitEntities, EntityUid user) + public MeleeHitEvent(List hitEntities, EntityUid user, DamageSpecifier baseDamage) { HitEntities = hitEntities; User = user; + BaseDamage = baseDamage; } } } diff --git a/Content.Server/Weapon/Melee/ZombieTransfer/Components/ZombieTransferComponent.cs b/Content.Server/Weapon/Melee/ZombieTransfer/Components/ZombieTransferComponent.cs deleted file mode 100644 index f0e95efb04..0000000000 --- a/Content.Server/Weapon/Melee/ZombieTransfer/Components/ZombieTransferComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Server.Weapons.Melee.ZombieTransfer.Components -{ - [RegisterComponent] - public sealed class ZombieTransferComponent : Component - { - } -} diff --git a/Content.Server/Weapon/Melee/ZombieTransfer/ZombieTransferSystem.cs b/Content.Server/Weapon/Melee/ZombieTransfer/ZombieTransferSystem.cs deleted file mode 100644 index e3069860f2..0000000000 --- a/Content.Server/Weapon/Melee/ZombieTransfer/ZombieTransferSystem.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Linq; -using Robust.Shared.Random; -using Content.Server.Body.Systems; -using Content.Server.Disease.Components; -using Content.Server.Disease.Zombie.Components; -using Content.Server.Drone.Components; -using Content.Server.Weapon.Melee; -using Content.Shared.Chemistry.Components; -using Content.Shared.Damage; -using Content.Shared.MobState.Components; -using Content.Server.Disease; -using Content.Server.Weapons.Melee.ZombieTransfer.Components; - -namespace Content.Server.Weapons.Melee.ZombieTransfer -{ - public sealed class ZombieTransferSystem : EntitySystem - { - [Dependency] private readonly DiseaseSystem _disease = default!; - [Dependency] private readonly BloodstreamSystem _bloodstream = default!; - [Dependency] private readonly IRobustRandom _robustRandom = default!; - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnMeleeHit); - } - - private void OnMeleeHit(EntityUid uid, ZombieTransferComponent component, MeleeHitEvent args) - { - if (!EntityManager.TryGetComponent(args.User, out var diseaseZombieComp)) - return; - - if (!args.HitEntities.Any()) - return; - - foreach (EntityUid entity in args.HitEntities) - { - if (args.User == entity) - continue; - - if (!HasComp(entity) || HasComp(entity)) - continue; - - if (_robustRandom.Prob(diseaseZombieComp.Probability) && HasComp(entity)) - { - _disease.TryAddDisease(entity, "ZombieInfection"); - } - - EntityManager.EnsureComponent(entity, out var mobState); - if ((mobState.IsDead() || mobState.IsCritical()) && !HasComp(entity)) //dead entities are eautomatically infected. MAYBE: have activated infect ability? - { - EntityManager.AddComponent(entity); - var dspec = new DamageSpecifier(); - //these damages match the zombie claw - dspec.DamageDict.TryAdd("Slash", -12); - dspec.DamageDict.TryAdd("Piercing", -7); - args.BonusDamage += dspec; - } - else if (mobState.IsAlive()) //heals when zombies bite live entities - { - var healingSolution = new Solution(); - healingSolution.AddReagent("Bicaridine", 1.00); //if OP, reduce/change chem - _bloodstream.TryAddToChemicals(args.User, healingSolution); - } - } - } - } -} diff --git a/Content.Server/Zombies/ZombieComponent.cs b/Content.Server/Zombies/ZombieComponent.cs new file mode 100644 index 0000000000..57f59c5b5f --- /dev/null +++ b/Content.Server/Zombies/ZombieComponent.cs @@ -0,0 +1,12 @@ +namespace Content.Server.Zombies +{ + [RegisterComponent] + public sealed class ZombieComponent : Component + { + /// + /// The coefficient of the damage reduction applied when a zombie + /// attacks another zombie. longe name + /// + public float OtherZombieDamageCoefficient = 0.75f; + } +} diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs new file mode 100644 index 0000000000..818e3941b4 --- /dev/null +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -0,0 +1,62 @@ +using System.Linq; +using Robust.Shared.Random; +using Content.Server.Body.Systems; +using Content.Server.Disease.Components; +using Content.Server.Drone.Components; +using Content.Server.Weapon.Melee; +using Content.Shared.Chemistry.Components; +using Content.Shared.MobState.Components; +using Content.Server.Disease; + +namespace Content.Server.Zombies +{ + public sealed class ZombieSystem : EntitySystem + { + [Dependency] private readonly DiseaseSystem _disease = default!; + [Dependency] private readonly BloodstreamSystem _bloodstream = default!; + [Dependency] private readonly ZombifyOnDeathSystem _zombify = default!; + [Dependency] private readonly IRobustRandom _robustRandom = default!; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMeleeHit); + } + + private void OnMeleeHit(EntityUid uid, ZombieComponent component, MeleeHitEvent args) + { + if (!EntityManager.TryGetComponent(args.User, out var zombieComp)) + return; + + if (!args.HitEntities.Any()) + return; + + foreach (EntityUid entity in args.HitEntities) + { + if (args.User == entity) + continue; + + if (!TryComp(entity, out var mobState) || HasComp(entity)) + continue; + + if (_robustRandom.Prob(0.5f) && HasComp(entity)) + _disease.TryAddDisease(entity, "ActiveZombieVirus"); + + if (HasComp(entity)) + args.BonusDamage = args.BaseDamage * zombieComp.OtherZombieDamageCoefficient; + + if ((mobState.IsDead() || mobState.IsCritical()) + && !HasComp(entity)) + { + _zombify.ZombifyEntity(entity); + args.BonusDamage = -args.BaseDamage; + } + else if (mobState.IsAlive()) //heals when zombies bite live entities + { + var healingSolution = new Solution(); + healingSolution.AddReagent("Bicaridine", 1.00); //if OP, reduce/change chem + _bloodstream.TryAddToChemicals(args.User, healingSolution); + } + } + } + } +} diff --git a/Content.Server/Zombies/ZombifyOnDeathComponent.cs b/Content.Server/Zombies/ZombifyOnDeathComponent.cs new file mode 100644 index 0000000000..c43ad57f51 --- /dev/null +++ b/Content.Server/Zombies/ZombifyOnDeathComponent.cs @@ -0,0 +1,15 @@ +using Content.Shared.Weapons.Melee; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Zombies +{ + [RegisterComponent] + public sealed class ZombifyOnDeathComponent : Component + { + [DataField("skinColor")] + public Color SkinColor = new Color(0.70f, 0.72f, 0.48f, 1); + + [DataField("attackArc", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string AttackArc = "claw"; + } +} diff --git a/Content.Server/Zombies/ZombifyOnDeathSystem.cs b/Content.Server/Zombies/ZombifyOnDeathSystem.cs new file mode 100644 index 0000000000..580bfb9ced --- /dev/null +++ b/Content.Server/Zombies/ZombifyOnDeathSystem.cs @@ -0,0 +1,147 @@ +using Content.Shared.Damage; +using Content.Shared.MobState.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.CharacterAppearance.Components; +using Content.Shared.CharacterAppearance.Systems; +using Content.Server.Disease.Components; +using Content.Server.Body.Components; +using Content.Server.Atmos.Components; +using Content.Server.Nutrition.Components; +using Robust.Shared.Player; +using Content.Server.Popups; +using Content.Server.Speech.Components; +using Content.Server.Body.Systems; +using Content.Server.CombatMode; +using Content.Server.Inventory; +using Content.Server.Mind.Components; +using Content.Server.Chat.Managers; +using Content.Server.Ghost.Roles.Components; +using Content.Server.Hands.Components; +using Content.Server.Mind.Commands; +using Content.Server.Temperature.Components; +using Content.Server.Weapon.Melee.Components; +using Content.Server.Disease; +using Robust.Shared.Containers; +using Content.Shared.Movement.Components; +using Content.Shared.MobState; + +namespace Content.Server.Zombies +{ + /// + /// Handles zombie propagation and inherent zombie traits + /// + public sealed class ZombifyOnDeathSystem : EntitySystem + { + [Dependency] private readonly SharedHandsSystem _sharedHands = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly BloodstreamSystem _bloodstream = default!; + [Dependency] private readonly ServerInventorySystem _serverInventory = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly DiseaseSystem _disease = default!; + [Dependency] private readonly SharedHumanoidAppearanceSystem _sharedHuApp = default!; + [Dependency] private readonly IChatManager _chatMan = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDamageChanged); + } + + /// + /// Handles an entity turning into a zombie when they die or go into crit + /// + private void OnDamageChanged(EntityUid uid, ZombifyOnDeathComponent component, MobStateChangedEvent args) + { + if (!TryComp(uid, out var mobstate)) + return; + + if (mobstate.IsDead() || + mobstate.IsCritical()) + { + ZombifyEntity(uid); + } + } + + /// + /// This is the general purpose function to call if you want to zombify an entity. + /// It handles both humanoid and nonhumanoid transformation. + /// + /// the entity being zombified + public void ZombifyEntity(EntityUid target) + { + if (HasComp(target)) + return; + + _disease.CureAllDiseases(target); + RemComp(target); + RemComp(target); + RemComp(target); + RemComp(target); + RemComp(target); + + var zombiecomp = EnsureComp(target); + if (TryComp(target, out var huApComp)) + { + var appearance = huApComp.Appearance; + _sharedHuApp.UpdateAppearance(target, appearance.WithSkinColor(zombiecomp.SkinColor), huApComp); + _sharedHuApp.ForceAppearanceUpdate(target, huApComp); + } + + if (!HasComp(target)) + MakeSentientCommand.MakeSentient(target, EntityManager); + + EnsureComp(target).Accent = "zombie"; + + //funny add delet go brrr + RemComp(target); + AddComp(target); + + var melee = EnsureComp(target); + melee.Arc = zombiecomp.AttackArc; + melee.ClickArc = zombiecomp.AttackArc; + //lord forgive me for the hardcoded damage + DamageSpecifier dspec = new(); + dspec.DamageDict.Add("Slash", 13); + dspec.DamageDict.Add("Piercing", 7); + melee.Damage = dspec; + + _damageable.SetDamageModifierSetId(target, "Zombie"); + _bloodstream.SetBloodLossThreshold(target, 0f); + + _popupSystem.PopupEntity(Loc.GetString("zombie-transform", ("target", target)), target, Filter.Pvs(target)); + _serverInventory.TryUnequip(target, "gloves", true, true); + + if (TryComp(target, out var tempComp)) + tempComp.ColdDamage.ClampMax(0); + + if (TryComp(target, out var damageablecomp)) + _damageable.SetAllDamage(damageablecomp, 0); + + if (TryComp(target, out var meta)) + meta.EntityName = Loc.GetString("zombie-name-prefix", ("target", meta.EntityName)); + + var mindcomp = EnsureComp(target); + if (mindcomp.Mind != null && mindcomp.Mind.TryGetSession(out var session)) + _chatMan.DispatchServerMessage(session, Loc.GetString("zombie-infection-greeting")); + + if (!HasComp(target) && !mindcomp.HasMind) //this specific component gives build test trouble so pop off, ig + { + EntityManager.EnsureComponent(target, out var ghostcomp); + ghostcomp.RoleName = Loc.GetString("zombie-generic"); + ghostcomp.RoleDescription = Loc.GetString("zombie-role-desc"); + ghostcomp.RoleRules = Loc.GetString("zombie-role-rules"); + } + + foreach (var hand in _sharedHands.EnumerateHands(target)) + { + _sharedHands.SetActiveHand(target, hand); + hand.Container?.EmptyContainer(); + _sharedHands.RemoveHand(target, hand.Name); + } + RemComp(target); + + EnsureComp(target); + } + } +} diff --git a/Content.Shared/Polymorph/PolymorphPrototype.cs b/Content.Shared/Polymorph/PolymorphPrototype.cs index 31cdf22933..53891eb8ea 100644 --- a/Content.Shared/Polymorph/PolymorphPrototype.cs +++ b/Content.Shared/Polymorph/PolymorphPrototype.cs @@ -53,11 +53,28 @@ namespace Content.Shared.Polymorph public bool Forced = false; /// - /// Whether or not the target will drop their inventory - /// when they are polymorphed (includes items in hands) + /// Whether or not the entity transfers its damage between forms. /// - [DataField("dropInventory", serverOnly: true)] - public bool DropInventory = false; + [DataField("transferDamage", serverOnly: true)] + public bool TransferDamage = true; + + /// + /// Whether or not the entity transfers its name between forms. + /// + [DataField("transferName", serverOnly: true)] + public bool TransferName = false; + + /// + /// Whether or not the entity transfers its hair, skin color, hair color, etc. + /// + [DataField("transferHumanoidAppearance", serverOnly: true)] + public bool TransferHumanoidAppearance = false; + + /// + /// Whether or not the entity transfers its inventory and equipment between forms. + /// + [DataField("inventory", serverOnly: true)] + public PolymorphInventoryChange Inventory = PolymorphInventoryChange.None; /// /// Whether or not the polymorph reverts when the entity goes into crit. @@ -71,4 +88,11 @@ namespace Content.Shared.Polymorph [DataField("revertOnDeath", serverOnly: true)] public bool RevertOnDeath = true; } + + public enum PolymorphInventoryChange : byte + { + None, + Drop, + Transfer, + } } diff --git a/Resources/Locale/en-US/disease/zombie.ftl b/Resources/Locale/en-US/zombies/zombie.ftl similarity index 100% rename from Resources/Locale/en-US/disease/zombie.ftl rename to Resources/Locale/en-US/zombies/zombie.ftl diff --git a/Resources/Prototypes/Diseases/noninfectious.yml b/Resources/Prototypes/Diseases/noninfectious.yml index 753bdcc858..4ed05a3f12 100644 --- a/Resources/Prototypes/Diseases/noninfectious.yml +++ b/Resources/Prototypes/Diseases/noninfectious.yml @@ -18,7 +18,6 @@ reagent: Phalanximine min: 15 - - type: disease id: StageIIIALungCancer name: Stage IIIA Lung Cancer @@ -42,27 +41,3 @@ ### Once radiation is refactored I want it to have a small chance of giving you regular cancer - -- type: disease - id: ZombieInfection - name: Zombie Infection #This is the incubation period of the zombie disease. - infectious: false - cureResist: 0.2 - effects: - - !type:DiseaseHealthChange - probability: 0.01 - damage: - types: - Blunt: 2 #this is low but it goes for like 5 minutes so it's fine - - !type:DiseaseSnough - probability: 0.05 - snoughMessage: disease-cough - snoughSound: - collection: Coughs - - !type:DiseaseProgression - probability: 0.33 - comp: DiseaseZombie - cures: - - !type:DiseaseReagentCure - reagent: Romerol - min: 10 diff --git a/Resources/Prototypes/Diseases/zombie.yml b/Resources/Prototypes/Diseases/zombie.yml new file mode 100644 index 0000000000..cbdca7bbaf --- /dev/null +++ b/Resources/Prototypes/Diseases/zombie.yml @@ -0,0 +1,26 @@ +- type: disease + id: ActiveZombieVirus + name: Zombie Virus + infectious: false + cureResist: 0.2 + effects: + - !type:DiseaseHealthChange + probability: 0.075 + damage: + types: + Blunt: 4 + - !type:DiseaseAdjustReagent + probability: 0.05 + reagent: Toxin + amount: 1 + - !type:DiseaseSnough + probability: 0.01 + snoughMessage: disease-cough + snoughSound: + collection: Coughs + - !type:DiseaseAddComponent + comp: ZombifyOnDeath + cures: + - !type:DiseaseReagentCure + reagent: Romerol + min: 5 \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 7773438083..f54f9648bb 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -728,7 +728,6 @@ damage: types: Blunt: 0.1 - - type: HumanoidAppearance # no this doesnt make sense but its needed for vocal - type: Vocal # mice are gender neutral who cares maleScream: /Audio/Animals/mouse_squeak.ogg diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml index c9d4220cb5..a4cc92a4a7 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml @@ -40,8 +40,8 @@ parent: HandheldHealthAnalyzer id: HandheldHealthAnalyzerZombie name: Zombie Infector - suffix: DEBUG + suffix: Active components: - type: HealthAnalyzer fake: true - disease: ZombieInfection \ No newline at end of file + disease: ActiveZombieVirus \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/zombieclaw.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/zombieclaw.yml deleted file mode 100644 index b1bdd295fb..0000000000 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/zombieclaw.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Special entity used to fill zombie's hands when they turn undead -- type: entity - id: ZombieClaw - name: Zombie Claw - noSpawn: true - components: - - type: Sprite - sprite: Objects/Weapons/Melee/zombie_claw.rsi - state: icon - - type: Item - - type: Sharp - - type: ZombieTransfer - - type: Unremoveable - - type: MeleeWeapon - damage: - types: - Slash: 13 - Piercing: 7 - range: 1 - arcwidth: 0 - arc: claw - diff --git a/Resources/Prototypes/Polymorphs/polymorph.yml b/Resources/Prototypes/Polymorphs/polymorph.yml index c7013ea795..aec7946591 100644 --- a/Resources/Prototypes/Polymorphs/polymorph.yml +++ b/Resources/Prototypes/Polymorphs/polymorph.yml @@ -8,30 +8,38 @@ id: Chicken entity: MobChicken forced: true - dropInventory: true + inventory: Drop - type: polymorph id: Monkey entity: MobMonkey forced: true - dropInventory: true + inventory: Drop revertOnCrit: true revertOnDeath: true +# this is a test for transferring some visual appearance stuff +- type: polymorph + id: TestHumanMorph + entity: MobHuman + transferName: true + transferHumanoidAppearance: true + inventory: Transfer + - type: polymorph id: AdminMonkeySmite entity: MobMonkey forced: true - dropInventory: true + inventory: Drop - type: polymorph id: AdminBreadSmite entity: FoodBreadPlain forced: true - dropInventory: true + inventory: Drop - type: polymorph id: AdminInstrumentSmite entity: SuperSynthesizerInstrument forced: true - dropInventory: true + inventory: Drop diff --git a/Resources/Prototypes/Reagents/toxins.yml b/Resources/Prototypes/Reagents/toxins.yml index fef7ffc2ec..b0a5485dfa 100644 --- a/Resources/Prototypes/Reagents/toxins.yml +++ b/Resources/Prototypes/Reagents/toxins.yml @@ -309,4 +309,4 @@ Cellular: 1 - !type:ChemCauseDisease causeChance: 1 - disease: ZombieInfection + disease: ActiveZombieVirus diff --git a/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/icon.png b/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/icon.png deleted file mode 100644 index 361dfbf844f4d3d12a5c9c67616b0f6198067673..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6932 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 diff --git a/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/inhand-left.png deleted file mode 100644 index 7cb0ee924af197895894f3b4f9a4866b588c998d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5868 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 Nqgm0Z7dG$S`ybm+IPm}g diff --git a/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/inhand-right.png deleted file mode 100644 index 69a0bef26f03602491e777ea28ad2778a80b9add..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5553 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 F_%G_)jhz4h diff --git a/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/meta.json deleted file mode 100644 index a0d45845d1..0000000000 --- a/Resources/Textures/Objects/Weapons/Melee/zombie_claw.rsi/meta.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Illustrated by EmoGarbage", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -}