diff --git a/Content.Client/ADT/Changeling/UI/ChangelingTransformMenu.xaml b/Content.Client/ADT/Changeling/UI/ChangelingTransformMenu.xaml new file mode 100644 index 00000000000..36c24b3e978 --- /dev/null +++ b/Content.Client/ADT/Changeling/UI/ChangelingTransformMenu.xaml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/Content.Client/ADT/Changeling/UI/ChangelingTransformMenu.xaml.cs b/Content.Client/ADT/Changeling/UI/ChangelingTransformMenu.xaml.cs new file mode 100644 index 00000000000..14a1fd8c1e2 --- /dev/null +++ b/Content.Client/ADT/Changeling/UI/ChangelingTransformMenu.xaml.cs @@ -0,0 +1,105 @@ +using System.Numerics; +using Content.Client.UserInterface.Controls; +using Content.Shared.Chat.Prototypes; +using Content.Shared.Speech; +using Content.Shared.Whitelist; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Content.Shared.ADT.Phantom; +using Robust.Shared.Utility; +using Content.Shared.Humanoid.Prototypes; +using Content.Client.Humanoid; +using Content.Shared.Preferences; +using Robust.Shared.Map; +using Content.Shared.Humanoid; +using System.Linq; +using Content.Shared.Changeling; + +namespace Content.Client.ADT.Changeling.UI; + +[GenerateTypedNameReferences] +public sealed partial class ChangelingTransformMenu : RadialMenu +{ + [Dependency] private readonly EntityManager _entManager = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly ISharedPlayerManager _playerManager = default!; + + private readonly HumanoidAppearanceSystem _appearanceSystem; + private readonly SpriteSystem _spriteSystem; + public List Forms = new(); + public ChangelingMenuType Type = ChangelingMenuType.Transform; + public NetEntity Target = NetEntity.Invalid; + + public event Action? OnSelectForm; + + public ChangelingTransformMenu() + { + IoCManager.InjectDependencies(this); + RobustXamlLoader.Load(this); + + _spriteSystem = _entManager.System(); + _appearanceSystem = _entManager.System(); + } + + public void Populate(RequestChangelingFormsMenuEvent args) + { + var parent = FindControl("Main"); + + foreach (var item in args.HumanoidData) + { + if (Forms.Contains(item.NetEntity)) + return; + + var dummy = _entManager.SpawnEntity(_proto.Index(item.Profile.Species).DollPrototype, MapCoordinates.Nullspace); + _appearanceSystem.LoadProfile(dummy, item.Profile); + var face = new SpriteView(); + face.SetEntity(dummy); + + var button = new ChangelingTransformMenuButton + { + StyleClasses = { "RadialMenuButton" }, + SetSize = new Vector2(64f, 64f), + ToolTip = Loc.GetString(item.Name ?? String.Empty), + Entity = item.NetEntity, + Profile = item.Profile, + Name = item.Name, + }; + + face.Scale *= 1f; + button.AddChild(face); + parent.AddChild(button); + Forms.Add(item.NetEntity); + } + foreach (var child in Children) + { + if (child is not RadialContainer container) + continue; + AddLingClickAction(container); + } + } + private void AddLingClickAction(RadialContainer container) + { + foreach (var child in container.Children) + { + if (child is not ChangelingTransformMenuButton castChild) + continue; + + castChild.OnButtonUp += _ => + { + OnSelectForm?.Invoke(castChild.Entity); + }; + } + } +} + + +public sealed class ChangelingTransformMenuButton : RadialMenuTextureButton +{ + public NetEntity Entity; + public HumanoidCharacterProfile? Profile; + public string? Name; +} diff --git a/Content.Client/ADT/Changeling/UI/ChangelingTransformUIController.cs b/Content.Client/ADT/Changeling/UI/ChangelingTransformUIController.cs new file mode 100644 index 00000000000..7c2527e30f6 --- /dev/null +++ b/Content.Client/ADT/Changeling/UI/ChangelingTransformUIController.cs @@ -0,0 +1,88 @@ +using JetBrains.Annotations; +using Robust.Client.Graphics; +using Robust.Client.Input; +using Robust.Client.UserInterface.Controllers; +using Robust.Shared.Player; +using Content.Shared.Changeling; + +namespace Content.Client.ADT.Changeling.UI; + +[UsedImplicitly] +public sealed class ChangelingTransformUIController : UIController//, IOnStateChanged +{ + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IClyde _displayManager = default!; + [Dependency] private readonly IInputManager _inputManager = default!; + [Dependency] private readonly ISharedPlayerManager _playerManager = default!; + + private ChangelingTransformMenu? _menu; + + public override void Initialize() + { + EntityManager.EventBus.SubscribeEvent(EventSource.Network, this, OnRequestMenu); + } + + private void OnRequestMenu(RequestChangelingFormsMenuEvent ev) + { + ToggleMenu(ev); + } + + private void ToggleMenu(RequestChangelingFormsMenuEvent ev) + { + if (_menu == null) + { + // setup window + _menu = UIManager.CreateWindow(); + _menu.OnClose += OnWindowClosed; + _menu.OnOpen += OnWindowOpen; + _menu.OnSelectForm += OnSelectForm; + + _menu.Type = ev.Type; + _menu.Target = ev.Target; + + _menu.Populate(ev); + + _menu.OpenCentered(); + } + else + { + _menu.OnClose -= OnWindowClosed; + _menu.OnOpen -= OnWindowOpen; + _menu.OnSelectForm -= OnSelectForm; + _menu.Forms.Clear(); + + CloseMenu(); + } + } + + private void OnWindowClosed() + { + CloseMenu(); + } + + private void OnWindowOpen() + { + } + + private void CloseMenu() + { + if (_menu == null) + return; + + _menu.Dispose(); + _menu = null; + } + + private void OnSelectForm(NetEntity ent) + { + if (_menu == null) + return; + + var player = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid); + + var ev = new SelectChangelingFormEvent(player, _menu.Target, ent, _menu.Type); + _entityManager.RaisePredictiveEvent(ev); + + CloseMenu(); + } +} diff --git a/Content.Client/ADT/Stealth/StealthSystem.cs b/Content.Client/ADT/Stealth/StealthSystem.cs new file mode 100644 index 00000000000..011e73608d7 --- /dev/null +++ b/Content.Client/ADT/Stealth/StealthSystem.cs @@ -0,0 +1,31 @@ +using Content.Client.Interactable.Components; +using Content.Client.StatusIcon; +using Content.Shared.ADT.Stealth.Components; +using Content.Shared.Stealth; +using Content.Shared.Stealth.Components; +using Content.Shared.Tag; +using Content.Shared.Whitelist; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Prototypes; + +namespace Content.Client.Stealth; + +public sealed partial class StealthSystem +{ + private void InitializeADT() + { + _player.LocalPlayerAttached += OnAttachedChanged; + _player.LocalPlayerDetached += OnAttachedChanged; + } + + private void OnAttachedChanged(EntityUid uid) + { + var query = AllEntityQuery(); + while (query.MoveNext(out var ent, out var comp, out _)) + { + SetShader(ent, comp.Enabled); + } + } +} diff --git a/Content.Client/Stealth/StealthSystem.cs b/Content.Client/Stealth/StealthSystem.cs index adb25e1ef63..d59145d7c7c 100644 --- a/Content.Client/Stealth/StealthSystem.cs +++ b/Content.Client/Stealth/StealthSystem.cs @@ -1,17 +1,22 @@ using Content.Client.Interactable.Components; using Content.Client.StatusIcon; +using Content.Shared.ADT.Stealth.Components; using Content.Shared.Stealth; using Content.Shared.Stealth.Components; +using Content.Shared.Tag; +using Content.Shared.Whitelist; using Robust.Client.GameObjects; using Robust.Client.Graphics; +using Robust.Client.Player; using Robust.Shared.Prototypes; namespace Content.Client.Stealth; -public sealed class StealthSystem : SharedStealthSystem +public sealed partial class StealthSystem : SharedStealthSystem { [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; + [Dependency] private readonly IPlayerManager _player = default!; private ShaderInstance _shader = default!; @@ -24,6 +29,8 @@ public override void Initialize() SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnShaderRender); + + InitializeADT(); // ADT tweak } public override void SetEnabled(EntityUid uid, bool value, StealthComponent? component = null) @@ -39,6 +46,10 @@ private void SetShader(EntityUid uid, bool enabled, StealthComponent? component { if (!Resolve(uid, ref component, ref sprite, false)) return; + // ADT start + if (!CheckStealthWhitelist(_player.LocalEntity, uid)) + enabled = false; + // ADT end sprite.Color = Color.White; sprite.PostShader = enabled ? _shader : null; diff --git a/Content.Server/ADT/Changeling/ChangelingActionNotPresentCondition.cs b/Content.Server/ADT/Changeling/ChangelingActionNotPresentCondition.cs new file mode 100644 index 00000000000..1839f5a2a0f --- /dev/null +++ b/Content.Server/ADT/Changeling/ChangelingActionNotPresentCondition.cs @@ -0,0 +1,23 @@ +using Content.Shared.Changeling.Components; +using Content.Shared.Store; + +namespace Content.Server.Store.Conditions; + +/// +/// Only allows a listing to be purchased while buyer can refresh. +/// +public sealed partial class ChangelingActionNotPresentCondition : ListingCondition +{ + public override bool Condition(ListingConditionArgs args) + { + if (!args.EntityManager.TryGetComponent(args.Buyer, out var ling)) + return false; + + foreach (var item in ling.BoughtActions) + { + if (args.EntityManager.TryGetComponent(item, out var meta) && meta.EntityPrototype?.ID == args.Listing.ProductAction) + return false; + } + return true; + } +} diff --git a/Content.Server/ADT/Changeling/ChangelingCanRefreshCondition.cs b/Content.Server/ADT/Changeling/ChangelingCanRefreshCondition.cs new file mode 100644 index 00000000000..9821a9670a0 --- /dev/null +++ b/Content.Server/ADT/Changeling/ChangelingCanRefreshCondition.cs @@ -0,0 +1,16 @@ +using Content.Shared.Changeling.Components; +using Content.Shared.Store; + +namespace Content.Server.Store.Conditions; + +/// +/// Only allows a listing to be purchased while buyer can refresh. +/// +public sealed partial class ChangelingCanRefreshCondition : ListingCondition +{ + + public override bool Condition(ListingConditionArgs args) + { + return args.EntityManager.TryGetComponent(args.Buyer, out var ling) && ling.CanRefresh; + } +} diff --git a/Content.Server/ADT/Changeling/ChangelingLastResortNotUsedCondition.cs b/Content.Server/ADT/Changeling/ChangelingLastResortNotUsedCondition.cs new file mode 100644 index 00000000000..38b4dcbb8fb --- /dev/null +++ b/Content.Server/ADT/Changeling/ChangelingLastResortNotUsedCondition.cs @@ -0,0 +1,20 @@ +using Content.Shared.Changeling.Components; +using Content.Shared.Store; + +namespace Content.Server.Store.Conditions; + +/// +/// Only allows a listing to be purchased while buyer can refresh. +/// +public sealed partial class ChangelingLastResortNotUsedCondition : ListingCondition +{ + public override bool Condition(ListingConditionArgs args) + { + if (!args.EntityManager.TryGetComponent(args.Buyer, out var ling)) + return false; + if (ling.LastResortUsed) + return false; + + return true; + } +} diff --git a/Content.Server/ADT/Changeling/Role/ChangelingRoleComponent.cs b/Content.Server/ADT/Changeling/Role/ChangelingRoleComponent.cs new file mode 100644 index 00000000000..12a5eb939f9 --- /dev/null +++ b/Content.Server/ADT/Changeling/Role/ChangelingRoleComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Roles; + +namespace Content.Server.Roles; + +[RegisterComponent] +public sealed partial class ChangelingRoleComponent : BaseMindRoleComponent +{ +} diff --git a/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Combat.cs b/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Combat.cs new file mode 100644 index 00000000000..4edf484b68f --- /dev/null +++ b/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Combat.cs @@ -0,0 +1,523 @@ +using Content.Shared.Changeling.Components; +using Content.Shared.Changeling; +using Content.Shared.Inventory; +using Content.Shared.Interaction.Components; +using Content.Shared.Hands.Components; +using Content.Shared.Damage; +using Content.Shared.Damage.Prototypes; +using Content.Shared.Popups; +using Robust.Shared.Player; +using Content.Shared.IdentityManagement; +using Content.Shared.FixedPoint; +using Content.Shared.Chemistry.Components; +using Content.Server.Destructible; +using Content.Shared.Movement.Systems; +using Content.Shared.ADT.Damage.Events; +using Content.Shared.StatusEffect; +using Content.Shared.Eye.Blinding.Components; +using Content.Shared.Eye.Blinding.Systems; +using Content.Shared.Damage.Components; +using Content.Shared.Mobs.Components; + +namespace Content.Server.Changeling.EntitySystems; + +public sealed partial class ChangelingSystem +{ + private void InitializeCombatAbilities() + { + SubscribeLocalEvent(OnLingEmp); + SubscribeLocalEvent(OnResonantShriek); + SubscribeLocalEvent(OnMuscles); + SubscribeLocalEvent(OnBlindSting); + SubscribeLocalEvent(OnAdrenaline); + + SubscribeLocalEvent(OnArmBladeAction); + SubscribeLocalEvent(OnArmShieldAction); + SubscribeLocalEvent(OnArmaceAction); + SubscribeLocalEvent(OnLingArmorAction); + SubscribeLocalEvent(OnBoneShard); + + SubscribeLocalEvent(OnRefreshMovespeed); + SubscribeLocalEvent(OnDamage); + SubscribeLocalEvent(OnBeforeStaminacrit); + } + + #region Actions + private void OnLingEmp(EntityUid uid, ChangelingComponent component, LingEMPActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty)) + return; + + args.Handled = true; + + var coords = _transform.GetMapCoordinates(uid); + _emp.EmpPulse(coords, component.DissonantShriekEmpRange, component.DissonantShriekEmpConsumption, component.DissonantShriekEmpDuration); + } + + public void OnResonantShriek(EntityUid uid, ChangelingComponent component, LingResonantShriekEvent args) + { + if (args.Handled) + return; + + if (_mobState.IsDead(uid)) + { + var selfMessage = Loc.GetString("changeling-regenerate-fail-dead"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty)) + return; + + args.Handled = true; + + var xform = Transform(uid); + foreach (var ent in _lookup.GetEntitiesInRange(xform.Coordinates, 15)) + { + if (HasComp(ent)) + continue; + + _flashSystem.Flash(ent, uid, null, 6f, 0.8f, false); + + if (!_mindSystem.TryGetMind(ent, out var mindId, out var mind)) + continue; + if (mind.Session == null) + continue; + _audioSystem.PlayGlobal(component.SoundResonant, mind.Session); + } + } + + private void OnMuscles(EntityUid uid, ChangelingComponent component, ChangelingMusclesActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty)) + return; + + args.Handled = true; + + var message = Loc.GetString("changeling-lingmuscles"); + _popup.PopupEntity(message, uid, uid); + + component.MusclesActive = !component.MusclesActive; + _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(uid); + if (!component.MusclesActive) + _stun.TryParalyze(uid, TimeSpan.FromSeconds(4), true); + + } + + private void OnAdrenaline(EntityUid uid, ChangelingComponent component, AdrenalineActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + _popup.PopupEntity(Loc.GetString("changeling-transform-fail-lesser-form"), uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTen)) + return; + + args.Handled = true; + + _status.TryAddStatusEffect(uid, "Adrenaline", TimeSpan.FromMinutes(1), false); + var selfMessage = Loc.GetString("changeling-adrenaline-self-success"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + + private void OnBlindSting(EntityUid uid, ChangelingComponent component, BlindStingEvent args) + { + if (args.Handled) + return; + + var target = args.Target; + + if (!TryStingTarget(uid, target)) + return; + + if (!TryUseAbility(uid, component, component.ChemicalsCostFifteen)) + return; + + args.Handled = true; + + _status.TryAddStatusEffect(target, TemporaryBlindnessSystem.BlindingStatusEffect, component.BlindStingDuration, true); + + var selfMessageSuccess = Loc.GetString("changeling-success-sting", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessageSuccess, uid, uid); + + } + + private void OnArmBladeAction(EntityUid uid, ChangelingComponent component, ArmBladeActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty, !component.ArmBladeActive)) + return; + + args.Handled = true; + + component.ArmBladeActive = !component.ArmBladeActive; + + if (component.ArmBladeActive) + { + if (!SpawnArmBlade(uid, component)) + { + _popup.PopupEntity(Loc.GetString("changeling-armblade-fail"), uid, uid); + return; + } + + _audioSystem.PlayPvs(component.SoundFlesh, uid); + + var othersMessage = Loc.GetString("changeling-armblade-success-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armblade-success-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + else + RemoveBladeEntity(uid, component); + } + + private void OnArmShieldAction(EntityUid uid, ChangelingComponent component, ArmShieldActionEvent args) // При нажатии на действие орг. щита + { + if (args.Handled) + return; + + if (!TryComp(uid, out HandsComponent? handsComponent)) + return; + if (handsComponent.ActiveHand == null) + return; + + var handContainer = handsComponent.ActiveHand.Container; + + if (handContainer == null) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty, !component.ArmShieldActive)) + return; + + args.Handled = true; + + component.ArmShieldActive = !component.ArmShieldActive; + + if (component.ArmShieldActive) + { + if (!SpawnArmShield(uid, component)) + { + _popup.PopupEntity(Loc.GetString("changeling-armshield-fail"), uid, uid); + return; + } + + _audioSystem.PlayPvs(component.SoundFlesh, uid); + + var othersMessage = Loc.GetString("changeling-armshield-success-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armshield-success-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + else + RemoveShieldEntity(uid, component); + } + + private void OnArmaceAction(EntityUid uid, ChangelingComponent component, ArmaceActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty, !component.ArmBladeActive)) + return; + + args.Handled = true; + + component.ArmaceActive = !component.ArmaceActive; + + if (component.ArmaceActive) + { + if (!SpawnArmace(uid, component)) + { + _popup.PopupEntity(Loc.GetString("changeling-armblade-fail"), uid, uid); + return; + } + + _audioSystem.PlayPvs(component.SoundFlesh, uid); + + var othersMessage = Loc.GetString("changeling-armace-success-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armace-success-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + else + RemoveArmaceEntity(uid, component); + } + + private void OnLingArmorAction(EntityUid uid, ChangelingComponent component, LingArmorActionEvent args) + { + if (args.Handled) + return; + + if (!TryComp(uid, out var inventory)) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty, !component.LingArmorActive, component.LingArmorRegenCost)) + return; + + _audioSystem.PlayPvs(component.SoundFlesh, uid); + component.LingArmorActive = !component.LingArmorActive; + + if (component.LingArmorActive) + { + args.Handled = true; + + SpawnLingArmor(uid, inventory); + + var othersMessage = Loc.GetString("changeling-armor-success-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armor-success-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + else + { + _inventorySystem.TryUnequip(uid, "head", true, true, false); + _inventorySystem.TryUnequip(uid, "outerClothing", true, true, false); + + var othersMessage = Loc.GetString("changeling-armor-retract-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armor-retract-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + + var solution = new Solution(); + solution.AddReagent("Blood", FixedPoint2.New(75)); + _puddle.TrySpillAt(Transform(uid).Coordinates, solution, out _); + } + } + + private void OnBoneShard(EntityUid uid, ChangelingComponent component, ChangelingBoneShardEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostFifteen)) + return; + + args.Handled = true; + + var shard = Spawn("ADTThrowingStarChangeling", Transform(uid).Coordinates); + + _damageableSystem.TryChangeDamage(uid, new DamageSpecifier(_proto.Index("Blunt"), 20)); + _handsSystem.TryPickupAnyHand(uid, shard); + + _audioSystem.PlayPvs(component.SoundFlesh, uid); + } + #endregion + + #region Events + private void OnRefreshMovespeed(EntityUid uid, ChangelingComponent component, RefreshMovementSpeedModifiersEvent args) + { + if (component.MusclesActive) + args.ModifySpeed(component.MusclesModifier); + } + + private void OnDamage(EntityUid uid, ChangelingShieldComponent component, DamageChangedEvent args) + { + var parent = Transform(uid).ParentUid; + if (!TryComp(parent, out var ling)) + return; + if (!TryComp(uid, out var damage)) + return; + + var additionalShieldHealth = 50 * ling.AbsorbedDnaModifier; + var shieldHealth = 150 + additionalShieldHealth; + if (damage.TotalDamage >= shieldHealth) + { + ling.ArmShieldActive = false; + QueueDel(ling.ShieldEntity); + + _audioSystem.PlayPvs(ling.SoundFlesh, uid); + + var othersMessage = Loc.GetString("changeling-armshield-broke-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, parent, Filter.PvsExcept(parent), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armshield-broke-self"); + _popup.PopupEntity(selfMessage, parent, parent, PopupType.MediumCaution); + } + } + + private void OnBeforeStaminacrit(EntityUid uid, ChangelingComponent component, ref BeforeStaminaCritEvent args) + { + if (!component.MusclesActive) + return; + + args.Cancelled = true; + + if (_timing.CurTime < component.NextMusclesDamage) + return; + + _damageableSystem.TryChangeDamage(uid, new DamageSpecifier(_proto.Index("Brute"), 5)); + component.NextMusclesDamage = _timing.CurTime + TimeSpan.FromSeconds(1); + } + #endregion + + #region Misc + public bool SpawnArmBlade(EntityUid uid, ChangelingComponent component) + { + var armblade = Spawn("ADTArmBlade", Transform(uid).Coordinates); + EnsureComp(armblade); + RemComp(armblade); + if (!_handsSystem.TryPickupAnyHand(uid, armblade)) + { + QueueDel(armblade); + return false; + } + + component.BladeEntity = armblade; + return true; + } + + public bool SpawnArmShield(EntityUid uid, ChangelingComponent component) + { + var armshield = Spawn("ADTArmShield", Transform(uid).Coordinates); + EnsureComp(armshield); + + if (!_handsSystem.TryPickupAnyHand(uid, armshield)) + { + QueueDel(armshield); + return false; + } + component.ShieldEntity = armshield; + return true; + } + + public bool SpawnArmace(EntityUid uid, ChangelingComponent component) + { + var mace = Spawn("ADTArmace", Transform(uid).Coordinates); + EnsureComp(mace); + + if (!_handsSystem.TryPickupAnyHand(uid, mace)) + { + QueueDel(mace); + return false; + } + component.ArmaceEntity = mace; + return true; + } + + private void RemoveBladeEntity(EntityUid uid, ChangelingComponent component) + { + if (!component.BladeEntity.HasValue) + return; + QueueDel(component.BladeEntity); + _audioSystem.PlayPvs(component.SoundFlesh, uid); + component.ArmBladeActive = false; + + var othersMessage = Loc.GetString("changeling-armblade-retract-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armblade-retract-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + + private void RemoveShieldEntity(EntityUid uid, ChangelingComponent component) + { + if (!component.ShieldEntity.HasValue) + return; + QueueDel(component.ShieldEntity); + _audioSystem.PlayPvs(component.SoundFlesh, uid); + component.ArmShieldActive = false; + + var othersMessage = Loc.GetString("changeling-armshield-retract-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armshield-retract-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + + private void RemoveArmaceEntity(EntityUid uid, ChangelingComponent component) + { + if (!component.ArmaceEntity.HasValue) + return; + QueueDel(component.ArmaceEntity); + _audioSystem.PlayPvs(component.SoundFlesh, uid); + component.ArmaceActive = false; + + var othersMessage = Loc.GetString("changeling-armace-retract-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-armace-retract-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + + public void SpawnLingArmor(EntityUid uid, InventoryComponent inventory) + { + var helmet = Spawn("ClothingHeadHelmetLing", Transform(uid).Coordinates); + var armor = Spawn("ClothingOuterArmorChangeling", Transform(uid).Coordinates); + EnsureComp(helmet); + EnsureComp(armor); + + _inventorySystem.TryUnequip(uid, "head", true, true, false, inventory); + _inventorySystem.TryUnequip(uid, "outerClothing", true, true, false, inventory); + + _inventorySystem.TryEquip(uid, helmet, "head", true, true, false, inventory); + _inventorySystem.TryEquip(uid, armor, "outerClothing", true, true, false, inventory); + } + #endregion +} diff --git a/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Headslug.cs b/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Headslug.cs new file mode 100644 index 00000000000..055de1754e4 --- /dev/null +++ b/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Headslug.cs @@ -0,0 +1,125 @@ +using Content.Shared.Changeling.Components; +using Content.Shared.Changeling; +using Content.Shared.Inventory; +using Content.Shared.Interaction.Components; +using Content.Shared.Hands.Components; +using Content.Shared.Damage; +using Content.Shared.Damage.Prototypes; +using Content.Shared.Popups; +using Robust.Shared.Player; +using Content.Shared.IdentityManagement; +using Content.Shared.FixedPoint; +using Content.Shared.Chemistry.Components; +using Content.Server.Destructible; +using Content.Shared.Movement.Systems; +using Content.Shared.ADT.Damage.Events; +using Content.Shared.StatusEffect; +using Content.Shared.Eye.Blinding.Components; +using Content.Shared.Eye.Blinding.Systems; +using Content.Shared.Damage.Components; +using Robust.Shared.Containers; +using Content.Shared.Interaction; +using Content.Shared.DoAfter; +using Content.Shared.Humanoid; +using Content.Server.Resist; +using Content.Shared.Examine; +using System.Linq; + +namespace Content.Server.Changeling.EntitySystems; + +public sealed partial class ChangelingSystem +{ + private void InitializeSlug() + { + SubscribeLocalEvent(OnLayEggs); + SubscribeLocalEvent(OnLayEggsDoAfter); + + SubscribeLocalEvent(OnExamineContainer); + } + + private void OnLayEggs(EntityUid uid, ChangelingHeadslugComponent comp, UserActivateInWorldEvent args) + { + if (args.Handled) + return; + + var target = args.Target; + if (!HasComp(target)) + return; + + if (!TryStingTarget(uid, target) || !_mobState.IsDead(target) || HasComp(target)) + return; + + var doAfter = new DoAfterArgs(EntityManager, uid, 4f, new LingEggDoAfterEvent(), uid, target: target) + { + DistanceThreshold = 1, + BreakOnMove = true, + BreakOnWeightlessMove = true, + BreakOnDamage = true, + AttemptFrequency = AttemptFrequency.StartAndEnd + }; + + _doAfter.TryStartDoAfter(doAfter); + } + + private void OnLayEggsDoAfter(EntityUid uid, ChangelingHeadslugComponent comp, LingEggDoAfterEvent args) + { + if (args.Handled || args.Cancelled || !args.Target.HasValue) + return; + + var containerComp = EnsureComp(args.Target.Value); + containerComp.Container = _container.EnsureContainer(args.Target.Value, "headslug", out _); + + RemComp(uid); + _container.Insert(uid, containerComp.Container); + comp.IsInside = true; + comp.Container = args.Target; + } + + private void OnExamineContainer(EntityUid uid, ChangelingHeadslugContainerComponent comp, ExaminedEvent args) + { + var slug = comp?.Container.ContainedEntities.First(); + if (!slug.HasValue) + return; + + if (!Comp(slug.Value).Alerted) + args.PushMarkup(Loc.GetString("changeling-headslug-inside")); + else + args.PushMarkup(Loc.GetString("changeling-headslug-inside-soon")); + } + + private void UpdateChangelingHeadslug(EntityUid uid, float frameTime, ChangelingHeadslugComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return; + if (!comp.IsInside || !comp.Container.HasValue) + return; + + comp.Accumulator += frameTime; + + if (comp.Accumulator >= comp.AccumulateTime * 0.75f && !comp.Alerted) + { + _popup.PopupEntity(Loc.GetString("changeling-slug-almost-ready"), uid, uid); + comp.Alerted = true; + } + + if (comp.Accumulator < comp.AccumulateTime) + return; + + if (!_mindSystem.TryGetMind(uid, out var mindId, out var mind)) + return; + + var monke = Spawn("ADTMobMonkeyChangeling", Transform(comp.Container.Value).Coordinates); + _mindSystem.TransferTo(mindId, monke); + var ling = EnsureComp(monke); + + EntityUid? lesserFormActionEntity = null; + _action.AddAction(monke, ref lesserFormActionEntity, "ActionLingLesserForm"); + _action.SetToggled(lesserFormActionEntity, true); + + ling.BoughtActions.Add(lesserFormActionEntity); + ling.LesserFormActive = true; + ling.LastResortUsed = true; + + _damageableSystem.TryChangeDamage(comp.Container.Value, new DamageSpecifier(_proto.Index("Blunt"), 500000)); + } +} diff --git a/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Useful.cs b/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Useful.cs new file mode 100644 index 00000000000..dffb8199b72 --- /dev/null +++ b/Content.Server/ADT/Changeling/Systems/ChangelingSystem.Useful.cs @@ -0,0 +1,709 @@ +using Content.Shared.Changeling.Components; +using Content.Shared.Changeling; +using Content.Shared.Damage; +using Content.Shared.Damage.Prototypes; +using Content.Shared.Popups; +using Robust.Shared.Player; +using Content.Shared.IdentityManagement; +using Content.Shared.Stealth.Components; +using Content.Shared.DoAfter; +using Content.Shared.Humanoid; +using Content.Server.Forensics; +using Content.Shared.FixedPoint; +using Content.Shared.Mobs; +using Content.Shared.Cuffs.Components; +using Content.Shared.Rejuvenate; +using Content.Shared.Store.Components; +using Content.Shared.Gibbing.Events; +using Content.Shared.Speech.Muting; +using System.Linq; +using Content.Shared.Chemistry.Components; +using Content.Shared.Whitelist; +using Content.Shared.ADT.Stealth.Components; + +namespace Content.Server.Changeling.EntitySystems; + +public sealed partial class ChangelingSystem +{ + private void InitializeUsefulAbilities() + { + SubscribeLocalEvent(StartAbsorbing); + + SubscribeLocalEvent(OnRegenerate); + SubscribeLocalEvent(OnStasisDeathAction); + SubscribeLocalEvent(OnFleshmend); + + SubscribeLocalEvent(OnLingInvisible); + SubscribeLocalEvent(OnDigitalCamouflage); + SubscribeLocalEvent(OnLesserForm); + SubscribeLocalEvent(OnLastResort); + SubscribeLocalEvent(OnBiodegrade); + + SubscribeLocalEvent(OnLingDNASting); + SubscribeLocalEvent(OnMuteSting); + SubscribeLocalEvent(OnDrugSting); + SubscribeLocalEvent(OnTransformSting); + + SubscribeLocalEvent(OnAbsorbDoAfter); + SubscribeLocalEvent(OnBiodegradeDoAfter); + } + + private void StartAbsorbing(EntityUid uid, ChangelingComponent component, LingAbsorbActionEvent args) // Начало поглощения + { + if (args.Handled) + return; + if (component.DoAfter.HasValue) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + var target = args.Target; + if (!HasComp(target)) + { + var selfMessage = Loc.GetString("changeling-dna-fail-nohuman", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!_mobState.IsIncapacitated(target)) // if target isn't crit or dead dont let absorb + { + var selfMessage = Loc.GetString("changeling-dna-fail-notdead", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (HasComp(target)) + { + var selfMessage = Loc.GetString("changeling-dna-alreadyabsorbed", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (_tagSystem.HasTag(target, "ChangelingBlacklist")) + { + var selfMessage = Loc.GetString("changeling-dna-sting-fail-nodna", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + + args.Handled = true; + + _popup.PopupEntity(Loc.GetString("changeling-dna-stage-1"), uid, uid); + + var doAfter = new DoAfterArgs(EntityManager, uid, component.AbsorbDuration, new AbsorbDoAfterEvent(), uid, target: target) + { + DistanceThreshold = 2, + BreakOnMove = true, + BreakOnWeightlessMove = true, + BreakOnDamage = true, + AttemptFrequency = AttemptFrequency.StartAndEnd + }; + + _doAfter.TryStartDoAfter(doAfter, out component.DoAfter); + } + + private void OnAbsorbDoAfter(EntityUid uid, ChangelingComponent component, AbsorbDoAfterEvent args) + { + if (args.Handled || args.Args.Target == null) + return; + + args.Handled = true; + args.Repeat = RepeatDoAfter(component); + var target = args.Args.Target.Value; + + if (args.Cancelled || !_mobState.IsIncapacitated(target) || HasComp(target)) + { + var selfMessage = Loc.GetString("changeling-dna-interrupted", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + component.AbsorbStage = 0; + args.Repeat = false; + return; + } + + if (component.AbsorbStage == 0) + { + var othersMessage = Loc.GetString("changeling-dna-stage-2-others", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-dna-stage-2-self"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + else if (component.AbsorbStage == 1) + { + var othersMessage = Loc.GetString("changeling-dna-stage-3-others", ("user", Identity.Entity(uid, EntityManager)), ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.LargeCaution); + + var selfMessage = Loc.GetString("changeling-dna-stage-3-self", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.LargeCaution); + } + else if (component.AbsorbStage == 2) + { + var doStealDNA = true; + if (TryComp(target, out var dnaCompTarget)) + { + foreach (var storedData in component.StoredDNA) + { + if (storedData.DNA != null && storedData.DNA == dnaCompTarget.DNA) + doStealDNA = false; + } + } + + if (doStealDNA) + { + if (!StealDNA(uid, target, component)) + { + component.AbsorbStage = 0; + args.Repeat = false; + return; + } + } + + component.DoAfter = null; + + // Нанесение 200 генетического урона и замена крови на кислоту + var dmg = new DamageSpecifier(_proto.Index("Genetic"), component.AbsorbGeneticDmg); + _damageableSystem.TryChangeDamage(target, dmg); + + var solution = new Solution(); + solution.AddReagent("FerrochromicAcid", FixedPoint2.New(150)); + _puddle.TrySpillAt(Transform(target).Coordinates, solution, out _); + _bloodstreamSystem.TryModifyBloodLevel(target, -500); + + EnsureComp(target); + + if (HasComp(target)) // Если это был другой генокрад, получим моментально 5 очков эволюции + { + var selfMessage = Loc.GetString("changeling-dna-success-ling", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.Medium); + + if (TryComp(uid, out var store)) + { + _store.TryAddCurrency(new Dictionary { { "EvolutionPoints", component.AbsorbedChangelingPointsAmount } }, uid, store); + _store.UpdateUserInterface(uid, uid, store); + } + } + else // Если это не был генокрад, получаем возможность "сброса" + { + var selfMessage = Loc.GetString("changeling-dna-success", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.Medium); + component.CanRefresh = true; + component.AbsorbedDnaModifier += 1; + } + } + + if (component.AbsorbStage >= 2) + component.AbsorbStage = 0; + else + component.AbsorbStage += 1; + } + + private static bool RepeatDoAfter(ChangelingComponent component) + { + if (component.AbsorbStage < 2.0) + return true; + else + return false; + } + + private void OnRegenerate(EntityUid uid, ChangelingComponent component, LingRegenerateActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + _popup.PopupEntity(Loc.GetString("changeling-transform-fail-lesser-form"), uid, uid); + return; + } + + if (!_mobState.IsCritical(uid)) // make sure the ling is critical, if not they cant regenerate + { + _popup.PopupEntity(Loc.GetString("changeling-regenerate-fail-not-crit"), uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTen)) + return; + + args.Handled = true; + + var damage_brute = new DamageSpecifier(_proto.Index("Brute"), component.RegenerateBruteHealAmount); + var damage_burn = new DamageSpecifier(_proto.Index("Burn"), component.RegenerateBurnHealAmount); + _damageableSystem.TryChangeDamage(uid, damage_brute); + _damageableSystem.TryChangeDamage(uid, damage_burn); + _bloodstreamSystem.TryModifyBloodLevel(uid, component.RegenerateBloodVolumeHealAmount); // give back blood and remove bleeding + _bloodstreamSystem.TryModifyBleedAmount(uid, component.RegenerateBleedReduceAmount); + _audioSystem.PlayPvs(component.SoundRegenerate, uid); + + var othersMessage = Loc.GetString("changeling-regenerate-others-success", ("user", Identity.Entity(uid, EntityManager))); + _popup.PopupEntity(othersMessage, uid, Filter.PvsExcept(uid), true, PopupType.MediumCaution); + + var selfMessage = Loc.GetString("changeling-regenerate-self-success"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + + private void OnLingInvisible(EntityUid uid, ChangelingComponent component, LingInvisibleActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + if (component.DigitalCamouflageActive) + { + var selfMessage = Loc.GetString("changeling-chameleon-fail-digi-camo"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwentyFive, !component.ChameleonSkinActive)) + return; + + args.Handled = true; + + var stealth = EnsureComp(uid); + var stealthonmove = EnsureComp(uid); + + var message = Loc.GetString(!component.ChameleonSkinActive ? "changeling-chameleon-toggle-on" : "changeling-chameleon-toggle-off"); + _popup.PopupEntity(message, uid, uid); + + if (!component.ChameleonSkinActive) + { + stealthonmove.PassiveVisibilityRate = component.ChameleonSkinPassiveVisibilityRate; + stealthonmove.MovementVisibilityRate = component.ChameleonSkinMovementVisibilityRate; + stealth.MinVisibility = -1f; + } + else + { + RemCompDeferred(uid, stealth); + RemCompDeferred(uid, stealthonmove); + } + + component.ChameleonSkinActive = !component.ChameleonSkinActive; + } + + private void OnLingDNASting(EntityUid uid, ChangelingComponent component, LingStingExtractActionEvent args) + { + if (args.Handled) + return; + + var target = args.Target; + + if (!TryStingTarget(uid, target)) + return; + + var dnaCompTarget = EnsureComp(target); + + foreach (var storedData in component.StoredDNA) + { + if (storedData.DNA != null && storedData.DNA == dnaCompTarget.DNA) + { + var selfMessageFailAlreadyDna = Loc.GetString("changeling-dna-sting-fail-alreadydna", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessageFailAlreadyDna, uid, uid); + return; + } + } + + if (component.StoredDNA.Count >= component.DNAStrandCap) + { + var selfMessage = Loc.GetString("changeling-dna-sting-fail-full"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwentyFive)) + return; + + if (StealDNA(uid, target, component)) + { + args.Handled = true; + + var selfMessageSuccess = Loc.GetString("changeling-dna-sting", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessageSuccess, uid, uid); + } + } + + private void OnStasisDeathAction(EntityUid uid, ChangelingComponent component, StasisDeathActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + component.StasisDeathActive = !component.StasisDeathActive; + + if (component.StasisDeathActive) + { + if (!TryUseAbility(uid, component, component.ChemicalsCostTwentyFive)) + return; + + args.Handled = true; + + if (_mindSystem.TryGetMind(uid, out var mindId, out var mind)) + mind.PreventGhosting = true; + + _mobState.ChangeMobState(uid, MobState.Dead); + + var selfMessage = Loc.GetString("changeling-stasis-death-self-success"); /// всё, я спать откисать, адьос + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + } + else + { + if (!_mobState.IsDead(uid)) + { + component.StasisDeathActive = false; + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostFree)) + return; + + args.Handled = true; + + var selfMessage = Loc.GetString("changeling-stasis-death-self-revive"); /// вейк ап энд cum бэк ту ворк + _popup.PopupEntity(selfMessage, uid, uid, PopupType.MediumCaution); + + _audioSystem.PlayPvs(component.SoundRegenerate, uid); + + RaiseLocalEvent(uid, new RejuvenateEvent()); + + component.StasisDeathActive = false; + + if (_mindSystem.TryGetMind(uid, out var mindId, out var mind)) + { + mind.PreventGhosting = false; + mind.PreventGhostingSendMessage = false; + } + } + + _action.SetToggled(component.ChangelingStasisDeathActionEntity, component.StasisDeathActive); + } + + private void OnMuteSting(EntityUid uid, ChangelingComponent component, MuteStingEvent args) + { + if (args.Handled) + return; + + var target = args.Target; + + if (!TryStingTarget(uid, target)) + return; + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty)) + return; + + args.Handled = true; + + _status.TryAddStatusEffect(target, "Muted", TimeSpan.FromSeconds(45), true); + + var selfMessageSuccess = Loc.GetString("changeling-success-sting", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessageSuccess, uid, uid); + + } + + private void OnDrugSting(EntityUid uid, ChangelingComponent component, DrugStingEvent args) + { + if (args.Handled) + return; + + var target = args.Target; + + if (!TryStingTarget(uid, target)) + return; + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty)) + return; + + args.Handled = true; + + _hallucinations.StartHallucinations(target, "ADTHallucinations", TimeSpan.FromSeconds(40), true, "Changeling"); + var selfMessageSuccess = Loc.GetString("changeling-success-sting", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessageSuccess, uid, uid); + + } + + private void OnFleshmend(EntityUid uid, ChangelingComponent component, FleshmendActionEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + _popup.PopupEntity(Loc.GetString("changeling-transform-fail-lesser-form"), uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwentyFive)) + return; + + args.Handled = true; + + var damage_brute = new DamageSpecifier(_proto.Index("Brute"), component.RegenerateBruteHealAmount); + var damage_burn = new DamageSpecifier(_proto.Index("Burn"), component.RegenerateBurnHealAmount); + _damageableSystem.TryChangeDamage(uid, damage_brute); + _damageableSystem.TryChangeDamage(uid, damage_burn); + _bloodstreamSystem.TryModifyBloodLevel(uid, component.RegenerateBloodVolumeHealAmount); // give back blood and remove bleeding + _bloodstreamSystem.TryModifyBleedAmount(uid, component.RegenerateBleedReduceAmount); + _audioSystem.PlayPvs(component.SoundFleshQuiet, uid); + + var selfMessage = Loc.GetString("changeling-omnizine-self-success"); + _popup.PopupEntity(selfMessage, uid, uid, PopupType.Small); + } + + private void OnLesserForm(EntityUid uid, ChangelingComponent component, ChangelingLesserFormActionEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + if (!component.LesserFormActive) + { + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty)) + return; + + RemoveShieldEntity(uid, component); + RemoveBladeEntity(uid, component); + RemCompDeferred(uid); + RemCompDeferred(uid); + component.MusclesActive = false; + _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(uid); + + if (component.LingArmorActive) + { + _inventorySystem.TryUnequip(uid, "head", true, true, false); + _inventorySystem.TryUnequip(uid, "outerClothing", true, true, false); + component.ChemicalsPerSecond += component.LingArmorRegenCost; + } + + foreach (var item in component.BoughtActions.Where(x => + x.HasValue && + TryPrototype(x.Value, out var proto) && + proto.ID == "ActionLingLesserForm")) + { + _action.SetToggled(item, true); + } + + component.LesserFormActive = true; + + var transformedUid = _polymorph.PolymorphEntity(uid, component.LesserFormMob); + if (transformedUid == null) + return; + + var selfMessage = Loc.GetString("changeling-lesser-form-activate-monkey"); + _popup.PopupEntity(selfMessage, transformedUid.Value, transformedUid.Value); + + CopyLing(uid, transformedUid.Value); + } + else + { + if (component.StoredDNA.Count <= 0) + { + _popup.PopupEntity(Loc.GetString("changeling-transform-fail-nodna"), uid, uid); + return; + } + + if (TryComp(uid, out var actorComponent)) + { + var ev = new RequestChangelingFormsMenuEvent(GetNetEntity(uid), ChangelingMenuType.HumanForm); + + foreach (var item in component.StoredDNA) + { + var netEntity = GetNetEntity(item.EntityUid); + + ev.HumanoidData.Add(new( + netEntity, + Name(item.EntityUid), + item.HumanoidAppearanceComponent.Species.Id, + BuildProfile(item))); + } + + // реализовать сортировку + RaiseNetworkEvent(ev, actorComponent.PlayerSession); + } + } + } + + private void OnLastResort(EntityUid uid, ChangelingComponent component, LastResortActionEvent args) + { + if (args.Handled) + return; + + if (!TryUseAbility(uid, component, component.ChemicalsCostFree)) + return; + if (!_mindSystem.TryGetMind(uid, out var mindId, out var mind)) + return; + + args.Handled = true; + + foreach (var item in component.BoughtActions) + { + _action.RemoveAction(item); + QueueDel(item); + } + + var slug = Spawn("ADTChangelingHeadslug", Transform(uid).Coordinates); + _mindSystem.TransferTo(mindId, slug); + + _damageableSystem.TryChangeDamage(uid, new DamageSpecifier(_proto.Index("Blunt"), 500000)); + } + + private void OnBiodegrade(EntityUid uid, ChangelingComponent component, LingBiodegradeActionEvent args) + { + if (args.Handled) + return; + + if (_mobState.IsDead(uid)) + { + var selfMessage = Loc.GetString("changeling-regenerate-fail-dead"); + _popup.PopupEntity(selfMessage, uid, uid); + } + + if (!TryComp(uid, out var cuffs) || cuffs.Container.ContainedEntities.Count < 1) + { + var selfMessage = Loc.GetString("changeling-biodegrade-fail-nocuffs"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostFifteen)) + return; + + args.Handled = true; + + _popup.PopupEntity(Loc.GetString("changeling-biodegrade-start"), uid, uid); + + var doAfter = new DoAfterArgs(EntityManager, uid, component.BiodegradeDuration, new BiodegradeDoAfterEvent(), uid, target: uid) + { + DistanceThreshold = 2, + BreakOnMove = true, + BreakOnWeightlessMove = true, + BreakOnDamage = true, + AttemptFrequency = AttemptFrequency.StartAndEnd, + RequireCanInteract = false + }; + + _doAfter.TryStartDoAfter(doAfter); + } + + private void OnBiodegradeDoAfter(EntityUid uid, ChangelingComponent component, BiodegradeDoAfterEvent args) + { + if (args.Handled || args.Args.Target == null) + return; + args.Handled = true; + var target = args.Args.Target.Value; + if (args.Cancelled) + { + var selfMessage = Loc.GetString("changeling-biodegrade-interrupted"); + _popup.PopupEntity(selfMessage, uid, uid); + args.Repeat = false; + return; + } + if (!TryComp(target, out var cuffs) || cuffs.Container.ContainedEntities.Count < 1) + return; + if (!TryComp(cuffs.LastAddedCuffs, out var handcuffs) || cuffs.Container.ContainedEntities.Count < 1) + return; + _cuffable.Uncuff(target, uid, cuffs.LastAddedCuffs, cuffs, handcuffs); + } + + public void OnTransformSting(EntityUid uid, ChangelingComponent component, TransformationStingEvent args) + { + if (args.Handled) + return; + + var target = args.Target; + + if (!TryStingTarget(uid, target)) + return; + + if (component.StoredDNA.Count <= 0) + { + _popup.PopupEntity(Loc.GetString("changeling-transform-fail-nodna"), uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostFifty)) + return; + + args.Handled = true; + + if (TryComp(uid, out var actorComponent)) + { + var ev = new RequestChangelingFormsMenuEvent(GetNetEntity(target), ChangelingMenuType.Sting); + + foreach (var item in component.StoredDNA) + { + var netEntity = GetNetEntity(item.EntityUid); + + ev.HumanoidData.Add(new( + netEntity, + Name(item.EntityUid), + item.HumanoidAppearanceComponent.Species.Id, + BuildProfile(item))); + } + + // реализовать сортировку + RaiseNetworkEvent(ev, actorComponent.PlayerSession); + } + } + + private void OnDigitalCamouflage(EntityUid uid, ChangelingComponent component, DigitalCamouflageEvent args) + { + if (args.Handled) + return; + + if (component.LesserFormActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + if (component.ChameleonSkinActive) + { + var selfMessage = Loc.GetString("changeling-digi-camo-fail-chameleon"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostTwenty, !component.DigitalCamouflageActive)) + return; + + args.Handled = true; + + + var message = Loc.GetString(!component.DigitalCamouflageActive ? "changeling-digital-camo-toggle-on" : "changeling-digital-camo-toggle-off"); + _popup.PopupEntity(message, uid, uid); + + if (!component.DigitalCamouflageActive) + { + EnsureComp(uid); + var stealth = EnsureComp(uid); + + stealth.MinVisibility = -1f; + _stealth.SetVisibility(uid, -1f); + _stealth.SetDesc(uid, Loc.GetString("changeling-digital-camo-desc", ("user", Identity.Entity(uid, EntityManager)))); + } + else + { + RemCompDeferred(uid); + RemCompDeferred(uid); + } + + component.DigitalCamouflageActive = !component.DigitalCamouflageActive; + } +} diff --git a/Content.Server/ADT/Changeling/Systems/ChangelingSystem.cs b/Content.Server/ADT/Changeling/Systems/ChangelingSystem.cs new file mode 100644 index 00000000000..4821d0013ea --- /dev/null +++ b/Content.Server/ADT/Changeling/Systems/ChangelingSystem.cs @@ -0,0 +1,612 @@ +using Content.Server.Actions; +using Content.Shared.Inventory; +using Content.Server.Store.Systems; +using Content.Shared.Changeling; +using Content.Shared.Changeling.Components; +using Content.Shared.Popups; +using Content.Shared.Store; +using Content.Server.Traitor.Uplink; +using Content.Shared.Mobs.Systems; +using Content.Shared.FixedPoint; +using Content.Shared.Humanoid; +using Content.Shared.IdentityManagement; +using Content.Server.Polymorph.Systems; +using Content.Server.Flash; +using Content.Shared.Polymorph; +using Content.Server.Forensics; +using Content.Shared.Actions; +using Robust.Shared.Serialization.Manager; +using Content.Shared.Alert; +using Content.Shared.Stealth.Components; +using Content.Shared.Nutrition.Components; +using Content.Shared.Tag; +using Content.Shared.StatusEffect; +using Content.Shared.Movement.Systems; +using Content.Shared.Damage.Systems; +using Content.Shared.Damage; +using Content.Server.Stunnable; +using Content.Shared.Mind; +using Robust.Shared.Player; +using System.Linq; +using Content.Shared.Preferences; +using Content.Server.Humanoid; +using Robust.Shared.Utility; +using Content.Shared.Humanoid.Markings; +using Content.Shared.Store.Components; +using Robust.Shared.Prototypes; +using Content.Server.Hands.Systems; +using Content.Server.Body.Systems; +using Robust.Shared.Audio.Systems; +using Content.Server.Emp; +using Content.Shared.DoAfter; +using Content.Server.Fluids.EntitySystems; +using Content.Server.Cuffs; +using Robust.Shared.Timing; +using Content.Server.ADT.Hallucinations; +using Content.Shared.Gibbing.Systems; +using Content.Shared.Mobs; +using Content.Server.Stealth; +using Content.Server.ADT.Store; +using Robust.Server.Containers; +using Content.Server.Ghost; +using Content.Shared.ADT.Stealth.Components; + +namespace Content.Server.Changeling.EntitySystems; + +public sealed partial class ChangelingSystem : EntitySystem +{ + #region Dependency + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly StoreSystem _store = default!; + [Dependency] private readonly ActionsSystem _action = default!; + [Dependency] private readonly UplinkSystem _uplink = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly PolymorphSystem _polymorph = default!; + [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly ISerializationManager _serialization = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly AlertsSystem _alerts = default!; + [Dependency] private readonly TagSystem _tagSystem = default!; + [Dependency] private readonly StatusEffectsSystem _status = default!; + [Dependency] private readonly EntityManager _entityManager = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!; + [Dependency] private readonly StaminaSystem _stamina = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; + [Dependency] private readonly AlertsSystem _alertsSystem = default!; + [Dependency] private readonly StunSystem _stun = default!; + [Dependency] private readonly FlashSystem _flashSystem = default!; + [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly HandsSystem _handsSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly EmpSystem _emp = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly PuddleSystem _puddle = default!; + [Dependency] private readonly CuffableSystem _cuffable = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly HallucinationsSystem _hallucinations = default!; + [Dependency] private readonly StealthSystem _stealth = default!; + + [Dependency] private readonly ContainerSystem _container = default!; + #endregion + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnMobState); + SubscribeLocalEvent(OnActionBought); + SubscribeLocalEvent(OnRefresh); + + SubscribeLocalEvent(OnShop); + SubscribeLocalEvent(OnTransform); + + SubscribeNetworkEvent(OnSelectChangelingForm); + + InitializeUsefulAbilities(); + InitializeCombatAbilities(); + InitializeSlug(); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var lingQuery = EntityQueryEnumerator(); + while (lingQuery.MoveNext(out var uid, out var comp)) + { + UpdateChangeling(uid, frameTime, comp); + } + + var slugQuery = EntityQueryEnumerator(); + while (slugQuery.MoveNext(out var uid, out var comp)) + { + UpdateChangelingHeadslug(uid, frameTime, comp); + } + } + + private void OnStartup(EntityUid uid, ChangelingComponent component, ComponentStartup args) + { + //RemComp(uid); // TODO: Исправить проблему с волосами слаймов + //RemComp(uid); + //RemComp(uid); + StealDNA(uid, component); + + RemComp(uid); + RemComp(uid); + _store.TryAddStore(uid, + new HashSet> { "EvolutionPoints" }, + new HashSet> { "ChangelingAbilities" }, + new Dictionary, FixedPoint2> { { "EvolutionPoints", 10 } }, + false, false); + } + + private void OnMapInit(EntityUid uid, ChangelingComponent component, MapInitEvent args) + { + _action.AddAction(uid, ref component.ChangelingEvolutionMenuActionEntity, component.ChangelingEvolutionMenuAction); + _action.AddAction(uid, ref component.ChangelingRegenActionEntity, component.ChangelingRegenAction); + _action.AddAction(uid, ref component.ChangelingAbsorbActionEntity, component.ChangelingAbsorbAction); + _action.AddAction(uid, ref component.ChangelingDNAStingActionEntity, component.ChangelingDNAStingAction); + _action.AddAction(uid, ref component.ChangelingDNACycleActionEntity, component.ChangelingDNACycleAction); + _action.AddAction(uid, ref component.ChangelingStasisDeathActionEntity, component.ChangelingStasisDeathAction); + + component.BasicTransferredActions.Add(component.ChangelingEvolutionMenuActionEntity); + component.BasicTransferredActions.Add(component.ChangelingRegenActionEntity); + component.BasicTransferredActions.Add(component.ChangelingAbsorbActionEntity); + component.BasicTransferredActions.Add(component.ChangelingDNAStingActionEntity); + component.BasicTransferredActions.Add(component.ChangelingDNACycleActionEntity); + component.BasicTransferredActions.Add(component.ChangelingStasisDeathActionEntity); + } + + private void OnShutdown(EntityUid uid, ChangelingComponent component, ComponentShutdown args) + { + _action.RemoveAction(uid, component.ChangelingEvolutionMenuActionEntity); + _action.RemoveAction(uid, component.ChangelingRegenActionEntity); + _action.RemoveAction(uid, component.ChangelingAbsorbActionEntity); + _action.RemoveAction(uid, component.ChangelingDNAStingActionEntity); + _action.RemoveAction(uid, component.ChangelingDNACycleActionEntity); + _action.RemoveAction(uid, component.ChangelingStasisDeathActionEntity); + } + + private void OnShop(EntityUid uid, ChangelingComponent component, ChangelingEvolutionMenuActionEvent args) + { + _store.OnInternalShop(uid); + } + + public void OnTransform(EntityUid uid, ChangelingComponent component, ChangelingTransformActionEvent args) + { + if (args.Handled) + return; + if (component.StoredDNA.Count <= 0) + { + _popup.PopupEntity(Loc.GetString("changeling-transform-fail-nodna"), uid, uid); + return; + } + + if (TryComp(uid, out var actorComponent)) + { + var ev = new RequestChangelingFormsMenuEvent(GetNetEntity(uid), ChangelingMenuType.Transform); + + foreach (var item in component.StoredDNA) + { + var netEntity = GetNetEntity(item.EntityUid); + + ev.HumanoidData.Add(new( + netEntity, + Name(item.EntityUid), + item.HumanoidAppearanceComponent.Species.Id, + BuildProfile(item))); + } + + // реализовать сортировку + RaiseNetworkEvent(ev, actorComponent.PlayerSession); + } + args.Handled = true; + } + + private void OnMobState(EntityUid uid, ChangelingComponent component, MobStateChangedEvent args) + { + if (args.NewMobState == MobState.Dead) + { + RemoveBladeEntity(uid, component); + RemoveShieldEntity(uid, component); + RemoveArmaceEntity(uid, component); + RemCompDeferred(uid); + RemCompDeferred(uid); + RemCompDeferred(uid); + component.ChameleonSkinActive = false; + component.DigitalCamouflageActive = false; + return; + } + + if (args.NewMobState != MobState.Dead && component.StasisDeathActive) + { + component.StasisDeathActive = false; + _action.SetToggled(component.ChangelingStasisDeathActionEntity, component.StasisDeathActive); + } + } + + private void OnActionBought(EntityUid uid, ChangelingComponent component, ref ActionBoughtEvent args) + { + component.BoughtActions.Add(args.ActionEntity); + } + + private void OnRefresh(EntityUid uid, ChangelingComponent component, ChangelingRefreshEvent args) + { + if (!component.CanRefresh) + { + _popup.PopupEntity(Loc.GetString("changeling-cant-refresh"), uid, uid); + return; + } + + foreach (var item in component.BoughtActions) + { + _action.RemoveAction(item); + QueueDel(item); + } + + if (!TryComp(uid, out var store)) + return; + + RemoveBladeEntity(uid, component); + RemoveShieldEntity(uid, component); + RemoveArmaceEntity(uid, component); + RemCompDeferred(uid); + RemCompDeferred(uid); + RemCompDeferred(uid); + component.ChameleonSkinActive = false; + component.DigitalCamouflageActive = false; + + if (component.LingArmorActive) + { + _inventorySystem.TryUnequip(uid, "head", true, true, false); + _inventorySystem.TryUnequip(uid, "outerClothing", true, true, false); + TryUseAbility(uid, component, 0f, false, component.LingArmorRegenCost); + component.LingArmorActive = false; + } + + component.BoughtActions.Clear(); + + _store.TrySetCurrency(new Dictionary, FixedPoint2> { { "EvolutionPoints", 10 } }, uid); + _store.TryRefreshStoreStock(uid); + component.CanRefresh = false; + + _store.UpdateUserInterface(uid, uid); + } + + private void OnSelectChangelingForm(SelectChangelingFormEvent ev) + { + var uid = GetEntity(ev.User); + var target = GetEntity(ev.Target); + var selected = GetEntity(ev.EntitySelected); + + if (!TryComp(uid, out var comp)) + return; + + if (ev.Type == ChangelingMenuType.Sting) + { + var list = comp.StoredDNA.Where(x => x.EntityUid == selected); + if (list.Count() <= 0) + return; + + var newHumanoidData = _polymorph.CopyPolymorphHumanoidData(list.First()); + + _polymorph.PolymorphEntityAsHumanoid(GetEntity(ev.Target), newHumanoidData); + + comp.StoredDNA.Remove(list.First()); + return; + } + + TransformChangeling(uid, comp, ev); + } + + public void CopyLing(EntityUid from, EntityUid to, ChangelingComponent? comp = null) + { + if (!Resolve(from, ref comp)) + return; + if (HasComp(to)) + RemComp(to); + + var newLingComponent = EnsureComp(to); + newLingComponent.Chemicals = comp.Chemicals; + newLingComponent.ChemicalsPerSecond = comp.ChemicalsPerSecond; + newLingComponent.StoredDNA = comp.StoredDNA; + newLingComponent.SelectedDNA = comp.SelectedDNA; + newLingComponent.ArmBladeActive = comp.ArmBladeActive; + newLingComponent.ChameleonSkinActive = comp.ChameleonSkinActive; + newLingComponent.LingArmorActive = comp.LingArmorActive; + newLingComponent.CanRefresh = comp.CanRefresh; + newLingComponent.LesserFormActive = comp.LesserFormActive; + newLingComponent.AbsorbedDnaModifier = comp.AbsorbedDnaModifier; + newLingComponent.BasicTransferredActions = comp.BasicTransferredActions; + newLingComponent.BoughtActions = comp.BoughtActions; + newLingComponent.LastResortUsed = comp.LastResortUsed; + RemComp(from, comp); + + if (TryComp(from, out StoreComponent? storeComp)) + { + var copiedStoreComponent = (Component)_serialization.CreateCopy(storeComp, notNullableOverride: true); + RemComp(to); + EntityManager.AddComponent(to, copiedStoreComponent); + } + + if (TryComp(from, out StealthComponent? stealthComp)) // copy over stealth status + { + if (TryComp(from, out StealthOnMoveComponent? stealthOnMoveComp)) + { + var copiedStealthComponent = (Component)_serialization.CreateCopy(stealthComp, notNullableOverride: true); + EntityManager.AddComponent(to, copiedStealthComponent); + RemComp(from, stealthComp); + + var copiedStealthOnMoveComponent = (Component)_serialization.CreateCopy(stealthOnMoveComp, notNullableOverride: true); + EntityManager.AddComponent(to, copiedStealthOnMoveComponent); + RemComp(from, stealthOnMoveComp); + } + } + + foreach (var basic in comp.BasicTransferredActions) + { + if (basic.HasValue) + _actionContainer.TransferActionWithNewAttached(basic.Value, to, to); + } + foreach (var item in comp.BoughtActions) + { + if (item.HasValue) + _actionContainer.TransferActionWithNewAttached(item.Value, to, to); + } + + } + + private HumanoidCharacterProfile BuildProfile(PolymorphHumanoidData data) + { + HumanoidCharacterAppearance hca = new(); + var humanoid = data.HumanoidAppearanceComponent; + + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.FacialHair, out var facialHair)) + if (facialHair.TryGetValue(0, out var marking)) + { + hca = hca.WithFacialHairStyleName(marking.MarkingId); + hca = hca.WithFacialHairColor(marking.MarkingColors.First()); + } + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Hair, out var hair)) + if (hair.TryGetValue(0, out var marking)) + { + hca = hca.WithHairStyleName(marking.MarkingId); + hca = hca.WithHairColor(marking.MarkingColors.First()); + } + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Head, out var head)) + hca = hca.WithMarkings(head); + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.HeadSide, out var headSide)) + hca = hca.WithMarkings(headSide); + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.HeadTop, out var headTop)) + hca = hca.WithMarkings(headTop); + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Snout, out var snout)) + hca = hca.WithMarkings(snout); + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Chest, out var chest)) + hca = hca.WithMarkings(chest); + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Arms, out var arms)) + hca = hca.WithMarkings(arms); + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Legs, out var legs)) + hca = hca.WithMarkings(legs); + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Tail, out var tail)) + hca = hca.WithMarkings(tail); + if (humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Overlay, out var overlay)) + hca = hca.WithMarkings(overlay); + + hca = hca.WithSkinColor(humanoid.SkinColor); + hca = hca.WithEyeColor(humanoid.EyeColor); + + return new HumanoidCharacterProfile(). + WithCharacterAppearance(hca). + WithSpecies(data.HumanoidAppearanceComponent.Species). + WithSex(data.HumanoidAppearanceComponent.Sex). + WithName(data.MetaDataComponent.EntityName); + } + + public void TransformChangeling(EntityUid uid, ChangelingComponent component, SelectChangelingFormEvent ev) + { + var selectedEntity = GetEntity(ev.EntitySelected); + var list = component.StoredDNA.Where(x => x.EntityUid == selectedEntity); + if (list.Count() <= 0) + return; + + var selectedHumanoidData = list.First(); + + var dnaComp = EnsureComp(uid); + + if (selectedHumanoidData.DNA == dnaComp.DNA) + { + var selfMessage = Loc.GetString("changeling-transform-fail-already", ("target", selectedHumanoidData.MetaDataComponent.EntityName)); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (component.ArmBladeActive || component.LingArmorActive || component.ChameleonSkinActive || component.MusclesActive || component.DigitalCamouflageActive) + { + var selfMessage = Loc.GetString("changeling-transform-fail-mutation"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (component.LesserFormActive && ev.Type != ChangelingMenuType.HumanForm) + { + var selfMessage = Loc.GetString("changeling-transform-fail-lesser-form"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + + if (!TryUseAbility(uid, component, component.ChemicalsCostFive)) + return; + + foreach (var item in component.BoughtActions.Where(x => + x.HasValue && + TryPrototype(x.Value, out var proto) && + proto.ID == "ActionLingLesserForm")) + { + _action.SetToggled(item, false); + } + + component.LesserFormActive = false; + + component.StoredDNA.Remove(selectedHumanoidData); + + var transformedUid = _polymorph.PolymorphEntityAsHumanoid(uid, selectedHumanoidData); + if (transformedUid == null) + return; + + var message = Loc.GetString("changeling-transform-activate", ("target", selectedHumanoidData.MetaDataComponent.EntityName)); + _popup.PopupEntity(message, transformedUid.Value, transformedUid.Value); + + CopyLing(uid, transformedUid.Value); + } + + public void StealDNA(EntityUid uid, ChangelingComponent component) + { + var newHumanoidData = _polymorph.TryRegisterPolymorphHumanoidData(uid, uid); + if (newHumanoidData == null) + return; + + if (component.StoredDNA.Count >= component.DNAStrandCap) + { + var selfMessage = Loc.GetString("changeling-dna-sting-fail-full"); + _popup.PopupEntity(selfMessage, uid, uid); + return; + } + else + { + component.StoredDNA.Add(newHumanoidData.Value); + } + + return; + } + + private bool TryStingTarget(EntityUid uid, EntityUid target) + { + if (HasComp(target)) + { + var selfMessage = Loc.GetString("changeling-sting-fail-self", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + + var targetMessage = Loc.GetString("changeling-sting-fail-target"); + _popup.PopupEntity(targetMessage, target, target); + return false; + } + + if (HasComp(target)) + { + var selfMessageFailNoDna = Loc.GetString("changeling-dna-sting-fail-nodna", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessageFailNoDna, uid, uid); + return false; + } + + if (!HasComp(target)) + { + var selfMessage = Loc.GetString("changeling-dna-fail-nohuman", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + return false; + } + + if (!HasComp(target)) + { + var selfMessage = Loc.GetString("changeling-dna-sting-fail-nodna", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + return false; + } + + if (_tagSystem.HasTag(target, "ChangelingBlacklist")) + { + var selfMessage = Loc.GetString("changeling-dna-sting-fail-nodna", ("target", Identity.Entity(target, EntityManager))); + _popup.PopupEntity(selfMessage, uid, uid); + return false; + } + + return true; + } + + public bool ChangeChemicalsAmount(EntityUid uid, float amount, ChangelingComponent? component = null, bool regenCap = true) + { + if (!Resolve(uid, ref component)) + return false; + + component.Chemicals += amount; + + if (regenCap) + float.Min(component.Chemicals, component.MaxChemicals); + + _alerts.ShowAlert(uid, _proto.Index("Chemicals"), (short)Math.Clamp(Math.Round(component.Chemicals / 10.7f), 0, 7)); + + return true; + } + + private bool TryUseAbility(EntityUid uid, ChangelingComponent component, float abilityCost, bool activated = true, float regenCost = 0f) + { + if (component.Chemicals <= Math.Abs(abilityCost) && activated) + { + _popup.PopupEntity(Loc.GetString("changeling-not-enough-chemicals"), uid, uid); + return false; + } + + if (activated) + { + ChangeChemicalsAmount(uid, abilityCost, component, false); + component.ChemicalsPerSecond -= regenCost; + } + else + { + component.ChemicalsPerSecond += regenCost; + } + + return true; + } + + public bool StealDNA(EntityUid uid, EntityUid target, ChangelingComponent component) + { + if (!HasComp(target)) + return false; + + var newHumanoidData = _polymorph.TryRegisterPolymorphHumanoidData(target); + if (newHumanoidData == null) + return false; + + else if (component.StoredDNA.Count >= component.DNAStrandCap) + { + var selfMessage = Loc.GetString("changeling-dna-sting-fail-full"); + _popup.PopupEntity(selfMessage, uid, uid); + return false; + } + + else + { + component.StoredDNA.Add(newHumanoidData.Value); + } + + return true; + } + + private void UpdateChangeling(EntityUid uid, float frameTime, ChangelingComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return; + + comp.Accumulator += frameTime; + + if (comp.Accumulator <= 1) + return; + comp.Accumulator -= 1; + + if (comp.Chemicals < comp.MaxChemicals) + ChangeChemicalsAmount(uid, _mobState.IsDead(uid) ? comp.ChemicalsPerSecond / 2 : comp.ChemicalsPerSecond, comp, regenCap: true); + + if (comp.MusclesActive) + _stamina.TakeStaminaDamage(uid, comp.MusclesStaminaDamage, null, null, null, false); + + } +} diff --git a/Content.Server/ADT/GameTicking/Rules/ChangelingRuleSystem.cs b/Content.Server/ADT/GameTicking/Rules/ChangelingRuleSystem.cs new file mode 100644 index 00000000000..2638ba4d84a --- /dev/null +++ b/Content.Server/ADT/GameTicking/Rules/ChangelingRuleSystem.cs @@ -0,0 +1,72 @@ +using Content.Server.Antag; +using Content.Server.GameTicking.Rules.Components; +using Content.Server.Mind; +using Content.Server.Objectives; +using Content.Shared.Roles; +using Robust.Shared.Prototypes; +using System.Text; +using Content.Shared.Changeling.Components; +using Content.Shared.NPC.Systems; +using Content.Shared.NPC.Prototypes; +using Content.Shared.IdentityManagement; +using Content.Shared.Tag; + +namespace Content.Server.GameTicking.Rules; + +public sealed partial class ChangelingRuleSystem : GameRuleSystem +{ + [Dependency] private readonly MindSystem _mind = default!; + [Dependency] private readonly AntagSelectionSystem _antag = default!; + [Dependency] private readonly NpcFactionSystem _npcFaction = default!; + [Dependency] private readonly SharedRoleSystem _role = default!; + [Dependency] private readonly TagSystem _tag = default!; + + public readonly ProtoId SyndicateFactionId = "Syndicate"; + + public readonly ProtoId NanotrasenFactionId = "NanoTrasen"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAntagSelect); + // SubscribeLocalEvent(OnObjectivesTextPrepend); + } + + private void OnAntagSelect(Entity ent, ref AfterAntagEntitySelectedEvent args) + { + TryMakeChangeling(args.EntityUid, ent.Comp); + } + + public bool TryMakeChangeling(EntityUid target, ChangelingRuleComponent rule) + { + if (!_mind.TryGetMind(target, out var mindId, out var mind)) + return false; + if (_tag.HasTag(target, "ChangelingBlacklist")) + return false; + + // briefing + if (HasComp(target)) + { + _antag.SendBriefing(target, Loc.GetString("changeling-role-greeting", ("character-name", Identity.Entity(target, EntityManager))), Color.Red, rule.ChangelingStartSound); + + _role.MindAddRole(mindId, "MindRoleChangeling", mind, true); + } + + _npcFaction.RemoveFaction(target, NanotrasenFactionId, false); + _npcFaction.AddFaction(target, SyndicateFactionId); + + // Ensure Changeling component and role + EnsureComp(target); + + rule.Minds.Add(mindId); + + return true; + } + + + // public void OnObjectivesTextPrepend(Entity ent, ref ObjectivesTextPrependEvent args) + // { + // args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords))); + // } +} diff --git a/Content.Server/ADT/GameTicking/Rules/Components/ChangelingRuleComponent.cs b/Content.Server/ADT/GameTicking/Rules/Components/ChangelingRuleComponent.cs new file mode 100644 index 00000000000..2491438970b --- /dev/null +++ b/Content.Server/ADT/GameTicking/Rules/Components/ChangelingRuleComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; +using Content.Shared.Store; + +namespace Content.Server.GameTicking.Rules.Components; + +[RegisterComponent, Access(typeof(ChangelingRuleSystem))] +public sealed partial class ChangelingRuleComponent : Component +{ + public readonly List Minds = new(); + + /// + /// Path to changeling start sound. + /// + [DataField] + public SoundSpecifier ChangelingStartSound = new SoundPathSpecifier("/Audio/Ambience/Antag/changeling_start.ogg"); +} diff --git a/Content.Server/ADT/Objectives/Components/AbsorbDnaConditionComponent.cs b/Content.Server/ADT/Objectives/Components/AbsorbDnaConditionComponent.cs new file mode 100644 index 00000000000..cba90d4a531 --- /dev/null +++ b/Content.Server/ADT/Objectives/Components/AbsorbDnaConditionComponent.cs @@ -0,0 +1,25 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// Requires that the player is on the emergency shuttle's grid when docking to CentCom. +/// +[RegisterComponent, Access(typeof(AbsorbDnaConditionSystem))] +public sealed partial class AbsorbDnaConditionComponent : Component +{ + [DataField] + public int AbsorbDnaCount = 4; + + [DataField] + public int MaxDnaCount = 4; + + [DataField] + public int MinDnaCount = 2; + + [DataField(required: true)] + public LocId ObjectiveText; + [DataField(required: true)] + public LocId DescriptionText; + +} diff --git a/Content.Server/ADT/Objectives/Components/PickRandomDnaComponent.cs b/Content.Server/ADT/Objectives/Components/PickRandomDnaComponent.cs new file mode 100644 index 00000000000..9b85ae2fc03 --- /dev/null +++ b/Content.Server/ADT/Objectives/Components/PickRandomDnaComponent.cs @@ -0,0 +1,11 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// Sets the target for to a random person. +/// +[RegisterComponent, Access(typeof(StealPersonalityConditionSystem))] +public sealed partial class PickRandomDnaComponent : Component +{ +} diff --git a/Content.Server/ADT/Objectives/Components/PickRandomHeadDnaComponent.cs b/Content.Server/ADT/Objectives/Components/PickRandomHeadDnaComponent.cs new file mode 100644 index 00000000000..d8fe0ecd714 --- /dev/null +++ b/Content.Server/ADT/Objectives/Components/PickRandomHeadDnaComponent.cs @@ -0,0 +1,12 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// Sets the target for to a random head. +/// If there are no heads it will fallback to any person. +/// +[RegisterComponent, Access(typeof(StealPersonalityConditionSystem))] +public sealed partial class PickRandomHeadDnaComponent : Component +{ +} diff --git a/Content.Server/ADT/Objectives/Components/StealPersonalityConditionComponent.cs b/Content.Server/ADT/Objectives/Components/StealPersonalityConditionComponent.cs new file mode 100644 index 00000000000..95b60ca200c --- /dev/null +++ b/Content.Server/ADT/Objectives/Components/StealPersonalityConditionComponent.cs @@ -0,0 +1,20 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// Requires that a target dies or, if is false, is not on the emergency shuttle. +/// Depends on to function. +/// +[RegisterComponent, Access(typeof(StealPersonalityConditionSystem))] +public sealed partial class StealPersonalityConditionComponent : Component +{ + /// + /// Whether the target must be truly dead, ignores missing evac. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool RequireDead = false; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string? ReqiredDNA; +} diff --git a/Content.Server/ADT/Objectives/Systems/AbsorbDnaConditionSystem.cs b/Content.Server/ADT/Objectives/Systems/AbsorbDnaConditionSystem.cs new file mode 100644 index 00000000000..2681adcfa08 --- /dev/null +++ b/Content.Server/ADT/Objectives/Systems/AbsorbDnaConditionSystem.cs @@ -0,0 +1,75 @@ +using Content.Server.Objectives.Components; +using Content.Server.Shuttles.Systems; +using Content.Shared.Changeling.Components; +using Robust.Shared.Random; +using Content.Shared.Mind; +using Content.Shared.Objectives.Components; +using Content.Shared.Mobs.Systems; + +namespace Content.Server.Objectives.Systems; + +public sealed class AbsorbDnaConditionSystem : EntitySystem +{ + [Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!; + [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly MetaDataSystem _metaData = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAssigned); + SubscribeLocalEvent(OnAfterAssign); + + SubscribeLocalEvent(OnGetProgress); + } + + private void OnAssigned(Entity condition, ref ObjectiveAssignedEvent args) + { + var maxSize = condition.Comp.MaxDnaCount; + + var minSize = condition.Comp.MinDnaCount; + + condition.Comp.AbsorbDnaCount = _random.Next(minSize, maxSize); + + } + + public void OnAfterAssign(Entity condition, ref ObjectiveAfterAssignEvent args) + { + var title = Loc.GetString(condition.Comp.ObjectiveText, ("count", condition.Comp.AbsorbDnaCount)); + + var description = Loc.GetString(condition.Comp.DescriptionText, ("count", condition.Comp.AbsorbDnaCount)); + + _metaData.SetEntityName(condition.Owner, title, args.Meta); + _metaData.SetEntityDescription(condition.Owner, description, args.Meta); + + } + private void OnGetProgress(EntityUid uid, AbsorbDnaConditionComponent comp, ref ObjectiveGetProgressEvent args) + { + if (args.Mind.OwnedEntity != null) + { + var ling = args.Mind.OwnedEntity.Value; + args.Progress = GetProgress(ling, args.MindId, args.Mind, comp); + } + else + args.Progress = 0f; + } + + private float GetProgress(EntityUid uid, EntityUid mindId, MindComponent mind, AbsorbDnaConditionComponent comp) + { + // Не генокрад - не выполнил цель (да ладно.) + if (!TryComp(uid, out var ling)) + return 0f; + + // Умер - не выполнил цель. + if (mind.OwnedEntity == null || _mind.IsCharacterDeadIc(mind)) + return 0f; + + // Подсчёт требуемых и имеющихся ДНК + var count = ling.AbsorbedDnaModifier; + var result = count / comp.AbsorbDnaCount; + result = Math.Clamp(result, 0, 1); + return result; + } +} diff --git a/Content.Server/ADT/Objectives/Systems/StealPersonalityConditionSystem.cs b/Content.Server/ADT/Objectives/Systems/StealPersonalityConditionSystem.cs new file mode 100644 index 00000000000..d0860454c2c --- /dev/null +++ b/Content.Server/ADT/Objectives/Systems/StealPersonalityConditionSystem.cs @@ -0,0 +1,146 @@ +using Content.Server.Objectives.Components; +using Content.Server.Shuttles.Systems; +using Content.Shared.CCVar; +using Content.Shared.Mind; +using Content.Shared.Objectives.Components; +using Content.Shared.Roles.Jobs; +using Robust.Shared.Configuration; +using Robust.Shared.Random; +using Content.Server.Forensics; +using Content.Shared.Cuffs.Components; + +namespace Content.Server.Objectives.Systems; + +/// +/// Handles kill person condition logic and picking random kill targets. +/// +public sealed class StealPersonalityConditionSystem : EntitySystem +{ + [Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!; + [Dependency] private readonly IConfigurationManager _config = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedJobSystem _job = default!; + [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly TargetObjectiveSystem _target = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetProgress); + + SubscribeLocalEvent(OnPersonAssigned); + + SubscribeLocalEvent(OnHeadAssigned); + } + + private void OnGetProgress(EntityUid uid, StealPersonalityConditionComponent comp, ref ObjectiveGetProgressEvent args) + { + if (!_target.GetTarget(uid, out var target)) + return; + + args.Progress = GetProgress(args.MindId, args.Mind, target.Value, comp.ReqiredDNA ?? "", comp.RequireDead); + } + + private void OnPersonAssigned(EntityUid uid, PickRandomDnaComponent comp, ref ObjectiveAssignedEvent args) + { + // invalid objective prototype + if (!TryComp(uid, out var target)) + { + args.Cancelled = true; + return; + } + + // target already assigned + if (target.Target != null) + return; + + // no other humans to kill + var allHumans = _mind.GetAliveHumansExcept(args.MindId); + if (allHumans.Count == 0) + { + args.Cancelled = true; + return; + } + + if (!TryComp(uid, out var reqiredDna)) + { + args.Cancelled = true; + return; + } + + if (TryComp(uid, out var pers)) + pers.ReqiredDNA = reqiredDna.DNA; + } + + private void OnHeadAssigned(EntityUid uid, PickRandomHeadDnaComponent comp, ref ObjectiveAssignedEvent args) + { + // invalid prototype + if (!TryComp(uid, out var target)) + { + args.Cancelled = true; + return; + } + + // target already assigned + if (target.Target != null) + return; + + // no other humans to kill + var allHumans = _mind.GetAliveHumansExcept(args.MindId); + if (allHumans.Count == 0) + { + args.Cancelled = true; + return; + } + + var allHeads = new List(); + foreach (var mind in allHumans) + { + // RequireAdminNotify used as a cheap way to check for command department + if (_job.MindTryGetJob(mind, out var prototype) && prototype.RequireAdminNotify) + allHeads.Add(mind); + } + + if (allHeads.Count == 0) + allHeads = allHumans; // fallback to non-head target + + if (!TryComp(uid, out var reqiredDna)) + { + args.Cancelled = true; + return; + } + if (TryComp(uid, out var pers)) + pers.ReqiredDNA = reqiredDna.DNA; + } + + private float GetProgress(EntityUid mindId, MindComponent mind, EntityUid target, string targetDna, bool requireDead) + { + // Генокрада не существует? + if (!TryComp(mindId, out _)) + return 0f; + + // Если генокрад в форме обезьяны, например + if (!TryComp(mind.CurrentEntity, out var dna)) + return 0f; + + if (_emergencyShuttle.ShuttlesLeft && _emergencyShuttle.IsTargetEscaping(mind.CurrentEntity.Value)) + { + if (_emergencyShuttle.IsTargetEscaping(target)) + return 0f; + if (dna.DNA == targetDna && TryComp(mind.CurrentEntity, out var cuffed) && cuffed.CuffedHandCount > 0) + return 1f; + } + else + { + // ДНК соответствует, но нужно ещё улететь и убить цель + if (targetDna == dna.DNA) + return 0.5f; + else + return 0f; + } + + // Эвак ждёт, а цель ещё не пришла к нему. Ещё и жива, падаль. + return _emergencyShuttle.EmergencyShuttleArrived ? 0.5f : 0f; + } +} diff --git a/Content.Server/ADT/Store/ActionBoughtEvent.cs b/Content.Server/ADT/Store/ActionBoughtEvent.cs new file mode 100644 index 00000000000..c43b88ccb10 --- /dev/null +++ b/Content.Server/ADT/Store/ActionBoughtEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Server.ADT.Store; + +[ByRefEvent] +public record struct ActionBoughtEvent(EntityUid? ActionEntity); diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs index d755a54bf8f..13e93af0277 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs @@ -36,6 +36,11 @@ public sealed partial class AdminVerbSystem [ValidatePrototypeId] private const string PirateGearId = "PirateGear"; + // ADT-Changeling-Tweak-Start + [ValidatePrototypeId] + private const string DefaultChangelingRule = "ChangelingGameRule"; + // ADT-Changeling-Tweak-End + // All antag verbs have names so invokeverb works. private void AddAntagVerbs(GetVerbsEvent args) { @@ -166,5 +171,21 @@ private void AddAntagVerbs(GetVerbsEvent args) Message = Loc.GetString("admin-verb-make-heretic"), }; args.Verbs.Add(heretic); + + // ADT-Changeling-Tweak-Start + Verb changeling = new() + { + Text = Loc.GetString("admin-verb-text-make-changeling"), + Category = VerbCategory.Antag, + Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/ADT/Changeling/Objects/armblade.rsi"), "icon"), + Act = () => + { + _antag.ForceMakeAntag(targetPlayer, DefaultChangelingRule); + }, + Impact = LogImpact.High, + Message = Loc.GetString("admin-verb-make-changeling"), + }; + args.Verbs.Add(changeling); + // ADT-Changeling-Tweak-End } } diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index 9a27de3b1d9..58d29dd3d37 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -519,7 +519,7 @@ public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaComma if (mind.PreventGhosting) { - if (mind.Session != null) // Logging is suppressed to prevent spam from ghost attempts caused by movement attempts + if (mind.Session != null && mind.PreventGhostingSendMessage) // Logging is suppressed to prevent spam from ghost attempts caused by movement attempts // ADT tweak { _chatManager.DispatchServerMessage(mind.Session, Loc.GetString("comp-mind-ghosting-prevented"), true); diff --git a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs index 92944b2b15f..0407628e1d6 100644 --- a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs +++ b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs @@ -1,26 +1,42 @@ -using Content.Shared.ADT.SpeechBarks; +using Content.Shared.Examine; // ADT-Changeling-Tweak +using System.Linq; // ADT-Changeling-Tweak +using Content.Shared.Decals; // ADT-Changeling-Tweak using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Prototypes; +using Content.Shared.IdentityManagement; // ADT-Changeling-Tweak using Content.Shared.Preferences; using Content.Shared.Verbs; using Robust.Shared.GameObjects.Components.Localization; +using Robust.Shared.Prototypes; // ADT-Changeling-Tweak namespace Content.Server.Humanoid; public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem { [Dependency] private readonly MarkingManager _markingManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; // ADT-Changeling-Tweak public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnMarkingsSet); SubscribeLocalEvent(OnBaseLayersSet); SubscribeLocalEvent>(OnVerbsRequest); + //SubscribeLocalEvent(OnExamined); } + // ADT-Changeling-Tweak-Start + private void OnExamined(EntityUid uid, HumanoidAppearanceComponent component, ExaminedEvent args) + { + var identity = Identity.Entity(uid, EntityManager); + var species = GetSpeciesRepresentation(component.Species).ToLower(); + var age = GetAgeRepresentation(component.Species, component.Age); + + args.PushText(Loc.GetString("humanoid-appearance-component-examine", ("user", identity), ("age", age), ("species", species))); + } + // ADT-Changeling-Tweak-End + // this was done enough times that it only made sense to do it here /// @@ -30,33 +46,50 @@ public override void Initialize() /// Target entity to apply the source entity's appearance to. /// Source entity's humanoid component. /// Target entity's humanoid component. - public void CloneAppearance(EntityUid source, EntityUid target, HumanoidAppearanceComponent? sourceHumanoid = null, - HumanoidAppearanceComponent? targetHumanoid = null) + + // ADT-Changeling-Tweak-Start + public void SetAppearance(HumanoidAppearanceComponent sourceHumanoid, HumanoidAppearanceComponent targetHumanoid) { - if (!Resolve(source, ref sourceHumanoid) || !Resolve(target, ref targetHumanoid)) - { - return; - } targetHumanoid.Species = sourceHumanoid.Species; targetHumanoid.SkinColor = sourceHumanoid.SkinColor; targetHumanoid.EyeColor = sourceHumanoid.EyeColor; targetHumanoid.Age = sourceHumanoid.Age; - SetSex(target, sourceHumanoid.Sex, false, targetHumanoid); + SetSex(targetHumanoid.Owner, sourceHumanoid.Sex, false, targetHumanoid); targetHumanoid.CustomBaseLayers = new(sourceHumanoid.CustomBaseLayers); targetHumanoid.MarkingSet = new(sourceHumanoid.MarkingSet); - SetTTSVoice(target, sourceHumanoid.Voice, targetHumanoid); // Corvax-TTS - if (TryComp(source, out var barks)) - SetBarkData(target, barks.Sound, barks.BarkPitch, barks.BarkLowVar, barks.BarkHighVar); // ADT Barks + SetTTSVoice(targetHumanoid.Owner, sourceHumanoid.Voice, targetHumanoid); // Corvax-TTS targetHumanoid.Gender = sourceHumanoid.Gender; - if (TryComp(target, out var grammar)) + if (TryComp(targetHumanoid.Owner, out var grammar)) { grammar.Gender = sourceHumanoid.Gender; } - Dirty(target, targetHumanoid); + Dirty(targetHumanoid.Owner, targetHumanoid); + } + // ADT-Changeling-Tweak-End + + /// + /// Clones a humanoid's appearance to a target mob, provided they both have humanoid components. + /// + /// Source entity to fetch the original appearance from. + /// Target entity to apply the source entity's appearance to. + /// Source entity's humanoid component. + /// Target entity's humanoid component. + + // ADT-Changeling-Tweak-Start + public void CloneAppearance(EntityUid source, EntityUid target, HumanoidAppearanceComponent? sourceHumanoid = null, + HumanoidAppearanceComponent? targetHumanoid = null) + { + if (!Resolve(source, ref sourceHumanoid) || !Resolve(target, ref targetHumanoid)) + { + return; + } + + SetAppearance(sourceHumanoid, targetHumanoid); } + // ADT-Changeling-Tweak-End /// /// Removes a marking from a humanoid by ID. @@ -155,4 +188,44 @@ public void SetMarkingColor(EntityUid uid, MarkingCategories category, int index Dirty(uid, humanoid); } + + // ADT-Changeling-Tweak-Start + /// + /// Takes ID of the species prototype, returns UI-friendly name of the species. + /// + public string GetSpeciesRepresentation(string speciesId) + { + if (_prototypeManager.TryIndex(speciesId, out var species)) + { + return Loc.GetString(species.Name); + } + else + { + return Loc.GetString("humanoid-appearance-component-unknown-species"); + } + } + + public string GetAgeRepresentation(string species, int age) + { + _prototypeManager.TryIndex(species, out var speciesPrototype); + + if (speciesPrototype == null) + { + Logger.Error("Tried to get age representation of species that couldn't be indexed: " + species); + return Loc.GetString("identity-age-young"); + } + + if (age < speciesPrototype.YoungAge) + { + return Loc.GetString("identity-age-young"); + } + + if (age < speciesPrototype.OldAge) + { + return Loc.GetString("identity-age-middle-aged"); + } + + return Loc.GetString("identity-age-old"); + } + // ADT-Changeling-Tweak-End } diff --git a/Content.Server/Inventory/ServerInventorySystem.cs b/Content.Server/Inventory/ServerInventorySystem.cs index e3783753bbc..a97697d6129 100644 --- a/Content.Server/Inventory/ServerInventorySystem.cs +++ b/Content.Server/Inventory/ServerInventorySystem.cs @@ -31,8 +31,8 @@ public void TransferEntityInventories(Entity source, Entity var enumerator = new InventorySlotEnumerator(source.Comp); while (enumerator.NextItem(out var item, out var slot)) { - if (TryUnequip(source, slot.Name, true, true, inventory: source.Comp)) - TryEquip(target, item, slot.Name , true, true, inventory: target.Comp); + if (!TryEquip(target, item, slot.Name , true, true, inventory: target.Comp)) // ADT-Changeling-Tweak + TryUnequip(source, slot.Name, true, true, inventory: source.Comp); // ADT-Changeling-Tweak } } } diff --git a/Content.Server/Medical/DefibrillatorSystem.cs b/Content.Server/Medical/DefibrillatorSystem.cs index da7a251c06a..90a1b52e299 100644 --- a/Content.Server/Medical/DefibrillatorSystem.cs +++ b/Content.Server/Medical/DefibrillatorSystem.cs @@ -24,7 +24,11 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Player; using Robust.Shared.Timing; -using Content.Shared.ADT.Atmos.Miasma; //ADT-Medicine +using Content.Shared.ADT.Atmos.Miasma; +using Content.Shared.Changeling.Components; +using Robust.Server.Containers; +using System.Linq; +using Content.Server.Resist; //ADT-Medicine namespace Content.Server.Medical; @@ -48,6 +52,7 @@ public sealed class DefibrillatorSystem : EntitySystem [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly ContainerSystem _container = default!; /// public override void Initialize() @@ -148,6 +153,28 @@ public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorCo ICommonSession? session = null; var dead = true; + // ADT Changeling start + if (TryComp(target, out var slug)) + { + _chatManager.TrySendInGameICMessage(uid, Loc.GetString("defibrillator-changeling-slug"), + InGameICChatType.Speak, true); + + var headslug = slug.Container.ContainedEntities.First(); + _container.EmptyContainer(slug.Container, true); + _electrocution.TryDoElectrocution(headslug, null, component.ZapDamage, component.WritheDuration, true, ignoreInsulation: true); + if (TryComp(headslug, out var slugComp)) + { + slugComp.Accumulator = 0; + slugComp.Alerted = false; + slugComp.Container = null; + } + EnsureComp(headslug); + + RemComp(target, slug); + return; + } + // ADT Changeling end + if (_rotting.IsRotten(target)) { _chatManager.TrySendInGameICMessage(uid, Loc.GetString("defibrillator-rotten"), diff --git a/Content.Server/Objectives/Components/TargetObjectiveComponent.cs b/Content.Server/Objectives/Components/TargetObjectiveComponent.cs index c0cd521bc7c..26233d8f3e7 100644 --- a/Content.Server/Objectives/Components/TargetObjectiveComponent.cs +++ b/Content.Server/Objectives/Components/TargetObjectiveComponent.cs @@ -18,4 +18,7 @@ public sealed partial class TargetObjectiveComponent : Component /// [DataField, ViewVariables(VVAccess.ReadWrite)] public EntityUid? Target; + + [DataField, ViewVariables(VVAccess.ReadWrite)] // ADT-Changeling-Tweak + public string? TargetDNA; } diff --git a/Content.Server/Objectives/Systems/TargetObjectiveSystem.cs b/Content.Server/Objectives/Systems/TargetObjectiveSystem.cs index 82ebd28ca9e..81d9c1965cf 100644 --- a/Content.Server/Objectives/Systems/TargetObjectiveSystem.cs +++ b/Content.Server/Objectives/Systems/TargetObjectiveSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Roles.Jobs; using Robust.Shared.GameObjects; using System.Diagnostics.CodeAnalysis; +using Content.Server.Forensics; // ADT-Changeling-Tweak namespace Content.Server.Objectives.Systems; diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.cs index 08c94bc5d0a..96abd3c2a88 100644 --- a/Content.Server/Polymorph/Systems/PolymorphSystem.cs +++ b/Content.Server/Polymorph/Systems/PolymorphSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Actions; using Content.Server.Humanoid; +using Content.Shared.Humanoid; // ADT-Changeling-Tweak using Content.Server.Inventory; using Content.Server.Mind.Commands; using Content.Server.Nutrition; @@ -22,6 +23,9 @@ using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Utility; +using Content.Server.Forensics; // ADT-Changeling-Tweak +using Content.Shared.Mindshield.Components; // ADT-Changeling-Tweak +using Robust.Shared.Serialization.Manager; // ADT-Changeling-Tweak namespace Content.Server.Polymorph.Systems; @@ -45,7 +49,7 @@ public sealed partial class PolymorphSystem : EntitySystem [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly SharedMindSystem _mindSystem = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; - + [Dependency] private readonly ISerializationManager _serialization = default!; // ADT-Changeling-Tweak private const string RevertPolymorphId = "ActionRevertPolymorph"; public override void Initialize() @@ -255,17 +259,89 @@ private void OnDestruction(Entity ent, ref Destructi { _humanoid.CloneAppearance(uid, child); } + // ADT-Changeling-Tweak-Start + if (_mindSystem.TryGetMind(uid, out var mindId, out var mind)) + _mindSystem.TransferTo(mindId, child, mind: mind); + SendToPausedMap(uid, targetTransformComp); + + return child; + } + + /// + /// Polymorphs the target entity into an exact copy of the given PolymorphHumanoidData + /// + /// The entity that will be transformed + /// The humanoid data + public EntityUid? PolymorphEntityAsHumanoid(EntityUid uid, PolymorphHumanoidData data) + { + var targetTransformComp = Transform(uid); + var child = data.EntityUid; + + RetrievePausedEntity(uid, child); + + if (TryComp(child, out var humanoidAppearance)) + _humanoid.SetAppearance(data.HumanoidAppearanceComponent, humanoidAppearance); + + if (TryComp(child, out var dnaComp)) + dnaComp.DNA = data.DNA; + + //Transfers all damage from the original to the new one + if (TryComp(child, out var damageParent) + && _mobThreshold.GetScaledDamage(uid, child, out var damage) + && damage != null) + { + _damageable.SetDamage(child, damageParent, damage); + } + _inventory.TransferEntityInventories(uid, child); // transfer the inventory all the time + foreach (var hand in _hands.EnumerateHeld(uid)) + { + if (!_hands.TryPickupAnyHand(child, hand)) + _hands.TryDrop(uid, hand, checkActionBlocker: false); + } + // ADT-Changeling-Tweak-End if (_mindSystem.TryGetMind(uid, out var mindId, out var mind)) _mindSystem.TransferTo(mindId, child, mind: mind); - //Ensures a map to banish the entity to EnsurePausedMap(); if (PausedMap != null) _transform.SetParent(uid, targetTransformComp, PausedMap.Value); return child; } + // ADT-Changeling-Tweak-Start + /// + /// Sends the given entity to a pauses map + /// + public void SendToPausedMap(EntityUid uid, TransformComponent transform) + { + //Ensures a map to banish the entity to + EnsurePausedMap(); + if (PausedMap != null) + _transform.SetParent(uid, transform, PausedMap.Value); + } + + /// + /// Retrieves a paused entity (target) at the user's position + /// + private void RetrievePausedEntity(EntityUid user, EntityUid target) + { + if (Deleted(user)) + return; + if (Deleted(target)) + return; + + var targetTransform = Transform(target); + var userTransform = Transform(user); + + _transform.SetParent(target, targetTransform, user); + targetTransform.Coordinates = userTransform.Coordinates; + targetTransform.LocalRotation = userTransform.LocalRotation; + + if (_container.TryGetContainingContainer(user, out var cont)) + _container.Insert(target, cont); + } + // ADT-Changeling-Tweak-End /// /// Reverts a polymorphed entity back into its original form @@ -387,6 +463,92 @@ public void RemovePolymorphAction(ProtoId id, Entity + /// Registers PolymorphHumanoidData from an EntityUid, provived they have all the needed components + /// + /// The source that the humanoid data is referencing from + public PolymorphHumanoidData? TryRegisterPolymorphHumanoidData(EntityUid source) + { + var newHumanoidData = new PolymorphHumanoidData(); + + if (!TryComp(source, out var targetMeta)) + return null; + if (!TryPrototype(source, out var prototype, targetMeta)) + return null; + if (!TryComp(source, out var dnaComp)) + return null; + if (!TryComp(source, out var targetHumanoidAppearance)) + return null; + + + newHumanoidData.EntityPrototype = prototype; + newHumanoidData.MetaDataComponent = targetMeta; + newHumanoidData.HumanoidAppearanceComponent = _serialization.CreateCopy(targetHumanoidAppearance, notNullableOverride: true); + newHumanoidData.DNA = dnaComp.DNA; + + var targetTransformComp = Transform(source); + + var newEntityUid = Spawn(newHumanoidData.EntityPrototype.ID, targetTransformComp.Coordinates); + var newEntityUidTransformComp = Transform(newEntityUid); + + if (TryComp(source, out MindShieldComponent? mindshieldComp)) // copy over mindshield status + { + var copiedMindshieldComp = (Component) _serialization.CreateCopy(mindshieldComp, notNullableOverride: true); + EntityManager.AddComponent(newEntityUid, copiedMindshieldComp); + } + + SendToPausedMap(newEntityUid, newEntityUidTransformComp); + + newHumanoidData.EntityUid = newEntityUid; + _metaData.SetEntityName(newEntityUid, targetMeta.EntityName); + + return newHumanoidData; + } + + /// + /// Registers PolymorphHumanoidData from an EntityUid, provived they have all the needed components. This allows you to add a uid as the HumanoidData's EntityUid variable. Does not send the given uid to the pause map. + /// + /// The source that the humanoid data is referencing from + /// The uid that will become the newHumanoidData's EntityUid + public PolymorphHumanoidData? TryRegisterPolymorphHumanoidData(EntityUid source, EntityUid uid) + { + var newHumanoidData = new PolymorphHumanoidData(); + + if (!TryComp(source, out var targetMeta)) + return null; + if (!TryPrototype(source, out var prototype, targetMeta)) + return null; + if (!TryComp(source, out var dnaComp)) + return null; + if (!TryComp(source, out var targetHumanoidAppearance)) + return null; + + newHumanoidData.EntityPrototype = prototype; + newHumanoidData.MetaDataComponent = targetMeta; + newHumanoidData.HumanoidAppearanceComponent = _serialization.CreateCopy(targetHumanoidAppearance, notNullableOverride: true);; + newHumanoidData.DNA = dnaComp.DNA; + newHumanoidData.EntityUid = uid; + + return newHumanoidData; + } + + public PolymorphHumanoidData CopyPolymorphHumanoidData(PolymorphHumanoidData data) + { + var newHumanoidData = new PolymorphHumanoidData(); + var ent = Spawn(data.EntityPrototype.ID); + SendToPausedMap(ent, Transform(ent)); + + newHumanoidData.EntityPrototype = data.EntityPrototype; + newHumanoidData.MetaDataComponent = data.MetaDataComponent; + newHumanoidData.HumanoidAppearanceComponent = _serialization.CreateCopy(data.HumanoidAppearanceComponent, notNullableOverride: true);; + newHumanoidData.DNA = data.DNA; + newHumanoidData.EntityUid = ent; + _metaData.SetEntityName(ent, data.MetaDataComponent.EntityName); + return newHumanoidData; + } + // ADT-Changeling-Tweak-End } // goob edit diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.cs index dec4d191e03..ba28d57a98c 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.cs @@ -180,7 +180,7 @@ private bool TryUseAbility(EntityUid uid, RevenantComponent component, FixedPoin var tileref = Transform(uid).Coordinates.GetTileRef(); if (tileref != null) { - if(_physics.GetEntitiesIntersectingBody(uid, (int) CollisionGroup.Impassable).Count > 0) + if (_physics.GetEntitiesIntersectingBody(uid, (int) CollisionGroup.Impassable).Count > 0) { _popup.PopupEntity(Loc.GetString("revenant-in-solid"), uid, uid); return false; @@ -197,9 +197,7 @@ private bool TryUseAbility(EntityUid uid, RevenantComponent component, FixedPoin private void OnShop(EntityUid uid, RevenantComponent component, RevenantShopActionEvent args) { - if (!TryComp(uid, out var store)) - return; - _store.ToggleUi(uid, uid, store); + _store.OnInternalShop(uid); // ADT-Changeling-Tweak } private void OnSinguloConsumeAttempt(EntityUid uid, RevenantComponent component, ref EventHorizonAttemptConsumeEntityEvent args) // ADT diff --git a/Content.Server/Store/Systems/StoreSystem.Listings.cs b/Content.Server/Store/Systems/StoreSystem.Listings.cs index 4699ec7b669..2e39485128c 100644 --- a/Content.Server/Store/Systems/StoreSystem.Listings.cs +++ b/Content.Server/Store/Systems/StoreSystem.Listings.cs @@ -2,11 +2,13 @@ using Content.Shared.Store; using Content.Shared.Store.Components; using Robust.Shared.Prototypes; +using Content.Shared.Actions; // ADT-Changeling-Tweak namespace Content.Server.Store.Systems; public sealed partial class StoreSystem { + /// /// Refreshes all listings on a store. /// Do not use if you don't know what you're doing. diff --git a/Content.Server/Store/Systems/StoreSystem.Ui.cs b/Content.Server/Store/Systems/StoreSystem.Ui.cs index e73b03cfe48..9512f58df02 100644 --- a/Content.Server/Store/Systems/StoreSystem.Ui.cs +++ b/Content.Server/Store/Systems/StoreSystem.Ui.cs @@ -1,6 +1,8 @@ using System.Linq; using Content.Server.Actions; using Content.Server.Administration.Logs; +using Content.Server.ADT.Store; // ADT-Changeling-Tweak +using Content.Server.Botany.Components; // ADT-Changeling-Tweak using Content.Server.Heretic.EntitySystems; using Content.Server.PDA.Ringer; using Content.Server.Stack; @@ -218,11 +220,16 @@ private void OnBuyRequest(EntityUid uid, StoreComponent component, StoreBuyListi EntityUid? actionId; // I guess we just allow duplicate actions? // Allow duplicate actions and just have a single list buy for the buy-once ones. - if (!_mind.TryGetMind(buyer, out var mind, out _)) + if (!_mind.TryGetMind(buyer, out var mind, out _) || !listing.MindAction) // ADT-Changeling-Tweak actionId = _actions.AddAction(buyer, listing.ProductAction); else actionId = _actionContainer.AddAction(mind, listing.ProductAction); + // ADT start + var actionEv = new ActionBoughtEvent(actionId); + RaiseLocalEvent(buyer, ref actionEv); + // ADT end + // Add the newly bought action entity to the list of bought entities // And then add that action entity to the relevant product upgrade listing, if applicable if (actionId != null) diff --git a/Content.Server/Store/Systems/StoreSystem.cs b/Content.Server/Store/Systems/StoreSystem.cs index 7bdf550301e..6c9769757ab 100644 --- a/Content.Server/Store/Systems/StoreSystem.cs +++ b/Content.Server/Store/Systems/StoreSystem.cs @@ -10,6 +10,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; using System.Linq; +using Content.Shared.Store; // ADT-Changeling-Tweak namespace Content.Server.Store.Systems; @@ -105,6 +106,18 @@ private void OnImplantActivate(EntityUid uid, StoreComponent component, OpenUpli ToggleUi(args.Performer, uid, component); } + /// + /// Toggles the shop UI if the given entityuid has a shop component. + /// Used for things such as revenants or changelings. + /// + + public void OnInternalShop(EntityUid uid) + { + if (!TryComp(uid, out StoreComponent? store)) + return; + ToggleUi(uid, uid, store); + } + /// /// Gets the value from an entity's currency component. /// Scales with stacks. @@ -181,6 +194,77 @@ public bool TryAddCurrency(Dictionary currency, EntityUid u UpdateUserInterface(null, uid, store); return true; } + + // ADT changeling start + public bool TryAddStore(EntityUid uid, + HashSet> currencyWhitelist, + HashSet> categories, + Dictionary, FixedPoint2> balance, + bool allowRefund, + bool ownerOnly) + { + if (HasComp(uid)) + return false; + + AddStore(uid, currencyWhitelist, categories, balance, allowRefund, ownerOnly); + + return true; + } + + public void AddStore(EntityUid uid, + HashSet> currencyWhitelist, + HashSet> categories, + Dictionary, FixedPoint2> balance, + bool allowRefund, + bool ownerOnly) + { + var comp = new StoreComponent(); + comp.CurrencyWhitelist = currencyWhitelist; + comp.Categories = categories; + comp.Balance = balance; + comp.RefundAllowed = allowRefund; + comp.OwnerOnly = ownerOnly; + + AddComp(uid, comp); + } + + public bool TrySetCurrency(Dictionary, FixedPoint2> currency, EntityUid uid, StoreComponent? store = null) + { + if (!Resolve(uid, ref store)) + return false; + + //verify these before values are modified + foreach (var type in currency) + { + if (!store.CurrencyWhitelist.Contains(type.Key)) + return false; + } + + foreach (var type in currency) + { + if (!store.Balance.TryAdd(type.Key, type.Value)) + store.Balance[type.Key] = type.Value; + } + + UpdateUserInterface(null, uid, store); + return true; + } + + public bool TryRefreshStoreStock(EntityUid uid, StoreComponent? store = null) + { + if (!Resolve(uid, ref store)) + return false; + + foreach (var item in store.FullListingsCatalog) + { + item.PurchaseAmount = 0; + } + + UpdateUserInterface(null, uid, store); + return true; + } + + // ADT changeling end } public sealed class CurrencyInsertAttemptEvent : CancellableEntityEventArgs diff --git a/Content.Shared/ADT/Changeling/Components/AbsorbedComponent.cs b/Content.Shared/ADT/Changeling/Components/AbsorbedComponent.cs new file mode 100644 index 00000000000..f87721db783 --- /dev/null +++ b/Content.Shared/ADT/Changeling/Components/AbsorbedComponent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Changeling.Components; + +[RegisterComponent] +public sealed partial class AbsorbedComponent : Component // component give to people who have been absorbed by changelings +{ + +} diff --git a/Content.Shared/ADT/Changeling/Components/ChangelingComponent.cs b/Content.Shared/ADT/Changeling/Components/ChangelingComponent.cs new file mode 100644 index 00000000000..8712384dcc2 --- /dev/null +++ b/Content.Shared/ADT/Changeling/Components/ChangelingComponent.cs @@ -0,0 +1,330 @@ +using Robust.Shared.Audio; +using Content.Shared.Polymorph; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; +using Content.Shared.Actions; +using Robust.Shared.GameStates; +using System.Diagnostics.CodeAnalysis; +using Content.Shared.DoAfter; + +namespace Content.Shared.Changeling.Components; + +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState(true)] +public sealed partial class ChangelingComponent : Component +{ + /// + /// The amount of chemicals the ling has. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float Chemicals = 20f; + + public float Accumulator = 0f; + + /// + /// The amount of chemicals passively generated per second + /// + [ViewVariables(VVAccess.ReadWrite)] + public float ChemicalsPerSecond = 0.5f; + + /// + /// The lings's current max amount of chemicals. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float MaxChemicals = 75f; + + /// + /// The maximum amount of DNA strands a ling can have at one time + /// + [ViewVariables(VVAccess.ReadWrite)] + public int DNAStrandCap = 7; + + /// + /// List of stolen DNA + /// + [ViewVariables(VVAccess.ReadWrite)] + public List StoredDNA = new List(); + + /// + /// The DNA index that the changeling currently has selected + /// + [ViewVariables(VVAccess.ReadWrite)] + public int SelectedDNA = 0; + + /// + /// Flesh sound + /// + public SoundSpecifier? SoundFlesh = new SoundPathSpecifier("/Audio/Effects/blobattack.ogg") + { + Params = AudioParams.Default.WithVolume(-3f), + }; + + /// + /// Flesh sound + /// + public SoundSpecifier? SoundFleshQuiet = new SoundPathSpecifier("/Audio/Effects/blobattack.ogg") + { + Params = AudioParams.Default.WithVolume(-1f), + }; + + public SoundSpecifier? SoundResonant = new SoundPathSpecifier("/Audio/ADT/resonant.ogg") + { + Params = AudioParams.Default.WithVolume(-3f), + }; + + /// + /// Blind sting duration + /// + [ViewVariables(VVAccess.ReadWrite)] + public TimeSpan BlindStingDuration = TimeSpan.FromSeconds(18); + + /// + /// Refresh ability + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool CanRefresh = false; + + #region Actions + public EntProtoId ChangelingEvolutionMenuAction = "ActionChangelingEvolutionMenu"; + + [AutoNetworkedField] + public EntityUid? ChangelingEvolutionMenuActionEntity; + + public EntProtoId ChangelingRegenAction = "ActionLingRegenerate"; + + [AutoNetworkedField] + public EntityUid? ChangelingRegenActionEntity; + + public EntProtoId ChangelingAbsorbAction = "ActionChangelingAbsorb"; + + [AutoNetworkedField] + public EntityUid? ChangelingAbsorbActionEntity; + + public EntProtoId ChangelingDNACycleAction = "ActionChangelingTransform"; + + [AutoNetworkedField] + public EntityUid? ChangelingDNACycleActionEntity; + + public EntProtoId ChangelingDNAStingAction = "ActionLingStingExtract"; + + [AutoNetworkedField] + public EntityUid? ChangelingDNAStingActionEntity; + + public EntProtoId ChangelingStasisDeathAction = "ActionStasisDeath"; + + [AutoNetworkedField] + public EntityUid? ChangelingStasisDeathActionEntity; + + public List BoughtActions = new(); + + public List BasicTransferredActions = new(); + #endregion + + #region Chemical Costs + public float ChemicalsCostFree = 0; + public float ChemicalsCostFive = -5f; + public float ChemicalsCostTen = -10f; + public float ChemicalsCostFifteen = -15f; + public float ChemicalsCostTwenty = -20f; + public float ChemicalsCostTwentyFive = -25f; + public float ChemicalsCostFifty = -50f; + #endregion + + #region DNA Absorb Ability + /// + /// How long an absorb stage takes, in seconds. + /// + [ViewVariables(VVAccess.ReadWrite)] + public int AbsorbDuration = 10; + + /// + /// The stage of absorbing that the changeling is on. Maximum of 2 stages. + /// + public int AbsorbStage = 0; + + /// + /// The amount of genetic damage the target gains when they're absorbed. + /// + public float AbsorbGeneticDmg = 200.0f; + + /// + /// The amount of evolution points the changeling gains when they absorb another changeling. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float AbsorbedChangelingPointsAmount = 5.0f; + + /// + /// The amount of evolution points the changeling gains when they absorb somebody. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float AbsorbedMobPointsAmount = 2.0f; + + [ViewVariables(VVAccess.ReadWrite)] + public float AbsorbedDnaModifier = 0f; + + [ViewVariables(VVAccess.ReadWrite)] + public DoAfterId? DoAfter; + #endregion + + #region Regenerate Ability + /// + /// The amount of burn damage is healed when the regenerate ability is sucesssfully used. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float RegenerateBurnHealAmount = -100f; + + /// + /// The amount of brute damage is healed when the regenerate ability is sucesssfully used. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float RegenerateBruteHealAmount = -125f; + + /// + /// The amount of blood volume that is gained when the regenerate ability is sucesssfully used. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float RegenerateBloodVolumeHealAmount = 1000f; + + /// + /// The amount of bleeding that is reduced when the regenerate ability is sucesssfully used. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float RegenerateBleedReduceAmount = -1000f; + + /// + /// Sound that plays when the ling uses the regenerate ability. + /// + public SoundSpecifier? SoundRegenerate = new SoundPathSpecifier("/Audio/Effects/demon_consume.ogg") + { + Params = AudioParams.Default.WithVolume(-3f), + }; + #endregion + + #region Armblade Ability + /// + /// If the ling has an active armblade or not. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool ArmBladeActive = false; + + [AutoNetworkedField] + public EntityUid? BladeEntity; + + #endregion + + #region Armace Ability + /// + /// If the ling has an active armace or not. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool ArmaceActive = false; + + [AutoNetworkedField] + public EntityUid? ArmaceEntity; + #endregion + + #region Chitinous Armor Ability + /// + /// The amount of chemical regeneration is reduced when the ling armor is active. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float LingArmorRegenCost = 0.125f; + + /// + /// If the ling has the armor on or not. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool LingArmorActive = false; + #endregion + + #region Chameleon Skin Ability + /// + /// If the ling has chameleon skin active or not. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool ChameleonSkinActive = false; + + /// + /// How fast the changeling will turn invisible from standing still when using chameleon skin. + /// + public float ChameleonSkinPassiveVisibilityRate = -0.15f; + + /// + /// How fast the changeling will turn visible from movement when using chameleon skin. + /// + public float ChameleonSkinMovementVisibilityRate = 0.60f; + #endregion + + #region Dissonant Shriek Ability + /// + /// Range of the Dissonant Shriek's EMP in tiles. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float DissonantShriekEmpRange = 5f; + + /// + /// Power consumed from batteries by the Dissonant Shriek's EMP + /// + public float DissonantShriekEmpConsumption = 50000f; + + /// + /// How long the Dissonant Shriek's EMP effects last for + /// + [ViewVariables(VVAccess.ReadWrite)] + public float DissonantShriekEmpDuration = 12f; + #endregion + + #region Stasis Death Ability + + [ViewVariables(VVAccess.ReadWrite)] + public bool StasisDeathActive = false; /// Is ling dead or alive + + #endregion + + #region Muscles Ability + + [ViewVariables(VVAccess.ReadWrite)] + public bool MusclesActive = false; + + [ViewVariables(VVAccess.ReadWrite)] + public float MusclesModifier = 1.4f; + + [ViewVariables(VVAccess.ReadWrite)] + public float MusclesStaminaDamage = 3f; + + public TimeSpan NextMusclesDamage = TimeSpan.Zero; + #endregion + + #region Lesser Form Ability + + [ViewVariables(VVAccess.ReadWrite)] + public bool LesserFormActive = false; + + [ViewVariables(VVAccess.ReadWrite)] + public string LesserFormMob = "ADTChangelingLesserForm"; + + + #endregion + + #region Armshield Ability + /// + /// If the ling has an active armblade or not. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool ArmShieldActive = false; + + [AutoNetworkedField] + public EntityUid? ShieldEntity; + + #endregion + + [ViewVariables(VVAccess.ReadWrite)] + public int BiodegradeDuration = 3; + + [ViewVariables(VVAccess.ReadWrite)] + public bool LastResortUsed = false; + + [ViewVariables(VVAccess.ReadWrite)] + public bool DigitalCamouflageActive = false; +} diff --git a/Content.Shared/ADT/Changeling/Components/ChangelingHeadslugComponent.cs b/Content.Shared/ADT/Changeling/Components/ChangelingHeadslugComponent.cs new file mode 100644 index 00000000000..8f7d878598b --- /dev/null +++ b/Content.Shared/ADT/Changeling/Components/ChangelingHeadslugComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Changeling.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class ChangelingHeadslugComponent : Component +{ + public EntityUid? Container; + + public bool IsInside = false; + + public float Accumulator = 0f; + + public float AccumulateTime = 90f; + + public bool Alerted = false; +} diff --git a/Content.Shared/ADT/Changeling/Components/ChangelingShieldComponent.cs b/Content.Shared/ADT/Changeling/Components/ChangelingShieldComponent.cs new file mode 100644 index 00000000000..b82f0d5cdae --- /dev/null +++ b/Content.Shared/ADT/Changeling/Components/ChangelingShieldComponent.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Changeling.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class ChangelingShieldComponent : Component +{ +} diff --git a/Content.Shared/ADT/Changeling/Components/ChangelingSlugContainerComponent.cs b/Content.Shared/ADT/Changeling/Components/ChangelingSlugContainerComponent.cs new file mode 100644 index 00000000000..bfc48fb3147 --- /dev/null +++ b/Content.Shared/ADT/Changeling/Components/ChangelingSlugContainerComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Containers; +using System.Diagnostics.CodeAnalysis; + +namespace Content.Shared.Changeling.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class ChangelingHeadslugContainerComponent : Component +{ + [NotNull] + public Container? Container; +} diff --git a/Content.Shared/ADT/Changeling/SharedChangeling.cs b/Content.Shared/ADT/Changeling/SharedChangeling.cs new file mode 100644 index 00000000000..37313d5f418 --- /dev/null +++ b/Content.Shared/ADT/Changeling/SharedChangeling.cs @@ -0,0 +1,193 @@ +using Content.Shared.Actions; +using Content.Shared.DoAfter; +using Content.Shared.Preferences; +using Robust.Shared.Serialization; + +namespace Content.Shared.Changeling; + +public sealed partial class LingAbsorbActionEvent : EntityTargetActionEvent +{ +} + +public sealed partial class LingStingExtractActionEvent : EntityTargetActionEvent +{ +} + +public sealed partial class BlindStingEvent : EntityTargetActionEvent +{ +} + +public sealed partial class MuteStingEvent : EntityTargetActionEvent +{ +} + +public sealed partial class DrugStingEvent : EntityTargetActionEvent +{ +} + +public sealed partial class TransformationStingEvent : EntityTargetActionEvent +{ +} + +public sealed partial class LingEggActionEvent : EntityTargetActionEvent +{ +} + +[Serializable, NetSerializable] +public sealed partial class AbsorbDoAfterEvent : SimpleDoAfterEvent +{ +} + +[Serializable, NetSerializable] +public sealed partial class LingEggDoAfterEvent : SimpleDoAfterEvent +{ +} + +[Serializable, NetSerializable] +public sealed partial class BiodegradeDoAfterEvent : SimpleDoAfterEvent +{ +} +public sealed partial class ChangelingEvolutionMenuActionEvent : InstantActionEvent +{ +} + +public sealed partial class ChangelingTransformActionEvent : InstantActionEvent +{ +} + +public sealed partial class LingRegenerateActionEvent : InstantActionEvent +{ +} + +public sealed partial class ArmBladeActionEvent : InstantActionEvent +{ +} + +public sealed partial class LingArmorActionEvent : InstantActionEvent +{ +} + +public sealed partial class LingInvisibleActionEvent : InstantActionEvent +{ +} + +public sealed partial class LingEMPActionEvent : InstantActionEvent +{ +} + +public sealed partial class StasisDeathActionEvent : InstantActionEvent +{ +} + +public sealed partial class AdrenalineActionEvent : InstantActionEvent +{ +} + +public sealed partial class FleshmendActionEvent : InstantActionEvent +{ +} + +public sealed partial class ChangelingRefreshActionEvent : InstantActionEvent +{ +} + +public sealed partial class ChangelingMusclesActionEvent : InstantActionEvent +{ +} + +public sealed partial class ChangelingLesserFormActionEvent : InstantActionEvent +{ +} + +public sealed partial class ArmShieldActionEvent : InstantActionEvent +{ +} + +public sealed partial class ArmaceActionEvent : InstantActionEvent +{ +} + +public sealed partial class LastResortActionEvent : InstantActionEvent +{ +} + +public sealed partial class LingBiodegradeActionEvent : InstantActionEvent +{ +} + +public sealed partial class LingResonantShriekEvent : InstantActionEvent +{ +} + +public sealed partial class DigitalCamouflageEvent : InstantActionEvent +{ +} + +public sealed partial class ChangelingBoneShardEvent : InstantActionEvent +{ +} + +/// +/// This event carries humanoid information list of entities, which DNA were stolen. Used for radial UI of "The genestealer". +/// +[Serializable, NetSerializable] +public sealed partial class RequestChangelingFormsMenuEvent : EntityEventArgs +{ + public List HumanoidData = new(); + + public NetEntity Target; + public ChangelingMenuType Type; + + public RequestChangelingFormsMenuEvent(NetEntity target, ChangelingMenuType type) + { + Target = target; + Type = type; + } +} + +[Serializable, NetSerializable] +public enum ChangelingMenuType : byte +{ + Transform, + HumanForm, + Sting, +} + +[Serializable, NetSerializable] +public sealed class HDATA(NetEntity netEntity, string name, string species, HumanoidCharacterProfile profile) +{ + public NetEntity NetEntity = netEntity; + public string Name = name; + public string Species = species; + public HumanoidCharacterProfile Profile = profile; +} + + +/// +/// This event carries prototype-id of emote, which was selected. This class is a part of code which is responsible for using RadialUiController. +/// +[Serializable, NetSerializable] +public sealed partial class SelectChangelingFormEvent : EntityEventArgs +{ + public NetEntity EntitySelected; + + public NetEntity User; + public NetEntity Target; + + public bool Handled = false; + public ChangelingMenuType Type; + + public SelectChangelingFormEvent(NetEntity user, NetEntity target, NetEntity entitySelected, ChangelingMenuType type) + { + User = user; + Target = target; + EntitySelected = entitySelected; + Type = type; + } +} + +[NetSerializable, Serializable] +[DataDefinition] +public sealed partial class ChangelingRefreshEvent : EntityEventArgs +{ +} diff --git a/Content.Shared/ADT/Damage/Events/BeforeStaminaCritEvent.cs b/Content.Shared/ADT/Damage/Events/BeforeStaminaCritEvent.cs new file mode 100644 index 00000000000..a47402483b2 --- /dev/null +++ b/Content.Shared/ADT/Damage/Events/BeforeStaminaCritEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared.ADT.Damage.Events; + +[ByRefEvent] +public record struct BeforeStaminaCritEvent(bool Cancelled = false); diff --git a/Content.Shared/ADT/Stealth/Components/DigitalCamouflageComponent.cs b/Content.Shared/ADT/Stealth/Components/DigitalCamouflageComponent.cs new file mode 100644 index 00000000000..4f9353ea45e --- /dev/null +++ b/Content.Shared/ADT/Stealth/Components/DigitalCamouflageComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared.Stealth; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.ADT.Stealth.Components; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedStealthSystem))] +public sealed partial class DigitalCamouflageComponent : Component +{ +} diff --git a/Content.Shared/ADT/Stealth/Events/CheckStealthWhitelistEvent.cs b/Content.Shared/ADT/Stealth/Events/CheckStealthWhitelistEvent.cs new file mode 100644 index 00000000000..2bf3a21983b --- /dev/null +++ b/Content.Shared/ADT/Stealth/Events/CheckStealthWhitelistEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared.Stealth; + +[ByRefEvent] +public record struct CheckStealthWhitelistEvent(EntityUid? User, EntityUid StealthEntity, bool Cancelled = false); diff --git a/Content.Shared/ADT/Stealth/SharedStealthSystem.cs b/Content.Shared/ADT/Stealth/SharedStealthSystem.cs new file mode 100644 index 00000000000..12e009dc79c --- /dev/null +++ b/Content.Shared/ADT/Stealth/SharedStealthSystem.cs @@ -0,0 +1,47 @@ +using Content.Shared.ADT.Stealth.Components; +using Content.Shared.Stealth.Components; +using Content.Shared.Tag; + +namespace Content.Shared.Stealth; + +public abstract partial class SharedStealthSystem +{ + [Dependency] private readonly TagSystem _tag = default!; + + private void InitializeADT() + { + SubscribeLocalEvent(CheckDigiCamo); + } + + private void CheckDigiCamo(EntityUid uid, DigitalCamouflageComponent comp, ref CheckStealthWhitelistEvent args) + { + if (!args.User.HasValue) + return; + + if (!_tag.HasTag(args.User.Value, "ADTSiliconStealthWhitelist")) + args.Cancelled = true; + } + + /// + /// + /// + /// + /// + /// True, если для отрисовывается шейдер + public bool CheckStealthWhitelist(EntityUid? user, EntityUid stealthEnt) + { + var ev = new CheckStealthWhitelistEvent(user, stealthEnt); + RaiseLocalEvent(stealthEnt, ref ev); + return !ev.Cancelled; + } + + public void SetDesc(EntityUid uid, string desc, StealthComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.ExaminedDesc = desc; + + Dirty(uid, component); + } +} diff --git a/Content.Shared/Actions/ActionContainerSystem.cs b/Content.Shared/Actions/ActionContainerSystem.cs index 1a83cf38e51..2dc6a43ca72 100644 --- a/Content.Shared/Actions/ActionContainerSystem.cs +++ b/Content.Shared/Actions/ActionContainerSystem.cs @@ -237,6 +237,20 @@ public bool AddAction(EntityUid uid, EntityUid actionId, BaseActionComponent? ac DebugTools.AssertOwner(uid, comp); comp ??= EnsureComp(uid); + + // ADT-Tweak-Changeling-start + if (!TryComp(actionId, out var actionMetaData)) + return false; + if (!TryPrototype(actionId, out var actionPrototype, actionMetaData)) + return false; + + if (HasAction(uid, actionPrototype.ID)) + { + Log.Debug($"Tried to insert action {ToPrettyString(actionId)} into {ToPrettyString(uid)}. Failed due to duplicate actions."); + return false; + } + // ADT-Tweak-Changeling-end + if (!_container.Insert(actionId, comp.Container)) { Log.Error($"Failed to insert action {ToPrettyString(actionId)} into {ToPrettyString(uid)}"); @@ -250,6 +264,30 @@ public bool AddAction(EntityUid uid, EntityUid actionId, BaseActionComponent? ac return true; } + // ADT changeling start + /// + /// Checks if the given entity has an action prototype in their actions container. + /// + public bool HasAction(EntityUid uid, string prototypeID, ActionsContainerComponent? actionsContainerComp = null) + { + if (!Resolve(uid, ref actionsContainerComp, false)) + return false; + + foreach (var act in actionsContainerComp.Container.ContainedEntities.ToArray()) + { + if (TryPrototype(act, out var actPrototype)) + { + if (prototypeID == actPrototype.ID) + { + return true; + } + } + } + + return false; + } + // ADT changeling end + /// /// Removes an action from its container and any action-performer and moves the action to null-space /// diff --git a/Content.Shared/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs index 1244a603796..a3f5b228344 100644 --- a/Content.Shared/Damage/Systems/StaminaSystem.cs +++ b/Content.Shared/Damage/Systems/StaminaSystem.cs @@ -1,5 +1,6 @@ using System.Linq; using Content.Shared.Administration.Logs; +using Content.Shared.ADT.Damage.Events; // ADT-Changeling-Tweak using Content.Shared.Alert; using Content.Shared.CombatMode; using Content.Shared.Damage.Components; @@ -368,6 +369,13 @@ private void EnterStamCrit(EntityUid uid, StaminaComponent? component = null) { return; } + // ADT staminacrit cancellation event start + var ev = new BeforeStaminaCritEvent(); + RaiseLocalEvent(uid, ref ev); + + if (ev.Cancelled) + return; + // ADT staminacrit cancellation event end // To make the difference between a stun and a stamcrit clear // TODO: Mask? diff --git a/Content.Shared/Eye/VisibilityFlags.cs b/Content.Shared/Eye/VisibilityFlags.cs index a616b430bec..a29bee1c285 100644 --- a/Content.Shared/Eye/VisibilityFlags.cs +++ b/Content.Shared/Eye/VisibilityFlags.cs @@ -10,5 +10,8 @@ public enum VisibilityFlags : int Normal = 1 << 0, Ghost = 1 << 1, // ADT Phantom PhantomVessel = 2 << 1, // ADT Phantom + Narcotic = 1 << 2, // ADT-Changeling-Tweak + Schizo = 1 << 3, // ADT-Changeling-Tweak + LingToxin = 1 << 4, // ADT-Changeling-Tweak } } diff --git a/Content.Shared/Mind/MindComponent.cs b/Content.Shared/Mind/MindComponent.cs index 010a8a5d7d4..e45c4bd1f2c 100644 --- a/Content.Shared/Mind/MindComponent.cs +++ b/Content.Shared/Mind/MindComponent.cs @@ -124,4 +124,9 @@ public void AddMemory(Memory memory) [ViewVariables, Access(typeof(SharedMindSystem), typeof(SharedGameTicker))] // TODO remove this after moving IPlayerManager functions to shared public ICommonSession? Session { get; set; } + + // ADT + [ViewVariables(VVAccess.ReadWrite)] + [DataField("preventGhostingSendMessage")] + public bool PreventGhostingSendMessage = true; } diff --git a/Content.Shared/Polymorph/PolymorphPrototype.cs b/Content.Shared/Polymorph/PolymorphPrototype.cs index 6d010711d2e..b1392924c01 100644 --- a/Content.Shared/Polymorph/PolymorphPrototype.cs +++ b/Content.Shared/Polymorph/PolymorphPrototype.cs @@ -1,5 +1,6 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array; +using Content.Shared.Humanoid; // ADT-Changeling-Tweak namespace Content.Shared.Polymorph; @@ -123,3 +124,13 @@ public enum PolymorphInventoryChange : byte Drop, Transfer, } +// ADT-Changeling-Tweak-Start +public struct PolymorphHumanoidData +{ + public EntityPrototype EntityPrototype; + public MetaDataComponent MetaDataComponent; + public HumanoidAppearanceComponent HumanoidAppearanceComponent; + public string DNA; + public EntityUid EntityUid; +} +// ADT-Changeling-Tweak-End diff --git a/Content.Shared/Stealth/Components/StealthComponent.cs b/Content.Shared/Stealth/Components/StealthComponent.cs index 0e32e90ba16..fd05af98142 100644 --- a/Content.Shared/Stealth/Components/StealthComponent.cs +++ b/Content.Shared/Stealth/Components/StealthComponent.cs @@ -80,11 +80,13 @@ public sealed class StealthComponentState : ComponentState public readonly float Visibility; public readonly TimeSpan? LastUpdated; public readonly bool Enabled; + public string Desc; // ADT tweak - public StealthComponentState(float stealthLevel, TimeSpan? lastUpdated, bool enabled) + public StealthComponentState(float stealthLevel, TimeSpan? lastUpdated, bool enabled, string desc) // ADT tweak { Visibility = stealthLevel; LastUpdated = lastUpdated; Enabled = enabled; + Desc = desc; // ADT tweak } } diff --git a/Content.Shared/Stealth/SharedStealthSystem.cs b/Content.Shared/Stealth/SharedStealthSystem.cs index 1bab55589fd..335ea6c9573 100644 --- a/Content.Shared/Stealth/SharedStealthSystem.cs +++ b/Content.Shared/Stealth/SharedStealthSystem.cs @@ -1,13 +1,12 @@ using Content.Shared.Examine; using Content.Shared.Mobs; -using Content.Shared.Mobs.Systems; using Content.Shared.Stealth.Components; using Robust.Shared.GameStates; using Robust.Shared.Timing; namespace Content.Shared.Stealth; -public abstract class SharedStealthSystem : EntitySystem +public abstract partial class SharedStealthSystem : EntitySystem // ADT partial { [Dependency] private readonly IGameTiming _timing = default!; @@ -25,11 +24,13 @@ public override void Initialize() SubscribeLocalEvent(OnExamineAttempt); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnMobStateChanged); + + InitializeADT(); // ADT } private void OnExamineAttempt(EntityUid uid, StealthComponent component, ExamineAttemptEvent args) { - if (!component.Enabled || GetVisibility(uid, component) > component.ExamineThreshold) + if (!component.Enabled || GetVisibility(uid, component) > component.ExamineThreshold || !CheckStealthWhitelist(args.Examiner, uid)) // ADT tweaked return; // Don't block examine for owner or children of the cloaked entity. @@ -98,7 +99,7 @@ protected virtual void OnInit(EntityUid uid, StealthComponent component, Compone private void OnStealthGetState(EntityUid uid, StealthComponent component, ref ComponentGetState args) { - args.State = new StealthComponentState(component.LastVisibility, component.LastUpdated, component.Enabled); + args.State = new StealthComponentState(component.LastVisibility, component.LastUpdated, component.Enabled, component.ExaminedDesc); // ADT tweaked } private void OnStealthHandleState(EntityUid uid, StealthComponent component, ref ComponentHandleState args) @@ -109,6 +110,7 @@ private void OnStealthHandleState(EntityUid uid, StealthComponent component, ref SetEnabled(uid, cast.Enabled, component); component.LastVisibility = cast.Visibility; component.LastUpdated = cast.LastUpdated; + component.ExaminedDesc = cast.Desc; // ADT tweaked } private void OnMove(EntityUid uid, StealthOnMoveComponent component, ref MoveEvent args) diff --git a/Content.Shared/Store/ListingPrototype.cs b/Content.Shared/Store/ListingPrototype.cs index 4e00f3f47db..227006c50dd 100644 --- a/Content.Shared/Store/ListingPrototype.cs +++ b/Content.Shared/Store/ListingPrototype.cs @@ -164,6 +164,9 @@ public ListingData( [DataField] public EntProtoId? ProductAction; + [DataField("mindAction")] // ADT-Changeling-Tweak + public bool MindAction = true; + /// /// The listing ID of the related upgrade listing. Can be used to link a to an /// upgrade or to use standalone as an upgrade @@ -443,4 +446,4 @@ public sealed partial class DiscountCategoryPrototype : IPrototype /// [DataField] public int? MaxItems { get; private set; } -} \ No newline at end of file +} diff --git a/Content.Shared/Weapons/Melee/Components/MeleeThrowOnHitComponent.cs b/Content.Shared/Weapons/Melee/Components/MeleeThrowOnHitComponent.cs index 82ffc5e51fc..87a4434d91c 100644 --- a/Content.Shared/Weapons/Melee/Components/MeleeThrowOnHitComponent.cs +++ b/Content.Shared/Weapons/Melee/Components/MeleeThrowOnHitComponent.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Content.Shared.Damage; using Robust.Shared.GameStates; using Robust.Shared.Physics.Components; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; @@ -47,6 +48,17 @@ public sealed partial class MeleeThrowOnHitComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] public bool Enabled = true; + + // ADT tweak start + [DataField, ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier? CollideDamage; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier? ToCollideDamage; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool DownOnHit = false; + // ADT tweak end } /// @@ -96,6 +108,14 @@ public sealed partial class MeleeThrownComponent : Component /// [DataField] public BodyStatus PreviousStatus; + + // ADT tweak start + [DataField, ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier? CollideDamage; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier? ToCollideDamage; + // ADT tweak end } /// diff --git a/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs b/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs index 78863562330..de68bdd4a13 100644 --- a/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs +++ b/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs @@ -1,5 +1,7 @@ using System.Numerics; using Content.Shared.Construction.Components; +using Content.Shared.Damage; +using Content.Shared.Standing; using Content.Shared.Weapons.Melee.Components; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Physics; @@ -18,6 +20,8 @@ public sealed class MeleeThrowOnHitSystem : EntitySystem [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly StandingStateSystem _standing = default!; // ADT-Changeling-Tweak + [Dependency] private readonly DamageableSystem _damage = default!; // ADT-Changeling-Tweak /// public override void Initialize() @@ -57,9 +61,14 @@ private void OnMeleeHit(Entity ent, ref MeleeHitEvent { Velocity = angle.Normalized() * comp.Speed, Lifetime = comp.Lifetime, - MinLifetime = comp.MinLifetime + MinLifetime = comp.MinLifetime, + CollideDamage = comp.CollideDamage, // ADT tweak + ToCollideDamage = comp.ToCollideDamage // ADT tweak }; AddComp(hit, thrownComp); + + if (comp.DownOnHit) // ADT tweak + _standing.Down(hit); } } @@ -97,6 +106,11 @@ private void OnStartCollide(Entity ent, ref StartCollideEv if (_timing.CurTime < comp.MinLifetimeTime) return; + if (ent.Comp.CollideDamage != null) // ADT tweak + _damage.TryChangeDamage(ent.Owner, ent.Comp.CollideDamage); + if (ent.Comp.ToCollideDamage != null) // ADT tweak + _damage.TryChangeDamage(args.OtherEntity, ent.Comp.ToCollideDamage); + RemCompDeferred(ent, ent.Comp); } diff --git a/Resources/Audio/Ambience/Antag/changeling_start.ogg b/Resources/Audio/Ambience/Antag/changeling_start.ogg new file mode 100644 index 00000000000..1132ccca29c Binary files /dev/null and b/Resources/Audio/Ambience/Antag/changeling_start.ogg differ diff --git a/Resources/Audio/Effects/blobattack.ogg b/Resources/Audio/Effects/blobattack.ogg new file mode 100644 index 00000000000..c9fcfbee448 Binary files /dev/null and b/Resources/Audio/Effects/blobattack.ogg differ diff --git a/Resources/Locale/ru-RU/ADT/changeling/action_changeling.ftl b/Resources/Locale/ru-RU/ADT/changeling/action_changeling.ftl new file mode 100644 index 00000000000..4e9ac9fa7d7 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/action_changeling.ftl @@ -0,0 +1,86 @@ +action-evolution-menu = Меню эволюции +action-evolution-menu-decs = Открывает меню эволюции, в котором можно улучшить свои показатели для адаптации к внешней среде. + +action-absorb-dna = Поглотить оболочку цели +action-absorb-dna-desc = Поглощает цель и её ДНК. [color=red]Она должна быть в критическом или мёртвом состоянии и обязательно гуманоидом[/color], чтобы можно было забрать образцы ДНК. + +action-cycle-dna = Выбор ДНК поглощённых +action-cycle-dna-desc = Выбирает ДНК поглощённого для трансформации. + +action-transform = Трансформация +action-transform-desc = Трансформирует вас в выбранную цепочку ДНК. [color=#db03fc]Использует 5 химикатов.[/color] + +action-regenerate = Регенерация +action-regenerate-desc = Позволяет быстро регенерировать, заживляя серьезные раны и восстанавливая объем крови. [color=#db03fc]Использует 10 химикатов[/color] и может быть использовано [color=red]только в критическом состоянии.[/color] + +action-extract-dna-sting = Скрытый сбор ДНК +action-extract-dna-sting-desc = Забирает пробу ДНК цели. Не информирует цель о том, что её ужалили. [color=#db03fc]Использует 25 химикатов.[/color] + +action-toggle-arm-blade = Переключить руку-клинок +action-toggle-arm-blade-desc = Превращает одну из ваших свободных рук в причудливый клинок, сделанный из костей и плоти. Также позволяет вскрывать двери как ломом. [color=#db03fc]Использует 20 химикатов.[/color] + +action-toggle-chitinous-armor = Переключить хитиновую броню +action-toggle-chitinous-armor-desc = Превращает ваше тело во всепоглощающую хитиновую броню. [color=#db03fc]Использует 20 химикатов[/color] и [color=red]замедляет химическую регенерацию на 25% в активном состоянии.[/color] + +action-toggle-chameleon-skin = Переключить маскировку +action-toggle-chameleon-skin-desc = Пигментация вашей кожи быстро меняется в соответствии с окружающей средой, делая вас невидимым после нескольких секунд неподвижного стояния. [color=#db03fc]Использует 25 химикатов.[/color] + +action-activate-dissonant-shriek = Активируйте диссонирующий рёв +action-activate-dissonant-shriek-desc = Вы напрягаете голосовые связки, чтобы издать высокочастотный звук, который перегружает близлежащую электронику. [color=#db03fc]Использует 20 химикатов.[/color] + +action-stasis-death = Регенеративный стазис +action-stasis-death-desc = Войдите в стазис, подобный смерти для дальнейшей [color=green]полной[/color] регенерации. Можно использовать даже в мёртвом состоянии. [color=#db03fc]Использует 25 химикатов.[/color] + +action-refresh-ling = Очистить ДНК +action-refresh-ling-desc = Очистите собранные цепочки ДНК, получив взамен [color=#db03fc]2 очка эволюции[/color]. + +action-adrenaline = Выброс адреналина +action-adrenaline-desc = Ваше тело моментально вырабатывает химикаты, отключающие болевые рецепторы и останавливающие кровотечение. [color=#db03fc]Использует 10 химикатов.[/color] + +action-blind-sting = Жало ослепления +action-blind-sting-desc = Ужальте кого-либо скрытым жалом и ослепите его на 18 секунд. [color=#db03fc]Использует 15 химикатов.[/color] + +action-mute-sting = Жало безмолвия +action-mute-sting-desc = Ужальте кого-либо скрытым жалом и временно лишите его возможности говорить. [color=#db03fc]Использует 20 химикатов.[/color] + +action-drug-sting = Галлюценогенное жало +action-drug-sting-desc = Введите кому-либо большое количество нетоксичного, но крайне мощного галлюценогена. Цель ни о чём не догадается, пока вокруг неё не начнёт происходить хаос. [color=#db03fc]Использует 20 химикатов.[/color] + +action-fleshmend = Исцеление плоти +action-fleshmend-desc = Ваше тело моментально заживляет многие раны и ожоги. [color=#db03fc]Использует 25 химикатов.[/color] + +action-lingmuscles = Напряжённые мышцы +action-lingmuscles-desc = Ваши мышцы ног начинают сокращаться, позволяя вам бегать с крайне высокой скоростью. [color=#db03fc]Использует 20 химикатов.[/color] + +action-lesser-form = Низшая форма +action-lesser-form-desc = Превратитесь в обезьяну, либо из обезьяны в выбранную форму. [color=#db03fc]Использует 20 химикатов.[/color] + +action-toggle-arm-shield = Переключить органический щит +action-toggle-arm-shield-desc = Превращает одну из ваших свободных рук в щит, сделанный из костей и плоти. [color=#db03fc]Использует 20 химикатов.[/color] + +action-resort = Последний шанс +action-resort-desc = Разорвите собственное тело и высвободите свою настоящую форму для последующей кладки личинок в новое тело. + +action-eggs = Отложить яйца +action-eggs-desc = Отложите яйца в бездыханный труп для продолжения рода улья. + +action-hatch = Вылупиться +action-hatch-desc = Разорвите оболочку и вернитесь в облике нового генокрада. + +action-biodegrade = Плевок кислотой +action-biodegrade-desc = Синтезируйте крайне едкую кислоту и уничтожьте ей надетые на вас наручники. [color=#db03fc]Использует 15 химикатов.[/color] + +action-resonant = Резонантный рёв +action-resonant-desc = Дезориентируйте окружающих вас не-генокрадов с помощью высокочастотного звука. [color=#db03fc]Использует 20 химикатов.[/color] + +action-transform-sting = Жало трансформации +action-transform-sting-desc = Заставьте выбранную цель превратиться в того, кого в данный момент вы выбрали. [color=#db03fc]Использует 50 химикатов.[/color] + +action-toggle-arm-hammer = Рука-молот +action-toggle-arm-hammer-desc = Превращает одну из ваших рук в громадный молот из плоти. [color=#db03fc]Использует 25 химикатов.[/color] + +action-digi-camo = Цифровой камуфляж +action-digi-camo-desc = Начните двигаться особым образом, предотвращая ваше обнаружение позитронными сенсорами. [color=#db03fc]Использует 20 химикатов.[/color] + +action-bone-shard = Костяной сюрикен +action-bone-shard-desc = Создайте из своих костей сюрикен. [color=#db03fc]Использует 15 химикатов,[/color] [color=crimson]наносит 20 единиц урона.[/color] diff --git a/Resources/Locale/ru-RU/ADT/changeling/alerts.ftl b/Resources/Locale/ru-RU/ADT/changeling/alerts.ftl new file mode 100644 index 00000000000..93a5b7adf1f --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/alerts.ftl @@ -0,0 +1,2 @@ +alerts-changeling-chemicals-name = Химические вещества +alerts-changeling-chemicals-desc = Количество химических веществ в вашем теле. Они используются для способностей. Восстанавливаются через время. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ADT/changeling/animals.ftl b/Resources/Locale/ru-RU/ADT/changeling/animals.ftl new file mode 100644 index 00000000000..dcc24ee40e7 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/animals.ftl @@ -0,0 +1,4 @@ +ent-ADTMobMonkeyChangeling = обезьяна + .desc = Новая церковь неодарвинистов действительно верит, что КАЖДОЕ животное произошло от обезьяны. На вкус они как свинина, а убивать их весело и приятно. +ent-ADTChangelingHeadslug = червь генокрада + .desc = Отвратительное нечто, оставшееся от генокрада. Почему вы просто стоите и смотрите?! Убейте это, пока не поздно! \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ADT/changeling/antags.ftl b/Resources/Locale/ru-RU/ADT/changeling/antags.ftl new file mode 100644 index 00000000000..886f25dc8b4 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/antags.ftl @@ -0,0 +1,6 @@ +roles-antag-changeling-name = Генокрад +roles-antag-changeling-objective = Используйте свои особые инопланетные способности, чтобы помочь в достижении ваших целей. + +admin-verb-make-changeling = Сделать цель генокрадом. + +admin-verb-text-make-changeling = Сделать генокрадом diff --git a/Resources/Locale/ru-RU/ADT/changeling/currency.ftl b/Resources/Locale/ru-RU/ADT/changeling/currency.ftl new file mode 100644 index 00000000000..2fb32475a43 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/currency.ftl @@ -0,0 +1 @@ +store-currency-display-evolution-points = Очки Эволюции diff --git a/Resources/Locale/ru-RU/ADT/changeling/objectives.ftl b/Resources/Locale/ru-RU/ADT/changeling/objectives.ftl new file mode 100644 index 00000000000..d5297d6e5c2 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/objectives.ftl @@ -0,0 +1,15 @@ +ent-EscapeLingShuttleObjective = Доберитесь до Центкома живым и свободным. + .desc = Мы должны пройти через станцию Центрального Командования. + +absorb-dna-name = Поглотите { $count } штамма ДНК. +absorb-dna-desc = Нам нужно { $count } полностью поглощённых ДНК для дальнейшей эволюции. + +ling-kill-desc = Мы должны убить их. +objective-condition-steal-personality-title = Украдите личность { $targetName }, в должности { CAPITALIZE($job) }. +objective-condition-steal-head-personality-title = Украдите личность { $targetName }, в должности { CAPITALIZE($job) }. Цель НЕ ДОЛЖНА пережить смену. +ling-steal-personality-desc = Нам нужно это тело. + +objective-condition-changeling-commandidcard = Украдите любую ID карту командования, кроме карты капитана. +objective-condition-changeling-smileextract = Вы должны украсть экстракт Смайла. Он содержит соединение, которое будет очень полезно для улья. + +changeling-issuer = Генокрад \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ADT/changeling/objects.ftl b/Resources/Locale/ru-RU/ADT/changeling/objects.ftl new file mode 100644 index 00000000000..96a5dff7457 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/objects.ftl @@ -0,0 +1,11 @@ +ent-ADTArmBlade = рука-клинок + .desc = Гротескный клинок из костей и плоти, который рассекает людей, как горячий нож масло. +ent-ADTArmShield = органический щит + .desc = Крупное месиво из плоти, формирующее собой нечто наподобие щита, что достаточно эффективно блокирует некоторые виды урона. +ent-ADTArmace = рука-молот + .desc = Громадный костяной молот, обволакиваемый плотью. Крайне увесистый, и очень хорошо пробивает стены. +ent-ADTThrowingStarChangeling = костяной сюрикен + .desc = Комок из плоти и острых выпирающих костей в форме сюрикена. Тем не менее, он выглядит так, словно в любой момент может рассыпаться в прах. + +changeling-headslug-inside = [color=white]Внутри тела двигается что-то живое...[/color] +changeling-headslug-inside-soon = [color=crimson]Что-то пытается выбраться из тела![/color] diff --git a/Resources/Locale/ru-RU/ADT/changeling/preset-changeling.ftl b/Resources/Locale/ru-RU/ADT/changeling/preset-changeling.ftl new file mode 100644 index 00000000000..c9a7b4865b1 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/preset-changeling.ftl @@ -0,0 +1,93 @@ +## CHANGELINGS + +adt-rotting-ling-eggs = [color=#ffd6d6]Внутри тела видны странные личинки...[/color] +ling-round-end-name = генокрад +objective-issuer-changeling = [color=red]Разум улья[/color] +changelings-title = Генокрады +changelings-description = дурацкие воришки ДНК +changelings-not-enough-ready-players = Недостаточно игроков нажали "Готов"! Всего было {$readyPlayersCount} готовых игроков из {$minimumPlayers} нужных. Режим "Генокрады" не запустится. +changelings-no-one-ready = Никто не нажал "Готов"! Режим "Генокрады" начать нельзя. +# Ling role +changeling-role-greeting = + Вы являетесь Генокрадом, впитавшим форму {$character-name} и превратившимся в него. + Ваши цели перечислены в специальном меню, используйте ваши способности, чтобы выполнить их. +changeling-role-greeting-short = + Вы являетесь Генокрадом, впитавшим форму + {$character-name} и превратившимся в него. + Используйте ваши способности, чтобы выполнить цели. +# Ling abilities +changeling-not-enough-chemicals = Недостаточно химических веществ! +changeling-armblade-fail = Вам нужна свободная рука! +changeling-armblade-success-others = Вокруг руки {THE($user)} образуется причудливое лезвие! +changeling-armblade-success-self = Ваша рука изгибается и мутирует, превращаясь в смертоносный клинок. +changeling-armblade-retract-others = Клинок {CAPITALIZE(THE($target))} впитывается обратно в руку! +changeling-armblade-retract-self = Вы впитываете клинок обратно в свою руку. +changeling-armor-success-others = Тело {CAPITALIZE(THE($target))} набирает бронированную защитную массу! +changeling-armor-success-self = Ваше тело набирает защитную массу. +changeling-armor-retract-others = Броня {CAPITALIZE(THE($target))} отслаивается. +changeling-armor-retract-self = Ваша броня отслаивается. +changeling-regenerate-others-success = {CAPITALIZE(THE($user))} быстро излечивает все раны, издавая громкий, странный звук! +changeling-regenerate-self-success = Вы чувствуете зуд, как внутри, так и снаружи, когда ваши ткани восстанавливаются снова и снова! +changeling-regenerate-fail-not-crit = Вы не в критическом состоянии! +changeling-regenerate-fail-dead = Вы мертвы! +changeling-chameleon-toggle-on = Ваша кожа переливается прозрачной оболочкой... +changeling-chameleon-toggle-off = Ваша кожа возвращается к нормальному виду. +changeling-dna-stage-1 = Это существо подходит для взятия ДНК. Вы должны стоять неподвижно... +changeling-dna-stage-2-self = Вы вытягиваете жало. +changeling-dna-stage-2-others = {CAPITALIZE(THE($user))} вытягивает жало! +changeling-dna-stage-3-self = Вы укалываете {THE($target)} своим жалом! +changeling-dna-stage-3-others = {CAPITALIZE(THE($user))} укалывает {THE($target)} жалом! +changeling-dna-success = Вы впитали ДНК {THE($target)}. +changeling-dna-success-ling = Вы впитали ДНК {THE($target)}. Это был другой генокрад! Вы набрали 5 очков эволюции. +changeling-dna-fail-nohuman = {CAPITALIZE(THE($target))} не гуманоид. +changeling-dna-fail-notdead = {CAPITALIZE(THE($target))} не критическом состоянии или мёртв. +changeling-dna-interrupted = Поглощение ДНК {THE($target)} было прервано. +changeling-dna-alreadyabsorbed = ДНК {CAPITALIZE(THE($target))} уже собраны! +changeling-dna-nodna = {CAPITALIZE(THE($target))} не имеет ДНК! +changeling-dna-switchdna = Переключился на ДНК {$target}. +changeling-transform-activate = Вы превратились в {$target}. +changeling-transform-fail-already = Вы уже превратились в {$target}! +changeling-transform-fail-mutation = Ваше тело слишком искажено для превращения! +changeling-sting-fail-self = Ужалить {THE($target)} не вышло! +changeling-sting-fail-target = Вы чувствуёте лёгкое покалывание. +changeling-dna-sting = Вы забираете образец ДНК {THE($target)}. +changeling-dna-sting-fail-nodna = {CAPITALIZE(THE($target))} не имеет ДНК! +changeling-dna-sting-fail-alreadydna = У вас уже есть ДНК {THE($target)}! +changeling-stasis-death-self-success = Вы впадаете в стазис. +changeling-stasis-death-self-revive = Вы восстаёте из мёртвых! +changeling-refresh-not-ready = Сначала поглотите существо. +changeling-adrenaline-self-success = Боль начинает уходить. +changeling-refresh-self-success = Успешно очищена цепочка ДНК. +changeling-omnizine-self-success = Ваша плоть начинает восстанавливаться. +changeling-success-sting = Вы успешно ужалили {CAPITALIZE(THE($target))}! +changeling-dna-sting-fail-full = Вы не сможете собрать ещё одну цепочку ДНК! +changeling-lingmuscles = Ваши мышцы быстро меняются! +changeling-lesser-form-activate-monkey = Вы превратились в обезьяну! +changeling-transform-fail-lesser-form = Вы не можете использовать данную способность в этой форме! +changeling-armshield-fail = Нужна свободная рука! +changeling-armshield-success-others = Вокруг руки {THE($user)} образуется массивный щит! +changeling-armshield-success-self = Ваша рука изгибается и мутирует, превращаясь в огромный массивный щит. +changeling-armshield-retract-others = Щит {CAPITALIZE(THE($target))} впитывается обратно в руку! +changeling-armshield-retract-self = Вы впитываете щит обратно в свою руку. +changeling-armshield-broke-others = Щит {CAPITALIZE(THE($user))} разорвался и впитался обратно! +changeling-armshield-broke-self = Ваш щит был пробит! +changeling-eggs-self-start = Вы начинаете откладывать личинки в {CAPITALIZE(THE($target))}. +changeling-eggs-self-success = Вы успешно оставили кладку в {CAPITALIZE(THE($target))}. +changeling-eggs-interrupted = Кладка была прервана! +changeling-egg-others = Личинки в теле {THE($user)} начинают активно шевелиться и разрастаться! +changeling-egg-self = Личинки прорастают, готовясь вырваться наружу. +changeling-biodegrade-start = Вы начинаете расплавлять наручники. +changeling-biodegrade-interrupted = Освобождение было прервано! +changeling-biodegrade-fail-nocuffs = На вас нет наручников. +changeling-transform-fail-nodna = У вас нет сохранённых ДНК! +changeling-armace-success-others = Кости и плоть руки {THE($user)} преобразуются в огромный молот! +changeling-armace-success-self = Ваша рука изгибается и мутирует, превращаясь в огромный молот. +changeling-armace-retract-others = Молот {CAPITALIZE(THE($target))} впитывается обратно в руку! +changeling-armace-retract-self = Вы впитываете молот обратно в свою руку. +defibrillator-changeling-slug = Внутри тела обнаружен паразит. +changeling-slug-almost-ready = Скоро вы выберетесь наружу. +changeling-digital-camo-toggle-on = Вы скрываетесь от камер. +changeling-digital-camo-toggle-off = Вы снова двигаетесь нормально. +changeling-digital-camo-desc = [color=white]{CAPITALIZE($user)} двигается неестественными рывками.[/color] +changeling-digi-camo-fail-chameleon = Сначала выключите хамелеон. +changeling-chameleon-fail-digi-camo = Сначала выключите цифровой камуфляж. diff --git a/Resources/Locale/ru-RU/ADT/changeling/store_changeling.ftl b/Resources/Locale/ru-RU/ADT/changeling/store_changeling.ftl new file mode 100644 index 00000000000..cc3220c83a8 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/changeling/store_changeling.ftl @@ -0,0 +1,59 @@ +listing-arm-blade = Рука-клинок +listing-arm-blade-desc = Превращает одну из ваших рук в клинок, сделанный из кости и плоти. Клинок наносит 40 повреждений за удар, позволяет с легкостью отрубать конечности. + +listing-chitinous-armor = Хитиновая броня +listing-chitinous-armor-desc = Наращивает на вашем теле массивный хитиновый покров, хорошо защищающий от физических повреждений. Немного замедляет регенерацию химикатов, пока активна. + +listing-chameleon-skin = Хамелеон +listing-chameleon-skin-desc = Измените пигментацию своей кожи для маскировки и слияния с окружением. Маскировка быстро спадает при движении. + +listing-dissonant-shriek = Диссонирующий рёв +listing-dissonant-shriek-desc = Позволяет вам издать высокочастотный рёв, перегружающий ближающую электронику. + +listing-blind-sting = Жало ослепления +listing-blind-sting-desc = Полностью ослепляет цель на непродолжительный срок. + +listing-adrenaline = Выброс адреналина +listing-adrenaline-desc = Временно отключить болевые рецепторы для более быстрого передвижения с травмами. + +listing-fleshmend = Исцеление плоти +listing-fleshmend-desc = Ваше тело моментально заживляет многие раны и ожоги. + +listing-mute-sting = Жало безмолвия +listing-mute-sting-desc = Лишает цель возможности говорить на некоторое время. + +listing-strained-muscles = Напряжённые мышцы +listing-strained-muscles-desc = Ваши мышцы ног начинают сокращаться, позволяя вам бегать с крайне высокой скоростью. Пока активно, тратит вашу выносливость, и в итоге может привести к перенагрузке. Пока активно, вас невозможно сбить с ног. + +listing-lesser-form = Низшая форма +listing-lesser-form-desc = Превратитесь в обезьяну. В форме обезьяны вы свободно можете использовать только жала. Вы сможете вернуться в форму гуманоида по желанию. + +listing-drug-sting = Галлюценогенное жало +listing-drug-sting-desc = Вводит цели большое количество галлюценогена. Цель ни о чём не догадается, пока вокруг неё не начнёт происходить хаос. + +listing-arm-shield = Органический щит +listing-arm-shield-desc = Превращает одну из ваших свободных рук в массивный щит, сделанный из плоти. Каждое поглощение усиливает его. + +listing-last-resort = Последний шанс +listing-last-resort-desc = Разорвите собственное тело и высвободите свою настоящую форму для последующей кладки личинок в новое тело. Данную способность можно использовать лишь единожды. + +listing-biodegrade = Плевок кислотой +listing-biodegrade-desc = Уничтожьте надетые на вас наручники. Окружающие могут заметить использование этой способности. + +listing-resonant-shriek = Резонантный рёв +listing-resonant-shriek-desc = Дезориентируйте окружающих вас не-генокрадов с помощью высокочастотного звука. + +listing-transform-sting = Жало трансформации +listing-transform-sting-desc = Заставьте цель принять выбранную вами форму. + +listing-arm-mace = Рука-молот +listing-arm-mace-desc = Превращает одну из ваших рук в громадный молот из плоти. Молот наносит большое количество структурного урона, а так же откидывает цели. + +listing-digi-camo = Цифровой камуфляж +listing-digi-camo-desc = Начните двигаться особым образом, предотвращая ваше обнаружение позитронными сенсорами. В этот список входят ИИ станции, киборги и КПБ. Тем не менее, ваши странные движения могут вызвать вопросы у экипажа. + +listing-bone-shard = Костяной сюрикен +listing-bone-shard-desc = Создайте из своих костей острый сюрикен, что просуществует 30 секунд. Этим вы нанесёте себе небольшой урон. + +changeling-refresh = Сброс ДНК +changeling-refresh-desc = Сбросьте все свои способности для выбора новых. diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Objectives/steal-target-groups.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Objectives/steal-target-groups.ftl index d46aa9a73ed..bf7a09305c3 100644 --- a/Resources/Locale/ru-RU/ADT/prototypes/Objectives/steal-target-groups.ftl +++ b/Resources/Locale/ru-RU/ADT/prototypes/Objectives/steal-target-groups.ftl @@ -1,2 +1,4 @@ steal-target-groups-clothing-mask-gas-ce = противогаз старшего инженера steal-target-groups-adt-mobile-defibrillator = мобильный дефибриллятор +steal-target-groups-command-id = ID карта члена командования +steal-target-groups-smile-extract = экстракт Смайла diff --git a/Resources/Locale/ru-RU/store/currency.ftl b/Resources/Locale/ru-RU/store/currency.ftl index 339201d06d1..62ad9412cae 100644 --- a/Resources/Locale/ru-RU/store/currency.ftl +++ b/Resources/Locale/ru-RU/store/currency.ftl @@ -12,6 +12,4 @@ store-currency-display-telecrystal = ТК store-currency-display-stolen-essence = Украденная эссенция store-currency-display-wizcoin = Маг₭øин™ -store-currency-display-evolution-points = Очки Эволюции - store-currency-display-tradeunit = ЕТ diff --git a/Resources/Maps/Ruins/corvax_sanctus.yml b/Resources/Maps/Ruins/corvax_sanctus.yml deleted file mode 100644 index c41f87c0608..00000000000 --- a/Resources/Maps/Ruins/corvax_sanctus.yml +++ /dev/null @@ -1,1739 +0,0 @@ -meta: - format: 6 - postmapinit: false -tilemap: - 0: Space - 12: FloorAstroGrass - 3: FloorBrassFilled - 1: FloorCave - 2: FloorElevatorShaft - 4: FloorHullReinforced - 136: FloorWoodLargeLight - 138: FloorWoodLight - 139: FloorWoodParquet - 146: Lattice - 147: Plating -entities: -- proto: "" - entities: - - uid: 2 - components: - - type: MetaData - name: "" - - type: Transform - pos: 0.390625,-0.390625 - parent: invalid - - type: MapGrid - chunks: - 0,0: - ind: 0,0 - tiles: AQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - 0,-1: - ind: 0,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAwAAAAAAAQAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - -1,0: - ind: -1,0 - tiles: AAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - -1,-1: - ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAkwAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAQAAAAAAAwAAAAAAAgAAAAAAAgAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAgAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAQAAAAAAAwAAAAAAAgAAAAAABAAAAAAAAwAAAAAAAwAAAAAAAwAAAAAAAwAAAAAABAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAAAAgAAAAAAAgAAAAAAAQAAAAAAAgAAAAAAAQAAAAAAAQAAAAAAAwAAAAAAAgAAAAAAAQAAAAAA - version: 6 - -2,-1: - ind: -2,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - - type: Broadphase - - type: Physics - bodyStatus: InAir - angularDamping: 0.05 - linearDamping: 0.05 - fixedRotation: False - bodyType: Dynamic - - type: Fixtures - fixtures: {} - - type: OccluderTree - - type: SpreaderGrid - - type: Shuttle - - type: GridPathfinding - - type: Gravity - gravityShakeSound: !type:SoundPathSpecifier - path: /Audio/Effects/alert.ogg - - type: DecalGrid - chunkCollection: - version: 2 - nodes: - - node: - color: '#FFFFFFFF' - id: Basalt1 - decals: - 54: -14,-2 - 103: -7,-13 - - node: - color: '#FFFFFFFF' - id: Basalt2 - decals: - 56: -12,3 - 105: -11,-10 - - node: - color: '#FFFFFFFF' - id: Basalt3 - decals: - 63: 1,-1 - 107: -13,-4 - - node: - color: '#FFFFFFFF' - id: Basalt5 - decals: - 57: -4,5 - 58: 6,-8 - 59: 1,-13 - 60: -9,-6 - - node: - color: '#FFFFFFFF' - id: Basalt7 - decals: - 53: -15,-6 - 61: -10,-5 - 64: 2,-3 - 106: -15,-9 - - node: - color: '#FFFFFFFF' - id: Basalt8 - decals: - 55: -8,5 - 62: -2,-8 - - node: - color: '#FFFFFFFF' - id: Basalt9 - decals: - 104: -1,-14 - - node: - color: '#FFFFFFFF' - id: Dirt - decals: - 65: -8,-6 - 66: -8,-5 - 67: -10,-4 - 68: -9,-4 - 69: -8,-3 - 71: -3,-10 - 72: -2,-10 - 73: 1,-6 - 74: 1,-5 - 75: 2,-2 - 76: 3,-3 - 77: 3,-4 - 78: -2,1 - 79: -4,1 - 80: -5,1 - 81: -3,-1 - 82: -4,0 - 83: -4,-2 - 84: -6,-4 - 85: -10,-2 - 86: -5,2 - 87: -1,2 - 88: -8,-1 - 89: -7,-3 - 90: -5,-11 - 93: 1,-8 - 94: 2,-7 - 95: 2,-6 - 96: 3,-7 - 97: 3,-6 - 98: 0,-4 - 99: 0,-3 - 100: -3,-8 - 102: -7,-10 - 124: -4,-12 - 125: -4,-11 - 126: -4,-8 - 127: -4,-9 - 128: -2,-11 - - node: - color: '#9C2020FF' - id: body - decals: - 46: -2,-7 - - node: - color: '#1D1D21FF' - id: splatter - decals: - 50: -6,-3 - 51: -2,-2 - 52: -5,-2 - - node: - color: '#571212FF' - id: splatter - decals: - 47: -5,-7 - 48: -6,-6 - 49: -1,-6 - - type: GridAtmosphere - version: 2 - data: - chunkSize: 4 - - type: GasTileOverlay - - type: RadiationGridResistance -- proto: AltarFangs - entities: - - uid: 51 - components: - - type: Transform - pos: -1.5,-5.5 - parent: 2 - - uid: 274 - components: - - type: Transform - pos: -4.5,-5.5 - parent: 2 -- proto: AltarHeaven - entities: - - uid: 60 - components: - - type: Transform - pos: -4.5,-2.5 - parent: 2 - - uid: 252 - components: - - type: Transform - pos: -1.5,-2.5 - parent: 2 -- proto: ArmBlade - entities: - - uid: 75 - components: - - type: Transform - pos: -9.542018,-1.4161515 - parent: 2 -- proto: BibleNecronomicon - entities: - - uid: 153 - components: - - type: Transform - pos: 4.5,-8.5 - parent: 2 -- proto: Bloodpack - entities: - - uid: 111 - components: - - type: Transform - pos: -1.5,-6.5 - parent: 2 -- proto: BookNarsieLegend - entities: - - uid: 44 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 3.5,-6.5 - parent: 2 -- proto: ButchCleaver - entities: - - uid: 11 - components: - - type: Transform - pos: 3.5,1.5 - parent: 2 -- proto: CandleInfinite - entities: - - uid: 42 - components: - - type: Transform - pos: -4.5,-9.5 - parent: 2 - - uid: 224 - components: - - type: Transform - pos: -1.5,1.5 - parent: 2 -- proto: CandleRedSmallInfinite - entities: - - uid: 41 - components: - - type: Transform - pos: -7.5,-2.5 - parent: 2 - - uid: 106 - components: - - type: Transform - pos: -0.5914495,0.29293394 - parent: 2 - - uid: 142 - components: - - type: Transform - pos: -0.1695745,-4.863316 - parent: 2 - - uid: 143 - components: - - type: Transform - pos: -5.8258247,-7.6133156 - parent: 2 - - uid: 173 - components: - - type: Transform - pos: -7.3570747,-2.191441 - parent: 2 - - uid: 222 - components: - - type: Transform - pos: 0.5,-1.5 - parent: 2 - - uid: 223 - components: - - type: Transform - pos: -6.5,-7.5 - parent: 2 -- proto: CandleSmall - entities: - - uid: 228 - components: - - type: Transform - pos: -5.5,-10.5 - parent: 2 -- proto: ChairBrass - entities: - - uid: 199 - components: - - type: Transform - pos: -0.5,1.5 - parent: 2 - - uid: 208 - components: - - type: Transform - pos: -6.5,1.5 - parent: 2 - - uid: 210 - components: - - type: Transform - pos: -1.5,0.5 - parent: 2 -- proto: ChairRitual - entities: - - uid: 52 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -0.5,-8.5 - parent: 2 - - uid: 53 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 0.5,-8.5 - parent: 2 - - uid: 64 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 0.5,-9.5 - parent: 2 - - uid: 235 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -5.5,-9.5 - parent: 2 - - uid: 238 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -4.5,-8.5 - parent: 2 - - uid: 243 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -0.5,-9.5 - parent: 2 -- proto: ClockworkGirder - entities: - - uid: 63 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -0.5,-1.5 - parent: 2 - - uid: 70 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -5.5,-1.5 - parent: 2 -- proto: ClockworkShield - entities: - - uid: 45 - components: - - type: Transform - pos: -4.5,-2.5 - parent: 2 -- proto: ClockworkWindow - entities: - - uid: 74 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,1.5 - parent: 2 - - uid: 80 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,-8.5 - parent: 2 - - uid: 167 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,-9.5 - parent: 2 - - uid: 179 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -8.5,0.5 - parent: 2 - - uid: 192 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -7.5,1.5 - parent: 2 - - uid: 236 - components: - - type: Transform - pos: 2.5,-8.5 - parent: 2 -- proto: ClothingHeadHatHoodCulthood - entities: - - uid: 254 - components: - - type: Transform - pos: 2.5,-3.5 - parent: 2 -- proto: ClothingHeadHatRedwizard - entities: - - uid: 5 - components: - - type: Transform - pos: -10.5,-9.5 - parent: 2 -- proto: ClothingHeadHelmetCult - entities: - - uid: 255 - components: - - type: Transform - pos: -7.5,-5.5 - parent: 2 -- proto: ClothingOuterRobesCult - entities: - - uid: 3 - components: - - type: Transform - pos: -5.5,0.5 - parent: 2 -- proto: ClothingOuterWizardRed - entities: - - uid: 1 - components: - - type: Transform - pos: -10.5,-9.5 - parent: 2 -- proto: ClothingShoesCult - entities: - - uid: 256 - components: - - type: Transform - pos: -2.5,-8.5 - parent: 2 -- proto: ComplexXenoArtifact - entities: - - uid: 244 - components: - - type: Transform - pos: -2.955439,-3.9142942 - parent: 2 -- proto: CrystalGrey - entities: - - uid: 137 - components: - - type: Transform - pos: -5.5,-13.5 - parent: 2 - - uid: 138 - components: - - type: Transform - pos: -11.5,0.5 - parent: 2 - - uid: 139 - components: - - type: Transform - pos: -11.5,-11.5 - parent: 2 - - uid: 140 - components: - - type: Transform - pos: 5.5,-6.5 - parent: 2 - - uid: 141 - components: - - type: Transform - pos: -0.5,4.5 - parent: 2 -- proto: CrystalOrange - entities: - - uid: 38 - components: - - type: Transform - pos: 6.5,-0.5 - parent: 2 - - uid: 205 - components: - - type: Transform - pos: -14.5,-6.5 - parent: 2 - - uid: 206 - components: - - type: Transform - pos: -6.5,4.5 - parent: 2 - - uid: 215 - components: - - type: Transform - pos: 2.5,-12.5 - parent: 2 -- proto: DrinkBloodGlass - entities: - - uid: 233 - components: - - type: Transform - pos: -1.5,-5.5 - parent: 2 -- proto: FloorTileItemBrassFilled - entities: - - uid: 46 - components: - - type: Transform - pos: -1.5,-3.5 - parent: 2 - - uid: 160 - components: - - type: Transform - pos: -6.5,-4.5 - parent: 2 - - uid: 168 - components: - - type: Transform - pos: -3.5,-9.5 - parent: 2 - - uid: 187 - components: - - type: Transform - pos: 2.5,-2.5 - parent: 2 - - uid: 188 - components: - - type: Transform - pos: -3.5,-0.5 - parent: 2 - - uid: 272 - components: - - type: Transform - pos: -8.5,-1.5 - parent: 2 -- proto: FloorTileItemElevatorShaft - entities: - - uid: 26 - components: - - type: Transform - pos: -6.5,-0.5 - parent: 2 - - uid: 71 - components: - - type: Transform - pos: -2.5,2.5 - parent: 2 - - uid: 72 - components: - - type: Transform - pos: -2.5,-6.5 - parent: 2 - - uid: 273 - components: - - type: Transform - pos: 1.5,-6.5 - parent: 2 -- proto: FloraRockSolid01 - entities: - - uid: 110 - components: - - type: Transform - pos: -8.5,-11.5 - parent: 2 - - uid: 149 - components: - - type: Transform - pos: 3.5,-9.5 - parent: 2 -- proto: FloraRockSolid02 - entities: - - uid: 112 - components: - - type: Transform - pos: -14.5,-4.5 - parent: 2 - - uid: 115 - components: - - type: Transform - pos: -3.5,4.5 - parent: 2 -- proto: FloraRockSolid03 - entities: - - uid: 114 - components: - - type: Transform - pos: -13.5,-0.5 - parent: 2 -- proto: HamtrHarness - entities: - - uid: 69 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -5.5,-2.5 - parent: 2 -- proto: HamtrLArm - entities: - - uid: 144 - components: - - type: Transform - pos: -6.5,-3.5 - parent: 2 -- proto: HonkerHarness - entities: - - uid: 209 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -4.5,-1.5 - parent: 2 -- proto: KitchenSpike - entities: - - uid: 247 - components: - - type: Transform - pos: -1.5,-6.5 - parent: 2 - - uid: 258 - components: - - type: Transform - pos: -4.5,-6.5 - parent: 2 - - uid: 260 - components: - - type: Transform - pos: -5.5,-5.5 - parent: 2 - - uid: 261 - components: - - type: Transform - pos: -0.5,-5.5 - parent: 2 -- proto: LeftArmArachnid - entities: - - uid: 152 - components: - - type: Transform - pos: -0.5,-5.5 - parent: 2 -- proto: MaterialWoodPlank1 - entities: - - uid: 8 - components: - - type: Transform - pos: -5.5,-8.5 - parent: 2 - - uid: 200 - components: - - type: Transform - pos: -1.5,-8.5 - parent: 2 -- proto: PinionAirlock - entities: - - uid: 4 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -10.5,-4.5 - parent: 2 - - uid: 161 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -3.5,3.5 - parent: 2 - - uid: 164 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -10.5,-3.5 - parent: 2 -- proto: PinionAirlockAssembly - entities: - - uid: 48 - components: - - type: Transform - pos: -3.5,-11.5 - parent: 2 - - uid: 163 - components: - - type: Transform - pos: 4.5,-4.5 - parent: 2 - - uid: 165 - components: - - type: Transform - pos: -2.5,3.5 - parent: 2 - - uid: 257 - components: - - type: Transform - pos: -2.5,-11.5 - parent: 2 -- proto: PlushieNar - entities: - - uid: 259 - components: - - type: Transform - pos: -3.5,-5.5 - parent: 2 -- proto: PlushieRatvar - entities: - - uid: 246 - components: - - type: Transform - pos: -2.5,-2.5 - parent: 2 -- proto: RandomGreyStalagmite - entities: - - uid: 217 - components: - - type: Transform - pos: -5.5,2.5 - parent: 2 - - uid: 218 - components: - - type: Transform - pos: 0.5,-7.5 - parent: 2 - - uid: 219 - components: - - type: Transform - pos: 0.5,1.5 - parent: 2 - - uid: 220 - components: - - type: Transform - pos: -8.5,-6.5 - parent: 2 - - uid: 231 - components: - - type: Transform - pos: -4.5,-7.5 - parent: 2 -- proto: RightArmVox - entities: - - uid: 146 - components: - - type: Transform - pos: -5.5,-5.5 - parent: 2 -- proto: RipleyHarness - entities: - - uid: 249 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -1.5,-1.5 - parent: 2 -- proto: RitualDagger - entities: - - uid: 245 - components: - - type: Transform - pos: -4.5,-5.5 - parent: 2 -- proto: ShadowBasaltFour - entities: - - uid: 175 - components: - - type: Transform - pos: -0.5,-7.5 - parent: 2 -- proto: ShadowBasaltOne - entities: - - uid: 195 - components: - - type: Transform - pos: -8.5,-4.5 - parent: 2 -- proto: ShadowBasaltRandom - entities: - - uid: 174 - components: - - type: Transform - pos: -4.5,-0.5 - parent: 2 -- proto: ShadowBasaltTwo - entities: - - uid: 7 - components: - - type: Transform - pos: -9.5,-6.5 - parent: 2 - - uid: 176 - components: - - type: Transform - pos: -1.5,-3.5 - parent: 2 -- proto: ShardGlassClockwork - entities: - - uid: 25 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -8.5,-7.5 - parent: 2 - - uid: 82 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -6.5,-6.5 - parent: 2 - - uid: 85 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -6.5,-9.5 - parent: 2 - - uid: 158 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,-1.5 - parent: 2 - - uid: 159 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -7.5,-0.5 - parent: 2 - - uid: 162 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -0.5,-0.5 - parent: 2 -- proto: SheetBrass1 - entities: - - uid: 170 - components: - - type: Transform - pos: -5.5,1.5 - parent: 2 - - uid: 186 - components: - - type: Transform - pos: -4.5,0.5 - parent: 2 -- proto: SheetBrass10 - entities: - - uid: 207 - components: - - type: Transform - pos: 0.5,0.5 - parent: 2 -- proto: SheetClockworkGlass1 - entities: - - uid: 232 - components: - - type: Transform - pos: -1.5,-2.5 - parent: 2 -- proto: SpaceTickSpawner - entities: - - uid: 40 - components: - - type: Transform - pos: 4.5,-8.5 - parent: 2 - - uid: 151 - components: - - type: Transform - pos: 4.5,-8.5 - parent: 2 - - uid: 212 - components: - - type: Transform - pos: 4.5,-8.5 - parent: 2 -- proto: SpawnMobCarpHolo - entities: - - uid: 147 - components: - - type: Transform - pos: 0.5,-6.5 - parent: 2 -- proto: SpawnMobCarpMagic - entities: - - uid: 216 - components: - - type: Transform - pos: -9.5,-6.5 - parent: 2 -- proto: SpawnMobHellspawn - entities: - - uid: 43 - components: - - type: Transform - pos: -6.5,-1.5 - parent: 2 -- proto: TableBrass - entities: - - uid: 169 - components: - - type: Transform - pos: -9.5,-1.5 - parent: 2 -- proto: VimHarness - entities: - - uid: 68 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -0.5,-2.5 - parent: 2 -- proto: WallCult - entities: - - uid: 9 - components: - - type: Transform - pos: -6.5,2.5 - parent: 2 - - uid: 10 - components: - - type: Transform - pos: 0.5,-10.5 - parent: 2 - - uid: 13 - components: - - type: Transform - pos: -5.5,-1.5 - parent: 2 - - uid: 14 - components: - - type: Transform - pos: 0.5,2.5 - parent: 2 - - uid: 15 - components: - - type: Transform - pos: -0.5,-6.5 - parent: 2 - - uid: 16 - components: - - type: Transform - pos: -11.5,-5.5 - parent: 2 - - uid: 17 - components: - - type: Transform - pos: -5.5,3.5 - parent: 2 - - uid: 19 - components: - - type: Transform - pos: -9.5,-8.5 - parent: 2 - - uid: 20 - components: - - type: Transform - pos: -10.5,-1.5 - parent: 2 - - uid: 27 - components: - - type: Transform - pos: 4.5,-7.5 - parent: 2 - - uid: 29 - components: - - type: Transform - pos: 0.5,-11.5 - parent: 2 - - uid: 30 - components: - - type: Transform - pos: -5.5,-6.5 - parent: 2 - - uid: 31 - components: - - type: Transform - pos: -5.5,-11.5 - parent: 2 - - uid: 33 - components: - - type: Transform - pos: 3.5,-0.5 - parent: 2 - - uid: 34 - components: - - type: Transform - pos: -4.5,3.5 - parent: 2 - - uid: 35 - components: - - type: Transform - pos: 3.5,-7.5 - parent: 2 - - uid: 37 - components: - - type: Transform - pos: -0.5,-1.5 - parent: 2 - - uid: 49 - components: - - type: Transform - pos: -1.5,-11.5 - parent: 2 - - uid: 62 - components: - - type: Transform - pos: 1.5,-10.5 - parent: 2 - - uid: 73 - components: - - type: Transform - pos: -7.5,-10.5 - parent: 2 - - uid: 79 - components: - - type: Transform - pos: 5.5,-2.5 - parent: 2 - - uid: 81 - components: - - type: Transform - pos: -10.5,-7.5 - parent: 2 - - uid: 83 - components: - - type: Transform - pos: -10.5,-2.5 - parent: 2 - - uid: 89 - components: - - type: Transform - pos: 4.5,-0.5 - parent: 2 - - uid: 91 - components: - - type: Transform - pos: -6.5,-11.5 - parent: 2 - - uid: 92 - components: - - type: Transform - pos: -10.5,-0.5 - parent: 2 - - uid: 93 - components: - - type: Transform - pos: -11.5,-2.5 - parent: 2 - - uid: 94 - components: - - type: Transform - pos: -9.5,-0.5 - parent: 2 - - uid: 97 - components: - - type: Transform - pos: 3.5,0.5 - parent: 2 - - uid: 166 - components: - - type: Transform - pos: -0.5,-11.5 - parent: 2 - - uid: 172 - components: - - type: Transform - pos: -6.5,3.5 - parent: 2 - - uid: 177 - components: - - type: Transform - pos: -1.5,-12.5 - parent: 2 - - uid: 180 - components: - - type: Transform - pos: -0.5,3.5 - parent: 2 - - uid: 184 - components: - - type: Transform - pos: -1.5,4.5 - parent: 2 - - uid: 185 - components: - - type: Transform - pos: 4.5,-2.5 - parent: 2 - - uid: 189 - components: - - type: Transform - pos: -10.5,-5.5 - parent: 2 - - uid: 190 - components: - - type: Transform - pos: 1.5,2.5 - parent: 2 - - uid: 191 - components: - - type: Transform - pos: -4.5,4.5 - parent: 2 - - uid: 193 - components: - - type: Transform - pos: 4.5,-1.5 - parent: 2 - - uid: 194 - components: - - type: Transform - pos: 5.5,-5.5 - parent: 2 - - uid: 196 - components: - - type: Transform - pos: -10.5,-6.5 - parent: 2 - - uid: 198 - components: - - type: Transform - pos: 4.5,-6.5 - parent: 2 - - uid: 203 - components: - - type: Transform - pos: -7.5,2.5 - parent: 2 - - uid: 204 - components: - - type: Transform - pos: -9.5,0.5 - parent: 2 - - uid: 250 - components: - - type: Transform - pos: -9.5,-7.5 - parent: 2 - - uid: 264 - components: - - type: Transform - pos: -1.5,3.5 - parent: 2 - - uid: 265 - components: - - type: Transform - pos: 4.5,-5.5 - parent: 2 - - uid: 267 - components: - - type: Transform - pos: 0.5,3.5 - parent: 2 - - uid: 270 - components: - - type: Transform - pos: -4.5,-11.5 - parent: 2 - - uid: 271 - components: - - type: Transform - pos: -6.5,-10.5 - parent: 2 - - uid: 275 - components: - - type: Transform - pos: 3.5,-8.5 - parent: 2 - - uid: 278 - components: - - type: Transform - pos: -4.5,-12.5 - parent: 2 -- proto: WallRock - entities: - - uid: 6 - components: - - type: Transform - pos: 5.5,0.5 - parent: 2 - - uid: 12 - components: - - type: Transform - pos: -8.5,2.5 - parent: 2 - - uid: 18 - components: - - type: Transform - pos: -12.5,-0.5 - parent: 2 - - uid: 22 - components: - - type: Transform - pos: -9.5,3.5 - parent: 2 - - uid: 23 - components: - - type: Transform - pos: -7.5,4.5 - parent: 2 - - uid: 28 - components: - - type: Transform - pos: -11.5,-10.5 - parent: 2 - - uid: 36 - components: - - type: Transform - pos: -9.5,-10.5 - parent: 2 - - uid: 39 - components: - - type: Transform - pos: -16.5,-3.5 - parent: 2 - - uid: 47 - components: - - type: Transform - pos: 0.5,-13.5 - parent: 2 - - uid: 50 - components: - - type: Transform - pos: -11.5,-1.5 - parent: 2 - - uid: 54 - components: - - type: Transform - pos: 3.5,-12.5 - parent: 2 - - uid: 55 - components: - - type: Transform - pos: 5.5,-13.5 - parent: 2 - - uid: 56 - components: - - type: Transform - pos: 4.5,-9.5 - parent: 2 - - uid: 57 - components: - - type: Transform - pos: -15.5,-2.5 - parent: 2 - - uid: 58 - components: - - type: Transform - pos: -12.5,1.5 - parent: 2 - - uid: 59 - components: - - type: Transform - pos: -9.5,-11.5 - parent: 2 - - uid: 61 - components: - - type: Transform - pos: 4.5,-12.5 - parent: 2 - - uid: 65 - components: - - type: Transform - pos: -11.5,-9.5 - parent: 2 - - uid: 66 - components: - - type: Transform - pos: -8.5,3.5 - parent: 2 - - uid: 67 - components: - - type: Transform - pos: -10.5,-11.5 - parent: 2 - - uid: 76 - components: - - type: Transform - pos: 6.5,-10.5 - parent: 2 - - uid: 77 - components: - - type: Transform - pos: 5.5,-12.5 - parent: 2 - - uid: 84 - components: - - type: Transform - pos: -4.5,-13.5 - parent: 2 - - uid: 88 - components: - - type: Transform - pos: -10.5,0.5 - parent: 2 - - uid: 95 - components: - - type: Transform - pos: -13.5,-6.5 - parent: 2 - - uid: 96 - components: - - type: Transform - pos: -7.5,-9.5 - parent: 2 - - uid: 98 - components: - - type: Transform - pos: -5.5,4.5 - parent: 2 - - uid: 100 - components: - - type: Transform - pos: 3.5,3.5 - parent: 2 - - uid: 101 - components: - - type: Transform - pos: 8.5,-3.5 - parent: 2 - - uid: 102 - components: - - type: Transform - pos: 9.5,-5.5 - parent: 2 - - uid: 103 - components: - - type: Transform - pos: 7.5,-2.5 - parent: 2 - - uid: 104 - components: - - type: Transform - pos: -7.5,-12.5 - parent: 2 - - uid: 105 - components: - - type: Transform - pos: 8.5,-6.5 - parent: 2 - - uid: 107 - components: - - type: Transform - pos: -7.5,-11.5 - parent: 2 - - uid: 109 - components: - - type: Transform - pos: -9.5,-9.5 - parent: 2 - - uid: 113 - components: - - type: Transform - pos: -2.5,-12.5 - parent: 2 - - uid: 116 - components: - - type: Transform - pos: 2.5,0.5 - parent: 2 - - uid: 118 - components: - - type: Transform - pos: 5.5,3.5 - parent: 2 - - uid: 119 - components: - - type: Transform - pos: 3.5,2.5 - parent: 2 - - uid: 120 - components: - - type: Transform - pos: 1.5,0.5 - parent: 2 - - uid: 121 - components: - - type: Transform - pos: 7.5,-7.5 - parent: 2 - - uid: 122 - components: - - type: Transform - pos: 0.5,-0.5 - parent: 2 - - uid: 123 - components: - - type: Transform - pos: 2.5,3.5 - parent: 2 - - uid: 124 - components: - - type: Transform - pos: 4.5,1.5 - parent: 2 - - uid: 125 - components: - - type: Transform - pos: -0.5,6.5 - parent: 2 - - uid: 126 - components: - - type: Transform - pos: 6.5,-2.5 - parent: 2 - - uid: 127 - components: - - type: Transform - pos: 7.5,-1.5 - parent: 2 - - uid: 128 - components: - - type: Transform - pos: -2.5,6.5 - parent: 2 - - uid: 129 - components: - - type: Transform - pos: 5.5,-0.5 - parent: 2 - - uid: 130 - components: - - type: Transform - pos: 7.5,-3.5 - parent: 2 - - uid: 131 - components: - - type: Transform - pos: 6.5,-4.5 - parent: 2 - - uid: 132 - components: - - type: Transform - pos: 5.5,-3.5 - parent: 2 - - uid: 134 - components: - - type: Transform - pos: 6.5,-5.5 - parent: 2 - - uid: 135 - components: - - type: Transform - pos: 8.5,-4.5 - parent: 2 - - uid: 136 - components: - - type: Transform - pos: -5.5,-12.5 - parent: 2 - - uid: 145 - components: - - type: Transform - pos: -3.5,-13.5 - parent: 2 - - uid: 150 - components: - - type: Transform - pos: -4.5,-14.5 - parent: 2 - - uid: 154 - components: - - type: Transform - pos: 5.5,-9.5 - parent: 2 - - uid: 155 - components: - - type: Transform - pos: 4.5,-10.5 - parent: 2 - - uid: 156 - components: - - type: Transform - pos: 3.5,-11.5 - parent: 2 - - uid: 157 - components: - - type: Transform - pos: 1.5,-13.5 - parent: 2 - - uid: 171 - components: - - type: Transform - pos: -9.5,1.5 - parent: 2 - - uid: 178 - components: - - type: Transform - pos: -8.5,-8.5 - parent: 2 - - uid: 181 - components: - - type: Transform - pos: -11.5,-6.5 - parent: 2 - - uid: 183 - components: - - type: Transform - pos: -11.5,-0.5 - parent: 2 - - uid: 197 - components: - - type: Transform - pos: -11.5,-7.5 - parent: 2 - - uid: 202 - components: - - type: Transform - pos: -7.5,0.5 - parent: 2 - - uid: 211 - components: - - type: Transform - pos: -3.5,7.5 - parent: 2 - - uid: 213 - components: - - type: Transform - pos: -0.5,-15.5 - parent: 2 - - uid: 214 - components: - - type: Transform - pos: -15.5,-8.5 - parent: 2 - - uid: 221 - components: - - type: Transform - pos: -14.5,-10.5 - parent: 2 - - uid: 225 - components: - - type: Transform - pos: -12.5,-7.5 - parent: 2 - - uid: 226 - components: - - type: Transform - pos: -14.5,-7.5 - parent: 2 - - uid: 227 - components: - - type: Transform - pos: -13.5,-8.5 - parent: 2 - - uid: 229 - components: - - type: Transform - pos: -12.5,-8.5 - parent: 2 - - uid: 230 - components: - - type: Transform - pos: -13.5,-7.5 - parent: 2 - - uid: 234 - components: - - type: Transform - pos: 4.5,-3.5 - parent: 2 - - uid: 237 - components: - - type: Transform - pos: -12.5,3.5 - parent: 2 - - uid: 239 - components: - - type: Transform - pos: -8.5,5.5 - parent: 2 - - uid: 240 - components: - - type: Transform - pos: 2.5,5.5 - parent: 2 - - uid: 241 - components: - - type: Transform - pos: -14.5,0.5 - parent: 2 - - uid: 242 - components: - - type: Transform - pos: 1.5,5.5 - parent: 2 - - uid: 248 - components: - - type: Transform - pos: 3.5,-4.5 - parent: 2 - - uid: 251 - components: - - type: Transform - pos: -7.5,-7.5 - parent: 2 - - uid: 253 - components: - - type: Transform - pos: -6.5,-8.5 - parent: 2 - - uid: 262 - components: - - type: Transform - pos: -11.5,-8.5 - parent: 2 - - uid: 263 - components: - - type: Transform - pos: -12.5,-9.5 - parent: 2 - - uid: 268 - components: - - type: Transform - pos: -8.5,-12.5 - parent: 2 - - uid: 269 - components: - - type: Transform - pos: -10.5,1.5 - parent: 2 - - uid: 277 - components: - - type: Transform - pos: -12.5,-10.5 - parent: 2 - - uid: 279 - components: - - type: Transform - pos: -7.5,-8.5 - parent: 2 - - uid: 281 - components: - - type: Transform - pos: -12.5,-2.5 - parent: 2 -- proto: WallRockArtifactFragment - entities: - - uid: 86 - components: - - type: Transform - pos: -10.5,-8.5 - parent: 2 - - uid: 201 - components: - - type: Transform - pos: -8.5,-9.5 - parent: 2 -- proto: WallRockBananium - entities: - - uid: 99 - components: - - type: Transform - pos: 5.5,-8.5 - parent: 2 - - uid: 133 - components: - - type: Transform - pos: 7.5,-4.5 - parent: 2 -- proto: WallRockGold - entities: - - uid: 24 - components: - - type: Transform - pos: -9.5,2.5 - parent: 2 - - uid: 276 - components: - - type: Transform - pos: -8.5,1.5 - parent: 2 -- proto: WallRockUranium - entities: - - uid: 117 - components: - - type: Transform - pos: 2.5,1.5 - parent: 2 - - uid: 148 - components: - - type: Transform - pos: -3.5,-12.5 - parent: 2 -- proto: WindowClockworkDirectional - entities: - - uid: 21 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -5.5,-2.5 - parent: 2 - - uid: 32 - components: - - type: Transform - pos: -1.5,-1.5 - parent: 2 - - uid: 78 - components: - - type: Transform - pos: -4.5,-1.5 - parent: 2 - - uid: 87 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -0.5,-2.5 - parent: 2 - - uid: 90 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -5.5,-5.5 - parent: 2 - - uid: 182 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: -0.5,-5.5 - parent: 2 - - uid: 266 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -1.5,-6.5 - parent: 2 - - uid: 280 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -4.5,-6.5 - parent: 2 -... diff --git a/Resources/Prototypes/ADT/Actions/changeling.yml b/Resources/Prototypes/ADT/Actions/changeling.yml new file mode 100644 index 00000000000..888e4f51d6f --- /dev/null +++ b/Resources/Prototypes/ADT/Actions/changeling.yml @@ -0,0 +1,426 @@ +- type: entity + id: ActionChangelingEvolutionMenu + name: action-evolution-menu + description: action-evolution-menu-decs + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: changelingsting + event: !type:ChangelingEvolutionMenuActionEvent + priority: -70 + +- type: entity + id: ActionChangelingAbsorb + name: action-absorb-dna + description: action-absorb-dna-desc + categories: [ HideSpawnMenu ] + components: + - type: EntityTargetAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: absorb_dna + itemIconStyle: BigAction + whitelist: + components: + - Body + event: !type:LingAbsorbActionEvent + useDelay: 5 + canTargetSelf: false + priority: -60 + +- type: entity + id: ActionChangelingTransform + name: action-transform + description: action-transform-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: transform + itemIconStyle: BigAction + event: !type:ChangelingTransformActionEvent + useDelay: 5 + priority: -69 + +- type: entity + id: ActionLingRegenerate + name: action-regenerate + description: action-regenerate-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + checkCanInteract: false + checkConsciousness: false + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: regenerate + itemIconStyle: BigAction + event: !type:LingRegenerateActionEvent + useDelay: 115 + priority: -66 + +- type: entity + id: ActionLingStingExtract + name: action-extract-dna-sting + description: action-extract-dna-sting-desc + categories: [ HideSpawnMenu ] + components: + - type: EntityTargetAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: sting_extract + itemIconStyle: BigAction + whitelist: + components: + - Body + event: !type:LingStingExtractActionEvent + useDelay: 30 + canTargetSelf: false + priority: -65 + +- type: entity + id: ActionArmBlade + name: action-toggle-arm-blade + description: action-toggle-arm-blade-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: armblade + itemIconStyle: BigAction + event: !type:ArmBladeActionEvent + useDelay: 1 + priority: -50 + +- type: entity + id: ActionLingArmor + name: action-toggle-chitinous-armor + description: action-toggle-chitinous-armor-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: chitinous_armor + itemIconStyle: BigAction + event: !type:LingArmorActionEvent + useDelay: 15 + priority: -49 + +- type: entity + id: ActionLingInvisible + name: action-toggle-chameleon-skin + description: action-toggle-chameleon-skin-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: chameleon_skin + itemIconStyle: BigAction + event: !type:LingInvisibleActionEvent + useDelay: 1 + priority: -48 + +- type: entity + id: ActionLingEMP + name: action-activate-dissonant-shriek + description: action-activate-dissonant-shriek-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: dissonant_shriek + itemIconStyle: BigAction + useDelay: 15 + event: !type:LingEMPActionEvent + priority: -47 + # Stasis Death + +- type: entity + id: ActionStasisDeath + name: action-stasis-death + description: action-stasis-death-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + checkCanInteract: false + checkConsciousness: false + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: fake_death + iconOn: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: revive + itemIconStyle: BigAction + event: !type:StasisDeathActionEvent + useDelay: 90 + priority: -46 + + # Blind sting +- type: entity + id: ActionLingBlindSting + name: action-blind-sting + description: action-blind-sting-desc + categories: [ HideSpawnMenu ] + components: + - type: EntityTargetAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: sting_blind + itemIconStyle: BigAction + whitelist: + components: + - Body + event: !type:BlindStingEvent + useDelay: 2 + canTargetSelf: false + priority: -64 + + # Adrenaline +- type: entity + id: ActionLingAdrenaline + name: action-adrenaline + description: action-adrenaline-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: adrenaline + itemIconStyle: BigAction + event: !type:AdrenalineActionEvent + useDelay: 90 + priority: -45 + + # Fleshmend +- type: entity + id: ActionLingFleshmend + name: action-fleshmend + description: action-fleshmend-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: fleshmend + itemIconStyle: BigAction + event: !type:FleshmendActionEvent + useDelay: 90 + priority: -44 + + # Mute sting +- type: entity + id: ActionLingMuteSting + name: action-mute-sting + description: action-mute-sting-desc + categories: [ HideSpawnMenu ] + components: + - type: EntityTargetAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: sting_mute + itemIconStyle: BigAction + whitelist: + components: + - Body + event: !type:MuteStingEvent + useDelay: 5 + canTargetSelf: false + priority: -63 + + # Drug sting +- type: entity + id: ActionLingDrugSting + name: action-drug-sting + description: action-drug-sting-desc + categories: [ HideSpawnMenu ] + components: + - type: EntityTargetAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: sting_lsd + itemIconStyle: BigAction + whitelist: + components: + - Body + event: !type:DrugStingEvent + useDelay: 5 + canTargetSelf: false + priority: -62 + + # Muscles +- type: entity + id: ActionLingMuscles + name: action-lingmuscles + description: action-lingmuscles-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: strained_muscles + itemIconStyle: BigAction + event: !type:ChangelingMusclesActionEvent + useDelay: 1 + priority: -43 + + # Lesser form +- type: entity + id: ActionLingLesserForm + name: action-lesser-form + description: action-lesser-form-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: lesser_form + iconOn: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: human_form + itemIconStyle: BigAction + checkCanInteract: false + event: !type:ChangelingLesserFormActionEvent + useDelay: 10 + priority: -67 + + # Arm shield +- type: entity + id: ActionArmShield + name: action-toggle-arm-shield + description: action-toggle-arm-shield-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: organic_shield + itemIconStyle: BigAction + event: !type:ArmShieldActionEvent + useDelay: 1 + priority: -51 + + # Last Resort +- type: entity + id: ActionLingLastResort + name: action-resort + description: action-resort-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: last_resort + itemIconStyle: BigAction + checkCanInteract: false + event: !type:LastResortActionEvent + useDelay: 1 + priority: -61 + + # Biodegrade +- type: entity + id: ActionLingBiodegrade + name: action-biodegrade + description: action-biodegrade-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: biodegrade + itemIconStyle: BigAction + checkCanInteract: false + event: !type:LingBiodegradeActionEvent + useDelay: 10 + priority: -61 + + # Resonant +- type: entity + id: ActionLingResonant + name: action-resonant + description: action-resonant-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: resonant_shriek + itemIconStyle: BigAction + checkCanInteract: false + event: !type:LingResonantShriekEvent + useDelay: 10 + priority: -61 + + # TSting +- type: entity + id: ActionLingTransformSting + name: action-transform-sting + description: action-transform-sting-desc + categories: [ HideSpawnMenu ] + components: + - type: EntityTargetAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: sting_transform + itemIconStyle: BigAction + event: !type:TransformationStingEvent + whitelist: + components: + - Body + canTargetSelf: false + useDelay: 10 + priority: -61 + + # Arm Hammer +- type: entity + id: ActionArmace + name: action-toggle-arm-hammer + description: action-toggle-arm-hammer-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: armhammer + itemIconStyle: BigAction + event: !type:ArmaceActionEvent + useDelay: 1 + priority: -51 + + # Digital Camo +- type: entity + id: ActionDigiCamo + name: action-digi-camo + description: action-digi-camo-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: digital_camo + itemIconStyle: BigAction + event: !type:DigitalCamouflageEvent + useDelay: 1 + priority: -55 + + # Bone shard +- type: entity + id: ActionBoneShard + name: action-bone-shard + description: action-bone-shard-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: bone_shard + itemIconStyle: BigAction + event: !type:ChangelingBoneShardEvent + useDelay: 15 + priority: -55 diff --git a/Resources/Prototypes/ADT/Alerts/alerts.yml b/Resources/Prototypes/ADT/Alerts/alerts.yml index 996eaf7c4eb..7d451a5d3a5 100644 --- a/Resources/Prototypes/ADT/Alerts/alerts.yml +++ b/Resources/Prototypes/ADT/Alerts/alerts.yml @@ -152,3 +152,27 @@ description: alerts-shadekin-power-desc minSeverity: 0 maxSeverity: 4 + +- type: alert + id: Chemicals + icons: + - sprite: /Textures/ADT/Changeling/Alerts/chemicals_counter.rsi + state: chemicals0 + - sprite: /Textures/ADT/Changeling/Alerts/chemicals_counter.rsi + state: chemicals1 + - sprite: /Textures/ADT/Changeling/Alerts/chemicals_counter.rsi + state: chemicals2 + - sprite: /Textures/ADT/Changeling/Alerts/chemicals_counter.rsi + state: chemicals3 + - sprite: /Textures/ADT/Changeling/Alerts/chemicals_counter.rsi + state: chemicals4 + - sprite: /Textures/ADT/Changeling/Alerts/chemicals_counter.rsi + state: chemicals5 + - sprite: /Textures/ADT/Changeling/Alerts/chemicals_counter.rsi + state: chemicals6 + - sprite: /Textures/ADT/Changeling/Alerts/chemicals_counter.rsi + state: chemicals7 + name: alerts-changeling-chemicals-name + description: alerts-changeling-chemicals-desc + minSeverity: 0 + maxSeverity: 7 diff --git a/Resources/Prototypes/ADT/Catalog/ling_catalog.yml b/Resources/Prototypes/ADT/Catalog/ling_catalog.yml new file mode 100644 index 00000000000..1917a74a510 --- /dev/null +++ b/Resources/Prototypes/ADT/Catalog/ling_catalog.yml @@ -0,0 +1,300 @@ +- type: listing + id: ChangelingArmBlade + name: listing-arm-blade + description: listing-arm-blade-desc + productAction: ActionArmBlade + mindAction: false + cost: + EvolutionPoints: 3 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingArmor + name: listing-chitinous-armor + description: listing-chitinous-armor-desc + productAction: ActionLingArmor + mindAction: false + cost: + EvolutionPoints: 3 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingChameleonSkin + name: listing-chameleon-skin + description: listing-chameleon-skin-desc + productAction: ActionLingInvisible + mindAction: false + cost: + EvolutionPoints: 3 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingEMP + name: listing-dissonant-shriek + description: listing-dissonant-shriek-desc + productAction: ActionLingEMP + mindAction: false + cost: + EvolutionPoints: 2 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingBlindSting + name: listing-blind-sting + description: listing-blind-sting-desc + productAction: ActionLingBlindSting + mindAction: false + cost: + EvolutionPoints: 2 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingAdrenaline + name: listing-adrenaline + description: listing-adrenaline-desc + productAction: ActionLingAdrenaline + mindAction: false + cost: + EvolutionPoints: 1 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingFleshmend + name: listing-fleshmend + description: listing-fleshmend-desc + productAction: ActionLingFleshmend + mindAction: false + cost: + EvolutionPoints: 3 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingMuteSting + name: listing-mute-sting + description: listing-mute-sting-desc + productAction: ActionLingMuteSting + mindAction: false + cost: + EvolutionPoints: 2 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingMuscles + name: listing-strained-muscles + description: listing-strained-muscles-desc + productAction: ActionLingMuscles + mindAction: false + cost: + EvolutionPoints: 2 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingLesserForm + name: listing-lesser-form + description: listing-lesser-form-desc + productAction: ActionLingLesserForm + mindAction: false + cost: + EvolutionPoints: 2 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingDrugSting + name: listing-drug-sting + description: listing-drug-sting-desc + productAction: ActionLingDrugSting + mindAction: false + cost: + EvolutionPoints: 2 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingArmShield + name: listing-arm-shield + description: listing-arm-shield-desc + productAction: ActionArmShield + mindAction: false + cost: + EvolutionPoints: 3 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingLastResort + name: listing-last-resort + description: listing-last-resort-desc + productAction: ActionLingLastResort + mindAction: false + cost: + EvolutionPoints: 2 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + - !type:ChangelingLastResortNotUsedCondition + +- type: listing + id: ChangelingBiodegrade + name: listing-biodegrade + description: listing-biodegrade-desc + productAction: ActionLingBiodegrade + mindAction: false + cost: + EvolutionPoints: 1 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingResonant + name: listing-resonant-shriek + description: listing-resonant-shriek-desc + productAction: ActionLingResonant + mindAction: false + cost: + EvolutionPoints: 1 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingTransformSting + name: listing-transform-sting + description: listing-transform-sting-desc + productAction: ActionLingTransformSting + mindAction: false + cost: + EvolutionPoints: 3 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingArmace + name: listing-arm-mace + description: listing-arm-mace-desc + productAction: ActionArmace + mindAction: false + cost: + EvolutionPoints: 4 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingDigiCamo + name: listing-digi-camo + description: listing-digi-camo-desc + productAction: ActionDigiCamo + mindAction: false + cost: + EvolutionPoints: 2 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingBoneShard + name: listing-bone-shard + description: listing-bone-shard-desc + productAction: ActionBoneShard + mindAction: false + cost: + EvolutionPoints: 1 + categories: + - ChangelingAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - !type:ChangelingActionNotPresentCondition + +- type: listing + id: ChangelingRefresh + name: changeling-refresh + description: changeling-refresh-desc + productEvent: !type:ChangelingRefreshEvent + raiseOnBuyer: true + cost: + EvolutionPoints: 0 + categories: + - ChangelingAbilities + icon: Interface/Actions/firestarter.png + conditions: + - !type:ChangelingCanRefreshCondition + - !type:ChangelingActionNotPresentCondition diff --git a/Resources/Prototypes/ADT/Changeling/polymorph.yml b/Resources/Prototypes/ADT/Changeling/polymorph.yml new file mode 100644 index 00000000000..692e2ac108c --- /dev/null +++ b/Resources/Prototypes/ADT/Changeling/polymorph.yml @@ -0,0 +1,12 @@ + # ling human morph + - type: polymorph + id: ChangelingHumanoidMorph + configuration: + entity: MobHuman + forced: true + transferName: false + transferHumanoidAppearance: false + inventory: Transfer + revertOnDeath: false + revertOnCrit: false + allowRepeatedMorphs: true diff --git a/Resources/Prototypes/ADT/Entities/Mobs/Player/changeling.yml b/Resources/Prototypes/ADT/Entities/Mobs/Player/changeling.yml new file mode 100644 index 00000000000..a0302f247f6 --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Mobs/Player/changeling.yml @@ -0,0 +1,127 @@ +- type: entity + id: ADTMobMonkeyChangeling + parent: MobMonkey + suffix: changeling + categories: [ HideSpawnMenu ] + components: + - type: LanguageSpeaker # Frontier + speaks: + - Monkey + understands: + - GalacticCommon + - Monkey + +- type: polymorph + id: ADTChangelingLesserForm + configuration: + entity: ADTMobMonkeyChangeling + forced: true + inventory: Drop + allowRepeatedMorphs: true + revertOnDeath: false + revertOnCrit: false + +- type: entity + name: changeling slug + parent: SimpleMobBase + id: ADTChangelingHeadslug + description: e + components: + - type: Body + prototype: Mouse + - type: Speech + speechSounds: Squeak + speechVerb: SmallMob + - type: Sprite + drawdepth: SmallMobs + sprite: ADT/Changeling/Mobs/headslug.rsi + layers: + - map: ["enum.DamageStateVisualLayers.Base"] + state: headslug + - type: Item + size: Tiny + - type: NpcFactionMember + factions: + - Mouse + - type: HTN + rootTask: + task: MouseCompound + - type: Physics + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.2 + density: 100 + mask: + - SmallMobMask + layer: + - SmallMobLayer + - type: MobState + - type: Deathgasp + - type: MobStateActions + actions: + Critical: + - ActionCritSuccumb + - ActionCritFakeDeath + - ActionCritLastWords + - type: MobThresholds + thresholds: + 0: Alive + 69: Critical + 70: Dead + - type: MovementSpeedModifier + baseWalkSpeed : 5 + baseSprintSpeed : 5 + - type: DamageStateVisuals + states: + Alive: + Base: headslug + Critical: + Base: headslug_dead + Dead: + Base: headslug_dead + - type: Food + # - type: Tag + # tags: + # - ShoesRequiredStepTriggerImmune # По-моему из за этой хуйни падал сервер + - type: Respirator + damage: + types: + Asphyxiation: 0.25 + damageRecovery: + types: + Asphyxiation: -0.25 + - type: Barotrauma + damage: + types: + Blunt: 0.1 + - type: Vocal + sounds: + Male: Mouse + Female: Mouse + Unsexed: Mouse + wilhelmProbability: 0.001 + - type: CombatMode + - type: Bloodstream + bloodMaxVolume: 50 + - type: CanEscapeInventory + - type: MobPrice + price: 5000 + - type: BadFood + - type: NonSpreaderZombie + - type: LanguageSpeaker # Frontier + speaks: + - Xeno + understands: + - Xeno + - type: MeleeWeapon + soundHit: + path: /Audio/Weapons/pierce.ogg + angle: 30 + animation: WeaponArcPunch + damage: + types: + Piercing: 7 + - type: ChangelingHeadslug diff --git a/Resources/Prototypes/ADT/Entities/Mobs/Species/ipc.yml b/Resources/Prototypes/ADT/Entities/Mobs/Species/ipc.yml index 3c7fadf86cb..5a1b672fec6 100644 --- a/Resources/Prototypes/ADT/Entities/Mobs/Species/ipc.yml +++ b/Resources/Prototypes/ADT/Entities/Mobs/Species/ipc.yml @@ -118,11 +118,12 @@ - RobotTalk - type: Tag tags: - # - ChangelingBlacklist # - ShoesRequiredStepTriggerImmune - CanPilot - FootstepSound - DoorBumpOpener + - ChangelingBlacklist + - ADTSiliconStealthWhitelist - type: Inventory templateId: ipc - type: SizeAttributeWhitelist # Frontier diff --git a/Resources/Prototypes/ADT/Entities/Mobs/Species/novakid.yml b/Resources/Prototypes/ADT/Entities/Mobs/Species/novakid.yml index 1b369b201aa..77f1f16b3b0 100644 --- a/Resources/Prototypes/ADT/Entities/Mobs/Species/novakid.yml +++ b/Resources/Prototypes/ADT/Entities/Mobs/Species/novakid.yml @@ -154,6 +154,13 @@ shortscale: 0.9 - type: BloodCough postingSayDamage: blood-cough-novakid + - type: Tag + tags: + - CanPilot + - FootstepSound + - DoorBumpOpener + - AnomalyHost + - ChangelingBlacklist - type: entity save: false diff --git a/Resources/Prototypes/ADT/Entities/Objects/Shields/changeling_shield.yml b/Resources/Prototypes/ADT/Entities/Objects/Shields/changeling_shield.yml new file mode 100644 index 00000000000..7eddc7e7515 --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Shields/changeling_shield.yml @@ -0,0 +1,38 @@ +- type: entity + name: armshield + parent: BaseItem + id: ADTArmShield + description: Meat. + components: + - type: Sprite + sprite: ADT/Changeling/Objects/armshield.rsi + state: icon + - type: Item + sprite: ADT/Changeling/Objects/armshield.rsi + inhandVisuals: + left: + - state: inhand-left + right: + - state: inhand-right + size: Ginormous + - type: Blocking + passiveBlockModifier: + coefficients: + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 0.8 + activeBlockModifier: + coefficients: + Blunt: 0.75 + Slash: 0.75 + Piercing: 0.75 + Heat: 0.7 + flatReductions: + Blunt: 0.5 + Slash: 0.5 + Piercing: 0.5 + Heat: 1 + - type: Damageable + damageContainer: Shield + - type: ChangelingShield diff --git a/Resources/Prototypes/ADT/Entities/Objects/Shields/fill.txt b/Resources/Prototypes/ADT/Entities/Objects/Shields/fill.txt deleted file mode 100644 index b4954caf47d..00000000000 --- a/Resources/Prototypes/ADT/Entities/Objects/Shields/fill.txt +++ /dev/null @@ -1 +0,0 @@ -# Данный файл существует по причине того что Githab плохо дружит с пустыми папками, при работе с этой папкой этот файл можно спокойно удалить \ No newline at end of file diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/changeling.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/changeling.yml new file mode 100644 index 00000000000..f7e686b0e5c --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Melee/changeling.yml @@ -0,0 +1,71 @@ +- type: entity + name: arm blade + parent: BaseKnife + id: ADTArmBlade + description: A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter. + components: + - type: Sprite + sprite: ADT/Changeling/Objects/armblade.rsi + state: icon + - type: MeleeWeapon + wideAnimationRotation: 90 + attackRate: 0.75 + damage: + types: + Slash: 25 + Piercing: 15 + - type: Item + size: Ginormous + sprite: ADT/Changeling/Objects/armblade.rsi + - type: Tool + qualities: + - Prying + - Slicing + speedModifier: 0.5 + - type: Prying + pryPowered: true + - type: DisarmMalus + malus: 0 + - type: Reflect + reflectProb: 0.5 + +- type: entity + name: arm mace + parent: BaseItem + id: ADTArmace + description: Meat. + components: + - type: Sprite + sprite: ADT/Changeling/Objects/armmace.rsi + state: icon + - type: MeleeWeapon + attackRate: 0.5 + wideAnimationRotation: -135 + damage: + types: + Blunt: 25 + Structural: 60 + soundHit: + collection: MetalThud + - type: Item + size: Ginormous + sprite: ADT/Changeling/Objects/armmace.rsi + inhandVisuals: + left: + - state: inhand-left + right: + - state: inhand-right + - type: Tool + qualities: + - Rolling + speedModifier: 0.75 + - type: MeleeThrowOnHit + speed: 15 + lifetime: 0.15 + collideDamage: + types: + Blunt: 12 + toCollideDamage: + types: + Structural: 75 + downOnHit: false diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Throwable/fill.txt b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Throwable/fill.txt deleted file mode 100644 index b4954caf47d..00000000000 --- a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Throwable/fill.txt +++ /dev/null @@ -1 +0,0 @@ -# Данный файл существует по причине того что Githab плохо дружит с пустыми папками, при работе с этой папкой этот файл можно спокойно удалить \ No newline at end of file diff --git a/Resources/Prototypes/ADT/Entities/Objects/Weapons/Throwable/throwing_stars.yml b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Throwable/throwing_stars.yml new file mode 100644 index 00000000000..2fbe4a65fdb --- /dev/null +++ b/Resources/Prototypes/ADT/Entities/Objects/Weapons/Throwable/throwing_stars.yml @@ -0,0 +1,12 @@ +- type: entity + parent: ThrowingStar + id: ADTThrowingStarChangeling + name: bone shard + components: + - type: Sprite + sprite: ADT/Changeling/Objects/bone_shard.rsi + layers: + - state: icon + map: ["base"] + - type: TimedDespawn + lifetime: 30 diff --git a/Resources/Prototypes/ADT/GameRules/fill.txt b/Resources/Prototypes/ADT/GameRules/fill.txt deleted file mode 100644 index b4954caf47d..00000000000 --- a/Resources/Prototypes/ADT/GameRules/fill.txt +++ /dev/null @@ -1 +0,0 @@ -# Данный файл существует по причине того что Githab плохо дружит с пустыми папками, при работе с этой папкой этот файл можно спокойно удалить \ No newline at end of file diff --git a/Resources/Prototypes/ADT/GameRules/roundstart.yml b/Resources/Prototypes/ADT/GameRules/roundstart.yml index ef5a870356d..164028a7d16 100644 --- a/Resources/Prototypes/ADT/GameRules/roundstart.yml +++ b/Resources/Prototypes/ADT/GameRules/roundstart.yml @@ -92,3 +92,31 @@ - type: BasicStationEventScheduler scheduledGameRules: !type:NestedSelector tableId: ExtendedGameRulesTable + +- type: entity + parent: BaseGameRule + id: ChangelingGameRule + components: + - type: ChangelingRule + - type: GameRule + minPlayers: 20 + - type: AntagSelection + definitions: + - prefRoles: [ Changeling ] + max: 5 + playerRatio: 15 + blacklist: + components: + - AntagImmune + tags: + - ChangelingBlacklist + lateJoinAdditional: true + mindRoles: + - MindRoleChangeling + components: + - type: Changeling + agentName: ling-round-end-name + - type: AntagRandomObjectives + sets: + - groups: ChangelingObjectiveGroups + maxDifficulty: 5 diff --git a/Resources/Prototypes/ADT/Objectives/changeling.yml b/Resources/Prototypes/ADT/Objectives/changeling.yml new file mode 100644 index 00000000000..0dba8675f47 --- /dev/null +++ b/Resources/Prototypes/ADT/Objectives/changeling.yml @@ -0,0 +1,130 @@ +- type: entity + abstract: true + parent: BaseObjective + id: BaseChangelingObjective + components: + - type: Objective + issuer: changeling-issuer + - type: RoleRequirement + roles: + mindRoles: + - ChangelingRole + +- type: entity + categories: [ HideSpawnMenu ] + parent: [BaseChangelingObjective, BaseLivingObjective] + id: DnaAbsorbObjective + name: Absorb 4 DNAs. + components: + - type: Objective + difficulty: 1.5 + unique: true + icon: + sprite: ADT/Changeling/Actions/actions_ling.rsi + state: absorb_dna + - type: AbsorbDnaCondition + objectiveText: absorb-dna-name + descriptionText: absorb-dna-desc + +- type: entity + abstract: true + parent: BaseTargetObjective + id: BasePersonalityStealObjective + components: + - type: Objective + unique: false + icon: + sprite: Objects/Weapons/Guns/Pistols/viper.rsi + state: icon + - type: ObjectiveBlacklistRequirement + blacklist: + components: + - SocialObjective + - type: StealPersonalityCondition + requireDead: true + - type: PickRandomDna + +- type: entity + categories: [ HideSpawnMenu ] + parent: [BaseChangelingObjective, BaseLivingObjective] + id: EscapeLingShuttleObjective + name: Escape to centcom alive and unrestrained. + description: We must get to central command. + components: + - type: Objective + difficulty: 1.2 + icon: + sprite: Structures/Furniture/chairs.rsi + state: shuttle + - type: EscapeShuttleCondition + +- type: entity + categories: [ HideSpawnMenu ] + parent: [BaseChangelingObjective, BaseKillObjective] + id: KillRandomPersonObjectiveLing + description: ling-kill-desc + components: + - type: Objective + difficulty: 1.5 + unique: false + - type: TargetObjective + title: objective-condition-kill-person-title + - type: PickRandomPerson + +- type: entity + categories: [ HideSpawnMenu ] + parent: [BaseChangelingObjective, BasePersonalityStealObjective] + id: StealRandomPersonalityObjectiveLing + description: ling-steal-personality-desc + components: + - type: Objective + difficulty: 2 + unique: true + - type: TargetObjective + title: objective-condition-steal-head-personality-title + - type: PickRandomPerson + +#- type: entity +# categories: [ HideSpawnMenu ] +# parent: [BaseChangelingObjective, BasePersonalityStealObjective] +# id: StealRandomHeadPersonalityObjectiveLing +# description: ling-steal-personality-desc +# components: +# - type: Objective +# difficulty: 1.5 +# unique: false +# - type: TargetObjective +# title: objective-condition-steal-head-personality-title +# - type: PickRandomHead +# - type: StealPersonalityCondition +# requireDead: true + +- type: entity + abstract: true + parent: [BaseChangelingObjective, BaseStealObjective] + id: BaseChangelingStealObjective + components: + - type: StealCondition + verifyMapExistance: false + - type: Objective + difficulty: 2.5 + - type: ObjectiveLimit + limit: 1 + +- type: entity + categories: [ HideSpawnMenu ] + parent: BaseChangelingStealObjective + id: CommandIDStealObjective + components: + - type: StealCondition + stealGroup: CommandIDCard + descriptionText: objective-condition-changeling-commandidcard + +- type: entity + categories: [ HideSpawnMenu ] + parent: BaseChangelingStealObjective + id: SmileExtractStealObjective + components: + - type: StealCondition + stealGroup: MaterialSmileExtract + descriptionText: objective-condition-changeling-smileextract diff --git a/Resources/Prototypes/ADT/Objectives/objectiveGroups.yml b/Resources/Prototypes/ADT/Objectives/objectiveGroups.yml index 2cc51a10afe..e9e2806ced4 100644 --- a/Resources/Prototypes/ADT/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/ADT/Objectives/objectiveGroups.yml @@ -26,3 +26,40 @@ PhantomStartNightmareObjective: 1 PhantomReincarnateObjective: 1 PhantomTyranyObjective: 1 + +# Changeling +- type: weightedRandom + id: ChangelingObjectiveGroups + weights: + ChangelingObjectiveGroupKill: 1 + ChangelingObjectiveGroupState: 1 + ChangelingObjectiveGroupSteal: 1 + ChangelingObjectiveGroupPersonalitySteal: 1 + ChangelingObjectiveGroupAbsorbDna: 1 # почему ты блять не работаешь + +- type: weightedRandom + id: ChangelingObjectiveGroupSteal + weights: + CommandIDStealObjective: 1 + SmileExtractStealObjective: 1 + +- type: weightedRandom + id: ChangelingObjectiveGroupKill + weights: + KillRandomPersonObjectiveLing: 1 + +- type: weightedRandom + id: ChangelingObjectiveGroupState + weights: + EscapeLingShuttleObjective: 1 + +- type: weightedRandom + id: ChangelingObjectiveGroupPersonalitySteal + weights: + StealRandomPersonalityObjectiveLing: 1 + #StealRandomHeadPersonalityObjectiveLing: 1 + +- type: weightedRandom + id: ChangelingObjectiveGroupAbsorbDna + weights: + DnaAbsorbObjective: 1 diff --git a/Resources/Prototypes/ADT/Objectives/stealTargetGroups.yml b/Resources/Prototypes/ADT/Objectives/stealTargetGroups.yml index d6398f274cb..39e307d07e3 100644 --- a/Resources/Prototypes/ADT/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/ADT/Objectives/stealTargetGroups.yml @@ -19,3 +19,19 @@ sprite: sprite: ADT/Clothing/Mask/gasCE.rsi state: icon + +# changeling + +- type: stealTargetGroup + id: CommandIDCard + name: steal-target-groups-command-id + sprite: + sprite: Objects/Misc/id_cards.rsi + state: silver + +- type: stealTargetGroup + id: MaterialSmileExtract + name: steal-target-groups-smile-extract + sprite: + sprite: Mobs/Aliens/slimes.rsi + state: rainbow_slime_extract diff --git a/Resources/Prototypes/ADT/Reagents/medicine.yml b/Resources/Prototypes/ADT/Reagents/medicine.yml index 0ebe71fdb99..06f0998b9fe 100644 --- a/Resources/Prototypes/ADT/Reagents/medicine.yml +++ b/Resources/Prototypes/ADT/Reagents/medicine.yml @@ -420,6 +420,10 @@ type: Add time: 2.5 refresh: false + - !type:HallucinationsReagentEffect + proto: Changeling + type: Remove + time: 7 - !type:PopupMessage type: Local visualType: Small diff --git a/Resources/Prototypes/ADT/Reagents/narcotics.yml b/Resources/Prototypes/ADT/Reagents/narcotics.yml index aaff83a34d4..c2c32fbfec3 100644 --- a/Resources/Prototypes/ADT/Reagents/narcotics.yml +++ b/Resources/Prototypes/ADT/Reagents/narcotics.yml @@ -67,30 +67,3 @@ types: Poison: 2 # End edit by Filo - -- type: reagent - id: LingDrugs - name: reagent-name-space-drugs - group: Narcotics - desc: reagent-desc-space-drugs - physicalDesc: reagent-physical-desc-syrupy - flavor: bitter - color: "#63806e" - metabolisms: - Narcotic: - effects: - - !type:GenericStatusEffect - key: SeeingRainbows - component: SeeingRainbows - type: Add - time: 5 - refresh: false - - !type:GenericStatusEffect - key: ADTHallucinations - component: LingHallucinations - type: Add - time: 10 - refresh: false - conditions: - - !type:ReagentThreshold - min: 15 diff --git a/Resources/Prototypes/ADT/Roles/Antags/changeling.yml b/Resources/Prototypes/ADT/Roles/Antags/changeling.yml new file mode 100644 index 00000000000..455cf0f73ad --- /dev/null +++ b/Resources/Prototypes/ADT/Roles/Antags/changeling.yml @@ -0,0 +1,10 @@ +- type: antag + id: Changeling + name: roles-antag-changeling-name + antagonist: true + setPreference: true + objective: roles-antag-changeling-objective + requirements: + - !type:OverallPlaytimeRequirement + time: 270000 #75 hrs + #guides: [ Heretics ] закомменчено до появления гайда diff --git a/Resources/Prototypes/ADT/Roles/Antags/fill.txt b/Resources/Prototypes/ADT/Roles/Antags/fill.txt deleted file mode 100644 index b4954caf47d..00000000000 --- a/Resources/Prototypes/ADT/Roles/Antags/fill.txt +++ /dev/null @@ -1 +0,0 @@ -# Данный файл существует по причине того что Githab плохо дружит с пустыми папками, при работе с этой папкой этот файл можно спокойно удалить \ No newline at end of file diff --git a/Resources/Prototypes/ADT/Roles/MindRoles/mind_roles.yml b/Resources/Prototypes/ADT/Roles/MindRoles/mind_roles.yml index b320ce4d340..761562b63a1 100644 --- a/Resources/Prototypes/ADT/Roles/MindRoles/mind_roles.yml +++ b/Resources/Prototypes/ADT/Roles/MindRoles/mind_roles.yml @@ -20,3 +20,13 @@ antagPrototype: Heretic exclusiveAntag: true - type: HereticRole + +- type: entity + parent: BaseMindRoleAntag + id: MindRoleChangeling + name: Changeling Role + components: + - type: MindRole + antagPrototype: Changeling + exclusiveAntag: true + - type: ChangelingRole diff --git a/Resources/Prototypes/ADT/Store/categories.yml b/Resources/Prototypes/ADT/Store/categories.yml index f451cd24eda..aa8afce3f82 100644 --- a/Resources/Prototypes/ADT/Store/categories.yml +++ b/Resources/Prototypes/ADT/Store/categories.yml @@ -7,3 +7,8 @@ id: ADTUplinkERTMisc name: прочее priority: 2 + +#ling +- type: storeCategory + id: ChangelingAbilities + name: store-category-abilities diff --git a/Resources/Prototypes/ADT/Store/currency.yml b/Resources/Prototypes/ADT/Store/currency.yml index 12759541855..4c5f0b30ef2 100644 --- a/Resources/Prototypes/ADT/Store/currency.yml +++ b/Resources/Prototypes/ADT/Store/currency.yml @@ -4,3 +4,8 @@ cash : 1: SpaceCash displayName: store-currency-display-space-cash + +- type: currency + id: EvolutionPoints + displayName: store-currency-display-evolution-points + canWithdraw: false diff --git a/Resources/Prototypes/ADT/game_presets.yml b/Resources/Prototypes/ADT/game_presets.yml index 141223d7e03..491ec77c556 100644 --- a/Resources/Prototypes/ADT/game_presets.yml +++ b/Resources/Prototypes/ADT/game_presets.yml @@ -28,3 +28,18 @@ - SubGamemodesRule - BasicStationEventScheduler - MeteorSwarmScheduler + +- type: gamePreset + id: Changeling + alias: + - changeling + name: changelings-title + minPlayers: 25 + showInVote: true + description: changelings-description + rules: + - ChangelingGameRule + - BasicRoundstartVariation + - SubGamemodesRule + - BasicStationEventScheduler + - MeteorSwarmScheduler diff --git a/Resources/Prototypes/ADT/tags.yml b/Resources/Prototypes/ADT/tags.yml index 9f0eb2c5542..9de14c84fe7 100644 --- a/Resources/Prototypes/ADT/tags.yml +++ b/Resources/Prototypes/ADT/tags.yml @@ -139,6 +139,15 @@ - type: Tag id: ADTMagazineRifleAR12 +- type: Tag + id: ChangelingBlacklist + +- type: Tag + id: MaskBlocker + +- type: Tag + id: GlassesBlocker + - type: Tag id: ADTMobileDefibrillator @@ -157,6 +166,9 @@ - type: Tag id: ADTMedipen +- type: Tag + id: ADTSiliconStealthWhitelist + - type: Tag id: ADTCandies diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index d80e36bde1f..500fac01ace 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -19,6 +19,7 @@ icon: Interface/Actions/scream.png event: !type:ScreamActionEvent checkCanInteract: false + priority: -99 # ADT tweak - type: entity id: ActionTurnUndead diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml index bc1fc1a08c0..a5340d9a8a8 100644 --- a/Resources/Prototypes/Alerts/alerts.yml +++ b/Resources/Prototypes/Alerts/alerts.yml @@ -25,6 +25,7 @@ - alertType: Magboots - alertType: Pacified - alertType: Crawling #ADT crawling + - alertType: Chemicals # ADT Changeling - type: entity id: AlertSpriteView categories: [ HideSpawnMenu ] diff --git a/Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml b/Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml index d636cc5229c..17bdd5a6e72 100644 --- a/Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml +++ b/Resources/Prototypes/Corvax/Entities/Stations/nanotrasen.yml @@ -41,7 +41,7 @@ - /Maps/Ruins/corvax_ore.yml - /Maps/Ruins/corvax_research_station.yml - /Maps/Ruins/corvax_rnd_debris.yml - - /Maps/Ruins/corvax_sanctus.yml + # - /Maps/Ruins/corvax_sanctus.yml - /Maps/Ruins/corvax_syndi_base.yml - /Maps/Ruins/corvax_ussp_debris.yml - /Maps/Ruins/corvax_ussp_asteroid.yml diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index ee30bd26387..2276040495f 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -247,6 +247,7 @@ - DoorBumpOpener - FootstepSound - CanPilot + - ADTSiliconStealthWhitelist # ADT tweak - type: Emoting # ADT-CollectiveMind-Tweak-Start - type: CollectiveMind diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 35946628e5b..2b48d9ff352 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -400,6 +400,8 @@ - HideContextMenu - StationAi - NoConsoleSound + - ADTSiliconStealthWhitelist # ADT tweak + # Start-ADT-Tweak: Ai chat - type: HighlightWordsInChat highlightWords: diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml index c9e85b124e5..b4f315a4124 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml @@ -36,6 +36,8 @@ enum.SlimeHairUiKey.Key: type: SlimeHairBoundUserInterface # ADT-SlimeHair-End + enum.StoreUiKey.Key: # Чтобы не ломался генокрад + type: StoreBoundUserInterface # Чтобы не ломался генокрад # to prevent bag open/honk spam - type: UseDelay delay: 0.5 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml index 612f7da0472..ac4d1cc3ac2 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml @@ -734,6 +734,8 @@ - type: Tag tags: - Meat + - type: StealTarget + stealGroup: MaterialSmileExtract - type: entity name: steak diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml index 57a600b088b..60a629d81bf 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml @@ -229,6 +229,8 @@ heldPrefix: silver - type: PresetIdCard job: Quartermaster + - type: StealTarget + stealGroup: CommandIDCard - type: entity parent: IDCardStandard @@ -376,6 +378,8 @@ heldPrefix: silver - type: PresetIdCard job: HeadOfPersonnel + - type: StealTarget + stealGroup: CommandIDCard - type: entity parent: IDCardStandard @@ -390,6 +394,8 @@ heldPrefix: silver - type: PresetIdCard job: ChiefEngineer + - type: StealTarget + stealGroup: CommandIDCard - type: entity parent: IDCardStandard @@ -404,6 +410,8 @@ heldPrefix: silver - type: PresetIdCard job: ChiefMedicalOfficer + - type: StealTarget + stealGroup: CommandIDCard - type: entity parent: IDCardStandard @@ -418,6 +426,8 @@ heldPrefix: silver - type: PresetIdCard job: ResearchDirector + - type: StealTarget + stealGroup: CommandIDCard - type: entity parent: IDCardStandard @@ -432,6 +442,8 @@ heldPrefix: silver - type: PresetIdCard job: HeadOfSecurity + - type: StealTarget + stealGroup: CommandIDCard - type: entity parent: IDCardStandard diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml index 398c04aee6e..60fee93ac30 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml @@ -1,23 +1,23 @@ -- type: entity - name: arm blade - parent: BaseItem - id: ArmBlade - description: A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter. - components: - - type: Sharp - - type: Execution - doAfterDuration: 4.0 - - type: Sprite - sprite: Objects/Weapons/Melee/armblade.rsi - state: icon - - type: MeleeWeapon - wideAnimationRotation: 90 - attackRate: 0.75 - damage: - types: - Slash: 25 - Piercing: 15 - - type: Item - size: Normal - sprite: Objects/Weapons/Melee/armblade.rsi - - type: Prying +# - type: entity +# name: arm blade +# parent: BaseItem +# id: ArmBlade +# description: A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter. +# components: +# - type: Sharp +# - type: Execution +# doAfterDuration: 4.0 +# - type: Sprite +# sprite: Objects/Weapons/Melee/armblade.rsi +# state: icon +# - type: MeleeWeapon +# wideAnimationRotation: 90 +# attackRate: 0.75 +# damage: +# types: +# Slash: 25 +# Piercing: 15 +# - type: Item +# size: Normal +# sprite: Objects/Weapons/Melee/armblade.rsi +# - type: Prying diff --git a/Resources/Prototypes/Entities/Stations/base.yml b/Resources/Prototypes/Entities/Stations/base.yml index 4f97136b1c6..b83b5d3998f 100644 --- a/Resources/Prototypes/Entities/Stations/base.yml +++ b/Resources/Prototypes/Entities/Stations/base.yml @@ -77,7 +77,7 @@ - /Maps/Ruins/corvax_ore.yml - /Maps/Ruins/corvax_research_station.yml - /Maps/Ruins/corvax_rnd_debris.yml - - /Maps/Ruins/corvax_sanctus.yml + # - /Maps/Ruins/corvax_sanctus.yml - /Maps/Ruins/corvax_syndi_base.yml - /Maps/Ruins/corvax_ussp_debris.yml - /Maps/Ruins/corvax_ussp_asteroid.yml diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index dc41238a69b..38379b24309 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -24,6 +24,8 @@ prob: 0.5 - id: HereticGameRule # goob edit prob: 0.2 + - id: ChangelingGameRule # ADT-Changeling-Tweak + prob: 0.1 - type: entity id: DeathMatch31 diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml index 651e750eec7..cbc3fba6950 100644 --- a/Resources/Prototypes/Reagents/narcotics.yml +++ b/Resources/Prototypes/Reagents/narcotics.yml @@ -261,6 +261,11 @@ type: Add time: 16 refresh: false + - !type:HallucinationsReagentEffect + proto: Changeling + type: Add + time: 4 + refresh: false - type: reagent id: Nicotine @@ -321,6 +326,11 @@ type: Add time: 5 refresh: false + - !type:HallucinationsReagentEffect + proto: Changeling + type: Add + time: 4 + refresh: false - type: reagent id: Bananadine @@ -339,6 +349,11 @@ type: Add time: 5 refresh: false + - !type:HallucinationsReagentEffect + proto: Changeling + type: Add + time: 4 + refresh: false # Probably replace this one with sleeping chem when putting someone in a comatose state is easier - type: reagent @@ -521,3 +536,8 @@ type: Add time: 5 refresh: false + - !type:HallucinationsReagentEffect + proto: Changeling + type: Add + time: 4 + refresh: false diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/absorb_dna.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/absorb_dna.png new file mode 100644 index 00000000000..c7a65d00495 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/absorb_dna.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/adrenaline.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/adrenaline.png new file mode 100644 index 00000000000..744864efc46 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/adrenaline.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/armblade.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/armblade.png new file mode 100644 index 00000000000..eda9084981e Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/armblade.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/armhammer.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/armhammer.png new file mode 100644 index 00000000000..0f1ff31e34f Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/armhammer.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/augmented_eyesight.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/augmented_eyesight.png new file mode 100644 index 00000000000..857f8414d4a Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/augmented_eyesight.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/background.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/background.png new file mode 100644 index 00000000000..6fd7d2db6f2 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/background.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/biodegrade.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/biodegrade.png new file mode 100644 index 00000000000..3b143b37d99 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/biodegrade.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/bone_shard.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/bone_shard.png new file mode 100644 index 00000000000..8bc52989a4c Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/bone_shard.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/chameleon_skin.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/chameleon_skin.png new file mode 100644 index 00000000000..c355d8485a8 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/chameleon_skin.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/changeling_channel.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/changeling_channel.png new file mode 100644 index 00000000000..845c212dc5a Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/changeling_channel.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/changelingsting.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/changelingsting.png new file mode 100644 index 00000000000..1c39f4f8254 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/changelingsting.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/chitinous_armor.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/chitinous_armor.png new file mode 100644 index 00000000000..7c41fb0cc9d Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/chitinous_armor.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/darkness_adaptation.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/darkness_adaptation.png new file mode 100644 index 00000000000..995c23e6f72 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/darkness_adaptation.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/digital_camo.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/digital_camo.png new file mode 100644 index 00000000000..73b523dc5b3 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/digital_camo.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/dissonant_shriek.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/dissonant_shriek.png new file mode 100644 index 00000000000..50254888796 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/dissonant_shriek.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/fake_death.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/fake_death.png new file mode 100644 index 00000000000..103fbd4d171 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/fake_death.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/fleshmend.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/fleshmend.png new file mode 100644 index 00000000000..b5b78d62d98 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/fleshmend.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_absorb.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_absorb.png new file mode 100644 index 00000000000..e0846bca05a Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_absorb.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_head.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_head.png new file mode 100644 index 00000000000..e55dcda0d66 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_head.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_link.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_link.png new file mode 100644 index 00000000000..a16cd75c94e Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/hive_link.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/human_form.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/human_form.png new file mode 100644 index 00000000000..1b814a7ee0c Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/human_form.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/last_resort.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/last_resort.png new file mode 100644 index 00000000000..6e2be0b2121 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/last_resort.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/lesser_form.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/lesser_form.png new file mode 100644 index 00000000000..7edf36065c0 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/lesser_form.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/meta.json b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/meta.json new file mode 100644 index 00000000000..aac08bf1f0c --- /dev/null +++ b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/meta.json @@ -0,0 +1,134 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "taken from tg at https://github.com/tgstation/tgstation/commit/3e9ea4d77cdf4173777e665b2b4f4ba8cecf2c03#diff-06a6d3876124f6bb0adf70a4dffab8d82b9a7ae0abf9ec0ebc22211ca9d8ad4b. Sprites made by KREKS (#.kreks. discord), ported to Space Station 14 by Username228 (#serj3428 discord)", + "states": [ + { + "name": "absorb_dna" + }, + { + "name": "adrenaline" + }, + { + "name": "armblade" + }, + { + "name": "augmented_eyesight" + }, + { + "name": "biodegrade" + }, + { + "name": "chameleon_skin" + }, + { + "name": "changeling_channel" + }, + { + "name": "chitinous_armor" + }, + { + "name": "changelingsting" + }, + { + "name": "darkness_adaptation" + }, + { + "name": "digital_camo" + }, + { + "name": "dissonant_shriek" + }, + { + "name": "fake_death" + }, + { + "name": "fleshmend" + }, + { + "name": "hive_absorb" + }, + { + "name": "hive_head" + }, + { + "name": "hive_link" + }, + { + "name": "human_form" + }, + { + "name": "lesser_form" + }, + { + "name": "last_resort" + }, + { + "name": "mimic_voice" + }, + { + "name": "organic_shield" + }, + { + "name": "organic_suit" + }, + { + "name": "panacea" + }, + { + "name": "regenerate" + }, + { + "name": "resonant_shriek" + }, + { + "name": "revive" + }, + { + "name": "spread_infestation" + }, + { + "name": "sting_armblade" + }, + { + "name": "sting_blind" + }, + { + "name": "sting_cryo" + }, + { + "name": "sting_extract" + }, + { + "name": "sting_lsd" + }, + { + "name": "sting_mute" + }, + { + "name": "sting_transform" + }, + { + "name": "strained_muscles" + }, + { + "name": "tentacle" + }, + { + "name": "transform" + }, + { + "name": "armhammer" + }, + { + "name": "background" + }, + { + "name": "bone_shard" + } + ] +} diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/mimic_voice.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/mimic_voice.png new file mode 100644 index 00000000000..8e36b8cbfa6 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/mimic_voice.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/organic_shield.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/organic_shield.png new file mode 100644 index 00000000000..60275564cc3 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/organic_shield.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/organic_suit.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/organic_suit.png new file mode 100644 index 00000000000..61fb8fe845e Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/organic_suit.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/panacea.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/panacea.png new file mode 100644 index 00000000000..df37fd67203 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/panacea.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/regenerate.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/regenerate.png new file mode 100644 index 00000000000..26cc976c52c Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/regenerate.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/resonant_shriek.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/resonant_shriek.png new file mode 100644 index 00000000000..3a3d222b312 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/resonant_shriek.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/revive.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/revive.png new file mode 100644 index 00000000000..ad3b4da407e Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/revive.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/spread_infestation.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/spread_infestation.png new file mode 100644 index 00000000000..5550b21eddc Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/spread_infestation.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_armblade.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_armblade.png new file mode 100644 index 00000000000..fbb06b86037 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_armblade.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_blind.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_blind.png new file mode 100644 index 00000000000..0f3ae0e4e20 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_blind.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_cryo.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_cryo.png new file mode 100644 index 00000000000..81c10e6ed13 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_cryo.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_extract.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_extract.png new file mode 100644 index 00000000000..26c2a105317 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_extract.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_lsd.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_lsd.png new file mode 100644 index 00000000000..dc8b67b2003 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_lsd.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_mute.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_mute.png new file mode 100644 index 00000000000..fbe83cc881a Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_mute.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_transform.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_transform.png new file mode 100644 index 00000000000..e6cb0c82dde Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/sting_transform.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/strained_muscles.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/strained_muscles.png new file mode 100644 index 00000000000..f6a5cadb423 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/strained_muscles.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/tentacle.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/tentacle.png new file mode 100644 index 00000000000..3ebf73396a7 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/tentacle.png differ diff --git a/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/transform.png b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/transform.png new file mode 100644 index 00000000000..b53771f4581 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Actions/actions_ling.rsi/transform.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals0.png b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals0.png new file mode 100644 index 00000000000..5d4f1b73098 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals0.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals1.png b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals1.png new file mode 100644 index 00000000000..b59f46bf28e Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals1.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals2.png b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals2.png new file mode 100644 index 00000000000..8b333510621 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals2.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals3.png b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals3.png new file mode 100644 index 00000000000..7d22c2a9b6f Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals3.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals4.png b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals4.png new file mode 100644 index 00000000000..98f6fc0764a Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals4.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals5.png b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals5.png new file mode 100644 index 00000000000..11252a4c16c Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals5.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals6.png b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals6.png new file mode 100644 index 00000000000..36211437c09 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals6.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals7.png b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals7.png new file mode 100644 index 00000000000..6c93a576e35 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/chemicals7.png differ diff --git a/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/meta.json b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/meta.json new file mode 100644 index 00000000000..5463dcfdfab --- /dev/null +++ b/Resources/Textures/ADT/Changeling/Alerts/chemicals_counter.rsi/meta.json @@ -0,0 +1,35 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Dutch-VanDerLinde (github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "chemicals0" + }, + { + "name": "chemicals1" + }, + { + "name": "chemicals2" + }, + { + "name": "chemicals3" + }, + { + "name": "chemicals4" + }, + { + "name": "chemicals5" + }, + { + "name": "chemicals6" + }, + { + "name": "chemicals7" + } + ] +} diff --git a/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/headslug.png b/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/headslug.png new file mode 100644 index 00000000000..65a29e5423f Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/headslug.png differ diff --git a/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/headslug_dead.png b/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/headslug_dead.png new file mode 100644 index 00000000000..5aebe0014ff Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/headslug_dead.png differ diff --git a/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/meta.json b/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/meta.json new file mode 100644 index 00000000000..07396b10887 --- /dev/null +++ b/Resources/Textures/ADT/Changeling/Mobs/headslug.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/blob/master/icons/mob/simple/animal.dmi", + "states": [ + { + "name": "headslug", + "directions": 4 + }, + { + "name": "headslug_dead" + } + ] +} diff --git a/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/icon.png b/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/icon.png new file mode 100644 index 00000000000..d362e6d1f43 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/icon.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/inhand-left.png b/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/inhand-left.png new file mode 100644 index 00000000000..759aa26500e Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/inhand-left.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/inhand-right.png b/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/inhand-right.png new file mode 100644 index 00000000000..0f8b2404f82 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/inhand-right.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/meta.json b/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/meta.json new file mode 100644 index 00000000000..715d260a1be --- /dev/null +++ b/Resources/Textures/ADT/Changeling/Objects/armblade.rsi/meta.json @@ -0,0 +1,82 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "taken from tg at https://github.com/tgstation/tgstation/commit/3e9ea4d77cdf4173777e665b2b4f4ba8cecf2c03#diff-06a6d3876124f6bb0adf70a4dffab8d82b9a7ae0abf9ec0ebc22211ca9d8ad4b. Sprites made by KREKS (#.kreks. discord), ported to Space Station 14 by Username228 (#serj3428 discord)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4, + "delays": [ + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "inhand-right", + "directions": 4, + "delays": [ + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ] + ] + } + ] +} diff --git a/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/icon.png b/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/icon.png new file mode 100644 index 00000000000..5b9a2cc3e4c Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/icon.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/inhand-left.png b/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/inhand-left.png new file mode 100644 index 00000000000..199f64d02ff Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/inhand-left.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/inhand-right.png b/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/inhand-right.png new file mode 100644 index 00000000000..74ce77b9db2 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/inhand-right.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/meta.json b/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/meta.json new file mode 100644 index 00000000000..06bca78f2c1 --- /dev/null +++ b/Resources/Textures/ADT/Changeling/Objects/armmace.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Username228 (#serj3428 discord)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/icon.png b/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/icon.png new file mode 100644 index 00000000000..9e75fa61e16 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/icon.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/inhand-left.png b/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/inhand-left.png new file mode 100644 index 00000000000..f54fadf4a84 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/inhand-left.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/inhand-right.png b/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/inhand-right.png new file mode 100644 index 00000000000..f3511818023 Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/inhand-right.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/meta.json b/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/meta.json new file mode 100644 index 00000000000..2422b8124cc --- /dev/null +++ b/Resources/Textures/ADT/Changeling/Objects/armshield.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "taken from tg at https://github.com/tgstation/tgstation/commit/3e9ea4d77cdf4173777e665b2b4f4ba8cecf2c03#diff-06a6d3876124f6bb0adf70a4dffab8d82b9a7ae0abf9ec0ebc22211ca9d8ad4b. Sprites made by KREKS (#.kreks. discord), ported to Space Station 14 by Username228 (#serj3428 discord)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/ADT/Changeling/Objects/bone_shard.rsi/icon.png b/Resources/Textures/ADT/Changeling/Objects/bone_shard.rsi/icon.png new file mode 100644 index 00000000000..7661444b00f Binary files /dev/null and b/Resources/Textures/ADT/Changeling/Objects/bone_shard.rsi/icon.png differ diff --git a/Resources/Textures/ADT/Changeling/Objects/bone_shard.rsi/meta.json b/Resources/Textures/ADT/Changeling/Objects/bone_shard.rsi/meta.json new file mode 100644 index 00000000000..d4e300c160c --- /dev/null +++ b/Resources/Textures/ADT/Changeling/Objects/bone_shard.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC0-1.0", + "copyright": "https://github.com/RealFakeSoof with references from deltanedas (github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + } + ] + } diff --git a/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/icon.png b/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/icon.png new file mode 100644 index 00000000000..96fe562db8a Binary files /dev/null and b/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/icon.png differ diff --git a/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/inhand-left.png b/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/inhand-left.png new file mode 100644 index 00000000000..78d2cc1d60d Binary files /dev/null and b/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/inhand-left.png differ diff --git a/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/inhand-right.png b/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/inhand-right.png new file mode 100644 index 00000000000..0bf22f8b69a Binary files /dev/null and b/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/inhand-right.png differ diff --git a/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/meta.json b/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/meta.json new file mode 100644 index 00000000000..715d260a1be --- /dev/null +++ b/Resources/Textures/ADT/Objects/Weapons/Melee/armtentacle.rsi/meta.json @@ -0,0 +1,82 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "taken from tg at https://github.com/tgstation/tgstation/commit/3e9ea4d77cdf4173777e665b2b4f4ba8cecf2c03#diff-06a6d3876124f6bb0adf70a4dffab8d82b9a7ae0abf9ec0ebc22211ca9d8ad4b. Sprites made by KREKS (#.kreks. discord), ported to Space Station 14 by Username228 (#serj3428 discord)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4, + "delays": [ + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "inhand-right", + "directions": 4, + "delays": [ + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.2, + 0.3, + 0.3, + 0.3 + ] + ] + } + ] +}