diff --git a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs index f1c700316b..b6c5b52081 100644 --- a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs +++ b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs @@ -8,14 +8,9 @@ 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; -using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; -using Content.Shared.Fluids.Components; using Content.Shared.Inventory; using Content.Shared.Stacks; -using Content.Shared.StatusEffect; using Content.Shared.Stunnable; using Content.Shared._White.Cult.Actions; using Content.Shared._White.Cult.Components; @@ -25,8 +20,8 @@ using Content.Shared.Actions; using Content.Shared.Cuffs; using Content.Shared.Cuffs.Components; using Content.Shared.DoAfter; +using Content.Shared.Doors.Components; using Content.Shared.Maps; -using Content.Shared.Mindshield.Components; using Content.Shared.Popups; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -72,6 +67,21 @@ public partial class CultSystem SubscribeLocalEvent(OnStun); SubscribeLocalEvent(OnActionRemoved); SubscribeLocalEvent(OnShackles); + SubscribeLocalEvent(OnTwistedConstruction); + } + + private void OnTwistedConstruction(Entity ent, ref TwistedConstructionEvent args) + { + if (args.Cancelled) + QueueDel(GetEntity(args.Effect)); + + if (args.Handled || args.Cancelled) + return; + + args.Handled = true; + + Del(args.Target); + Spawn(args.RunicDoor, GetCoordinates(args.Location)); } private void OnShackles(Entity ent, ref ShacklesEvent args) @@ -115,22 +125,14 @@ public partial class CultSystem !TryComp(uid, out var actor)) return; - if (_holyWeapon.IsHoldingHolyWeapon(args.Target)) + if (!HasComp(args.Target)) { - _popupSystem.PopupEntity(Loc.GetString("cult-magic-holy"), args.Performer, args.Performer, + _popupSystem.PopupEntity("Цель должна быть культистом.", args.Performer, args.Performer, PopupType.MediumCaution); return; } - if (!HasComp(args.Target) && !HasComp(args.Target) && - _actionBlocker.CanInteract(args.Target, null)) - { - _popupSystem.PopupEntity("Цель должна быть культистом, быть скованной или парализованной.", args.Performer, - args.Performer, PopupType.MediumCaution); - return; - } - - _bloodstreamSystem.TryModifyBloodLevel(uid, -5, bloodstream, createPuddle: false); + _bloodstreamSystem.TryModifyBloodLevel(uid, -7, bloodstream, createPuddle: false); var eui = new CultTeleportSpellEui(args.Performer, args.Target); _euiManager.OpenEui(eui, actor.PlayerSession); @@ -367,13 +369,47 @@ public partial class CultSystem if (!TryComp(args.Target, out CuffableComponent? cuffs) || cuffs.Container.ContainedEntities.Count > 0) return; - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Performer, TimeSpan.FromSeconds(2), - new ShacklesEvent(), args.Performer, args.Target) + var doAfterArgs = new DoAfterArgs(EntityManager, args.Performer, TimeSpan.FromSeconds(2), new ShacklesEvent(), + args.Performer, args.Target) { BreakOnMove = true, BreakOnDamage = true - }); + }; + if (!_doAfterSystem.TryStartDoAfter(doAfterArgs)) + return; + + Speak(args); + args.Handled = true; + } + + private void ConvertDoor(EntityUid uid, EntityUid target, BloodstreamComponent bloodstream, + CultTwistedConstructionActionEvent args) + { + var meta = MetaData(target); + if (meta.EntityPrototype?.ID == args.RunicDoor.Id) + return; + + var xform = Transform(target); + if (!xform.Anchored) + return; + + var effect = Spawn(args.Effect, xform.Coordinates); + var ev = new TwistedConstructionEvent(GetNetEntity(effect), args.RunicDoor, GetNetCoordinates(xform.Coordinates)); + var doAfterArgs = new DoAfterArgs(EntityManager, uid, args.Delay, ev, uid, target) + { + BreakOnDamage = true, + BreakOnMove = true, + }; + + if (!_doAfterSystem.TryStartDoAfter(doAfterArgs)) + { + QueueDel(effect); + return; + } + + _audio.PlayPvs(args.Sound, xform.Coordinates); + _bloodstreamSystem.TryModifyBloodLevel(uid, -12, bloodstream, createPuddle: false); Speak(args); args.Handled = true; } @@ -389,6 +425,12 @@ public partial class CultSystem if (!TryComp(args.Performer, out var bloodstreamComponent)) return; + if (HasComp(args.Target)) + { + ConvertDoor(uid, args.Target, bloodstreamComponent, args); + return; + } + if (!_entityManager.TryGetComponent(args.Target, out var stack)) return; diff --git a/Content.Shared/_White/Cult/Actions/CultActions.cs b/Content.Shared/_White/Cult/Actions/CultActions.cs index eedcf82029..87feaf9872 100644 --- a/Content.Shared/_White/Cult/Actions/CultActions.cs +++ b/Content.Shared/_White/Cult/Actions/CultActions.cs @@ -1,5 +1,7 @@ using Content.Shared.Actions; using Content.Shared.Magic; +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; namespace Content.Shared._White.Cult.Actions; @@ -7,6 +9,21 @@ public sealed partial class CultTwistedConstructionActionEvent : EntityTargetAct { [DataField("speech")] public string? Speech { get; private set; } + + [DataField] + public EntProtoId RunicDoor = "AirlockGlassCult"; + + [DataField] + public EntProtoId Effect = "EffectConstructRed"; + + [DataField] + public TimeSpan Delay = TimeSpan.FromSeconds(4); + + [DataField] + public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Machines/airlock_creaking.ogg") + { + Params = AudioParams.Default.WithVolume(-3f), + }; } public sealed partial class CultSummonDaggerActionEvent : InstantActionEvent, ISpeakSpell diff --git a/Content.Shared/_White/Cult/Actions/CultEvents.cs b/Content.Shared/_White/Cult/Actions/CultEvents.cs new file mode 100644 index 0000000000..5f584db374 --- /dev/null +++ b/Content.Shared/_White/Cult/Actions/CultEvents.cs @@ -0,0 +1,30 @@ +using Content.Shared.DoAfter; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared._White.Cult.Actions; + +[Serializable, NetSerializable] +public sealed partial class ShacklesEvent : SimpleDoAfterEvent +{ +} + +[Serializable, NetSerializable] +public sealed partial class TwistedConstructionEvent : DoAfterEvent +{ + public NetEntity Effect { get; private set; } + + public EntProtoId RunicDoor { get; private set; } + + public NetCoordinates Location { get; private set; } + + public TwistedConstructionEvent(NetEntity effect, EntProtoId runicDoor, NetCoordinates location) + { + Effect = effect; + RunicDoor = runicDoor; + Location = location; + } + + public override DoAfterEvent Clone() => this; +} diff --git a/Content.Shared/_White/Cult/Actions/ShacklesEvent.cs b/Content.Shared/_White/Cult/Actions/ShacklesEvent.cs deleted file mode 100644 index 6c27ce1aab..0000000000 --- a/Content.Shared/_White/Cult/Actions/ShacklesEvent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Content.Shared.DoAfter; -using Robust.Shared.Serialization; - -namespace Content.Shared._White.Cult.Actions; - -[Serializable, NetSerializable] -public sealed partial class ShacklesEvent : SimpleDoAfterEvent -{ -} diff --git a/Resources/Locale/ru-RU/_white/cult/abilities.ftl b/Resources/Locale/ru-RU/_white/cult/abilities.ftl index 11f07a834f..f16bf673d6 100644 --- a/Resources/Locale/ru-RU/_white/cult/abilities.ftl +++ b/Resources/Locale/ru-RU/_white/cult/abilities.ftl @@ -20,10 +20,10 @@ juggernaut-create-wall-action-name = Щит juggernaut-create-wall-action-description = Это заклинание создает временное невидимое силовое поле для защиты себя и союзников от подавляющего огня. ent-ActionCultTwistedConstruction = Искажённое Воздействие - .desc = Зловещее заклинание, которое используют для превращения металла в рунический металл. + .desc = Зловещее заклинание, которое используют для превращения металла в рунический металл и обычных дверей в рунические. ent-ActionCultTeleport = Телепорт - .desc = Полезное заклинание, которое телепортирует цель на выбранную руну телепотрации. Цель должна являются культистом или быть парализованной. + .desc = Полезное заклинание, которое телепортирует культиста на выбранную руну телепотрации. ent-ActionCultSummonCombatEquipment = Призыв Боевого Снаряжения .desc = Важное заклинание, которое позволяет вам вызвать полный набор боевого снаряжения. diff --git a/Resources/Prototypes/Entities/Effects/rcd.yml b/Resources/Prototypes/Entities/Effects/rcd.yml index 902429818e..5016bfbff7 100644 --- a/Resources/Prototypes/Entities/Effects/rcd.yml +++ b/Resources/Prototypes/Entities/Effects/rcd.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity id: EffectRCDBase abstract: true noSpawn: true @@ -15,7 +15,7 @@ tags: - HideContextMenu - type: AnimationPlayer - + - type: entity parent: EffectRCDBase id: EffectRCDDeconstructPreview @@ -23,7 +23,7 @@ components: - type: Sprite state: deconstructPreview - + - type: entity parent: EffectRCDBase id: EffectRCDConstruct0 @@ -33,7 +33,7 @@ state: construct0 - type: TimedDespawn lifetime: 1.2 - + - type: entity parent: EffectRCDBase id: EffectRCDConstruct1 @@ -43,7 +43,7 @@ state: construct1 - type: TimedDespawn lifetime: 2.2 - + - type: entity parent: EffectRCDBase id: EffectRCDConstruct2 @@ -53,7 +53,7 @@ state: construct2 - type: TimedDespawn lifetime: 3.2 - + - type: entity parent: EffectRCDBase id: EffectRCDConstruct3 @@ -63,7 +63,7 @@ state: construct3 - type: TimedDespawn lifetime: 4.2 - + - type: entity parent: EffectRCDBase id: EffectRCDConstruct4 @@ -83,7 +83,7 @@ state: deconstruct2 - type: TimedDespawn lifetime: 3.2 - + - type: entity parent: EffectRCDBase id: EffectRCDDeconstruct4 @@ -112,4 +112,4 @@ - type: Sprite state: deconstruct8 - type: TimedDespawn - lifetime: 9.2 \ No newline at end of file + lifetime: 9.2 diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 02d466667d..5d9df35b40 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -766,6 +766,7 @@ normalState: normal-unshaded ejectState: eject-unshaded denyState: deny-unshaded + priceMultiplier: 0.0 - type: Sprite sprite: Structures/Machines/VendingMachines/engivend.rsi layers: diff --git a/Resources/Prototypes/_White/Entities/Cult/Effects/effects.yml b/Resources/Prototypes/_White/Entities/Cult/Effects/effects.yml index 5282cb3c7b..233306405e 100644 --- a/Resources/Prototypes/_White/Entities/Cult/Effects/effects.yml +++ b/Resources/Prototypes/_White/Entities/Cult/Effects/effects.yml @@ -118,3 +118,13 @@ duration: 0.5 - type: TimedDespawn lifetime: 0.5 + +- type: entity + parent: EffectRCDBase + id: EffectConstructRed + noSpawn: true + components: + - type: Sprite + state: construct_red + - type: TimedDespawn + lifetime: 5.2 diff --git a/Resources/Textures/Effects/rcd.rsi/construct_red.png b/Resources/Textures/Effects/rcd.rsi/construct_red.png new file mode 100644 index 0000000000..e21b111ab7 Binary files /dev/null and b/Resources/Textures/Effects/rcd.rsi/construct_red.png differ diff --git a/Resources/Textures/Effects/rcd.rsi/meta.json b/Resources/Textures/Effects/rcd.rsi/meta.json index c9e8320c60..43a62a27fa 100644 --- a/Resources/Textures/Effects/rcd.rsi/meta.json +++ b/Resources/Textures/Effects/rcd.rsi/meta.json @@ -25,7 +25,7 @@ 0.1 ] ] - }, + }, { "name": "construct1", "delays": [ @@ -64,7 +64,7 @@ 0.1 ] ] - }, + }, { "name": "construct2", "delays": [ @@ -201,7 +201,66 @@ 0.1 ] ] - }, + }, + { + "name": "construct_red", + "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, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 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": "deconstruct2", "delays": [ @@ -358,7 +417,7 @@ 0.1 ] ] - }, + }, { "name": "deconstruct8", "delays": [ @@ -451,7 +510,7 @@ 0.05, 0.05, 0.05, - 0.05 + 0.05 ] ] }