diff --git a/Content.Client/Chat/Managers/ChatManager.cs b/Content.Client/Chat/Managers/ChatManager.cs index 55e1b0a5c6..7120dd202f 100644 --- a/Content.Client/Chat/Managers/ChatManager.cs +++ b/Content.Client/Chat/Managers/ChatManager.cs @@ -1,5 +1,6 @@ using Content.Client.Administration.Managers; using Content.Client.Ghost; +using Content.Shared._White.Cult.Components; using Content.Shared.Administration; using Content.Shared.Changeling; using Content.Shared.Chat; @@ -54,7 +55,8 @@ namespace Content.Client.Chat.Managers case ChatSelectChannel.Cult: var localEnt = _player.LocalPlayer != null ? _player.LocalPlayer.ControlledEntity : null; - if (_entityManager.TryGetComponent(localEnt, out CultistComponent? comp)) + if (_entityManager.HasComponent(localEnt) || + _entityManager.HasComponent(localEnt)) _consoleHost.ExecuteCommand($"csay \"{CommandParsing.Escape(text)}\""); break; diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index b366449eee..1200fa0d96 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -20,6 +20,7 @@ using Content.Shared.Damage.ForceSay; using Content.Shared.Input; using Content.Shared.Radio; using Content.Shared._White; +using Content.Shared._White.Cult.Components; using Content.Shared._White.Utils; using Content.Shared._White.Cult.Systems; using Robust.Client.Graphics; @@ -235,8 +236,8 @@ public sealed class ChatUIController : UIController _input.SetInputCommand(ContentKeyFunctions.CycleChatChannelBackward, InputCmdHandler.FromDelegate(_ => CycleChatChannel(false))); - SubscribeLocalEvent(OnUpdateChangelingChat); // WD EDIT + SubscribeLocalEvent(OnUpdateChangelingChat); SubscribeLocalEvent(OnUpdateCultState); // WD EDIT END @@ -563,7 +564,7 @@ public sealed class ChatUIController : UIController // WD EDIT var localEnt = _player.LocalEntity; - if (_entities.HasComponent(localEnt)) + if (_entities.HasComponent(localEnt) || _entities.HasComponent(localEnt)) { FilterableChannels |= ChatChannel.Cult; CanSendChannels |= ChatSelectChannel.Cult; diff --git a/Content.Client/_White/Cult/ShowCultHudSystem.cs b/Content.Client/_White/Cult/ShowCultHudSystem.cs index 6c845f468d..5edccd14e0 100644 --- a/Content.Client/_White/Cult/ShowCultHudSystem.cs +++ b/Content.Client/_White/Cult/ShowCultHudSystem.cs @@ -1,5 +1,4 @@ -using Content.Shared._White.Cult; -using Content.Shared._White.Cult.Components; +using Content.Shared._White.Cult.Components; using Robust.Client.Graphics; using Robust.Client.Player; using Robust.Shared.Player; @@ -29,7 +28,7 @@ public sealed class ShowCultHudSystem : EntitySystem _overlay = new CultHudOverlay(EntityManager); } - private void OnComponentInit(EntityUid uid, ShowCultHudComponent component, ComponentInit args) + private void OnComponentInit(EntityUid uid, T component, ComponentInit args) { if (_player.LocalSession?.AttachedEntity != uid) return; @@ -38,7 +37,7 @@ public sealed class ShowCultHudSystem : EntitySystem } - private void OnComponentRemoved(EntityUid uid, ShowCultHudComponent component, ComponentRemove args) + private void OnComponentRemoved(EntityUid uid, T component, ComponentRemove args) { if (_player.LocalSession?.AttachedEntity != uid) return; @@ -47,7 +46,7 @@ public sealed class ShowCultHudSystem : EntitySystem } - private void OnPlayerAttached(EntityUid uid, ShowCultHudComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, T component, PlayerAttachedEvent args) { if (_player.LocalSession != args.Player) return; @@ -55,7 +54,7 @@ public sealed class ShowCultHudSystem : EntitySystem _overlayManager.AddOverlay(_overlay); } - private void OnPlayerDetached(EntityUid uid, ShowCultHudComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(EntityUid uid, T component, PlayerDetachedEvent args) { if (_player.LocalSession != args.Player) return; diff --git a/Content.Client/_White/Cult/UI/StructureRadial/CultPylonPlacementHijack.cs b/Content.Client/_White/Cult/UI/StructureRadial/CultPylonPlacementHijack.cs index bf3f349560..c6a12e6e0c 100644 --- a/Content.Client/_White/Cult/UI/StructureRadial/CultPylonPlacementHijack.cs +++ b/Content.Client/_White/Cult/UI/StructureRadial/CultPylonPlacementHijack.cs @@ -1,5 +1,6 @@ using System.Linq; using Content.Client.Construction; +using Content.Shared._White.Cult.Pylon; using Content.Shared.Construction.Prototypes; using Content.Shared.Popups; using Robust.Client.Placement; @@ -8,60 +9,33 @@ using Robust.Shared.Map; namespace Content.Client._White.Cult.UI.StructureRadial; -public sealed class CultPylonPlacementHijack : PlacementHijack +public sealed class CultPylonPlacementHijack(ConstructionPrototype? prototype, IEntityManager entMan, EntityUid player) + : PlacementHijack { - private readonly ConstructionSystem _constructionSystem; - private readonly IEntityManager _entMan; - private readonly ConstructionPrototype? _prototype; - private readonly EntityUid _player; + private readonly ConstructionSystem _constructionSystem = entMan.System(); - public override bool CanRotate { get; } - - public CultPylonPlacementHijack(ConstructionPrototype? prototype, IEntityManager entMan, EntityUid player) - { - _prototype = prototype; - _entMan = entMan; - _player = player; - _constructionSystem = entMan.System(); - CanRotate = prototype?.CanRotate ?? true; - } + public override bool CanRotate { get; } = prototype?.CanRotate ?? true; /// public override bool HijackPlacementRequest(EntityCoordinates coordinates) { - if (_prototype == null) + if (prototype == null) return true; - if (CheckForStructure(coordinates)) + if (SharedPylonComponent.CheckForStructure(coordinates, entMan, 10f)) { - var popup = _entMan.System(); - popup.PopupClient(Loc.GetString("cult-structure-craft-another-structure-nearby"), _player, _player); + var popup = entMan.System(); + popup.PopupClient(Loc.GetString("cult-structure-craft-another-structure-nearby"), player, player); return true; } _constructionSystem.ClearAllGhosts(); var dir = Manager.Direction; - _constructionSystem.SpawnGhost(_prototype, coordinates, dir); + _constructionSystem.SpawnGhost(prototype, coordinates, dir); return true; } - private bool CheckForStructure(EntityCoordinates coordinates) - { - var lookupSystem = _entMan.System(); - var entities = lookupSystem.GetEntitiesInRange(coordinates, 10f); - foreach (var ent in entities) - { - if (!_entMan.TryGetComponent(ent, out var metadata)) - continue; - - if (metadata.EntityPrototype?.ID is "CultPylon") - return true; - } - - return false; - } - /// public override bool HijackDeletion(EntityUid entity) { @@ -77,6 +51,6 @@ public sealed class CultPylonPlacementHijack : PlacementHijack public override void StartHijack(PlacementManager manager) { base.StartHijack(manager); - manager.CurrentTextures = _prototype?.Layers.Select(sprite => sprite.DirFrame0()).ToList(); + manager.CurrentTextures = prototype?.Layers.Select(sprite => sprite.DirFrame0()).ToList(); } } diff --git a/Content.Server/Chat/Commands/CultCommand.cs b/Content.Server/Chat/Commands/CultCommand.cs index d10fc376ee..35763c2f6c 100644 --- a/Content.Server/Chat/Commands/CultCommand.cs +++ b/Content.Server/Chat/Commands/CultCommand.cs @@ -1,6 +1,7 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; using Content.Shared._White.Cult; +using Content.Shared._White.Cult.Components; using Robust.Shared.Console; using Robust.Shared.Enums; using CultistComponent = Content.Shared._White.Cult.Components.CultistComponent; @@ -35,7 +36,8 @@ namespace Content.Server.Chat.Commands var entityManager = IoCManager.Resolve(); - if (!entityManager.HasComponent(entity)) + if (!entityManager.HasComponent(entity) && + !entityManager.HasComponent(entity)) { return; } diff --git a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs index 7447271526..4183ae243d 100644 --- a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs +++ b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs @@ -3,6 +3,7 @@ using Content.Server.Damage.Components; using Content.Server.Weapons.Ranged.Systems; using Content.Shared.Camera; using Content.Server._White.Crossbow; +using Content.Shared._White.Cult.Systems; using Content.Shared.Damage; using Content.Shared.Damage.Events; using Content.Shared.Damage.Systems; @@ -30,7 +31,8 @@ namespace Content.Server.Damage.Systems public override void Initialize() { SubscribeLocalEvent(OnDoHit, - before: new[] {typeof(MeleeThrowOnHitSystem)}); // WD EDIT + before: new[] {typeof(MeleeThrowOnHitSystem)}, + after: new[] {typeof(BloodSpearSystem)}); // WD EDIT SubscribeLocalEvent(OnDamageExamine); } diff --git a/Content.Server/_White/Cult/GameRule/CultRuleComponent.cs b/Content.Server/_White/Cult/GameRule/CultRuleComponent.cs index e16d943501..e253305772 100644 --- a/Content.Server/_White/Cult/GameRule/CultRuleComponent.cs +++ b/Content.Server/_White/Cult/GameRule/CultRuleComponent.cs @@ -50,6 +50,8 @@ public sealed partial class CultRuleComponent : Component public List Constructs = new(); public CultWinCondition WinCondition = CultWinCondition.Draw; + + public CultStage Stage = CultStage.Normal; } public enum CultWinCondition : byte @@ -59,4 +61,11 @@ public enum CultWinCondition : byte Failure, } +public enum CultStage : byte +{ + Normal, + RedEyes, + Pentagram, +} + public sealed class CultNarsieSummoned : EntityEventArgs; diff --git a/Content.Server/_White/Cult/GameRule/CultRuleSystem.cs b/Content.Server/_White/Cult/GameRule/CultRuleSystem.cs index 4ad0a2047a..5ba8bb2e3c 100644 --- a/Content.Server/_White/Cult/GameRule/CultRuleSystem.cs +++ b/Content.Server/_White/Cult/GameRule/CultRuleSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Bible.Components; using Content.Server.GameTicking; using Content.Server.GameTicking.Rules; using Content.Server.GameTicking.Rules.Components; +using Content.Server.Hands.Systems; using Content.Server.Objectives.Components; using Content.Server.Roles; using Content.Server.RoundEnd; @@ -53,6 +54,7 @@ public sealed class CultRuleSystem : GameRuleSystem [Dependency] private readonly GulagSystem _gulag = default!; [Dependency] private readonly BloodSpearSystem _bloodSpear = default!; [Dependency] private readonly ContainerSystem _container = default!; + [Dependency] private readonly HandsSystem _hands = default!; private const int PlayerPerCultist = 10; private int _minStartingCultists; @@ -175,6 +177,8 @@ public sealed class CultRuleSystem : GameRuleSystem if (TryComp(uid, out var actor)) { cult.CultistsCache.TryAdd(name, actor.PlayerSession.Name); + _mindSystem.TryGetMind(actor.PlayerSession.UserId, out var mind); + component.OriginalMind = mind; } UpdateCultistsAppearance(cult); @@ -339,7 +343,12 @@ public sealed class CultRuleSystem : GameRuleSystem var cultistsCount = cultRuleComponent.CurrentCultists.Count; var constructsCount = cultRuleComponent.Constructs.Count; var totalCultMembers = cultistsCount + constructsCount; - if (totalCultMembers < cultRuleComponent.ReadEyeThreshold) + if (totalCultMembers >= cultRuleComponent.PentagramThreshold) + cultRuleComponent.Stage = CultStage.Pentagram; + else if (totalCultMembers >= cultRuleComponent.ReadEyeThreshold && cultRuleComponent.Stage == CultStage.Normal) + cultRuleComponent.Stage = CultStage.RedEyes; + + if (cultRuleComponent.Stage == CultStage.Normal) return; foreach (var cultistComponent in cultRuleComponent.CurrentCultists) @@ -350,7 +359,7 @@ public sealed class CultRuleSystem : GameRuleSystem Dirty(cultistComponent.Owner, appearanceComponent); } - if (totalCultMembers < cultRuleComponent.PentagramThreshold) + if (cultRuleComponent.Stage != CultStage.Pentagram) return; EnsureComp(cultistComponent.Owner); @@ -458,6 +467,13 @@ public sealed class CultRuleSystem : GameRuleSystem _container.Remove(container.ContainedEntity.Value, container, true, true); } } + + foreach (var item in _hands.EnumerateHeld(uid)) + { + if (TryComp(item, out CultItemComponent? cultItem) && !cultItem.CanPickUp && + !_hands.TryDrop(uid, item, null, false, false)) + QueueDel(item); + } } public void TransferRole(EntityUid transferFrom, EntityUid transferTo) diff --git a/Content.Server/_White/Cult/Items/Components/CultStunHandComponent.cs b/Content.Server/_White/Cult/Items/Components/CultStunHandComponent.cs new file mode 100644 index 0000000000..e7e43a730e --- /dev/null +++ b/Content.Server/_White/Cult/Items/Components/CultStunHandComponent.cs @@ -0,0 +1,20 @@ +namespace Content.Server._White.Cult.Items.Components; + +[RegisterComponent] +public sealed partial class CultStunHandComponent : Component +{ + [DataField] + public TimeSpan Duration = TimeSpan.FromSeconds(16); + + [DataField] + public TimeSpan HaloDuration = TimeSpan.FromSeconds(1.5); + + [DataField] + public TimeSpan MuteDuration = TimeSpan.FromSeconds(12); + + [DataField] + public TimeSpan HaloMuteDuration = TimeSpan.FromSeconds(1); + + [DataField] + public string Speech = "Fuu ma'jin!"; +} diff --git a/Content.Server/_White/Cult/Items/Systems/CultStunHandSystem.cs b/Content.Server/_White/Cult/Items/Systems/CultStunHandSystem.cs new file mode 100644 index 0000000000..57b4006d7a --- /dev/null +++ b/Content.Server/_White/Cult/Items/Systems/CultStunHandSystem.cs @@ -0,0 +1,56 @@ +using Content.Server._White.Cult.Items.Components; +using Content.Server.Body.Components; +using Content.Server.Body.Systems; +using Content.Server.Chat.Systems; +using Content.Server.Popups; +using Content.Server.Stunnable; +using Content.Shared._White.Chaplain; +using Content.Shared.Popups; +using Content.Shared.StatusEffect; +using Content.Shared.Weapons.Melee.Events; + +namespace Content.Server._White.Cult.Items.Systems; + +public sealed class CultStunHandSystem : EntitySystem +{ + [Dependency] private readonly StunSystem _stun = default!; + [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly HolyWeaponSystem _holyWeapon = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly BloodstreamSystem _bloodstream = default!; + [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHit); + } + + private void OnHit(Entity ent, ref MeleeHitEvent args) + { + if (args.HitEntities.Count == 0) + return; + + var target = args.HitEntities[0]; + var (uid, comp) = ent; + + QueueDel(uid); + Spawn("CultStunFlashEffect", Transform(target).Coordinates); + _chat.TrySendInGameICMessage(args.User, comp.Speech, InGameICChatType.Whisper, false); + if (TryComp(args.User, out BloodstreamComponent? bloodstream)) + _bloodstream.TryModifyBloodLevel(args.User, -10, bloodstream, createPuddle: false); + + if (_holyWeapon.IsHoldingHolyWeapon(target)) + { + _popupSystem.PopupEntity(Loc.GetString("cult-magic-holy"), args.User, args.User, PopupType.MediumCaution); + return; + } + + var halo = HasComp(args.User); + + _statusEffects.TryAddStatusEffect(target, "Muted", halo ? comp.HaloMuteDuration : comp.MuteDuration, true, + "Muted"); + _stun.TryParalyze(target, halo ? comp.HaloDuration : comp.Duration, true); + } +} diff --git a/Content.Server/_White/Cult/Pylon/PylonSystem.cs b/Content.Server/_White/Cult/Pylon/PylonSystem.cs index 1673a4ca90..4f47481227 100644 --- a/Content.Server/_White/Cult/Pylon/PylonSystem.cs +++ b/Content.Server/_White/Cult/Pylon/PylonSystem.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Numerics; using Content.Server.Atmos.Piping.Other.Components; using Content.Server.Body.Components; @@ -61,6 +61,15 @@ public sealed class PylonSystem : EntitySystem private void OnInit(EntityUid uid, SharedPylonComponent component, ComponentInit args) { + var coords = Transform(uid).Coordinates; + if (SharedPylonComponent.CheckForStructure(coords, EntityManager, 9f, uid)) + { + QueueDel(uid); + _popupSystem.PopupCoordinates(Loc.GetString("cult-structure-craft-another-structure-nearby"), + coords, PopupType.MediumCaution); + Spawn("CultRunicMetal4", coords); + return; + } UpdateAppearance(uid, component); } diff --git a/Content.Server/_White/Cult/Runes/Comps/CultRuneBaseComponent.cs b/Content.Server/_White/Cult/Runes/Comps/CultRuneBaseComponent.cs index 5e26945c34..5164b5ff43 100644 --- a/Content.Server/_White/Cult/Runes/Comps/CultRuneBaseComponent.cs +++ b/Content.Server/_White/Cult/Runes/Comps/CultRuneBaseComponent.cs @@ -1,3 +1,5 @@ +using Content.Server.Chat.Systems; + namespace Content.Server._White.Cult.Runes.Comps; [RegisterComponent] @@ -14,4 +16,7 @@ public sealed partial class CultRuneBaseComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("invokePhrase")] public string InvokePhrase = ""; + + [DataField] + public InGameICChatType InvokeChatType = InGameICChatType.Whisper; } diff --git a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs index 6004d21a1b..4e900eaae4 100644 --- a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs +++ b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs @@ -5,6 +5,8 @@ using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Emp; using Content.Server.EUI; using Content.Server._White.Cult.UI; +using Content.Server._White.Wizard.Magic; +using Content.Server.Chat.Systems; using Content.Shared._White.Chaplain; using Content.Shared.Chemistry.Components; using Content.Shared.Damage; @@ -50,6 +52,7 @@ public partial class CultSystem [Dependency] private readonly PhysicsSystem _physics = default!; [Dependency] private readonly HolyWeaponSystem _holyWeapon = default!; [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; + [Dependency] private readonly WizardSpellsSystem _spells = default!; private const string TileId = "CultFloor"; private const string ConcealedTileId = "CultFloorConcealed"; @@ -66,7 +69,7 @@ public partial class CultSystem SubscribeLocalEvent(OnBloodRites); SubscribeLocalEvent(OnBloodSpearRecall); SubscribeLocalEvent(OnTeleport); - SubscribeLocalEvent(OnStunTarget); + SubscribeLocalEvent(OnStun); SubscribeLocalEvent(OnActionRemoved); SubscribeLocalEvent(OnShackles); } @@ -84,6 +87,11 @@ public partial class CultSystem if (_cuffable.TryAddNewCuffs(args.Target.Value, args.User, cuffs, cuffable, handcuffComponent)) { SharedCuffableSystem.SetUsed(handcuffComponent, true); + if (_statusEffectsSystem.TryAddStatusEffect(args.Target.Value, "Muted", TimeSpan.FromSeconds(10), + true, "Muted")) + { + _popupSystem.PopupEntity("Цель обезмолвлена.", args.User, args.User); + } return; } @@ -96,32 +104,16 @@ public partial class CultSystem Dirty(ent); } - private void OnStunTarget(EntityUid uid, CultistComponent component, CultStunTargetActionEvent args) + private void OnStun(EntityUid uid, CultistComponent component, CultStunActionEvent args) { - if (args.Target == uid || !TryComp(args.Performer, out var bloodstream) || - !TryComp(args.Target, out var status)) - return; - - if (_holyWeapon.IsHoldingHolyWeapon(args.Target)) + var entity = Spawn("StunHand", Transform(uid).Coordinates); + if (!_handsSystem.TryPickupAnyHand(uid, entity)) { - _popupSystem.PopupEntity("Сила священного оружия препятствует магии.", args.Performer, args.Performer, - PopupType.MediumCaution); + _popupSystem.PopupEntity(Loc.GetString("cult-magic-no-empty-hand"), uid, uid); + QueueDel(entity); + _actionsSystem.SetCooldown(args.Action, TimeSpan.FromSeconds(1)); return; } - - if (HasComp(args.Target)) - { - _popupSystem.PopupEntity("Он имплантирован чипом защиты разума.", args.Performer, args.Performer, - PopupType.MediumCaution); - return; - } - - if (!_stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(6), true, status) & - !_statusEffectsSystem.TryAddStatusEffect(args.Target, "Muted", TimeSpan.FromSeconds(12), true, "Muted", - status)) - return; - - _bloodstreamSystem.TryModifyBloodLevel(uid, -10, bloodstream, createPuddle: false); args.Handled = true; } @@ -133,7 +125,7 @@ public partial class CultSystem if (_holyWeapon.IsHoldingHolyWeapon(args.Target)) { - _popupSystem.PopupEntity("Сила священного оружия препятствует магии.", args.Performer, args.Performer, + _popupSystem.PopupEntity(Loc.GetString("cult-magic-holy"), args.Performer, args.Performer, PopupType.MediumCaution); return; } @@ -152,6 +144,7 @@ public partial class CultSystem _euiManager.OpenEui(eui, actor.PlayerSession); eui.StateDirty(); + Speak(args); args.Handled = true; } @@ -210,6 +203,7 @@ public partial class CultSystem _popupSystem.PopupEntity(Loc.GetString("verb-blood-rites-message", ("blood", component.RitesBloodAmount)), uid, uid); + Speak(args); args.Handled = true; } @@ -342,6 +336,7 @@ public partial class CultSystem _audio.PlayPvs(conceal ? "/Audio/White/Cult/smoke.ogg" : "/Audio/White/Cult/enter_blood.ogg", uid, AudioParams.Default.WithMaxDistance(5f)); _bloodstreamSystem.TryModifyBloodLevel(uid, -2, bloodstream, createPuddle: false); + Speak(args); args.Handled = true; } @@ -420,6 +415,7 @@ public partial class CultSystem _empSystem.EmpPulse(_transform.GetMapCoordinates(uid), 5, 100000, 10f); + Speak(args); args.Handled = true; } @@ -430,13 +426,6 @@ public partial class CultSystem _bloodstreamSystem.TryModifyBloodLevel(uid, -5, bloodstream, createPuddle: false); - if (!_holyWeapon.IsHoldingHolyWeapon(args.Target) && - _statusEffectsSystem.TryAddStatusEffect(args.Target, "Muted", TimeSpan.FromSeconds(10), true, "Muted")) - { - _popupSystem.PopupEntity("Цель обезмолвлена.", args.Performer, args.Performer); - args.Handled = true; - } - if (!TryComp(args.Target, out CuffableComponent? cuffs) || cuffs.Container.ContainedEntities.Count > 0) return; @@ -447,6 +436,7 @@ public partial class CultSystem BreakOnDamage = true }); + Speak(args); args.Handled = true; } @@ -482,6 +472,7 @@ public partial class CultSystem stackNew.Count = count; _popupSystem.PopupEntity("Конвертируем сталь в руинический металл!", args.Performer, args.Performer); + Speak(args); args.Handled = true; } @@ -498,6 +489,12 @@ public partial class CultSystem _bloodstreamSystem.TryModifyBloodLevel(args.Performer, -10, bloodstreamComponent, false); _handsSystem.TryPickupAnyHand(args.Performer, dagger); + Speak(args); args.Handled = true; } + + private void Speak(BaseActionEvent args) + { + _spells.Speak(args, InGameICChatType.Whisper); + } } diff --git a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Rune.cs b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Rune.cs index 919974f7d5..1c5ceb6e7e 100644 --- a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Rune.cs +++ b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Rune.cs @@ -16,6 +16,7 @@ using Content.Server.Chemistry.Components; using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.Components; using Content.Server.Ghost; +using Content.Server.Pinpointer; using Content.Server.Revenant.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Cuffs.Components; @@ -51,6 +52,7 @@ using Robust.Shared.Map; using Robust.Shared.Physics.Events; using Robust.Shared.Player; using Robust.Shared.Random; +using Robust.Shared.Utility; using CultistComponent = Content.Shared._White.Cult.Components.CultistComponent; namespace Content.Server._White.Cult.Runes.Systems; @@ -77,6 +79,7 @@ public sealed partial class CultSystem : EntitySystem [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly MobThresholdSystem _thresholdSystem = default!; + [Dependency] private readonly NavMapSystem _navMap = default!; public override void Initialize() { @@ -404,7 +407,7 @@ public sealed partial class CultSystem : EntitySystem foreach (var cultist in cultists) { - _chat.TrySendInGameICMessage(cultist, component.InvokePhrase, InGameICChatType.Speak, false, false, null, + _chat.TrySendInGameICMessage(cultist, component.InvokePhrase, component.InvokeChatType, false, false, null, null, null, false); } } @@ -1347,11 +1350,8 @@ public sealed partial class CultSystem : EntitySystem } damage = 40; - var pos = _transform.GetMapCoordinates(uid, transComp); - var x = (int) pos.X; - var y = (int) pos.Y; - var posText = $"(x = {x}, y = {y})"; - _chat.DispatchGlobalAnnouncement(Loc.GetString("cult-narsie-summon-drawn-position", ("posText", posText)), + _chat.DispatchGlobalAnnouncement(Loc.GetString("cult-narsie-summon-drawn-position", + ("location", FormattedMessage.RemoveMarkup(_navMap.GetNearestBeaconString((uid, transComp))))), "CULT", true, _apocRuneEndDrawing, colorOverride: Color.DarkRed); } diff --git a/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs b/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs index e648bcdf94..a08f8af110 100644 --- a/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs +++ b/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs @@ -174,6 +174,12 @@ public sealed class WizardSpellsSystem : EntitySystem return; } + if (HasComp(target)) + { + _popupSystem.PopupEntity(Loc.GetString("mindswap-cultist-failed"), uid, uid, PopupType.MediumCaution); + return; + } + var userHasMind = _mindSystem.TryGetMind(uid, out var mindId, out var mind); var targetHasMind = _mindSystem.TryGetMind(target, out var targetMindId, out var targetMind); @@ -183,8 +189,6 @@ public sealed class WizardSpellsSystem : EntitySystem SwapComponent(uid, target); SwapComponent(uid, target); SwapComponent(uid, target); - SwapComponent(uid, target); - SwapComponent(uid, target); SwapComponent(uid, target); _mindSystem.TransferTo(mindId, target, mind: mind); @@ -854,13 +858,12 @@ public sealed class WizardSpellsSystem : EntitySystem !_statusEffectsSystem.HasStatusEffect(msg.Performer, "Incorporeal"); } - private void Speak(BaseActionEvent args) + public void Speak(BaseActionEvent args, InGameICChatType type = InGameICChatType.Speak) { if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech)) return; - _chat.TrySendInGameICMessage(args.Performer, Loc.GetString(speak.Speech), - InGameICChatType.Speak, false); + _chat.TrySendInGameICMessage(args.Performer, Loc.GetString(speak.Speech), type, false); } private void SetCooldown(EntityUid action, ActionUseType useType) diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs index 3a8f086ba2..e2cb96fe65 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs @@ -101,7 +101,7 @@ public abstract partial class SharedHandsSystem : EntitySystem if (TryComp(session?.AttachedEntity, out HandsComponent? hands) && hands.ActiveHand != null) // WD EDIT START { - if (HasComp(hands.ActiveHandEntity)) + if (HasComp(hands.ActiveHandEntity)) { if (_net.IsServer) QueueDel(hands.ActiveHandEntity.Value); diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index ba54be37b7..5fe5c7b208 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -116,6 +116,9 @@ public abstract partial class SharedProjectileSystem : EntitySystem return; // WD START + if (args.Handled) + return; + if (component is {Penetrate: true, PenetratedUid: null} && TryComp(args.Target, out PenetratedComponent? penetrated) && penetrated is {ProjectileUid: null, IsPinned: false} && diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs index ca1e074944..c19cc5edfa 100644 --- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs +++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.Damage; using Content.Shared.FixedPoint; +using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -62,19 +63,31 @@ public sealed partial class MeleeWeaponComponent : Component public bool Attacking = false; // WD START - [ViewVariables(VVAccess.ReadWrite), DataField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public bool CanHeavyAttack = true; - [ViewVariables(VVAccess.ReadWrite), DataField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public bool CanAttackSelf = true; + + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public bool CanMiss = true; + + [DataField] + public EntityWhitelist? AttackWhitelist; + + [DataField] + public EntityWhitelist? AttackBlacklist; + + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public bool IgnoreResistances; - [ViewVariables(VVAccess.ReadWrite), DataField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float HeavyAttackStaminaCost = 8; - [ViewVariables(VVAccess.ReadWrite), DataField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public EntProtoId MissAnimation = "WeaponArcPunch"; - [ViewVariables(VVAccess.ReadWrite), DataField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public EntProtoId DisarmAnimation = "WeaponArcDisarm"; // WD END diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index 29772d804d..85e6edfa49 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -365,6 +365,30 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem if (weaponUid == lightTarget) return false; + // WD START + if (user == lightTarget && !weapon.CanAttackSelf) + return false; + + if (lightTarget == null) + { + if (weapon.CanMiss) + break; + return false; + } + + if (weapon.AttackWhitelist != null) + { + if (!weapon.AttackWhitelist.IsValid(lightTarget.Value, EntityManager)) + return false; + } + + if (weapon.AttackBlacklist != null) + { + if (weapon.AttackBlacklist.IsValid(lightTarget.Value, EntityManager)) + return false; + } + // WD END + break; case DisarmAttackEvent disarm: var disarmTarget = GetEntity(disarm.Target); diff --git a/Content.Shared/_White/Cult/Actions/CultActions.cs b/Content.Shared/_White/Cult/Actions/CultActions.cs index b3924e0046..eedcf82029 100644 --- a/Content.Shared/_White/Cult/Actions/CultActions.cs +++ b/Content.Shared/_White/Cult/Actions/CultActions.cs @@ -1,29 +1,40 @@ using Content.Shared.Actions; +using Content.Shared.Magic; namespace Content.Shared._White.Cult.Actions; -public sealed partial class CultTwistedConstructionActionEvent : EntityTargetActionEvent +public sealed partial class CultTwistedConstructionActionEvent : EntityTargetActionEvent, ISpeakSpell +{ + [DataField("speech")] + public string? Speech { get; private set; } +} + +public sealed partial class CultSummonDaggerActionEvent : InstantActionEvent, ISpeakSpell +{ + [DataField("speech")] + public string? Speech { get; private set; } +} + +public sealed partial class CultStunActionEvent : InstantActionEvent { } -public sealed partial class CultSummonDaggerActionEvent : InstantActionEvent +public sealed partial class CultTeleportTargetActionEvent : EntityTargetActionEvent, ISpeakSpell { + [DataField("speech")] + public string? Speech { get; private set; } } -public sealed partial class CultStunTargetActionEvent : EntityTargetActionEvent +public sealed partial class CultElectromagneticPulseInstantActionEvent : InstantActionEvent, ISpeakSpell { + [DataField("speech")] + public string? Speech { get; private set; } } -public sealed partial class CultTeleportTargetActionEvent : EntityTargetActionEvent -{ -} - -public sealed partial class CultElectromagneticPulseInstantActionEvent : InstantActionEvent -{ -} - -public sealed partial class CultShadowShacklesTargetActionEvent : EntityTargetActionEvent +public sealed partial class CultShadowShacklesTargetActionEvent : EntityTargetActionEvent, ISpeakSpell { + [DataField("speech")] + public string? Speech { get; private set; } } public sealed partial class CultSummonCombatEquipmentTargetActionEvent : EntityTargetActionEvent @@ -31,8 +42,10 @@ public sealed partial class CultSummonCombatEquipmentTargetActionEvent : EntityT } [Virtual] -public partial class CultConcealPresenceInstantActionEvent : InstantActionEvent +public partial class CultConcealPresenceInstantActionEvent : InstantActionEvent, ISpeakSpell { + [DataField("speech")] + public string? Speech { get; private set; } } public sealed partial class CultConcealInstantActionEvent : CultConcealPresenceInstantActionEvent @@ -43,8 +56,10 @@ public sealed partial class CultRevealInstantActionEvent : CultConcealPresenceIn { } -public sealed partial class CultBloodRitesInstantActionEvent : InstantActionEvent +public sealed partial class CultBloodRitesInstantActionEvent : InstantActionEvent, ISpeakSpell { + [DataField("speech")] + public string? Speech { get; private set; } } public sealed partial class CultBloodSpearRecallInstantActionEvent : InstantActionEvent diff --git a/Content.Shared/_White/Cult/Components/CultistComponent.cs b/Content.Shared/_White/Cult/Components/CultistComponent.cs index 758c61cd1c..a61f3a5f83 100644 --- a/Content.Shared/_White/Cult/Components/CultistComponent.cs +++ b/Content.Shared/_White/Cult/Components/CultistComponent.cs @@ -11,7 +11,7 @@ namespace Content.Shared._White.Cult.Components; /// This is used for tagging a mob as a cultist. /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class CultistComponent : ShowCultHudComponent +public sealed partial class CultistComponent : Component { [DataField("greetSound", customTypeSerializer: typeof(SoundSpecifierTypeSerializer))] public SoundSpecifier? CultistGreetSound = new SoundPathSpecifier("/Audio/CultSounds/fart.ogg"); @@ -41,7 +41,7 @@ public sealed partial class CultistComponent : ShowCultHudComponent public static string CultSummonCombatEquipmentAction = "ActionCultSummonCombatEquipment"; - public static string CultStunAction = "ActionCultStun"; + public static string CultStunAction = "InstantActionCultStun"; public static string CultShadowShacklesAction = "ActionCultShadowShackles"; diff --git a/Content.Shared/_White/Cult/Components/DeleteOnDropAttemptComponent.cs b/Content.Shared/_White/Cult/Components/DeleteOnDropAttemptComponent.cs new file mode 100644 index 0000000000..c6609123a2 --- /dev/null +++ b/Content.Shared/_White/Cult/Components/DeleteOnDropAttemptComponent.cs @@ -0,0 +1,8 @@ +namespace Content.Shared._White.Cult.Components; + +[RegisterComponent] +public sealed partial class DeleteOnDropAttemptComponent : Component +{ + [DataField] + public string Message = string.Empty; +} diff --git a/Content.Shared/_White/Cult/Pylon/SharedPylonComponent.cs b/Content.Shared/_White/Cult/Pylon/SharedPylonComponent.cs index 53964dd247..ab8597ae54 100644 --- a/Content.Shared/_White/Cult/Pylon/SharedPylonComponent.cs +++ b/Content.Shared/_White/Cult/Pylon/SharedPylonComponent.cs @@ -1,5 +1,6 @@ -using Content.Shared.Damage; +using Content.Shared.Damage; using Robust.Shared.Audio; +using Robust.Shared.Map; using Robust.Shared.Serialization; namespace Content.Shared._White.Cult.Pylon; @@ -64,6 +65,25 @@ public sealed partial class SharedPylonComponent : Component [DataField("wallConvertEffect")] public string WallConvertEffect = "CultWallGlow"; + + public static bool CheckForStructure(EntityCoordinates coordinates, IEntityManager entMan, float range, EntityUid? pylon = null) + { + var lookupSystem = entMan.System(); + var entities = lookupSystem.GetEntitiesInRange(coordinates, range); + foreach (var ent in entities) + { + if (ent == pylon) + continue; + + if (!entMan.TryGetComponent(ent, out var metadata)) + continue; + + if (metadata.EntityPrototype?.ID is "CultPylon") + return true; + } + + return false; + } } [Serializable, NetSerializable] diff --git a/Content.Shared/_White/Cult/Systems/BloodSpearSystem.cs b/Content.Shared/_White/Cult/Systems/BloodSpearSystem.cs index 35be109b81..523e8b576d 100644 --- a/Content.Shared/_White/Cult/Systems/BloodSpearSystem.cs +++ b/Content.Shared/_White/Cult/Systems/BloodSpearSystem.cs @@ -1,7 +1,9 @@ +using Content.Shared._White.Chaplain; using Content.Shared._White.Cult.Components; using Content.Shared.Actions; using Content.Shared.Examine; using Content.Shared.Hands; +using Content.Shared.Projectiles; using Content.Shared.StatusEffect; using Content.Shared.Stunnable; using Content.Shared.Throwing; @@ -15,6 +17,7 @@ public sealed class BloodSpearSystem : EntitySystem [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly HolyWeaponSystem _holy = default!; [Dependency] private readonly INetManager _net = default!; public override void Initialize() @@ -23,7 +26,8 @@ public sealed class BloodSpearSystem : EntitySystem SubscribeLocalEvent(OnRemove); SubscribeLocalEvent(OnEquip); - SubscribeLocalEvent(OnThrowDoHit); + SubscribeLocalEvent(OnThrowDoHit, + before: new[] {typeof(SharedProjectileSystem)}); SubscribeLocalEvent(OnExamine); } @@ -34,11 +38,20 @@ public sealed class BloodSpearSystem : EntitySystem private void OnThrowDoHit(Entity ent, ref ThrowDoHitEvent args) { + if (HasComp(args.Target) || HasComp(args.Target)) + { + args.Handled = true; + return; + } + if (!TryComp(args.Target, out StatusEffectsComponent? status)) return; - if(!_stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(6), true, status)) - return; + if (!_holy.IsHoldingHolyWeapon(args.Target)) + { + if(!_stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(4), true, status)) + return; + } if (_net.IsClient) return; diff --git a/Content.Shared/_White/Cult/Systems/CultistSystem.cs b/Content.Shared/_White/Cult/Systems/CultistSystem.cs index 57dc4661cf..12a8e1e387 100644 --- a/Content.Shared/_White/Cult/Systems/CultistSystem.cs +++ b/Content.Shared/_White/Cult/Systems/CultistSystem.cs @@ -1,3 +1,5 @@ +using Content.Shared._White.Cult.Components; + namespace Content.Shared._White.Cult.Systems; /// @@ -9,16 +11,18 @@ public sealed class CultistSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnRemove); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnRemove); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnRemove); } - private void OnInit(EntityUid uid, Components.CultistComponent component, ComponentStartup args) + private void OnInit(EntityUid uid, T component, ComponentStartup args) { RaiseLocalEvent(new EventCultistComponentState(true)); } - private void OnRemove(EntityUid uid, Components.CultistComponent component, ComponentShutdown args) + private void OnRemove(EntityUid uid, T component, ComponentShutdown args) { RaiseLocalEvent(new EventCultistComponentState(false)); } diff --git a/Content.Shared/_White/Cult/Systems/DeleteOnDropAttemptSystem.cs b/Content.Shared/_White/Cult/Systems/DeleteOnDropAttemptSystem.cs new file mode 100644 index 0000000000..ab6b419e12 --- /dev/null +++ b/Content.Shared/_White/Cult/Systems/DeleteOnDropAttemptSystem.cs @@ -0,0 +1,19 @@ +using Content.Shared._White.Cult.Components; +using Content.Shared.Examine; + +namespace Content.Shared._White.Cult.Systems; + +public sealed class DeleteOnDropAttemptSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnExamine); + } + + private void OnExamine(Entity ent, ref ExaminedEvent args) + { + args.PushMarkup(Loc.GetString(ent.Comp.Message)); + } +} diff --git a/Resources/Locale/ru-RU/_white/cult/abilities.ftl b/Resources/Locale/ru-RU/_white/cult/abilities.ftl index fa6414e8fa..11f07a834f 100644 --- a/Resources/Locale/ru-RU/_white/cult/abilities.ftl +++ b/Resources/Locale/ru-RU/_white/cult/abilities.ftl @@ -34,8 +34,8 @@ ent-InstantActionSummonCultDagger = Призыв Ритуального Кинж ent-InstantActionBloodRites = Кровавые Обряды .desc = Высасывает кровь и исцеляет вас. -ent-ActionCultStun = Оглушение - .desc = Сильное заклинание, которое оглушает и обезмолвливает жертв. Не работает на цели со священным оружием в руках или с чипом защиты разума. +ent-InstantActionCultStun = Оглушение + .desc = Сильное заклинание, которое оглушает и обезмолвливает жертв. Не работает на цели со священным оружием в руках. При наличии пентаграммы над головой эффект сильно ослабевает. ent-ActionCultShadowShackles = Теневые Узы .desc = Бесшумное заклинание, которое наложит на человека теневые наручники и заставит вашу жертву замолчать на 10 секунд. diff --git a/Resources/Locale/ru-RU/_white/cult/bolt-barrage.ftl b/Resources/Locale/ru-RU/_white/cult/bolt-barrage.ftl index 0aa68a47a8..4812e36b20 100644 --- a/Resources/Locale/ru-RU/_white/cult/bolt-barrage.ftl +++ b/Resources/Locale/ru-RU/_white/cult/bolt-barrage.ftl @@ -1,3 +1,4 @@ bolt-barrage-component-no-empty-hand = Вам нужно иметь свободную руку, чтобы стрелять. bolt-barrage-component-not-cultist = Вы не умеете пользоваться магией. -bolt-barrage-component-extra-desc = [color=darkgray]Для стрельбы залпом необходимо иметь свободную руку. Вобросите залп, чтобы навсегда избавиться от него.[/color] +bolt-barrage-component-extra-desc = [color=darkgray]Для стрельбы залпом необходимо иметь свободную руку.[/color] +bolt-barrage-component-extra-message = [color=darkgray]Выбросите залп, чтобы навсегда избавиться от него.[/color] diff --git a/Resources/Locale/ru-RU/_white/cult/cult.ftl b/Resources/Locale/ru-RU/_white/cult/cult.ftl index ff9eb49c64..3b0b78375e 100644 --- a/Resources/Locale/ru-RU/_white/cult/cult.ftl +++ b/Resources/Locale/ru-RU/_white/cult/cult.ftl @@ -32,7 +32,7 @@ cult-blood-boil-rune-need-minimum = Необходимо минимум 3 кул cult-blood-boil-rune-no-blood = Кому-то из культистов не хватает крови. cult-blood-boil-rune-no-targets = Нет целей. cult-teleport-rune-default-label = безымянная метка -cult-narsie-summon-drawn-position = Культ закончил рисовать руну ритуала разрыва измерений! Координаты: { $posText } +cult-narsie-summon-drawn-position = Культ закончил рисовать руну ритуала разрыва измерений! Локация: { $location } cult-cant-draw-rune = Нельзя рисовать руну в космосе. runes-window-title = Руны diff --git a/Resources/Locale/ru-RU/_white/cult/entities.ftl b/Resources/Locale/ru-RU/_white/cult/entities.ftl index 81c08d879e..1c16bb87ab 100644 --- a/Resources/Locale/ru-RU/_white/cult/entities.ftl +++ b/Resources/Locale/ru-RU/_white/cult/entities.ftl @@ -5,11 +5,11 @@ ent-SoulShardGhost = камень душ .desc = Мистический светящийся осколок. .suffix = Роль призраков -ent-WetStone = точильный камень - .desc = Используется для заточки кромок стальных инструментов. +ent-StunHand = оглушающая аура + .desc = Оглушит и обезмолвит жертву при ударе. -ent-CultSharpener = древний точильный камень - .desc = Используется для заточки кромок стальных инструментов. +ent-ShadowShackles = теневые оковы + .desc = Оковы, сковывающие запястья с помощью зловещей магии. ent-CultRunicMetal = рунический металл .desc = Необычный лист металла с пульсирующей руной. @@ -19,10 +19,17 @@ ent-CultRunicMetal1 = рунический металл .desc = Необычный лист металла с пульсирующей руной. .suffix = Один +ent-CultRunicMetal4 = рунический металл + .desc = Необычный лист металла с пульсирующей руной. + .suffix = 4 + ent-CultRunicMetal20 = рунический металл .desc = Необычный лист металла с пульсирующей руной. .suffix = 20 +ent-AltarTome = архивы + .desc = Стол, заваленный тайными рукописями и книгами на неизвестных языках. + ent-CultBloodAltar = алтарь .desc = Кровавый алтарь, посвященный какому-то существу. @@ -38,9 +45,6 @@ ent-AirlockGlassCult = рунический шлюз ent-WallForceCult = светящаяся стена .desc = Нечестивый щит, блокирующий все атаки. -ent-CultClothingBlindfold = повязка Зилота - .desc = Повязка, наделенная странной силой. - ent-OfferingRune = руна предпонесения .desc = Мгновенно превращает обычного члена экипажа в культиста, для чего требуется 2 культиста вокруг руны. Члена экипажа с имплантом защиты разума нельзя перевоплотить, можно только принести в жертву, для чего нужно 3 культиста, которые встанут вокруг руны. Если цель мертва, то она будет принесена в жертву, для чего требуется 1 культист. diff --git a/Resources/Locale/ru-RU/_white/cult/factory.ftl b/Resources/Locale/ru-RU/_white/cult/factory.ftl index 177d2764cf..157e1b87a1 100644 --- a/Resources/Locale/ru-RU/_white/cult/factory.ftl +++ b/Resources/Locale/ru-RU/_white/cult/factory.ftl @@ -2,9 +2,6 @@ cultist-factory-charging = { $name } будут заряжаться ещё { $s cultist-factory-create = Создать { $itemName } cultist-factory-too-far = Слишком далеко -ent-AltarTome = архивы - .desc = Стол, заваленный тайными рукописями и книгами на неизвестных языках. - ent-CultRobeModify = одеяние флагелланта .desc = Какая-то религиозная роба. @@ -13,9 +10,18 @@ ent-CultMirrorShield = зеркальный щит ent-CultOuterArmor = бронированная мантия .desc = С первого взгляда кажется, что это простая мантия, но на ней имеется элементы брони. -ent-ShadowShackles = теневые оковы - .desc = Оковы, сковывающие запястья с помощью зловещей магии. + +ent-WetStone = точильный камень + .desc = Используется для заточки кромок стальных инструментов. + +ent-CultSharpener = древний точильный камень + .desc = Используется для заточки кромок стальных инструментов. + +ent-CultClothingBlindfold = повязка Зилота + .desc = Повязка, наделенная странной силой. + ent-BloodSpear = кровавое копьё .desc = Ужасающее копьё, полностью состоящее из кристаллизованной крови. + ent-BloodBarrage = залп кровавых снарядов .desc = Кровь за кровь. diff --git a/Resources/Locale/ru-RU/_white/cult/messages.ftl b/Resources/Locale/ru-RU/_white/cult/messages.ftl new file mode 100644 index 0000000000..560d37bedf --- /dev/null +++ b/Resources/Locale/ru-RU/_white/cult/messages.ftl @@ -0,0 +1,3 @@ +cult-stun-component-extra-message = [color=darkgray]Выбросите ауру, чтобы навсегда избавиться от неё.[/color] +cult-magic-holy = Сила священного предмета в руках цели препятствует магии! +cult-magic-no-empty-hand = Вам нужна свободная рука для использования заклинания! diff --git a/Resources/Locale/ru-RU/_white/wizard/wizard.ftl b/Resources/Locale/ru-RU/_white/wizard/wizard.ftl index f704e32454..bf8c6b9332 100644 --- a/Resources/Locale/ru-RU/_white/wizard/wizard.ftl +++ b/Resources/Locale/ru-RU/_white/wizard/wizard.ftl @@ -43,6 +43,7 @@ arcane-barrage-no-empty-hand = Вам нужна свободная рука д mindswap-success = Ваш разум подменили! mindswap-borer-failed = Его разумом кто-то управляет. +mindswap-cultist-failed = Нечестивая сила препятствует подмене сознания. store-currency-display-spell-point = Очки заклинаний diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index 9100b5bf2e..f79e9222fe 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -1442,7 +1442,7 @@ - type: Projectile damage: types: - Piercing: 25 + Piercing: 20 - type: entity name: arcane bolt diff --git a/Resources/Prototypes/_White/Actions/cult_actions.yml b/Resources/Prototypes/_White/Actions/cult_actions.yml index fd5098ee21..864f0f93cd 100644 --- a/Resources/Prototypes/_White/Actions/cult_actions.yml +++ b/Resources/Prototypes/_White/Actions/cult_actions.yml @@ -10,6 +10,7 @@ sprite: /Textures/Objects/Materials/Sheets/metal.rsi state: steel event: !type:CultTwistedConstructionActionEvent + speech: "Ethra p'ni dedol!" itemIconStyle: BigAction charges: 1 temporary: true @@ -31,6 +32,7 @@ sprite: /Textures/White/Cult/actions_cult.rsi state: teleport event: !type:CultTeleportTargetActionEvent + speech: "Sas'so c'arta forbici!" itemIconStyle: BigAction charges: 1 temporary: true @@ -58,20 +60,16 @@ removeOnNoCharges: true - type: entity - id: ActionCultStun + id: InstantActionCultStun name: Stun description: A potent spell that will stun and mute victims. noSpawn: true components: - - type: EntityTargetAction - whitelist: - components: - - HumanoidAppearance - canTargetSelf: false + - type: InstantAction icon: sprite: /Textures/White/Cult/actions_cult.rsi state: stun - event: !type:CultStunTargetActionEvent + event: !type:CultStunActionEvent itemIconStyle: BigAction charges: 1 temporary: true @@ -92,6 +90,7 @@ sprite: /Textures/White/Cult/actions_cult.rsi state: shackles event: !type:CultShadowShacklesTargetActionEvent + speech: "In'totum Lig'abis!" itemIconStyle: BigAction charges: 4 temporary: true @@ -108,6 +107,7 @@ sprite: /Textures/White/Cult/interface.rsi state: icon event: !type:CultSummonDaggerActionEvent + speech: "Wur d'dai leev'mai k'sagan!" charges: 1 temporary: true removeOnNoCharges: true @@ -123,6 +123,7 @@ sprite: /Textures/White/Cult/actions_cult.rsi state: blood_rites event: !type:CultBloodRitesInstantActionEvent + speech: "Fel'th Dol Ab'orod!" charges: 5 temporary: true removeOnNoCharges: true @@ -138,6 +139,7 @@ sprite: /Textures/White/Cult/actions_cult.rsi state: emp event: !type:CultElectromagneticPulseInstantActionEvent + speech: "Ta'gh fara'qha fel d'amar det!" charges: 1 temporary: true removeOnNoCharges: true @@ -153,12 +155,15 @@ sprite: /Textures/White/Cult/actions_cult.rsi state: gone event: !type:CultConcealInstantActionEvent + speech: "Kla'atu barada nikt'o!" charges: 10 temporary: true removeOnNoCharges: true - type: ConcealPresenceSpell concealEvent: !type:CultConcealInstantActionEvent + speech: "Kla'atu barada nikt'o!" revealEvent: !type:CultRevealInstantActionEvent + speech: "Kla'atu barada nikt'o!" concealIcon: sprite: /Textures/White/Cult/actions_cult.rsi state: gone diff --git a/Resources/Prototypes/_White/Entities/Cult/Effects/effects.yml b/Resources/Prototypes/_White/Entities/Cult/Effects/effects.yml index 5b6a66c0c1..885844e63b 100644 --- a/Resources/Prototypes/_White/Entities/Cult/Effects/effects.yml +++ b/Resources/Prototypes/_White/Entities/Cult/Effects/effects.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity id: CultTileSpawnEffect name: Sparkle placement: @@ -103,3 +103,18 @@ drawdepth: Effects - type: PointLight color: "#FF0000" + +- type: entity + id: CultStunFlashEffect + noSpawn: true + components: + - type: PointLight + enabled: true + radius: 5 + energy: 8 + netsync: false + color: Red + - type: LightFade + duration: 0.5 + - type: TimedDespawn + lifetime: 0.5 diff --git a/Resources/Prototypes/_White/Entities/Cult/Items/blood_barrage.yml b/Resources/Prototypes/_White/Entities/Cult/Items/blood_barrage.yml index 00914aa8e4..7e36f2df5a 100644 --- a/Resources/Prototypes/_White/Entities/Cult/Items/blood_barrage.yml +++ b/Resources/Prototypes/_White/Entities/Cult/Items/blood_barrage.yml @@ -24,6 +24,8 @@ proto: BloodBolt capacity: 25 - type: BoltBarrage + - type: DeleteOnDropAttempt + message: bolt-barrage-component-extra-message - type: GiftIgnore - type: CultItem canPickUp: false diff --git a/Resources/Prototypes/_White/Entities/Cult/Items/stun_hand.yml b/Resources/Prototypes/_White/Entities/Cult/Items/stun_hand.yml new file mode 100644 index 0000000000..c73620a53f --- /dev/null +++ b/Resources/Prototypes/_White/Entities/Cult/Items/stun_hand.yml @@ -0,0 +1,34 @@ +- type: entity + parent: BaseItem + id: StunHand + name: stunning aura + description: Will stun and mute a weak-minded victim on hit. + components: + - type: Sprite + sprite: White/Cult/Entities/stun.rsi + state: icon + - type: Item + size: Ginormous + sprite: White/Cult/Entities/stun.rsi + - type: MeleeWeapon + canHeavyAttack: false + canAttackSelf: false + canMiss: false + attackWhitelist: + components: + - StatusEffects + attackBlacklist: + components: + - Cultist + - Construct + wideAnimationRotation: 180 + damage: + types: + Heat: 0 + - type: CultStunHand + - type: DeleteOnDropAttempt + message: cult-stun-component-extra-message + - type: Unremoveable + deleteOnDrop: true + - type: CultItem + canPickUp: false diff --git a/Resources/Prototypes/_White/Entities/Cult/Items/tome_craft.yml b/Resources/Prototypes/_White/Entities/Cult/Items/tome_craft.yml index 4cd0e39620..1baf08e5f1 100644 --- a/Resources/Prototypes/_White/Entities/Cult/Items/tome_craft.yml +++ b/Resources/Prototypes/_White/Entities/Cult/Items/tome_craft.yml @@ -187,6 +187,16 @@ - type: Stack count: 1 +- type: entity + parent: CultRunicMetal + id: CultRunicMetal4 + suffix: 4 + components: + - type: Sprite + state: runic + - type: Stack + count: 4 + - type: entity parent: CultRunicMetal id: CultRunicMetal20 diff --git a/Resources/Prototypes/_White/Entities/Cult/Runes/cult_runes.yml b/Resources/Prototypes/_White/Entities/Cult/Runes/cult_runes.yml index 0ab3d8e9ed..262acf8e10 100644 --- a/Resources/Prototypes/_White/Entities/Cult/Runes/cult_runes.yml +++ b/Resources/Prototypes/_White/Entities/Cult/Runes/cult_runes.yml @@ -165,4 +165,5 @@ - type: CultRuneBase invokePhrase: "TOK-LYR RQA-NAP G'OLT-ULOFT!" cultistGatheringRange: 1.5 + invokeChatType: Speak - type: CultRuneApocalypse diff --git a/Resources/Prototypes/_White/Entities/Cult/Weapons/blood_spear.yml b/Resources/Prototypes/_White/Entities/Cult/Weapons/blood_spear.yml index 14de56bd1a..d617be4e60 100644 --- a/Resources/Prototypes/_White/Entities/Cult/Weapons/blood_spear.yml +++ b/Resources/Prototypes/_White/Entities/Cult/Weapons/blood_spear.yml @@ -19,7 +19,7 @@ - 0.30,0.40 density: 20 mask: - - ItemMask + - BulletImpassable restitution: 0.3 friction: 0.2 - type: Sharp diff --git a/Resources/Prototypes/_White/Entities/Objects/Weapons/chaplain_weapons.yml b/Resources/Prototypes/_White/Entities/Objects/Weapons/chaplain_weapons.yml index 28848c007b..8242662c74 100644 --- a/Resources/Prototypes/_White/Entities/Objects/Weapons/chaplain_weapons.yml +++ b/Resources/Prototypes/_White/Entities/Objects/Weapons/chaplain_weapons.yml @@ -65,7 +65,7 @@ types: Heat: 18 - type: Item - size: Normal + size: Ginormous sprite: White/Objects/Weapons/Chaplain/godhand.rsi - type: Unremoveable deleteOnDrop: true diff --git a/Resources/Prototypes/_White/Wizard/magic_items.yml b/Resources/Prototypes/_White/Wizard/magic_items.yml index 4adfd2e9c8..52953f32ef 100644 --- a/Resources/Prototypes/_White/Wizard/magic_items.yml +++ b/Resources/Prototypes/_White/Wizard/magic_items.yml @@ -133,5 +133,7 @@ - type: BasicEntityAmmoProvider proto: ArcaneBolt capacity: 30 + - type: DeleteOnDropAttempt + message: bolt-barrage-component-extra-message - type: BoltBarrage - type: GiftIgnore diff --git a/Resources/Textures/White/Cult/Entities/arcane_barrage.rsi/bullet.png b/Resources/Textures/White/Cult/Entities/arcane_barrage.rsi/bullet.png index 98351139f2..f1184e4e7b 100644 Binary files a/Resources/Textures/White/Cult/Entities/arcane_barrage.rsi/bullet.png and b/Resources/Textures/White/Cult/Entities/arcane_barrage.rsi/bullet.png differ diff --git a/Resources/Textures/White/Cult/Entities/stun.rsi/icon.png b/Resources/Textures/White/Cult/Entities/stun.rsi/icon.png new file mode 100644 index 0000000000..d19d7ff797 Binary files /dev/null and b/Resources/Textures/White/Cult/Entities/stun.rsi/icon.png differ diff --git a/Resources/Textures/White/Cult/Entities/stun.rsi/inhand-left.png b/Resources/Textures/White/Cult/Entities/stun.rsi/inhand-left.png new file mode 100644 index 0000000000..19acec50cf Binary files /dev/null and b/Resources/Textures/White/Cult/Entities/stun.rsi/inhand-left.png differ diff --git a/Resources/Textures/White/Cult/Entities/stun.rsi/inhand-right.png b/Resources/Textures/White/Cult/Entities/stun.rsi/inhand-right.png new file mode 100644 index 0000000000..12410f5e0b Binary files /dev/null and b/Resources/Textures/White/Cult/Entities/stun.rsi/inhand-right.png differ diff --git a/Resources/Textures/White/Cult/Entities/stun.rsi/meta.json b/Resources/Textures/White/Cult/Entities/stun.rsi/meta.json new file mode 100644 index 0000000000..489466f74a --- /dev/null +++ b/Resources/Textures/White/Cult/Entities/stun.rsi/meta.json @@ -0,0 +1,66 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/49264/commits/d0dffe7ca643db2624424fdcebf45863f85c0448", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "inhand-right", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +}