mirror of
https://github.com/wega-team/ss14-wega.git
synced 2026-02-14 19:30:01 +01:00
МбКульт & Gambling^3 (#279)
* refmbcult * fixrule * minich * yeee * linter * somefixes * cultext&gamb * linterfix * fixtarot
This commit is contained in:
@@ -82,6 +82,12 @@ internal sealed class ChatManager : IChatManager
|
||||
_consoleHost.ExecuteCommand($"whisper \"{CommandParsing.Escape(str)}\"");
|
||||
break;
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
case ChatSelectChannel.Mind:
|
||||
_consoleHost.ExecuteCommand($"mindsay \"{CommandParsing.Escape(str)}\"");
|
||||
break;
|
||||
// Corvax-Wega-MindChat-end
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(channel), channel, null);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ using Content.Shared.Chat;
|
||||
using Content.Shared.Damage.ForceSay;
|
||||
using Content.Shared.Decals;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Mind; // Corvax-Wega-MindChat
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Roles.RoleCodeword;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -84,7 +85,8 @@ public sealed partial class ChatUIController : UIController
|
||||
{SharedChatSystem.EmotesAltPrefix, ChatSelectChannel.Emotes},
|
||||
{SharedChatSystem.AdminPrefix, ChatSelectChannel.Admin},
|
||||
{SharedChatSystem.RadioCommonPrefix, ChatSelectChannel.Radio},
|
||||
{SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead}
|
||||
{SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead},
|
||||
{SharedChatSystem.MindPrefix, ChatSelectChannel.Mind} // Corvax-Wega-MindChat
|
||||
};
|
||||
|
||||
public static readonly Dictionary<ChatSelectChannel, char> ChannelPrefixes = new()
|
||||
@@ -97,7 +99,8 @@ public sealed partial class ChatUIController : UIController
|
||||
{ChatSelectChannel.Emotes, SharedChatSystem.EmotesPrefix},
|
||||
{ChatSelectChannel.Admin, SharedChatSystem.AdminPrefix},
|
||||
{ChatSelectChannel.Radio, SharedChatSystem.RadioCommonPrefix},
|
||||
{ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix}
|
||||
{ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix},
|
||||
{ChatSelectChannel.Mind, SharedChatSystem.MindPrefix} // Corvax-Wega-MindChat
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -534,6 +537,7 @@ public sealed partial class ChatUIController : UIController
|
||||
FilterableChannels |= ChatChannel.Whisper;
|
||||
FilterableChannels |= ChatChannel.Radio;
|
||||
FilterableChannels |= ChatChannel.Emotes;
|
||||
FilterableChannels |= ChatChannel.Mind; // Corvax-Wega-MindChat
|
||||
FilterableChannels |= ChatChannel.Notifications;
|
||||
|
||||
// Can only send local / radio / emote when attached to a non-ghost entity.
|
||||
@@ -545,6 +549,8 @@ public sealed partial class ChatUIController : UIController
|
||||
CanSendChannels |= ChatSelectChannel.Radio;
|
||||
CanSendChannels |= ChatSelectChannel.Emotes;
|
||||
}
|
||||
|
||||
CanSendChannels |= ChatSelectChannel.Mind; // Corvax-Wega-MindChat
|
||||
}
|
||||
|
||||
// Only ghosts and admins can send / see deadchat.
|
||||
@@ -692,46 +698,66 @@ public sealed partial class ChatUIController : UIController
|
||||
&& _chatSys.TryProcessRadioMessage(uid, text, out _, out radioChannel, quiet: true);
|
||||
}
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
private bool TryGetMindChannel(string text, out MindChannelPrototype? mindChannel)
|
||||
{
|
||||
mindChannel = null;
|
||||
return _player.LocalEntity is EntityUid { Valid: true } uid
|
||||
&& _chatSys != null
|
||||
&& _chatSys.TryProcessMindMessage(uid, text, out _, out mindChannel, quiet: true);
|
||||
}
|
||||
// Corvax-Wega-MindChat-end
|
||||
|
||||
public void UpdateSelectedChannel(ChatBox box)
|
||||
{
|
||||
var (prefixChannel, _, radioChannel) = SplitInputContents(box.ChatInput.Input.Text.ToLower());
|
||||
var (prefixChannel, text, radioChannel, mindChannel) = SplitInputContents(box.ChatInput.Input.Text.ToLower()); // Corvax-Wega-MindChat-Edit
|
||||
|
||||
if (prefixChannel == ChatSelectChannel.None)
|
||||
box.ChatInput.ChannelSelector.UpdateChannelSelectButton(box.SelectedChannel, null);
|
||||
box.ChatInput.ChannelSelector.UpdateChannelSelectButton(box.SelectedChannel, null, null); // Corvax-Wega-MindChat-Edit
|
||||
else
|
||||
box.ChatInput.ChannelSelector.UpdateChannelSelectButton(prefixChannel, radioChannel);
|
||||
box.ChatInput.ChannelSelector.UpdateChannelSelectButton(prefixChannel, radioChannel, mindChannel); // Corvax-Wega-MindChat-Edit
|
||||
}
|
||||
|
||||
public (ChatSelectChannel chatChannel, string text, RadioChannelPrototype? radioChannel) SplitInputContents(string text)
|
||||
public (ChatSelectChannel chatChannel, string text, RadioChannelPrototype? radioChannel, MindChannelPrototype? mindChannel) SplitInputContents(string text) // Corvax-Wega-MindChat-Edit
|
||||
{
|
||||
text = text.Trim();
|
||||
if (text.Length == 0)
|
||||
return (ChatSelectChannel.None, text, null);
|
||||
return (ChatSelectChannel.None, text, null, null); // Corvax-Wega-MindChat-Edit
|
||||
|
||||
// We only cut off prefix only if it is not a radio or local channel, which both map to the same /say command
|
||||
// because ????????
|
||||
|
||||
// Corvax-Wega-MindChat-Edit-start
|
||||
ChatSelectChannel chatChannel;
|
||||
if (TryGetRadioChannel(text, out var radioChannel))
|
||||
RadioChannelPrototype? radioChannel = null;
|
||||
MindChannelPrototype? mindChannel = null;
|
||||
|
||||
if (TryGetRadioChannel(text, out radioChannel))
|
||||
chatChannel = ChatSelectChannel.Radio;
|
||||
else if (TryGetMindChannel(text, out mindChannel))
|
||||
chatChannel = ChatSelectChannel.Mind;
|
||||
else
|
||||
chatChannel = PrefixToChannel.GetValueOrDefault(text[0]);
|
||||
|
||||
if ((CanSendChannels & chatChannel) == 0)
|
||||
return (ChatSelectChannel.None, text, null);
|
||||
return (ChatSelectChannel.None, text, null, null);
|
||||
|
||||
if (chatChannel == ChatSelectChannel.Radio)
|
||||
return (chatChannel, text, radioChannel);
|
||||
return (chatChannel, text, radioChannel, null);
|
||||
|
||||
if (chatChannel == ChatSelectChannel.Mind)
|
||||
return (chatChannel, text, null, mindChannel);
|
||||
|
||||
if (chatChannel == ChatSelectChannel.Local)
|
||||
{
|
||||
if (_ghost?.IsGhost != true)
|
||||
return (chatChannel, text, null);
|
||||
return (chatChannel, text, null, null);
|
||||
else
|
||||
chatChannel = ChatSelectChannel.Dead;
|
||||
}
|
||||
|
||||
return (chatChannel, text[1..].TrimStart(), null);
|
||||
return (chatChannel, text[1..].TrimStart(), null, null);
|
||||
// Corvax-Wega-MindChat-Edit-end
|
||||
}
|
||||
|
||||
public void SendMessage(ChatBox box, ChatSelectChannel channel)
|
||||
@@ -746,7 +772,7 @@ public sealed partial class ChatUIController : UIController
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
|
||||
(var prefixChannel, text, var _) = SplitInputContents(text);
|
||||
(var prefixChannel, text, var _, var _) = SplitInputContents(text); // Corvax-Wega-MindChat-Edit
|
||||
|
||||
// Check if message is longer than the character limit
|
||||
if (text.Length > MaxMessageLength)
|
||||
@@ -764,6 +790,12 @@ public sealed partial class ChatUIController : UIController
|
||||
// radio must have prefix as it goes through the say command.
|
||||
text = $";{text}";
|
||||
}
|
||||
// Corvax-Wega-MindChat-start
|
||||
else if (channel == ChatSelectChannel.Mind)
|
||||
{
|
||||
text = $"+{text}";
|
||||
}
|
||||
// Corvax-Wega-MindChat-end
|
||||
|
||||
_manager.SendMessage(text, prefixChannel == 0 ? channel : prefixChannel);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed partial class ChannelFilterPopup : Popup
|
||||
ChatChannel.LOOC,
|
||||
ChatChannel.OOC,
|
||||
ChatChannel.Dead,
|
||||
ChatChannel.Mind, // Corvax-Wega-MindChat
|
||||
ChatChannel.Admin,
|
||||
ChatChannel.AdminAlert,
|
||||
ChatChannel.AdminChat,
|
||||
|
||||
@@ -63,14 +63,30 @@ public sealed class ChannelSelectorButton : ChatPopupButton<ChannelSelectorPopup
|
||||
ChatSelectChannel.LOOC => Color.MediumTurquoise,
|
||||
ChatSelectChannel.OOC => Color.LightSkyBlue,
|
||||
ChatSelectChannel.Dead => Color.MediumPurple,
|
||||
ChatSelectChannel.Mind => Color.Peru, // Corvax-Wega-MindChat
|
||||
ChatSelectChannel.Admin => Color.HotPink,
|
||||
_ => Color.DarkGray
|
||||
};
|
||||
}
|
||||
|
||||
public void UpdateChannelSelectButton(ChatSelectChannel channel, Shared.Radio.RadioChannelPrototype? radio)
|
||||
// Corvax-Wega-MindChat-Edit-start
|
||||
public void UpdateChannelSelectButton(ChatSelectChannel channel, Shared.Radio.RadioChannelPrototype? radio, Shared.Mind.MindChannelPrototype? mind)
|
||||
{
|
||||
Text = radio != null ? Loc.GetString(radio.Name) : ChannelSelectorName(channel);
|
||||
Modulate = radio?.Color ?? ChannelSelectColor(channel);
|
||||
if (radio != null)
|
||||
{
|
||||
Text = Loc.GetString(radio.Name);
|
||||
Modulate = radio.Color;
|
||||
}
|
||||
else if (mind != null)
|
||||
{
|
||||
Text = Loc.GetString(mind.Name);
|
||||
Modulate = mind.Color;
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = ChannelSelectorName(channel);
|
||||
Modulate = ChannelSelectColor(channel);
|
||||
}
|
||||
}
|
||||
// Corvax-Wega-MindChat-Edit-end
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public sealed class ChannelSelectorPopup : Popup
|
||||
ChatSelectChannel.LOOC,
|
||||
ChatSelectChannel.OOC,
|
||||
ChatSelectChannel.Dead,
|
||||
ChatSelectChannel.Mind, // Corvax-Wega-MindChat
|
||||
ChatSelectChannel.Admin
|
||||
// NOTE: Console is not in there and it can never be permanently selected.
|
||||
// You can, however, still submit commands as console by prefixing with /.
|
||||
|
||||
@@ -6,7 +6,6 @@ using Content.Shared.StatusIcon.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Blood.Cult
|
||||
{
|
||||
@@ -24,9 +23,8 @@ namespace Content.Client.Blood.Cult
|
||||
SubscribeLocalEvent<BloodRuneComponent, AppearanceChangeEvent>(OnRuneAppearanceChanged);
|
||||
SubscribeLocalEvent<BloodRitualDimensionalRendingComponent, AppearanceChangeEvent>(OnRuneAppearanceChanged);
|
||||
SubscribeLocalEvent<BloodCultistComponent, GetStatusIconsEvent>(GetCultistIcons);
|
||||
SubscribeLocalEvent<PentagramDisplayComponent, ComponentStartup>(GetHalo);
|
||||
SubscribeLocalEvent<PentagramDisplayComponent, ComponentShutdown>(RemoveHalo);
|
||||
SubscribeLocalEvent<StoneSoulComponent, AppearanceChangeEvent>(OnSoulStoneAppearanceChanged);
|
||||
SubscribeLocalEvent<BloodPentagramDisplayComponent, ComponentStartup>(GetHalo);
|
||||
SubscribeLocalEvent<BloodPentagramDisplayComponent, ComponentShutdown>(RemoveHalo);
|
||||
}
|
||||
|
||||
private void OnRuneAppearanceChanged(Entity<BloodRuneComponent> entity, ref AppearanceChangeEvent args)
|
||||
@@ -51,7 +49,7 @@ namespace Content.Client.Blood.Cult
|
||||
args.StatusIcons.Add(iconPrototype);
|
||||
}
|
||||
|
||||
private void GetHalo(EntityUid uid, PentagramDisplayComponent component, ComponentStartup args)
|
||||
private void GetHalo(EntityUid uid, BloodPentagramDisplayComponent component, ComponentStartup args)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
||||
return;
|
||||
@@ -77,28 +75,10 @@ namespace Content.Client.Blood.Cult
|
||||
_sprite.LayerMapSet(uid, PentagramKey.Halo, layer);
|
||||
}
|
||||
|
||||
private void RemoveHalo(EntityUid uid, PentagramDisplayComponent component, ComponentShutdown args)
|
||||
private void RemoveHalo(EntityUid uid, BloodPentagramDisplayComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (_sprite.LayerMapTryGet(uid, PentagramKey.Halo, out var layer, true))
|
||||
{
|
||||
_sprite.RemoveLayer(uid, layer);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSoulStoneAppearanceChanged(EntityUid uid, StoneSoulComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (!_appearance.TryGetData(uid, StoneSoulVisuals.HasSoul, out bool hasSoul))
|
||||
hasSoul = false;
|
||||
|
||||
_sprite.LayerSetVisible(uid, StoneSoulVisualLayers.Soul, hasSoul);
|
||||
if (!hasSoul)
|
||||
{
|
||||
_sprite.LayerSetVisible(uid, StoneSoulVisualLayers.Base, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sprite.LayerSetVisible(uid, StoneSoulVisualLayers.Base, false);
|
||||
}
|
||||
}
|
||||
|
||||
private enum PentagramKey
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class BloodConstructBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private BloodConstructMenu? _menu;
|
||||
|
||||
public BloodConstructBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<BloodConstructMenu>();
|
||||
_menu.OnSelectConstruct += construct =>
|
||||
{
|
||||
SendMessage(new BloodConstructSelectMessage(construct));
|
||||
Close();
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,27 @@
|
||||
<ui:RadialMenu xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:local="clr-namespace:Content.Client.Select.Construct.UI;assembly=Content.Client"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Content.Client.Select.Construct.UI.BloodConstructMenu"
|
||||
CloseButtonStyleClass="RadialMenuCloseButton"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
MinSize="450 450">
|
||||
VerticalExpand="True" HorizontalExpand="True">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" ReserveSpaceForHiddenChildren="False">
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="128" ReserveSpaceForHiddenChildren="False">
|
||||
<!-- Juggernaut -->
|
||||
<ui:RadialMenuButton Name="BloodJuggernautButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-constuct-juggernaut'}" TargetLayerControlName="BloodJuggernaut">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/juggernaut.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/juggernaut.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Wraith -->
|
||||
<ui:RadialMenuButton Name="BloodWraithButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-constuct-wraith'}" TargetLayerControlName="BloodWraith">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/wraith.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/wraith.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Artificer -->
|
||||
<ui:RadialMenuButton Name="BloodArtificerButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-constuct-artificer'}" TargetLayerControlName="BloodArtificer">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/artificer.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/artificer.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Proteon -->
|
||||
<ui:RadialMenuButton Name="BloodProteonButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-constuct-proteon'}" TargetLayerControlName="BloodProteon">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/proteon.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/proteon.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
@@ -1,49 +1,31 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Select.Construct.UI;
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BloodConstructMenu : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
|
||||
public event Action<string>? OnSelectConstruct;
|
||||
private NetEntity _constructUid;
|
||||
private NetEntity _mindUid;
|
||||
|
||||
public BloodConstructMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
private void InitializeButtons()
|
||||
{
|
||||
BloodJuggernautButton.OnButtonUp += _ => HandleRitesSelection("MobConstructJuggernaut");
|
||||
BloodWraithButton.OnButtonUp += _ => HandleRitesSelection("MobConstructWraith");
|
||||
BloodArtificerButton.OnButtonUp += _ => HandleRitesSelection("MobConstructArtificer");
|
||||
BloodProteonButton.OnButtonUp += _ => HandleRitesSelection("MobConstructProteon");
|
||||
BloodJuggernautButton.OnButtonUp += _ => HandleConstructSelection("MobConstructJuggernaut");
|
||||
BloodWraithButton.OnButtonUp += _ => HandleConstructSelection("MobConstructWraith");
|
||||
BloodArtificerButton.OnButtonUp += _ => HandleConstructSelection("MobConstructArtificer");
|
||||
BloodProteonButton.OnButtonUp += _ => HandleConstructSelection("MobConstructProteon");
|
||||
}
|
||||
|
||||
public void SetData(NetEntity constructUid, NetEntity mindUid)
|
||||
{
|
||||
_constructUid = constructUid;
|
||||
_mindUid = mindUid;
|
||||
}
|
||||
|
||||
private void HandleRitesSelection(string constructName)
|
||||
private void HandleConstructSelection(string constructName)
|
||||
{
|
||||
OnSelectConstruct?.Invoke(constructName);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new BloodConstructMenuClosedEvent(netEntity, _constructUid, _mindUid, constructName));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
|
||||
namespace Content.Client.Select.Construct.UI
|
||||
{
|
||||
public sealed class BloodConstructMenuUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private BloodConstructMenu? _menu;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<OpenConstructMenuEvent>(OnConstructMenuReceived);
|
||||
}
|
||||
|
||||
private void OnConstructMenuReceived(OpenConstructMenuEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var session = IoCManager.Resolve<IPlayerManager>().LocalSession;
|
||||
var userEntity = _entityManager.GetEntity(args.Uid);
|
||||
|
||||
if (session?.AttachedEntity.HasValue == true && session.AttachedEntity.Value == userEntity)
|
||||
{
|
||||
if (_menu is null)
|
||||
{
|
||||
_menu = _uiManager.CreateWindow<BloodConstructMenu>();
|
||||
|
||||
_menu.SetData(args.ConstructUid, args.Mind);
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
else
|
||||
{
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
Timer.Spawn(30000, () =>
|
||||
{
|
||||
if (_menu != null)
|
||||
{
|
||||
_menu.Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Content.Client/_Wega/BloodCult/Ui/BloodMagicEui.cs
Normal file
31
Content.Client/_Wega/BloodCult/Ui/BloodMagicEui.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Content.Client.Eui;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class BloodMagicEui : BaseEui
|
||||
{
|
||||
private readonly BloodMagicMenu _menu;
|
||||
|
||||
public BloodMagicEui()
|
||||
{
|
||||
_menu = new BloodMagicMenu();
|
||||
_menu.OnSelectedSpell += spell =>
|
||||
{
|
||||
SendMessage(new BloodMagicSelectSpellMessage(spell));
|
||||
_menu.Close();
|
||||
};
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
public override void Closed()
|
||||
{
|
||||
_menu.Close();
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,57 @@
|
||||
<ui:RadialMenu xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:local="clr-namespace:Content.Client.Blood.Magic.UI;assembly=Content.Client"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Content.Client.Blood.Magic.UI.BloodMagicMenu"
|
||||
CloseButtonStyleClass="RadialMenuCloseButton"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
MinSize="450 450">
|
||||
VerticalExpand="True" HorizontalExpand="True">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" ReserveSpaceForHiddenChildren="False">
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="128" ReserveSpaceForHiddenChildren="False">
|
||||
<!-- Stun -->
|
||||
<ui:RadialMenuButton Name="StunButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-stun'}" TargetLayerControlName="Stun">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/stun.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/stun.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Teleport -->
|
||||
<ui:RadialMenuButton Name="TeleportButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-teleport'}" TargetLayerControlName="Teleport">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/teleport.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/teleport.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Electromagnetic Pulse -->
|
||||
<ui:RadialMenuButton Name="ElectromagneticPulseButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-electromagnetic-pulse'}" TargetLayerControlName="ElectromagneticPulse">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/electromagneticpulse.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/electromagneticpulse.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Shadow Shackles -->
|
||||
<ui:RadialMenuButton Name="ShadowShacklesButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-shadow-shackles'}" TargetLayerControlName="ShadowShackles">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/shadowshackles.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/shadowshackles.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Twisted Construction -->
|
||||
<ui:RadialMenuButton Name="TwistedConstructionButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-twisted-construction'}" TargetLayerControlName="TwistedConstruction">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/twistedconstruction.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/twistedconstruction.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Summon Equipment -->
|
||||
<ui:RadialMenuButton Name="SummonEquipmentButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-summon-equipment'}" TargetLayerControlName="SummonEquipment">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/summonequipment.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/summonequipment.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Summon Dagger -->
|
||||
<ui:RadialMenuButton Name="SummonDaggerButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-summon-dagger'}" TargetLayerControlName="SummonDagger">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/dagger.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/dagger.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Hallucinations -->
|
||||
<ui:RadialMenuButton Name="HallucinationsButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-hallucinations'}" TargetLayerControlName="Hallucinations">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/hallucinations.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/hallucinations.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Conceal Presence -->
|
||||
<ui:RadialMenuButton Name="ConcealPresenceButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-conceal-presence'}" TargetLayerControlName="ConcealPresence">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/concealpresence.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/concealpresence.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Blood Rites -->
|
||||
<ui:RadialMenuButton Name="BloodRitesButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-blood-rites'}" TargetLayerControlName="BloodRites">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/blood_rites.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/blood_rites.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Blood.Magic.UI;
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BloodMagicMenu : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
|
||||
public event Action<string>? OnSelectSpell;
|
||||
public event Action<EntProtoId>? OnSelectedSpell;
|
||||
|
||||
public BloodMagicMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
@@ -37,12 +30,9 @@ public sealed partial class BloodMagicMenu : RadialMenu
|
||||
BloodRitesButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultBloodRites");
|
||||
}
|
||||
|
||||
private void HandleSpellSelection(string spellName)
|
||||
private void HandleSpellSelection(EntProtoId spell)
|
||||
{
|
||||
OnSelectSpell?.Invoke(spellName);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new BloodMagicMenuClosedEvent(netEntity, spellName));
|
||||
Close();
|
||||
OnSelectedSpell?.Invoke(spell);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
|
||||
namespace Content.Client.Blood.Magic.UI
|
||||
{
|
||||
public sealed class BloodMagicMenuUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private BloodMagicMenu? _menu;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<BloodMagicPressedEvent>(OnBloodMagicMenuReceived);
|
||||
}
|
||||
|
||||
private void OnBloodMagicMenuReceived(BloodMagicPressedEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var session = IoCManager.Resolve<IPlayerManager>().LocalSession;
|
||||
var userEntity = _entityManager.GetEntity(args.Uid);
|
||||
if (session?.AttachedEntity.HasValue == true && session.AttachedEntity.Value == userEntity)
|
||||
{
|
||||
if (_menu is null)
|
||||
{
|
||||
_menu = _uiManager.CreateWindow<BloodMagicMenu>();
|
||||
_menu.OnClose += OnMenuClosed;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
else
|
||||
{
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMenuClosed()
|
||||
{
|
||||
_menu = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
public sealed class BloodRitesBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private BloodRitesMenu? _menu;
|
||||
|
||||
public BloodRitesBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<BloodRitesMenu>();
|
||||
_menu.OnSelectRites += rites =>
|
||||
{
|
||||
SendMessage(new BloodRitesSelectRitesMessage(rites));
|
||||
Close();
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,27 @@
|
||||
<ui:RadialMenu xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:local="clr-namespace:Content.Client.Blood.Rites.UI;assembly=Content.Client"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Content.Client.Blood.Rites.UI.BloodRitesMenu"
|
||||
CloseButtonStyleClass="RadialMenuCloseButton"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
MinSize="450 450">
|
||||
VerticalExpand="True" HorizontalExpand="True">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" ReserveSpaceForHiddenChildren="False">
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="128" ReserveSpaceForHiddenChildren="False">
|
||||
<!-- Blood Orb -->
|
||||
<ui:RadialMenuButton Name="BloodOrbButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-blood-orb'}" TargetLayerControlName="BloodOrb">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/orb.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/orb.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Blood Recharge -->
|
||||
<ui:RadialMenuButton Name="BloodRechargeButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-blood-recharge'}" TargetLayerControlName="BloodRecharge">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/recharge.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/recharge.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Blood Spear -->
|
||||
<ui:RadialMenuButton Name="BloodSpearButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-blood-spear'}" TargetLayerControlName="BloodSpear">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/spear.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/spear.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Blood Bolt Barrage -->
|
||||
<ui:RadialMenuButton Name="BloodBoltBarrageButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-blood-bolt-barrage'}" TargetLayerControlName="BloodBoltBarrage">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/barrage.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/barrage.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Blood.Rites.UI;
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BloodRitesMenu : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
|
||||
public event Action<string>? OnSelectRites;
|
||||
public event Action<EntProtoId>? OnSelectRites;
|
||||
|
||||
public BloodRitesMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
@@ -31,12 +24,9 @@ public sealed partial class BloodRitesMenu : RadialMenu
|
||||
BloodBoltBarrageButton.OnButtonUp += _ => HandleRitesSelection("ActionBloodCultBoltBarrage");
|
||||
}
|
||||
|
||||
private void HandleRitesSelection(string ritesName)
|
||||
private void HandleRitesSelection(EntProtoId rites)
|
||||
{
|
||||
OnSelectRites?.Invoke(ritesName);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new BloodRitesMenuClosedEvent(netEntity, ritesName));
|
||||
OnSelectRites?.Invoke(rites);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
|
||||
namespace Content.Client.Blood.Rites.UI
|
||||
{
|
||||
public sealed class BloodRitesMenuUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private BloodRitesMenu? _menu;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<BloodRitesPressedEvent>(OnBloodMagicMenuReceived);
|
||||
}
|
||||
|
||||
private void OnBloodMagicMenuReceived(BloodRitesPressedEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var session = IoCManager.Resolve<IPlayerManager>().LocalSession;
|
||||
var userEntity = _entityManager.GetEntity(args.Uid);
|
||||
if (session?.AttachedEntity.HasValue == true && session.AttachedEntity.Value == userEntity)
|
||||
{
|
||||
if (_menu is null)
|
||||
{
|
||||
_menu = _uiManager.CreateWindow<BloodRitesMenu>();
|
||||
_menu.OnClose += OnMenuClosed;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
else
|
||||
{
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMenuClosed()
|
||||
{
|
||||
_menu = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class BloodStructureBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private BloodStructureMenu? _menu;
|
||||
|
||||
public BloodStructureBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<BloodStructureMenu>();
|
||||
_menu.OnSelectItem += item =>
|
||||
{
|
||||
SendMessage(new BloodStructureSelectMessage(item));
|
||||
Close();
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (state is BloodStructureBoundUserInterfaceState structureState)
|
||||
_menu?.InitializeButtons(structureState);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,9 @@
|
||||
<ui:RadialMenu xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:local="clr-namespace:Content.Client.Structure.UI;assembly=Content.Client"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Content.Client.Structure.UI.BloodStructureMenu"
|
||||
CloseButtonStyleClass="RadialMenuCloseButton"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
MinSize="450 450">
|
||||
VerticalExpand="True" HorizontalExpand="True">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" ReserveSpaceForHiddenChildren="False">
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="128" ReserveSpaceForHiddenChildren="False">
|
||||
</ui:RadialContainer>
|
||||
|
||||
</ui:RadialMenu>
|
||||
|
||||
@@ -1,48 +1,33 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Structure.UI;
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BloodStructureMenu : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public event Action<string>? OnSelectItem;
|
||||
private NetEntity _structure;
|
||||
|
||||
public BloodStructureMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
IoCManager.Instance!.InjectDependencies(this);
|
||||
}
|
||||
|
||||
public void SetData(NetEntity structure)
|
||||
public void InitializeButtons(BloodStructureBoundUserInterfaceState state)
|
||||
{
|
||||
_structure = structure;
|
||||
InitializeButtons();
|
||||
}
|
||||
Main.RemoveAllChildren();
|
||||
|
||||
private void InitializeButtons()
|
||||
{
|
||||
var structure = _entityManager.GetEntity(_structure);
|
||||
if (!_entityManager.TryGetComponent<BloodStructureComponent>(structure, out var structureComp)
|
||||
|| structureComp.StructureGear.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var prototypeId in structureComp.StructureGear)
|
||||
foreach (var prototypeId in state.Items)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex<EntityPrototype>(prototypeId, out var prototype))
|
||||
if (!_proto.TryIndex(prototypeId, out var prototype))
|
||||
continue;
|
||||
|
||||
var button = new RadialMenuButton
|
||||
@@ -75,8 +60,6 @@ public sealed partial class BloodStructureMenu : RadialMenu
|
||||
private void HandleItemSelection(string name)
|
||||
{
|
||||
OnSelectItem?.Invoke(name);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new BloodStructureMenuClosedEvent(netEntity, name, _structure));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
|
||||
namespace Content.Client.Structure.UI
|
||||
{
|
||||
public sealed class BloodStructureMenuUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private BloodStructureMenu? _menu;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeNetworkEvent<OpenStructureMenuEvent>(OnStructureMenuReceived);
|
||||
}
|
||||
|
||||
private void OnStructureMenuReceived(OpenStructureMenuEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var session = IoCManager.Resolve<IPlayerManager>().LocalSession;
|
||||
var userEntity = _entityManager.GetEntity(args.Uid);
|
||||
if (session?.AttachedEntity.HasValue == true && session.AttachedEntity.Value == userEntity)
|
||||
{
|
||||
if (_menu is null)
|
||||
{
|
||||
_menu = _uiManager.CreateWindow<BloodStructureMenu>();
|
||||
_menu.OnClose += OnMenuClosed;
|
||||
|
||||
_menu.SetData(args.Structure);
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
else
|
||||
{
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
Timer.Spawn(30000, () =>
|
||||
{
|
||||
if (_menu != null)
|
||||
{
|
||||
_menu.Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMenuClosed()
|
||||
{
|
||||
_menu = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
public sealed class EmpoweringRuneBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private EmpoweringRuneMenu? _menu;
|
||||
|
||||
public EmpoweringRuneBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<EmpoweringRuneMenu>();
|
||||
_menu.OnSelectSpell += spell =>
|
||||
{
|
||||
SendMessage(new EmpoweringRuneSelectSpellMessage(spell));
|
||||
Close();
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,57 @@
|
||||
<ui:RadialMenu xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:local="clr-namespace:Content.Client.Runes.Panel.Ui;assembly=Content.Client"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Content.Client.Runes.Panel.Ui.EmpoweringRuneMenu"
|
||||
CloseButtonStyleClass="RadialMenuCloseButton"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
MinSize="450 450">
|
||||
VerticalExpand="True" HorizontalExpand="True">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" ReserveSpaceForHiddenChildren="False">
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="128" ReserveSpaceForHiddenChildren="False">
|
||||
<!-- Stun -->
|
||||
<ui:RadialMenuButton Name="StunButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-stun'}" TargetLayerControlName="Stun">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/stun.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/stun.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Teleport -->
|
||||
<ui:RadialMenuButton Name="TeleportButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-teleport'}" TargetLayerControlName="Teleport">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/teleport.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/teleport.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Electromagnetic Pulse -->
|
||||
<ui:RadialMenuButton Name="ElectromagneticPulseButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-electromagnetic-pulse'}" TargetLayerControlName="ElectromagneticPulse">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/electromagneticpulse.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/electromagneticpulse.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Shadow Shackles -->
|
||||
<ui:RadialMenuButton Name="ShadowShacklesButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-shadow-shackles'}" TargetLayerControlName="ShadowShackles">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/shadowshackles.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/shadowshackles.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Twisted Construction -->
|
||||
<ui:RadialMenuButton Name="TwistedConstructionButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-twisted-construction'}" TargetLayerControlName="TwistedConstruction">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/twistedconstruction.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/twistedconstruction.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Summon Equipment -->
|
||||
<ui:RadialMenuButton Name="SummonEquipmentButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-summon-equipment'}" TargetLayerControlName="SummonEquipment">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/summonequipment.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/summonequipment.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Summon Dagger -->
|
||||
<ui:RadialMenuButton Name="SummonDaggerButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-summon-dagger'}" TargetLayerControlName="SummonDagger">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/dagger.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/dagger.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Hallucinations -->
|
||||
<ui:RadialMenuButton Name="HallucinationsButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-hallucinations'}" TargetLayerControlName="Hallucinations">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/hallucinations.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/hallucinations.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Conceal Presence -->
|
||||
<ui:RadialMenuButton Name="ConcealPresenceButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-conceal-presence'}" TargetLayerControlName="ConcealPresence">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/concealpresence.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/concealpresence.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Blood Rites -->
|
||||
<ui:RadialMenuButton Name="BloodRitesButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-spell-blood-rites'}" TargetLayerControlName="BloodRites">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/blood_rites.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/actions_bloodcult.rsi/blood_rites.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
38
Content.Client/_Wega/BloodCult/Ui/EmpoweringRuneMenu.xaml.cs
Normal file
38
Content.Client/_Wega/BloodCult/Ui/EmpoweringRuneMenu.xaml.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class EmpoweringRuneMenu : RadialMenu
|
||||
{
|
||||
public event Action<EntProtoId>? OnSelectSpell;
|
||||
|
||||
public EmpoweringRuneMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
private void InitializeButtons()
|
||||
{
|
||||
StunButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultStun");
|
||||
TeleportButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultTeleport");
|
||||
ElectromagneticPulseButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultElectromagneticPulse");
|
||||
ShadowShacklesButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultShadowShackles");
|
||||
TwistedConstructionButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultTwistedConstruction");
|
||||
SummonEquipmentButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultSummonEquipment");
|
||||
SummonDaggerButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultSummonDagger");
|
||||
HallucinationsButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultHallucinations");
|
||||
ConcealPresenceButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultConcealPresence");
|
||||
BloodRitesButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultBloodRites");
|
||||
}
|
||||
|
||||
private void HandleSpellSelection(EntProtoId spell)
|
||||
{
|
||||
OnSelectSpell?.Invoke(spell);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,9 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
x:Class="Content.Client.Runes.Panel.Ui.RunesPanelMenu"
|
||||
Title="{Loc 'runes-ui-default-title'}"
|
||||
MinSize="256 256"
|
||||
SetSize="256 256">
|
||||
<ui:RadialMenu xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
CloseButtonStyleClass="RadialMenuCloseButton"
|
||||
VerticalExpand="True" HorizontalExpand="True">
|
||||
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" Margin="4">
|
||||
<PanelContainer VerticalExpand="True">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#80808005" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="128" ReserveSpaceForHiddenChildren="False">
|
||||
</ui:RadialContainer>
|
||||
|
||||
<ScrollContainer Name="Scroll" HScrollEnabled="False" VerticalExpand="True">
|
||||
<BoxContainer Name="RunesContainer" Orientation="Vertical" VerticalExpand="True">
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
</ui:RadialMenu>
|
||||
|
||||
@@ -1,162 +1,74 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Runes.Panel.Ui;
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
public sealed partial class RunesPanelMenu : DefaultWindow
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class RunesMenu : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public event Action<string>? OnRuneSelected;
|
||||
public BoxContainer RunesContainer => this.FindControl<BoxContainer>("RunesContainer");
|
||||
public event Action<EntProtoId>? OnRuneSelected;
|
||||
|
||||
public RunesPanelMenu()
|
||||
public RunesMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
IoCManager.Instance!.InjectDependencies(this);
|
||||
InitializeRunes();
|
||||
}
|
||||
|
||||
private void InitializeRunes()
|
||||
{
|
||||
AddRuneButton(Loc.GetString("offering-rune"), "BloodRuneOffering");
|
||||
AddRuneButton(Loc.GetString("teleport-rune"), "BloodRuneTeleport");
|
||||
AddRuneButton(Loc.GetString("empowering-rune"), "BloodRuneEmpowering");
|
||||
AddRuneButton(Loc.GetString("revive-rune"), "BloodRuneRevive");
|
||||
AddRuneButton(Loc.GetString("barrier-rune"), "BloodRuneBarrier");
|
||||
AddRuneButton(Loc.GetString("summoning-rune"), "BloodRuneSummoning");
|
||||
AddRuneButton(Loc.GetString("bloodboil-rune"), "BloodRuneBloodBoil");
|
||||
AddRuneButton(Loc.GetString("spiritrealm-rune"), "BloodRuneSpiritealm");
|
||||
AddRuneButton(Loc.GetString("ritual-dimensional-rending-rune"), "BloodRuneRitualDimensionalRending");
|
||||
AddRuneButton("offering-rune", "BloodRuneOffering");
|
||||
AddRuneButton("teleport-rune", "BloodRuneTeleport");
|
||||
AddRuneButton("empowering-rune", "BloodRuneEmpowering");
|
||||
AddRuneButton("revive-rune", "BloodRuneRevive");
|
||||
AddRuneButton("barrier-rune", "BloodRuneBarrier");
|
||||
AddRuneButton("summoning-rune", "BloodRuneSummoning");
|
||||
AddRuneButton("bloodboil-rune", "BloodRuneBloodBoil");
|
||||
AddRuneButton("spiritrealm-rune", "BloodRuneSpiritealm");
|
||||
}
|
||||
|
||||
public void AddRitualButton()
|
||||
{
|
||||
AddRuneButton("ritual-dimensional-rending-rune", "BloodRuneRitualDimensionalRending");
|
||||
}
|
||||
|
||||
private void AddRuneButton(string runeName, string protoId)
|
||||
{
|
||||
var button = new Button
|
||||
if (!_proto.TryIndex(protoId, out var prototype))
|
||||
return;
|
||||
|
||||
var button = new RadialMenuButton
|
||||
{
|
||||
Text = runeName,
|
||||
MinSize = new Vector2(300, 32),
|
||||
MaxSize = new Vector2(300, 32),
|
||||
HorizontalAlignment = HAlignment.Center,
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
ToolTip = Loc.GetString(runeName) + $"\n{Loc.GetString(runeName + "-desc")}",
|
||||
SetSize = new Vector2(64, 64),
|
||||
};
|
||||
|
||||
button.StyleClasses.Add("RadialMenuButton");
|
||||
|
||||
var entityView = new EntityPrototypeView
|
||||
{
|
||||
Scale = new Vector2(2, 2),
|
||||
SetSize = new Vector2(64, 64),
|
||||
Margin = new Thickness(4)
|
||||
};
|
||||
entityView.SetPrototype(prototype.ID);
|
||||
|
||||
button.AddChild(entityView);
|
||||
|
||||
button.OnPressed += _ => HandleRuneSelection(protoId);
|
||||
|
||||
RunesContainer.AddChild(button);
|
||||
Main.AddChild(button);
|
||||
}
|
||||
|
||||
private void HandleRuneSelection(string protoId)
|
||||
private void HandleRuneSelection(EntProtoId protoId)
|
||||
{
|
||||
OnRuneSelected?.Invoke(protoId);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new RuneSelectEvent(netEntity, protoId));
|
||||
Close();
|
||||
}
|
||||
|
||||
public new void Close()
|
||||
{
|
||||
base.Close();
|
||||
}
|
||||
}
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class EmpoweringRuneMenu : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
|
||||
public event Action<string>? OnSelectSpell;
|
||||
|
||||
public EmpoweringRuneMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
private void InitializeButtons()
|
||||
{
|
||||
StunButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultStun");
|
||||
TeleportButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultTeleport");
|
||||
ElectromagneticPulseButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultElectromagneticPulse");
|
||||
ShadowShacklesButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultShadowShackles");
|
||||
TwistedConstructionButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultTwistedConstruction");
|
||||
SummonEquipmentButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultSummonEquipment");
|
||||
SummonDaggerButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultSummonDagger");
|
||||
HallucinationsButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultHallucinations");
|
||||
ConcealPresenceButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultConcealPresence");
|
||||
BloodRitesButton.OnButtonUp += _ => HandleSpellSelection("ActionBloodCultBloodRites");
|
||||
}
|
||||
|
||||
private void HandleSpellSelection(string spellName)
|
||||
{
|
||||
OnSelectSpell?.Invoke(spellName);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new EmpoweringRuneMenuClosedEvent(netEntity, spellName));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class SummoningRunePanelMenu : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
|
||||
public BoxContainer CultistsContainer => this.FindControl<BoxContainer>("CultistsContainer");
|
||||
|
||||
public SummoningRunePanelMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
private void InitializeButtons()
|
||||
{
|
||||
var cultistQuery = _entityManager.EntityQueryEnumerator<BloodCultistComponent, MetaDataComponent>();
|
||||
while (cultistQuery.MoveNext(out var uid, out _, out var metaData))
|
||||
{
|
||||
var entityName = metaData.EntityName;
|
||||
AddCultistButton(entityName, uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCultistButton(string cultistName, EntityUid cultistUid)
|
||||
{
|
||||
var button = new Button
|
||||
{
|
||||
Text = cultistName,
|
||||
HorizontalAlignment = HAlignment.Center,
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
MinSize = new Vector2(300, 32),
|
||||
MaxSize = new Vector2(300, 32)
|
||||
};
|
||||
|
||||
button.OnPressed += _ => HandleCultistSelection(cultistUid);
|
||||
|
||||
CultistsContainer.AddChild(button);
|
||||
}
|
||||
|
||||
private void HandleCultistSelection(EntityUid cultistUid)
|
||||
{
|
||||
var netTargerEntity = _entityManager.GetNetEntity(cultistUid);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new SummoningSelectedEvent(netEntity, netTargerEntity));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class RunesMenuBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private RunesMenu? _menu;
|
||||
|
||||
public RunesMenuBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<RunesMenu>();
|
||||
_menu.OnRuneSelected += rune =>
|
||||
{
|
||||
SendMessage(new SelectBloodRuneMessage(rune));
|
||||
Close();
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (state is BloodRitualBoundUserInterfaceState _)
|
||||
_menu?.AddRitualButton();
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
|
||||
namespace Content.Client.Runes.Panel.Ui
|
||||
{
|
||||
public sealed class RunesMenuUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private RunesPanelMenu? _panel;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<RunesMenuOpenedEvent>(OnRunesMenuReceived);
|
||||
}
|
||||
|
||||
private void OnRunesMenuReceived(RunesMenuOpenedEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var session = IoCManager.Resolve<IPlayerManager>().LocalSession;
|
||||
var userEntity = _entityManager.GetEntity(args.Uid);
|
||||
if (session?.AttachedEntity.HasValue == true && session.AttachedEntity.Value == userEntity)
|
||||
{
|
||||
if (_panel is null)
|
||||
{
|
||||
_panel = _uiManager.CreateWindow<RunesPanelMenu>();
|
||||
_panel.OnClose += OnMenuClosed;
|
||||
_panel.OpenCentered();
|
||||
}
|
||||
else
|
||||
{
|
||||
_panel.OpenCentered();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMenuClosed()
|
||||
{
|
||||
_panel = null;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class EmpoweringRuneMenuUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private EmpoweringRuneMenu? _menu;
|
||||
private bool _menuDisposed = false;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<EmpoweringRuneMenuOpenedEvent>(OnRuneMenuReceived);
|
||||
}
|
||||
|
||||
private void OnRuneMenuReceived(EmpoweringRuneMenuOpenedEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var session = IoCManager.Resolve<IPlayerManager>().LocalSession;
|
||||
var userEntity = _entityManager.GetEntity(args.Uid);
|
||||
if (session?.AttachedEntity.HasValue == true && session.AttachedEntity.Value == userEntity)
|
||||
{
|
||||
if (_menu is null)
|
||||
{
|
||||
_menu = _uiManager.CreateWindow<EmpoweringRuneMenu>();
|
||||
_menu.OnClose += OnMenuClosed;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
else
|
||||
{
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
}
|
||||
|
||||
Timer.Spawn(30000, () =>
|
||||
{
|
||||
if (_menu != null && !_menuDisposed)
|
||||
{
|
||||
_menu.Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void OnMenuClosed()
|
||||
{
|
||||
_menuDisposed = true;
|
||||
_menu = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public sealed class SummoningRuneMenuUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private SummoningRunePanelMenu? _panel;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<SummoningRuneMenuOpenedEvent>(OnRuneMenuReceived);
|
||||
}
|
||||
|
||||
private void OnRuneMenuReceived(SummoningRuneMenuOpenedEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var session = IoCManager.Resolve<IPlayerManager>().LocalSession;
|
||||
var userEntity = _entityManager.GetEntity(args.Uid);
|
||||
if (session?.AttachedEntity.HasValue == true && session.AttachedEntity.Value == userEntity)
|
||||
{
|
||||
if (_panel is null)
|
||||
{
|
||||
_panel = _uiManager.CreateWindow<SummoningRunePanelMenu>();
|
||||
_panel.OnClose += OnMenuClosed;
|
||||
_panel.OpenCentered();
|
||||
}
|
||||
else
|
||||
{
|
||||
_panel.OpenCentered();
|
||||
}
|
||||
|
||||
Timer.Spawn(30000, () =>
|
||||
{
|
||||
if (_panel != null)
|
||||
{
|
||||
_panel.Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMenuClosed()
|
||||
{
|
||||
_panel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
public sealed class SummoningRuneBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private SummoningRuneMenu? _menu;
|
||||
|
||||
public SummoningRuneBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<SummoningRuneMenu>();
|
||||
_menu.OnCultistSelected += cultist =>
|
||||
{
|
||||
SendMessage(new SummoningRuneSelectCultistMessage(cultist));
|
||||
Close();
|
||||
};
|
||||
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
<DefaultWindow
|
||||
<controls:FancyWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
x:Class="Content.Client.Runes.Panel.Ui.SummoningRunePanelMenu"
|
||||
Title="{Loc 'runes-ui-default-title'}"
|
||||
MinSize="512 340"
|
||||
SetSize="512 340">
|
||||
@@ -19,4 +18,4 @@
|
||||
</ScrollContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
</controls:FancyWindow>
|
||||
|
||||
56
Content.Client/_Wega/BloodCult/Ui/SummoningRuneMenu.xaml.cs
Normal file
56
Content.Client/_Wega/BloodCult/Ui/SummoningRuneMenu.xaml.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._Wega.BloodCult.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class SummoningRuneMenu : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
public event Action<NetEntity>? OnCultistSelected;
|
||||
|
||||
public SummoningRuneMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.Instance!.InjectDependencies(this);
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
private void InitializeButtons()
|
||||
{
|
||||
var cultistQuery = _entityManager.EntityQueryEnumerator<BloodCultistComponent, MetaDataComponent>();
|
||||
while (cultistQuery.MoveNext(out var uid, out _, out var metaData))
|
||||
{
|
||||
var entityName = metaData.EntityName;
|
||||
AddCultistButton(entityName, uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCultistButton(string cultistName, EntityUid cultistUid)
|
||||
{
|
||||
var button = new Button
|
||||
{
|
||||
Text = cultistName,
|
||||
HorizontalAlignment = HAlignment.Center,
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
MinSize = new Vector2(300, 32),
|
||||
MaxSize = new Vector2(300, 32)
|
||||
};
|
||||
|
||||
button.OnPressed += _ => HandleCultistSelection(cultistUid);
|
||||
|
||||
CultistsContainer.AddChild(button);
|
||||
}
|
||||
|
||||
private void HandleCultistSelection(EntityUid cultistUid)
|
||||
{
|
||||
var netCultist = _entityManager.GetNetEntity(cultistUid);
|
||||
OnCultistSelected?.Invoke(netCultist);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
29
Content.Client/_Wega/CardTarot/CardTarotSystem.cs
Normal file
29
Content.Client/_Wega/CardTarot/CardTarotSystem.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Content.Shared.Card.Tarot;
|
||||
using Content.Shared.Card.Tarot.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Card.Tarot;
|
||||
|
||||
public sealed class CardTarotSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<CardTarotComponent, AppearanceChangeEvent>(OnAppearanceChanged);
|
||||
}
|
||||
|
||||
private void OnAppearanceChanged(Entity<CardTarotComponent> entity, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (!_appearance.TryGetData(entity, CardTarotVisuals.State, out CardTarot card)
|
||||
|| !_appearance.TryGetData(entity, CardTarotVisuals.Reversed, out bool reversed))
|
||||
return;
|
||||
|
||||
var state = card.ToString().ToLower();
|
||||
if (reversed) state += "-reversed";
|
||||
|
||||
_sprite.LayerSetRsiState(entity.Owner, 0, state);
|
||||
}
|
||||
}
|
||||
@@ -13,27 +13,27 @@
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" ReserveSpaceForHiddenChildren="False">
|
||||
<!-- Button 1: Hemomancer -->
|
||||
<ui:RadialMenuButton Name="HemomancerButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-class-hemomancer'}" TargetLayerControlName="Hemomancer">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/claws.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/claws.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Button 2: Umbrae -->
|
||||
<ui:RadialMenuButton Name="UmbraeButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-class-umbrae'}" TargetLayerControlName="Umbrae">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/cloak.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/cloak.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Button 3: Gargantua -->
|
||||
<ui:RadialMenuButton Name="GargantuaButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-class-gargantua'}" TargetLayerControlName="Gargantua">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/swell.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/swell.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Button 4: Dantalion -->
|
||||
<ui:RadialMenuButton Name="DantalionButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-class-dantalion'}" TargetLayerControlName="Dantalion">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/enthrall.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/enthrall.png"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
<!-- Button 5: Bestia -->
|
||||
<!-- <ui:RadialMenuButton Name="BestiaButton" StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'select-class-bestia'}" TargetLayerControlName="Bestia">
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/rush.png"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/_Wega/Interface/Actions/rush.png"/>
|
||||
</ui:RadialMenuButton> -->
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
@@ -36,6 +36,8 @@ using Robust.Shared.Replays;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.Strangulation; // Corvax-Wega-Strangulation
|
||||
using Content.Shared.SoundInsolation; // Corvax-Wega-SoundInsolation
|
||||
using Content.Shared.Mind; // Corvax-Wega-MindChat
|
||||
using Content.Shared.Blood.Cult.Components; // Corvax-Wega-Blood-Cult
|
||||
|
||||
namespace Content.Server.Chat.Systems;
|
||||
|
||||
@@ -235,6 +237,14 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
SendEntityWhisper(source, modMessage, range, channel, nameOverride, hideLog, ignoreActionBlocker);
|
||||
return;
|
||||
}
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
if (TryProcessMindMessage(source, message, out var mindMessage, out var mindChannel) && mindChannel != null)
|
||||
{
|
||||
SendMindMessage(source, mindMessage, mindChannel, ignoreActionBlocker);
|
||||
return;
|
||||
}
|
||||
// Corvax-Wega-MindChat-end
|
||||
}
|
||||
|
||||
// Otherwise, send whatever type.
|
||||
@@ -384,6 +394,69 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Station Announcement on {station} from {sender}: {message}");
|
||||
}
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
/// <inheritdoc/>
|
||||
public override void SendMindMessage(
|
||||
EntityUid source,
|
||||
string message,
|
||||
MindChannelPrototype channel,
|
||||
bool ignoreActionBlocker = false)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
return;
|
||||
|
||||
if (!ignoreActionBlocker && !_actionBlocker.CanSpeak(source))
|
||||
return;
|
||||
|
||||
var name = MetaData(source).EntityName;
|
||||
name = FormattedMessage.EscapeText(name);
|
||||
|
||||
var wrappedMessage = Loc.GetString("chat-mind-message-wrap",
|
||||
("color", channel.Color),
|
||||
("channel", $"\\[{channel.LocalizedName}\\]"),
|
||||
("name", name),
|
||||
("message", message));
|
||||
|
||||
// Send to all entities with the same mind channel
|
||||
foreach (var (session, _) in GetRecipients(source, MindChatRange))
|
||||
{
|
||||
if ((!TryComp<MindLinkComponent>(session.AttachedEntity, out var mindLink) || !mindLink.Channels.Contains(channel.ID))
|
||||
&& !HasComp<AdminMindLinkListenerComponent>(session.AttachedEntity))
|
||||
continue;
|
||||
|
||||
_chatManager.ChatMessageToOne(
|
||||
ChatChannel.Mind,
|
||||
message,
|
||||
wrappedMessage,
|
||||
source,
|
||||
false,
|
||||
session.Channel);
|
||||
}
|
||||
|
||||
// Also send a whisper
|
||||
TrySendInGameICMessage(
|
||||
source,
|
||||
message,
|
||||
InGameICChatType.Whisper,
|
||||
ChatTransmitRange.Normal,
|
||||
nameOverride: name,
|
||||
ignoreActionBlocker: true);
|
||||
|
||||
// Log to admin logs
|
||||
_adminLogger.Add(LogType.Chat, LogImpact.Low,
|
||||
$"Mind message from {ToPrettyString(source):user} on {channel.LocalizedName}: {message}");
|
||||
|
||||
// Record for replay
|
||||
var chat = new ChatMessage(
|
||||
ChatChannel.Mind,
|
||||
message,
|
||||
wrappedMessage,
|
||||
GetNetEntity(source),
|
||||
null);
|
||||
_replay.RecordServerMessage(chat);
|
||||
}
|
||||
// Corvax-Wega-MindChat-end
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private API
|
||||
@@ -634,6 +707,9 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
|
||||
private void SendDeadChat(EntityUid source, ICommonSession player, string message, bool hideChat)
|
||||
{
|
||||
if (HasComp<BloodCultGhostComponent>(source)) // Corvax-Wega-Blood-Cult-Add
|
||||
return; // Corvax-Wega-Blood-Cult-Add
|
||||
|
||||
var clients = GetDeadChatClients();
|
||||
var playerName = Name(source);
|
||||
string wrappedMessage;
|
||||
@@ -814,6 +890,7 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
.AddWhereAttachedEntity(HasComp<GhostComponent>)
|
||||
.Recipients
|
||||
.Union(_adminManager.ActiveAdmins)
|
||||
.Where(d => !HasComp<BloodCultGhostComponent>(d.AttachedEntity)) // Corvax-Wega-Blood-Cult-Add
|
||||
.Select(p => p.Channel);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1002
Content.Server/_Wega/BloodCult/BloodCultSystem.Runes.cs
Normal file
1002
Content.Server/_Wega/BloodCult/BloodCultSystem.Runes.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,41 +1,39 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Bed.Cryostorage;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Audio;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Prayer;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.EnergyShield;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Mindshield.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -44,37 +42,37 @@ namespace Content.Server.Blood.Cult;
|
||||
public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
{
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly BloodCultRuleSystem _bloodCult = default!;
|
||||
[Dependency] private readonly BodySystem _body = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly MetaDataSystem _meta = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
||||
[Dependency] private readonly ServerGlobalSoundSystem _sound = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _action = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
|
||||
[Dependency] private readonly PrayerSystem _prayerSystem = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
||||
|
||||
private readonly List<EntityUid> _selectedTargets = new();
|
||||
private bool _firstTriggered = false;
|
||||
private bool _secondTriggered = false;
|
||||
private bool _conductedComplete = false;
|
||||
private bool _ritualStage = false;
|
||||
private int _curses = 2;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<BloodCultRuleComponent, ComponentShutdown>(OnRuleShutdown);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultObjectiveActionEvent>(OnCheckObjective);
|
||||
SubscribeLocalEvent<BloodCultistComponent, ComponentStartup>(OnComponentStartup);
|
||||
base.Initialize();
|
||||
|
||||
InitializeRunes();
|
||||
InitializeBloodAbilities();
|
||||
|
||||
SubscribeLocalEvent<BloodCultistEyesComponent, ExaminedEvent>(OnCultistEyesExamined);
|
||||
|
||||
SubscribeLocalEvent<BloodCultistComponent, ShotAttemptedEvent>(OnShotAttempted); // Corvax-Wega-Testing
|
||||
SubscribeLocalEvent<BloodCultConstructComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<BloodCultObjectComponent, ComponentShutdown>(OnComponentShutdown);
|
||||
SubscribeLocalEvent<BloodCultObjectComponent, CryostorageEnterEvent>(OnCryostorageEnter);
|
||||
SubscribeLocalEvent<BloodCultWeaponComponent, AttemptMeleeEvent>(OnAttemptMelee);
|
||||
SubscribeLocalEvent<BloodDaggerComponent, AfterInteractEvent>(OnInteract);
|
||||
SubscribeLocalEvent<AttackAttemptEvent>(OnAttackAttempt);
|
||||
|
||||
SubscribeLocalEvent<StoneSoulComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<StoneSoulComponent, ComponentShutdown>(OnShutdown);
|
||||
@@ -84,16 +82,17 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
|
||||
SubscribeLocalEvent<BloodShuttleCurseComponent, UseInHandEvent>(OnShuttleCurse);
|
||||
|
||||
SubscribeLocalEvent<VeilShifterComponent, ExaminedEvent>(OnVeilShifterExamined);
|
||||
SubscribeLocalEvent<VeilShifterComponent, UseInHandEvent>(OnVeilShifter);
|
||||
|
||||
SubscribeLocalEvent<BloodShieldActivaebleComponent, GotUnequippedEvent>(OnShieldGotUnequipped);
|
||||
|
||||
SubscribeLocalEvent<ConstructComponent, InteractHandEvent>(OnConstructInteract);
|
||||
SubscribeNetworkEvent<BloodConstructMenuClosedEvent>(OnConstructSelect);
|
||||
SubscribeLocalEvent<ConstructComponent, BloodConstructSelectMessage>(OnConstructSelect);
|
||||
|
||||
SubscribeLocalEvent<BloodStructureComponent, MapInitEvent>(OnStructureMapInit);
|
||||
SubscribeLocalEvent<BloodStructureComponent, InteractHandEvent>(OnStructureInteract);
|
||||
SubscribeNetworkEvent<BloodStructureMenuClosedEvent>(OnStructureItemSelect);
|
||||
|
||||
InitializeRunes();
|
||||
InitializeBloodAbilities();
|
||||
SubscribeLocalEvent<BloodStructureComponent, BloodStructureSelectMessage>(OnStructureItemSelect);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
@@ -107,8 +106,7 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
{
|
||||
pylonQueryComponent.NextTimeTick = 3;
|
||||
var nearbyCultists = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(Transform(pylon).Coordinates, 11f)
|
||||
.Where(cultist => !_entityManager.TryGetComponent<MobThresholdsComponent>(cultist.Owner, out var thresholds)
|
||||
|| thresholds.CurrentThresholdState != MobState.Dead)
|
||||
.Where(cultist => !_mobState.IsDead(cultist))
|
||||
.ToList();
|
||||
|
||||
foreach (var target in nearbyCultists)
|
||||
@@ -116,35 +114,44 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
var heal = new DamageSpecifier { DamageDict = { { "Blunt", -1 }, { "Slash", -1 } } };
|
||||
_damage.TryChangeDamage(target.Owner, heal, true);
|
||||
|
||||
if (TryComp<BloodstreamComponent>(target, out var blood))
|
||||
_blood.TryModifyBloodLevel(target.Owner, +1);
|
||||
_blood.TryModifyBloodLevel(target.Owner, +1);
|
||||
}
|
||||
}
|
||||
pylonQueryComponent.NextTimeTick -= frameTime;
|
||||
}
|
||||
|
||||
var ritualQuery = EntityQueryEnumerator<BloodRitualDimensionalRendingComponent>();
|
||||
while (ritualQuery.MoveNext(out var rune, out var ritualQueryComponent))
|
||||
while (ritualQuery.MoveNext(out var rune, out var ritualDimensional))
|
||||
{
|
||||
if (ritualQueryComponent.Activate)
|
||||
if (ritualDimensional.Activate)
|
||||
{
|
||||
if (!_ritualStage)
|
||||
if (ritualDimensional.NextTimeTick <= 0)
|
||||
{
|
||||
_ritualStage = true;
|
||||
CheckStage();
|
||||
}
|
||||
|
||||
if (ritualQueryComponent.NextTimeTick <= 0)
|
||||
{
|
||||
ritualQueryComponent.NextTimeTick = 1;
|
||||
ritualDimensional.NextTimeTick = 1;
|
||||
if (!CheckRitual(_transform.GetMapCoordinates(rune), 9))
|
||||
ritualQueryComponent.Activate = false;
|
||||
ritualDimensional.Activate = false;
|
||||
|
||||
if (!ritualDimensional.SoundPlayed && _gameTiming.CurTime > ritualDimensional.ActivateTime + TimeSpan.FromSeconds(30))
|
||||
{
|
||||
_sound.PlayGlobalOnStation(rune, _audio.ResolveSound(ritualDimensional.RitualMusic));
|
||||
ritualDimensional.SoundPlayed = true;
|
||||
}
|
||||
}
|
||||
ritualQueryComponent.NextTimeTick -= frameTime;
|
||||
ritualDimensional.NextTimeTick -= frameTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCultistEyesExamined(EntityUid uid, BloodCultistEyesComponent component, ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
var name = Identity.Name(uid, EntityManager, args.Examiner);
|
||||
if (Name(uid) == name)
|
||||
args.PushMarkup(Loc.GetString("blood-cultist-eyes-glow-examined", ("name", name)));
|
||||
}
|
||||
|
||||
// Corvax-Wega-Testing-start
|
||||
// Да я пометил тегами чтобы банально не забыть про это и чо?
|
||||
private void OnShotAttempted(Entity<BloodCultistComponent> ent, ref ShotAttemptedEvent args)
|
||||
@@ -157,308 +164,20 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
}
|
||||
// Corvax-Wega-Testing-end
|
||||
|
||||
#region Stages Update
|
||||
private void OnRuleShutdown(EntityUid uid, BloodCultRuleComponent component, ComponentShutdown args)
|
||||
#region Dagger & Weapon
|
||||
private void OnAttemptMelee(Entity<BloodCultWeaponComponent> entity, ref AttemptMeleeEvent args)
|
||||
{
|
||||
_selectedTargets.Clear();
|
||||
_firstTriggered = false;
|
||||
_secondTriggered = false;
|
||||
_conductedComplete = false;
|
||||
_curses = 2;
|
||||
|
||||
_offerings = 3;
|
||||
_isRitualRuneUnlocked = false;
|
||||
}
|
||||
|
||||
public void SelectRandomTargets()
|
||||
{
|
||||
_selectedTargets.Clear();
|
||||
|
||||
var candidates = new List<EntityUid>();
|
||||
var enumerator = EntityQueryEnumerator<MindShieldComponent>();
|
||||
while (enumerator.MoveNext(out var uid, out _))
|
||||
var user = Transform(entity.Owner).ParentUid;
|
||||
if (!HasComp<BloodCultistComponent>(user))
|
||||
{
|
||||
candidates.Add(uid);
|
||||
}
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-failed-attack"), user, user, PopupType.SmallCaution);
|
||||
|
||||
if (candidates.Count >= 2)
|
||||
{
|
||||
var selectedIndices = new HashSet<int>();
|
||||
while (selectedIndices.Count < 2)
|
||||
{
|
||||
var index = _random.Next(0, candidates.Count);
|
||||
selectedIndices.Add(index);
|
||||
}
|
||||
|
||||
foreach (var index in selectedIndices)
|
||||
{
|
||||
var target = candidates[index];
|
||||
_selectedTargets.Add(target);
|
||||
EnsureComp<BloodCultObjectComponent>(target);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_selectedTargets.AddRange(candidates);
|
||||
foreach (var target in candidates)
|
||||
{
|
||||
EnsureComp<BloodCultObjectComponent>(target);
|
||||
}
|
||||
|
||||
var globalCandidates = new List<EntityUid>();
|
||||
var globalEnumerator = EntityQueryEnumerator<HumanoidAppearanceComponent, ActorComponent, MobStateComponent>();
|
||||
while (globalEnumerator.MoveNext(out var uid, out _, out _, out _))
|
||||
{
|
||||
if (_selectedTargets.Contains(uid) || HasComp<BloodCultistComponent>(uid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
globalCandidates.Add(uid);
|
||||
}
|
||||
|
||||
while (_selectedTargets.Count < 2 && globalCandidates.Count > 0)
|
||||
{
|
||||
var index = _random.Next(0, globalCandidates.Count);
|
||||
var target = globalCandidates[index];
|
||||
_selectedTargets.Add(target);
|
||||
EnsureComp<BloodCultObjectComponent>(target);
|
||||
globalCandidates.RemoveAt(index);
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(user, ref dropEvent);
|
||||
args.Cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private EntityUid? FindNewRandomTarget(Entity<BloodCultObjectComponent> excludedEntity)
|
||||
{
|
||||
var candidates = new List<EntityUid>();
|
||||
var query = EntityQueryEnumerator<HumanoidAppearanceComponent, ActorComponent, MobStateComponent>();
|
||||
while (query.MoveNext(out var uid, out _, out _, out _))
|
||||
{
|
||||
if (uid == excludedEntity.Owner || HasComp<BloodCultistComponent>(uid)
|
||||
|| HasComp<BloodCultObjectComponent>(uid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
candidates.Add(uid);
|
||||
}
|
||||
|
||||
if (candidates.Count == 0)
|
||||
return null;
|
||||
|
||||
var index = _random.Next(0, candidates.Count);
|
||||
return candidates[index];
|
||||
}
|
||||
|
||||
private void CheckTargetsConducted(EntityUid eliminatedTarget)
|
||||
{
|
||||
if (_selectedTargets.Contains(eliminatedTarget))
|
||||
_selectedTargets.Remove(eliminatedTarget);
|
||||
|
||||
if (_selectedTargets.Count == 0 || !_selectedTargets.Any(IsTargetValid))
|
||||
{
|
||||
_conductedComplete = true;
|
||||
RaiseLocalEvent(new RitualConductedEvent());
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsTargetValid(EntityUid target)
|
||||
{
|
||||
return _entityManager.EntityExists(target);
|
||||
}
|
||||
|
||||
private void OnCheckObjective(EntityUid uid, BloodCultistComponent component, BloodCultObjectiveActionEvent args)
|
||||
{
|
||||
if (!TryComp<ActorComponent>(uid, out var playerActor))
|
||||
return;
|
||||
|
||||
string msg;
|
||||
if (_selectedTargets.Count == 0 && !_conductedComplete || !_selectedTargets.Any(IsTargetValid) && !_conductedComplete)
|
||||
{
|
||||
msg = Loc.GetString("blood-cult-targets-no-select");
|
||||
}
|
||||
else if (_selectedTargets.Count == 0 && IsRitualConducted())
|
||||
{
|
||||
msg = Loc.GetString("blood-cult-ritual-completed-next-objective");
|
||||
}
|
||||
else if (IsGodCalled())
|
||||
{
|
||||
msg = Loc.GetString("blood-cult-objective-complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetNames = _selectedTargets
|
||||
.Where(IsTargetValid)
|
||||
.Select(target => Name(target))
|
||||
.ToList();
|
||||
|
||||
if (targetNames.Count > 0)
|
||||
{
|
||||
msg = Loc.GetString("blood-cult-current-targets", ("targets", string.Join(", ", targetNames)));
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = Loc.GetString("blood-cult-no-valid-targets");
|
||||
}
|
||||
}
|
||||
|
||||
_prayerSystem.SendSubtleMessage(playerActor.PlayerSession, playerActor.PlayerSession, string.Empty, msg);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private bool IsRitualConducted()
|
||||
{
|
||||
var query = EntityManager.EntityQuery<BloodCultRuleComponent>();
|
||||
foreach (var cult in query)
|
||||
{
|
||||
var winConditions = cult.BloodCultWinCondition.ToList();
|
||||
if (winConditions.Contains(BloodCultWinType.RitualConducted))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsGodCalled()
|
||||
{
|
||||
var query = EntityManager.EntityQuery<BloodCultRuleComponent>();
|
||||
foreach (var cult in query)
|
||||
{
|
||||
var winConditions = cult.BloodCultWinCondition.ToList();
|
||||
if (winConditions.Contains(BloodCultWinType.GodCalled))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnComponentStartup(Entity<BloodCultistComponent> entity, ref ComponentStartup args)
|
||||
{
|
||||
CheckStage();
|
||||
}
|
||||
|
||||
private void OnComponentStartup(Entity<BloodCultConstructComponent> entity, ref ComponentStartup args)
|
||||
{
|
||||
CheckStage();
|
||||
}
|
||||
|
||||
private void OnComponentShutdown(Entity<BloodCultObjectComponent> entity, ref ComponentShutdown args)
|
||||
{
|
||||
CheckStage();
|
||||
}
|
||||
|
||||
private void OnCryostorageEnter(Entity<BloodCultObjectComponent> entity, ref CryostorageEnterEvent args)
|
||||
{
|
||||
if (!TryComp<BloodCultObjectComponent>(args.Uid, out var objectComponent))
|
||||
return;
|
||||
|
||||
var newTarget = FindNewRandomTarget((args.Uid, objectComponent));
|
||||
if (newTarget != null)
|
||||
{
|
||||
_selectedTargets.Add(newTarget.Value);
|
||||
EnsureComp<BloodCultObjectComponent>(newTarget.Value);
|
||||
}
|
||||
|
||||
_selectedTargets.Remove(args.Uid);
|
||||
RemComp<BloodCultObjectComponent>(args.Uid);
|
||||
}
|
||||
|
||||
private void CheckStage()
|
||||
{
|
||||
var totalCultEntities = GetCultEntities();
|
||||
var playerCount = GetPlayerCount();
|
||||
|
||||
// Second
|
||||
if (playerCount >= 100 && totalCultEntities >= playerCount * 0.1f || playerCount < 100 && totalCultEntities >= playerCount * 0.2f || _ritualStage)
|
||||
{
|
||||
foreach (var cultist in GetAllCultists())
|
||||
{
|
||||
if (!HasComp<CultistEyesComponent>(cultist))
|
||||
{
|
||||
UpdateCultistEyes(cultist);
|
||||
AddComp<CultistEyesComponent>(cultist);
|
||||
}
|
||||
}
|
||||
if (!_firstTriggered)
|
||||
{
|
||||
var actorFilter = Filter.Empty();
|
||||
var actorQuery = EntityQueryEnumerator<ActorComponent, BloodCultistComponent>();
|
||||
while (actorQuery.MoveNext(out var actorUid, out var actor, out _))
|
||||
{
|
||||
if (actorUid != EntityUid.Invalid)
|
||||
{
|
||||
actorFilter.AddPlayer(actor.PlayerSession);
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-first-warning"), actorUid, actorUid, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
_audio.PlayGlobal(new SoundPathSpecifier("/Audio/_Wega/Ambience/Antag/bloodcult_eyes.ogg"), actorFilter, true);
|
||||
_firstTriggered = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Third
|
||||
if (playerCount >= 100 && totalCultEntities >= playerCount * 0.2f || playerCount < 100 && totalCultEntities >= playerCount * 0.3f || _ritualStage)
|
||||
{
|
||||
foreach (var cultist in GetAllCultists())
|
||||
{
|
||||
if (!HasComp<PentagramDisplayComponent>(cultist))
|
||||
{
|
||||
AddComp<PentagramDisplayComponent>(cultist);
|
||||
}
|
||||
}
|
||||
if (!_secondTriggered)
|
||||
{
|
||||
var actorFilter = Filter.Empty();
|
||||
var actorQuery = EntityQueryEnumerator<ActorComponent, BloodCultistComponent>();
|
||||
while (actorQuery.MoveNext(out var actorUid, out var actor, out _))
|
||||
{
|
||||
if (actorUid != EntityUid.Invalid)
|
||||
{
|
||||
actorFilter.AddPlayer(actor.PlayerSession);
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-second-warning"), actorUid, actorUid, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
_audio.PlayGlobal(new SoundPathSpecifier("/Audio/_Wega/Ambience/Antag/bloodcult_halos.ogg"), actorFilter, true);
|
||||
_secondTriggered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCultistEyes(EntityUid cultist)
|
||||
{
|
||||
if (TryComp<HumanoidAppearanceComponent>(cultist, out var appearanceComponent))
|
||||
{
|
||||
appearanceComponent.EyeColor = Color.FromHex("#E22218FF");
|
||||
Dirty(cultist, appearanceComponent);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetCultEntities()
|
||||
{
|
||||
var totalCultists = GetAllCultists().Count;
|
||||
var totalConstructs = EntityQuery<BloodCultConstructComponent>().Count();
|
||||
return totalCultists + totalConstructs;
|
||||
}
|
||||
|
||||
private int GetPlayerCount()
|
||||
{
|
||||
var players = AllEntityQuery<HumanoidAppearanceComponent, ActorComponent, MobStateComponent, TransformComponent>();
|
||||
int count = 0;
|
||||
while (players.MoveNext(out _, out _, out _, out _, out _))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private List<EntityUid> GetAllCultists()
|
||||
{
|
||||
var cultists = new List<EntityUid>();
|
||||
var enumerator = EntityQueryEnumerator<BloodCultistComponent>();
|
||||
while (enumerator.MoveNext(out var uid, out _))
|
||||
{
|
||||
cultists.Add(uid);
|
||||
}
|
||||
return cultists;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Dagger
|
||||
private void OnInteract(EntityUid uid, BloodDaggerComponent component, AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled || !args.CanReach || args.Target is not { Valid: true } target)
|
||||
@@ -472,6 +191,7 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Slash", 5 } } };
|
||||
_damage.TryChangeDamage(user, damage, true);
|
||||
_popup.PopupEntity(Loc.GetString("blood-dagger-failed-interact"), user, user, PopupType.SmallCaution);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -496,30 +216,25 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
|
||||
private void HandleCultistInteraction(AfterInteractEvent args)
|
||||
{
|
||||
if (!TryComp<BodyComponent>(args.Target, out var bodyComponent))
|
||||
if (!HasComp<BodyComponent>(args.Target) || !TryComp<BloodstreamComponent>(args.Target, out var bloodstream))
|
||||
return;
|
||||
|
||||
foreach (var organ in _body.GetBodyOrgans(args.Target.Value, bodyComponent))
|
||||
{
|
||||
if (!HasComp<MetabolizerComponent>(organ.Id)
|
||||
|| !TryComp<StomachComponent>(organ.Id, out var stomachComponent) || stomachComponent.Solution == null
|
||||
|| !TryComp<SolutionContainerManagerComponent>(stomachComponent.Solution.Value, out var solutionContainer)
|
||||
|| !_solution.TryGetSolution((stomachComponent.Solution.Value, solutionContainer), null, out var solutionEntity, out var solution))
|
||||
continue;
|
||||
var solution = bloodstream.BloodSolution;
|
||||
if (solution == null)
|
||||
return;
|
||||
|
||||
var holywaterReagentId = new ReagentId("Holywater", new List<ReagentData>());
|
||||
var holywater = solution.GetReagentQuantity(holywaterReagentId);
|
||||
var holywaterReagentId = new ReagentId("Holywater", new List<ReagentData>());
|
||||
var holywater = solution.Value.Comp.Solution.GetReagentQuantity(holywaterReagentId);
|
||||
|
||||
if (holywater <= 0)
|
||||
continue;
|
||||
if (holywater <= 0)
|
||||
return;
|
||||
|
||||
solution.RemoveReagent(holywaterReagentId, holywater);
|
||||
solution.Value.Comp.Solution.RemoveReagent(holywaterReagentId, holywater);
|
||||
|
||||
var unholywaterReagentId = new ReagentId("Unholywater", new List<ReagentData>());
|
||||
var unholywaterQuantity = new ReagentQuantity(unholywaterReagentId, holywater);
|
||||
if (solutionEntity != null && _solution.TryAddReagent(solutionEntity.Value, unholywaterQuantity, out var addedQuantity) && addedQuantity > 0)
|
||||
args.Handled = true;
|
||||
}
|
||||
var unholywaterReagentId = new ReagentId("Unholywater", new List<ReagentData>());
|
||||
var unholywaterQuantity = new ReagentQuantity(unholywaterReagentId, holywater);
|
||||
|
||||
args.Handled = _solution.TryAddReagent(solution.Value, unholywaterQuantity, out var addedQuantity) && addedQuantity > 0;
|
||||
}
|
||||
|
||||
private void HandleRuneInteraction(AfterInteractEvent args)
|
||||
@@ -548,8 +263,8 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
meleeWeaponComponent.Damage.DamageDict["Slash"] = FixedPoint2.New(4);
|
||||
|
||||
component.IsSharpered = true;
|
||||
_entityManager.DeleteEntity(args.Target);
|
||||
_entityManager.SpawnEntity("Ash", Transform(user).Coordinates);
|
||||
QueueDel(args.Target);
|
||||
Spawn("Ash", Transform(user).Coordinates);
|
||||
_popup.PopupEntity(Loc.GetString("blood-sharpener-success"), user, user, PopupType.Small);
|
||||
}
|
||||
else
|
||||
@@ -557,19 +272,6 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
_popup.PopupEntity(Loc.GetString("blood-sharpener-failed"), user, user, PopupType.Small);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAttackAttempt(AttackAttemptEvent args)
|
||||
{
|
||||
if (args.Weapon == null || !HasComp<BloodDaggerComponent>(args.Weapon))
|
||||
return;
|
||||
|
||||
var user = args.Uid;
|
||||
if (!HasComp<BloodCultistComponent>(user))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-failed-attack"), user, user, PopupType.SmallCaution);
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Soul Stone
|
||||
@@ -580,10 +282,8 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
|
||||
private void OnShutdown(EntityUid uid, StoneSoulComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (component.SoulEntity != null && _entityManager.EntityExists(component.SoulEntity.Value))
|
||||
{
|
||||
if (component.SoulEntity != null && Exists(component.SoulEntity.Value))
|
||||
QueueDel(component.SoulEntity.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUseInHand(EntityUid uid, StoneSoulComponent component, UseInHandEvent args)
|
||||
@@ -612,9 +312,6 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var transformSystem = _entityManager.System<TransformSystem>();
|
||||
var metaDataSystem = _entityManager.System<MetaDataSystem>();
|
||||
|
||||
if (!_mind.TryGetMind(stone, out var mindId, out var mind))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("stone-soul-empty"), user, user);
|
||||
@@ -629,10 +326,10 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
|
||||
var stoneTransform = Transform(stone).Coordinates;
|
||||
var soul = Spawn(component.SoulProto, stoneTransform);
|
||||
transformSystem.AttachToGridOrMap(soul, Transform(soul));
|
||||
_transform.AttachToGridOrMap(soul, Transform(soul));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(mind.CharacterName))
|
||||
metaDataSystem.SetEntityName(soul, mind.CharacterName);
|
||||
_meta.SetEntityName(soul, mind.CharacterName);
|
||||
|
||||
_mind.Visit(mindId, soul, mind);
|
||||
component.SoulEntity = soul;
|
||||
@@ -643,7 +340,7 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
|
||||
private void RetractSoul(EntityUid stone, StoneSoulComponent component, EntityUid user)
|
||||
{
|
||||
if (component.SoulEntity == null || !_entityManager.EntityExists(component.SoulEntity.Value))
|
||||
if (component.SoulEntity == null || !Exists(component.SoulEntity.Value))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("stone-soul-empty"), user, user);
|
||||
return;
|
||||
@@ -681,11 +378,12 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
if (args.Handled || !HasComp<BloodCultistComponent>(user))
|
||||
return;
|
||||
|
||||
if (_curses > 0)
|
||||
var cult = _bloodCult.GetActiveRule();
|
||||
if (cult != null && cult.Curses > 0)
|
||||
{
|
||||
_roundEndSystem.CancelRoundEndCountdown(user);
|
||||
_entityManager.DeleteEntity(entity);
|
||||
_curses--;
|
||||
_roundEndSystem.CancelRoundEndCountdown(user, true);
|
||||
QueueDel(entity);
|
||||
cult.Curses--;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -696,6 +394,14 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
#endregion
|
||||
|
||||
#region Veil Shifter
|
||||
private void OnVeilShifterExamined(EntityUid uid, VeilShifterComponent component, ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange || !HasComp<BloodCultistComponent>(args.Examiner))
|
||||
return;
|
||||
|
||||
args.PushMarkup(Loc.GetString("veil-shifter-examined", ("count", component.ActivationsCount)));
|
||||
}
|
||||
|
||||
private void OnVeilShifter(EntityUid uid, VeilShifterComponent component, UseInHandEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
@@ -715,11 +421,14 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
var transform = Transform(user);
|
||||
var targetPosition = transform.Coordinates.Offset(alignedDirection * randomDistance);
|
||||
_transform.SetCoordinates(user, targetPosition);
|
||||
|
||||
_appearance.SetData(uid, VeilShifterVisuals.Charged, component.ActivationsCount > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-veil-shifter-failed"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -738,131 +447,123 @@ public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Shield
|
||||
private void OnShieldGotUnequipped(Entity<BloodShieldActivaebleComponent> ent, ref GotUnequippedEvent args)
|
||||
{
|
||||
if (!TryComp<EnergyShieldOwnerComponent>(args.Equipee, out var energyShield))
|
||||
return;
|
||||
|
||||
QueueDel(energyShield.ShieldEntity);
|
||||
RemComp(args.Equipee, energyShield);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Construct
|
||||
private void OnConstructInteract(Entity<ConstructComponent> cosntruct, ref InteractHandEvent args)
|
||||
private void OnConstructInteract(Entity<ConstructComponent> construct, ref InteractHandEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (args.Handled || !HasComp<BloodCultistComponent>(user))
|
||||
return;
|
||||
|
||||
if (TryComp<ItemSlotsComponent>(cosntruct, out var itemSlotsComponent))
|
||||
if (TryComp<ItemSlotsComponent>(construct, out var itemSlotsComponent))
|
||||
{
|
||||
foreach (var slot in itemSlotsComponent.Slots.Values)
|
||||
EntityUid? item = itemSlotsComponent.Slots.First().Value.Item;
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
if (slot.HasItem)
|
||||
if (_mind.TryGetMind(item.Value, out _, out _))
|
||||
{
|
||||
var containedEntity = slot.Item;
|
||||
if (containedEntity != null)
|
||||
{
|
||||
if (TryComp<MindContainerComponent>(containedEntity.Value, out var mindContainer) && mindContainer.Mind != null)
|
||||
{
|
||||
var netEntity = _entityManager.GetNetEntity(user);
|
||||
var netCosntruct = _entityManager.GetNetEntity(cosntruct);
|
||||
var mind = _entityManager.GetNetEntity(mindContainer.Mind.Value);
|
||||
RaiseNetworkEvent(new OpenConstructMenuEvent(netEntity, netCosntruct, mind));
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-no-mind"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
_ui.OpenUi(construct.Owner, BloodConstructUiKey.Key, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-failed"), user, user, PopupType.SmallCaution);
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-no-mind"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-failed"), user, user, PopupType.SmallCaution);
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-failed"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConstructSelect(BloodConstructMenuClosedEvent args)
|
||||
private void OnConstructSelect(Entity<ConstructComponent> construct, ref BloodConstructSelectMessage args)
|
||||
{
|
||||
var user = _entityManager.GetEntity(args.Uid);
|
||||
var construct = _entityManager.GetEntity(args.ConstructUid);
|
||||
var mind = _entityManager.GetEntity(args.Mind);
|
||||
EntityUid? mindUid = null;
|
||||
if (TryComp<ItemSlotsComponent>(construct, out var itemSlotsComponent))
|
||||
mindUid = itemSlotsComponent.Slots.First().Value.Item;
|
||||
|
||||
if (mind == EntityUid.Invalid)
|
||||
if (mindUid == null || !_mind.TryGetMind(mindUid.Value, out var mind, out _))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-no-mind"), user, user, PopupType.SmallCaution);
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-no-mind"), args.Actor, args.Actor, PopupType.SmallCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
var constructMobe = _entityManager.SpawnEntity(args.ConstructProto, Transform(construct).Coordinates);
|
||||
var constructMobe = Spawn(args.Construct, Transform(construct).Coordinates);
|
||||
_mind.TransferTo(mind, constructMobe);
|
||||
_entityManager.DeleteEntity(construct);
|
||||
QueueDel(construct);
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-succses"), user, user);
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-succses"), args.Actor, args.Actor);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Structures
|
||||
private void OnStructureMapInit(EntityUid structure, BloodStructureComponent component, MapInitEvent args)
|
||||
{
|
||||
component.ActivateTime = _gameTiming.CurTime + TimeSpan.FromMinutes(4);
|
||||
}
|
||||
|
||||
private void OnStructureInteract(EntityUid structure, BloodStructureComponent component, InteractHandEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (args.Handled || !HasComp<BloodCultistComponent>(user))
|
||||
return;
|
||||
|
||||
if (structure is not { Valid: true } target || !component.CanInteract)
|
||||
return;
|
||||
|
||||
var currentTime = _gameTiming.RealTime;
|
||||
if (currentTime < component.ActivateTime)
|
||||
var currentTime = _gameTiming.CurTime;
|
||||
var nextActivateTime = component.ActivateTime + TimeSpan.FromMinutes(4);
|
||||
if (currentTime < nextActivateTime)
|
||||
{
|
||||
var remainingTime = (component.ActivateTime - currentTime).TotalSeconds;
|
||||
var remainingTime = (nextActivateTime - currentTime).TotalSeconds;
|
||||
_popup.PopupEntity(Loc.GetString("blood-structure-failed", ("time", Math.Ceiling(remainingTime))), user, user, PopupType.Small);
|
||||
return;
|
||||
}
|
||||
|
||||
var netEntity = _entityManager.GetNetEntity(user);
|
||||
var netStructureEntity = _entityManager.GetNetEntity(target);
|
||||
RaiseNetworkEvent(new OpenStructureMenuEvent(netEntity, netStructureEntity));
|
||||
_ui.OpenUi(structure, BloodStructureUiKey.Key, user);
|
||||
var state = new BloodStructureBoundUserInterfaceState(component.StructureGear);
|
||||
_ui.SetUiState(structure, BloodStructureUiKey.Key, state);
|
||||
}
|
||||
|
||||
private void OnStructureItemSelect(BloodStructureMenuClosedEvent args)
|
||||
private void OnStructureItemSelect(Entity<BloodStructureComponent> structure, ref BloodStructureSelectMessage args)
|
||||
{
|
||||
var user = _entityManager.GetEntity(args.Uid);
|
||||
var structure = _entityManager.GetEntity(args.Structure);
|
||||
if (!TryComp<BloodStructureComponent>(structure, out var structureComp))
|
||||
return;
|
||||
|
||||
var currentTime = _gameTiming.RealTime;
|
||||
if (currentTime < structureComp.ActivateTime)
|
||||
var currentTime = _gameTiming.CurTime;
|
||||
var nextActivateTime = structure.Comp.ActivateTime + TimeSpan.FromMinutes(4);
|
||||
if (currentTime < nextActivateTime)
|
||||
{
|
||||
var remainingTime = (structureComp.ActivateTime - currentTime).TotalSeconds;
|
||||
_popup.PopupEntity(Loc.GetString("blood-structure-failed", ("time", Math.Ceiling(remainingTime))), user, user, PopupType.Small);
|
||||
var remainingTime = (nextActivateTime - currentTime).TotalSeconds;
|
||||
_popup.PopupEntity(Loc.GetString("blood-structure-failed", ("time", Math.Ceiling(remainingTime))), args.Actor, args.Actor, PopupType.Small);
|
||||
return;
|
||||
}
|
||||
|
||||
structureComp.ActivateTime = currentTime + TimeSpan.FromMinutes(4);
|
||||
structure.Comp.ActivateTime = currentTime;
|
||||
|
||||
var item = _entityManager.SpawnEntity(args.Item, Transform(structure).Coordinates);
|
||||
_audio.PlayPvs(structureComp.Sound, structure);
|
||||
var item = Spawn(args.Item, Transform(structure).Coordinates);
|
||||
_audio.PlayPvs(structure.Comp.Sound, structure);
|
||||
|
||||
var cultistPosition = _transform.GetWorldPosition(user);
|
||||
var cultistPosition = _transform.GetWorldPosition(args.Actor);
|
||||
var structurePosition = _transform.GetWorldPosition(structure);
|
||||
var distance = (structurePosition - cultistPosition).Length();
|
||||
if (distance < 3f)
|
||||
_hands.TryPickupAnyHand(user, item);
|
||||
if (distance < 3f) _hands.TryPickupAnyHand(args.Actor, item);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region God Check
|
||||
private string GetCurrentGod()
|
||||
private BloodCultGod GetCurrentGod()
|
||||
{
|
||||
var query = EntityQueryEnumerator<BloodCultRuleComponent>();
|
||||
while (query.MoveNext(out var cult))
|
||||
{
|
||||
if (cult.SelectedGod == null)
|
||||
{
|
||||
return "Narsie";
|
||||
}
|
||||
return cult.SelectedGod;
|
||||
}
|
||||
return "Narsie";
|
||||
var cult = _bloodCult.GetActiveRule();
|
||||
if (cult != null && cult.SelectedGod != null)
|
||||
return cult.SelectedGod.Value;
|
||||
|
||||
return BloodCultGod.NarSi;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
24
Content.Server/_Wega/BloodCult/BloodMagicEui.cs
Normal file
24
Content.Server/_Wega/BloodCult/BloodMagicEui.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Content.Server.EUI;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Content.Shared.Eui;
|
||||
|
||||
namespace Content.Server.Blood.Cult.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Logic for the blood magic window
|
||||
/// </summary>
|
||||
public sealed class BloodMagicEui(EntityUid cultist, BloodCultSystem bloodCult) : BaseEui
|
||||
{
|
||||
public override EuiStateBase GetNewState()
|
||||
=> new BloodMagicState();
|
||||
|
||||
public override void HandleMessage(EuiMessageBase msg)
|
||||
{
|
||||
base.HandleMessage(msg);
|
||||
|
||||
if (msg is BloodMagicSelectSpellMessage msgSpell)
|
||||
bloodCult.AfterSpellSelect(cultist, msgSpell.Spell);
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
@@ -1,880 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Bible.Components;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Ghost.Roles.Components;
|
||||
using Content.Server.Pinpointer;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Shared.Administration.Systems;
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Mindshield.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.NullRod.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Silicons.Borgs.Components;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.Surgery.Components;
|
||||
using Content.Shared.Timing;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Blood.Cult;
|
||||
|
||||
public sealed partial class BloodCultSystem
|
||||
{
|
||||
[Dependency] private readonly BloodCultSystem _bloodCult = default!;
|
||||
[Dependency] private readonly IConsoleHost _consoleHost = default!;
|
||||
[Dependency] private readonly FlammableSystem _flammable = default!;
|
||||
[Dependency] private readonly NavMapSystem _navMap = default!;
|
||||
[Dependency] private readonly IMapManager _mapMan = default!;
|
||||
[Dependency] private readonly RejuvenateSystem _rejuvenate = default!;
|
||||
[Dependency] private readonly SharedGhostSystem _ghost = default!;
|
||||
|
||||
private static readonly EntProtoId ActionComms = "ActionBloodCultComms";
|
||||
private const string BloodCultObserver = "MobObserverIfrit";
|
||||
private static int _offerings = 3;
|
||||
private bool _isRitualRuneUnlocked = false;
|
||||
|
||||
private void InitializeRunes()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<RitualConductedEvent>(UnlockRitual);
|
||||
|
||||
SubscribeNetworkEvent<RuneSelectEvent>(AfterRuneSelect);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodRuneDoAfterEvent>(DoAfterRuneSelect);
|
||||
SubscribeLocalEvent<BloodDaggerComponent, UseInHandEvent>(OnDaggerInteract);
|
||||
SubscribeLocalEvent<BloodRuneComponent, InteractHandEvent>(OnRuneInteract);
|
||||
SubscribeLocalEvent<BloodRitualDimensionalRendingComponent, InteractHandEvent>(OnRitualInteract);
|
||||
SubscribeLocalEvent<BloodRitualDimensionalRendingComponent, ComponentShutdown>(OnComponentShutdown);
|
||||
|
||||
SubscribeNetworkEvent<EmpoweringRuneMenuClosedEvent>(OnEmpoweringSelected);
|
||||
SubscribeLocalEvent<BloodCultistComponent, EmpoweringDoAfterEvent>(OnEmpoweringDoAfter);
|
||||
SubscribeNetworkEvent<SummoningSelectedEvent>(OnSummoningSelected);
|
||||
|
||||
SubscribeLocalEvent<BloodRuneCleaningDoAfterEvent>(DoAfterInteractRune);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodRuneCleaningDoAfterEvent>(DoAfterInteractRune);
|
||||
}
|
||||
|
||||
#region Runes
|
||||
private void UnlockRitual(RitualConductedEvent ev)
|
||||
{
|
||||
_isRitualRuneUnlocked = true;
|
||||
}
|
||||
|
||||
private void OnComponentShutdown(EntityUid uid, BloodRitualDimensionalRendingComponent component, ComponentShutdown args)
|
||||
{
|
||||
_isRitualRuneUnlocked = false;
|
||||
}
|
||||
|
||||
private void AfterRuneSelect(RuneSelectEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var uid = _entityManager.GetEntity(args.Uid);
|
||||
if (!HasComp<BloodCultistComponent>(uid) || IsInSpace(uid))
|
||||
return;
|
||||
|
||||
var selectedRune = args.RuneProto;
|
||||
if (selectedRune == "BloodRuneRitualDimensionalRending" && !_isRitualRuneUnlocked)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-ritual-failed"), uid, uid, PopupType.MediumCaution);
|
||||
return;
|
||||
}
|
||||
else if (selectedRune == "BloodRuneRitualDimensionalRending" && _isRitualRuneUnlocked)
|
||||
{
|
||||
var xform = Transform(uid);
|
||||
if (!TryComp<MapGridComponent>(xform.GridUid, out var grid) || !HasComp<BecomesStationComponent>(xform.GridUid.Value))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-ritual-failed"), uid, uid, PopupType.MediumCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isValidSurface = true;
|
||||
var cultistPosition = _transform.GetMapCoordinates(Transform(uid));
|
||||
if (!_mapMan.TryFindGridAt(cultistPosition, out _, out _))
|
||||
isValidSurface = false;
|
||||
|
||||
if (isValidSurface)
|
||||
{
|
||||
var ritualRune = _entityManager.SpawnEntity(TrySelectRuneEffect(selectedRune), Transform(uid).Coordinates);
|
||||
_appearance.SetData(ritualRune, RuneColorVisuals.Color, TryFindColor(uid));
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, TimeSpan.FromSeconds(9.75f),
|
||||
new BloodRuneDoAfterEvent(selectedRune, GetNetEntity(ritualRune)), uid)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
NeedHand = false
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-ritual-failed"), uid, uid, PopupType.MediumCaution);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var rune = _entityManager.SpawnEntity(TrySelectRuneEffect(selectedRune), Transform(uid).Coordinates);
|
||||
_appearance.SetData(rune, RuneColorVisuals.Color, TryFindColor(uid));
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, TimeSpan.FromSeconds(4f),
|
||||
new BloodRuneDoAfterEvent(selectedRune, GetNetEntity(rune)), uid)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
NeedHand = false
|
||||
});
|
||||
}
|
||||
|
||||
private void DoAfterRuneSelect(EntityUid cultist, BloodCultistComponent component, BloodRuneDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
{
|
||||
_entityManager.DeleteEntity(GetEntity(args.Rune));
|
||||
return;
|
||||
}
|
||||
|
||||
var rune = _entityManager.SpawnEntity(args.SelectedRune, Transform(cultist).Coordinates);
|
||||
_appearance.SetData(rune, RuneColorVisuals.Color, TryFindColor(cultist));
|
||||
|
||||
if (args.SelectedRune == "BloodRuneRitualDimensionalRending")
|
||||
{
|
||||
var xform = _entityManager.GetComponent<TransformComponent>(rune);
|
||||
var msg = Loc.GetString("blood-ritual-warning",
|
||||
("location", FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString((rune, xform)))));
|
||||
_chat.DispatchGlobalAnnouncement(msg, colorOverride: Color.Red);
|
||||
|
||||
_isRitualRuneUnlocked = false;
|
||||
}
|
||||
|
||||
if (TryComp<BloodstreamComponent>(cultist, out var blood) && _blood.GetBloodLevel(cultist) > 0)
|
||||
_blood.TryModifyBloodLevel(cultist, -5);
|
||||
else
|
||||
{
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Slash", 5 } } };
|
||||
_damage.TryChangeDamage(cultist, damage, true);
|
||||
}
|
||||
_popup.PopupEntity(Loc.GetString("rune-select-complete"), cultist, cultist, PopupType.SmallCaution);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRuneInteract(EntityUid rune, BloodRuneComponent component, InteractHandEvent args)
|
||||
{
|
||||
if (args.Handled || !HasComp<BloodCultistComponent>(args.User))
|
||||
return;
|
||||
|
||||
if (rune is not { Valid: true } target)
|
||||
return;
|
||||
|
||||
if (component.Prototype is null)
|
||||
return;
|
||||
|
||||
OnRuneAfterInteract(target, component, args.User);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRitualInteract(EntityUid rune, BloodRitualDimensionalRendingComponent component, InteractHandEvent args)
|
||||
{
|
||||
if (args.Handled || !HasComp<BloodCultistComponent>(args.User))
|
||||
return;
|
||||
|
||||
var currentTime = _gameTiming.RealTime;
|
||||
if (currentTime < component.ActivateTime)
|
||||
{
|
||||
var remainingTime = component.ActivateTime - currentTime;
|
||||
_popup.PopupEntity(Loc.GetString("ritual-activate-too-soon", ("time", remainingTime.TotalSeconds)), args.User, args.User, PopupType.LargeCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rune is not { Valid: true } target || !CheckRitual(_transform.GetMapCoordinates(target), 9))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("ritual-activate-failed"), args.User, args.User, PopupType.LargeCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
component.ActivateTime = currentTime + TimeSpan.FromSeconds(120);
|
||||
component.Activate = true;
|
||||
|
||||
OnRitualAfterInteract(target, component);
|
||||
var cultistEntities = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(_transform.GetMapCoordinates(target), 6f);
|
||||
foreach (var cultistEntity in cultistEntities)
|
||||
{
|
||||
SendCultistMessage(cultistEntity.Owner, "ritual");
|
||||
}
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRuneAfterInteract(EntityUid rune, BloodRuneComponent runeComp, EntityUid cultist)
|
||||
{
|
||||
var coords = _transform.GetMapCoordinates(rune);
|
||||
if (!TryComp<UseDelayComponent>(rune, out var useDelay) || _useDelay.IsDelayed((rune, useDelay)))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (runeComp.Prototype)
|
||||
{
|
||||
case "offering":
|
||||
var targets = _entityLookup.GetEntitiesInRange<HumanoidAppearanceComponent>(coords, 1f);
|
||||
foreach (var targetEntity in targets)
|
||||
{
|
||||
var target = targetEntity.Owner;
|
||||
if (HasComp<BloodCultistComponent>(target) || HasComp<BloodCultConstructComponent>(target)
|
||||
|| HasComp<NullRodOwnerComponent>(target))
|
||||
continue;
|
||||
|
||||
if (!_entityManager.TryGetComponent<MobThresholdsComponent>(target, out var targetThresholds))
|
||||
continue;
|
||||
|
||||
var currentState = targetThresholds.CurrentThresholdState;
|
||||
if (currentState is MobState.Dead && (HasComp<MindShieldComponent>(target) || HasComp<BibleUserComponent>(target)
|
||||
|| HasComp<BloodCultObjectComponent>(target)) && !HasComp<SyntheticOperatedComponent>(target))
|
||||
{
|
||||
if (CheckRuneActivate(coords, 3))
|
||||
{
|
||||
var cultistEntities = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(coords, 2f);
|
||||
foreach (var cultistEntity in cultistEntities)
|
||||
{
|
||||
SendCultistMessage(cultistEntity.Owner, "offering");
|
||||
}
|
||||
|
||||
var soulStone = _entityManager.SpawnEntity("BloodCultSoulStone", Transform(target).Coordinates);
|
||||
if (TryComp<MindContainerComponent>(target, out var mindContainer) && mindContainer.Mind != null)
|
||||
_mind.TransferTo(mindContainer.Mind.Value, soulStone);
|
||||
|
||||
// Gib
|
||||
if (HasComp<BloodCultObjectComponent>(target))
|
||||
{
|
||||
_bloodCult.CheckTargetsConducted(target);
|
||||
RemComp<BloodCultObjectComponent>(target);
|
||||
}
|
||||
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Blunt", 1000 } } };
|
||||
_damage.TryChangeDamage(target, damage, true);
|
||||
IncrementOfferingsCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (currentState != MobState.Dead && !HasComp<MindShieldComponent>(target) && !HasComp<BibleUserComponent>(target)
|
||||
&& !HasComp<SyntheticOperatedComponent>(target))
|
||||
{
|
||||
if (CheckRuneActivate(coords, 2))
|
||||
{
|
||||
var cultistEntities = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(coords, 2f);
|
||||
foreach (var cultistEntity in cultistEntities)
|
||||
{
|
||||
SendCultistMessage(cultistEntity.Owner, "offering");
|
||||
}
|
||||
|
||||
_rejuvenate.PerformRejuvenate(target);
|
||||
EnsureComp<AutoCultistComponent>(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (currentState is MobState.Dead && !HasComp<MindShieldComponent>(target) && !HasComp<BibleUserComponent>(target)
|
||||
&& !HasComp<SyntheticOperatedComponent>(target))
|
||||
{
|
||||
if (CheckRuneActivate(coords, 1))
|
||||
{
|
||||
var cultistEntities = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(coords, 2f);
|
||||
foreach (var cultistEntity in cultistEntities)
|
||||
{
|
||||
SendCultistMessage(cultistEntity.Owner, "offering");
|
||||
}
|
||||
|
||||
var soulStone = _entityManager.SpawnEntity("BloodCultSoulStone", Transform(target).Coordinates);
|
||||
if (TryComp<MindContainerComponent>(target, out var mindContainer) && mindContainer.Mind != null)
|
||||
_mind.TransferTo(mindContainer.Mind.Value, soulStone);
|
||||
|
||||
// Gib
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Blunt", 1000 } } };
|
||||
_damage.TryChangeDamage(target, damage, true);
|
||||
IncrementOfferingsCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "teleport":
|
||||
var runes = new List<EntityUid>();
|
||||
var runeQuery = EntityQueryEnumerator<BloodRuneComponent>();
|
||||
while (runeQuery.MoveNext(out var runeUid, out var runeCompQ))
|
||||
{
|
||||
if (runeCompQ.Prototype == "teleport" && runeUid != rune)
|
||||
runes.Add(runeUid);
|
||||
}
|
||||
|
||||
if (runes.Any() && CheckRuneActivate(coords, 1))
|
||||
{
|
||||
var randomRuneEntity = runes[_random.Next(runes.Count)];
|
||||
var runeTransform = _entityManager.GetComponent<TransformComponent>(randomRuneEntity);
|
||||
var runeCoords = runeTransform.Coordinates;
|
||||
SendCultistMessage(cultist, "teleport");
|
||||
|
||||
_entityManager.SpawnEntity("BloodCultOutEffect", Transform(cultist).Coordinates);
|
||||
_transform.SetCoordinates(cultist, runeCoords);
|
||||
_entityManager.SpawnEntity("BloodCultInEffect", runeCoords);
|
||||
_entityManager.DeleteEntity(randomRuneEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
case "empowering":
|
||||
if (CheckRuneActivate(coords, 1))
|
||||
{
|
||||
if (TryComp<BloodCultistComponent>(cultist, out var comp) && comp.Empowering < 4)
|
||||
{
|
||||
SendCultistMessage(cultist, "empowering");
|
||||
|
||||
var netEntity = _entityManager.GetNetEntity(cultist);
|
||||
RaiseNetworkEvent(new EmpoweringRuneMenuOpenedEvent(netEntity));
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "revive":
|
||||
if (CheckRuneActivate(coords, 1))
|
||||
{
|
||||
var revivetarget = _entityLookup.GetEntitiesInRange<BodyComponent>(coords, 1f);
|
||||
foreach (var targetEntity in revivetarget)
|
||||
{
|
||||
var target = targetEntity.Owner;
|
||||
if (!_entityManager.TryGetComponent<MobThresholdsComponent>(target, out var targetThresholds) || target == cultist)
|
||||
continue;
|
||||
|
||||
var currentState = targetThresholds.CurrentThresholdState;
|
||||
if (HasComp<BloodCultistComponent>(target) && HasComp<HumanoidAppearanceComponent>(target)
|
||||
&& currentState is MobState.Dead)
|
||||
{
|
||||
if (GetOfferingsCount() >= 3)
|
||||
{
|
||||
SendCultistMessage(cultist, "revive");
|
||||
_rejuvenate.PerformRejuvenate(target);
|
||||
SubtractOfferingsCount();
|
||||
|
||||
if (TryComp<MindContainerComponent>(target, out var mind) && mind.Mind is null
|
||||
&& !HasComp<GhostRoleComponent>(target))
|
||||
{
|
||||
var formattedCommand = string.Format(
|
||||
"makeghostrole {0} {1} {2} {3}",
|
||||
target,
|
||||
Loc.GetString("ghost-role-information-cultist"),
|
||||
Loc.GetString("ghost-role-information-cultist-desc"),
|
||||
Loc.GetString("ghost-role-information-cultist-rules")
|
||||
);
|
||||
_consoleHost.ExecuteCommand(formattedCommand);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (HasComp<BloodCultistComponent>(target) && HasComp<HumanoidAppearanceComponent>(target)
|
||||
&& TryComp<MindContainerComponent>(target, out var mind) && mind.Mind is null && !HasComp<GhostRoleComponent>(target))
|
||||
{
|
||||
SendCultistMessage(cultist, "revive");
|
||||
var formattedCommand = string.Format(
|
||||
"makeghostrole {0} {1} {2} {3}",
|
||||
target,
|
||||
Loc.GetString("ghost-role-information-cultist"),
|
||||
Loc.GetString("ghost-role-information-cultist-desc"),
|
||||
Loc.GetString("ghost-role-information-cultist-rules")
|
||||
);
|
||||
_consoleHost.ExecuteCommand(formattedCommand);
|
||||
}
|
||||
else if (HasComp<BodyComponent>(target) && !HasComp<BloodCultistComponent>(target) && currentState is MobState.Dead
|
||||
&& !HasComp<BorgChassisComponent>(target) && !HasComp<BloodCultObjectComponent>(target)
|
||||
&& !HasComp<HumanoidAppearanceComponent>(target)/*Stop killing humanoid this way*/)
|
||||
{
|
||||
SendCultistMessage(cultist, "revive");
|
||||
|
||||
// Gib
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Blunt", 1000 } } };
|
||||
_damage.TryChangeDamage(target, damage, true);
|
||||
IncrementOfferingsCount();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
case "barrier":
|
||||
if (CheckRuneActivate(coords, 1))
|
||||
{
|
||||
if (!runeComp.BarrierActive)
|
||||
{
|
||||
runeComp.BarrierActive = true;
|
||||
SendCultistMessage(cultist, "barrier");
|
||||
var nearbyRunes = _entityLookup.GetEntitiesInRange<BloodRuneComponent>(coords, 1f)
|
||||
.Where(r => EntityManager.TryGetComponent(r, out BloodRuneComponent? nearbyRuneComp)
|
||||
&& nearbyRuneComp.Prototype == "barrier" && r.Owner != rune)
|
||||
.ToList();
|
||||
|
||||
Entity<BloodRuneComponent>? randomRune = nearbyRunes.Any()
|
||||
? nearbyRunes[new Random().Next(nearbyRunes.Count)]
|
||||
: null;
|
||||
|
||||
if (randomRune != null)
|
||||
{
|
||||
var randomRuneUid = randomRune.Value;
|
||||
if (TryComp<BloodRuneComponent>(randomRuneUid, out var randomRuneComp) && !randomRuneComp.BarrierActive)
|
||||
{
|
||||
randomRuneComp.BarrierActive = true;
|
||||
if (EntityManager.TryGetComponent(randomRuneUid, out PhysicsComponent? randomPhysicsComp))
|
||||
{
|
||||
var fixture = _fixtures.GetFixtureOrNull(randomRuneUid, "barrier");
|
||||
if (fixture != null)
|
||||
{
|
||||
_physics.SetHard(randomRuneUid, fixture, randomRuneComp.BarrierActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EntityManager.TryGetComponent(rune, out PhysicsComponent? physicsComp))
|
||||
{
|
||||
var fixture = _fixtures.GetFixtureOrNull(rune, "barrier");
|
||||
if (fixture != null)
|
||||
{
|
||||
_physics.SetHard(rune, fixture, runeComp.BarrierActive);
|
||||
}
|
||||
}
|
||||
|
||||
var barrierRunes = new List<EntityUid>();
|
||||
var barrierRuneQuery = EntityQueryEnumerator<BloodRuneComponent>();
|
||||
|
||||
while (barrierRuneQuery.MoveNext(out var runeUid, out var runeCompQ))
|
||||
{
|
||||
if (runeCompQ.Prototype == "barrier")
|
||||
barrierRunes.Add(runeUid);
|
||||
}
|
||||
|
||||
var damageFormula = 2 * barrierRunes.Count;
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Slash", damageFormula } } };
|
||||
_damage.TryChangeDamage(cultist, damage, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
runeComp.BarrierActive = false;
|
||||
SendCultistMessage(cultist, "barrier");
|
||||
if (EntityManager.TryGetComponent(rune, out PhysicsComponent? physicsComp))
|
||||
{
|
||||
var fixture = _fixtures.GetFixtureOrNull(rune, "barrier");
|
||||
if (fixture != null)
|
||||
{
|
||||
_physics.SetHard(rune, fixture, runeComp.BarrierActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
case "summoning":
|
||||
if (CheckRuneActivate(coords, 2))
|
||||
{
|
||||
var cultistEntities = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(coords, 2f);
|
||||
foreach (var cultistEntity in cultistEntities)
|
||||
{
|
||||
SendCultistMessage(cultist, "summoning");
|
||||
}
|
||||
|
||||
var netEntity = _entityManager.GetNetEntity(cultist);
|
||||
RaiseNetworkEvent(new SummoningRuneMenuOpenedEvent(netEntity));
|
||||
|
||||
_entityManager.DeleteEntity(rune);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
case "bloodboil":
|
||||
if (CheckRuneActivate(coords, 2))
|
||||
{
|
||||
RemComp<BloodRuneComponent>(rune);
|
||||
var cultistEntities = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(coords, 2f);
|
||||
foreach (var cultistEntity in cultistEntities)
|
||||
{
|
||||
SendCultistMessage(cultistEntity.Owner, "bloodboil");
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var damageValues = new[] { 5, 10, 10 };
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var targetsFlammable = _entityLookup.GetEntitiesInRange<FlammableComponent>(coords, 10f)
|
||||
.Where(flammableEntity =>
|
||||
!HasComp<BloodCultistComponent>(flammableEntity.Owner))
|
||||
.ToList();
|
||||
|
||||
foreach (var targetFlammable in targetsFlammable)
|
||||
{
|
||||
if (HasComp<NullRodOwnerComponent>(targetFlammable.Owner))
|
||||
continue;
|
||||
|
||||
if (TryComp<FlammableComponent>(targetFlammable.Owner, out var flammable))
|
||||
{
|
||||
flammable.FireStacks = 3f;
|
||||
_flammable.Ignite(targetFlammable.Owner, rune);
|
||||
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Heat", damageValues[i] } } };
|
||||
_damage.TryChangeDamage(cultist, damage, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 2)
|
||||
{
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
}
|
||||
|
||||
_entityManager.DeleteEntity(rune);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
break;
|
||||
case "spiritrealm":
|
||||
if (CheckRuneActivate(coords, 1))
|
||||
{
|
||||
SendCultistMessage(cultist, "spiritrealm");
|
||||
if (TryComp<MindContainerComponent>(cultist, out var mindContainer) && mindContainer.Mind != null)
|
||||
{
|
||||
var mindSystem = _entityManager.System<SharedMindSystem>();
|
||||
var metaDataSystem = _entityManager.System<MetaDataSystem>();
|
||||
var transformSystem = _entityManager.System<TransformSystem>();
|
||||
var gameTicker = _entityManager.System<GameTicker>();
|
||||
|
||||
if (!mindSystem.TryGetMind(cultist, out var mindId, out var mind))
|
||||
return;
|
||||
|
||||
if (mind.VisitingEntity != default && _entityManager.TryGetComponent<GhostComponent>(mind.VisitingEntity, out var oldGhostComponent))
|
||||
{
|
||||
mindSystem.UnVisit(mindId, mind);
|
||||
if (oldGhostComponent.CanGhostInteract)
|
||||
return;
|
||||
}
|
||||
|
||||
var canReturn = mind.CurrentEntity != null
|
||||
&& !_entityManager.HasComponent<GhostComponent>(mind.CurrentEntity);
|
||||
var ghost = _entityManager.SpawnEntity(BloodCultObserver, coords);
|
||||
transformSystem.AttachToGridOrMap(ghost, _entityManager.GetComponent<TransformComponent>(ghost));
|
||||
|
||||
if (canReturn)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(mind.CharacterName))
|
||||
metaDataSystem.SetEntityName(ghost, mind.CharacterName);
|
||||
|
||||
mindSystem.Visit(mindId, ghost, mind);
|
||||
}
|
||||
else
|
||||
{
|
||||
metaDataSystem.SetEntityName(ghost, Name(cultist));
|
||||
mindSystem.TransferTo(mindId, ghost, mind: mind);
|
||||
}
|
||||
|
||||
var comp = _entityManager.GetComponent<GhostComponent>(ghost);
|
||||
_action.RemoveAction(ghost, comp.ToggleGhostBarActionEntity); // Ghost-Bar-Block
|
||||
_action.AddAction(ghost, ActionComms);
|
||||
_ghost.SetCanReturnToBody((ghost, comp), canReturn);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_popup.PopupEntity(Loc.GetString("rune-activate-failed"), cultist, cultist, PopupType.MediumCaution);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_entityManager.EntityExists(rune))
|
||||
_useDelay.TryResetDelay((rune, useDelay));
|
||||
}
|
||||
|
||||
private void OnRitualAfterInteract(EntityUid rune, BloodRitualDimensionalRendingComponent runeComp)
|
||||
{
|
||||
var xform = _entityManager.GetComponent<TransformComponent>(rune);
|
||||
var msg = Loc.GetString("blood-ritual-activate-warning",
|
||||
("location", FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString((rune, xform)))));
|
||||
_chat.DispatchGlobalAnnouncement(msg, playSound: false, colorOverride: Color.Red);
|
||||
_audio.PlayGlobal(new SoundPathSpecifier("/Audio/_Wega/Ambience/Antag/bloodcult_scribe.ogg"), Filter.Broadcast(), true);
|
||||
Timer.Spawn(TimeSpan.FromSeconds(45), () =>
|
||||
{
|
||||
if (runeComp.Activate)
|
||||
{
|
||||
var coords = Transform(rune).Coordinates;
|
||||
_entityManager.DeleteEntity(rune);
|
||||
_entityManager.SpawnEntity("BloodCultDistortedEffect", coords);
|
||||
string currentGod = GetCurrentGod() switch
|
||||
{
|
||||
"Narsie" => "MobNarsieSpawn",
|
||||
"Reaper" => "MobReaperSpawn",
|
||||
"Kharin" => "MobKharinSpawn",
|
||||
_ => "MobNarsieSpawn"
|
||||
};
|
||||
_entityManager.SpawnEntity(currentGod, coords);
|
||||
RaiseLocalEvent(new GodCalledEvent());
|
||||
|
||||
var nearbyCultists = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(coords, 6f)
|
||||
.ToList();
|
||||
|
||||
foreach (var target in nearbyCultists)
|
||||
{
|
||||
var harvester = _entityManager.SpawnEntity("MobConstructHarvester", Transform(target).Coordinates);
|
||||
if (TryComp<MindContainerComponent>(target, out var mindContainer) && mindContainer.Mind != null)
|
||||
_mind.TransferTo(mindContainer.Mind.Value, harvester);
|
||||
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Blunt", 1000 } } };
|
||||
_damage.TryChangeDamage(target.Owner, damage, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var cultists = EntityQueryEnumerator<BloodCultistComponent>();
|
||||
while (cultists.MoveNext(out var cultist, out _))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("ritual-failed"), cultist, cultist, PopupType.LargeCaution);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
private void OnEmpoweringSelected(EmpoweringRuneMenuClosedEvent args)
|
||||
{
|
||||
var cultist = _entityManager.GetEntity(args.Uid);
|
||||
if (!HasComp<BloodCultistComponent>(cultist))
|
||||
return;
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, cultist, TimeSpan.FromSeconds(4f), new EmpoweringDoAfterEvent(args.SelectedSpell), cultist)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
NeedHand = true
|
||||
});
|
||||
}
|
||||
|
||||
private void OnEmpoweringDoAfter(EntityUid cultist, BloodCultistComponent component, EmpoweringDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled) return;
|
||||
|
||||
var actionEntityUid = _action.AddAction(cultist, args.SelectedSpell);
|
||||
component.SelectedEmpoweringSpells.Add(actionEntityUid);
|
||||
component.Empowering++;
|
||||
|
||||
if (TryComp<BloodstreamComponent>(cultist, out var blood) && _blood.GetBloodLevel(cultist) > 0)
|
||||
_blood.TryModifyBloodLevel(cultist, -5);
|
||||
else
|
||||
{
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Slash", 2 } } };
|
||||
_damage.TryChangeDamage(cultist, damage, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSummoningSelected(SummoningSelectedEvent args)
|
||||
{
|
||||
var user = _entityManager.GetEntity(args.User);
|
||||
var target = _entityManager.GetEntity(args.Target);
|
||||
_entityManager.SpawnEntity("BloodCultOutEffect", Transform(target).Coordinates);
|
||||
_transform.SetCoordinates(target, Transform(user).Coordinates);
|
||||
_entityManager.SpawnEntity("BloodCultInEffect", Transform(user).Coordinates);
|
||||
}
|
||||
|
||||
private bool CheckRuneActivate(MapCoordinates coords, int needCount)
|
||||
{
|
||||
var constructsCount = _entityLookup.GetEntitiesInRange<BloodCultConstructComponent>(coords, 2f).Count();
|
||||
var aliveCultistsCount = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(coords, 2f)
|
||||
.Count(cultist => !_entityManager.TryGetComponent<MobThresholdsComponent>(cultist.Owner, out var thresholds)
|
||||
|| thresholds.CurrentThresholdState != MobState.Dead);
|
||||
return aliveCultistsCount + constructsCount >= needCount;
|
||||
}
|
||||
|
||||
private bool CheckRitual(MapCoordinates coords, int needCount)
|
||||
{
|
||||
var aliveCultistsCount = _entityLookup.GetEntitiesInRange<BloodCultistComponent>(coords, 6f)
|
||||
.Count(cultist => !_entityManager.TryGetComponent<MobThresholdsComponent>(cultist.Owner, out var thresholds)
|
||||
|| thresholds.CurrentThresholdState != MobState.Dead);
|
||||
return aliveCultistsCount >= needCount;
|
||||
}
|
||||
|
||||
private void SendCultistMessage(EntityUid cultist, string messageType)
|
||||
{
|
||||
string message = messageType switch
|
||||
{
|
||||
"offering" => Loc.GetString("blood-cultist-offering-message"),
|
||||
"teleport" => Loc.GetString("blood-cultist-teleport-message"),
|
||||
"empowering" => Loc.GetString("blood-cultist-empowering-message"),
|
||||
"revive" => Loc.GetString("blood-cultist-revive-message"),
|
||||
"barrier" => Loc.GetString("blood-cultist-barrier-message"),
|
||||
"summoning" => Loc.GetString("blood-cultist-summoning-message"),
|
||||
"bloodboil" => Loc.GetString("blood-cultist-bloodboil-message"),
|
||||
"spiritrealm" => Loc.GetString("blood-cultist-spiritrealm-message"),
|
||||
"ritual" => Loc.GetString("blood-cultist-ritual-message"),
|
||||
_ => Loc.GetString("blood-cultist-default-message")
|
||||
};
|
||||
|
||||
_chat.TrySendInGameICMessage(cultist, message, InGameICChatType.Whisper, ChatTransmitRange.Normal, checkRadioPrefix: false);
|
||||
}
|
||||
|
||||
private string TrySelectRuneEffect(string messageType)
|
||||
{
|
||||
string message = messageType switch
|
||||
{
|
||||
"BloodRuneOffering" => "BloodRuneOfferingEffect",
|
||||
"BloodRuneTeleport" => "BloodRuneTeleportEffect",
|
||||
"BloodRuneEmpowering" => "BloodRuneEmpoweringEffect",
|
||||
"BloodRuneRevive" => "BloodRuneReviveEffect",
|
||||
"BloodRuneBarrier" => "BloodRuneBarrierEffect",
|
||||
"BloodRuneSummoning" => "BloodRuneSummoningEffect",
|
||||
"BloodRuneBloodBoil" => "BloodRuneBloodBoilEffect",
|
||||
"BloodRuneSpiritealm" => "BloodRuneSpiritealmEffect",
|
||||
"BloodRuneRitualDimensionalRending" => "BloodRuneRitualDimensionalRendingEffect",
|
||||
_ => "BloodRuneOfferingEffect"
|
||||
};
|
||||
return message;
|
||||
}
|
||||
|
||||
private void OnDaggerInteract(Entity<BloodDaggerComponent> ent, ref UseInHandEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (!HasComp<BloodCultistComponent>(user))
|
||||
{
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(user, ref dropEvent);
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Slash", 5 } } };
|
||||
_damage.TryChangeDamage(user, damage, true);
|
||||
_popup.PopupEntity(Loc.GetString("blood-dagger-failed-interact"), user, user, PopupType.SmallCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
var netEntity = _entityManager.GetNetEntity(args.User);
|
||||
RaiseNetworkEvent(new RunesMenuOpenedEvent(netEntity));
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private bool IsInSpace(EntityUid cultist)
|
||||
{
|
||||
var cultistPosition = _transform.GetMapCoordinates(Transform(cultist));
|
||||
if (!_mapMan.TryFindGridAt(cultistPosition, out _, out _))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Color TryFindColor(EntityUid cultist)
|
||||
{
|
||||
if (!TryComp<BloodstreamComponent>(cultist, out var bloodStreamComponent))
|
||||
return Color.White;
|
||||
|
||||
string? bloodReagentPrototypeId = null;
|
||||
if (bloodStreamComponent.BloodReferenceSolution.Contents.Count > 0)
|
||||
{
|
||||
var reagentQuantity = bloodStreamComponent.BloodReferenceSolution.Contents[0];
|
||||
bloodReagentPrototypeId = reagentQuantity.Reagent.Prototype;
|
||||
}
|
||||
|
||||
if (bloodReagentPrototypeId == null)
|
||||
return Color.White;
|
||||
|
||||
if (!_prototypeManager.TryIndex(bloodReagentPrototypeId, out ReagentPrototype? reagentPrototype))
|
||||
return Color.White;
|
||||
|
||||
return reagentPrototype.SubstanceColor;
|
||||
}
|
||||
|
||||
private void DoAfterInteractRune(BloodRuneCleaningDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled) return;
|
||||
|
||||
_entityManager.DeleteEntity(args.Target);
|
||||
}
|
||||
|
||||
private void DoAfterInteractRune(EntityUid cultist, BloodCultistComponent component, BloodRuneCleaningDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled) return;
|
||||
|
||||
_entityManager.DeleteEntity(args.Target);
|
||||
}
|
||||
|
||||
private static void IncrementOfferingsCount()
|
||||
{
|
||||
_offerings++;
|
||||
}
|
||||
|
||||
private static void SubtractOfferingsCount()
|
||||
{
|
||||
_offerings -= 3;
|
||||
}
|
||||
|
||||
private static int GetOfferingsCount()
|
||||
{
|
||||
return _offerings;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
920
Content.Server/_Wega/CardTarot/CardTarotSystem.cs
Normal file
920
Content.Server/_Wega/CardTarot/CardTarotSystem.cs
Normal file
@@ -0,0 +1,920 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Cargo.Components;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Dice;
|
||||
using Content.Server.Economy.SlotMachine;
|
||||
using Content.Server.Guardian;
|
||||
using Content.Server.Hallucinations;
|
||||
using Content.Server.Polymorph.Systems;
|
||||
using Content.Server.Revolutionary.Components;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Stack;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Surgery;
|
||||
using Content.Shared.Administration.Systems;
|
||||
using Content.Shared.Armor;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Card.Tarot;
|
||||
using Content.Shared.Card.Tarot.Components;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.CombatMode.Pacification;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Disease.Components;
|
||||
using Content.Shared.EnergyShield;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Shared.Pinpointer;
|
||||
using Content.Shared.Polymorph;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Tiles;
|
||||
using Content.Shared.Traits.Assorted;
|
||||
using Content.Shared.Trigger.Components.Triggers;
|
||||
using Content.Shared.Trigger.Systems;
|
||||
using Content.Shared.VendingMachines;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Card.Tarot;
|
||||
|
||||
public sealed class CardTarotSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly BloodstreamSystem _blood = default!;
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly DamageableSystem _damage = default!;
|
||||
[Dependency] private readonly DiceOfFateSystem _dice = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
|
||||
[Dependency] private readonly SharedGravitySystem _gravity = default!;
|
||||
[Dependency] private readonly HallucinationsSystem _hallucinations = default!;
|
||||
[Dependency] private readonly IngestionSystem _ingestion = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly LockSystem _lock = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly PolymorphSystem _polymorph = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly RejuvenateSystem _rejuvenate = default!;
|
||||
[Dependency] private readonly SlotMachineSystem _slotMachine = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
|
||||
[Dependency] private readonly StackSystem _stack = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||
[Dependency] private readonly SurgerySystem _surgery = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||
[Dependency] private readonly TriggerSystem _trigger = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
// 200,000 static variables are ready, and another million is on the way
|
||||
private static readonly EntProtoId Ash = "Ash";
|
||||
private static readonly EntProtoId ClusterBang = "ClusterBangFull";
|
||||
private static readonly EntProtoId ClusterGrenade = "ClusterGrenade";
|
||||
private static readonly EntProtoId CursedSlotMachine = "CursedSlotMachine";
|
||||
private static readonly EntProtoId Drunk = "StatusEffectDrunk";
|
||||
private static readonly EntProtoId EmptyCardTarot = "CardTarotNotEnchanted";
|
||||
private static readonly EntProtoId Pill = "StrangePill";
|
||||
private static readonly EntProtoId RandomContainer = "RandomContainerBlank";
|
||||
private static readonly EntProtoId RandomVending = "RandomVending";
|
||||
private static readonly EntProtoId Rock = "WallRock";
|
||||
private static readonly EntProtoId Smoke = "AdminInstantEffectSmoke30";
|
||||
private static readonly EntProtoId SpaceCash = "SpaceCash";
|
||||
private static readonly EntProtoId Stand = "MobHoloparasiteGuardian";
|
||||
|
||||
private static readonly List<EntProtoId> DeathEnt = new() {
|
||||
"BloodCultConstruct", "BloodCultSoulStone"
|
||||
};
|
||||
|
||||
private static readonly List<EntProtoId> JusticeEnt = new() {
|
||||
"MedkitFilled", "TearGasGrenade", "WeaponWandPolymorphDoor", "SpaceCash100"
|
||||
};
|
||||
|
||||
private static readonly ProtoId<DamageTypePrototype> BluntDamage = "Blunt";
|
||||
private static readonly ProtoId<DamageTypePrototype> CellularDamage = "Cellular";
|
||||
private static readonly ProtoId<DamageTypePrototype> HeatDamage = "Heat";
|
||||
private static readonly ProtoId<DamageTypePrototype> PoisonDamage = "Poison";
|
||||
private static readonly ProtoId<DamageTypePrototype> RadiationDamage = "Blunt";
|
||||
|
||||
private static readonly ProtoId<PolymorphPrototype> ChariotStatue = "ChariotStatue";
|
||||
|
||||
private static readonly ProtoId<TagPrototype> Grenade = "HandGrenade";
|
||||
private static readonly ProtoId<TagPrototype> SlowImmune = "SlowImmune";
|
||||
private static readonly ProtoId<TagPrototype> StunImmune = "StunImmune";
|
||||
|
||||
private static readonly string Drug = "Desoxyephedrine";
|
||||
private static readonly string NotHeal = "Puncturase"; // LoL
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CardTarotComponent, AfterInteractEvent>(OnTarotInteract);
|
||||
SubscribeLocalEvent<CardTarotComponent, UseInHandEvent>(OnUseTarot);
|
||||
}
|
||||
|
||||
#region Card Tarot
|
||||
private void OnTarotInteract(Entity<CardTarotComponent> ent, ref AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled || !args.CanReach || args.Target is not { Valid: true } target)
|
||||
return;
|
||||
|
||||
if (ent.Comp.Card == CardTarot.NotEnchanted)
|
||||
{
|
||||
_popup.PopupEntity("tarot-card-not-enchanted", args.User, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
PerformTarotEffect(target, args.User, ent);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnUseTarot(Entity<CardTarotComponent> ent, ref UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (ent.Comp.Card == CardTarot.NotEnchanted)
|
||||
{
|
||||
_popup.PopupEntity("tarot-card-not-enchanted", args.User, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
PerformTarotEffect(args.User, args.User, ent);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void PerformTarotEffect(EntityUid target, EntityUid user, Entity<CardTarotComponent> card)
|
||||
{
|
||||
var isReversed = card.Comp.CardType == CardTarotType.Reversed;
|
||||
|
||||
switch (card.Comp.Card)
|
||||
{
|
||||
case CardTarot.NotEnchanted:
|
||||
_popup.PopupEntity("tarot-card-not-enchanted", user, user);
|
||||
return;
|
||||
case CardTarot.Fool:
|
||||
PerformFool(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Magician:
|
||||
PerformMagician(target, isReversed);
|
||||
break;
|
||||
case CardTarot.HighPriestess:
|
||||
PerformHighPriestess(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Empress:
|
||||
PerformEmpress(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Emperor:
|
||||
PerformEmperor(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Hierophant:
|
||||
PerformHierophant(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Lovers:
|
||||
PerformLovers(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Chariot:
|
||||
PerformChariot(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Justice:
|
||||
PerformJustice(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Hermit:
|
||||
PerformHermit(target, isReversed);
|
||||
break;
|
||||
case CardTarot.WheelOfFortune:
|
||||
PerformWheelOfFortune(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Strength:
|
||||
PerformStrength(target, isReversed);
|
||||
break;
|
||||
case CardTarot.HangedMan:
|
||||
PerformHangedMan(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Death:
|
||||
PerformDeath(user, target, isReversed);
|
||||
break;
|
||||
case CardTarot.Temperance:
|
||||
PerformTemperance(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Devil:
|
||||
PerformDevil(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Tower:
|
||||
PerformTower(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Stars:
|
||||
PerformStars(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Moon:
|
||||
PerformMoon(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Sun:
|
||||
PerformSun(target, isReversed);
|
||||
break;
|
||||
case CardTarot.Judgement:
|
||||
PerformJudgement(target, isReversed);
|
||||
break;
|
||||
case CardTarot.TheWorld:
|
||||
PerformTheWorld(target, isReversed);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
var coords = Transform(user).Coordinates;
|
||||
|
||||
var ash = Spawn(Ash, coords);
|
||||
_throwing.TryThrow(ash, _random.NextVector2());
|
||||
_audio.PlayPredicted(card.Comp.UseSound, coords, user);
|
||||
_popup.PopupEntity(Loc.GetString("tarot-used", ("name", Identity.Name(user, EntityManager)),
|
||||
("type", Loc.GetString($"tarot-card-{card.Comp.Card.ToString().ToLower()}"))),
|
||||
user, PopupType.Medium);
|
||||
|
||||
QueueDel(card);
|
||||
}
|
||||
|
||||
#region Card Effects
|
||||
private void PerformFool(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
if (_inventory.TryGetSlots(target, out var slots))
|
||||
{
|
||||
foreach (var slot in slots)
|
||||
{
|
||||
_inventory.TryUnequip(target, slot.Name, force: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityUid? shuttle = null;
|
||||
var shuttles = EntityQueryEnumerator<ArrivalsShuttleComponent>();
|
||||
while (shuttles.MoveNext(out var uid, out _))
|
||||
{
|
||||
shuttle = uid;
|
||||
break;
|
||||
}
|
||||
|
||||
if (shuttle == null)
|
||||
return;
|
||||
|
||||
_transform.SetCoordinates(target, Transform(shuttle.Value).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformMagician(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var nearbyEntity = _entityLookup.GetEntitiesInRange<TransformComponent>(Transform(target).Coordinates, 6f, LookupFlags.Dynamic)
|
||||
.Where(e => !e.Comp.Anchored).ToList();
|
||||
|
||||
foreach (var entity in nearbyEntity)
|
||||
{
|
||||
var entityUid = entity.Owner;
|
||||
if (entityUid == target)
|
||||
continue;
|
||||
|
||||
var targetPosition = _transform.GetWorldPosition(target);
|
||||
var entityPosition = _transform.GetWorldPosition(entityUid);
|
||||
var direction = (entityPosition - targetPosition).Normalized();
|
||||
|
||||
_physics.ApplyLinearImpulse(entityUid, direction * 2000f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_statusEffects.TrySetStatusEffectDuration(target, "StatusEffectPainNumbness", TimeSpan.FromMinutes(2));
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformHighPriestess(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
/// Temporarily empty
|
||||
}
|
||||
else
|
||||
{
|
||||
var time = TimeSpan.FromSeconds(20);
|
||||
_stun.TryAddParalyzeDuration(target, time);
|
||||
Timer.Spawn(time, () =>
|
||||
{
|
||||
var damage = new DamageSpecifier { DamageDict = { { BluntDamage, 60 } } };
|
||||
_damage.TryChangeDamage(target, damage);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformEmpress(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var nearbyEntity = _entityLookup.GetEntitiesInRange<MobStateComponent>(Transform(target).Coordinates, 6f)
|
||||
.Where(e => e.Owner != target).ToList();
|
||||
|
||||
foreach (var entity in nearbyEntity)
|
||||
{
|
||||
var entityUid = entity.Owner;
|
||||
if (HasComp<PacifiedComponent>(entityUid))
|
||||
return;
|
||||
|
||||
EnsureComp<PacifiedComponent>(entityUid);
|
||||
Timer.Spawn(TimeSpan.FromSeconds(40), () => { RemComp<PacifiedComponent>(entityUid); });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TryComp<BloodstreamComponent>(target, out var bloodstream) || bloodstream.BloodSolution == null)
|
||||
return;
|
||||
|
||||
var drugQuantity = new ReagentQuantity(Drug, FixedPoint2.New(4.5));
|
||||
var notHealQuantity = new ReagentQuantity(NotHeal, FixedPoint2.New(12));
|
||||
|
||||
_solution.TryAddReagent(bloodstream.BloodSolution.Value, drugQuantity, out _);
|
||||
_solution.TryAddReagent(bloodstream.BloodSolution.Value, notHealQuantity, out _);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformEmperor(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var selected = new List<EntityUid>();
|
||||
var commandQuery = EntityQueryEnumerator<CommandStaffComponent>();
|
||||
while (commandQuery.MoveNext(out var uid, out _))
|
||||
selected.Add(uid);
|
||||
|
||||
if (selected.Count == 0)
|
||||
return;
|
||||
|
||||
_transform.SetCoordinates(target, Transform(_random.Pick(selected)).Coordinates);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityUid? bridgeUid = null;
|
||||
var beaconQuery = EntityQueryEnumerator<NavMapBeaconComponent>();
|
||||
while (beaconQuery.MoveNext(out var uid, out var beacon))
|
||||
{
|
||||
if (beacon.DefaultText == "station-beacon-bridge")
|
||||
{
|
||||
bridgeUid = uid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bridgeUid == null)
|
||||
return;
|
||||
|
||||
_transform.SetCoordinates(target, Transform(bridgeUid.Value).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformHierophant(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
/// Temporarily empty
|
||||
}
|
||||
else
|
||||
{
|
||||
var slot = "jumpsuit";
|
||||
if (!_inventory.TryGetSlotEntity(target, slot, out var clothing))
|
||||
return;
|
||||
|
||||
if (!HasComp<BloodShieldActivaebleComponent>(clothing))
|
||||
{
|
||||
EnsureComp<BloodShieldActivaebleComponent>(clothing.Value).CurrentSlot = slot;
|
||||
|
||||
var shield = EnsureComp<EnergyShieldOwnerComponent>(target);
|
||||
shield.ShieldEntity = Spawn("BloodCultShieldEffect", Transform(target).Coordinates);
|
||||
_transform.SetParent(shield.ShieldEntity.Value, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformLovers(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var damage = new DamageSpecifier { DamageDict = { { BluntDamage, 20 }, { HeatDamage, 20 } } };
|
||||
_damage.TryChangeDamage(target, damage, true);
|
||||
_blood.TryModifyBloodLevel(target, -120);
|
||||
}
|
||||
else
|
||||
{
|
||||
var damage = new DamageSpecifier { DamageDict = { { BluntDamage, -40 }, { HeatDamage, -40 }, { PoisonDamage, -40 } } };
|
||||
_damage.TryChangeDamage(target, damage, true);
|
||||
_blood.TryModifyBloodLevel(target, 100);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformChariot(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
_polymorph.PolymorphEntity(target, ChariotStatue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var time = TimeSpan.FromSeconds(10);
|
||||
_statusEffects.TrySetStatusEffectDuration(target, "StatusEffectDesoxyStamina", time);
|
||||
|
||||
bool isStunImmuned = false;
|
||||
bool isSlowImmuned = false;
|
||||
bool isPacified = false;
|
||||
if (!_tag.HasTag(target, StunImmune))
|
||||
{
|
||||
isStunImmuned = _tag.TryAddTag(target, StunImmune);
|
||||
}
|
||||
|
||||
if (!_tag.HasTag(target, SlowImmune))
|
||||
{
|
||||
isSlowImmuned = _tag.TryAddTag(target, SlowImmune);
|
||||
}
|
||||
|
||||
if (!HasComp<PacifiedComponent>(target))
|
||||
{
|
||||
EnsureComp<PacifiedComponent>(target);
|
||||
isPacified = true;
|
||||
}
|
||||
|
||||
Timer.Spawn(time, () =>
|
||||
{
|
||||
if (isStunImmuned) _tag.RemoveTag(target, StunImmune);
|
||||
if (isSlowImmuned) _tag.RemoveTag(target, SlowImmune);
|
||||
if (isPacified) RemComp<PacifiedComponent>(target);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformJustice(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
Spawn(RandomContainer, Transform(target).Coordinates);
|
||||
}
|
||||
else
|
||||
{
|
||||
var coords = Transform(target).Coordinates;
|
||||
foreach (var ent in JusticeEnt)
|
||||
Spawn(ent, coords);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformHermit(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var allEnt = new HashSet<EntityUid>();
|
||||
var nearbyGuns = _entityLookup.GetEntitiesInRange<GunComponent>(Transform(target).Coordinates, 6f);
|
||||
var nearbyMelees = _entityLookup.GetEntitiesInRange<MeleeWeaponComponent>(Transform(target).Coordinates, 6f)
|
||||
.Where(e => !HasComp<MobStateComponent>(e) && !Transform(e).Anchored);
|
||||
var nearbyArmor = _entityLookup.GetEntitiesInRange<ArmorComponent>(Transform(target).Coordinates, 6f);
|
||||
var nearbyGrenades = _entityLookup.GetEntitiesInRange<TriggerOnUseComponent>(Transform(target).Coordinates, 6f)
|
||||
.Where(e => _tag.HasTag(e, Grenade));
|
||||
|
||||
allEnt.UnionWith(nearbyGuns.Select(e => e.Owner));
|
||||
allEnt.UnionWith(nearbyMelees.Select(e => e.Owner));
|
||||
allEnt.UnionWith(nearbyArmor.Select(e => e.Owner));
|
||||
allEnt.UnionWith(nearbyGrenades.Select(e => e.Owner));
|
||||
|
||||
foreach (var ent in allEnt)
|
||||
{
|
||||
var cash = Spawn(SpaceCash, Transform(ent).Coordinates);
|
||||
if (TryComp<StackComponent>(cash, out var stack) && TryComp<StaticPriceComponent>(ent, out var price))
|
||||
_stack.SetCount((cash, stack), (int)price.Price);
|
||||
|
||||
QueueDel(ent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var map = Transform(target).MapID;
|
||||
|
||||
var selected = new List<EntityUid>();
|
||||
var vendigsQuery = EntityQueryEnumerator<VendingMachineComponent>();
|
||||
while (vendigsQuery.MoveNext(out var uid, out _))
|
||||
{
|
||||
if (map == Transform(uid).MapID)
|
||||
selected.Add(uid);
|
||||
}
|
||||
|
||||
if (selected.Count == 0)
|
||||
return;
|
||||
|
||||
_transform.SetCoordinates(target, Transform(_random.Pick(selected)).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformWheelOfFortune(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var luck = _random.Next(1, 21);
|
||||
_dice.RollFate(target, luck);
|
||||
}
|
||||
else
|
||||
{
|
||||
Spawn(RandomVending, Transform(target).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformStrength(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var nearbyEntity = _entityLookup.GetEntitiesInRange<MobStateComponent>(Transform(target).Coordinates, 6f);
|
||||
|
||||
foreach (var entity in nearbyEntity)
|
||||
{
|
||||
var entityUid = entity.Owner;
|
||||
_hallucinations.StartHallucinations(entityUid, "Hallucinations", TimeSpan.FromMinutes(2), true, "MindBreaker");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TryComp<DamageableComponent>(target, out var damageable))
|
||||
return;
|
||||
|
||||
var oldMod = damageable.DamageModifierSetId;
|
||||
_damage.SetDamageModifierSetId(target, "VampireBloodSwell");
|
||||
|
||||
Timer.Spawn(TimeSpan.FromSeconds(30), () => { _damage.SetDamageModifierSetId(target, oldMod); });
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformHangedMan(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var slotMachine = Spawn(CursedSlotMachine, Transform(target).Coordinates);
|
||||
_slotMachine.FreeSpeen(slotMachine, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gravity.RefreshWeightless(target, false);
|
||||
Timer.Spawn(TimeSpan.FromMinutes(1), () => { _gravity.RefreshWeightless(target, true); });
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformDeath(EntityUid user, EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var coords = Transform(target).Coordinates;
|
||||
foreach (var ent in DeathEnt)
|
||||
Spawn(ent, coords);
|
||||
}
|
||||
else
|
||||
{
|
||||
var nearbyEntity = _entityLookup.GetEntitiesInRange<MobStateComponent>(Transform(target).Coordinates, 6f)
|
||||
.Where(e => e.Owner != user);
|
||||
|
||||
var damage = new DamageSpecifier { DamageDict = { { BluntDamage, 20 }, { HeatDamage, 20 } } };
|
||||
foreach (var entity in nearbyEntity)
|
||||
{
|
||||
_damage.TryChangeDamage(entity.Owner, damage, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformTemperance(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
var pill = Spawn(Pill, Transform(target).Coordinates);
|
||||
if (!_ingestion.TryIngest(target, pill))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_statusEffects.TryRemoveStatusEffect(target, Drunk);
|
||||
if (TryComp<DiseaseCarrierComponent>(target, out var disease))
|
||||
disease.Diseases.Clear();
|
||||
|
||||
if (TryComp<DamageableComponent>(target, out var damageable))
|
||||
{
|
||||
var damageTypes = new[] { RadiationDamage, PoisonDamage };
|
||||
foreach (var damageType in damageTypes)
|
||||
{
|
||||
if (damageable.Damage.DamageDict.TryGetValue(damageType, out var currentDamage) && currentDamage > 0)
|
||||
{
|
||||
var healSpecifier = new DamageSpecifier { DamageDict = { { damageType, -currentDamage } } };
|
||||
_damage.TryChangeDamage(target, healSpecifier, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformDevil(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var grenade = Spawn(ClusterBang, Transform(target).Coordinates);
|
||||
_trigger.Trigger(grenade);
|
||||
}
|
||||
else
|
||||
{
|
||||
var nearbyEntity = _entityLookup.GetEntitiesInRange<DamageableComponent>(Transform(target).Coordinates, 6f)
|
||||
.Where(e => e.Owner != target && HasComp<MobStateComponent>(e)).Select(e => e.Owner).ToList();
|
||||
|
||||
var heal = new DamageSpecifier { DamageDict = { { BluntDamage, -45 }, { HeatDamage, -45 } } };
|
||||
_damage.TryChangeDamage(target, heal, true);
|
||||
_popup.PopupEntity(Loc.GetString("tarot-devil-healed"), target, target);
|
||||
|
||||
Timer.Spawn(TimeSpan.FromSeconds(3), () =>
|
||||
{
|
||||
if (!Exists(target))
|
||||
return;
|
||||
|
||||
StartDamagePhase(nearbyEntity);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void StartDamagePhase(List<EntityUid> initialNearby)
|
||||
{
|
||||
var validTargets = initialNearby.Where(Exists).ToList();
|
||||
if (validTargets.Count == 0)
|
||||
return;
|
||||
|
||||
var damageTicks = 30;
|
||||
var currentDamageTick = 0;
|
||||
|
||||
var totalBluntPerTarget = 22;
|
||||
var totalHeatPerTarget = 23;
|
||||
|
||||
var bluntPerSecondPerTarget = totalBluntPerTarget / (float)damageTicks;
|
||||
var heatPerSecondPerTarget = totalHeatPerTarget / (float)damageTicks;
|
||||
|
||||
var damageDealt = new Dictionary<EntityUid, (float Blunt, float Heat)>();
|
||||
foreach (var target in validTargets)
|
||||
{
|
||||
damageDealt[target] = (0, 0);
|
||||
}
|
||||
|
||||
void DamageTick()
|
||||
{
|
||||
validTargets = validTargets.Where(Exists).ToList();
|
||||
if (validTargets.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var target in validTargets)
|
||||
{
|
||||
var expectedBlunt = bluntPerSecondPerTarget * (currentDamageTick + 1);
|
||||
var expectedHeat = heatPerSecondPerTarget * (currentDamageTick + 1);
|
||||
|
||||
var (dealtBlunt, dealtHeat) = damageDealt[target];
|
||||
var bluntThisTick = (int)(expectedBlunt - dealtBlunt);
|
||||
var heatThisTick = (int)(expectedHeat - dealtHeat);
|
||||
|
||||
if (bluntThisTick > 0 || heatThisTick > 0)
|
||||
{
|
||||
var damageSpec = new DamageSpecifier();
|
||||
|
||||
if (bluntThisTick > 0)
|
||||
damageSpec.DamageDict[BluntDamage] = bluntThisTick;
|
||||
|
||||
if (heatThisTick > 0)
|
||||
damageSpec.DamageDict[HeatDamage] = heatThisTick;
|
||||
|
||||
_damage.TryChangeDamage(target, damageSpec, true);
|
||||
|
||||
if (_random.Prob(0.2f))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("tarot-devil-damaged"), target, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDamageTick++;
|
||||
if (currentDamageTick < damageTicks)
|
||||
{
|
||||
Timer.Spawn(TimeSpan.FromSeconds(1), DamageTick);
|
||||
}
|
||||
}
|
||||
|
||||
DamageTick();
|
||||
}
|
||||
|
||||
private void PerformTower(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var radius = 6;
|
||||
var center = Transform(target).Coordinates;
|
||||
for (int x = -radius; x <= radius; x++)
|
||||
{
|
||||
for (int y = -radius; y <= radius; y++)
|
||||
{
|
||||
if (x * x + y * y <= radius * radius)
|
||||
{
|
||||
if (_random.Prob(0.25f))
|
||||
{
|
||||
var spawnCoords = center.Offset(new Vector2(x, y));
|
||||
Spawn(Rock, spawnCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var grenade = Spawn(ClusterGrenade, Transform(target).Coordinates);
|
||||
_trigger.Trigger(grenade);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformStars(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
var damage = new DamageSpecifier { DamageDict = { { CellularDamage, 50 } } };
|
||||
_damage.TryChangeDamage(target, damage, true);
|
||||
|
||||
var damageTypes = new[] { "ClosedFracture", "ArterialBleeding", "MildBurns" };
|
||||
_surgery.TryAddInternalDamage(target, _random.Pick(damageTypes));
|
||||
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var card = Spawn(EmptyCardTarot, Transform(target).Coordinates);
|
||||
var tarot = EnsureComp<CardTarotComponent>(card);
|
||||
|
||||
var allCards = Enum.GetValues<CardTarot>();
|
||||
tarot.Card = (CardTarot)_random.Next(1, allCards.Length);
|
||||
|
||||
bool reversedCard = _random.Prob(0.5f);
|
||||
if (reversed) tarot.CardType = CardTarotType.Reversed;
|
||||
|
||||
_appearance.SetData(card, CardTarotVisuals.State, tarot.Card);
|
||||
_appearance.SetData(card, CardTarotVisuals.Reversed, reversedCard);
|
||||
|
||||
_throwing.TryThrow(card, _random.NextVector2());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var lockers = new List<EntityUid>();
|
||||
var lockersQuery = EntityQueryEnumerator<EntityStorageComponent, LockComponent, MetaDataComponent>();
|
||||
while (lockersQuery.MoveNext(out var uid, out _, out _, out var meta))
|
||||
{
|
||||
if (meta.EntityPrototype != null && meta.EntityPrototype.ID == "LockerEvidence")
|
||||
lockers.Add(uid);
|
||||
}
|
||||
|
||||
if (lockers.Count == 0)
|
||||
return;
|
||||
|
||||
var locker = _random.Pick(lockers);
|
||||
var lockerCoords = Transform(locker).Coordinates;
|
||||
var centerTile = Transform(locker).LocalPosition;
|
||||
|
||||
for (int radiusStep = 1; radiusStep <= 3; radiusStep++)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
var angle = (float)i / 8 * MathHelper.TwoPi;
|
||||
var offset = new Vector2(
|
||||
(float)Math.Cos(angle) * radiusStep,
|
||||
(float)Math.Sin(angle) * radiusStep);
|
||||
|
||||
var testPos = centerTile + offset;
|
||||
var testCoords = new EntityCoordinates(lockerCoords.EntityId, testPos);
|
||||
|
||||
var mapCoords = _transform.ToMapCoordinates(testCoords);
|
||||
var intersecting = _entityLookup.GetEntitiesIntersecting(mapCoords, LookupFlags.Dynamic)
|
||||
.Where(e => e != target).ToList();
|
||||
|
||||
if (intersecting.Count == 0)
|
||||
{
|
||||
_transform.SetCoordinates(target, testCoords);
|
||||
_lock.Unlock(locker, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformMoon(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
// Well, like i couldn't think of anything smarter
|
||||
var message = Loc.GetString("tarot-moon-m-message");
|
||||
if (TryComp<HumanoidAppearanceComponent>(target, out var humanoid) && humanoid.Gender == Gender.Female)
|
||||
message = Loc.GetString("tarot-moon-f-message");
|
||||
|
||||
_chat.TrySendInGameICMessage(target, message, InGameICChatType.Speak, false);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var grids = _mapManager.GetAllGrids(Transform(target).MapID)
|
||||
.Where(g => !HasComp<BecomesStationComponent>(g) && !HasComp<ProtectedGridComponent>(g)).ToList();
|
||||
|
||||
if (grids.Count == 0)
|
||||
return;
|
||||
|
||||
var randomGrid = _random.Pick(grids);
|
||||
_transform.SetCoordinates(target, Transform(randomGrid).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformSun(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
if (HasComp<PermanentBlindnessComponent>(target))
|
||||
return;
|
||||
|
||||
EnsureComp<PermanentBlindnessComponent>(target).Blindness = 4;
|
||||
Timer.Spawn(TimeSpan.FromMinutes(1), () => { RemComp<PermanentBlindnessComponent>(target); });
|
||||
}
|
||||
else
|
||||
{
|
||||
_rejuvenate.PerformRejuvenate(target);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformJudgement(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
/// Temporarily empty
|
||||
}
|
||||
else
|
||||
{
|
||||
// ALL GHOSTS BE MINE!!!
|
||||
var ghosts = new List<EntityUid>();
|
||||
var ghostsQuery = EntityQueryEnumerator<GhostComponent>();
|
||||
while (ghostsQuery.MoveNext(out var uid, out _))
|
||||
ghosts.Add(uid);
|
||||
|
||||
foreach (var ghost in ghosts)
|
||||
_transform.SetCoordinates(ghost, Transform(target).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformTheWorld(EntityUid target, bool reversed)
|
||||
{
|
||||
if (reversed)
|
||||
{
|
||||
// He should be doing something else, but that means "Temporarily empty." So it's a reference to JoJo
|
||||
var host = EnsureComp<GuardianHostComponent>(target);
|
||||
var guardian = Spawn(Stand, Transform(target).Coordinates);
|
||||
|
||||
_container.Insert(guardian, host.GuardianContainer);
|
||||
host.HostedGuardian = guardian;
|
||||
|
||||
if (TryComp<GuardianComponent>(guardian, out var guardianComp))
|
||||
guardianComp.Host = target;
|
||||
}
|
||||
else
|
||||
{
|
||||
Spawn(Smoke, Transform(target).Coordinates);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
63
Content.Server/_Wega/Chat/Commands/MindSayCommand.cs
Normal file
63
Content.Server/_Wega/Chat/Commands/MindSayCommand.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Enums;
|
||||
|
||||
namespace Content.Server.Chat.Commands
|
||||
{
|
||||
[AnyCommand]
|
||||
internal sealed class MindSayCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
|
||||
public override string Command => "mindsay";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (shell.Player is not { } player)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.Status != SessionStatus.InGame)
|
||||
return;
|
||||
|
||||
if (player.AttachedEntity is not { } playerEntity)
|
||||
{
|
||||
shell.WriteError(Loc.GetString($"shell-must-be-attached-to-entity"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 1)
|
||||
return;
|
||||
|
||||
var message = string.Join(" ", args).Trim();
|
||||
if (string.IsNullOrEmpty(message))
|
||||
return;
|
||||
|
||||
// Process the mind message
|
||||
if (_chatSystem.TryProcessMindMessage(playerEntity, message, out var modifiedMessage, out var channel))
|
||||
{
|
||||
if (channel != null)
|
||||
{
|
||||
// Check if entity has access to the channel
|
||||
if (EntityManager.TryGetComponent<MindLinkComponent>(playerEntity, out var mindLink) &&
|
||||
mindLink.Channels.Contains(channel.ID))
|
||||
{
|
||||
_chatSystem.SendMindMessage(playerEntity, modifiedMessage, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
shell.WriteError(Loc.GetString("chat-manager-no-access-mind-channel"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shell.WriteError(Loc.GetString("chat-manager-no-mind-channel"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Content.Server/_Wega/Dice/DiceOfFateComponent.cs
Normal file
7
Content.Server/_Wega/Dice/DiceOfFateComponent.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Content.Server.Dice;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class DiceOfFateComponent : Component
|
||||
{
|
||||
public bool Used;
|
||||
}
|
||||
333
Content.Server/_Wega/Dice/DiceOfFateSystem.cs
Normal file
333
Content.Server/_Wega/Dice/DiceOfFateSystem.cs
Normal file
@@ -0,0 +1,333 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Antag;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Polymorph.Systems;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Administration.Systems;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Dice;
|
||||
using Content.Shared.Disease;
|
||||
using Content.Shared.Explosion;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.PDA;
|
||||
using Content.Shared.Polymorph;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Roles.Components;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Throwing;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Dice;
|
||||
|
||||
public sealed class DiceOfFateSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAccessSystem _access = default!;
|
||||
[Dependency] private readonly IAdminLogManager _admin = default!;
|
||||
[Dependency] private readonly AntagSelectionSystem _antag = default!;
|
||||
[Dependency] private readonly BodySystem _body = default!;
|
||||
[Dependency] private readonly DamageableSystem _damage = default!;
|
||||
[Dependency] private readonly SharedDiseaseSystem _disease = default!;
|
||||
[Dependency] private readonly ExplosionSystem _explosion = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _speed = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly PolymorphSystem _polymorph = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly RejuvenateSystem _rejuvenate = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DiceOfFateComponent, UseInHandEvent>(OnUseInHand, after: [typeof(SharedDiceSystem)]);
|
||||
SubscribeLocalEvent<DiceOfFateComponent, LandEvent>(OnLand, after: [typeof(SharedDiceSystem)]);
|
||||
}
|
||||
|
||||
private static readonly ProtoId<DamageModifierSetPrototype> DamageMod = "DiceOfFateMod";
|
||||
private static readonly ProtoId<PolymorphPrototype> Monkey = "Monkey";
|
||||
private static readonly ProtoId<DiseasePrototype> Cold = "SpaceCold";
|
||||
private static readonly ProtoId<DamageTypePrototype> Damage = "Asphyxiation";
|
||||
private static readonly EntProtoId RandomAgressive = "RandomAgressiveAnimal";
|
||||
private static readonly EntProtoId RandomSpellbook = "RandomSpellbook";
|
||||
private static readonly EntProtoId Revolver = "WeaponRevolverInspector";
|
||||
private static readonly EntProtoId DefaultWizardRule = "Wizard";
|
||||
private static readonly EntProtoId Cookie = "FoodBakedCookie";
|
||||
private static readonly EntProtoId Servant = "PlushieLizard";
|
||||
private static readonly EntProtoId Toolbox = "ToolboxThief";
|
||||
private static readonly EntProtoId Cash = "SpaceCash10000";
|
||||
|
||||
private void OnUseInHand(Entity<DiceOfFateComponent> entity, ref UseInHandEvent args)
|
||||
{
|
||||
if (!TryComp<DiceComponent>(entity, out var dice) || entity.Comp.Used)
|
||||
return;
|
||||
|
||||
entity.Comp.Used = true;
|
||||
RollFate(args.User, dice.CurrentValue);
|
||||
Timer.Spawn(TimeSpan.FromSeconds(1), () => { QueueDel(entity); }); // So that you can see the number
|
||||
}
|
||||
|
||||
private void OnLand(Entity<DiceOfFateComponent> entity, ref LandEvent args)
|
||||
{
|
||||
if (args.User == null || !TryComp<DiceComponent>(entity, out var dice)
|
||||
|| entity.Comp.Used)
|
||||
return;
|
||||
|
||||
entity.Comp.Used = true;
|
||||
RollFate(args.User.Value, dice.CurrentValue);
|
||||
Timer.Spawn(TimeSpan.FromSeconds(1), () => { QueueDel(entity); }); // So that you can see the number
|
||||
}
|
||||
|
||||
public void RollFate(EntityUid user, int value)
|
||||
{
|
||||
var success = value switch
|
||||
{
|
||||
1 => CompleteAnnihilation(user),
|
||||
2 => InstantDeath(user),
|
||||
3 => SummonAggressiveCreatures(user),
|
||||
4 => DestroyAllEquippedItems(user),
|
||||
5 => TransformIntoMonkey(user),
|
||||
6 => PermanentMovementSpeedReduction(user),
|
||||
7 => StunAndDamage(user),
|
||||
8 => ExplosionUser(user),
|
||||
9 => CommonCold(user),
|
||||
10 => NothingHappens(user),
|
||||
11 => SpawnCookie(user),
|
||||
12 => FullHealthRestoration(user),
|
||||
13 => SpawnMoney(user),
|
||||
14 => SpawnRevolver(user),
|
||||
15 => SpawnSpellbook(user),
|
||||
16 => SummonServant(user),
|
||||
17 => SuspiciousBeacon(user),
|
||||
18 => FullAccess(user),
|
||||
19 => PermanentDamageReduction(user),
|
||||
20 => BecomeWizard(user),
|
||||
_ => NothingHappens(user)
|
||||
};
|
||||
|
||||
_admin.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(user):user} rools fade is '{success}', got nimber {value}.");
|
||||
}
|
||||
|
||||
private bool CompleteAnnihilation(EntityUid user)
|
||||
{
|
||||
_body.GibBody(user, true, splatModifier: 10f);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool InstantDeath(EntityUid user)
|
||||
{
|
||||
var damage = new DamageSpecifier { DamageDict = { { Damage, 400 } } };
|
||||
_damage.ChangeDamage(user, damage, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SummonAggressiveCreatures(EntityUid user)
|
||||
{
|
||||
var count = _random.Next(3, 6);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
Spawn(RandomAgressive, Transform(user).Coordinates);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DestroyAllEquippedItems(EntityUid user)
|
||||
{
|
||||
if (_inventory.TryGetSlots(user, out var slots))
|
||||
{
|
||||
foreach (var slot in slots)
|
||||
{
|
||||
if (_inventory.TryGetSlotEntity(user, slot.Name, out var ent))
|
||||
QueueDel(ent);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TransformIntoMonkey(EntityUid user)
|
||||
{
|
||||
_polymorph.PolymorphEntity(user, Monkey);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool PermanentMovementSpeedReduction(EntityUid user)
|
||||
{
|
||||
if (TryComp(user, out MovementSpeedModifierComponent? speedmod))
|
||||
{
|
||||
var originalWalkSpeed = speedmod.BaseWalkSpeed;
|
||||
var originalSprintSpeed = speedmod.BaseSprintSpeed;
|
||||
|
||||
var multiplier = _random.NextFloat(0.3f, 0.95f);
|
||||
_speed.ChangeBaseSpeed(user, originalWalkSpeed * multiplier, originalSprintSpeed * multiplier, speedmod.Acceleration, speedmod);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool StunAndDamage(EntityUid user)
|
||||
{
|
||||
_stun.TryKnockdown(user, TimeSpan.FromSeconds(30));
|
||||
var damage = new DamageSpecifier { DamageDict = { { Damage, 50 } } };
|
||||
_damage.ChangeDamage(user, damage, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ExplosionUser(EntityUid user)
|
||||
{
|
||||
if (!_prototype.TryIndex(ExplosionSystem.DefaultExplosionPrototypeId, out ExplosionPrototype? type))
|
||||
return false;
|
||||
|
||||
_explosion.QueueExplosion(user, type.ID, 5000f, 3f, 10f);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CommonCold(EntityUid user)
|
||||
{
|
||||
_disease.TryAddDisease(user, Cold);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool NothingHappens(EntityUid user)
|
||||
{
|
||||
// I'm Lazy
|
||||
_popup.PopupEntity(Loc.GetString("reagent-desc-nothing"), user, user);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SpawnCookie(EntityUid user)
|
||||
{
|
||||
var cookie = Spawn(Cookie, Transform(user).Coordinates);
|
||||
_hands.TryForcePickupAnyHand(user, cookie);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool FullHealthRestoration(EntityUid user)
|
||||
{
|
||||
_rejuvenate.PerformRejuvenate(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SpawnMoney(EntityUid user)
|
||||
{
|
||||
var cash = Spawn(Cash, Transform(user).Coordinates);
|
||||
_hands.TryForcePickupAnyHand(user, cash);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SpawnRevolver(EntityUid user)
|
||||
{
|
||||
var revolver = Spawn(Revolver, Transform(user).Coordinates);
|
||||
_hands.TryForcePickupAnyHand(user, revolver);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SpawnSpellbook(EntityUid user)
|
||||
{
|
||||
var spellbook = Spawn(RandomSpellbook, Transform(user).Coordinates);
|
||||
_hands.TryForcePickupAnyHand(user, spellbook);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Very goodluck
|
||||
private bool SummonServant(EntityUid user)
|
||||
{
|
||||
var servant = Spawn(Servant, Transform(user).Coordinates);
|
||||
_hands.TryForcePickupAnyHand(user, servant);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SuspiciousBeacon(EntityUid user)
|
||||
{
|
||||
var toolbox = Spawn(Toolbox, Transform(user).Coordinates);
|
||||
_hands.TryForcePickupAnyHand(user, toolbox);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool FullAccess(EntityUid user)
|
||||
{
|
||||
var ent = FindActiveId(user);
|
||||
if (ent == null)
|
||||
return false;
|
||||
|
||||
GiveAllAccess(ent.Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
private EntityUid? FindActiveId(EntityUid target)
|
||||
{
|
||||
if (_inventory.TryGetSlotEntity(target, "id", out var slotEntity))
|
||||
{
|
||||
if (HasComp<AccessComponent>(slotEntity))
|
||||
{
|
||||
return slotEntity.Value;
|
||||
}
|
||||
else if (TryComp<PdaComponent>(slotEntity, out var pda)
|
||||
&& HasComp<IdCardComponent>(pda.ContainedId))
|
||||
{
|
||||
return pda.ContainedId;
|
||||
}
|
||||
}
|
||||
else if (TryComp<HandsComponent>(target, out var hands))
|
||||
{
|
||||
foreach (var held in _hands.EnumerateHeld((target, hands)))
|
||||
{
|
||||
if (HasComp<AccessComponent>(held))
|
||||
{
|
||||
return held;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void GiveAllAccess(EntityUid entity)
|
||||
{
|
||||
var allAccess = _prototype
|
||||
.EnumeratePrototypes<AccessLevelPrototype>()
|
||||
.Select(p => new ProtoId<AccessLevelPrototype>(p.ID)).ToArray();
|
||||
|
||||
_access.TrySetTags(entity, allAccess);
|
||||
}
|
||||
|
||||
private bool PermanentDamageReduction(EntityUid user)
|
||||
{
|
||||
_damage.SetDamageModifierSetId(user, DamageMod);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool BecomeWizard(EntityUid user)
|
||||
{
|
||||
if (!TryComp<ActorComponent>(user, out var actor))
|
||||
return false;
|
||||
|
||||
_antag.ForceMakeAntag<WizardRoleComponent>(actor.PlayerSession, DefaultWizardRule);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,14 @@ using System.Linq;
|
||||
using Content.Server.Actions;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Antag;
|
||||
using Content.Server.Blood.Cult;
|
||||
using Content.Server.Bed.Cryostorage;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Objectives;
|
||||
using Content.Server.Objectives.Components;
|
||||
using Content.Server.Objectives.Systems;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Shared.Blood.Cult;
|
||||
@@ -18,14 +21,17 @@ using Content.Shared.Database;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mindshield.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.NPC.Prototypes;
|
||||
using Content.Shared.NPC.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Zombies;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules
|
||||
{
|
||||
@@ -34,7 +40,6 @@ namespace Content.Server.GameTicking.Rules
|
||||
[Dependency] private readonly ActionsSystem _action = default!;
|
||||
[Dependency] private readonly AntagSelectionSystem _antag = default!;
|
||||
[Dependency] private readonly BodySystem _body = default!;
|
||||
[Dependency] private readonly BloodCultSystem _cult = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _player = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogManager = default!;
|
||||
@@ -44,6 +49,12 @@ namespace Content.Server.GameTicking.Rules
|
||||
[Dependency] private readonly RoleSystem _role = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly ObjectivesSystem _objectives = default!;
|
||||
[Dependency] private readonly TargetObjectiveSystem _target = default!;
|
||||
[Dependency] private readonly MetaDataSystem _meta = default!;
|
||||
|
||||
public readonly ProtoId<NpcFactionPrototype> BloodCultNpcFaction = "BloodCult";
|
||||
|
||||
@@ -54,44 +65,164 @@ namespace Content.Server.GameTicking.Rules
|
||||
SubscribeLocalEvent<BloodCultRuleComponent, ComponentStartup>(OnRuleStartup);
|
||||
SubscribeLocalEvent<BloodCultRuleComponent, AfterAntagEntitySelectedEvent>(OnCultistSelected);
|
||||
|
||||
SubscribeLocalEvent<BloodCultistComponent, ComponentStartup>((_, _, _) => CheckStage());
|
||||
SubscribeLocalEvent<BloodCultConstructComponent, ComponentStartup>((_, _, _) => CheckStage());
|
||||
SubscribeLocalEvent<BloodCultObjectComponent, ComponentShutdown>(OnBloodCultObjectShutdown);
|
||||
SubscribeLocalEvent<BloodCultObjectComponent, CryostorageEnterEvent>(OnCryostorageEnter);
|
||||
|
||||
SubscribeLocalEvent<GodCalledEvent>(OnGodCalled);
|
||||
SubscribeLocalEvent<RitualConductedEvent>(OnRitualConducted);
|
||||
|
||||
SubscribeLocalEvent<AutoCultistComponent, ComponentStartup>(OnAutoCultistAdded);
|
||||
SubscribeLocalEvent<BloodCultistComponent, ComponentRemove>(OnComponentRemove);
|
||||
SubscribeLocalEvent<BloodCultistComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
SubscribeLocalEvent<BloodCultistComponent, EntityZombifiedEvent>(OnOperativeZombified);
|
||||
SubscribeLocalEvent<BloodCultistComponent, EntityZombifiedEvent>(OnCultistZombified);
|
||||
}
|
||||
|
||||
private void OnRuleStartup(EntityUid uid, BloodCultRuleComponent component, ComponentStartup args)
|
||||
{
|
||||
List<string> gods = new List<string> { "Narsie", "Reaper", "Kharin" };
|
||||
component.SelectedGod = gods[new Random().Next(gods.Count)];
|
||||
Timer.Spawn(TimeSpan.FromMinutes(1), _cult.SelectRandomTargets);
|
||||
component.SelectedGod = (BloodCultGod)_random.Next(0, 3);
|
||||
}
|
||||
|
||||
private void OnCryostorageEnter(EntityUid uid, BloodCultObjectComponent component, CryostorageEnterEvent args)
|
||||
{
|
||||
var cult = GetActiveRule();
|
||||
if (cult == null)
|
||||
return;
|
||||
|
||||
if (!cult.SelectedTargets.Contains(uid))
|
||||
return;
|
||||
|
||||
var newTarget = FindNewRandomTarget(cult, uid);
|
||||
if (newTarget == null)
|
||||
return;
|
||||
|
||||
ReplaceTargetForAllCultists(uid, newTarget.Value);
|
||||
|
||||
cult.SelectedTargets.Remove(uid);
|
||||
cult.SelectedTargets.Add(newTarget.Value);
|
||||
|
||||
RemComp<BloodCultObjectComponent>(uid);
|
||||
EnsureComp<BloodCultObjectComponent>(newTarget.Value);
|
||||
}
|
||||
|
||||
#region Cultist Processing
|
||||
|
||||
private void OnCultistSelected(Entity<BloodCultRuleComponent> mindId, ref AfterAntagEntitySelectedEvent args)
|
||||
{
|
||||
var ent = args.EntityUid;
|
||||
|
||||
if (mindId.Comp.SelectedTargets.Count == 0)
|
||||
SelectRandomTargets(mindId.Comp);
|
||||
|
||||
MakeCultist(ent);
|
||||
_antag.SendBriefing(ent, MakeBriefing(ent), Color.Red, null);
|
||||
}
|
||||
|
||||
private void SelectRandomTargets(BloodCultRuleComponent cult)
|
||||
{
|
||||
cult.SelectedTargets.Clear();
|
||||
|
||||
var mindShieldCandidates = new List<EntityUid>();
|
||||
var enumerator = EntityQueryEnumerator<MindShieldComponent>();
|
||||
while (enumerator.MoveNext(out var uid, out _))
|
||||
mindShieldCandidates.Add(uid);
|
||||
|
||||
if (mindShieldCandidates.Count >= 2)
|
||||
{
|
||||
var selectedIndices = new HashSet<int>();
|
||||
while (selectedIndices.Count < 2)
|
||||
{
|
||||
var index = _random.Next(0, mindShieldCandidates.Count);
|
||||
selectedIndices.Add(index);
|
||||
}
|
||||
|
||||
foreach (var index in selectedIndices)
|
||||
{
|
||||
var target = mindShieldCandidates[index];
|
||||
cult.SelectedTargets.Add(target);
|
||||
EnsureComp<BloodCultObjectComponent>(target);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var target in mindShieldCandidates)
|
||||
{
|
||||
cult.SelectedTargets.Add(target);
|
||||
EnsureComp<BloodCultObjectComponent>(target);
|
||||
}
|
||||
|
||||
var globalCandidates = new List<EntityUid>();
|
||||
var globalEnumerator = EntityQueryEnumerator<HumanoidAppearanceComponent, ActorComponent>();
|
||||
while (globalEnumerator.MoveNext(out var uid, out _, out _))
|
||||
{
|
||||
if (cult.SelectedTargets.Contains(uid) || HasComp<BloodCultistComponent>(uid))
|
||||
continue;
|
||||
|
||||
globalCandidates.Add(uid);
|
||||
}
|
||||
|
||||
while (cult.SelectedTargets.Count < 2 && globalCandidates.Count > 0)
|
||||
{
|
||||
var index = _random.Next(0, globalCandidates.Count);
|
||||
var target = globalCandidates[index];
|
||||
cult.SelectedTargets.Add(target);
|
||||
EnsureComp<BloodCultObjectComponent>(target);
|
||||
globalCandidates.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
private EntityUid? FindNewRandomTarget(BloodCultRuleComponent cult, EntityUid excludedTarget)
|
||||
{
|
||||
var candidates = new List<EntityUid>();
|
||||
var query = EntityQueryEnumerator<HumanoidAppearanceComponent, ActorComponent>();
|
||||
while (query.MoveNext(out var uid, out _, out _))
|
||||
{
|
||||
if (uid == excludedTarget || cult.SelectedTargets.Contains(uid)
|
||||
|| HasComp<BloodCultistComponent>(uid)
|
||||
|| HasComp<BloodCultObjectComponent>(uid))
|
||||
continue;
|
||||
|
||||
candidates.Add(uid);
|
||||
}
|
||||
|
||||
if (candidates.Count == 0)
|
||||
return null;
|
||||
|
||||
var index = _random.Next(0, candidates.Count);
|
||||
return candidates[index];
|
||||
}
|
||||
|
||||
private void ReplaceTargetForAllCultists(EntityUid oldTarget, EntityUid newTarget)
|
||||
{
|
||||
var replacedObjectives = new List<EntityUid>();
|
||||
var query = EntityQueryEnumerator<TargetObjectiveComponent, BloodCultTargetObjectiveComponent>();
|
||||
while (query.MoveNext(out var objectiveUid, out var targetComp, out _))
|
||||
{
|
||||
if (targetComp.Target == oldTarget)
|
||||
{
|
||||
replacedObjectives.Add(objectiveUid);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var objectiveUid in replacedObjectives)
|
||||
{
|
||||
_target.SetTarget(objectiveUid, newTarget);
|
||||
_meta.SetEntityName(objectiveUid, Loc.GetString("objective-condition-blood-ritual-person-title",
|
||||
("targetName", Name(newTarget))));
|
||||
}
|
||||
}
|
||||
|
||||
private void MakeCultist(EntityUid ent)
|
||||
{
|
||||
var actionPrototypes = new[]
|
||||
{
|
||||
BloodCultistComponent.CultObjective,
|
||||
BloodCultistComponent.CultCommunication,
|
||||
BloodCultistComponent.BloodMagic,
|
||||
BloodCultistComponent.RecallBloodDagger
|
||||
};
|
||||
|
||||
foreach (var actionPrototype in actionPrototypes)
|
||||
{
|
||||
_action.AddAction(ent, actionPrototype);
|
||||
}
|
||||
|
||||
var componentsToRemove = new[]
|
||||
{
|
||||
@@ -100,25 +231,65 @@ namespace Content.Server.GameTicking.Rules
|
||||
};
|
||||
|
||||
foreach (var compType in componentsToRemove)
|
||||
{
|
||||
if (HasComp(ent, compType))
|
||||
RemComp(ent, compType);
|
||||
}
|
||||
RemComp(ent, compType);
|
||||
|
||||
HandleMetabolism(ent);
|
||||
CreateObjectivesForCultist(ent);
|
||||
}
|
||||
|
||||
private void CreateObjectivesForCultist(EntityUid cultist)
|
||||
{
|
||||
var cult = GetActiveRule();
|
||||
if (cult == null || cult.SelectedTargets.Count == 0)
|
||||
return;
|
||||
|
||||
if (!_mind.TryGetMind(cultist, out var mindId, out var mind))
|
||||
return;
|
||||
|
||||
foreach (var target in cult.SelectedTargets)
|
||||
{
|
||||
if (!Exists(target))
|
||||
continue;
|
||||
|
||||
var objective = _objectives.TryCreateObjective(mindId, mind, cult.ObjectivePrototype);
|
||||
if (objective == null)
|
||||
continue;
|
||||
|
||||
_target.SetTarget(objective.Value, target);
|
||||
_meta.SetEntityName(objective.Value, Loc.GetString("objective-condition-blood-ritual-person-title",
|
||||
("targetName", Name(target)))); // <see cref="ObjectiveAssignedEvent"/> here doesn't worked, or i'm stupid
|
||||
_mind.AddObjective(mindId, mind, objective.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMetabolism(EntityUid cultist)
|
||||
{
|
||||
if (TryComp<BodyComponent>(cultist, out var bodyComponent))
|
||||
{
|
||||
foreach (var organ in _body.GetBodyOrgans(cultist, bodyComponent))
|
||||
{
|
||||
if (TryComp<MetabolizerComponent>(organ.Id, out var metabolizer))
|
||||
{
|
||||
if (TryComp<StomachComponent>(organ.Id, out _))
|
||||
_metabolism.ClearMetabolizerTypes(metabolizer);
|
||||
|
||||
_metabolism.TryAddMetabolizerType(metabolizer, "BloodCultist");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string MakeBriefing(EntityUid ent)
|
||||
{
|
||||
string selectedGod = Loc.GetString("current-god-narsie");
|
||||
string selectedGod = "";
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out _, out _, out var cult, out _))
|
||||
{
|
||||
selectedGod = cult.SelectedGod switch
|
||||
{
|
||||
"Narsie" => Loc.GetString("current-god-narsie"),
|
||||
"Reaper" => Loc.GetString("current-god-reaper"),
|
||||
"Kharin" => Loc.GetString("current-god-kharin"),
|
||||
BloodCultGod.NarSi => Loc.GetString("current-god-narsie"),
|
||||
BloodCultGod.Reaper => Loc.GetString("current-god-reaper"),
|
||||
BloodCultGod.Kharin => Loc.GetString("current-god-kharin"),
|
||||
_ => Loc.GetString("current-god-narsie")
|
||||
};
|
||||
break;
|
||||
@@ -153,11 +324,11 @@ namespace Content.Server.GameTicking.Rules
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out _, out _, out var cult, out _))
|
||||
{
|
||||
string selectedDagger = cult.SelectedGod switch
|
||||
EntProtoId selectedDagger = cult.SelectedGod switch
|
||||
{
|
||||
"Narsie" => "WeaponBloodDagger",
|
||||
"Reaper" => "WeaponDeathDagger",
|
||||
"Kharin" => "WeaponHellDagger",
|
||||
BloodCultGod.NarSi => "WeaponBloodDagger",
|
||||
BloodCultGod.Reaper => "WeaponDeathDagger",
|
||||
BloodCultGod.Kharin => "WeaponHellDagger",
|
||||
_ => "WeaponBloodDagger"
|
||||
};
|
||||
|
||||
@@ -168,23 +339,134 @@ namespace Content.Server.GameTicking.Rules
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMetabolism(EntityUid cultist)
|
||||
{
|
||||
if (TryComp<BodyComponent>(cultist, out var bodyComponent))
|
||||
{
|
||||
foreach (var organ in _body.GetBodyOrgans(cultist, bodyComponent))
|
||||
{
|
||||
if (TryComp<MetabolizerComponent>(organ.Id, out var metabolizer))
|
||||
{
|
||||
if (TryComp<StomachComponent>(organ.Id, out _))
|
||||
_metabolism.ClearMetabolizerTypes(metabolizer);
|
||||
#endregion
|
||||
|
||||
_metabolism.TryAddMetabolizerType(metabolizer, "Cultist");
|
||||
#region Stages
|
||||
|
||||
private void OnBloodCultObjectShutdown(EntityUid uid, BloodCultObjectComponent component, ComponentShutdown args)
|
||||
{
|
||||
var cult = GetActiveRule();
|
||||
if (cult == null)
|
||||
return;
|
||||
|
||||
if (!cult.SelectedTargets.Contains(uid))
|
||||
{
|
||||
CheckStage();
|
||||
if (cult.SelectedTargets.Count == 0)
|
||||
RaiseLocalEvent(new RitualConductedEvent());
|
||||
return;
|
||||
}
|
||||
|
||||
var newTarget = FindNewRandomTarget(cult, uid);
|
||||
if (newTarget == null)
|
||||
return;
|
||||
|
||||
ReplaceTargetForAllCultists(uid, newTarget.Value);
|
||||
|
||||
cult.SelectedTargets.Remove(uid);
|
||||
cult.SelectedTargets.Add(newTarget.Value);
|
||||
|
||||
EnsureComp<BloodCultObjectComponent>(newTarget.Value);
|
||||
}
|
||||
|
||||
private void CheckStage()
|
||||
{
|
||||
var cult = GetActiveRule();
|
||||
if (cult == null)
|
||||
return;
|
||||
|
||||
var totalCultEntities = GetCultEntities();
|
||||
var playerCount = GetPlayerCount();
|
||||
|
||||
// Second
|
||||
if (playerCount >= 100 && totalCultEntities >= playerCount * 0.1f || playerCount < 100 && totalCultEntities >= playerCount * 0.2f || cult.RitualStage)
|
||||
{
|
||||
foreach (var cultist in GetAllCultists())
|
||||
{
|
||||
if (!HasComp<BloodCultistEyesComponent>(cultist))
|
||||
{
|
||||
UpdateCultistEyes(cultist);
|
||||
AddComp<BloodCultistEyesComponent>(cultist);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cult.FirstTriggered)
|
||||
{
|
||||
var actorFilter = Filter.Empty();
|
||||
var actorQuery = EntityQueryEnumerator<ActorComponent, BloodCultistComponent>();
|
||||
while (actorQuery.MoveNext(out var actorUid, out var actor, out _))
|
||||
{
|
||||
actorFilter.AddPlayer(actor.PlayerSession);
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-first-warning"), actorUid, actorUid, PopupType.SmallCaution);
|
||||
}
|
||||
|
||||
_audio.PlayGlobal(new SoundPathSpecifier("/Audio/_Wega/Ambience/Antag/bloodcult_eyes.ogg"), actorFilter, true);
|
||||
cult.FirstTriggered = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Third
|
||||
if (playerCount >= 100 && totalCultEntities >= playerCount * 0.2f || playerCount < 100 && totalCultEntities >= playerCount * 0.3f || cult.RitualStage)
|
||||
{
|
||||
foreach (var cultist in GetAllCultists())
|
||||
{
|
||||
EnsureComp<BloodPentagramDisplayComponent>(cultist);
|
||||
}
|
||||
|
||||
if (!cult.SecondTriggered)
|
||||
{
|
||||
var actorFilter = Filter.Empty();
|
||||
var actorQuery = EntityQueryEnumerator<ActorComponent, BloodCultistComponent>();
|
||||
while (actorQuery.MoveNext(out var actorUid, out var actor, out _))
|
||||
{
|
||||
actorFilter.AddPlayer(actor.PlayerSession);
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-second-warning"), actorUid, actorUid, PopupType.SmallCaution);
|
||||
}
|
||||
|
||||
_audio.PlayGlobal(new SoundPathSpecifier("/Audio/_Wega/Ambience/Antag/bloodcult_halos.ogg"), actorFilter, true);
|
||||
cult.SecondTriggered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCultistEyes(EntityUid cultist)
|
||||
{
|
||||
if (TryComp<HumanoidAppearanceComponent>(cultist, out var appearanceComponent))
|
||||
{
|
||||
appearanceComponent.EyeColor = Color.FromHex("#E22218FF");
|
||||
Dirty(cultist, appearanceComponent);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetCultEntities()
|
||||
{
|
||||
var totalCultists = GetAllCultists().Count;
|
||||
var totalConstructs = EntityQuery<BloodCultConstructComponent>().Count();
|
||||
return totalCultists + totalConstructs;
|
||||
}
|
||||
|
||||
private int GetPlayerCount()
|
||||
{
|
||||
int count = 0;
|
||||
var players = AllEntityQuery<HumanoidAppearanceComponent, ActorComponent, TransformComponent>();
|
||||
while (players.MoveNext(out _, out _, out _, out _))
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private List<EntityUid> GetAllCultists()
|
||||
{
|
||||
var cultists = new List<EntityUid>();
|
||||
var enumerator = EntityQueryEnumerator<BloodCultistComponent>();
|
||||
while (enumerator.MoveNext(out var uid, out _))
|
||||
cultists.Add(uid);
|
||||
|
||||
return cultists;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void AppendRoundEndText(EntityUid uid,
|
||||
BloodCultRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
@@ -208,69 +490,71 @@ namespace Content.Server.GameTicking.Rules
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGodCalled(GodCalledEvent ev)
|
||||
public BloodCultRuleComponent? GetActiveRule()
|
||||
{
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out _, out _, out var cult, out _))
|
||||
{
|
||||
if (cult.BloodCultWinCondition.Contains(BloodCultWinType.RitualConducted))
|
||||
cult.BloodCultWinCondition.Remove(BloodCultWinType.RitualConducted);
|
||||
return cult;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
cult.WinType = BloodCultWinType.GodCalled;
|
||||
private void OnGodCalled(GodCalledEvent ev)
|
||||
{
|
||||
var cult = GetActiveRule();
|
||||
if (cult == null)
|
||||
return;
|
||||
|
||||
if (!cult.BloodCultWinCondition.Contains(BloodCultWinType.GodCalled))
|
||||
{
|
||||
cult.BloodCultWinCondition.Add(BloodCultWinType.GodCalled);
|
||||
_roundEndSystem.DoRoundEndBehavior(RoundEndBehavior.ShuttleCall, TimeSpan.FromMinutes(1f));
|
||||
}
|
||||
if (cult.BloodCultWinCondition.Contains(BloodCultWinType.RitualConducted))
|
||||
cult.BloodCultWinCondition.Remove(BloodCultWinType.RitualConducted);
|
||||
|
||||
cult.WinType = BloodCultWinType.GodCalled;
|
||||
|
||||
if (!cult.BloodCultWinCondition.Contains(BloodCultWinType.GodCalled))
|
||||
{
|
||||
cult.BloodCultWinCondition.Add(BloodCultWinType.GodCalled);
|
||||
_roundEndSystem.DoRoundEndBehavior(RoundEndBehavior.ShuttleCall, TimeSpan.FromMinutes(1f));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRitualConducted(RitualConductedEvent ev)
|
||||
{
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out _, out _, out var cult, out _))
|
||||
{
|
||||
cult.WinType = BloodCultWinType.RitualConducted;
|
||||
var cult = GetActiveRule();
|
||||
if (cult == null)
|
||||
return;
|
||||
|
||||
if (!cult.BloodCultWinCondition.Contains(BloodCultWinType.RitualConducted))
|
||||
cult.BloodCultWinCondition.Add(BloodCultWinType.RitualConducted);
|
||||
}
|
||||
cult.RitualStage = true;
|
||||
cult.WinType = BloodCultWinType.RitualConducted;
|
||||
|
||||
CheckStage();
|
||||
|
||||
if (!cult.BloodCultWinCondition.Contains(BloodCultWinType.RitualConducted))
|
||||
cult.BloodCultWinCondition.Add(BloodCultWinType.RitualConducted);
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(EntityUid uid, BloodCultistComponent component, MobStateChangedEvent ev)
|
||||
{
|
||||
if (ev.NewMobState == MobState.Dead)
|
||||
{
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out var ruleUid, out _, out var cult, out _))
|
||||
{
|
||||
CheckCultLose(ruleUid, cult);
|
||||
}
|
||||
}
|
||||
CheckCultLose(GetActiveRule());
|
||||
}
|
||||
|
||||
private void OnComponentRemove(EntityUid uid, BloodCultistComponent component, ComponentRemove args)
|
||||
{
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out var ruleUid, out _, out var cult, out _))
|
||||
{
|
||||
CheckCultLose(ruleUid, cult);
|
||||
}
|
||||
CheckCultLose(GetActiveRule());
|
||||
}
|
||||
|
||||
private void OnOperativeZombified(EntityUid uid, BloodCultistComponent component, EntityZombifiedEvent args)
|
||||
private void OnCultistZombified(EntityUid uid, BloodCultistComponent component, EntityZombifiedEvent args)
|
||||
{
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out var ruleUid, out _, out var cult, out _))
|
||||
{
|
||||
CheckCultLose(ruleUid, cult);
|
||||
}
|
||||
CheckCultLose(GetActiveRule());
|
||||
}
|
||||
|
||||
private void CheckCultLose(EntityUid uid, BloodCultRuleComponent cult)
|
||||
private void CheckCultLose(BloodCultRuleComponent? cult)
|
||||
{
|
||||
var hasLivingCultists = EntityManager.EntityQuery<BloodCultistComponent>().Any();
|
||||
if (cult == null)
|
||||
return;
|
||||
|
||||
var hasLivingCultists = EntityQuery<BloodCultistComponent>().Any();
|
||||
if (!hasLivingCultists && !cult.BloodCultWinCondition.Contains(BloodCultWinType.GodCalled)
|
||||
&& !cult.BloodCultWinCondition.Contains(BloodCultWinType.RitualConducted))
|
||||
{
|
||||
|
||||
@@ -1,19 +1,38 @@
|
||||
using Content.Server.Blood.Cult;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Stores data for <see cref="BloodCultRuleSystem"/>.
|
||||
/// Stores data for <see cref="BloodCultRuleSystem"/> and <see cref="BloodCultSystem"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(BloodCultRuleSystem))]
|
||||
[RegisterComponent, Access(typeof(BloodCultRuleSystem), typeof(BloodCultSystem))]
|
||||
public sealed partial class BloodCultRuleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string? SelectedGod;
|
||||
public BloodCultGod? SelectedGod;
|
||||
|
||||
[DataField]
|
||||
public BloodCultWinType WinType = BloodCultWinType.Neutral;
|
||||
|
||||
[DataField]
|
||||
public List<BloodCultWinType> BloodCultWinCondition = new();
|
||||
|
||||
[DataField]
|
||||
public HashSet<EntityUid> SelectedTargets = new();
|
||||
|
||||
public EntProtoId ObjectivePrototype = "BloodCultTargetObjective";
|
||||
|
||||
[DataField]
|
||||
public int Curses = 2;
|
||||
|
||||
[DataField]
|
||||
public int Offerings = 3;
|
||||
|
||||
[DataField] public bool FirstTriggered;
|
||||
[DataField] public bool SecondTriggered;
|
||||
[DataField] public bool RitualStage;
|
||||
}
|
||||
|
||||
public enum BloodCultWinType : byte
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Content.Server.Objectives.Systems;
|
||||
|
||||
namespace Content.Server.Objectives.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A goal that requires completion of the ritual.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(BloodCultRitualObjectiveSystem))]
|
||||
public sealed partial class BloodCultRitualObjectiveComponent : Component;
|
||||
@@ -0,0 +1,9 @@
|
||||
using Content.Server.Objectives.Systems;
|
||||
|
||||
namespace Content.Server.Objectives.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A common elimination task.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(BloodCultTargetObjectiveSystem))]
|
||||
public sealed partial class BloodCultTargetObjectiveComponent : Component;
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Objectives.Components;
|
||||
using Content.Shared.Objectives.Components;
|
||||
|
||||
namespace Content.Server.Objectives.Systems;
|
||||
|
||||
public sealed class BloodCultRitualObjectiveSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly BloodCultRuleSystem _bloodCult = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BloodCultRitualObjectiveComponent, ObjectiveGetProgressEvent>(OnGetProgress);
|
||||
}
|
||||
|
||||
private void OnGetProgress(EntityUid uid, BloodCultRitualObjectiveComponent comp, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
var cult = _bloodCult.GetActiveRule();
|
||||
if (cult == null || !cult.RitualStage)
|
||||
{
|
||||
args.Progress = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
var condition = cult.BloodCultWinCondition.ToList();
|
||||
if (condition.Contains(BloodCultWinType.GodCalled))
|
||||
{
|
||||
args.Progress = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Progress = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Content.Server.Objectives.Components;
|
||||
using Content.Shared.Objectives.Components;
|
||||
|
||||
namespace Content.Server.Objectives.Systems;
|
||||
|
||||
public sealed class BloodCultTargetObjectiveSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly TargetObjectiveSystem _target = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BloodCultTargetObjectiveComponent, ObjectiveGetProgressEvent>(OnGetProgress);
|
||||
}
|
||||
|
||||
private void OnGetProgress(EntityUid uid, BloodCultTargetObjectiveComponent comp, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
if (!_target.GetTarget(uid, out var target))
|
||||
return;
|
||||
|
||||
if (!Exists(target))
|
||||
{
|
||||
args.Progress = 1f;
|
||||
return;
|
||||
}
|
||||
|
||||
args.Progress = 0f;
|
||||
}
|
||||
}
|
||||
469
Content.Server/_Wega/SlotMachine/SlotMachineSystem.cs
Normal file
469
Content.Server/_Wega/SlotMachine/SlotMachineSystem.cs
Normal file
@@ -0,0 +1,469 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Destructible;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Stack;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Economy.SlotMachine;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Economy.SlotMachine;
|
||||
|
||||
public sealed class SlotMachineSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly DamageableSystem _damage = default!;
|
||||
[Dependency] private readonly DestructibleSystem _destructible = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly StackSystem _stack = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
private static readonly string[] AllSymbols = { "♥", "★", "♠", "♦", "♣", "♡" };
|
||||
private static readonly string[] CursedSymbols = { "☠", "🩸", "☢", "☣" };
|
||||
private static readonly string[] CursedWinSymbols = { "💰", "♔", "🎮" };
|
||||
private static readonly ProtoId<StackPrototype> Credit = "Credit";
|
||||
private static readonly EntProtoId SpaceCash = "SpaceCash";
|
||||
private static readonly EntProtoId Reward = "DiceOfFate";
|
||||
|
||||
private const float JackpotChance = 0.0002f;
|
||||
private const float BigWinChance = 0.004f;
|
||||
private const float MediumWinChance = 0.016f;
|
||||
private const float SmallWinChance = 0.08f;
|
||||
private const float TinyWinChance = 0.1f;
|
||||
private const float CursedWinChance = 0.05f;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SlotMachineComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<SlotMachineComponent, ExaminedEvent>(OnExamined);
|
||||
SubscribeLocalEvent<SlotMachineComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<SlotMachineComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if (comp.Working && comp.SpinFinishTime.HasValue)
|
||||
{
|
||||
if (_timing.CurTime >= comp.SpinFinishTime.Value)
|
||||
FinishSpin(uid, comp);
|
||||
else
|
||||
UpdateSlotsAnimation(uid, comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, SlotMachineComponent comp, MapInitEvent args)
|
||||
=> UpdateAppearance(uid);
|
||||
|
||||
private void OnExamined(Entity<SlotMachineComponent> entity, ref ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
string slots = string.Empty;
|
||||
foreach (var slot in entity.Comp.Slots)
|
||||
slots += $"{slot} ";
|
||||
|
||||
args.PushMarkup(Loc.GetString("slot-machine-examine", ("slots", slots.Trim()), ("spins", entity.Comp.Plays)));
|
||||
|
||||
if (TryComp<CursedSlotMachineComponent>(entity, out var cursedComp))
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("cursed-slot-machine-uses",
|
||||
("uses", cursedComp.Uses), ("max", cursedComp.MaxUses)));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInteractUsing(Entity<SlotMachineComponent> entity, ref InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = TrySpin(entity, args.User, args.Used);
|
||||
}
|
||||
|
||||
public bool TrySpin(Entity<SlotMachineComponent> entity, EntityUid user, EntityUid used)
|
||||
{
|
||||
if (!TryComp<StackComponent>(used, out var stack))
|
||||
return false;
|
||||
|
||||
if (entity.Comp.Working)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("slot-machine-busy"), user, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isCursed = HasComp<CursedSlotMachineComponent>(entity);
|
||||
if (!this.IsPowered(entity.Owner, EntityManager) && !isCursed)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("slot-machine-unpowered"), user, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stack.StackTypeId != Credit)
|
||||
return false;
|
||||
|
||||
if (isCursed)
|
||||
{
|
||||
var cursedComp = Comp<CursedSlotMachineComponent>(entity);
|
||||
if (cursedComp.Uses >= cursedComp.MaxUses)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cursed-slot-machine-deny"), user, user, PopupType.SmallCaution);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.Count < entity.Comp.SpinCost)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("slot-machine-no-money"), user, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
StartSpin(entity, user, isCursed);
|
||||
_stack.ReduceCount(used, entity.Comp.SpinCost);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void StartSpin(Entity<SlotMachineComponent> entity, EntityUid user, bool isCursed)
|
||||
{
|
||||
entity.Comp.User = user;
|
||||
|
||||
var spinTime = isCursed ? 5 : 2.5;
|
||||
entity.Comp.SpinFinishTime = _timing.CurTime + TimeSpan.FromSeconds(spinTime);
|
||||
entity.Comp.Working = true;
|
||||
entity.Comp.Plays++;
|
||||
|
||||
entity.Comp.Slots = new[] { "?", "?", "?" };
|
||||
|
||||
UpdateAppearance(entity.Owner);
|
||||
|
||||
if (isCursed && TryComp<CursedSlotMachineComponent>(entity, out var cursedComp))
|
||||
{
|
||||
_audio.PlayPvs(entity.Comp.CoinSound, entity);
|
||||
_audio.PlayPvs(cursedComp.RollSound, entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_audio.PlayPvs(entity.Comp.CoinSound, entity);
|
||||
_audio.PlayPvs(entity.Comp.RollSound, entity);
|
||||
}
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("slot-machine-spinning"), user, user);
|
||||
|
||||
if (isCursed)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cursed-slot-machine-spin", ("name", Identity.Name(user, EntityManager))),
|
||||
entity.Owner, PopupType.Medium);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSlotsAnimation(EntityUid uid, SlotMachineComponent comp)
|
||||
{
|
||||
var symbols = HasComp<CursedSlotMachineComponent>(uid) ? CursedSymbols : AllSymbols;
|
||||
|
||||
for (int i = 0; i < comp.Slots.Length; i++)
|
||||
{
|
||||
if (_random.Prob(0.3f))
|
||||
{
|
||||
comp.Slots[i] = _random.Pick(symbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FinishSpin(EntityUid machineUid, SlotMachineComponent comp)
|
||||
{
|
||||
comp.Working = false;
|
||||
comp.SpinFinishTime = null;
|
||||
|
||||
if (TryComp<CursedSlotMachineComponent>(machineUid, out var cursed))
|
||||
{
|
||||
DetermineCursedResult(machineUid, comp, cursed);
|
||||
}
|
||||
else
|
||||
{
|
||||
DetermineNormalResult(machineUid, comp);
|
||||
}
|
||||
|
||||
UpdateAppearance(machineUid);
|
||||
|
||||
_audio.PlayPvs(comp.EndSound, machineUid);
|
||||
}
|
||||
|
||||
private void DetermineNormalResult(EntityUid machineUid, SlotMachineComponent comp)
|
||||
{
|
||||
var user = comp.User;
|
||||
if (user == null)
|
||||
return;
|
||||
|
||||
var rand = _random.NextFloat();
|
||||
|
||||
if (rand < JackpotChance)
|
||||
{
|
||||
GenerateJackpotSlots(comp);
|
||||
AwardJackpot(machineUid, comp, user.Value);
|
||||
}
|
||||
else if (rand < JackpotChance + BigWinChance)
|
||||
{
|
||||
GenerateBigWinSlots(comp);
|
||||
AwardBigWin(machineUid, comp, user.Value);
|
||||
}
|
||||
else if (rand < JackpotChance + BigWinChance + MediumWinChance)
|
||||
{
|
||||
GenerateMediumWinSlots(comp);
|
||||
AwardMediumWin(machineUid, comp, user.Value);
|
||||
}
|
||||
else if (rand < JackpotChance + BigWinChance + MediumWinChance + SmallWinChance)
|
||||
{
|
||||
GenerateSmallWinSlots(comp);
|
||||
AwardSmallWin(machineUid, comp, user.Value);
|
||||
}
|
||||
else if (rand < JackpotChance + BigWinChance + MediumWinChance + SmallWinChance + TinyWinChance)
|
||||
{
|
||||
GenerateTinyWinSlots(comp);
|
||||
AwardTinyWin(machineUid, comp, user.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateLoseSlots(comp);
|
||||
_popup.PopupEntity(Loc.GetString("slot-machine-lose"), user.Value, user.Value);
|
||||
_audio.PlayPvs(comp.FailedSound, machineUid);
|
||||
}
|
||||
|
||||
comp.User = null;
|
||||
}
|
||||
|
||||
private void DetermineCursedResult(EntityUid machineUid, SlotMachineComponent comp, CursedSlotMachineComponent cursed)
|
||||
{
|
||||
var user = comp.User;
|
||||
if (user == null)
|
||||
return;
|
||||
|
||||
var rand = _random.NextFloat();
|
||||
|
||||
if (rand < CursedWinChance)
|
||||
{
|
||||
GenerateCursedWinSlots(comp);
|
||||
AwardCursedJackpot(machineUid, user.Value, cursed);
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateCursedLoseSlots(comp);
|
||||
AwardCursedLoss(machineUid, comp, user.Value, cursed);
|
||||
}
|
||||
|
||||
comp.User = null;
|
||||
}
|
||||
|
||||
#region Slots Vis Generation
|
||||
|
||||
private void GenerateJackpotSlots(SlotMachineComponent comp)
|
||||
{
|
||||
comp.Slots = new[] { "★", "★", "★" };
|
||||
}
|
||||
|
||||
private void GenerateBigWinSlots(SlotMachineComponent comp)
|
||||
{
|
||||
var symbol = _random.Pick(AllSymbols.Where(s => s != "★").ToArray());
|
||||
comp.Slots = new[] { symbol, symbol, symbol };
|
||||
}
|
||||
|
||||
private void GenerateMediumWinSlots(SlotMachineComponent comp)
|
||||
{
|
||||
var symbols = new[] { "♥", "♦", "♡" };
|
||||
var symbol = _random.Pick(symbols);
|
||||
comp.Slots = new[] { symbol, symbol, symbol };
|
||||
}
|
||||
|
||||
private void GenerateSmallWinSlots(SlotMachineComponent comp)
|
||||
{
|
||||
var symbol = _random.Pick(AllSymbols);
|
||||
var otherSymbols = AllSymbols.Where(s => s != symbol).ToArray();
|
||||
|
||||
var pattern = _random.Next(3);
|
||||
switch (pattern)
|
||||
{
|
||||
case 0:
|
||||
comp.Slots = new[] { symbol, symbol, _random.Pick(otherSymbols) };
|
||||
break;
|
||||
case 1:
|
||||
comp.Slots = new[] { _random.Pick(otherSymbols), symbol, symbol };
|
||||
break;
|
||||
default:
|
||||
comp.Slots = new[] { symbol, _random.Pick(otherSymbols), symbol };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateTinyWinSlots(SlotMachineComponent comp)
|
||||
{
|
||||
var symbols = new[] { "♠", "♣" };
|
||||
var symbol = _random.Pick(symbols);
|
||||
var otherSymbols = AllSymbols.Where(s => s != symbol).ToArray();
|
||||
|
||||
var pattern = _random.Next(3);
|
||||
switch (pattern)
|
||||
{
|
||||
case 0:
|
||||
comp.Slots = new[] { symbol, symbol, _random.Pick(otherSymbols) };
|
||||
break;
|
||||
case 1:
|
||||
comp.Slots = new[] { _random.Pick(otherSymbols), symbol, symbol };
|
||||
break;
|
||||
default:
|
||||
comp.Slots = new[] { symbol, _random.Pick(otherSymbols), symbol };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateLoseSlots(SlotMachineComponent comp)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
comp.Slots = new[]
|
||||
{
|
||||
_random.Pick(AllSymbols),
|
||||
_random.Pick(AllSymbols),
|
||||
_random.Pick(AllSymbols)
|
||||
};
|
||||
|
||||
if (IsLosingCombination(comp.Slots))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateCursedWinSlots(SlotMachineComponent comp)
|
||||
{
|
||||
var symbol = _random.Pick(CursedWinSymbols);
|
||||
comp.Slots = new[] { symbol, symbol, symbol };
|
||||
}
|
||||
|
||||
private void GenerateCursedLoseSlots(SlotMachineComponent comp)
|
||||
{
|
||||
comp.Slots = new[]
|
||||
{
|
||||
_random.Pick(CursedSymbols),
|
||||
_random.Pick(CursedSymbols),
|
||||
_random.Pick(CursedSymbols)
|
||||
};
|
||||
}
|
||||
|
||||
private bool IsLosingCombination(string[] slots)
|
||||
{
|
||||
if (slots[0] == slots[1] && slots[1] == slots[2])
|
||||
return false;
|
||||
|
||||
if (slots[0] == slots[1] || slots[1] == slots[2] || slots[0] == slots[2])
|
||||
return false;
|
||||
|
||||
var luckySymbols = new[] { "♥", "♦", "♡" };
|
||||
if (luckySymbols.Contains(slots[0]) && luckySymbols.Contains(slots[1]) && luckySymbols.Contains(slots[2]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Awards
|
||||
|
||||
private void AwardJackpot(EntityUid machineUid, SlotMachineComponent comp, EntityUid user)
|
||||
{
|
||||
SpawnAward(machineUid, user, comp.JackpotPrize);
|
||||
_audio.PlayPvs(comp.JackpotSound, machineUid);
|
||||
_popup.PopupEntity(Loc.GetString("slot-machine-jackpot", ("prize", comp.JackpotPrize)), user, user);
|
||||
|
||||
var name = Identity.Name(user, EntityManager);
|
||||
_chat.DispatchGlobalAnnouncement(Loc.GetString("auto-announcements-jackpot", ("winner", name)),
|
||||
Loc.GetString("auto-announcements-title"), true, colorOverride: Color.Turquoise);
|
||||
}
|
||||
|
||||
private void AwardBigWin(EntityUid machineUid, SlotMachineComponent comp, EntityUid user)
|
||||
{
|
||||
SpawnAward(machineUid, user, comp.BigWinPrize);
|
||||
_popup.PopupEntity(Loc.GetString("slot-machine-bigwin", ("prize", comp.BigWinPrize)), user, user);
|
||||
}
|
||||
|
||||
private void AwardMediumWin(EntityUid machineUid, SlotMachineComponent comp, EntityUid user)
|
||||
{
|
||||
SpawnAward(machineUid, user, comp.MediumWinPrize);
|
||||
_popup.PopupEntity(Loc.GetString("slot-medium-win", ("prize", comp.MediumWinPrize)), user, user);
|
||||
}
|
||||
|
||||
private void AwardSmallWin(EntityUid machineUid, SlotMachineComponent comp, EntityUid user)
|
||||
{
|
||||
SpawnAward(machineUid, user, comp.SmallWinPrize);
|
||||
_popup.PopupEntity(Loc.GetString("slot-small-win", ("prize", comp.SmallWinPrize)), user, user);
|
||||
}
|
||||
|
||||
private void AwardTinyWin(EntityUid machineUid, SlotMachineComponent comp, EntityUid user)
|
||||
{
|
||||
SpawnAward(machineUid, user, comp.TinyWinPrize);
|
||||
_popup.PopupEntity(Loc.GetString("slot-tiny-win", ("prize", comp.TinyWinPrize)), user, user);
|
||||
}
|
||||
|
||||
private void AwardCursedJackpot(EntityUid machineUid, EntityUid user, CursedSlotMachineComponent cursedComp)
|
||||
{
|
||||
var die = Spawn(Reward, Transform(machineUid).Coordinates);
|
||||
_hands.TryPickupAnyHand(user, die);
|
||||
|
||||
_audio.PlayPvs(cursedComp.JackpotSound, machineUid);
|
||||
_popup.PopupEntity(Loc.GetString("cursed-slot-machine-jackpot", ("name", Name(user))), // He know who are you
|
||||
machineUid, PopupType.LargeCaution);
|
||||
|
||||
cursedComp.Uses = 5; // Win. Stop
|
||||
Timer.Spawn(TimeSpan.FromSeconds(5), () => { _destructible.DestroyEntity(machineUid); });
|
||||
}
|
||||
|
||||
private void AwardCursedLoss(EntityUid machineUid, SlotMachineComponent comp, EntityUid user, CursedSlotMachineComponent cursedComp)
|
||||
{
|
||||
cursedComp.Uses++;
|
||||
_damage.TryChangeDamage(user, cursedComp.Damage, true);
|
||||
|
||||
_audio.PlayPvs(comp.FailedSound, machineUid);
|
||||
_popup.PopupEntity(Loc.GetString("cursed-slot-machine-lose"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
|
||||
private void SpawnAward(EntityUid machineUid, EntityUid user, int award)
|
||||
{
|
||||
var cash = Spawn(SpaceCash, Transform(machineUid).Coordinates);
|
||||
_stack.SetCount((cash, null), award);
|
||||
|
||||
_hands.TryPickupAnyHand(user, cash);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void FreeSpeen(Entity<SlotMachineComponent?> entity, EntityUid user)
|
||||
{
|
||||
if (!Resolve(entity.Owner, ref entity.Comp))
|
||||
return;
|
||||
|
||||
StartSpin((entity.Owner, entity.Comp), user, HasComp<CursedSlotMachineComponent>(entity));
|
||||
}
|
||||
|
||||
private void UpdateAppearance(Entity<SlotMachineComponent?> entity)
|
||||
{
|
||||
if (!Resolve(entity.Owner, ref entity.Comp))
|
||||
return;
|
||||
|
||||
_appearance.SetData(entity, SlotMachineVisuals.Working, entity.Comp.Working);
|
||||
}
|
||||
}
|
||||
@@ -65,25 +65,32 @@ namespace Content.Shared.Chat
|
||||
/// </summary>
|
||||
Dead = 1 << 10,
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
/// <summary>
|
||||
/// Mind chat
|
||||
/// </summary>
|
||||
Mind = 1 << 11,
|
||||
// Corvax-Wega-MindChat-end
|
||||
|
||||
/// <summary>
|
||||
/// Misc admin messages
|
||||
/// </summary>
|
||||
Admin = 1 << 11,
|
||||
Admin = 1 << 12, // Corvax-Wega-Edit
|
||||
|
||||
/// <summary>
|
||||
/// Admin alerts, messages likely of elevated importance to admins
|
||||
/// </summary>
|
||||
AdminAlert = 1 << 12,
|
||||
AdminAlert = 1 << 13, // Corvax-Wega-Edit
|
||||
|
||||
/// <summary>
|
||||
/// Admin chat
|
||||
/// </summary>
|
||||
AdminChat = 1 << 13,
|
||||
AdminChat = 1 << 14, // Corvax-Wega-Edit
|
||||
|
||||
/// <summary>
|
||||
/// Unspecified.
|
||||
/// </summary>
|
||||
Unspecified = 1 << 14,
|
||||
Unspecified = 1 << 15, // Corvax-Wega-Edit
|
||||
|
||||
/// <summary>
|
||||
/// Channels considered to be IC.
|
||||
|
||||
@@ -11,6 +11,7 @@ public static class ChatChannelExtensions
|
||||
ChatChannel.LOOC => Color.MediumTurquoise,
|
||||
ChatChannel.OOC => Color.LightSkyBlue,
|
||||
ChatChannel.Dead => Color.MediumPurple,
|
||||
ChatChannel.Mind => Color.Peru, // Corvax-Wega-MindChat
|
||||
ChatChannel.Admin => Color.Red,
|
||||
ChatChannel.AdminAlert => Color.Red,
|
||||
ChatChannel.AdminChat => Color.HotPink,
|
||||
|
||||
@@ -46,6 +46,13 @@
|
||||
/// </summary>
|
||||
Dead = ChatChannel.Dead,
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
/// <summary>
|
||||
/// Mind chat
|
||||
/// </summary>
|
||||
Mind = ChatChannel.Mind,
|
||||
// Corvax-Wega-MindChat-end
|
||||
|
||||
/// <summary>
|
||||
/// Admin chat
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Frozen;
|
||||
using System.Text.RegularExpressions;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Mind; // Corvax-Wega-MindChat
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Speech;
|
||||
@@ -31,11 +32,13 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
public const char EmotesAltPrefix = '*';
|
||||
public const char AdminPrefix = ']';
|
||||
public const char WhisperPrefix = ',';
|
||||
public const char MindPrefix = '+'; // Corvax-Wega-MindChat
|
||||
public const char DefaultChannelKey = 'а'; // Corvax-Wega-Edit
|
||||
// Corvax-TTS-Start: Moved from Server to Shared
|
||||
public const int VoiceRange = 10; // how far voice goes in world units
|
||||
public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units
|
||||
public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units
|
||||
public const int MindChatRange = 1000; // Corvax-Wega-MindChat
|
||||
public static readonly SoundSpecifier DefaultAnnouncementSound
|
||||
= new SoundPathSpecifier("/Audio/Announcements/announce.ogg");
|
||||
|
||||
@@ -57,6 +60,8 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
/// </summary>
|
||||
private FrozenDictionary<char, RadioChannelPrototype> _keyCodes = default!;
|
||||
|
||||
private FrozenDictionary<char, MindChannelPrototype> _mindKeyCodes = default!; // Corvax-Wega-MindChat
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -66,6 +71,7 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReload);
|
||||
CacheRadios();
|
||||
CacheEmotes();
|
||||
CacheMindChannels(); // Corvax-Wega-MindChat
|
||||
}
|
||||
|
||||
protected virtual void OnPrototypeReload(PrototypesReloadedEventArgs obj)
|
||||
@@ -75,6 +81,11 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
|
||||
if (obj.WasModified<EmotePrototype>())
|
||||
CacheEmotes();
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
if (obj.WasModified<MindChannelPrototype>())
|
||||
CacheMindChannels();
|
||||
// Corvax-Wega-MindChat-end
|
||||
}
|
||||
|
||||
private void CacheRadios()
|
||||
@@ -83,6 +94,14 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
.ToFrozenDictionary(x => x.KeyCode);
|
||||
}
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
private void CacheMindChannels()
|
||||
{
|
||||
_mindKeyCodes = _prototypeManager.EnumeratePrototypes<MindChannelPrototype>()
|
||||
.ToFrozenDictionary(x => x.KeyCode);
|
||||
}
|
||||
// Corvax-Wega-MindChat-end
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to find an applicable <see cref="SpeechVerbPrototype"/> for a speaking entity's message.
|
||||
/// If one is not found, returns <see cref="DefaultSpeechVerb"/>.
|
||||
@@ -200,6 +219,42 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
return true;
|
||||
}
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
public bool TryProcessMindMessage(
|
||||
EntityUid source,
|
||||
string input,
|
||||
out string output,
|
||||
out MindChannelPrototype? channel,
|
||||
bool quiet = false)
|
||||
{
|
||||
output = input.Trim();
|
||||
channel = null;
|
||||
|
||||
if (input.Length == 0 || !input.StartsWith(MindPrefix))
|
||||
return false;
|
||||
|
||||
if (input.Length < 2 || char.IsWhiteSpace(input[1]))
|
||||
{
|
||||
output = SanitizeMessageCapital(input[1..].TrimStart());
|
||||
if (!quiet)
|
||||
_popup.PopupEntity(Loc.GetString("chat-manager-no-mind-key"), source, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
var channelKey = input[1];
|
||||
channelKey = char.ToLower(channelKey);
|
||||
output = SanitizeMessageCapital(input[2..].TrimStart());
|
||||
|
||||
if (!_mindKeyCodes.TryGetValue(channelKey, out channel) && !quiet)
|
||||
{
|
||||
var msg = Loc.GetString("chat-manager-no-such-mind-channel", ("key", channelKey));
|
||||
_popup.PopupEntity(msg, source, source);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// Corvax-Wega-MindChat-end
|
||||
|
||||
public string SanitizeMessageCapital(string message)
|
||||
{
|
||||
if (string.IsNullOrEmpty(message))
|
||||
@@ -450,6 +505,15 @@ public abstract partial class SharedChatSystem : EntitySystem
|
||||
SoundSpecifier? announcementSound = null,
|
||||
Color? colorOverride = null)
|
||||
{ }
|
||||
|
||||
// Corvax-Wega-MindChat-start
|
||||
public virtual void SendMindMessage(
|
||||
EntityUid source,
|
||||
string message,
|
||||
MindChannelPrototype channel,
|
||||
bool ignoreActionBlocker = false)
|
||||
{ }
|
||||
// Corvax-Wega-MindChat-end
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -130,6 +130,7 @@ public abstract class SharedEmpSystem : EntitySystem
|
||||
{
|
||||
if (exclusionsSet.Contains(uid))
|
||||
continue;
|
||||
|
||||
TryEmpEffects(uid, energyConsumption, TimeSpan.FromSeconds(duration));
|
||||
}
|
||||
Spawn(EmpPulseEffectPrototype, coordinates);
|
||||
|
||||
@@ -3,35 +3,27 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Blood.Cult.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodCultistComponent : Component
|
||||
{
|
||||
public bool BloodMagicActive = false;
|
||||
|
||||
public EntityUid? SelectedSpell { get; set; }
|
||||
[DataField] public EntityUid? SelectedSpell { get; set; }
|
||||
|
||||
public List<EntityUid?> SelectedEmpoweringSpells = new();
|
||||
[DataField] public List<EntityUid?> SelectedEmpoweringSpells = new();
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? RecallDaggerActionEntity;
|
||||
[DataField] public EntityUid? RecallDaggerActionEntity;
|
||||
|
||||
public EntityUid? RecallSpearAction { get; set; }
|
||||
[DataField] public EntityUid? RecallSpearAction { get; set; }
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? RecallSpearActionEntity;
|
||||
[DataField] public EntityUid? RecallSpearActionEntity;
|
||||
|
||||
[DataField]
|
||||
public int BloodCount = 5;
|
||||
|
||||
[DataField]
|
||||
public int Empowering = 0;
|
||||
|
||||
public static readonly EntProtoId CultObjective = "ActionBloodCultObjective";
|
||||
public static readonly EntProtoId CultCommunication = "ActionBloodCultComms";
|
||||
public static readonly EntProtoId BloodMagic = "ActionBloodMagic";
|
||||
public static readonly EntProtoId RecallBloodDagger = "ActionRecallBloodDagger";
|
||||
public static readonly EntProtoId RecallBloodSpear = "RecallBloodCultSpear";
|
||||
@@ -40,14 +32,17 @@ public sealed partial class BloodCultistComponent : Component
|
||||
public ProtoId<FactionIconPrototype> StatusIcon { get; set; } = "BloodCultistFaction";
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class AutoCultistComponent : Component;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ShowCultistIconsComponent : Component;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class AutoCultistComponent : Component;
|
||||
public sealed partial class BloodCultObjectComponent : Component;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodCultObjectComponent : Component;
|
||||
public sealed partial class BloodCultWeaponComponent : Component;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodDaggerComponent : Component
|
||||
@@ -59,15 +54,21 @@ public sealed partial class BloodDaggerComponent : Component
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodSpellComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<string> Prototype = new();
|
||||
[DataField(required: true)]
|
||||
public BloodCultSpell SpellType = default!;
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodRuneComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public BloodCultRune RuneType = default!;
|
||||
|
||||
[DataField]
|
||||
public string Prototype = default!;
|
||||
public string Desc { get; private set; } = string.Empty;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public string LocDesc => Loc.GetString(Desc);
|
||||
|
||||
public bool IsActive = true;
|
||||
|
||||
@@ -83,13 +84,18 @@ public sealed partial class BloodRitualDimensionalRendingComponent : Component
|
||||
public bool Activate = false;
|
||||
|
||||
public float NextTimeTick { get; set; }
|
||||
|
||||
[DataField("ritualMusic")]
|
||||
public SoundSpecifier RitualMusic = new SoundCollectionSpecifier("BloodCultMusic");
|
||||
|
||||
public bool SoundPlayed;
|
||||
}
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodStructureComponent : Component
|
||||
{
|
||||
[DataField("structureGear")]
|
||||
public List<string> StructureGear { get; private set; } = new();
|
||||
public List<EntProtoId> StructureGear { get; private set; } = new();
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField]
|
||||
public TimeSpan ActivateTime = TimeSpan.Zero;
|
||||
@@ -100,9 +106,6 @@ public sealed partial class BloodStructureComponent : Component
|
||||
[DataField]
|
||||
public SoundSpecifier? Sound { get; private set; }
|
||||
|
||||
[DataField]
|
||||
public bool CanInteract = true;
|
||||
|
||||
public bool IsActive = true;
|
||||
}
|
||||
|
||||
@@ -112,6 +115,12 @@ public sealed partial class BloodPylonComponent : Component
|
||||
public float NextTimeTick { get; set; }
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodShieldActivaebleComponent : Component
|
||||
{
|
||||
public string CurrentSlot = "outerClothing";
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodOrbComponent : Component
|
||||
{
|
||||
@@ -122,7 +131,7 @@ public sealed partial class BloodOrbComponent : Component
|
||||
public sealed partial class StoneSoulComponent : Component
|
||||
{
|
||||
[DataField("soulProto", required: true)]
|
||||
public string SoulProto { get; set; } = default!;
|
||||
public EntProtoId SoulProto { get; set; } = default!;
|
||||
|
||||
public EntityUid? SoulEntity;
|
||||
|
||||
@@ -138,6 +147,9 @@ public sealed partial class ConstructComponent : Component;
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodCultConstructComponent : Component;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodCultGhostComponent : Component;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodShuttleCurseComponent : Component;
|
||||
|
||||
@@ -155,26 +167,7 @@ public sealed partial class BloodSharpenerComponent : Component;
|
||||
/// Заглушка для логики
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CultistEyesComponent : Component;
|
||||
public sealed partial class BloodCultistEyesComponent : Component;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class PentagramDisplayComponent : Component;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum RuneColorVisuals
|
||||
{
|
||||
Color
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum StoneSoulVisualLayers : byte
|
||||
{
|
||||
Base,
|
||||
Soul
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum StoneSoulVisuals : byte
|
||||
{
|
||||
HasSoul
|
||||
}
|
||||
public sealed partial class BloodPentagramDisplayComponent : Component;
|
||||
|
||||
113
Content.Shared/_Wega/BloodCult/BloodCultEnums.cs
Normal file
113
Content.Shared/_Wega/BloodCult/BloodCultEnums.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using Content.Shared.Eui;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Blood.Cult;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BloodCultGod : byte
|
||||
{
|
||||
NarSi,
|
||||
Reaper,
|
||||
Kharin
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BloodCultSpell : byte
|
||||
{
|
||||
Stun,
|
||||
Teleport,
|
||||
ShadowShackles,
|
||||
TwistedConstruction,
|
||||
SummonEquipment,
|
||||
BloodRites
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BloodCultRune : byte
|
||||
{
|
||||
Offering,
|
||||
Teleport,
|
||||
Empowering,
|
||||
Revive,
|
||||
Barrier,
|
||||
Summoning,
|
||||
Bloodboil,
|
||||
Spiritrealm,
|
||||
Ritual,
|
||||
Default
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum RuneColorVisuals : byte
|
||||
{
|
||||
Color
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum StoneSoulVisuals : byte
|
||||
{
|
||||
HasSoul
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum VeilShifterVisuals : byte
|
||||
{
|
||||
Charged
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodMagicState : EuiStateBase
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BloodRitesUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BloodConstructUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BloodStructureUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodStructureBoundUserInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
public readonly List<EntProtoId> Items;
|
||||
public BloodStructureBoundUserInterfaceState(List<EntProtoId> items)
|
||||
{
|
||||
Items = items;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum BloodRunesUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodRitualBoundUserInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum EmpoweringRuneUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum SummoningRuneUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Eui;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Blood.Cult;
|
||||
@@ -14,35 +16,83 @@ public sealed class RitualConductedEvent : EntityEventArgs
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodMagicPressedEvent : EntityEventArgs
|
||||
public sealed class BloodMagicSelectSpellMessage(EntProtoId spell) : EuiMessageBase
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public readonly EntProtoId Spell = spell;
|
||||
}
|
||||
|
||||
public BloodMagicPressedEvent(NetEntity uid)
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodRitesSelectRitesMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public EntProtoId Rites { get; }
|
||||
|
||||
public BloodRitesSelectRitesMessage(EntProtoId rites)
|
||||
{
|
||||
Uid = uid;
|
||||
Rites = rites;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodMagicMenuClosedEvent : EntityEventArgs
|
||||
public sealed class BloodConstructSelectMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public string SelectedSpell { get; }
|
||||
public EntProtoId Construct { get; }
|
||||
|
||||
public BloodMagicMenuClosedEvent(NetEntity uid, string selectedSpell)
|
||||
public BloodConstructSelectMessage(EntProtoId construct)
|
||||
{
|
||||
Uid = uid;
|
||||
SelectedSpell = selectedSpell;
|
||||
Construct = construct;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodStructureSelectMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public EntProtoId Item { get; }
|
||||
|
||||
public BloodStructureSelectMessage(EntProtoId item)
|
||||
{
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SelectBloodRuneMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public EntProtoId RuneProtoId { get; }
|
||||
|
||||
public SelectBloodRuneMessage(EntProtoId runeProtoId)
|
||||
{
|
||||
RuneProtoId = runeProtoId;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class EmpoweringRuneSelectSpellMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public EntProtoId Spell { get; }
|
||||
|
||||
public EmpoweringRuneSelectSpellMessage(EntProtoId spell)
|
||||
{
|
||||
Spell = spell;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SummoningRuneSelectCultistMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public NetEntity CultistUid { get; }
|
||||
|
||||
public SummoningRuneSelectCultistMessage(NetEntity cultistUid)
|
||||
{
|
||||
CultistUid = cultistUid;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class BloodMagicDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
public string SelectedSpell { get; }
|
||||
public EntProtoId SelectedSpell { get; }
|
||||
|
||||
public BloodMagicDoAfterEvent(string selectedSpell)
|
||||
public BloodMagicDoAfterEvent(EntProtoId selectedSpell)
|
||||
{
|
||||
SelectedSpell = selectedSpell;
|
||||
}
|
||||
@@ -53,89 +103,17 @@ public sealed partial class TeleportSpellDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class EmpoweringRuneMenuOpenedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
|
||||
public EmpoweringRuneMenuOpenedEvent(NetEntity uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class EmpoweringRuneMenuClosedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public string SelectedSpell { get; }
|
||||
|
||||
public EmpoweringRuneMenuClosedEvent(NetEntity uid, string selectedSpell)
|
||||
{
|
||||
Uid = uid;
|
||||
SelectedSpell = selectedSpell;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class EmpoweringDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
public string SelectedSpell { get; }
|
||||
public EntProtoId SelectedSpell { get; }
|
||||
|
||||
public EmpoweringDoAfterEvent(string selectedSpell)
|
||||
public EmpoweringDoAfterEvent(EntProtoId selectedSpell)
|
||||
{
|
||||
SelectedSpell = selectedSpell;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodRitesPressedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
|
||||
public BloodRitesPressedEvent(NetEntity uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodRitesMenuClosedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public string SelectedRites { get; }
|
||||
|
||||
public BloodRitesMenuClosedEvent(NetEntity uid, string selectedRites)
|
||||
{
|
||||
Uid = uid;
|
||||
SelectedRites = selectedRites;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RunesMenuOpenedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
|
||||
public RunesMenuOpenedEvent(NetEntity uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RuneSelectEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public string RuneProto { get; }
|
||||
|
||||
public RuneSelectEvent(NetEntity uid, string runeProto)
|
||||
{
|
||||
Uid = uid;
|
||||
RuneProto = runeProto;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class BloodRuneDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
@@ -154,99 +132,7 @@ public sealed partial class BloodRuneCleaningDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SummoningRuneMenuOpenedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
|
||||
public SummoningRuneMenuOpenedEvent(NetEntity uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SummoningSelectedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity User { get; }
|
||||
public NetEntity Target { get; }
|
||||
|
||||
public SummoningSelectedEvent(NetEntity user, NetEntity target)
|
||||
{
|
||||
User = user;
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class OpenConstructMenuEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public NetEntity ConstructUid { get; }
|
||||
public NetEntity Mind { get; }
|
||||
|
||||
public OpenConstructMenuEvent(NetEntity uid, NetEntity constructUid, NetEntity mind)
|
||||
{
|
||||
Uid = uid;
|
||||
ConstructUid = constructUid;
|
||||
Mind = mind;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodConstructMenuClosedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public NetEntity ConstructUid { get; }
|
||||
public NetEntity Mind { get; }
|
||||
public string ConstructProto { get; }
|
||||
|
||||
public BloodConstructMenuClosedEvent(NetEntity uid, NetEntity constructUid, NetEntity mind, string constructProto)
|
||||
{
|
||||
Uid = uid;
|
||||
ConstructUid = constructUid;
|
||||
Mind = mind;
|
||||
ConstructProto = constructProto;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class OpenStructureMenuEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public NetEntity Structure { get; }
|
||||
|
||||
public OpenStructureMenuEvent(NetEntity uid, NetEntity structure)
|
||||
{
|
||||
Uid = uid;
|
||||
Structure = structure;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodStructureMenuClosedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public string Item { get; }
|
||||
public NetEntity Structure { get; }
|
||||
|
||||
public BloodStructureMenuClosedEvent(NetEntity uid, string item, NetEntity structure)
|
||||
{
|
||||
Uid = uid;
|
||||
Item = item;
|
||||
Structure = structure;
|
||||
}
|
||||
}
|
||||
|
||||
// Abilities
|
||||
public sealed partial class BloodCultObjectiveActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultCommuneActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultBloodMagicActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
@@ -282,7 +168,6 @@ public sealed partial class RecallBloodDaggerEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public sealed partial class BloodCultHallucinationsActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,9 +28,7 @@ public abstract class SharedBloodCultSystem : EntitySystem
|
||||
continue;
|
||||
|
||||
var protoId = meta.EntityPrototype?.ID;
|
||||
if (protoId == BloodCultistComponent.CultObjective.Id
|
||||
|| protoId == BloodCultistComponent.CultCommunication.Id
|
||||
|| protoId == BloodCultistComponent.BloodMagic.Id
|
||||
if (protoId == BloodCultistComponent.BloodMagic.Id
|
||||
|| protoId == BloodCultistComponent.RecallBloodDagger.Id)
|
||||
{
|
||||
_action.RemoveAction(cultist, actionId);
|
||||
@@ -38,29 +36,18 @@ public abstract class SharedBloodCultSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
if (bloodCultist.RecallSpearActionEntity != null)
|
||||
_action.RemoveAction(cultist, bloodCultist.RecallSpearActionEntity);
|
||||
|
||||
if (bloodCultist.SelectedSpell != null)
|
||||
_action.RemoveAction(cultist, bloodCultist.SelectedSpell.Value);
|
||||
_action.RemoveAction(cultist, bloodCultist.RecallSpearActionEntity);
|
||||
_action.RemoveAction(cultist, bloodCultist.SelectedSpell);
|
||||
|
||||
foreach (var spell in bloodCultist.SelectedEmpoweringSpells)
|
||||
{
|
||||
if (spell != null)
|
||||
{
|
||||
_action.RemoveAction(cultist, spell.Value);
|
||||
}
|
||||
}
|
||||
_action.RemoveAction(cultist, spell);
|
||||
|
||||
var stunTime = TimeSpan.FromSeconds(4);
|
||||
var name = Identity.Entity(cultist, EntityManager);
|
||||
|
||||
_stun.TryKnockdown(cultist, stunTime, true);
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-break-control", ("name", name)), cultist);
|
||||
_stun.TryKnockdown(cultist, TimeSpan.FromSeconds(4), true);
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-break-control", ("name", Identity.Entity(cultist, EntityManager))), cultist);
|
||||
|
||||
RemComp<BloodCultistComponent>(cultist);
|
||||
if (HasComp<CultistEyesComponent>(cultist)) RemComp<CultistEyesComponent>(cultist);
|
||||
if (HasComp<PentagramDisplayComponent>(cultist)) RemComp<PentagramDisplayComponent>(cultist);
|
||||
RemComp<BloodCultistEyesComponent>(cultist);
|
||||
RemComp<BloodPentagramDisplayComponent>(cultist);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
16
Content.Shared/_Wega/CardTarot/CardTarotComponent.cs
Normal file
16
Content.Shared/_Wega/CardTarot/CardTarotComponent.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Card.Tarot.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class CardTarotComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public CardTarot Card = CardTarot.NotEnchanted;
|
||||
|
||||
[DataField]
|
||||
public CardTarotType CardType = CardTarotType.Normal;
|
||||
|
||||
public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg");
|
||||
}
|
||||
45
Content.Shared/_Wega/CardTarot/CardTarotEnums.cs
Normal file
45
Content.Shared/_Wega/CardTarot/CardTarotEnums.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Card.Tarot;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum CardTarotType : byte
|
||||
{
|
||||
Normal,
|
||||
Reversed
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum CardTarot : byte
|
||||
{
|
||||
NotEnchanted,
|
||||
Fool,
|
||||
Magician,
|
||||
HighPriestess,
|
||||
Empress,
|
||||
Emperor,
|
||||
Hierophant,
|
||||
Lovers,
|
||||
Chariot,
|
||||
Justice,
|
||||
Hermit,
|
||||
WheelOfFortune,
|
||||
Strength,
|
||||
HangedMan,
|
||||
Death,
|
||||
Temperance,
|
||||
Devil,
|
||||
Tower,
|
||||
Stars,
|
||||
Moon,
|
||||
Sun,
|
||||
Judgement,
|
||||
TheWorld // !!!!
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum CardTarotVisuals : byte
|
||||
{
|
||||
State,
|
||||
Reversed
|
||||
}
|
||||
11
Content.Shared/_Wega/EnergyShield/EnergyShieldComponent.cs
Normal file
11
Content.Shared/_Wega/EnergyShield/EnergyShieldComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Content.Shared.EnergyShield;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class EnergyShieldOwnerComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? ShieldEntity = null;
|
||||
|
||||
[DataField]
|
||||
public int SustainingCount = 3;
|
||||
}
|
||||
58
Content.Shared/_Wega/EnergyShield/EnergyShieldSystem.cs
Normal file
58
Content.Shared/_Wega/EnergyShield/EnergyShieldSystem.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Content.Shared.Projectiles;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
|
||||
namespace Content.Shared.EnergyShield;
|
||||
|
||||
public sealed partial class EnergyShieldSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedMeleeWeaponSystem _meleeWeapon = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<EnergyShieldOwnerComponent, AttackedEvent>(OnAttacked);
|
||||
SubscribeLocalEvent<EnergyShieldOwnerComponent, ProjectileReflectAttemptEvent>(OnProjectileAttemptE);
|
||||
}
|
||||
|
||||
private void OnAttacked(Entity<EnergyShieldOwnerComponent> ent, ref AttackedEvent args)
|
||||
{
|
||||
if (ent.Comp.ShieldEntity == null || ent.Comp.SustainingCount <= 0)
|
||||
{
|
||||
RemCompDeferred(ent.Owner, ent.Comp);
|
||||
QueueDel(ent.Comp.ShieldEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
ent.Comp.SustainingCount--;
|
||||
var damage = _meleeWeapon.GetDamage(args.Used, args.User);
|
||||
args.BonusDamage = -damage;
|
||||
|
||||
if (ent.Comp.SustainingCount <= 0)
|
||||
{
|
||||
QueueDel(ent.Comp.ShieldEntity);
|
||||
RemCompDeferred(ent.Owner, ent.Comp);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProjectileAttemptE(Entity<EnergyShieldOwnerComponent> ent, ref ProjectileReflectAttemptEvent args)
|
||||
{
|
||||
if (ent.Comp.ShieldEntity == null || ent.Comp.SustainingCount <= 0)
|
||||
{
|
||||
RemCompDeferred(ent.Owner, ent.Comp);
|
||||
QueueDel(ent.Comp.ShieldEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
ent.Comp.SustainingCount--;
|
||||
args.Cancelled = true;
|
||||
QueueDel(args.ProjUid);
|
||||
|
||||
if (ent.Comp.SustainingCount <= 0)
|
||||
{
|
||||
QueueDel(ent.Comp.ShieldEntity);
|
||||
RemCompDeferred(ent.Owner, ent.Comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Content.Shared/_Wega/Mind/MindChannelPrototype.cs
Normal file
28
Content.Shared/_Wega/Mind/MindChannelPrototype.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Mind;
|
||||
|
||||
[Prototype("mindChannel")]
|
||||
public sealed partial class MindChannelPrototype : IPrototype
|
||||
{
|
||||
/// <summary>
|
||||
/// Human-readable name for the channel.
|
||||
/// </summary>
|
||||
[DataField("name")]
|
||||
public LocId Name { get; private set; } = string.Empty;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public string LocalizedName => Loc.GetString(Name);
|
||||
|
||||
/// <summary>
|
||||
/// Single-character prefix to determine what channel a message should be sent to.
|
||||
/// </summary>
|
||||
[DataField("keycode")]
|
||||
public char KeyCode { get; private set; } = '\0';
|
||||
|
||||
[DataField("color")]
|
||||
public Color Color { get; private set; } = Color.Peru;
|
||||
|
||||
[IdDataField, ViewVariables]
|
||||
public string ID { get; private set; } = default!;
|
||||
}
|
||||
17
Content.Shared/_Wega/Mind/MindLinkComponents.cs
Normal file
17
Content.Shared/_Wega/Mind/MindLinkComponents.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Mind;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class MindLinkComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Available mind channels for this entity
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public HashSet<ProtoId<MindChannelPrototype>> Channels = new();
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class AdminMindLinkListenerComponent : Component;
|
||||
62
Content.Shared/_Wega/SlotMachine/SlotMachineComponents.cs
Normal file
62
Content.Shared/_Wega/SlotMachine/SlotMachineComponents.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Economy.SlotMachine;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class SlotMachineComponent : Component
|
||||
{
|
||||
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool Working = false;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||
public int Plays = 0;
|
||||
|
||||
[DataField]
|
||||
public string[] Slots = { "?", "?", "?" };
|
||||
|
||||
[DataField]
|
||||
public int SpinCost = 10;
|
||||
|
||||
[DataField]
|
||||
public EntityUid? User;
|
||||
|
||||
public TimeSpan? SpinFinishTime;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)] public int JackpotPrize = 50000;
|
||||
[ViewVariables(VVAccess.ReadOnly)] public int BigWinPrize = 2500;
|
||||
[ViewVariables(VVAccess.ReadOnly)] public int MediumWinPrize = 1250;
|
||||
[ViewVariables(VVAccess.ReadOnly)] public int SmallWinPrize = 50;
|
||||
[ViewVariables(VVAccess.ReadOnly)] public int TinyWinPrize = 10;
|
||||
|
||||
// Sounds
|
||||
public SoundSpecifier CoinSound = new SoundCollectionSpecifier("CoinDrop");
|
||||
public SoundSpecifier RollSound = new SoundPathSpecifier("/Audio/_Wega/Machines/Roulette/roulettewheel.ogg");
|
||||
public SoundSpecifier EndSound = new SoundPathSpecifier("/Audio/_Wega/Machines/Roulette/ding_short.ogg");
|
||||
public SoundSpecifier JackpotSound = new SoundPathSpecifier("/Audio/_Wega/Machines/Roulette/roulettejackpot.ogg");
|
||||
public SoundSpecifier FailedSound = new SoundPathSpecifier("/Audio/Effects/Cargo/buzz_sigh.ogg");
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CursedSlotMachineComponent : Component
|
||||
{
|
||||
[DataField] public int Uses = 0;
|
||||
[DataField] public int MaxUses = 5;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public DamageSpecifier Damage = new DamageSpecifier()
|
||||
{
|
||||
DamageDict = { ["Blunt"] = 10, ["Heat"] = 10 }
|
||||
};
|
||||
|
||||
// Sounds
|
||||
public SoundSpecifier RollSound = new SoundPathSpecifier("/Audio/_Wega/Machines/Roulette/cursed.ogg");
|
||||
public SoundSpecifier JackpotSound = new SoundPathSpecifier("/Audio/_Wega/Machines/Roulette/cursed_jackpot.ogg");
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum SlotMachineVisuals : byte
|
||||
{
|
||||
Working
|
||||
}
|
||||
BIN
Resources/Audio/_Wega/Effects/cult_spell.ogg
Normal file
BIN
Resources/Audio/_Wega/Effects/cult_spell.ogg
Normal file
Binary file not shown.
4
Resources/Audio/_Wega/Machines/Roulette/attributions.yml
Normal file
4
Resources/Audio/_Wega/Machines/Roulette/attributions.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- files: ["coindrop.ogg", "coindrop2.ogg", "cursed_jackpot.ogg", "cursed.ogg", "ding_short.ogg", "roulettejackpot.ogg", "roulettewheel.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken from TG Station"
|
||||
source: "https://github.com/tgstation/tgstation"
|
||||
BIN
Resources/Audio/_Wega/Machines/Roulette/coindrop.ogg
Normal file
BIN
Resources/Audio/_Wega/Machines/Roulette/coindrop.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Machines/Roulette/coindrop2.ogg
Normal file
BIN
Resources/Audio/_Wega/Machines/Roulette/coindrop2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Machines/Roulette/cursed.ogg
Normal file
BIN
Resources/Audio/_Wega/Machines/Roulette/cursed.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Machines/Roulette/cursed_jackpot.ogg
Normal file
BIN
Resources/Audio/_Wega/Machines/Roulette/cursed_jackpot.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Machines/Roulette/ding_short.ogg
Normal file
BIN
Resources/Audio/_Wega/Machines/Roulette/ding_short.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Machines/Roulette/roulettejackpot.ogg
Normal file
BIN
Resources/Audio/_Wega/Machines/Roulette/roulettejackpot.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Machines/Roulette/roulettewheel.ogg
Normal file
BIN
Resources/Audio/_Wega/Machines/Roulette/roulettewheel.ogg
Normal file
Binary file not shown.
4
Resources/Audio/_Wega/StationEvents/attributions.yml
Normal file
4
Resources/Audio/_Wega/StationEvents/attributions.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- files: ["tear_of_veil.ogg"]
|
||||
license: "CC-BY-3.0"
|
||||
copyright: "Created by Bolgarich"
|
||||
source: "https://www.youtube.com/watch?v=NqNHKfTAvcw"
|
||||
BIN
Resources/Audio/_Wega/StationEvents/tear_of_veil.ogg
Normal file
BIN
Resources/Audio/_Wega/StationEvents/tear_of_veil.ogg
Normal file
Binary file not shown.
@@ -20,3 +20,4 @@ auto-announcements-holiday-mode =
|
||||
Мы надеемся, что это добавит настроения и сделает ваше пребывание на станции еще более комфортным. Если у вас возникнут вопросы или предложения, пожалуйста, сообщите об этом через службу поддержки.
|
||||
С уважением,
|
||||
Автоматическая система "Текна"
|
||||
auto-announcements-jackpot = ПОЗДРАВЛЯЕМ! {$winner} выиграл ДЖЕКПОТ в игровом автомате!
|
||||
|
||||
@@ -20,26 +20,30 @@ select-blood-recharge = Кровавая Перезарядка
|
||||
select-blood-spear = Кровавое Копье
|
||||
select-blood-bolt-barrage = Кровавый Шквал Болтов
|
||||
|
||||
runes-ui-default-title = Руны
|
||||
offering-rune = Руна Предложения
|
||||
offering-rune-desc = Конвертирует нормального члена экипажа в культиста, исцеляя его от физических и ожоговых повреждений. Также создаёт ритуальный кинжал. Если цель мертва, непригодна для конвертации или имеет имплант "Защита разума", она гибнет, оставляя камень душ.
|
||||
teleport-rune = Руна Телепорта
|
||||
teleport-rune-desc = Телепортирует объекты и людей на другую случайную руну телепортации. Может быть использована для достаточно быстрой транспортировки.
|
||||
empowering-rune = Руна Усиления
|
||||
empowering-rune-desc = Позволяет дополнительно подготовить 4 доступных заклинания и снижает время их подготовки.
|
||||
revive-rune = Руна Возрождения
|
||||
revive-rune-desc = Позволяет воскрешать павших культистов, используя глобальные заряды, накопленные при жертвоприношениях на руне предложения. Также можно пробуждать кататоников(ССД) новой душой.
|
||||
barrier-rune = Руна Барьера
|
||||
barrier-rune-desc = Создаёт защитный барьер с 100 здоровья, который можно активировать или деактивировать, но каждое использование наносит урон заклинателю.
|
||||
summoning-rune = Руна Призыва
|
||||
summoning-rune-desc = Вызывает на руну живого культиста, после чего руна стирается. Работает только на станции.
|
||||
bloodboil-rune = Руна Вскипания Крови
|
||||
bloodboil-rune-desc = Высасывает здоровье у заклинателей и наносит мощный урон всем, кто видит руну. Не действует на существа без крови.
|
||||
spiritrealm-rune = Руна Царства Духов
|
||||
spiritrealm-rune-desc = Позволяет самому стать духом, чтобы координировать культ.
|
||||
ritual-dimensional-rending-rune = Ритуал Разрыва Измерений
|
||||
ritual-dimensional-rending-rune-desc = Вызывает Одно из божеств крови через пространственный разрыв.
|
||||
|
||||
# System
|
||||
blood-cultist-eyes-glow-examined = [color=red]Глаза {$name} созерцают неестественным цветом, это не к добру...[/color]
|
||||
blood-cult-first-warning = Ваши глаза начали полыхать заревом крови
|
||||
blood-cult-second-warning = Кровавая пентаграмма образуется над вами, это знак к действию
|
||||
blood-cult-targets-no-select = Цели ещё не определены...
|
||||
blood-cult-ritual-completed-next-objective = Ритуал завершён. Приступайте к следующей цели — призыв Нар-Си
|
||||
blood-cult-objective-complete = Цель выполнена! Слава Нар-Си!
|
||||
blood-cult-current-targets = Текущие жертвы: { $targets }. Принесите их в жертву, чтобы достичь своей цели.
|
||||
blood-cult-no-valid-targets = Нет доступных целей для выполнения задачи...
|
||||
blood-dagger-failed-interact = кинжал выскальзывает из вашей руки порезав ее
|
||||
blood-dagger-failed-interact = кинжал выскальзывает из вашей руки лезвием нанося увечья
|
||||
blood-sharpener-success = точило обратилось в прах
|
||||
blood-sharpener-failed = кинжал уже был заточен
|
||||
blood-cult-failed-attack = вы не можете навредить членам культа
|
||||
@@ -47,6 +51,7 @@ stone-soul-empty = камень души пустой
|
||||
stone-soul-already-summoned = душа уже была призвана
|
||||
stone-soul-summoned = душа призвана
|
||||
stone-soul-retracted = душа возвратилось в камень
|
||||
veil-shifter-examined = Осталось {$count} зарядов
|
||||
blood-curse-failed = кровавое проклятие не удалось
|
||||
blood-veil-shifter-failed = ничего не произошло
|
||||
blood-construct-no-mind = камень души пустой
|
||||
@@ -54,8 +59,6 @@ blood-construct-failed = конструкт пустой
|
||||
blood-construct-succses = конструкт призван
|
||||
blood-structure-failed = взаимодействие будет возможно через { $time } секунд
|
||||
|
||||
cult-commune-title = Общение
|
||||
cult-commune-massage = { $name }: { $massage }
|
||||
blood-cult-dagger-not-found = кинжала не существует
|
||||
blood-cult-dagger-recalled = кинжал образуется перед вами
|
||||
blood-cult-blood-dagger-exists = вы уже имеете кинжал
|
||||
@@ -65,6 +68,7 @@ blood-orb-invalid-input = Невозможное значение, укажит
|
||||
blood-orb-not-enough-blood = У вас не достаточно собранной крови
|
||||
blood-orb-success = Вы выделили { $amount } единиц крови
|
||||
blood-orb-absorbed = сфера растекается в лужу крови и поглащается
|
||||
blood-cult-recharge-failed = недостаточно крови для перезарядки...
|
||||
blood-cult-spear-failed = недостаточно крови для призыва копья
|
||||
cult-spear-not-found = кровавого копья не существует
|
||||
cult-spear-too-far = расстояние до копья слишком велико
|
||||
@@ -81,7 +85,7 @@ ritual-activate-too-soon = РИТУАЛ МОЖНО БУДЕТ НАЧАТЬ ПО
|
||||
ritual-activate-failed = НЕВОЗМОЖНО НАЧАТЬ РИТУАЛ
|
||||
rune-activate-failed = невозможно активировать руну
|
||||
blood-ritual-warning = Образы древнего богоподобного существа соединяюстя воедино { $location }. Прервите ритуал любой целой, пока станция не была уничтожена!
|
||||
blood-ritual-activate-warning = Был обнаружен сдвиг пространства { $location }. Прекратите распространение всеми доступными средствами. Ожидаемое расширение через 45 секунд.
|
||||
blood-ritual-activate-warning = Был обнаружен сдвиг пространства { $location }. Прекратите распространение всеми доступными средствами. Ожидаемое расширение через 90 секунд.
|
||||
ritual-failed = РИТУАЛ ПРОВАЛИ
|
||||
|
||||
blood-cultist-offering-message = Mah'weyh pleggh at e'ntrath!
|
||||
|
||||
29
Resources/Locale/ru-RU/_wega/cardtarot/cardtarot.ftl
Normal file
29
Resources/Locale/ru-RU/_wega/cardtarot/cardtarot.ftl
Normal file
@@ -0,0 +1,29 @@
|
||||
tarot-card-not-enchanted = Карта Таро не зачарована
|
||||
tarot-used = {$name} использует карту {$type}
|
||||
tarot-card-fool = Дурака
|
||||
tarot-card-magician = Мага
|
||||
tarot-card-highpriestess = Верховного жреца
|
||||
tarot-card-empress = Императрицы
|
||||
tarot-card-emperor = Императора
|
||||
tarot-card-hierophant = Иерофанта
|
||||
tarot-card-lovers = Любовников
|
||||
tarot-card-chariot = Колесницы
|
||||
tarot-card-justice = Правосудия
|
||||
tarot-card-hermit = Отшельника
|
||||
tarot-card-wheeloffortune = Колесо удачи
|
||||
tarot-card-strength = Силы
|
||||
tarot-card-hangedman = Повешенного
|
||||
tarot-card-death = Смерти
|
||||
tarot-card-temperance = Умеренности
|
||||
tarot-card-devil = Демона
|
||||
tarot-card-tower = Башни
|
||||
tarot-card-stars = Звезд
|
||||
tarot-card-moon = Луны
|
||||
tarot-card-sun = Солнца
|
||||
tarot-card-judgement = Суда
|
||||
tarot-card-theworld = ЗААААААА ВАРДООООООООО
|
||||
|
||||
tarot-devil-healed = Темная энергия исцеляет ваши раны...
|
||||
tarot-devil-damaged = Темная энергия высасывает вашу жизненную силу...
|
||||
tarot-moon-m-message = Я долбоеб
|
||||
tarot-moon-f-message = Я дура
|
||||
@@ -0,0 +1 @@
|
||||
chat-mind-message-wrap = [color={$color}]{$channel} [bold]{$name}[/bold] размышляет, "{$message}"[/color]
|
||||
2
Resources/Locale/ru-RU/_wega/chat/ui/chat-box.ftl
Normal file
2
Resources/Locale/ru-RU/_wega/chat/ui/chat-box.ftl
Normal file
@@ -0,0 +1,2 @@
|
||||
hud-chatbox-select-Mind = Разум
|
||||
hud-chatbox-select-channel-Mind = Разум
|
||||
@@ -0,0 +1,2 @@
|
||||
chat-manager-no-access-mind-channel = Вы не можете пользоваться данным каналом
|
||||
chat-manager-no-mind-channel = Канала не существует
|
||||
@@ -1,14 +1,16 @@
|
||||
blood-cult-title = Культ крови
|
||||
blood-cult-description = Верные последователи крови среди нас...
|
||||
|
||||
objective-issuer-blood-god = [color=red]Геометриви Крови[/color]
|
||||
|
||||
blood-cult-role-greeting-human =
|
||||
Вы — Культист Крови!
|
||||
Вы — часть тёмного культа, что служит Геометриви Крови, { $god }.
|
||||
Ваша цель — призвать аватар и привести культ к победе.
|
||||
Вы - Культист Крови!
|
||||
Вы часть тёмного культа, что служит Геометриви Крови, { $god }.
|
||||
Ваша цель - призвать аватар и привести культ к победе.
|
||||
В ваших руках ритуальный кинжал и руны для создания страшных структур. Жертвы должны быть принесены в дар высокопоставленные члены экипажа или охраны.
|
||||
Призовите божество в укромном месте с помощью 9 культистов и ритуала.
|
||||
Только так вы обеспечите победу!
|
||||
blood-cult-role-greeting-animal = Вы — Существо Крови! Вы — часть тени, служите Геометрии Крови, { $god }. Помогите своим братьям в призыве и принесении жертв.
|
||||
blood-cult-role-greeting-animal = Вы - Существо Крови! Вы - часть тени, служите Геометрии Крови, { $god }. Помогите своим братьям в призыве и принесении жертв.
|
||||
|
||||
current-god-narsie = Нар'Си
|
||||
current-god-reaper = Жнецу
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
metabolizer-type-vampire = Вампир
|
||||
metabolizer-type-cultist = Культист
|
||||
metabolizer-type-blood-cultist = Культист крови
|
||||
metabolizer-type-ariral = Арирал
|
||||
|
||||
1
Resources/Locale/ru-RU/_wega/mind/mindlink.ftl
Normal file
1
Resources/Locale/ru-RU/_wega/mind/mindlink.ftl
Normal file
@@ -0,0 +1 @@
|
||||
blood-cult-mind-channel = Культ крови
|
||||
@@ -0,0 +1 @@
|
||||
objective-condition-blood-ritual-person-title = Пренисите в жертву { $targetName } во славу Геометриви Крови.
|
||||
18
Resources/Locale/ru-RU/_wega/slotmachine/slotmachine.ftl
Normal file
18
Resources/Locale/ru-RU/_wega/slotmachine/slotmachine.ftl
Normal file
@@ -0,0 +1,18 @@
|
||||
slot-machine-examine = [color=green]{$slots}[/color] | Всего сыграно {$spins} раз
|
||||
slot-machine-busy = Автомат уже крутится!
|
||||
slot-machine-unpowered = Машина без питания
|
||||
slot-machine-no-money = Недостаточно денег для игры!
|
||||
slot-machine-spinning = Автомат начинает вращение...
|
||||
slot-machine-lose = Вы ничего не выиграли.
|
||||
|
||||
slot-machine-jackpot = ДЖЕКПОТ! Вы выиграли {$prize} кредитов!
|
||||
slot-machine-bigwin = Крупный выигрыш! Вы выиграли {$prize} кредитов!
|
||||
slot-medium-win = Выигрыш! Вы получили {$prize} кредитов.
|
||||
slot-small-win = Неплохо! Вы выиграли {$prize} кредитов.
|
||||
slot-tiny-win = Скромный приз, вы выиграли {$prize} кредитов!
|
||||
|
||||
cursed-slot-machine-uses = Использований [color=red]{$uses}/{$max}[/color]
|
||||
cursed-slot-machine-deny = Вы играли слишком много раз...
|
||||
cursed-slot-machine-lose = Вы чувствуете боль, когда энергия покидает ваше тело!
|
||||
cursed-slot-machine-jackpot = СМЕХ РАЗДАЕТСЯ ВОКРУГ! {$name} ВЫИГРАЛ ДЖЕКПОТ!
|
||||
cursed-slot-machine-spin = {$name} дергает рычаг с блеском в глазах!
|
||||
@@ -0,0 +1 @@
|
||||
cargo-gift-gambling = слот машины
|
||||
@@ -38,3 +38,5 @@ uplink-syndie-player-name = Плеер синдиката
|
||||
uplink-syndie-player-desc = Позволяет разбавить рутинную резню своей любимой музыкой.
|
||||
uplink-syndie-pouch-name = Усиленный карманный подсумок синдиката
|
||||
uplink-syndie-pouch-desc = Вместительный подсумок с усиленной защитой от взрывов. Всё, что нужно агенту, останется при нём.
|
||||
uplink-syndie-dice-of-fate-name = Кость судьбы
|
||||
uplink-syndie-dice-of-fate-desc = Неизвестной таинственности и силы артефакт, который способен кардинально изменить судьбу кинувшего его. Однако это невероятный риск!
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
ent-DiceOfFate = { ent-d20Dice }
|
||||
.desc = { ent-d20Dice.desc }
|
||||
.suffix = Кость судьбы, НЕ МАППИТЬ
|
||||
ent-CardTarotBoxEmpty = коробка с картами Таро
|
||||
.desc = Зачарованная колода карт Таро.
|
||||
.suffix = Пустая
|
||||
ent-CardTarotBoxFilled = { ent-CardTarotBoxEmpty }
|
||||
.desc = { ent-CardTarotBoxEmpty.desc }
|
||||
.suffix = Полная, НЕ МАППИТЬ
|
||||
|
||||
ent-BaseCardTarot = карта Таро
|
||||
.desc = Это одна из карт из колоды Таро.
|
||||
ent-CardTarotNotEnchanted = пустая карта Таро
|
||||
.desc = Это одна из карт в колоде Таро, но она, кажется, пустая.
|
||||
ent-CardTarotFool = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotMagician = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotHighPriestess = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotEmpress = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotEmperor = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotHierophant = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotLovers = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotChariot = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotJustice = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotHermit = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotWheelOfFortune = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotStrength = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotHangedMan = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotDeath = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotTemperance = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotDevil = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotTower = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotStars = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotMoon = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotSun = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotJudgement = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
ent-CardTarotTheWorld = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
|
||||
ent-CardTarotFoolReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotMagicianReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotHighPriestessReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotEmpressReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotEmperorReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotHierophantReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotLoversReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotChariotReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotJusticeReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotHermitReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotWheelOfFortuneReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotStrengthReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotHangedManReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotDeathReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotTemperanceReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotDevilReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotTowerReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotStarsReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotMoonReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotSunReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotJudgementReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
ent-CardTarotTheWorldReversed = { ent-BaseCardTarot }
|
||||
.desc = { ent-BaseCardTarot.desc }
|
||||
.suffix = Перевернутая
|
||||
@@ -0,0 +1,8 @@
|
||||
ent-SlotMachine = слот машина
|
||||
.desc = Азартные игры для необщительных людей. Внесите 10 кредитов и испытайте свою удачу.
|
||||
ent-BrokenSlotMachine = сломанная слот машина
|
||||
.desc = Видимо, кому-то очень не повезло и он был очень зол.
|
||||
.suffix = Сломанная
|
||||
ent-CursedSlotMachine = слот машина
|
||||
.desc = Высокие ставки, высокие награды. От этого автомата исходит жутковатая аура.
|
||||
.suffix = Проклятая, НЕ МАППИТЬ
|
||||
@@ -0,0 +1,3 @@
|
||||
ent-BloodCultTargetObjective = { ent-BaseObjective }
|
||||
ent-BloodCultRitualObjective = Проведите кровавый ритуал
|
||||
.desc = Геометриви Крови жаждет вернуться в этот мир, и вы должны совершить ритуал, чтобы вернуть ее обратно.
|
||||
@@ -359,6 +359,7 @@
|
||||
Piercing: 0.5
|
||||
Heat: 0.5
|
||||
- type: GroupExamine
|
||||
- type: BloodShieldActivaeble # Corvax-Wega-Blood-Cult
|
||||
|
||||
- type: entity
|
||||
parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing]
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 30
|
||||
# Corvax-End
|
||||
- type: AdminMindLinkListener # Corvax-Wega-MindChat
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
- id: d12Dice
|
||||
- id: d20Dice
|
||||
- id: PercentileDie
|
||||
# Corvax-Wega-DiceOfFate-start
|
||||
# For fun lol
|
||||
- id: DiceOfFate
|
||||
prob: 0.00001
|
||||
# Corvax-Wega-DiceOfFate-end
|
||||
- type: Sprite
|
||||
sprite: Objects/Fun/dice.rsi
|
||||
state: dicebag
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
belt: ClothingBeltWand
|
||||
pocket1: WizardTeleportScroll
|
||||
pocket2: WizardsGrimoire
|
||||
# Corvax-Wega-CardTarot-start
|
||||
storage:
|
||||
back:
|
||||
- CardTarotBoxFilled
|
||||
# Corvax-Wega-CardTarot-end
|
||||
|
||||
- type: startingGear
|
||||
id: WizardRedGear
|
||||
|
||||
@@ -1,31 +1,4 @@
|
||||
# Basic
|
||||
- type: entity
|
||||
id: ActionBloodCultObjective
|
||||
parent: BaseAction
|
||||
name: "[color=red]Objective[/color]"
|
||||
description: "Shows the current purpose of the cult."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "vote" }
|
||||
useDelay: 5
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultObjectiveActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultComms
|
||||
parent: BaseAction
|
||||
name: "[color=red]Communication[/color]"
|
||||
description: "Allows you to talk to your fellow humans."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "comms" }
|
||||
checkCanInteract: false
|
||||
useDelay: 5
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultCommuneActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodMagic
|
||||
parent: BaseAction
|
||||
|
||||
@@ -26,4 +26,14 @@
|
||||
product: SpaceVillainArcadeFilled
|
||||
cost: 1500
|
||||
category: cargoproduct-category-name-fun
|
||||
group: market
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: SlotMachine
|
||||
icon:
|
||||
sprite: _Wega/Structures/Machines/slot_machine.rsi
|
||||
state: base
|
||||
product: SlotMachine
|
||||
cost: 5000
|
||||
category: cargoproduct-category-name-fun
|
||||
group: market
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user