From d3684f553d4a4e8fa51f39eba1b56532c49fffee Mon Sep 17 00:00:00 2001 From: RevengenRat <138193222+Ratyyy@users.noreply.github.com> Date: Mon, 14 Oct 2024 19:45:37 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=20=D1=81=D1=82=D0=B0=D1=82=D0=B8?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BA=D0=B5,=20=D0=BA=D0=B0=D0=B6=D0=B4?= =?UTF-8?q?=D1=8B=D0=B9=203-=D0=B9=20=D0=B6=D0=B8=D1=82=D0=B5=D0=BB=D1=8C?= =?UTF-8?q?=20=D0=B8=D0=BC=D0=BF=D0=B5=D1=80=D0=B8=D1=83=D0=BC=D0=B0=20-?= =?UTF-8?q?=20=D0=B5=D1=80=D0=B5=D1=82=D0=B8=D0=BA=20(#641)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Описание PR черри-пикнуты пр-ы: https://github.com/Goob-Station/Goob-Station/pull/755 https://github.com/Goob-Station/Goob-Station/pull/726 https://github.com/Goob-Station/Goob-Station/pull/723 и добавлен перевод экшенов ## Почему / Баланс **Ссылка на публикацию в Discord** чтоб еретикам жизнь малинок не казалась ## Техническая информация ## Медиа ## Требования - [x] Я прочитал(а) и следую [Руководство по созданию пулл реквестов](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html). Я понимаю, что в противном случае мой ПР может быть закрыт по усмотрению мейнтейнера. - [x] Я добавил скриншоты/видео к этому пулл реквесту, демонстрирующие его изменения в игре, **или** этот пулл реквест не требует демонстрации в игре ## Критические изменения **Чейнджлог** :cl: Ratyyy - add: Древние боги перестали принимать в жертву случайных людей! - tweak: Еретики научились грамотно выбирать ритуалы используя круговую голограмму! - tweak: Сила пустотного втягивания ослабла и теперь наносит только в 2 раза больше повреждений! - fix: Еретики приняли решение стать более гуманными, и потому больше не используют органы внутри тел для ритуалов! --- .../HereticRitualRuneBoundUserInterface.cs | 39 ++++ .../UI/HereticRitualRuneRadialMenu.xaml | 13 ++ .../UI/HereticRitualRuneRadialMenu.xaml.cs | 101 +++++++++ .../ADT/Heretic/UI/LivingHeartMenu.xaml | 16 ++ .../ADT/Heretic/UI/LivingHeartMenu.xaml.cs | 97 +++++++++ .../UI/LivingHeartMenuBoundUserInterface.cs | 34 +++ .../Abilities/HereticAbilitySystem.Ash.cs | 2 + .../Abilities/HereticAbilitySystem.Flesh.cs | 3 + .../Abilities/HereticAbilitySystem.Void.cs | 2 +- .../Heretic/Abilities/HereticAbilitySystem.cs | 69 ++++++- .../Heretic/EntitySystems/AristocratSystem.cs | 2 +- .../EntitySystems/HereticKnowledgeSystem.cs | 8 +- .../EntitySystems/HereticRitualSystem.cs | 47 ++--- .../Heretic/EntitySystems/HereticSystem.cs | 147 +++++++++++-- .../Ritual/CustomBehavior.Sacrifice.cs | 13 +- .../ADT/Magic/ChainFireballComponent.cs | 7 +- .../ADT/Magic/ChainFireballSystem.cs | 16 +- .../Antag/AntagSelectionSystem.API.cs | 14 ++ .../Heretic/Components/HereticComponent.cs | 24 ++- .../Heretic/Components/HereticRitualEvents.cs | 22 ++ .../ADT/Heretic/Heretic.Abilites.cs | 9 + .../ADT/Heretic/Prototypes/Heretic.Data.cs | 17 +- .../Ambience/Antag/Heretic/attributions.yml | 4 + Resources/Audio/ADT/Heretic/attributions.yml | 9 + Resources/Audio/ADT/Heretic/heartbeat.ogg | Bin 0 -> 9088 bytes .../ru-RU/ADT/Heretic/abilities/heretic.ftl | 5 + .../Locale/ru-RU/ADT/Heretic/rituals.ftl | 3 +- .../ADT/prototypes/Actions/heretic/basic.ftl | 11 + .../prototypes/Actions/heretic/path_ash.ftl | 14 ++ .../prototypes/Actions/heretic/path_flesh.ftl | 5 + .../prototypes/Actions/heretic/path_void.ftl | 8 + .../Objects/personalization_items.yml | 195 +++++++++--------- .../ADT/Heretic/Actions/Heretic/basic.yml | 26 ++- .../ADT/Heretic/Actions/Heretic/path_ash.yml | 20 +- .../Heretic/Actions/Heretic/path_flesh.yml | 8 +- .../ADT/Heretic/Actions/Heretic/path_void.yml | 12 +- .../Entities/Clothing/OuterClothing/armor.yml | 1 + .../Objects/Weapons/Melee/heretic_blades.yml | 6 + .../Specific/Heretic/ritual_rune.yml | 4 + .../ADT/Heretic/Heretic/heretic_knowledge.yml | 39 +++- .../ADT/Heretic/Heretic/heretic_rituals.yml | 82 +++++++- .../Prototypes/ADT/Heretic/radio_channels.yml | 2 +- .../Entities/Clothing/Masks/masks.yml | 1 + .../Prototypes/Entities/Mobs/Species/base.yml | 2 + .../abilities_heretic.rsi/living_heart.png | Bin 0 -> 735 bytes .../Heretic/abilities_heretic.rsi/meta.json | 3 + 46 files changed, 932 insertions(+), 230 deletions(-) create mode 100644 Content.Client/ADT/Heretic/HereticRitualRuneBoundUserInterface.cs create mode 100644 Content.Client/ADT/Heretic/UI/HereticRitualRuneRadialMenu.xaml create mode 100644 Content.Client/ADT/Heretic/UI/HereticRitualRuneRadialMenu.xaml.cs create mode 100644 Content.Client/ADT/Heretic/UI/LivingHeartMenu.xaml create mode 100644 Content.Client/ADT/Heretic/UI/LivingHeartMenu.xaml.cs create mode 100644 Content.Client/ADT/Heretic/UI/LivingHeartMenuBoundUserInterface.cs create mode 100644 Content.Shared/ADT/Heretic/Components/HereticRitualEvents.cs create mode 100644 Resources/Audio/ADT/Heretic/Ambience/Antag/Heretic/attributions.yml create mode 100644 Resources/Audio/ADT/Heretic/attributions.yml create mode 100644 Resources/Audio/ADT/Heretic/heartbeat.ogg create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/basic.ftl create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_ash.ftl create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_flesh.ftl create mode 100644 Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_void.ftl create mode 100644 Resources/Textures/ADT/Heretic/abilities_heretic.rsi/living_heart.png diff --git a/Content.Client/ADT/Heretic/HereticRitualRuneBoundUserInterface.cs b/Content.Client/ADT/Heretic/HereticRitualRuneBoundUserInterface.cs new file mode 100644 index 00000000000..38b3b49aeb6 --- /dev/null +++ b/Content.Client/ADT/Heretic/HereticRitualRuneBoundUserInterface.cs @@ -0,0 +1,39 @@ +using Content.Client.ADT.Heretic.UI; +using Content.Shared.ADT.Heretic.Components; +using Content.Shared.Heretic.Prototypes; +using Robust.Client.Graphics; +using Robust.Client.Input; +using Robust.Client.UserInterface; +using Robust.Shared.Prototypes; + +namespace Content.Client.ADT.Heretic; + +public sealed class HereticRitualRuneBoundUserInterface : BoundUserInterface +{ + [Dependency] private readonly IClyde _displayManager = default!; + [Dependency] private readonly IInputManager _inputManager = default!; + + private HereticRitualRuneRadialMenu? _hereticRitualMenu; + + public HereticRitualRuneBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + IoCManager.InjectDependencies(this); + } + + protected override void Open() + { + base.Open(); + + _hereticRitualMenu = this.CreateWindow(); + _hereticRitualMenu.SetEntity(Owner); + _hereticRitualMenu.SendHereticRitualRuneMessageAction += SendHereticRitualMessage; + + var vpSize = _displayManager.ScreenSize; + _hereticRitualMenu.OpenCenteredAt(_inputManager.MouseScreenPosition.Position / vpSize); + } + + private void SendHereticRitualMessage(ProtoId protoId) + { + SendMessage(new HereticRitualMessage(protoId)); + } +} diff --git a/Content.Client/ADT/Heretic/UI/HereticRitualRuneRadialMenu.xaml b/Content.Client/ADT/Heretic/UI/HereticRitualRuneRadialMenu.xaml new file mode 100644 index 00000000000..425ba588c12 --- /dev/null +++ b/Content.Client/ADT/Heretic/UI/HereticRitualRuneRadialMenu.xaml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/Content.Client/ADT/Heretic/UI/HereticRitualRuneRadialMenu.xaml.cs b/Content.Client/ADT/Heretic/UI/HereticRitualRuneRadialMenu.xaml.cs new file mode 100644 index 00000000000..4ab95b8f9e4 --- /dev/null +++ b/Content.Client/ADT/Heretic/UI/HereticRitualRuneRadialMenu.xaml.cs @@ -0,0 +1,101 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared.Heretic; +using Content.Shared.Heretic.Prototypes; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using System.Numerics; + +namespace Content.Client.ADT.Heretic.UI; + +public sealed partial class HereticRitualRuneRadialMenu : RadialMenu +{ + [Dependency] private readonly EntityManager _entityManager = default!; + [Dependency] private readonly IEntitySystemManager _entitySystem = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly ISharedPlayerManager _playerManager = default!; + private readonly SpriteSystem _spriteSystem; + + public event Action>? SendHereticRitualRuneMessageAction; + + public EntityUid Entity { get; set; } + + public HereticRitualRuneRadialMenu() + { + IoCManager.InjectDependencies(this); + RobustXamlLoader.Load(this); + _spriteSystem = _entitySystem.GetEntitySystem(); + } + + public void SetEntity(EntityUid uid) + { + Entity = uid; + RefreshUI(); + } + + private void RefreshUI() + { + var main = FindControl("Main"); + if (main == null) + return; + + var player = _playerManager.LocalEntity; + + if (!_entityManager.TryGetComponent(player, out var heretic)) + return; + + foreach (var ritual in heretic.KnownRituals) + { + if (!_prototypeManager.TryIndex(ritual, out var ritualPrototype)) + continue; + + var button = new HereticRitualMenuButton + { + StyleClasses = { "RadialMenuButton" }, + SetSize = new Vector2(64, 64), + ToolTip = Loc.GetString(ritualPrototype.Name), + ProtoId = ritualPrototype.ID + }; + + var texture = new TextureRect + { + VerticalAlignment = VAlignment.Center, + HorizontalAlignment = HAlignment.Center, + Texture = _spriteSystem.Frame0(ritualPrototype.Icon), + TextureScale = new Vector2(2f, 2f) + }; + + button.AddChild(texture); + main.AddChild(button); + } + + AddHereticRitualMenuButtonOnClickAction(main); + } + + private void AddHereticRitualMenuButtonOnClickAction(RadialContainer mainControl) + { + if (mainControl == null) + return; + + foreach(var child in mainControl.Children) + { + var castChild = child as HereticRitualMenuButton; + + if (castChild == null) + continue; + + castChild.OnButtonUp += _ => + { + SendHereticRitualRuneMessageAction?.Invoke(castChild.ProtoId); + Close(); + }; + } + } + + public sealed class HereticRitualMenuButton : RadialMenuTextureButton + { + public ProtoId ProtoId { get; set; } + } +} diff --git a/Content.Client/ADT/Heretic/UI/LivingHeartMenu.xaml b/Content.Client/ADT/Heretic/UI/LivingHeartMenu.xaml new file mode 100644 index 00000000000..fd06facd081 --- /dev/null +++ b/Content.Client/ADT/Heretic/UI/LivingHeartMenu.xaml @@ -0,0 +1,16 @@ + + + + + + diff --git a/Content.Client/ADT/Heretic/UI/LivingHeartMenu.xaml.cs b/Content.Client/ADT/Heretic/UI/LivingHeartMenu.xaml.cs new file mode 100644 index 00000000000..a85077584ca --- /dev/null +++ b/Content.Client/ADT/Heretic/UI/LivingHeartMenu.xaml.cs @@ -0,0 +1,97 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared.Heretic; +using Robust.Client.Player; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; +using System.Numerics; + +namespace Content.Client.ADT.Heretic.UI; + +public sealed partial class LivingHeartMenu : RadialMenu +{ + [Dependency] private readonly EntityManager _ent = default!; + [Dependency] private readonly IPrototypeManager _prot = default!; + [Dependency] private readonly IPlayerManager _player = default!; + + public EntityUid Entity { get; private set; } + + public event Action? SendActivateMessageAction; + + public LivingHeartMenu() + { + IoCManager.InjectDependencies(this); + RobustXamlLoader.Load(this); + } + + public void SetEntity(EntityUid ent) + { + Entity = ent; + UpdateUI(); + } + + private void UpdateUI() + { + var main = FindControl("Main"); + if (main == null) return; + + var player = _player.LocalEntity; + + if (!_ent.TryGetComponent(player, out var heretic)) + return; + + foreach (var target in heretic.SacrificeTargets) + { + if (target == null) continue; + + var ent = _ent.GetEntity(target); + if (ent == null) + continue; + + var button = new EmbeddedEntityMenuButton + { + StyleClasses = { "RadialMenuButton" }, + SetSize = new Vector2(64, 64), + ToolTip = _ent.TryGetComponent(ent.Value, out var md) ? md.EntityName : "Unknown", + NetEntity = (NetEntity) target, + }; + + var texture = new SpriteView(ent.Value, _ent) + { + OverrideDirection = Direction.South, + VerticalAlignment = VAlignment.Center, + SetSize = new Vector2(64, 64), + VerticalExpand = true, + Stretch = SpriteView.StretchMode.Fill, + }; + button.AddChild(texture); + + main.AddChild(button); + } + AddAction(main); + } + + private void AddAction(RadialContainer main) + { + if (main == null) + return; + + foreach (var child in main.Children) + { + var castChild = child as EmbeddedEntityMenuButton; + if (castChild == null) + continue; + + castChild.OnButtonUp += _ => + { + SendActivateMessageAction?.Invoke(castChild.NetEntity); + Close(); + }; + } + } + + public sealed class EmbeddedEntityMenuButton : RadialMenuTextureButton + { + public NetEntity NetEntity; + } +} diff --git a/Content.Client/ADT/Heretic/UI/LivingHeartMenuBoundUserInterface.cs b/Content.Client/ADT/Heretic/UI/LivingHeartMenuBoundUserInterface.cs new file mode 100644 index 00000000000..d39372539d0 --- /dev/null +++ b/Content.Client/ADT/Heretic/UI/LivingHeartMenuBoundUserInterface.cs @@ -0,0 +1,34 @@ +using Content.Shared.Heretic; +using Robust.Client.Graphics; +using Robust.Client.Input; +using Robust.Client.UserInterface; + +namespace Content.Client.ADT.Heretic.UI; + +public sealed partial class LivingHeartMenuBoundUserInterface : BoundUserInterface +{ + [Dependency] private readonly IClyde _displayManager = default!; + [Dependency] private readonly IInputManager _inputManager = default!; + + [NonSerialized] private LivingHeartMenu? _menu; + + public LivingHeartMenuBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + IoCManager.InjectDependencies(this); + } + + protected override void Open() + { + base.Open(); + + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.SendActivateMessageAction += SendMessage; + _menu.OpenCenteredAt(_inputManager.MouseScreenPosition.Position / _displayManager.ScreenSize); + } + + private void SendMessage(NetEntity netent) + { + base.SendMessage(new EventHereticLivingHeartActivate() { Target = netent }); + } +} diff --git a/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Ash.cs b/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Ash.cs index 2bcae414d19..36e2127f301 100644 --- a/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Ash.cs +++ b/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Ash.cs @@ -51,9 +51,11 @@ private void OnVolcano(Entity ent, ref EventHereticVolcanoBlas return; var ignoredTargets = new List(); + // all ghouls are immune to heretic shittery foreach (var e in EntityQuery()) ignoredTargets.Add(e.Owner); + // all heretics with the same path are also immune foreach (var e in EntityQuery()) if (e.CurrentPath == ent.Comp.CurrentPath) diff --git a/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Flesh.cs b/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Flesh.cs index cec3512d4e3..8976a576eb2 100644 --- a/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Flesh.cs +++ b/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Flesh.cs @@ -86,6 +86,9 @@ private void OnFleshSurgery(Entity ent, ref EventHereticFleshS } private void OnFleshSurgeryDoAfter(Entity ent, ref EventHereticFleshSurgeryDoAfter args) { + if (args.Cancelled) + return; + if (args.Target == null) // shouldn't really happen. just in case return; diff --git a/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Void.cs b/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Void.cs index 18c0e36959c..4b821e3ff5b 100644 --- a/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Void.cs +++ b/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.Void.cs @@ -90,7 +90,7 @@ private void OnVoidPull(Entity ent, ref HereticVoidPullEvent a // damage closest ones foreach (var pookie in topPriority) if (TryComp(pookie, out var dmg)) - _dmg.SetAllDamage(pookie, dmg, dmg.TotalDamage + .5f); + _dmg.SetAllDamage(pookie, dmg, dmg.TotalDamage + .2f); // stun close-mid range foreach (var pookie in midPriority) diff --git a/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.cs b/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.cs index 52d924463c4..9cbf5bc64ce 100644 --- a/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.cs +++ b/Content.Server/ADT/Heretic/Abilities/HereticAbilitySystem.cs @@ -27,6 +27,10 @@ using Robust.Shared.Map; using Content.Shared.StatusEffect; using Content.Shared.Throwing; +using Content.Server.Station.Systems; +using Content.Shared.Localizations; +using Robust.Shared.Audio; +using Content.Shared.Mobs.Components; namespace Content.Server.Heretic.Abilities; @@ -56,6 +60,9 @@ public sealed partial class HereticAbilitySystem : EntitySystem [Dependency] private readonly PhysicsSystem _phys = default!; [Dependency] private readonly SharedStunSystem _stun = default!; [Dependency] private readonly ThrowingSystem _throw = default!; + [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; + [Dependency] private readonly StationSystem _station = default!; + [Dependency] private readonly IMapManager _mapMan = default!; private List GetNearbyPeople(Entity ent, float range) { @@ -86,6 +93,9 @@ public override void Initialize() SubscribeLocalEvent(OnStore); SubscribeLocalEvent(OnMansusGrasp); + SubscribeLocalEvent(OnLivingHeart); + SubscribeLocalEvent(OnLivingHeartActivate); + SubscribeLocalEvent(OnMansusLink); SubscribeLocalEvent(OnMansusLinkDoafter); @@ -105,9 +115,6 @@ private bool TryUseAbility(EntityUid ent, BaseActionEvent args) // check if any magic items are worn if (TryComp(ent, out var hereticComp) && actionComp.RequireMagicItem && !hereticComp.Ascended) { - if (hereticComp.CodexActive) - return true; - var ev = new CheckMagicItemEvent(); RaiseLocalEvent(ent, ev); @@ -159,6 +166,59 @@ private void OnMansusGrasp(Entity ent, ref EventHereticMansusG ent.Comp.MansusGraspActive = true; args.Handled = true; } + private void OnLivingHeart(Entity ent, ref EventHereticLivingHeart args) + { + if (!TryUseAbility(ent, args)) + return; + + if (!TryComp(ent, out var uic)) + return; + + if (ent.Comp.SacrificeTargets.Count == 0) + { + _popup.PopupEntity(Loc.GetString("heretic-livingheart-notargets"), ent, ent); + args.Handled = true; + return; + } + + _ui.OpenUi((ent, uic), HereticLivingHeartKey.Key, ent); + args.Handled = true; + } + private void OnLivingHeartActivate(Entity ent, ref EventHereticLivingHeartActivate args) + { + var loc = string.Empty; + + var target = GetEntity(args.Target); + if (target == null) + return; + + if (!TryComp(target, out var mobstate)) + return; + var state = mobstate.CurrentState; + + var xquery = GetEntityQuery(); + var targetStation = _station.GetOwningStation(target); + var ownStation = _station.GetOwningStation(ent); + + var isOnStation = targetStation != null && targetStation == ownStation; + + var ang = Angle.Zero; + if (_mapMan.TryFindGridAt(_transform.GetMapCoordinates(Transform(ent)), out var grid, out var _)) + ang = Transform(grid).LocalRotation; + + var vector = _transform.GetWorldPosition((EntityUid) target, xquery) - _transform.GetWorldPosition(ent, xquery); + var direction = (vector.ToWorldAngle() - ang).GetDir(); + + var locdir = ContentLocalizationManager.FormatDirection(direction).ToLower(); + var locstate = state.ToString().ToLower(); + + if (isOnStation) + loc = Loc.GetString("heretic-livingheart-onstation", ("state", locstate), ("direction", locdir)); + else loc = Loc.GetString("heretic-livingheart-offstation", ("state", locstate), ("direction", locdir)); + + _popup.PopupEntity(loc, ent, ent, PopupType.Medium); + _aud.PlayPvs(new SoundPathSpecifier("/Audio/ADT/Heretic/heartbeat.ogg"), ent, AudioParams.Default.WithVolume(-3f)); + } private void OnMansusLink(Entity ent, ref EventHereticMansusLink args) { @@ -190,6 +250,9 @@ private void OnMansusLink(Entity ent, ref EventHereticMansusLink } private void OnMansusLinkDoafter(Entity ent, ref HereticMansusLinkDoAfter args) { + if (args.Cancelled) + return; + var reciever = EnsureComp(args.Target); var transmitter = EnsureComp(args.Target); var radio = EnsureComp(args.Target); diff --git a/Content.Server/ADT/Heretic/EntitySystems/AristocratSystem.cs b/Content.Server/ADT/Heretic/EntitySystems/AristocratSystem.cs index c0060d42af3..f5d4b8cb44e 100644 --- a/Content.Server/ADT/Heretic/EntitySystems/AristocratSystem.cs +++ b/Content.Server/ADT/Heretic/EntitySystems/AristocratSystem.cs @@ -61,7 +61,7 @@ private void Cycle(Entity ent) continue; if (TryComp(look, out var temp)) - _temp.ChangeHeat(look, -100f, true, temp); + _temp.ChangeHeat(look, -200f, true, temp); _statusEffect.TryAddStatusEffect(look, "Muted", TimeSpan.FromSeconds(5), true); diff --git a/Content.Server/ADT/Heretic/EntitySystems/HereticKnowledgeSystem.cs b/Content.Server/ADT/Heretic/EntitySystems/HereticKnowledgeSystem.cs index bc6030e8a21..f4fa55a893c 100644 --- a/Content.Server/ADT/Heretic/EntitySystems/HereticKnowledgeSystem.cs +++ b/Content.Server/ADT/Heretic/EntitySystems/HereticKnowledgeSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Heretic; using Content.Shared.Popups; using Robust.Shared.Prototypes; +using Content.Shared.ADT.Heretic.Components; namespace Content.Server.Heretic.EntitySystems; @@ -31,6 +32,8 @@ public void AddKnowledge(EntityUid uid, HereticComponent comp, ProtoId comp.PathStage) + // make sure we only progress when buying current path knowledge + if (data.Stage > comp.PathStage && data.Path == comp.CurrentPath) comp.PathStage = data.Stage; if (!silent) @@ -64,6 +68,8 @@ public void RemoveKnowledge(EntityUid uid, HereticComponent comp, ProtoId e.Key, e => e.Value) ?? new(); var requiredTags = rit.RequiredTags?.ToDictionary(e => e.Key, e => e.Value) ?? new(); foreach (var behavior in behaviors) @@ -71,22 +74,11 @@ public bool TryDoRitual(EntityUid performer, EntityUid platform, ProtoId= 0) - toDelete.Add(look); - } - } - // check for matching tags foreach (var tag in requiredTags) { + if (_container.IsEntityInContainer(look)) + continue; if (!TryComp(look, out var tags)) continue; var ltags = tags.Tags; @@ -102,11 +94,6 @@ public bool TryDoRitual(EntityUid performer, EntityUid platform, ProtoId 0) - missingList.Add(name.Key); - // add missing tags foreach (var tag in requiredTags) if (tag.Value > 0) @@ -167,6 +154,7 @@ public override void Initialize() SubscribeLocalEvent(OnInteract); SubscribeLocalEvent(OnInteractUsing); SubscribeLocalEvent(OnExamine); + SubscribeLocalEvent(OnRitualChosenMessage); } private void OnInteract(Entity ent, ref InteractHandEvent args) @@ -180,22 +168,22 @@ private void OnInteract(Entity ent, ref InteractHand return; } - if (heretic.ChosenRitual == null) - heretic.ChosenRitual = heretic.KnownRituals[0]; + _uiSystem.OpenUi(ent.Owner, HereticRitualRuneUiKey.Key, args.User); + } - else if (heretic.ChosenRitual != null) - { - var index = heretic.KnownRituals.FindIndex(m => m == heretic.ChosenRitual) + 1; + private void OnRitualChosenMessage(Entity ent, ref HereticRitualMessage args) + { + var user = args.Actor; - if (index >= heretic.KnownRituals.Count) - index = 0; + if (!TryComp(user, out var heretic)) + return; - heretic.ChosenRitual = heretic.KnownRituals[index]; - } + heretic.ChosenRitual = args.ProtoId; var ritualName = Loc.GetString(GetRitual(heretic.ChosenRitual).Name); - _popup.PopupEntity(Loc.GetString("heretic-ritual-switch", ("name", ritualName)), args.User, args.User); + _popup.PopupEntity(Loc.GetString("heretic-ritual-switch", ("name", ritualName)), user, user); } + private void OnInteractUsing(Entity ent, ref InteractUsingEvent args) { if (!TryComp(args.User, out var heretic)) @@ -214,6 +202,7 @@ private void OnInteractUsing(Entity ent, ref Interac return; _audio.PlayPvs(RitualSuccessSound, ent, AudioParams.Default.WithVolume(-3f)); + _popup.PopupEntity(Loc.GetString("heretic-ritual-success"), ent, args.User); Spawn("HereticRuneRitualAnimation", Transform(ent).Coordinates); } diff --git a/Content.Server/ADT/Heretic/EntitySystems/HereticSystem.cs b/Content.Server/ADT/Heretic/EntitySystems/HereticSystem.cs index 4b4410b8ee0..0678bd6dcee 100644 --- a/Content.Server/ADT/Heretic/EntitySystems/HereticSystem.cs +++ b/Content.Server/ADT/Heretic/EntitySystems/HereticSystem.cs @@ -13,6 +13,16 @@ using Content.Server.Atmos.Components; using Content.Shared.Damage; using Content.Server.Heretic.Components; +using Content.Server.Antag; +using Robust.Shared.Random; +using System.Linq; +using Content.Shared.Humanoid; +using Robust.Server.Player; +using Content.Server.Revolutionary.Components; +using Content.Shared.Random.Helpers; +using Content.Shared.Roles.Jobs; +using Robust.Shared.Prototypes; +using Content.Shared.Roles; namespace Content.Server.Heretic.EntitySystems; @@ -23,6 +33,10 @@ public sealed partial class HereticSystem : EntitySystem [Dependency] private readonly HereticKnowledgeSystem _knowledge = default!; [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly SharedEyeSystem _eye = default!; + [Dependency] private readonly AntagSelectionSystem _antag = default!; + [Dependency] private readonly IRobustRandom _rand = default!; + [Dependency] private readonly IPlayerManager _playerMan = default!; + [Dependency] private readonly IPrototypeManager _prot = default!; private float _timer = 0f; private float _passivePointCooldown = 20f * 60f; @@ -32,10 +46,15 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnCompInit); - SubscribeLocalEvent(OnMagicItemExamine); + + SubscribeLocalEvent(OnUpdateTargets); + SubscribeLocalEvent(OnRerollTargets); SubscribeLocalEvent(OnAscension); + SubscribeLocalEvent(OnBeforeDamage); SubscribeLocalEvent(OnDamage); + + SubscribeLocalEvent(OnMagicItemExamine); } public override void Update(float frameTime) @@ -77,34 +96,82 @@ private void OnCompInit(Entity ent, ref ComponentInit args) foreach (var knowledge in ent.Comp.BaseKnowledge) _knowledge.AddKnowledge(ent, ent.Comp, knowledge); - } - private void OnMagicItemExamine(Entity ent, ref ExaminedEvent args) - { - if (!HasComp(args.Examiner)) - return; - - args.PushMarkup(Loc.GetString("heretic-magicitem-examine")); + RaiseLocalEvent(ent, new EventHereticRerollTargets()); } - private void OnBeforeDamage(Entity ent, ref BeforeDamageChangedEvent args) + #region Internal events (target reroll, ascension, etc.) + + private void OnUpdateTargets(Entity ent, ref EventHereticUpdateTargets args) { - // ignore damage from heretic stuff - if (args.Origin.HasValue && HasComp(args.Origin)) - args.Cancelled = true; + ent.Comp.SacrificeTargets = ent.Comp.SacrificeTargets + .Where(target => TryGetEntity(target, out var tent) && Exists(tent)) + .ToList(); + Dirty(ent); // update client } - private void OnDamage(Entity ent, ref DamageModifyEvent args) + + private void OnRerollTargets(Entity ent, ref EventHereticRerollTargets args) { - if (!ent.Comp.Ascended) - return; + // welcome to my linq smorgasbord of doom + // have fun figuring that out - switch (ent.Comp.CurrentPath) + var targets = _antag.GetAliveConnectedPlayers(_playerMan.Sessions) + .Where(ics => ics.AttachedEntity.HasValue && HasComp(ics.AttachedEntity)); + + var eligibleTargets = new List(); + foreach (var target in targets) + eligibleTargets.Add(target.AttachedEntity!.Value); // it can't be null because see .Where(HasValue) + + // no heretics or other baboons + eligibleTargets = eligibleTargets.Where(t => !HasComp(t) && !HasComp(t)).ToList(); + + var pickedTargets = new List(); + + var predicates = new List>(); + + // pick one command staff + predicates.Add(t => HasComp(t)); + + // pick one secoff + predicates.Add(t => + _prot.TryIndex("Security", out var dept) // can we get sec jobs? + && _mind.TryGetMind(t, out var mindid, out _) // does it have a mind? + && TryComp(mindid, out var jobc) && jobc.Prototype.HasValue // does it have a job? + && dept.Roles.Contains(jobc.Prototype!.Value)); // is that job being shitsec? + + // pick one person from the same department + predicates.Add(t => + _mind.TryGetMind(t, out var tmind, out _) && _mind.TryGetMind(ent, out var ownmind, out _) // get minds + && TryComp(tmind, out var tjob) && tjob.Prototype.HasValue // get jobs + && TryComp(ownmind, out var ownjob) && ownjob.Prototype.HasValue + && _prot.EnumeratePrototypes() // compare jobs for all + .Where(d => + d.Roles.Contains(tjob.Prototype.Value) + && d.Roles.Contains(ownjob.Prototype.Value)) // true = same department + .ToList().Count != 0); + + foreach (var predicate in predicates) { - case "Ash": - // nullify heat damage because zased - args.Damage.DamageDict["Heat"] = 0; - break; + var list = eligibleTargets.Where(predicate).ToList(); + + if (list.Count == 0) + continue; + + // pick and take + var picked = _rand.PickAndTake(list); + pickedTargets.Add(picked); } + + // add whatever more until satisfied + for (int i = 0; i <= ent.Comp.MaxTargets - pickedTargets.Count; i++) + if (eligibleTargets.Count > 0) + pickedTargets.Add(_rand.PickAndTake(eligibleTargets)); + + // leave only unique entityuids + pickedTargets = pickedTargets.Distinct().ToList(); + + ent.Comp.SacrificeTargets = pickedTargets.ConvertAll(t => GetNetEntity(t)).ToList(); + Dirty(ent); // update client } // notify the crew of how good the person is and play the cool sound :godo: @@ -153,4 +220,44 @@ private void OnAscension(Entity ent, ref EventHereticAscension break; } } + + #endregion + + #region External events (damage, etc.) + + private void OnBeforeDamage(Entity ent, ref BeforeDamageChangedEvent args) + { + // ignore damage from heretic stuff + if (args.Origin.HasValue && HasComp(args.Origin)) + args.Cancelled = true; + } + private void OnDamage(Entity ent, ref DamageModifyEvent args) + { + if (!ent.Comp.Ascended) + return; + + switch (ent.Comp.CurrentPath) + { + case "Ash": + // nullify heat damage because zased + args.Damage.DamageDict["Heat"] = 0; + break; + } + } + + #endregion + + + + #region Miscellaneous + + private void OnMagicItemExamine(Entity ent, ref ExaminedEvent args) + { + if (!HasComp(args.Examiner)) + return; + + args.PushMarkup(Loc.GetString("heretic-magicitem-examine")); + } + + #endregion } diff --git a/Content.Server/ADT/Heretic/Ritual/CustomBehavior.Sacrifice.cs b/Content.Server/ADT/Heretic/Ritual/CustomBehavior.Sacrifice.cs index 8ce3f7a660a..a43b7d61013 100644 --- a/Content.Server/ADT/Heretic/Ritual/CustomBehavior.Sacrifice.cs +++ b/Content.Server/ADT/Heretic/Ritual/CustomBehavior.Sacrifice.cs @@ -29,6 +29,11 @@ namespace Content.Server.Heretic.Ritual; /// [DataField] public float Max = 1; + /// + /// Should we count only targets? + /// + [DataField] public bool OnlyTargets = false; + // this is awful but it works so i'm not complaining protected SharedMindSystem _mind = default!; protected HereticSystem _heretic = default!; @@ -62,8 +67,9 @@ public override bool Execute(RitualData args, out string? outstr) // get all the dead ones foreach (var look in lookup) { - if (!args.EntityManager.TryGetComponent(look, out var mobstate) - || !args.EntityManager.HasComponent(look)) + if (!args.EntityManager.TryGetComponent(look, out var mobstate) // only mobs + || !args.EntityManager.HasComponent(look) // only humans + || (OnlyTargets && !hereticComp.SacrificeTargets.Contains(args.EntityManager.GetNetEntity(look)))) // only targets continue; if (mobstate.CurrentState == Shared.Mobs.MobState.Dead) @@ -72,7 +78,7 @@ public override bool Execute(RitualData args, out string? outstr) if (uids.Count < Min) { - outstr = Loc.GetString("heretic-ritual-fail-sacrifice"); + outstr = Loc.GetString("heretic-ritual-fail-sacrifice-ineligible"); return false; } @@ -115,5 +121,6 @@ public override void Finalize(RitualData args) // reset it because it refuses to work otherwise. uids = new(); + args.EntityManager.EventBus.RaiseLocalEvent(args.Performer, new EventHereticUpdateTargets()); } } diff --git a/Content.Server/ADT/Magic/ChainFireballComponent.cs b/Content.Server/ADT/Magic/ChainFireballComponent.cs index 0947fb6dfdb..a629f7170f6 100644 --- a/Content.Server/ADT/Magic/ChainFireballComponent.cs +++ b/Content.Server/ADT/Magic/ChainFireballComponent.cs @@ -3,15 +3,10 @@ namespace Content.Server.Magic; [RegisterComponent] public sealed partial class ChainFireballComponent : Component { - /// - /// The added chance of the ball disappearing (in %) - /// - [DataField] public float DisappearChanceDelta = 0.5f; - /// /// The chance of the ball disappearing (in %) /// - [DataField] public float DisappearChance = 0f; + [DataField] public float DisappearChance = 0.05f; public List IgnoredTargets = new(); } diff --git a/Content.Server/ADT/Magic/ChainFireballSystem.cs b/Content.Server/ADT/Magic/ChainFireballSystem.cs index a2544d726df..5909b28a94e 100644 --- a/Content.Server/ADT/Magic/ChainFireballSystem.cs +++ b/Content.Server/ADT/Magic/ChainFireballSystem.cs @@ -30,7 +30,8 @@ private void OnHit(Entity ent, ref ProjectileHitEvent ar if (_random.Prob(ent.Comp.DisappearChance)) return; - Spawn(ent, ent.Comp.IgnoredTargets); + // spawn new fireball on target + Spawn(args.Target, ent.Comp.IgnoredTargets); QueueDel(ent); } @@ -43,7 +44,7 @@ public bool Spawn(EntityUid source, List ignoredTargets) foreach (var look in lookup) { if (ignoredTargets.Contains(look) - || !HasComp(look)) // ignore non mobs whatsoever + || !HasComp(look)) // ignore non mobs continue; mobs.Add(look); @@ -60,17 +61,14 @@ public bool Spawn(EntityUid source, EntityUid target, List ignoredTar { return SpawnFireball(source, target, ignoredTargets); } - private bool SpawnFireball(EntityUid uid, EntityUid target, List ignoredTargets) + public bool SpawnFireball(EntityUid uid, EntityUid target, List ignoredTargets) { var ball = Spawn("FireballChain", Transform(uid).Coordinates); + + // set ignore list if it wasn't set already if (TryComp(ball, out var sfc)) - { sfc.IgnoredTargets = sfc.IgnoredTargets.Count > 0 ? sfc.IgnoredTargets : ignoredTargets; - if (TryComp(uid, out var usfc)) - sfc.DisappearChance = usfc.DisappearChance + sfc.DisappearChanceDelta; - } - // launch it towards the target var fromCoords = Transform(uid).Coordinates; var toCoords = Transform(target).Coordinates; @@ -86,7 +84,7 @@ private bool SpawnFireball(EntityUid uid, EntityUid target, List igno var direction = toCoords.ToMapPos(EntityManager, _transform) - spawnCoords.ToMapPos(EntityManager, _transform); - _gun.ShootProjectile(ball, direction, userVelocity, uid, ball); + _gun.ShootProjectile(ball, direction, userVelocity, uid, uid); return true; } diff --git a/Content.Server/Antag/AntagSelectionSystem.API.cs b/Content.Server/Antag/AntagSelectionSystem.API.cs index 23e77c21028..bbb38f01558 100644 --- a/Content.Server/Antag/AntagSelectionSystem.API.cs +++ b/Content.Server/Antag/AntagSelectionSystem.API.cs @@ -78,6 +78,20 @@ public int GetTotalPlayerCount(IList pool) return count; } + // goob edit + public List GetAliveConnectedPlayers(IList pool) + { + var l = new List(); + foreach (var session in pool) + { + if (session.Status is SessionStatus.Disconnected or SessionStatus.Zombie) + continue; + l.Add(session); + } + return l; + } + // goob edit end + /// /// Gets the number of antagonists that should be present for a given antag definition based on the provided pool. /// A null pool will simply use the player count. diff --git a/Content.Shared/ADT/Heretic/Components/HereticComponent.cs b/Content.Shared/ADT/Heretic/Components/HereticComponent.cs index 7422a662a8b..dbf23d7cceb 100644 --- a/Content.Shared/ADT/Heretic/Components/HereticComponent.cs +++ b/Content.Shared/ADT/Heretic/Components/HereticComponent.cs @@ -14,13 +14,23 @@ public sealed partial class HereticComponent : Component "BreakOfDawn", "HeartbeatOfMansus", "AmberFocus", - "CodexCicatrix", - "CloakOfShadow" + "LivingHeart", }; #endregion - [DataField, AutoNetworkedField] public bool Ascended = false; + [DataField, AutoNetworkedField] public List> KnownRituals = new(); + [DataField] public ProtoId? ChosenRitual; + + /// + /// Contains the list of targets that are eligible for sacrifice. + /// + [DataField, AutoNetworkedField] public List SacrificeTargets = new(); + + /// + /// How much targets can a heretic have? + /// + [DataField, AutoNetworkedField] public int MaxTargets = 5; // hardcoded paths because i hate it // "Ash", "Lock", "Flesh", "Void", "Blade", "Rust" @@ -34,19 +44,13 @@ public sealed partial class HereticComponent : Component /// [DataField, AutoNetworkedField] public int PathStage = 0; - [DataField, AutoNetworkedField] public List> KnownRituals = new(); - [DataField] public ProtoId? ChosenRitual; + [DataField, AutoNetworkedField] public bool Ascended = false; /// /// Used to prevent double casting mansus grasp. /// [ViewVariables(VVAccess.ReadOnly)] public bool MansusGraspActive = false; - /// - /// Doubles the eldritch influence if true. - /// - [ViewVariables(VVAccess.ReadOnly)] public bool CodexActive = false; - /// /// Indicates if a heretic is able to cast advanced spells. /// Requires wearing focus, codex cicatrix, hood or anything else that allows him to do so. diff --git a/Content.Shared/ADT/Heretic/Components/HereticRitualEvents.cs b/Content.Shared/ADT/Heretic/Components/HereticRitualEvents.cs new file mode 100644 index 00000000000..a883af4fd0c --- /dev/null +++ b/Content.Shared/ADT/Heretic/Components/HereticRitualEvents.cs @@ -0,0 +1,22 @@ +using Content.Shared.Heretic.Prototypes; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.ADT.Heretic.Components; + +[Serializable, NetSerializable] +public sealed class HereticRitualMessage : BoundUserInterfaceMessage +{ + public ProtoId ProtoId; + + public HereticRitualMessage(ProtoId protoId) + { + ProtoId = protoId; + } +} + +[Serializable, NetSerializable] +public enum HereticRitualRuneUiKey : byte +{ + Key +} diff --git a/Content.Shared/ADT/Heretic/Heretic.Abilites.cs b/Content.Shared/ADT/Heretic/Heretic.Abilites.cs index 1f1ef18e7fa..2b458adc7b9 100644 --- a/Content.Shared/ADT/Heretic/Heretic.Abilites.cs +++ b/Content.Shared/ADT/Heretic/Heretic.Abilites.cs @@ -66,6 +66,15 @@ public sealed partial class CheckMagicItemEvent : HandledEntityEventArgs, IInven // basic public sealed partial class EventHereticOpenStore : InstantActionEvent { } public sealed partial class EventHereticMansusGrasp : InstantActionEvent { } +public sealed partial class EventHereticLivingHeart : InstantActionEvent { } // opens ui +[Serializable, NetSerializable] public sealed partial class EventHereticLivingHeartActivate : BoundUserInterfaceMessage // triggers the logic +{ + public NetEntity? Target { get; set; } +} +[Serializable, NetSerializable] public enum HereticLivingHeartKey : byte +{ + Key +} // for mobs public sealed partial class EventHereticMansusLink : EntityTargetActionEvent { } diff --git a/Content.Shared/ADT/Heretic/Prototypes/Heretic.Data.cs b/Content.Shared/ADT/Heretic/Prototypes/Heretic.Data.cs index 5bd113a4df4..549d077f136 100644 --- a/Content.Shared/ADT/Heretic/Prototypes/Heretic.Data.cs +++ b/Content.Shared/ADT/Heretic/Prototypes/Heretic.Data.cs @@ -1,12 +1,12 @@ using Content.Shared.Tag; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Utility; namespace Content.Shared.Heretic.Prototypes; -[Serializable, NetSerializable] +[Serializable, NetSerializable, DataDefinition] [Prototype("hereticKnowledge")] -[DataDefinition] public sealed partial class HereticKnowledgePrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; @@ -27,9 +27,8 @@ public sealed partial class HereticKnowledgePrototype : IPrototype [DataField] public List? ActionPrototypes; } -[Serializable, NetSerializable] +[Serializable, NetSerializable, DataDefinition] [Prototype("hereticRitual")] -[DataDefinition] public sealed partial class HereticRitualPrototype : IPrototype, ICloneable { [IdDataField] public string ID { get; private set; } = default!; @@ -64,6 +63,11 @@ public sealed partial class HereticRitualPrototype : IPrototype, ICloneable /// [DataField] public ProtoId? OutputKnowledge; + /// + /// Icon for ritual in radial menu. + /// + [DataField] public SpriteSpecifier Icon = new SpriteSpecifier.Rsi(new("ADT/Heretic/amber_focus.rsi"), "icon"); + /// Please use this instead of editing the prototype. Shit WILL break if you don't. public object Clone() { @@ -76,9 +80,12 @@ public object Clone() CustomBehaviors = CustomBehaviors, Output = Output, OutputEvent = OutputEvent, - OutputKnowledge = OutputKnowledge + OutputKnowledge = OutputKnowledge, + Icon = Icon }; } } [Serializable, NetSerializable, DataDefinition] public sealed partial class EventHereticAscension : EntityEventArgs { } +[Serializable, NetSerializable, DataDefinition] public sealed partial class EventHereticRerollTargets : EntityEventArgs { } +[Serializable, NetSerializable, DataDefinition] public sealed partial class EventHereticUpdateTargets : EntityEventArgs { } diff --git a/Resources/Audio/ADT/Heretic/Ambience/Antag/Heretic/attributions.yml b/Resources/Audio/ADT/Heretic/Ambience/Antag/Heretic/attributions.yml new file mode 100644 index 00000000000..904fa35f354 --- /dev/null +++ b/Resources/Audio/ADT/Heretic/Ambience/Antag/Heretic/attributions.yml @@ -0,0 +1,4 @@ +- files: ["ascend_ash.ogg", "ascend_blade.ogg", "ascend_flesh.ogg", "ascend_knock.ogg", "ascend_rust.ogg", "ascend_void.ogg", "heretic_gain.ogg", "heretic_gain_intense.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from /tg/station" + source: "https://github.com/tgstation/tgstation/tree/master/sound/music/antag/heretic" \ No newline at end of file diff --git a/Resources/Audio/ADT/Heretic/attributions.yml b/Resources/Audio/ADT/Heretic/attributions.yml new file mode 100644 index 00000000000..571127c8b52 --- /dev/null +++ b/Resources/Audio/ADT/Heretic/attributions.yml @@ -0,0 +1,9 @@ +- files: ["blind.ogg", "castsummon.ogg", "disintegrate.ogg", "hereticknock.ogg", "repulse.ogg", "voidblink.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from /tg/station" + source: "https://github.com/tgstation/tgstation/tree/master/sound/effects/magic" + +- files: ["heartbeat.ogg"] + license: "CC-BY-SA-3.0" + copyright: "made by whateverusername0" + source: "https://knowyourmeme.com/memes/source-i-made-it-up" \ No newline at end of file diff --git a/Resources/Audio/ADT/Heretic/heartbeat.ogg b/Resources/Audio/ADT/Heretic/heartbeat.ogg new file mode 100644 index 0000000000000000000000000000000000000000..acd8dbeb82b0295ff6e6c9d5156ceb333b72cf95 GIT binary patch literal 9088 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 aDQWe$9v%$s?Mr6Y4r6$RrC0&i4)}k^r;05A literal 0 HcmV?d00001 diff --git a/Resources/Locale/ru-RU/ADT/Heretic/abilities/heretic.ftl b/Resources/Locale/ru-RU/ADT/Heretic/abilities/heretic.ftl index 021619e29ad..8d48956375e 100644 --- a/Resources/Locale/ru-RU/ADT/Heretic/abilities/heretic.ftl +++ b/Resources/Locale/ru-RU/ADT/Heretic/abilities/heretic.ftl @@ -17,6 +17,11 @@ heretic-manselink-fail-nomind = У этого существа отсутств heretic-manselink-start = Вы начинаете связывать разум существа со своим. heretic-manselink-start-target = Вы чувствуете, как ваш разум куда-то утягивает... +heretic-livingheart-notargets = Нет доступных целей. Посетите руну. +heretic-livingheart-offstation = {$state} в направлении к {$direction}у! +heretic-livingheart-onstation = {$state} в направелии к {$direction}у! +heretic-livingheart-unknown = Он... не в этой реальности. + ## speech heretic-speech-mansusgrasp = R'CH T'H TR'TH! diff --git a/Resources/Locale/ru-RU/ADT/Heretic/rituals.ftl b/Resources/Locale/ru-RU/ADT/Heretic/rituals.ftl index 70d53c412e1..c84715508f1 100644 --- a/Resources/Locale/ru-RU/ADT/Heretic/rituals.ftl +++ b/Resources/Locale/ru-RU/ADT/Heretic/rituals.ftl @@ -8,13 +8,14 @@ heretic-ritual-noritual = Ритуал не выбран! heretic-ritual-basic-sacrifice = Сердцебиение Мансуса heretic-ritual-basic-focus = Янтарная Призма -heretic-ritual-basic-codex = Кодекс Цикатрикс +heretic-ritual-basic-heart = Беспокойное сердцебиение heretic-ritual-fail-sacrifice = Нет тела для жертвоприношения. heretic-ritual-fail-reagentpuddle = Не имеется следующего реагента: {$reagentname}. heretic-ritual-fail-temperature-hot = Здесь слишком жарко. heretic-ritual-fail-temperature-cold = Здесь недостаточно холодно. heretic-ritual-fail-sacrifice-ash = Недостаточно мертвых или горящих. +heretic-ritual-fail-sacrifice-ineligible = Руна отказывается принять эту жертву. ## side quests heretic-ritual-side-knowledge = Ритуал Знания diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/basic.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/basic.ftl new file mode 100644 index 00000000000..fd1525f3153 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/basic.ftl @@ -0,0 +1,11 @@ +action-heretic-store-name = Открыть магазин знаний +action-heretic-store-desc = Откройте магазин знаний. + +action-heretic-grasp-name = Хватка мансуса +action-heretic-grasp-desc = Направьте силу Старых Богов через свою руку. + +action-heretic-heart-name = Живое сердце +action-heretic-heart-desc = Используйте свое сердце, чтобы определить местоположение жертвенных целей. + +action-heretic-link-name = Связь мансуса +action-heretic-link-desc = Пронзите реальность и соедините умы друг с другом. Радиоклавиша по умолчанию - \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_ash.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_ash.ftl new file mode 100644 index 00000000000..9781cc88ecd --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_ash.ftl @@ -0,0 +1,14 @@ +action-heretic-ash-passage-name = Пепельный Сдвиг +action-heretic-ash-passage-desc = Заклинание малой дальности, позволяющее беспрепятственно проходить сквозь стены. + +action-heretic-ash-blast-name = Вулканический Взрыв +action-heretic-ash-blast-desc = Зарядите огненную вспышку, которая проносится между ближайшими целями, поджигая их. + +action-heretic-ash-rebirth-name = Пламенное Перерождение +action-heretic-ash-rebirth-desc = Заклинание, которое гасит вас и лишает жизненных сил ближайших язычников, охваченных пламенем. + +action-heretic-ash-oath-name = Клятва пламени +action-heretic-ash-oath-desc = В течение минуты вы будете пассивно создавать вокруг себя огненное кольцо. + +action-heretic-ash-cascade-name = Огненный каскад +action-heretic-ash-cascade-desc = Поджигает воздух вокруг вас. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_flesh.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_flesh.ftl new file mode 100644 index 00000000000..d70021ad702 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_flesh.ftl @@ -0,0 +1,5 @@ +action-heretic-flesh-surgery-name = Хирургия плоти +action-heretic-flesh-surgery-desc = Удалите случайный орган жертвы. + +action-heretic-flesh-uncoil-name = ВЫСВОБОЖДЕНИЕ РЕАЛЬНОСТИ +action-heretic-flesh-uncoil-desc = Превратитесь в эльдрический ужас. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_void.ftl b/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_void.ftl new file mode 100644 index 00000000000..0e003be4a65 --- /dev/null +++ b/Resources/Locale/ru-RU/ADT/prototypes/Actions/heretic/path_void.ftl @@ -0,0 +1,8 @@ +action-heretic-void-blast-name = Пусотный выстрел +action-heretic-void-blast-desc = Выстрелите перед собой конусом льда. + +action-heretic-void-phase-name = Пустотный рывой +action-heretic-void-phase-desc = Сделайте рывок сквозь пустоту, сбивая с ног всех вокруг. + +action-heretic-void-pull-name = Тяга к пустоте +action-heretic-void-pull-desc = Притягивайте и повреждайте ближайших язычников. \ No newline at end of file diff --git a/Resources/Prototypes/ADT/Entities/Personalization/Objects/personalization_items.yml b/Resources/Prototypes/ADT/Entities/Personalization/Objects/personalization_items.yml index ec8fb3e73b6..3b3900a00b9 100644 --- a/Resources/Prototypes/ADT/Entities/Personalization/Objects/personalization_items.yml +++ b/Resources/Prototypes/ADT/Entities/Personalization/Objects/personalization_items.yml @@ -983,104 +983,103 @@ sound: path: /Audio/Voice/Reptilian/reptilian_scream.ogg - # Спальник для Бобо -- type: entity - id: ADTBedSleepingBagBobo - parent: BaseDeployFoldable - name: sleeping bag - description: This is a special cocoon blanket that keeps a person warm during sleep. - components: - - type: Item - size: Small - - type: Sprite - drawdepth: SmallObjects - sprite: ADT/Structures/Furniture/meshok.rsi - layers: - - state: duffel_bag - map: ["unfoldedLayer", "enum.StorageVisualLayers.Base"] - - state: duffel_bag_folded - map: ["foldedLayer"] - visible: false - - state: open_overlay - map: ["enum.StorageVisualLayers.Door"] - - type: Icon - sprite: ADT/Structures/Furniture/meshok.rsi - state: duffel_bag - - type: Tag - tags: - - BodyBag - - type: Clickable - - type: InteractionOutline - - type: MovedByPressure - - type: Physics - bodyType: Dynamic - - type: Transform - noRot: true - - type: Fixtures - fixtures: - fix1: - shape: - !type:PhysShapeAabb - bounds: "-0.25,-0.4,0.25,0.1" - density: 20 - mask: - - ItemMask - - type: EntityStorage - capacity: 1 - isCollidableWhenOpen: true - closeSound: - path: /Audio/Misc/zip.ogg - openSound: - path: /Audio/Misc/zip.ogg - - type: EntityStorageLayingDownOverride - - type: Appearance - - type: EntityStorageVisuals - stateDoorOpen: open_overlay - - type: GenericVisualizer - visuals: - enum.FoldedVisuals.State: - foldedLayer: - True: {visible: true} - False: {visible: false} - unfoldedLayer: - True: {visible: false} - False: {visible: true} - - type: Pullable - - type: AntiRottingContainer - - type: ItemSlots - - type: ContainerContainer - containers: - entity_storage: !type:Container - paper_label: !type:ContainerSlot - - type: StaticPrice - price: 50 - # св-ва кровати: - - type: HealOnBuckle - damage: - types: - Poison: -0.1 - Blunt: -0.1 - - type: Strap - position: Down - rotation: -90 - # Слоты - - type: Clothing - quickEquip: false - slots: - - back - -- type: entity - id: ADTBedSleepingBagBoboFolded - name: sleeping bag fold - description: A plastic bag designed for the storage and transportation of cadavers to stop body decomposition. - parent: ADTBedSleepingBagBobo - suffix: folded - components: - - type: Foldable - folded: true - - type: Item - size: Normal - - type: Strap +# # Спальник для Бобо +# - type: entity +# id: ADTBedSleepingBagBobo +# parent: BaseDeployFoldable +# name: sleeping bag +# description: This is a special cocoon blanket that keeps a person warm during sleep. +# components: +# - type: Item +# size: Small +# - type: Sprite +# drawdepth: SmallObjects +# sprite: ADT/Structures/Furniture/meshok.rsi +# layers: +# - state: duffel_bag +# map: ["unfoldedLayer", "enum.StorageVisualLayers.Base"] +# - state: duffel_bag_folded +# map: ["foldedLayer"] +# visible: false +# - state: open_overlay +# map: ["enum.StorageVisualLayers.Door"] +# - type: Icon +# sprite: ADT/Structures/Furniture/meshok.rsi +# state: duffel_bag +# - type: Tag +# tags: +# - BodyBag +# - type: Clickable +# - type: InteractionOutline +# - type: MovedByPressure +# - type: Physics +# bodyType: Dynamic +# - type: Transform +# noRot: true +# - type: Fixtures +# fixtures: +# fix1: +# shape: +# !type:PhysShapeAabb +# bounds: "-0.25,-0.4,0.25,0.1" +# density: 20 +# mask: +# - ItemMask +# - type: EntityStorage +# capacity: 1 +# isCollidableWhenOpen: true +# closeSound: +# path: /Audio/Misc/zip.ogg +# openSound: +# path: /Audio/Misc/zip.ogg +# - type: EntityStorageLayingDownOverride +# - type: Appearance +# - type: EntityStorageVisuals +# stateDoorOpen: open_overlay +# - type: GenericVisualizer +# visuals: +# enum.FoldedVisuals.State: +# foldedLayer: +# True: {visible: true} +# False: {visible: false} +# unfoldedLayer: +# True: {visible: false} +# False: {visible: true} +# - type: Pullable +# - type: AntiRottingContainer +# - type: ItemSlots +# - type: ContainerContainer +# containers: +# entity_storage: !type:Container +# paper_label: !type:ContainerSlot +# - type: StaticPrice +# price: 50 +# # св-ва кровати: +# - type: HealOnBuckle +# damage: +# types: +# Poison: -0.1 +# Blunt: -0.1 +# - type: Strap +# position: Down +# rotation: -90 +# # Слоты +# - type: Clothing +# quickEquip: false +# slots: +# - back + +# - type: entity +# id: ADTBedSleepingBagBoboFolded +# name: sleeping bag fold +# description: A plastic bag designed for the storage and transportation of cadavers to stop body decomposition. +# parent: ADTBedSleepingBagBobo +# suffix: folded +# components: +# - type: Foldable +# folded: true +# - type: Item +# size: Normal - type: entity parent: BasePlushie diff --git a/Resources/Prototypes/ADT/Heretic/Actions/Heretic/basic.yml b/Resources/Prototypes/ADT/Heretic/Actions/Heretic/basic.yml index bbb79a22edf..329d3d1f171 100644 --- a/Resources/Prototypes/ADT/Heretic/Actions/Heretic/basic.yml +++ b/Resources/Prototypes/ADT/Heretic/Actions/Heretic/basic.yml @@ -1,8 +1,8 @@ # actions - type: entity id: ActionHereticOpenStore - name: Open Knowledge Store - description: Open the Knowledge Store. + name: action-heretic-store-name + description: action-heretic-store-desc categories: [ HideSpawnMenu ] components: - type: InstantAction @@ -16,8 +16,8 @@ - type: entity id: ActionHereticMansusGrasp - name: Mansus Grasp - description: Channel the power of the Old Gods through your grip. + name: action-heretic-grasp-name + description: action-heretic-grasp-desc categories: [ HideSpawnMenu ] components: - type: InstantAction @@ -30,10 +30,26 @@ - type: HereticAction requireMagicItem: false +- type: entity + id: ActionHereticLivingHeart + name: action-heretic-heart-name + description: action-heretic-heart-desc + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + useDelay: 2 + itemIconStyle: NoItem + icon: + sprite: ADT/Heretic/abilities_heretic.rsi + state: living_heart + event: !type:EventHereticLivingHeart {} + - type: HereticAction + requireMagicItem: false + - type: entity id: ActionHereticMansusLink name: Manse Link - description: This spell allows you to pierce through reality and connect minds to one another via your Mansus Link. + description: Pierce through reality and connect minds to one another. Default radio key is :z categories: [ HideSpawnMenu ] components: - type: EntityTargetAction diff --git a/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_ash.yml b/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_ash.yml index 1ef52d43100..24367b28e76 100644 --- a/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_ash.yml +++ b/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_ash.yml @@ -1,7 +1,7 @@ - type: entity id: ActionHereticJaunt - name: Ashen Passage - description: A short range spell that allows you to pass unimpeded through walls. + name: action-heretic-ash-passage-name + description: action-heretic-ash-passage-desc categories: [ HideSpawnMenu ] components: - type: InstantAction @@ -17,8 +17,8 @@ - type: entity id: ActionHereticVolcanoBlast - name: Volcanic Blast - description: Charge up a blast of fire that chains between nearby targets, setting them ablaze. + name: action-heretic-ash-blast-name + description: action-heretic-ash-blast-desc categories: [ HideSpawnMenu ] components: - type: InstantAction @@ -34,8 +34,8 @@ - type: entity id: ActionHereticNightwatcherRebirth - name: Nightwatcher's Rebirth - description: A spell that extinguishes you and drains nearby heathens engulfed in flames of their life force. + name: action-heretic-ash-rebirth-name + description: action-heretic-ash-rebirth-desc categories: [ HideSpawnMenu ] components: - type: InstantAction @@ -51,8 +51,8 @@ - type: entity id: ActionHereticAscension1 - name: Oath of Flame - description: For a minute, you will passively create a ring of fire around you. + name: action-heretic-ash-oath-name + description: action-heretic-ash-oath-desc categories: [ HideSpawnMenu ] components: - type: InstantAction @@ -68,8 +68,8 @@ - type: entity id: ActionHereticAscension2 - name: Fire Cascade - description: Heats the air around you. + name: action-heretic-ash-cascade-name + description: action-heretic-ash-cascade-desc categories: [ HideSpawnMenu ] components: - type: InstantAction diff --git a/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_flesh.yml b/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_flesh.yml index afc0e8a66af..2c326681290 100644 --- a/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_flesh.yml +++ b/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_flesh.yml @@ -1,7 +1,7 @@ - type: entity id: ActionHereticFleshSurgery - name: flesh surgery - description: Remove a random organ from someone, or heal your teammates. + name: action-heretic-flesh-surgery-name + description: action-heretic-flesh-surgery-desc components: - type: EntityTargetAction useDelay: 30 @@ -15,8 +15,8 @@ - type: entity id: ActionPolymorphHereticHorror - name: REALITY UNCOIL - description: Transform into an eldritch horror. + name: action-heretic-flesh-uncoil-name + description: action-heretic-flesh-uncoil-desc components: - type: InstantAction useDelay: 60 diff --git a/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_void.yml b/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_void.yml index 3d9547ac32d..d0cc0d1d756 100644 --- a/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_void.yml +++ b/Resources/Prototypes/ADT/Heretic/Actions/Heretic/path_void.yml @@ -1,7 +1,7 @@ - type: entity id: ActionHereticVoidBlast - name: Void Blast - description: Fire off a cone of ice in front of you. + name: action-heretic-void-blast-name + description: action-heretic-void-blast-desc categories: [ HideSpawnMenu ] components: - type: InstantAction @@ -17,8 +17,8 @@ - type: entity id: ActionHereticVoidPhase - name: Void Phase - description: Shift through the void, knocking down everyone around you. + name: action-heretic-void-phase-name + description: action-heretic-void-phase-desc categories: [ HideSpawnMenu ] components: - type: WorldTargetAction @@ -36,8 +36,8 @@ - type: entity id: ActionHereticVoidPull - name: Void Pull - description: Pull and damage nearby heathens. + name: action-heretic-void-pull-name + description: action-heretic-void-pull-desc categories: [ HideSpawnMenu ] components: - type: InstantAction diff --git a/Resources/Prototypes/ADT/Heretic/Entities/Clothing/OuterClothing/armor.yml b/Resources/Prototypes/ADT/Heretic/Entities/Clothing/OuterClothing/armor.yml index f467c3753c3..54af67e0736 100644 --- a/Resources/Prototypes/ADT/Heretic/Entities/Clothing/OuterClothing/armor.yml +++ b/Resources/Prototypes/ADT/Heretic/Entities/Clothing/OuterClothing/armor.yml @@ -17,6 +17,7 @@ Piercing: 0.50 Heat: 0.50 Caustic: 0.50 + staminaModifier: 0.5 - type: ExplosionResistance damageCoefficient: 0.25 - type: ToggleableClothing diff --git a/Resources/Prototypes/ADT/Heretic/Entities/Objects/Weapons/Melee/heretic_blades.yml b/Resources/Prototypes/ADT/Heretic/Entities/Objects/Weapons/Melee/heretic_blades.yml index 4750601e04a..31ba63ac2c7 100644 --- a/Resources/Prototypes/ADT/Heretic/Entities/Objects/Weapons/Melee/heretic_blades.yml +++ b/Resources/Prototypes/ADT/Heretic/Entities/Objects/Weapons/Melee/heretic_blades.yml @@ -15,6 +15,8 @@ damage: types: Slash: 17.5 + soundHit: + path: /Audio/Weapons/bladeslice.ogg - type: Item size: Normal sprite: ADT/Heretic/Blades/blade_blade-inhand.rsi @@ -40,6 +42,8 @@ types: Heat: 10 Slash: 7.5 + soundHit: + path: /Audio/Weapons/bladeslice.ogg - type: entity parent: HereticBladeBase @@ -112,3 +116,5 @@ types: Cold: 10 Slash: 7.5 + soundHit: + path: /Audio/Weapons/bladeslice.ogg diff --git a/Resources/Prototypes/ADT/Heretic/Entities/Structures/Specific/Heretic/ritual_rune.yml b/Resources/Prototypes/ADT/Heretic/Entities/Structures/Specific/Heretic/ritual_rune.yml index d24300b0bad..a543dfcddbe 100644 --- a/Resources/Prototypes/ADT/Heretic/Entities/Structures/Specific/Heretic/ritual_rune.yml +++ b/Resources/Prototypes/ADT/Heretic/Entities/Structures/Specific/Heretic/ritual_rune.yml @@ -11,6 +11,10 @@ sprite: ADT/Heretic/ritual_rune.rsi state: icon - type: Clickable + - type: UserInterface + interfaces: + enum.HereticRitualRuneUiKey.Key: + type: HereticRitualRuneBoundUserInterface - type: entity id: HereticRuneRitualDrawAnimation diff --git a/Resources/Prototypes/ADT/Heretic/Heretic/heretic_knowledge.yml b/Resources/Prototypes/ADT/Heretic/Heretic/heretic_knowledge.yml index b1817559e5e..68ad60b4e74 100644 --- a/Resources/Prototypes/ADT/Heretic/Heretic/heretic_knowledge.yml +++ b/Resources/Prototypes/ADT/Heretic/Heretic/heretic_knowledge.yml @@ -16,17 +16,11 @@ - AmberFocus - type: hereticKnowledge - id: CodexCicatrix - # ritualPrototypes: - -- type: hereticKnowledge - id: CloakOfShadow - # actionPrototypes: - -- type: hereticKnowledge - id: RitualOfKnowledge + id: LivingHeart ritualPrototypes: - - RitualOfKnowledge + - LivingHeart + actionPrototypes: + - ActionHereticLivingHeart # ash path - type: hereticKnowledge @@ -43,6 +37,8 @@ - type: hereticKnowledge id: AshenShift + path: Ash + sideKnowledge: true stage: 3 actionPrototypes: - ActionHereticJaunt @@ -61,6 +57,8 @@ - type: hereticKnowledge id: MaskOfMadness + path: Ash + sideKnowledge: true stage: 6 ritualPrototypes: - MaskOfMadness @@ -72,6 +70,8 @@ - type: hereticKnowledge id: NightwatcherRebirth + path: Ash + sideKnowledge: true stage: 8 actionPrototypes: - ActionHereticNightwatcherRebirth @@ -106,6 +106,8 @@ - type: hereticKnowledge id: ImperfectRitual + path: Flesh + sideKnowledge: true stage: 3 ritualPrototypes: - ImperfectRitual @@ -124,6 +126,8 @@ - type: hereticKnowledge id: RawRitual + path: Flesh + sideKnowledge: true stage: 6 ritualPrototypes: - RawRitual @@ -135,6 +139,8 @@ - type: hereticKnowledge id: LonelyRitual + path: Flesh + sideKnowledge: true stage: 8 ritualPrototypes: - LonelyRitual @@ -168,6 +174,8 @@ - type: hereticKnowledge id: AristocratWay + path: Void + sideKnowledge: true stage: 3 event: !type:HereticAristocratWayEvent @@ -185,6 +193,8 @@ - type: hereticKnowledge id: VoidPhase + path: Void + sideKnowledge: true stage: 6 actionPrototypes: - ActionHereticVoidPhase @@ -196,6 +206,8 @@ - type: hereticKnowledge id: VoidPull + path: Void + sideKnowledge: true stage: 8 actionPrototypes: - ActionHereticVoidPull @@ -214,8 +226,15 @@ event: !type:HereticAscensionVoidEvent # side paths +- type: hereticKnowledge + id: RitualOfKnowledge + sideKnowledge: true + ritualPrototypes: + - RitualOfKnowledge + - type: hereticKnowledge id: ArmorerRitual + sideKnowledge: true stage: 3 ritualPrototypes: - ArmorerRitual diff --git a/Resources/Prototypes/ADT/Heretic/Heretic/heretic_rituals.yml b/Resources/Prototypes/ADT/Heretic/Heretic/heretic_rituals.yml index 6b503653915..d408c7c5c49 100644 --- a/Resources/Prototypes/ADT/Heretic/Heretic/heretic_rituals.yml +++ b/Resources/Prototypes/ADT/Heretic/Heretic/heretic_rituals.yml @@ -1,23 +1,49 @@ -# basic +### basic + +# Heartbeat of the Mansus (sacrifice) - type: hereticRitual id: Sacrifice name: heretic-ritual-basic-sacrifice + icon: + sprite: Mobs/Species/Human/organs.rsi + state: heart-on customBehaviors: - !type:RitualSacrificeBehavior + onlyTargets: true +# Amber Focus - type: hereticRitual id: AmberFocus name: heretic-ritual-basic-focus + icon: + sprite: ADT/Heretic/amber_focus.rsi + state: icon requiredTags: GlassShard: 1 Eyes: 1 output: ClothingNeckAmberFocus: 1 -# ash path +# Relentless Heartbeat (sacrifice target reroll) +- type: hereticRitual + id: LivingHeart + name: heretic-ritual-basic-heart + requiredTags: + Heart: 1 + Pen: 1 + Paper: 1 + outputEvent: !type:EventHereticRerollTargets + + + +### ash path + - type: hereticRitual id: BladeAsh name: heretic-ritual-ash-blade + icon: + sprite: ADT/Heretic/Blades/blade_ash.rsi + state: icon requiredTags: Knife: 1 Matchstick: 1 @@ -27,6 +53,9 @@ - type: hereticRitual id: MaskOfMadness name: heretic-ritual-ash-mask + icon: + sprite: ADT/Heretic/mad_mask.rsi + state: icon requiredTags: GasMask: 1 Candle: 4 @@ -37,6 +66,9 @@ - type: hereticRitual id: AscensionAsh name: heretic-ritual-ash-ascend + icon: + sprite: ADT/Heretic/abilities_heretic.rsi + state: ashlord_rite2 customBehaviors: - !type:RitualAshAscendBehavior min: 3 @@ -44,10 +76,16 @@ outputKnowledge: AshlordRite outputEvent: !type:EventHereticAscension -# flesh path + + +### flesh path + - type: hereticRitual id: BladeFlesh name: heretic-ritual-flesh-blade + icon: + sprite: ADT/Heretic/Blades/blade_flesh.rsi + state: icon customBehaviors: - !type:RitualReagentPuddleBehavior reagent: Blood @@ -59,14 +97,20 @@ - type: hereticRitual id: ImperfectRitual name: heretic-ritual-flesh-ghoul + icon: + sprite: Mobs/Species/Skeleton/parts.rsi + state: full customBehaviors: - !type:RitualMuteGhoulifyBehavior - requiredEntityNames: - poppy: 1 + requiredTags: + Poppy: 1 - type: hereticRitual id: RawRitual name: heretic-ritual-flesh-prophet + icon: + sprite: ADT/Heretic/eldritch_mobs.rsi + state: raw_prophet customBehaviors: - !type:RitualReagentPuddleBehavior reagent: Blood @@ -79,6 +123,9 @@ - type: hereticRitual id: LonelyRitual name: heretic-ritual-flesh-stalker + icon: + sprite: ADT/Heretic/eldritch_mobs.rsi + state: stalker customBehaviors: - !type:RitualReagentPuddleBehavior reagent: Blood @@ -93,6 +140,9 @@ - type: hereticRitual id: AscensionFlesh name: heretic-ritual-flesh-ascend + icon: + sprite: ADT/Heretic/abilities_heretic.rsi + state: final_hymn customBehaviors: - !type:RitualSacrificeBehavior min: 4 @@ -100,10 +150,16 @@ outputKnowledge: PriestFinalHymn outputEvent: !type:EventHereticAscension -# void path + + +### void path + - type: hereticRitual id: BladeVoid name: heretic-ritual-void-blade + icon: + sprite: ADT/Heretic/Blades/blade_void.rsi + state: icon customBehaviors: - !type:RitualTemperatureBehavior minThreshold: 0 # ~= -1 celcius. or sub zero temperatures @@ -115,6 +171,9 @@ - type: hereticRitual id: AscensionVoid name: heretic-ritual-void-ascend + icon: + sprite: Interface/Alerts/temperature.rsi + state: cold3 customBehaviors: - !type:RitualSacrificeBehavior min: 3 @@ -124,16 +183,25 @@ outputKnowledge: WaltzAtTheEndOfTime outputEvent: !type:EventHereticAscension -# side path + + +### side knowledge + - type: hereticRitual id: RitualOfKnowledge name: heretic-ritual-side-knowledge + icon: + sprite: Objects/Misc/books.rsi + state: book_icon customBehaviors: - !type:RitualKnowledgeBehavior - type: hereticRitual id: ArmorerRitual name: heretic-ritual-side-armor + icon: + sprite: ADT/Heretic/eldritch_armor.rsi + state: icon requiredTags: Table: 1 GasMask: 1 diff --git a/Resources/Prototypes/ADT/Heretic/radio_channels.yml b/Resources/Prototypes/ADT/Heretic/radio_channels.yml index 1ce51f47345..73f3afe0255 100644 --- a/Resources/Prototypes/ADT/Heretic/radio_channels.yml +++ b/Resources/Prototypes/ADT/Heretic/radio_channels.yml @@ -1,7 +1,7 @@ - type: radioChannel id: Mansus name: chat-radio-mansus - keycode: 'z' + keycode: 'з' frequency: 80085 color: "#237500" longRange: true \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml index cc7ed82bd9b..0f73d674734 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml @@ -202,6 +202,7 @@ tags: - ClownMask - WhitelistChameleon + - Mask # goob-edit - type: HideLayerClothing slots: - Snout diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index bec4dd73653..232f6e5a67f 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -199,6 +199,8 @@ # Goobstation - changelings & heretics enum.StoreUiKey.Key: type: StoreBoundUserInterface + enum.HereticLivingHeartKey.Key: # goob edit - heretics + type: LivingHeartMenuBoundUserInterface - type: Puller - type: Speech speechSounds: Alto diff --git a/Resources/Textures/ADT/Heretic/abilities_heretic.rsi/living_heart.png b/Resources/Textures/ADT/Heretic/abilities_heretic.rsi/living_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..d9c7a52e55488cb201a8821234007963fdc4e22c GIT binary patch literal 735 zcmV<50wDc~P)Px%nMp)JR9Hv7SHDkNF%Z6l{AdMKL6KUdpe`9;W8e=!3@nI&jS+QW0WmgX)PDh~ zI}B`y33chfU%-HvvsADkA))|kd4vR=-E;0a=h%Kkcu4Z{?7Q#2`|fP#U@-dZ_j~-z zp%e810Lpo>q960!q5;q=JdXtoxB2vtkj)%=RL)DavG@r#l3eSl3IIiJujZ)nosW&! z`OodX2Ee1A{_qLz|8)SrY2Y&-{2l+_Ugvvv+v;cl<*8E20Yz#@B=PHFC1fpXVTgg? zB#vPs>cD6K^C1nFK3wz3hEG?>oY6qFp3b+OV_O3fP+K#uXKpLSKrEv@UA<7~ruE~i z7ScwFf!H4K@(9rTt0Ct<>hFok*bo2=1H1}+wT_Xa^ZwKSMp7OC$(zRN24iWQ<+V7tR@7C3s0TH4FTqyPdvS{ax zM}IiC0$aN^XwEj24se{7?tp`^wIDI;tpcuCo__@JYjsC4u%65q+gt}O7J{lkLTfX? z=OBn5?TctFcp0#Pa1HF0>ag_rtC@0s^Ct!1r9D{9_XUvw-(J9V!I{AS5eN=m2~scM z!O*!uJP$~u3k&KPex4p}s0HNo>QMM?M%o-4x2)sXJ?gOLth^+5K4UjS4P8RD_sti*F)CVYUlxO=Hol3b4 z(S>BoXaEh{cLR2Ra|Ua#iD8B8r!J?lXTunWd@kJ!@gPM2R8z}pFylJq`xR