From f25ad286b977993ea62b2eb52947d1e498e5d9d0 Mon Sep 17 00:00:00 2001 From: Aviu00 <93730715+Aviu00@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:55:21 +0000 Subject: [PATCH] Magic and gamerule tweaks (#363) * - tweak: Wiz hardsuit tweaks. * - tweak: Gamemode tweaks. * - add: Mindswap spell. * - add: Transfer wizard component on mindswap. * - add: Wizard is blight immune. --- Content.Server/EnergyDome/EnergyDomeSystem.cs | 12 ++ .../Rules/Components/NukeopsRuleComponent.cs | 2 +- .../Rules/Components/ZombieRuleComponent.cs | 4 +- .../GameTicking/Rules/NukeopsRuleSystem.cs | 12 +- .../Rules/RevolutionaryRuleSystem.cs | 8 +- .../EntitySystems/RevenantSystem.Abilities.cs | 5 +- Content.Server/RoundEnd/RoundEndSystem.cs | 2 +- .../_White/Cult/GameRule/CultRuleSystem.cs | 2 +- .../_White/Wizard/Magic/WizardSpellsSystem.cs | 124 ++++++++++++++++-- .../_White/Wizard/WizardRuleComponent.cs | 2 +- .../_White/Wizard/WizardRuleSystem.cs | 11 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 + Content.Shared/_White/Wizard/WizardEvents.cs | 6 + .../Locale/ru-RU/_white/wizard/scrolls.ftl | 3 + .../Locale/ru-RU/_white/wizard/spellbook.ftl | 3 + .../Locale/ru-RU/_white/wizard/spells.ftl | 3 + .../Clothing/OuterClothing/hardsuits.yml | 4 +- Resources/Prototypes/Magic/knock_spell.yml | 2 + Resources/Prototypes/Magic/white.yml | 38 ++++++ .../_White/Objects/Scrolls/scrolls.yml | 9 ++ .../_White/Wizard/spellbook_catalog.yml | 18 ++- .../Objects/Magic/magicactions.rsi/meta.json | 3 + .../Magic/magicactions.rsi/mindswap.png | Bin 0 -> 600 bytes 23 files changed, 238 insertions(+), 37 deletions(-) create mode 100644 Resources/Textures/Objects/Magic/magicactions.rsi/mindswap.png diff --git a/Content.Server/EnergyDome/EnergyDomeSystem.cs b/Content.Server/EnergyDome/EnergyDomeSystem.cs index d04935304e..d39aa401ce 100644 --- a/Content.Server/EnergyDome/EnergyDomeSystem.cs +++ b/Content.Server/EnergyDome/EnergyDomeSystem.cs @@ -1,3 +1,4 @@ +using Content.Server.Damage.Components; using Content.Server.DeviceLinking.Events; using Content.Server.DeviceLinking.Systems; using Content.Server.Power.Components; @@ -12,6 +13,7 @@ using Content.Shared.Inventory; using Content.Shared.Popups; using Content.Shared.PowerCell; using Content.Shared.PowerCell.Components; +using Content.Shared.Throwing; using Content.Shared.Timing; using Content.Shared.Toggleable; using Content.Shared.Verbs; @@ -35,6 +37,8 @@ public sealed partial class EnergyDomeSystem : EntitySystem { base.Initialize(); + SubscribeLocalEvent(OnThrow); + //Generator events SubscribeLocalEvent(OnInit); @@ -62,6 +66,14 @@ public sealed partial class EnergyDomeSystem : EntitySystem SubscribeLocalEvent(OnDomeDamaged); } + private void OnThrow(Entity ent, ref ThrownEvent args) + { + if (args.User == null) + return; + + RaiseLocalEvent(args.User.Value, new EnergyDomeClothesTurnOffEvent()); + } + private void OnClothesTurnOff(Entity ent, ref InventoryRelayedEvent args) { diff --git a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs index 828ea95c7d..38da1506a6 100644 --- a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs @@ -30,7 +30,7 @@ public sealed partial class NukeopsRuleComponent : Component /// What will happen if all of the nuclear operatives will die. Used by LoneOpsSpawn event. /// [DataField] - public RoundEndBehavior RoundEndBehavior = RoundEndBehavior.ShuttleCall; + public RoundEndBehavior RoundEndBehavior = RoundEndBehavior.InstantEnd; /// /// Text for shuttle call if RoundEndBehavior is ShuttleCall. diff --git a/Content.Server/GameTicking/Rules/Components/ZombieRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/ZombieRuleComponent.cs index 4fe91e3a5f..7e66ac98c0 100644 --- a/Content.Server/GameTicking/Rules/Components/ZombieRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/ZombieRuleComponent.cs @@ -36,13 +36,13 @@ public sealed partial class ZombieRuleComponent : Component /// The minimum amount of time after the round starts that the initial infected will be chosen. /// [DataField] - public TimeSpan MinStartDelay = TimeSpan.FromMinutes(10); + public TimeSpan MinStartDelay = TimeSpan.FromMinutes(3); /// /// The maximum amount of time after the round starts that the initial infected will be chosen. /// [DataField] - public TimeSpan MaxStartDelay = TimeSpan.FromMinutes(15); + public TimeSpan MaxStartDelay = TimeSpan.FromMinutes(6); /// /// The sound that plays when someone becomes an initial infected. diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index ebdbdd480f..620864bfb3 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -45,6 +45,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; using System.Linq; +using Content.Server.StationEvents.Components; using Content.Shared.FixedPoint; using Content.Shared.Mind; @@ -683,9 +684,14 @@ public sealed class NukeopsRuleSystem : GameRuleSystem : WinCondition.AllNukiesDead); SetWinType(uid, WinType.CrewMajor, nukeops, false); - _roundEndSystem.DoRoundEndBehavior( - nukeops.RoundEndBehavior, nukeops.EvacShuttleTime, nukeops.RoundEndTextSender, - nukeops.RoundEndTextShuttleCall, nukeops.RoundEndTextAnnouncement); + + // WD EDIT, check for all at once gamemode + if (!GameTicker.GetActiveGameRules().Where(HasComp).Any()) + { + _roundEndSystem.DoRoundEndBehavior( + nukeops.RoundEndBehavior, nukeops.EvacShuttleTime, nukeops.RoundEndTextSender, + nukeops.RoundEndTextShuttleCall, nukeops.RoundEndTextAnnouncement); + } // prevent it called multiple times nukeops.RoundEndBehavior = RoundEndBehavior.Nothing; diff --git a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs index 69d0396e3a..0c389c5029 100644 --- a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs @@ -107,10 +107,8 @@ public sealed class RevolutionaryRuleSystem : GameRuleSystem).Any()) - _roundEnd.DoRoundEndBehavior(RoundEndBehavior.ShuttleCall, component.ShuttleCallTime); - else + // Check for all at once gamemode + if (!_gameTicker.GetActiveGameRules().Where(HasComp).Any()) _roundEnd.EndRound(); // WD EDIT END @@ -429,4 +427,4 @@ public sealed class RevolutionaryRuleSystem : GameRuleSystem(transferTo); RemComp(transferFrom); } -} \ No newline at end of file +} diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index f7c204899e..513571c970 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -14,6 +14,7 @@ using Content.Shared.Item; using Content.Shared.Bed.Sleep; using System.Linq; using System.Numerics; +using Content.Server._White.Wizard; using Content.Server.Bible.Components; using Content.Server.Maps; using Content.Server.Revenant.Components; @@ -335,10 +336,12 @@ public sealed partial class RevenantSystem // WD START var cultistQuery = GetEntityQuery(); + var wizardQuery = GetEntityQuery(); var humanoidQuery = GetEntityQuery(); foreach (var e in _lookup.GetEntitiesInRange(uid, component.BlightRadius)) { - if (!humanoidQuery.HasComponent(e) || !_mobState.IsAlive(e) || cultistQuery.HasComponent(e)) + if (!humanoidQuery.HasComponent(e) || !_mobState.IsAlive(e) || cultistQuery.HasComponent(e) || + wizardQuery.HasComponent(e)) continue; var blight = EnsureComp(e); diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index 07ebffa3c4..cf90f9b84f 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -53,7 +53,7 @@ namespace Content.Server.RoundEnd /// /// Countdown to use where there is no station alert countdown to be found. /// - public TimeSpan DefaultCountdownDuration { get; set; } = TimeSpan.FromMinutes(10); + public TimeSpan DefaultCountdownDuration { get; set; } = TimeSpan.FromMinutes(5); private CancellationTokenSource? _countdownTokenSource; private CancellationTokenSource? _cooldownTokenSource; diff --git a/Content.Server/_White/Cult/GameRule/CultRuleSystem.cs b/Content.Server/_White/Cult/GameRule/CultRuleSystem.cs index 5ef0ce6407..f419ad95af 100644 --- a/Content.Server/_White/Cult/GameRule/CultRuleSystem.cs +++ b/Content.Server/_White/Cult/GameRule/CultRuleSystem.cs @@ -311,7 +311,7 @@ public sealed class CultRuleSystem : GameRuleSystem cult.WinCondition = CultWinCondition.Failure; - // Check for all in once gamemode + // Check for all at once gamemode if (!GameTicker.GetActiveGameRules().Where(HasComp).Any()) _roundEndSystem.EndRound(); } diff --git a/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs b/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs index 3e0ac10fa8..a3382739fb 100644 --- a/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs +++ b/Content.Server/_White/Wizard/Magic/WizardSpellsSystem.cs @@ -13,14 +13,18 @@ using Content.Server.Emp; using Content.Server.EUI; using Content.Server.Lightning; using Content.Server.Magic; +using Content.Server.Mind; using Content.Server.Singularity.EntitySystems; using Content.Server.Standing; using Content.Server.Weapons.Ranged.Systems; using Content.Shared._White.BetrayalDagger; +using Content.Shared._White.Cult.Components; using Content.Shared._White.Events; using Content.Shared._White.Wizard; using Content.Shared._White.Wizard.Magic; using Content.Shared.Actions; +using Content.Shared.Borer; +using Content.Shared.Changeling; using Content.Shared.Cluwne; using Content.Shared.Coordinates.Helpers; using Content.Shared.Hands.Components; @@ -35,6 +39,7 @@ using Content.Shared.Maps; using Content.Shared.Mobs.Components; using Content.Shared.Physics; using Content.Shared.Popups; +using Content.Shared.Revolutionary.Components; using Content.Shared.StatusEffect; using Content.Shared.Throwing; using Robust.Shared.Audio.Systems; @@ -71,6 +76,8 @@ public sealed class WizardSpellsSystem : EntitySystem [Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly TelefragSystem _telefrag = default!; [Dependency] private readonly EuiManager _euiManager = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; #endregion @@ -78,6 +85,7 @@ public sealed class WizardSpellsSystem : EntitySystem { base.Initialize(); + SubscribeLocalEvent(OnMindswapSpell); SubscribeLocalEvent(OnTeleportSpell); SubscribeLocalEvent(OnInstantRecallSpell); SubscribeLocalEvent(OnMimeTouchSpell); @@ -95,6 +103,73 @@ public sealed class WizardSpellsSystem : EntitySystem SubscribeLocalEvent(OnBeforeCastSpell); } + #region Mindswap + + private void OnMindswapSpell(MindswapSpellEvent msg) + { + if (!CanCast(msg)) + return; + + var target = msg.Target; + var uid = msg.Performer; + + if (HasComp(target) || HasComp(target) || + HasComp(target)) + { + _popupSystem.PopupEntity("Не работает на культистов, генокрадов и революционеров.", uid, uid, + PopupType.MediumCaution); + return; + } + + if (TryComp(target, out InfestedBorerComponent? borer) && borer.ControllingBrain) + { + _popupSystem.PopupEntity("Им уже кто-то управляет.", 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); + + if (!userHasMind) + return; + + _mindSystem.TransferTo(mindId, target, mind: mind); + + if (targetHasMind) + { + _mindSystem.TransferTo(targetMindId, uid, mind: targetMind); + _popupSystem.PopupEntity(Loc.GetString("Ваш разум подменили!"), uid, uid, PopupType.LargeCaution); + } + + TransferAllMagicActions(uid, target); + + _standing.TryLieDown(uid); + _standing.TryLieDown(target); + + msg.Handled = true; + Speak(msg); + + var hasWiz = HasComp(uid); + var targetHasWiz = HasComp(target); + + if (hasWiz == targetHasWiz) + return; + + if (hasWiz) + { + RemComp(uid); + EnsureComp(target); + } + + if (targetHasWiz) + { + RemComp(target); + EnsureComp(uid); + } + } + + #endregion + #region Teleport private void OnTeleportSpell(TeleportSpellEvent msg) @@ -797,27 +872,48 @@ public sealed class WizardSpellsSystem : EntitySystem private void OnBeforeCastSpell(Entity ent, ref BeforeCastSpellEvent args) { var comp = ent.Comp; + + if (!comp.RequiresClothes) + return; + var hasReqs = false; - if (comp.RequiresClothes) + var enumerator = _inventory.GetSlotEnumerator(args.Performer, SlotFlags.OUTERCLOTHING | SlotFlags.HEAD); + while (enumerator.MoveNext(out var containerSlot)) { - var enumerator = _inventory.GetSlotEnumerator(args.Performer, SlotFlags.OUTERCLOTHING | SlotFlags.HEAD); - while (enumerator.MoveNext(out var containerSlot)) - { - if (containerSlot.ContainedEntity is { } item) - hasReqs = HasComp(item); - else - hasReqs = false; + if (containerSlot.ContainedEntity is { } item) + hasReqs = HasComp(item); + else + hasReqs = false; - if (!hasReqs) - break; - } + if (!hasReqs) + break; } - if (!hasReqs) + if (hasReqs) + return; + + args.Cancelled = true; + _popupSystem.PopupEntity(Loc.GetString("magic-component-missing-req"), args.Performer, args.Performer); + } + + private void TransferAllMagicActions(EntityUid uid1, EntityUid uid2) + { + if (!TryComp(uid1, out ActionsContainerComponent? container1) || + !TryComp(uid2, out ActionsContainerComponent? container2)) + return; + + var actions1 = container1.Container.ContainedEntities.Where(HasComp).ToList(); + var actions2 = container2.Container.ContainedEntities.Where(HasComp).ToList(); + + foreach (var act in actions1) { - args.Cancelled = true; - _popupSystem.PopupEntity(Loc.GetString("magic-component-missing-req"), args.Performer, args.Performer); + _actionContainer.TransferActionWithNewAttached(act, uid2, uid2, container: container2); + } + + foreach (var act in actions2) + { + _actionContainer.TransferActionWithNewAttached(act, uid1, uid1, container: container1); } } diff --git a/Content.Server/_White/Wizard/WizardRuleComponent.cs b/Content.Server/_White/Wizard/WizardRuleComponent.cs index 3bdda39bbd..9495e2b208 100644 --- a/Content.Server/_White/Wizard/WizardRuleComponent.cs +++ b/Content.Server/_White/Wizard/WizardRuleComponent.cs @@ -50,7 +50,7 @@ public sealed partial class WizardRuleComponent : Component [DataField] public ProtoId Faction = "Wizard"; - public RoundEndBehavior RoundEndBehavior = RoundEndBehavior.ShuttleCall; + public RoundEndBehavior RoundEndBehavior = RoundEndBehavior.InstantEnd; [DataField] public string RoundEndTextSender = "comms-console-announcement-title-centcom"; diff --git a/Content.Server/_White/Wizard/WizardRuleSystem.cs b/Content.Server/_White/Wizard/WizardRuleSystem.cs index c5b45ef761..b98f86c63e 100644 --- a/Content.Server/_White/Wizard/WizardRuleSystem.cs +++ b/Content.Server/_White/Wizard/WizardRuleSystem.cs @@ -23,6 +23,7 @@ using Robust.Shared.Prototypes; using System.Linq; using Content.Server.Objectives; using Content.Server.Station.Components; +using Content.Server.StationEvents.Components; using Content.Shared.Mind; using Content.Shared.NPC.Components; using Content.Shared.Objectives.Components; @@ -62,7 +63,6 @@ public sealed class WizardRuleSystem : GameRuleSystem SubscribeLocalEvent(OnStartAttempt); SubscribeLocalEvent(OnPlayersSpawning); SubscribeLocalEvent(OnRunLevelChanged); - SubscribeLocalEvent(OnComponentRemove); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnPlayersGhostSpawning); SubscribeLocalEvent(OnMindAdded); @@ -123,11 +123,6 @@ public sealed class WizardRuleSystem : GameRuleSystem SpawnWizardGhostRole(uid, component); } - private void OnComponentRemove(EntityUid uid, WizardComponent component, ComponentRemove args) - { - CheckAnnouncement(); - } - private void OnMobStateChanged(EntityUid uid, WizardComponent component, MobStateChangedEvent ev) { if (ev.NewMobState == MobState.Dead) @@ -249,6 +244,10 @@ public sealed class WizardRuleSystem : GameRuleSystem private void CheckAnnouncement() { + // Check for all at once gamemode + if (GameTicker.GetActiveGameRules().Where(HasComp).Any()) + return; + var query = QueryActiveRules(); while (query.MoveNext(out _, out _, out var wizard, out _)) { diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 873e3eeaa6..c77817d2d3 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; +using Content.Shared._White.Events; using Content.Shared._White.WeaponModules; using Content.Shared.ActionBlocker; using Content.Shared.Actions; @@ -353,6 +354,7 @@ public abstract partial class SharedGunSystem : EntitySystem return; } + RaiseLocalEvent(user, new EnergyDomeClothesTurnOffEvent()); // WD // Shoot confirmed - sounds also played here in case it's invalid (e.g. cartridge already spent). Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, out var userImpulse, user, throwItems: attemptEv.ThrowItems); var shotEv = new GunShotEvent(user, ev.Ammo); diff --git a/Content.Shared/_White/Wizard/WizardEvents.cs b/Content.Shared/_White/Wizard/WizardEvents.cs index 944ee69c91..e55ff3b241 100644 --- a/Content.Shared/_White/Wizard/WizardEvents.cs +++ b/Content.Shared/_White/Wizard/WizardEvents.cs @@ -178,4 +178,10 @@ public sealed partial class TeleportSpellEvent : InstantActionEvent, ISpeakSpell public string? Speech { get; private set; } } +public sealed partial class MindswapSpellEvent : EntityTargetActionEvent, ISpeakSpell +{ + [DataField("speech")] + public string? Speech { get; private set; } +} + #endregion diff --git a/Resources/Locale/ru-RU/_white/wizard/scrolls.ftl b/Resources/Locale/ru-RU/_white/wizard/scrolls.ftl index 40c0ac5cb9..ccbdefb1e4 100644 --- a/Resources/Locale/ru-RU/_white/wizard/scrolls.ftl +++ b/Resources/Locale/ru-RU/_white/wizard/scrolls.ftl @@ -16,6 +16,7 @@ scroll-component-silence = тишину scroll-component-recall = призыв scroll-component-teleport = телепортацию scroll-component-smite = кару +scroll-component-mindswap = подмену сознания ent-BaseScroll = магический свиток .desc = Этот древний пергамент, ставший реликвией в арканных преданиях, хранит в себе бесчисленные мистические заклятия и забытые заклинания. @@ -49,3 +50,5 @@ ent-ScrollTeleport = свиток телепортации .desc = { ent-BaseScroll.desc } ent-ScrollSmite = свиток кары .desc = { ent-BaseScroll.desc } +ent-ScrollMindswap = свиток подмены сознания + .desc = { ent-BaseScroll.desc } diff --git a/Resources/Locale/ru-RU/_white/wizard/spellbook.ftl b/Resources/Locale/ru-RU/_white/wizard/spellbook.ftl index 1d3f6e353e..2cf05319f0 100644 --- a/Resources/Locale/ru-RU/_white/wizard/spellbook.ftl +++ b/Resources/Locale/ru-RU/_white/wizard/spellbook.ftl @@ -40,6 +40,9 @@ spellbook-recall-desc = { ent-ActionInstantRecallSpell.desc } spellbook-smite-name = { ent-ActionSmite } spellbook-smite-desc = { ent-ActionSmite.desc } +spellbook-mindswap-name = { ent-ActionMindswapSpell } +spellbook-mindswap-desc = { ent-ActionMindswapSpell.desc } + spellbook-hardsuit-name = Скафандр волшебника spellbook-hardsuit-desc = Украшенный магическими драгоценными камнями скафандр, функционирующий так же, как и обычная мантия волшебника, но в то же время является пригодным для использования в космосе и бронированным. Небольшое замедление. Теперь вы можете произносить заклинания в космосе и местах с низкой температурой! Имеет функцию энергетического щита,который защищает от всех снарядов. Щит разряжается при получении урона и автоматически заряжается. diff --git a/Resources/Locale/ru-RU/_white/wizard/spells.ftl b/Resources/Locale/ru-RU/_white/wizard/spells.ftl index 075acfc6c4..c54b13bb07 100644 --- a/Resources/Locale/ru-RU/_white/wizard/spells.ftl +++ b/Resources/Locale/ru-RU/_white/wizard/spells.ftl @@ -42,3 +42,6 @@ ent-ActionKnock = Стук ent-ActionSmite = Кара .desc = Заряжает вашу руку мерзкой энергией, которую можно использовать для взрыва жертв. Заклинание требует, чтобы вы коснулись своей цели, поэтому вы не сможете использовать его в наручниках или будучи оглушённым. Не работает без волшебной мантии и шляпы. + +ent-ActionMindswapSpell = Подмена сознания + .desc = Позволяет заклинателю переключаться между телами с целью. Вы должны быть рядом с целью, в которую хотите перейти, после чего вы оба будете нокаутированы. Не работает на культистов, генокрадов и революционеров. diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index 614ed6dc1c..1238cd3785 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -685,17 +685,19 @@ toggleable-clothing: !type:ContainerSlot - type: PowerCellSlot cellSlotId: cell_slot + fitsInCharger: false - type: ItemSlots slots: cell_slot: name: power-cell-slot-component-slot-name-default startingItem: PowerCellMicroreactor + disableEject: true whitelist: tags: - PowerCell - PowerCellSmall - type: EnergyDomeGenerator - damageEnergyDraw: 5 + damageEnergyDraw: 20 domePrototype: EnergyDomeSmallPink - type: ClothingSpeedModifier walkModifier: 0.9 diff --git a/Resources/Prototypes/Magic/knock_spell.yml b/Resources/Prototypes/Magic/knock_spell.yml index dc7b38117d..d2a280ae5a 100644 --- a/Resources/Prototypes/Magic/knock_spell.yml +++ b/Resources/Prototypes/Magic/knock_spell.yml @@ -4,6 +4,8 @@ description: This spell opens nearby doors. noSpawn: true components: + - type: Magic + requiresClothes: false - type: InstantAction useDelay: 8 itemIconStyle: BigAction diff --git a/Resources/Prototypes/Magic/white.yml b/Resources/Prototypes/Magic/white.yml index 92be6e994f..a7111a8b68 100644 --- a/Resources/Prototypes/Magic/white.yml +++ b/Resources/Prototypes/Magic/white.yml @@ -38,6 +38,8 @@ name: Force noSpawn: true components: + - type: Magic + requiresClothes: false - type: WorldTargetAction itemIconStyle: BigAction useDelay: 60 @@ -100,6 +102,8 @@ name: Cards noSpawn: true components: + - type: Magic + requiresClothes: false - type: WorldTargetAction itemIconStyle: BigAction useDelay: 60 @@ -167,6 +171,8 @@ name: Blink noSpawn: true components: + - type: Magic + requiresClothes: false - type: InstantAction useDelay: 6 itemIconStyle: BigAction @@ -216,6 +222,8 @@ name: Cluwne Curse noSpawn: true components: + - type: Magic + requiresClothes: false - type: EntityTargetAction whitelist: components: @@ -235,6 +243,8 @@ name: Banana Touch noSpawn: true components: + - type: Magic + requiresClothes: false - type: EntityTargetAction whitelist: components: @@ -254,6 +264,8 @@ name: Mime Touch noSpawn: true components: + - type: Magic + requiresClothes: false - type: EntityTargetAction whitelist: components: @@ -273,6 +285,8 @@ name: Instant Recall noSpawn: true components: + - type: Magic + requiresClothes: false - type: InstantRecall - type: InstantAction useDelay: 10 @@ -288,6 +302,8 @@ name: Teleport noSpawn: true components: + - type: Magic + requiresClothes: false - type: InstantAction checkCanInteract: false useDelay: 60 @@ -297,3 +313,25 @@ state: teleport event: !type:TeleportSpellEvent speech: "SCYAR FIDE!" + +- type: entity + id: ActionMindswapSpell + name: Mindswap + noSpawn: true + components: + - type: Magic + requiresClothes: false + - type: EntityTargetAction + whitelist: + components: + - MindContainer + - ActionContainer + canTargetSelf: false + checkCanInteract: false + useDelay: 60 + itemIconStyle: BigAction + icon: + sprite: Objects/Magic/magicactions.rsi + state: mindswap + event: !type:MindswapSpellEvent + speech: "GIN'YU CAPAN!" diff --git a/Resources/Prototypes/_White/Objects/Scrolls/scrolls.yml b/Resources/Prototypes/_White/Objects/Scrolls/scrolls.yml index ab691c602a..1af1de715e 100644 --- a/Resources/Prototypes/_White/Objects/Scrolls/scrolls.yml +++ b/Resources/Prototypes/_White/Objects/Scrolls/scrolls.yml @@ -151,3 +151,12 @@ - type: Scroll actionId: ActionSmite learnPopup: scroll-component-smite + +- type: entity + id: ScrollMindswap + parent: BaseScroll + name: "Mindswap scroll" + components: + - type: Scroll + actionId: ActionMindswapSpell + learnPopup: scroll-component-mindswap diff --git a/Resources/Prototypes/_White/Wizard/spellbook_catalog.yml b/Resources/Prototypes/_White/Wizard/spellbook_catalog.yml index a9cd7016b0..97fdecd3ea 100644 --- a/Resources/Prototypes/_White/Wizard/spellbook_catalog.yml +++ b/Resources/Prototypes/_White/Wizard/spellbook_catalog.yml @@ -222,13 +222,29 @@ - !type:ListingLimitedStockCondition stock: 1 +- type: listing + id: SpellBookMindswap + name: spellbook-mindswap-name + description: spellbook-mindswap-desc + productEntity: ScrollMindswap + icon: + sprite: Objects/Magic/magicactions.rsi + state: mindswap + cost: + SpellPoint: 2 + categories: + - UtilitySpells + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + - type: listing id: SpellBookHardsuit name: spellbook-hardsuit-name description: spellbook-hardsuit-desc productEntity: ClothingOuterHardsuitWizard cost: - SpellPoint: 4 + SpellPoint: 5 categories: - MagicItems conditions: diff --git a/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json b/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json index b84afefb47..248ab268d2 100644 --- a/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json +++ b/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json @@ -57,6 +57,9 @@ }, { "name": "icebeam_active" + }, + { + "name": "mindswap" } ] } diff --git a/Resources/Textures/Objects/Magic/magicactions.rsi/mindswap.png b/Resources/Textures/Objects/Magic/magicactions.rsi/mindswap.png new file mode 100644 index 0000000000000000000000000000000000000000..53b8b47a4903e5ede6c85a5fbd16a64cc6f818c5 GIT binary patch literal 600 zcmV-e0;m0nP)GVvejZ1u+bIFok4X`mjLCVWgpZ4arwuO=dY)*|5I?jysV((DIK(`Zur4l3>q1&XGFe-qxptHB|bmAd%=zu6!gC2n! zNCglHzrcIuMf&Xx^$m@<6@3W3giu{stw6})?qfIZ1Bnk&8A2X8KvV$BM_yrBy4zGL z4bO>3dT|7?SPbE47_E+G1pIgG+}(3Poh=(e2FU}V`35M&iXbS7h?J+%Wr0^bMm%Xn zMY$hNyOUKx6G9f}fXLYgmfW6CA1x+bq^+e!nq|brD-q&F9IGcj?c`spVHDsiITc!j zi#Qz>ia2-ZR6)NL=YYsw>weEsh5TNi0RbbC2jXX&k&)0fu0s9-Rb$DK#H?|dsz5P} zOCNya6`M6K{t9SZL&3&n2tem86l`3E0CXTs8J8gd8A2mW85fGw2h12(Njjks<0@Gz m<~6R8dI67d{T(y