forked from space-syndicate/space-station-14
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7400f60521 | ||
|
|
0ddec6dc27 | ||
|
|
fd54b9c6f7 | ||
|
|
cfc77ba495 | ||
|
|
bde8fca1ec | ||
|
|
8ef558bd68 | ||
|
|
682c9c4c95 | ||
|
|
f66b429a8e | ||
|
|
94cc054c80 | ||
| 3403d7d2b8 | |||
| 9770d5e2be | |||
| 6c2fb13345 | |||
| c8feff6896 | |||
| 7c1edb7780 | |||
| 8e3b5dffcd | |||
| 5723109220 | |||
| d815c29b91 | |||
| 9c89ddd7af | |||
| 2bb5583c8a | |||
| 8a4be23057 | |||
| d8542feb6b | |||
| 70c9fad45e | |||
| 529e1de68e | |||
| ed13d8f57e | |||
| 922fe8b5ea |
109
Content.Client/_Wega/BloodCult/BloodCultSystem.cs
Normal file
109
Content.Client/_Wega/BloodCult/BloodCultSystem.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
using System.Numerics;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
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
|
||||
{
|
||||
public sealed class BloodCultSystem : SharedBloodCultSystem
|
||||
{
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BloodRuneComponent, AppearanceChangeEvent>(OnRuneAppearanceChanged);
|
||||
SubscribeLocalEvent<BloodRitualDimensionalRendingComponent, AppearanceChangeEvent>(OnRuneAppearanceChanged);
|
||||
SubscribeLocalEvent<BloodCultistComponent, GetStatusIconsEvent>(GetCultistIcons);
|
||||
SubscribeLocalEvent<PentagramDisplayComponent, ComponentStartup>(GetHalo);
|
||||
SubscribeLocalEvent<PentagramDisplayComponent, ComponentShutdown>(RemoveHalo);
|
||||
SubscribeLocalEvent<StoneSoulComponent, AppearanceChangeEvent>(OnSoulStoneAppearanceChanged);
|
||||
}
|
||||
|
||||
private void OnRuneAppearanceChanged(Entity<BloodRuneComponent> entity, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (!_appearance.TryGetData(entity, RuneColorVisuals.Color, out Color color))
|
||||
return;
|
||||
|
||||
_sprite.SetColor(entity.Owner, color);
|
||||
}
|
||||
|
||||
private void OnRuneAppearanceChanged(Entity<BloodRitualDimensionalRendingComponent> entity, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (!_appearance.TryGetData(entity, RuneColorVisuals.Color, out Color color))
|
||||
return;
|
||||
|
||||
_sprite.SetColor(entity.Owner, color);
|
||||
}
|
||||
|
||||
private void GetCultistIcons(Entity<BloodCultistComponent> ent, ref GetStatusIconsEvent args)
|
||||
{
|
||||
var iconPrototype = _prototype.Index(ent.Comp.StatusIcon);
|
||||
args.StatusIcons.Add(iconPrototype);
|
||||
}
|
||||
|
||||
private void GetHalo(EntityUid uid, PentagramDisplayComponent component, ComponentStartup args)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
||||
return;
|
||||
|
||||
if (_sprite.LayerMapTryGet(uid, PentagramKey.Halo, out _, true))
|
||||
return;
|
||||
|
||||
var haloVariant = _random.Next(1, 6);
|
||||
var haloState = $"halo{haloVariant}";
|
||||
|
||||
var bounds = _sprite.GetLocalBounds((uid, sprite));
|
||||
var adj = bounds.Height / 2 + 1.0f / 32 * 6.0f;
|
||||
|
||||
var layerData = new PrototypeLayerData
|
||||
{
|
||||
Shader = "unshaded",
|
||||
RsiPath = "_Wega/Interface/Misc/bloodcult_halo.rsi",
|
||||
State = haloState,
|
||||
Offset = new Vector2(0.0f, adj)
|
||||
};
|
||||
|
||||
var layer = _sprite.AddLayer(uid, layerData, null);
|
||||
_sprite.LayerMapSet(uid, PentagramKey.Halo, layer);
|
||||
}
|
||||
|
||||
private void RemoveHalo(EntityUid uid, PentagramDisplayComponent 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
|
||||
{
|
||||
Halo
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Content.Client/_Wega/BloodCult/Ui/BloodConstructMenu.xaml
Normal file
34
Content.Client/_Wega/BloodCult/Ui/BloodConstructMenu.xaml
Normal file
@@ -0,0 +1,34 @@
|
||||
<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">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" 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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
</ui:RadialMenu>
|
||||
49
Content.Client/_Wega/BloodCult/Ui/BloodConstructMenu.xaml.cs
Normal file
49
Content.Client/_Wega/BloodCult/Ui/BloodConstructMenu.xaml.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
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;
|
||||
|
||||
[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");
|
||||
}
|
||||
|
||||
public void SetData(NetEntity constructUid, NetEntity mindUid)
|
||||
{
|
||||
_constructUid = constructUid;
|
||||
_mindUid = mindUid;
|
||||
}
|
||||
|
||||
private void HandleRitesSelection(string constructName)
|
||||
{
|
||||
OnSelectConstruct?.Invoke(constructName);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new BloodConstructMenuClosedEvent(netEntity, _constructUid, _mindUid, constructName));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Content.Client/_Wega/BloodCult/Ui/BloodMagicMenu.xaml
Normal file
64
Content.Client/_Wega/BloodCult/Ui/BloodMagicMenu.xaml
Normal file
@@ -0,0 +1,64 @@
|
||||
<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">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" 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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
</ui:RadialMenu>
|
||||
48
Content.Client/_Wega/BloodCult/Ui/BloodMagicMenu.xaml.cs
Normal file
48
Content.Client/_Wega/BloodCult/Ui/BloodMagicMenu.xaml.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
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.Blood.Magic.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 BloodMagicMenu()
|
||||
{
|
||||
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 BloodMagicMenuClosedEvent(netEntity, spellName));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
45
Content.Client/_Wega/BloodCult/Ui/BloodMagicUIController.cs
Normal file
45
Content.Client/_Wega/BloodCult/Ui/BloodMagicUIController.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Content.Client/_Wega/BloodCult/Ui/BloodRitesMenu.xaml
Normal file
34
Content.Client/_Wega/BloodCult/Ui/BloodRitesMenu.xaml
Normal file
@@ -0,0 +1,34 @@
|
||||
<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">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" 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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
</ui:RadialMenu>
|
||||
42
Content.Client/_Wega/BloodCult/Ui/BloodRitesMenu.xaml.cs
Normal file
42
Content.Client/_Wega/BloodCult/Ui/BloodRitesMenu.xaml.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
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.Blood.Rites.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 BloodRitesMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
private void InitializeButtons()
|
||||
{
|
||||
BloodOrbButton.OnButtonUp += _ => HandleRitesSelection("ActionBloodCultOrb");
|
||||
BloodRechargeButton.OnButtonUp += _ => HandleRitesSelection("ActionBloodCultRecharge");
|
||||
BloodSpearButton.OnButtonUp += _ => HandleRitesSelection("ActionBloodCultSpear");
|
||||
BloodBoltBarrageButton.OnButtonUp += _ => HandleRitesSelection("ActionBloodCultBoltBarrage");
|
||||
}
|
||||
|
||||
private void HandleRitesSelection(string ritesName)
|
||||
{
|
||||
OnSelectRites?.Invoke(ritesName);
|
||||
var netEntity = _entityManager.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
_entityNetworkManager.SendSystemNetworkMessage(new BloodRitesMenuClosedEvent(netEntity, ritesName));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
45
Content.Client/_Wega/BloodCult/Ui/BloodRitesUIController.cs
Normal file
45
Content.Client/_Wega/BloodCult/Ui/BloodRitesUIController.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Content.Client/_Wega/BloodCult/Ui/BloodStructureMenu.xaml
Normal file
14
Content.Client/_Wega/BloodCult/Ui/BloodStructureMenu.xaml
Normal file
@@ -0,0 +1,14 @@
|
||||
<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">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" ReserveSpaceForHiddenChildren="False">
|
||||
</ui:RadialContainer>
|
||||
|
||||
</ui:RadialMenu>
|
||||
82
Content.Client/_Wega/BloodCult/Ui/BloodStructureMenu.xaml.cs
Normal file
82
Content.Client/_Wega/BloodCult/Ui/BloodStructureMenu.xaml.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
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;
|
||||
|
||||
[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!;
|
||||
|
||||
public event Action<string>? OnSelectItem;
|
||||
private NetEntity _structure;
|
||||
|
||||
public BloodStructureMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
public void SetData(NetEntity structure)
|
||||
{
|
||||
_structure = structure;
|
||||
InitializeButtons();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex<EntityPrototype>(prototypeId, out var prototype))
|
||||
continue;
|
||||
|
||||
var button = new RadialMenuButton
|
||||
{
|
||||
ToolTip = prototype.Name,
|
||||
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 += _ =>
|
||||
{
|
||||
HandleItemSelection(prototype.ID);
|
||||
};
|
||||
|
||||
Main.AddChild(button);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Content.Client/_Wega/BloodCult/Ui/EmpoweringRuneMenu.xaml
Normal file
64
Content.Client/_Wega/BloodCult/Ui/EmpoweringRuneMenu.xaml
Normal file
@@ -0,0 +1,64 @@
|
||||
<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">
|
||||
|
||||
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" InitialRadius="64" 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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</ui:RadialMenuButton>
|
||||
|
||||
</ui:RadialContainer>
|
||||
|
||||
</ui:RadialMenu>
|
||||
22
Content.Client/_Wega/BloodCult/Ui/RunesMenu.xaml
Normal file
22
Content.Client/_Wega/BloodCult/Ui/RunesMenu.xaml
Normal file
@@ -0,0 +1,22 @@
|
||||
<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">
|
||||
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" Margin="4">
|
||||
<PanelContainer VerticalExpand="True">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#80808005" />
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<ScrollContainer Name="Scroll" HScrollEnabled="False" VerticalExpand="True">
|
||||
<BoxContainer Name="RunesContainer" Orientation="Vertical" VerticalExpand="True">
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
162
Content.Client/_Wega/BloodCult/Ui/RunesMenu.xaml.cs
Normal file
162
Content.Client/_Wega/BloodCult/Ui/RunesMenu.xaml.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
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;
|
||||
|
||||
namespace Content.Client.Runes.Panel.Ui;
|
||||
|
||||
public sealed partial class RunesPanelMenu : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntityNetworkManager _entityNetworkManager = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
|
||||
public event Action<string>? OnRuneSelected;
|
||||
public BoxContainer RunesContainer => this.FindControl<BoxContainer>("RunesContainer");
|
||||
|
||||
public RunesPanelMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.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");
|
||||
}
|
||||
|
||||
private void AddRuneButton(string runeName, string protoId)
|
||||
{
|
||||
var button = new Button
|
||||
{
|
||||
Text = runeName,
|
||||
MinSize = new Vector2(300, 32),
|
||||
MaxSize = new Vector2(300, 32),
|
||||
HorizontalAlignment = HAlignment.Center,
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
};
|
||||
|
||||
button.OnPressed += _ => HandleRuneSelection(protoId);
|
||||
|
||||
RunesContainer.AddChild(button);
|
||||
}
|
||||
|
||||
private void HandleRuneSelection(string 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();
|
||||
}
|
||||
}
|
||||
144
Content.Client/_Wega/BloodCult/Ui/RunesMenuUIController.cs
Normal file
144
Content.Client/_Wega/BloodCult/Ui/RunesMenuUIController.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Content.Client/_Wega/BloodCult/Ui/SummoningRuneMenu.xaml
Normal file
22
Content.Client/_Wega/BloodCult/Ui/SummoningRuneMenu.xaml
Normal file
@@ -0,0 +1,22 @@
|
||||
<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.SummoningRunePanelMenu"
|
||||
Title="{Loc 'runes-ui-default-title'}"
|
||||
MinSize="512 340"
|
||||
SetSize="512 340">
|
||||
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" Margin="4">
|
||||
<PanelContainer VerticalExpand="True">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#80808005" />
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<ScrollContainer Name="Scroll" HScrollEnabled="False" VerticalExpand="True">
|
||||
<BoxContainer Name="CultistsContainer" Orientation="Vertical" VerticalExpand="True">
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
71
Content.Client/_Wega/Dirt/DirtVisualsSystem.cs
Normal file
71
Content.Client/_Wega/Dirt/DirtVisualsSystem.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using Content.Client.Clothing;
|
||||
using Content.Shared.DirtVisuals;
|
||||
using Content.Shared.Foldable;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.DirtVisuals;
|
||||
|
||||
public sealed class DirtVisualsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
[Dependency] private readonly ClientClothingSystem _clothing = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<DirtableComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, DirtableComponent comp, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not DirtableComponentState state)
|
||||
return;
|
||||
|
||||
comp.CurrentDirtLevel = state.CurrentDirtLevel;
|
||||
comp.DirtColor = state.DirtColor;
|
||||
UpdateDirtVisuals(uid, comp);
|
||||
}
|
||||
|
||||
private void UpdateDirtVisuals(EntityUid uid, DirtableComponent comp)
|
||||
{
|
||||
if (!HasComp<SpriteComponent>(uid))
|
||||
return;
|
||||
|
||||
var isFolded = false;
|
||||
if (HasComp<AppearanceComponent>(uid) && _appearance.TryGetData<bool>(uid, FoldableSystem.FoldedVisuals.State, out var folded))
|
||||
isFolded = folded;
|
||||
|
||||
var layerKey = $"dirt_{uid}";
|
||||
var dirtState = isFolded && !string.IsNullOrEmpty(comp.FoldingDirtState)
|
||||
? comp.FoldingDirtState
|
||||
: comp.DirtState;
|
||||
|
||||
if (comp.IsDirty)
|
||||
{
|
||||
if (!_sprite.LayerMapTryGet(uid, layerKey, out var layerIndex, false))
|
||||
{
|
||||
layerIndex = _sprite.AddLayer(uid, new SpriteSpecifier.Rsi(
|
||||
new ResPath(comp.DirtSpritePath),
|
||||
dirtState
|
||||
));
|
||||
_sprite.LayerMapSet(uid, layerKey, layerIndex);
|
||||
}
|
||||
|
||||
_sprite.LayerSetVisible(uid, layerIndex, true);
|
||||
_sprite.LayerSetColor(uid, layerIndex, comp.DirtColor);
|
||||
|
||||
_sprite.LayerSetRsiState(uid, layerIndex, dirtState);
|
||||
}
|
||||
else if (_sprite.LayerMapTryGet(uid, layerKey, out var layerIndex, false))
|
||||
{
|
||||
_sprite.LayerSetVisible(uid, layerIndex, false);
|
||||
}
|
||||
|
||||
if (TryComp(Transform(uid).ParentUid, out InventoryComponent? inventory))
|
||||
_clothing.InitClothing(Transform(uid).ParentUid, inventory);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Content.Shared.Item.Selector.UI;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client._Wega.Item.Selector.UI;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class ItemSelectorBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
||||
|
||||
[ViewVariables]
|
||||
private ItemSelectorWindow? _window;
|
||||
|
||||
public ItemSelectorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = this.CreateWindow<ItemSelectorWindow>();
|
||||
|
||||
_window.OnItemSelected += (selectedId) =>
|
||||
{
|
||||
var netEntity = EntMan.GetNetEntity(_playerManager.LocalSession?.AttachedEntity ?? EntityUid.Invalid);
|
||||
SendMessage(new ItemSelectorSelectionMessage(netEntity, selectedId));
|
||||
_window.Close();
|
||||
};
|
||||
}
|
||||
|
||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||
{
|
||||
if (_window == null || message is not ItemSelectorUserMessage msg)
|
||||
return;
|
||||
|
||||
_window.Populate(msg);
|
||||
}
|
||||
}
|
||||
15
Content.Client/_Wega/ItemSelector/ItemSelectorWindow.xaml
Normal file
15
Content.Client/_Wega/ItemSelector/ItemSelectorWindow.xaml
Normal file
@@ -0,0 +1,15 @@
|
||||
<ui:RadialMenu xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Content.Client._Wega.Item.Selector.UI.ItemSelectorWindow"
|
||||
MinWidth="450"
|
||||
MinHeight="450">
|
||||
|
||||
<ui:RadialContainer Name="MainContainer"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
InitialRadius="64"
|
||||
ReserveSpaceForHiddenChildren="False">
|
||||
</ui:RadialContainer>
|
||||
|
||||
</ui:RadialMenu>
|
||||
59
Content.Client/_Wega/ItemSelector/ItemSelectorWindow.xaml.cs
Normal file
59
Content.Client/_Wega/ItemSelector/ItemSelectorWindow.xaml.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Item.Selector.UI;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._Wega.Item.Selector.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ItemSelectorWindow : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public event Action<EntProtoId>? OnItemSelected;
|
||||
|
||||
public ItemSelectorWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
public void Populate(ItemSelectorUserMessage message)
|
||||
{
|
||||
MainContainer.RemoveAllChildren();
|
||||
|
||||
foreach (var prototypeId in message.Items)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex<EntityPrototype>(prototypeId, out var prototype))
|
||||
continue;
|
||||
|
||||
var button = new RadialMenuContextualCentralTextureButton
|
||||
{
|
||||
ToolTip = prototype.Name,
|
||||
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 += _ =>
|
||||
{
|
||||
OnItemSelected?.Invoke(prototype.ID);
|
||||
};
|
||||
|
||||
MainContainer.AddChild(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,6 +220,11 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
|
||||
UpdateCryostorageUIState((cryostorageEnt.Value, cryostorageComponent));
|
||||
AdminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(ent):player} was entered into cryostorage inside of {ToPrettyString(cryostorageEnt.Value)}");
|
||||
|
||||
// Corvax-Wega-BloodCult-start
|
||||
var ev = new CryostorageEnterEvent(ent.Owner);
|
||||
RaiseLocalEvent(ent.Owner, ref ev);
|
||||
// Corvax-Wega-BloodCult-end
|
||||
|
||||
if (!TryComp<StationRecordsComponent>(station, out var stationRecords))
|
||||
return;
|
||||
|
||||
@@ -347,3 +352,12 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Corvax-Wega-BloodCult-start
|
||||
/// <summary>
|
||||
/// Raised when an entity enters cryostorage.
|
||||
/// Used by Blood Cult to reassign targets when sacrifice targets go into cryo.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct CryostorageEnterEvent(EntityUid Uid);
|
||||
// Corvax-Wega-BloodCult-end
|
||||
|
||||
918
Content.Server/_Wega/BloodCult/BloodCultSystem.Abilities.cs
Normal file
918
Content.Server/_Wega/BloodCult/BloodCultSystem.Abilities.cs
Normal file
@@ -0,0 +1,918 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Emp;
|
||||
using Content.Server.Flash;
|
||||
using Content.Server.Hallucinations;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.Cuffs;
|
||||
using Content.Shared.Cuffs.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Fluids.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.Speech.Muting;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Timing;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Shared.Flash.Components;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.NullRod.Components;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Damage.Systems;
|
||||
|
||||
namespace Content.Server.Blood.Cult;
|
||||
|
||||
public sealed partial class BloodCultSystem
|
||||
{
|
||||
[Dependency] private readonly BloodstreamSystem _blood = default!;
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly DamageableSystem _damage = default!;
|
||||
[Dependency] private readonly EmpSystem _emp = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
|
||||
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
||||
[Dependency] private readonly FlashSystem _flash = default!;
|
||||
[Dependency] private readonly HallucinationsSystem _hallucinations = default!;
|
||||
[Dependency] private readonly IAdminLogManager _admin = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly QuickDialogSystem _quickDialog = default!;
|
||||
[Dependency] private readonly SharedCuffableSystem _cuff = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedStackSystem _stack = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||
[Dependency] private readonly VisibilitySystem _visibility = default!;
|
||||
[Dependency] private readonly LoadoutSystem _loadout = default!;
|
||||
|
||||
private void InitializeBloodAbilities()
|
||||
{
|
||||
// Blood Magic
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultBloodMagicActionEvent>(OnBloodMagic);
|
||||
SubscribeNetworkEvent<BloodMagicMenuClosedEvent>(AfterSpellSelect);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodMagicDoAfterEvent>(DoAfterSpellSelect);
|
||||
|
||||
// Abilities
|
||||
SubscribeLocalEvent<BloodCultCommuneActionEvent>(OnCultCommune);
|
||||
SubscribeLocalEvent<BloodSpellComponent, AfterInteractEvent>(OnInteract);
|
||||
SubscribeLocalEvent<BloodCultistComponent, RecallBloodDaggerEvent>(OnRecallDagger);
|
||||
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultStunActionEvent>(OnStun);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultTeleportActionEvent>(OnTeleport);
|
||||
SubscribeLocalEvent<BloodCultistComponent, TeleportSpellDoAfterEvent>(OnTeleportDoAfter);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultElectromagneticPulseActionEvent>(OnElectromagneticPulse);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultShadowShacklesActionEvent>(OnShadowShackles);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultTwistedConstructionActionEvent>(OnTwistedConstruction);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultSummonEquipmentActionEvent>(OnSummonEquipment);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultSummonDaggerActionEvent>(OnSummonDagger);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultHallucinationsActionEvent>(OnHallucinations);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultConcealPresenceActionEvent>(OnConcealPresence);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultBloodRitesActionEvent>(OnBloodRites);
|
||||
|
||||
SubscribeLocalEvent<BloodSpellComponent, UseInHandEvent>(BloodRites);
|
||||
SubscribeNetworkEvent<BloodRitesMenuClosedEvent>(BloodRitesSelect);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultBloodOrbActionEvent>(OnBloodOrb);
|
||||
SubscribeLocalEvent<BloodOrbComponent, UseInHandEvent>(OnBloodOrbAbsorbed);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultBloodRechargeActionEvent>(OnBloodRecharge);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultBloodSpearActionEvent>(OnBloodSpear);
|
||||
SubscribeLocalEvent<BloodCultistComponent, RecallBloodSpearEvent>(OnRecallSpear);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultBloodBoltBarrageActionEvent>(OnBloodBoltBarrage);
|
||||
}
|
||||
|
||||
#region Blood Magic
|
||||
private void OnBloodMagic(EntityUid uid, BloodCultistComponent component, BloodCultBloodMagicActionEvent args)
|
||||
{
|
||||
var netEntity = _entityManager.GetNetEntity(uid);
|
||||
RaiseNetworkEvent(new BloodMagicPressedEvent(netEntity));
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void AfterSpellSelect(BloodMagicMenuClosedEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var uid = _entityManager.GetEntity(args.Uid);
|
||||
if (!TryComp<BloodCultistComponent>(uid, out var cult))
|
||||
return;
|
||||
|
||||
if (!cult.BloodMagicActive)
|
||||
{
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, TimeSpan.FromSeconds(10f), new BloodMagicDoAfterEvent(args.SelectedSpell), uid)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
NeedHand = true
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var remSpell = cult.SelectedSpell;
|
||||
if (remSpell != null)
|
||||
_action.RemoveAction(uid, remSpell);
|
||||
cult.SelectedSpell = null;
|
||||
cult.BloodMagicActive = false;
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, TimeSpan.FromSeconds(10f), new BloodMagicDoAfterEvent(args.SelectedSpell), uid)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
NeedHand = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void DoAfterSpellSelect(EntityUid cultist, BloodCultistComponent component, BloodMagicDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled) return;
|
||||
|
||||
var actionEntityUid = _action.AddAction(cultist, args.SelectedSpell);
|
||||
if (actionEntityUid.HasValue)
|
||||
component.SelectedSpell = actionEntityUid.Value;
|
||||
else
|
||||
component.SelectedSpell = null;
|
||||
|
||||
ExtractBlood(cultist, -20, 10);
|
||||
component.BloodMagicActive = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Abilities
|
||||
private void OnCultCommune(BloodCultCommuneActionEvent args)
|
||||
{
|
||||
var uid = args.Performer;
|
||||
if (!TryComp<ActorComponent>(uid, out var playerActor))
|
||||
return;
|
||||
|
||||
// Админ логика, зато как просто
|
||||
var playerSession = playerActor.PlayerSession;
|
||||
_quickDialog.OpenDialog(playerSession, Loc.GetString("cult-commune-title"), "",
|
||||
(string message) =>
|
||||
{
|
||||
var finalMessage = string.IsNullOrWhiteSpace(message)
|
||||
? ""
|
||||
: message;
|
||||
|
||||
var senderName = Name(uid) ?? "Unknown";
|
||||
var popupMessage = Loc.GetString("cult-commune-massage", ("name", senderName), ("massage", finalMessage));
|
||||
|
||||
var cultistQuery = EntityQueryEnumerator<ActorComponent, BloodCultistComponent>();
|
||||
while (cultistQuery.MoveNext(out var cultistUid, out var actorComp, out var cultistComp))
|
||||
{
|
||||
if (actorComp == playerActor) continue;
|
||||
|
||||
_prayerSystem.SendSubtleMessage(actorComp.PlayerSession, actorComp.PlayerSession, string.Empty, popupMessage);
|
||||
}
|
||||
|
||||
var constructQuery = EntityQueryEnumerator<ActorComponent, BloodCultConstructComponent>();
|
||||
while (constructQuery.MoveNext(out var constructUid, out var actorComp, out var constructComp))
|
||||
{
|
||||
if (actorComp == playerActor) continue;
|
||||
|
||||
_prayerSystem.SendSubtleMessage(actorComp.PlayerSession, actorComp.PlayerSession, string.Empty, popupMessage);
|
||||
}
|
||||
|
||||
_admin.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(uid):user} saying the: {finalMessage} in cult commune");
|
||||
_chat.TrySendInGameICMessage(uid, finalMessage, InGameICChatType.Whisper, ChatTransmitRange.Normal, checkRadioPrefix: false);
|
||||
});
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRecallDagger(EntityUid cultist, BloodCultistComponent component, RecallBloodDaggerEvent args)
|
||||
{
|
||||
if (component.RecallDaggerActionEntity is not { } dagger || !HasComp<BloodDaggerComponent>(dagger))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-dagger-not-found"), cultist, cultist, PopupType.SmallCaution);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var cultistPosition = _transform.GetWorldPosition(cultist);
|
||||
_transform.SetWorldPosition(dagger, cultistPosition);
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-dagger-recalled"), cultist, cultist);
|
||||
_hands.TryPickupAnyHand(cultist, dagger);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnStun(EntityUid cultist, BloodCultistComponent component, BloodCultStunActionEvent args)
|
||||
{
|
||||
var spellGear = new ProtoId<StartingGearPrototype>("BloodCultSpellStunGear");
|
||||
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(cultist, ref dropEvent);
|
||||
List<ProtoId<StartingGearPrototype>> gear = new() { spellGear };
|
||||
_loadout.Equip(cultist, gear, null);
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void OnTeleport(EntityUid cultist, BloodCultistComponent component, BloodCultTeleportActionEvent args)
|
||||
{
|
||||
var spellGear = new ProtoId<StartingGearPrototype>("BloodCultSpellTeleportGear");
|
||||
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(cultist, ref dropEvent);
|
||||
List<ProtoId<StartingGearPrototype>> gear = new() { spellGear };
|
||||
_loadout.Equip(cultist, gear, null);
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void OnElectromagneticPulse(EntityUid cultist, BloodCultistComponent component, BloodCultElectromagneticPulseActionEvent args)
|
||||
{
|
||||
var coords = _transform.GetMapCoordinates(cultist);
|
||||
var exclusions = new List<EntityUid>();
|
||||
var entitiesInRange = _entityLookup.GetEntitiesInRange(coords, 5f);
|
||||
foreach (var uid in entitiesInRange)
|
||||
{
|
||||
if (HasComp<BloodCultistComponent>(uid))
|
||||
exclusions.Add(uid);
|
||||
}
|
||||
_emp.EmpPulseExclusions(coords, 5f, 100000f, 60f, exclusions);
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void OnShadowShackles(EntityUid cultist, BloodCultistComponent component, BloodCultShadowShacklesActionEvent args)
|
||||
{
|
||||
var spellGear = new ProtoId<StartingGearPrototype>("BloodCultSpellShadowShacklesGear");
|
||||
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(cultist, ref dropEvent);
|
||||
List<ProtoId<StartingGearPrototype>> gear = new() { spellGear };
|
||||
_loadout.Equip(cultist, gear, null);
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void OnTwistedConstruction(EntityUid cultist, BloodCultistComponent component, BloodCultTwistedConstructionActionEvent args)
|
||||
{
|
||||
var spellGear = new ProtoId<StartingGearPrototype>("BloodCultSpellTwistedConstructionGear");
|
||||
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(cultist, ref dropEvent);
|
||||
List<ProtoId<StartingGearPrototype>> gear = new() { spellGear };
|
||||
_loadout.Equip(cultist, gear, null);
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void OnSummonEquipment(EntityUid cultist, BloodCultistComponent component, BloodCultSummonEquipmentActionEvent args)
|
||||
{
|
||||
var spellGear = new ProtoId<StartingGearPrototype>("BloodCultSpellSummonEquipmentGear");
|
||||
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(cultist, ref dropEvent);
|
||||
List<ProtoId<StartingGearPrototype>> gear = new() { spellGear };
|
||||
_loadout.Equip(cultist, gear, null);
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void OnSummonDagger(EntityUid cultist, BloodCultistComponent component, BloodCultSummonDaggerActionEvent args)
|
||||
{
|
||||
if (_entityManager.EntityExists(component.RecallDaggerActionEntity))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-blood-dagger-exists"), cultist, cultist, PopupType.SmallCaution);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var cultistCoords = Transform(cultist).Coordinates;
|
||||
string selectedDagger = GetCurrentGod() switch
|
||||
{
|
||||
"Narsie" => "WeaponBloodDagger",
|
||||
"Reaper" => "WeaponDeathDagger",
|
||||
"Kharin" => "WeaponHellDagger",
|
||||
_ => "WeaponBloodDagger"
|
||||
};
|
||||
|
||||
var dagger = _entityManager.SpawnEntity(selectedDagger, cultistCoords);
|
||||
component.RecallDaggerActionEntity = dagger;
|
||||
_hands.TryPickupAnyHand(cultist, dagger);
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void OnHallucinations(EntityUid cultist, BloodCultistComponent component, BloodCultHallucinationsActionEvent args)
|
||||
{
|
||||
if (!HasComp<BloodCultistComponent>(args.Target))
|
||||
_hallucinations.StartHallucinations(args.Target, "Hallucinations", TimeSpan.FromSeconds(30f), true, "MindBreaker");
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void OnConcealPresence(EntityUid cultist, BloodCultistComponent component, BloodCultConcealPresenceActionEvent args)
|
||||
{
|
||||
var transform = _entityManager.GetComponent<TransformComponent>(cultist);
|
||||
var runes = _entityLookup.GetEntitiesInRange<BloodRuneComponent>(transform.Coordinates, 4f);
|
||||
var structures = _entityLookup.GetEntitiesInRange<BloodStructureComponent>(transform.Coordinates, 4f);
|
||||
|
||||
if (runes.Count > 0)
|
||||
{
|
||||
foreach (var rune in runes)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(rune.Owner, out BloodRuneComponent? bloodRuneComp))
|
||||
{
|
||||
if (EntityManager.TryGetComponent(rune.Owner, out VisibilityComponent? visibilityComp))
|
||||
{
|
||||
var entity = new Entity<VisibilityComponent?>(rune.Owner, visibilityComp);
|
||||
if (bloodRuneComp.IsActive)
|
||||
_visibility.SetLayer(entity, 6);
|
||||
else
|
||||
_visibility.SetLayer(entity, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newVisibilityComp = EntityManager.AddComponent<VisibilityComponent>(rune.Owner);
|
||||
var entity = new Entity<VisibilityComponent?>(rune.Owner, newVisibilityComp);
|
||||
if (bloodRuneComp.IsActive)
|
||||
_visibility.SetLayer(entity, 6);
|
||||
else
|
||||
_visibility.SetLayer(entity, 1);
|
||||
}
|
||||
|
||||
bloodRuneComp.IsActive = !bloodRuneComp.IsActive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (structures.Count > 0)
|
||||
{
|
||||
foreach (var structure in structures)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(structure.Owner, out BloodStructureComponent? bloodStructureComp))
|
||||
{
|
||||
if (EntityManager.TryGetComponent(structure.Owner, out VisibilityComponent? visibilityComp))
|
||||
{
|
||||
var entity = new Entity<VisibilityComponent?>(structure.Owner, visibilityComp);
|
||||
if (bloodStructureComp.IsActive)
|
||||
_visibility.SetLayer(entity, 6);
|
||||
else
|
||||
_visibility.SetLayer(entity, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newVisibilityComp = EntityManager.AddComponent<VisibilityComponent>(structure.Owner);
|
||||
var entity = new Entity<VisibilityComponent?>(structure.Owner, newVisibilityComp);
|
||||
if (bloodStructureComp.IsActive)
|
||||
_visibility.SetLayer(entity, 6);
|
||||
else
|
||||
_visibility.SetLayer(entity, 1);
|
||||
}
|
||||
|
||||
if (EntityManager.TryGetComponent(structure.Owner, out PhysicsComponent? physicsComp))
|
||||
{
|
||||
var fixture = _fixtures.GetFixtureOrNull(structure.Owner, bloodStructureComp.FixtureId);
|
||||
if (fixture != null)
|
||||
{
|
||||
_physics.SetHard(structure.Owner, fixture, !bloodStructureComp.IsActive);
|
||||
}
|
||||
}
|
||||
|
||||
bloodStructureComp.IsActive = !bloodStructureComp.IsActive;
|
||||
}
|
||||
}
|
||||
}
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
#region Blood Rites
|
||||
private void OnBloodRites(EntityUid cultist, BloodCultistComponent component, BloodCultBloodRitesActionEvent args)
|
||||
{
|
||||
var spellGear = new ProtoId<StartingGearPrototype>("BloodCultSpellBloodRitesGear");
|
||||
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(cultist, ref dropEvent);
|
||||
List<ProtoId<StartingGearPrototype>> gear = new() { spellGear };
|
||||
_loadout.Equip(cultist, gear, null);
|
||||
|
||||
args.Handled = true;
|
||||
EmpoweringCheck(args.Action, component);
|
||||
}
|
||||
|
||||
private void BloodRites(Entity<BloodSpellComponent> ent, ref UseInHandEvent args)
|
||||
{
|
||||
if (!TryComp<BloodSpellComponent>(ent, out var comp) || comp.Prototype.FirstOrDefault() != "bloodrites")
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
_entityManager.DeleteEntity(ent);
|
||||
var netEntity = _entityManager.GetNetEntity(args.User);
|
||||
RaiseNetworkEvent(new BloodRitesPressedEvent(netEntity));
|
||||
}
|
||||
|
||||
private void BloodRitesSelect(BloodRitesMenuClosedEvent args, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
var uid = _entityManager.GetEntity(args.Uid);
|
||||
if (!HasComp<BloodCultistComponent>(uid))
|
||||
return;
|
||||
|
||||
_action.AddAction(uid, args.SelectedRites);
|
||||
}
|
||||
|
||||
private void OnBloodOrb(EntityUid cultist, BloodCultistComponent component, BloodCultBloodOrbActionEvent args)
|
||||
{
|
||||
if (!TryComp<ActorComponent>(cultist, out var playerActor))
|
||||
return;
|
||||
|
||||
var playerSession = playerActor.PlayerSession;
|
||||
_quickDialog.OpenDialog(playerSession, Loc.GetString("blood-orb-dialog-title"), Loc.GetString("blood-orb-dialog-prompt"),
|
||||
(string input) =>
|
||||
{
|
||||
if (!int.TryParse(input, out var inputValue) || inputValue <= 0)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-orb-invalid-input"), cultist, cultist, PopupType.Medium);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputValue > component.BloodCount)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-orb-not-enough-blood"), cultist, cultist, PopupType.Medium);
|
||||
}
|
||||
else
|
||||
{
|
||||
component.BloodCount -= inputValue;
|
||||
|
||||
var bloodOrb = _entityManager.SpawnEntity("BloodCultOrb", Transform(cultist).Coordinates);
|
||||
EnsureComp<BloodOrbComponent>(bloodOrb, out var orb);
|
||||
orb.Blood = inputValue;
|
||||
|
||||
_action.RemoveAction(cultist, args.Action!);
|
||||
_popup.PopupEntity(Loc.GetString("blood-orb-success", ("amount", inputValue)), cultist, cultist, PopupType.Medium);
|
||||
}
|
||||
});
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnBloodOrbAbsorbed(Entity<BloodOrbComponent> ent, ref UseInHandEvent args)
|
||||
{
|
||||
var cultist = args.User;
|
||||
if (!TryComp<BloodCultistComponent>(cultist, out var cultistcomp)
|
||||
|| !TryComp<BloodOrbComponent>(ent, out var component))
|
||||
return;
|
||||
|
||||
var addedBlood = component.Blood;
|
||||
cultistcomp.BloodCount += addedBlood;
|
||||
_popup.PopupEntity(Loc.GetString("blood-orb-absorbed"), cultist, cultist, PopupType.Small);
|
||||
_entityManager.DeleteEntity(ent);
|
||||
}
|
||||
|
||||
private void OnBloodRecharge(EntityUid cultist, BloodCultistComponent component, BloodCultBloodRechargeActionEvent args)
|
||||
{
|
||||
var target = args.Target;
|
||||
if (TryComp<VeilShifterComponent>(target, out var veilShifterComponent))
|
||||
{
|
||||
var totalActivations = veilShifterComponent.ActivationsCount;
|
||||
veilShifterComponent.ActivationsCount = Math.Min(totalActivations + 4, 4);
|
||||
}
|
||||
|
||||
_action.RemoveAction(cultist, args.Action!);
|
||||
}
|
||||
|
||||
private void OnBloodSpear(EntityUid cultist, BloodCultistComponent component, BloodCultBloodSpearActionEvent args)
|
||||
{
|
||||
var totalBlood = component.BloodCount;
|
||||
if (totalBlood < 150)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-spear-failed"), cultist, cultist, PopupType.SmallCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.RecallSpearActionEntity != null)
|
||||
{
|
||||
_entityManager.DeleteEntity(component.RecallSpearActionEntity);
|
||||
component.RecallSpearActionEntity = null;
|
||||
|
||||
_action.RemoveAction(cultist, component.RecallSpearAction);
|
||||
component.RecallSpearAction = null;
|
||||
}
|
||||
|
||||
var spear = _entityManager.SpawnEntity("BloodCultSpear", Transform(cultist).Coordinates);
|
||||
component.RecallSpearActionEntity = spear;
|
||||
_hands.TryPickupAnyHand(cultist, spear);
|
||||
|
||||
var action = _action.AddAction(cultist, BloodCultistComponent.RecallBloodSpear);
|
||||
component.RecallSpearAction = action;
|
||||
|
||||
totalBlood -= 150;
|
||||
component.BloodCount = totalBlood;
|
||||
_action.RemoveAction(cultist, args.Action!);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnRecallSpear(EntityUid cultist, BloodCultistComponent component, RecallBloodSpearEvent args)
|
||||
{
|
||||
if (component.RecallSpearActionEntity is not { } spear || !_entityManager.EntityExists(spear))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cult-spear-not-found"), cultist, cultist);
|
||||
component.RecallSpearActionEntity = null;
|
||||
_action.RemoveAction(cultist, component.RecallSpearAction);
|
||||
component.RecallSpearAction = null;
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var cultistPosition = _transform.GetWorldPosition(cultist);
|
||||
var spearPosition = _transform.GetWorldPosition(spear);
|
||||
var distance = (spearPosition - cultistPosition).Length();
|
||||
if (distance > 10f)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cult-spear-too-far"), cultist, cultist);
|
||||
return;
|
||||
}
|
||||
|
||||
_transform.SetWorldPosition(spear, cultistPosition);
|
||||
_hands.TryPickupAnyHand(cultist, spear);
|
||||
_popup.PopupEntity(Loc.GetString("cult-spear-recalled"), cultist, cultist);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnBloodBoltBarrage(EntityUid cultist, BloodCultistComponent component, BloodCultBloodBoltBarrageActionEvent args)
|
||||
{
|
||||
var totalBlood = component.BloodCount;
|
||||
if (totalBlood < 300)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-bolt-barrage-failed"), cultist, cultist, PopupType.SmallCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
var boltBarrageGear = new ProtoId<StartingGearPrototype>("BloodCultSpellBloodBarrageGear");
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(cultist, ref dropEvent);
|
||||
List<ProtoId<StartingGearPrototype>> gear = new() { boltBarrageGear };
|
||||
_loadout.Equip(cultist, gear, null);
|
||||
|
||||
totalBlood -= 300;
|
||||
component.BloodCount = totalBlood;
|
||||
_action.RemoveAction(cultist, args.Action!);
|
||||
args.Handled = true;
|
||||
}
|
||||
#endregion Blood Rites
|
||||
#endregion Abilities
|
||||
|
||||
#region Other
|
||||
private void OnInteract(Entity<BloodSpellComponent> entity, ref AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled || !args.CanReach || args.Target is not { Valid: true } target
|
||||
|| !TryComp<BloodSpellComponent>(entity, out var spellComp))
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
switch (spellComp.Prototype.FirstOrDefault())
|
||||
{
|
||||
case "stun":
|
||||
if (!HasComp<BloodCultistComponent>(target) && !HasComp<NullRodOwnerComponent>(target))
|
||||
{
|
||||
ExtractBlood(user, -10, 6);
|
||||
if (!HasComp<MutedComponent>(target))
|
||||
{
|
||||
EnsureComp<MutedComponent>(target);
|
||||
Timer.Spawn(10000, () => { RemComp<MutedComponent>(target); });
|
||||
}
|
||||
|
||||
_stun.TryUpdateParalyzeDuration(target, TimeSpan.FromSeconds(4f));
|
||||
if (!TryComp<FlashImmunityComponent>(target, out var flash))
|
||||
_flash.Flash(target, user, entity, TimeSpan.FromSeconds(2f), 1f);
|
||||
_entityManager.DeleteEntity(entity);
|
||||
}
|
||||
break;
|
||||
case "teleport":
|
||||
ExtractBlood(user, -7, 5);
|
||||
if (HasComp<NullRodOwnerComponent>(target))
|
||||
break;
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(3f), new TeleportSpellDoAfterEvent(), user, target, entity)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
NeedHand = true
|
||||
});
|
||||
break;
|
||||
case "shadowshackles":
|
||||
if (!HasComp<BloodCultistComponent>(target) && !HasComp<NullRodOwnerComponent>(target))
|
||||
{
|
||||
if (TryComp<MobStateComponent>(target, out var mobstate) && mobstate.CurrentState != MobState.Alive && mobstate.CurrentState != MobState.Invalid
|
||||
|| HasComp<SleepingComponent>(target) || TryComp<StaminaComponent>(target, out var stamina) && stamina.StaminaDamage >= stamina.CritThreshold * 0.9f)
|
||||
{
|
||||
if (TryComp<CuffableComponent>(target, out var cuffable) && cuffable.CanStillInteract)
|
||||
{
|
||||
var handcuffs = _entityManager.SpawnEntity("Handcuffs", Transform(target).Coordinates);
|
||||
if (TryComp<HandcuffComponent>(handcuffs, out var handcuffsComp))
|
||||
{
|
||||
if (_cuff.TryAddNewCuffs(target, user, handcuffs, cuffable, handcuffsComp))
|
||||
{
|
||||
_cuff.CuffUsed(handcuffsComp);
|
||||
EnsureComp<MutedComponent>(target);
|
||||
Timer.Spawn(12000, () => { RemComp<MutedComponent>(target); });
|
||||
_entityManager.DeleteEntity(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-shadow-shackles-failed"), user, user, PopupType.SmallCaution);
|
||||
_entityManager.DeleteEntity(handcuffs);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-shadow-shackles-failed"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "twistedconstruction":
|
||||
if (HasComp<AirlockComponent>(target))
|
||||
{
|
||||
ExtractBlood(user, -12, 8);
|
||||
_entityManager.DeleteEntity(entity);
|
||||
|
||||
var airlockTransform = Transform(target).Coordinates;
|
||||
_entityManager.DeleteEntity(target);
|
||||
_entityManager.SpawnEntity("AirlockBloodCult", airlockTransform);
|
||||
}
|
||||
else if (TryComp<StackComponent>(target, out var stack))
|
||||
{
|
||||
if (_prototypeManager.TryIndex<StackPrototype>(stack.StackTypeId, out var stackPrototype))
|
||||
{
|
||||
if (stackPrototype.ID is "Steel" || stackPrototype.ID is "Plasteel")
|
||||
{
|
||||
ExtractBlood(user, -12, 8);
|
||||
var coords = Transform(target).Coordinates;
|
||||
if (stackPrototype.ID is "Steel" && stack.Count >= 30)
|
||||
{
|
||||
_stack.ReduceCount(target, 30);
|
||||
if (stack.Count > 0)
|
||||
{
|
||||
_entityManager.SpawnEntity("BloodCultConstruct", coords);
|
||||
}
|
||||
else
|
||||
{
|
||||
_entityManager.DeleteEntity(target);
|
||||
_entityManager.SpawnEntity("BloodCultConstruct", coords);
|
||||
}
|
||||
}
|
||||
if (stackPrototype.ID is "Plasteel")
|
||||
{
|
||||
var count = stack.Count;
|
||||
var runeSteel = _entityManager.SpawnEntity("SheetRuneMetal1", coords);
|
||||
_entityManager.DeleteEntity(target);
|
||||
if (TryComp<StackComponent>(runeSteel, out var newStack))
|
||||
{
|
||||
_stack.SetCount((runeSteel, newStack), count);
|
||||
}
|
||||
}
|
||||
|
||||
_entityManager.DeleteEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-twisted-failed"), user, user, PopupType.SmallCaution);
|
||||
_entityManager.DeleteEntity(entity);
|
||||
}
|
||||
break;
|
||||
case "summonequipment":
|
||||
_entityManager.DeleteEntity(entity);
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(target, ref dropEvent);
|
||||
ProtoId<StartingGearPrototype> selectedGear = GetCurrentGod() switch
|
||||
{
|
||||
"Narsie" => new ProtoId<StartingGearPrototype>("BloodCultWeaponBloodGear"),
|
||||
"Reaper" => new ProtoId<StartingGearPrototype>("BloodCultWeaponDeathGear"),
|
||||
"Kharin" => new ProtoId<StartingGearPrototype>("BloodCultWeaponHellGear"),
|
||||
_ => new ProtoId<StartingGearPrototype>("BloodCultWeaponBloodGear")
|
||||
};
|
||||
|
||||
List<ProtoId<StartingGearPrototype>> gear = new() { selectedGear };
|
||||
_loadout.Equip(target, gear, null);
|
||||
if (TryComp<InventoryComponent>(target, out var targetInventory))
|
||||
{
|
||||
var specificSlots = new[] { "outerClothing", "jumpsuit", "back", "shoes" };
|
||||
foreach (var slot in specificSlots)
|
||||
{
|
||||
if (!_inventorySystem.TryGetSlotEntity(target, slot, out var slotEntity, targetInventory))
|
||||
{
|
||||
switch (slot)
|
||||
{
|
||||
case "outerClothing":
|
||||
var outerClothingGear = new ProtoId<StartingGearPrototype>("BloodCultOuterGear");
|
||||
List<ProtoId<StartingGearPrototype>> outerClothing = new() { outerClothingGear };
|
||||
_loadout.Equip(target, outerClothing, null);
|
||||
break;
|
||||
case "jumpsuit":
|
||||
var jumpsuitGear = new ProtoId<StartingGearPrototype>("BloodCultJumpsuitGear");
|
||||
List<ProtoId<StartingGearPrototype>> jumpsuit = new() { jumpsuitGear };
|
||||
_loadout.Equip(target, jumpsuit, null);
|
||||
break;
|
||||
case "back":
|
||||
var backGear = new ProtoId<StartingGearPrototype>("BloodCultBackpackGear");
|
||||
List<ProtoId<StartingGearPrototype>> back = new() { backGear };
|
||||
_loadout.Equip(target, back, null);
|
||||
break;
|
||||
case "shoes":
|
||||
var shoesGear = new ProtoId<StartingGearPrototype>("BloodCultShoesGear");
|
||||
List<ProtoId<StartingGearPrototype>> shoes = new() { shoesGear };
|
||||
_loadout.Equip(target, shoes, null);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_entityManager.DeleteEntity(entity);
|
||||
}
|
||||
break;
|
||||
case "bloodrites":
|
||||
if (!TryComp<BloodCultistComponent>(user, out var cultist))
|
||||
{
|
||||
_entityManager.DeleteEntity(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<UseDelayComponent>(entity, out var useDelay) || _useDelay.IsDelayed((entity, useDelay)))
|
||||
return;
|
||||
|
||||
if (HasComp<BloodCultistComponent>(target))
|
||||
{
|
||||
if (!TryComp<DamageableComponent>(target, out var damage))
|
||||
return;
|
||||
|
||||
var totalBlood = cultist.BloodCount;
|
||||
var prioritizedDamageTypes = new[] { "Blunt", "Piercing", "Heat", "Slash", "Caustic" };
|
||||
foreach (var damageType in prioritizedDamageTypes)
|
||||
{
|
||||
if (totalBlood <= 0)
|
||||
break;
|
||||
|
||||
if (damage.Damage.DamageDict.TryGetValue(damageType, out var currentDamage) && currentDamage > 0)
|
||||
{
|
||||
var healAmount = FixedPoint2.Min(currentDamage, totalBlood);
|
||||
var healSpecifier = new DamageSpecifier { DamageDict = { { damageType, -healAmount } } };
|
||||
_damage.TryChangeDamage(target, healSpecifier, true);
|
||||
totalBlood -= healAmount.Int();
|
||||
}
|
||||
}
|
||||
cultist.BloodCount = totalBlood;
|
||||
args.Handled = true;
|
||||
}
|
||||
else if (HasComp<HumanoidAppearanceComponent>(target) && !HasComp<NullRodOwnerComponent>(target))
|
||||
{
|
||||
if (!TryComp<BloodstreamComponent>(target, out var blood) || HasComp<BloodCultistComponent>(target))
|
||||
return;
|
||||
|
||||
if (_blood.GetBloodLevel(target) > 0.6)
|
||||
{
|
||||
_blood.TryModifyBloodLevel(target, -50);
|
||||
cultist.BloodCount += 50;
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-blood-rites-failed"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
args.Handled = true;
|
||||
}
|
||||
else if (TryComp<PuddleComponent>(target, out var puddle))
|
||||
{
|
||||
var puddlesInRange = _entityLookup
|
||||
.GetEntitiesInRange<PuddleComponent>(Transform(user).Coordinates, 4f)
|
||||
.Where(puddle => TryComp(puddle.Owner, out ContainerManagerComponent? containerManager) &&
|
||||
containerManager.Containers.TryGetValue("solution@puddle", out var container) &&
|
||||
container.ContainedEntities.Any(containedEntity =>
|
||||
TryComp(containedEntity, out SolutionComponent? solutionComponent) &&
|
||||
solutionComponent.Solution.Contents.Any(r =>
|
||||
r.Reagent.Prototype == "Blood" || r.Reagent.Prototype == "CopperBlood")))
|
||||
.ToList();
|
||||
|
||||
var absorbedBlood = 0;
|
||||
foreach (var bloodPuddle in puddlesInRange)
|
||||
{
|
||||
if (TryComp(bloodPuddle.Owner, out ContainerManagerComponent? containerManager) &&
|
||||
containerManager.Containers.TryGetValue("solution@puddle", out var container))
|
||||
{
|
||||
foreach (var containedEntity in container.ContainedEntities.ToList())
|
||||
{
|
||||
if (TryComp(containedEntity, out SolutionComponent? solutionComponent))
|
||||
{
|
||||
foreach (var reagent in solutionComponent.Solution.Contents.ToList())
|
||||
{
|
||||
if (reagent.Reagent.Prototype == "Blood" || reagent.Reagent.Prototype == "CopperBlood")
|
||||
{
|
||||
absorbedBlood += reagent.Quantity.Int();
|
||||
solutionComponent.Solution.RemoveReagent(reagent.Reagent, reagent.Quantity);
|
||||
}
|
||||
}
|
||||
|
||||
_entityManager.SpawnEntity("BloodCultFloorGlowEffect", Transform(bloodPuddle.Owner).Coordinates);
|
||||
if (solutionComponent.Solution.Contents.Count == 0)
|
||||
_entityManager.DeleteEntity(bloodPuddle.Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cultist.BloodCount += absorbedBlood;
|
||||
args.Handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-blood-rites-failed"), user, user, PopupType.SmallCaution);
|
||||
args.Handled = true;
|
||||
}
|
||||
_useDelay.TryResetDelay((entity, useDelay));
|
||||
break;
|
||||
default:
|
||||
_popup.PopupEntity(Loc.GetString("blood-cult-spell-failed"), user, user, PopupType.SmallCaution);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtractBlood(EntityUid cultist, int extractBlood, FixedPoint2 bloodDamage)
|
||||
{
|
||||
if (TryComp<BloodstreamComponent>(cultist, out var blood) && _blood.GetBloodLevel(cultist) > 0)
|
||||
_blood.TryModifyBloodLevel(cultist, extractBlood);
|
||||
else
|
||||
{
|
||||
var damage = new DamageSpecifier { DamageDict = { { "Slash", bloodDamage } } };
|
||||
_damage.TryChangeDamage(cultist, damage, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTeleportDoAfter(EntityUid cultist, BloodCultistComponent component, TeleportSpellDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Target == null || args.Used == null)
|
||||
return;
|
||||
|
||||
_entityManager.DeleteEntity(args.Used);
|
||||
|
||||
var runes = new List<EntityUid>();
|
||||
var runeQuery = EntityQueryEnumerator<BloodRuneComponent>();
|
||||
|
||||
while (runeQuery.MoveNext(out var runeUid, out var runeComp))
|
||||
{
|
||||
if (runeComp.Prototype == "teleport")
|
||||
runes.Add(runeUid);
|
||||
}
|
||||
|
||||
if (runes.Count > 0)
|
||||
{
|
||||
var randomRune = runes[_random.Next(runes.Count)];
|
||||
var runeTransform = _entityManager.GetComponent<TransformComponent>(randomRune);
|
||||
var targetCoords = Transform(args.Target.Value).Coordinates;
|
||||
_entityManager.SpawnEntity("BloodCultOutEffect", targetCoords);
|
||||
_transform.SetCoordinates(args.Target.Value, runeTransform.Coordinates);
|
||||
_entityManager.SpawnEntity("BloodCultInEffect", runeTransform.Coordinates);
|
||||
_entityManager.DeleteEntity(randomRune);
|
||||
}
|
||||
}
|
||||
|
||||
private void EmpoweringCheck(EntityUid spell, BloodCultistComponent component)
|
||||
{
|
||||
if (component.SelectedEmpoweringSpells.Contains(spell))
|
||||
{
|
||||
component.Empowering--;
|
||||
component.SelectedEmpoweringSpells.Remove(spell);
|
||||
|
||||
_action.RemoveAction(spell);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
868
Content.Server/_Wega/BloodCult/BloodCultSystem.cs
Normal file
868
Content.Server/_Wega/BloodCult/BloodCultSystem.cs
Normal file
@@ -0,0 +1,868 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Bed.Cryostorage;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Prayer;
|
||||
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.FixedPoint;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Components;
|
||||
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.Popups;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
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.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Blood.Cult;
|
||||
|
||||
public sealed partial class BloodCultSystem : SharedBloodCultSystem
|
||||
{
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly BodySystem _body = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = 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 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;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<BloodCultRuleComponent, ComponentShutdown>(OnRuleShutdown);
|
||||
SubscribeLocalEvent<BloodCultistComponent, BloodCultObjectiveActionEvent>(OnCheckObjective);
|
||||
SubscribeLocalEvent<BloodCultistComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<BloodCultistComponent, ShotAttemptedEvent>(OnShotAttempted); // Corvax-Wega-Testing
|
||||
SubscribeLocalEvent<BloodCultConstructComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<BloodCultObjectComponent, ComponentShutdown>(OnComponentShutdown);
|
||||
SubscribeLocalEvent<BloodCultObjectComponent, CryostorageEnterEvent>(OnCryostorageEnter);
|
||||
SubscribeLocalEvent<BloodDaggerComponent, AfterInteractEvent>(OnInteract);
|
||||
SubscribeLocalEvent<AttackAttemptEvent>(OnAttackAttempt);
|
||||
|
||||
SubscribeLocalEvent<StoneSoulComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<StoneSoulComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<StoneSoulComponent, UseInHandEvent>(OnUseInHand);
|
||||
SubscribeLocalEvent<StoneSoulComponent, MindAddedMessage>(OnSoulStoneMindAdded);
|
||||
SubscribeLocalEvent<StoneSoulComponent, MindRemovedMessage>(OnSoulStoneMindRemoved);
|
||||
|
||||
SubscribeLocalEvent<BloodShuttleCurseComponent, UseInHandEvent>(OnShuttleCurse);
|
||||
|
||||
SubscribeLocalEvent<VeilShifterComponent, UseInHandEvent>(OnVeilShifter);
|
||||
|
||||
SubscribeLocalEvent<ConstructComponent, InteractHandEvent>(OnConstructInteract);
|
||||
SubscribeNetworkEvent<BloodConstructMenuClosedEvent>(OnConstructSelect);
|
||||
|
||||
SubscribeLocalEvent<BloodStructureComponent, InteractHandEvent>(OnStructureInteract);
|
||||
SubscribeNetworkEvent<BloodStructureMenuClosedEvent>(OnStructureItemSelect);
|
||||
|
||||
InitializeRunes();
|
||||
InitializeBloodAbilities();
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var pylonQuery = EntityQueryEnumerator<BloodPylonComponent>();
|
||||
while (pylonQuery.MoveNext(out var pylon, out var pylonQueryComponent))
|
||||
{
|
||||
if (pylonQueryComponent.NextTimeTick <= 0)
|
||||
{
|
||||
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)
|
||||
.ToList();
|
||||
|
||||
foreach (var target in nearbyCultists)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
pylonQueryComponent.NextTimeTick -= frameTime;
|
||||
}
|
||||
|
||||
var ritualQuery = EntityQueryEnumerator<BloodRitualDimensionalRendingComponent>();
|
||||
while (ritualQuery.MoveNext(out var rune, out var ritualQueryComponent))
|
||||
{
|
||||
if (ritualQueryComponent.Activate)
|
||||
{
|
||||
if (!_ritualStage)
|
||||
{
|
||||
_ritualStage = true;
|
||||
CheckStage();
|
||||
}
|
||||
|
||||
if (ritualQueryComponent.NextTimeTick <= 0)
|
||||
{
|
||||
ritualQueryComponent.NextTimeTick = 1;
|
||||
if (!CheckRitual(_transform.GetMapCoordinates(rune), 9))
|
||||
ritualQueryComponent.Activate = false;
|
||||
}
|
||||
ritualQueryComponent.NextTimeTick -= frameTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Corvax-Wega-Testing-start
|
||||
// Да я пометил тегами чтобы банально не забыть про это и чо?
|
||||
private void OnShotAttempted(Entity<BloodCultistComponent> ent, ref ShotAttemptedEvent args)
|
||||
{
|
||||
if (HasComp<DeleteOnDropComponent>(args.Used))
|
||||
return;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("gun-disabled"), ent, ent);
|
||||
args.Cancel();
|
||||
}
|
||||
// Corvax-Wega-Testing-end
|
||||
|
||||
#region Stages Update
|
||||
private void OnRuleShutdown(EntityUid uid, BloodCultRuleComponent component, ComponentShutdown 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 _))
|
||||
{
|
||||
candidates.Add(uid);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (HasComp<BloodCultistComponent>(target))
|
||||
{
|
||||
HandleCultistInteraction(args);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasComp<BloodRuneComponent>(target))
|
||||
{
|
||||
HandleRuneInteraction(args);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasComp<BloodSharpenerComponent>(target))
|
||||
{
|
||||
HandleSharpenerInteraction(uid, component, args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCultistInteraction(AfterInteractEvent args)
|
||||
{
|
||||
if (!TryComp<BodyComponent>(args.Target, out var bodyComponent))
|
||||
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 holywaterReagentId = new ReagentId("Holywater", new List<ReagentData>());
|
||||
var holywater = solution.GetReagentQuantity(holywaterReagentId);
|
||||
|
||||
if (holywater <= 0)
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleRuneInteraction(AfterInteractEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(4f), new BloodRuneCleaningDoAfterEvent(), user, args.Target)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
NeedHand = false
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleSharpenerInteraction(EntityUid dagger, BloodDaggerComponent component, AfterInteractEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (!TryComp<MeleeWeaponComponent>(dagger, out var meleeWeaponComponent))
|
||||
return;
|
||||
|
||||
if (!component.IsSharpered)
|
||||
{
|
||||
if (meleeWeaponComponent.Damage.DamageDict.TryGetValue("Slash", out var currentSlashDamage))
|
||||
meleeWeaponComponent.Damage.DamageDict["Slash"] = currentSlashDamage + FixedPoint2.New(4);
|
||||
else
|
||||
meleeWeaponComponent.Damage.DamageDict["Slash"] = FixedPoint2.New(4);
|
||||
|
||||
component.IsSharpered = true;
|
||||
_entityManager.DeleteEntity(args.Target);
|
||||
_entityManager.SpawnEntity("Ash", Transform(user).Coordinates);
|
||||
_popup.PopupEntity(Loc.GetString("blood-sharpener-success"), user, user, PopupType.Small);
|
||||
}
|
||||
else
|
||||
{
|
||||
_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
|
||||
private void OnComponentInit(EntityUid uid, StoneSoulComponent component, ComponentInit args)
|
||||
{
|
||||
component.SoulContainer = _container.EnsureContainer<ContainerSlot>(uid, "SoulContainer");
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, StoneSoulComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (component.SoulEntity != null && _entityManager.EntityExists(component.SoulEntity.Value))
|
||||
{
|
||||
QueueDel(component.SoulEntity.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUseInHand(EntityUid uid, StoneSoulComponent component, UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
if (component.IsSoulSummoned)
|
||||
{
|
||||
RetractSoul(uid, component, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
SummonSoul(uid, component, user);
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void SummonSoul(EntityUid stone, StoneSoulComponent component, EntityUid user)
|
||||
{
|
||||
if (!TryComp<MindContainerComponent>(stone, out var mindContainer) || mindContainer.Mind == null)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("stone-soul-empty"), user, user);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mind.VisitingEntity != default)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("stone-soul-already-summoned"), user, user);
|
||||
return;
|
||||
}
|
||||
|
||||
var stoneTransform = Transform(stone).Coordinates;
|
||||
var soul = Spawn(component.SoulProto, stoneTransform);
|
||||
transformSystem.AttachToGridOrMap(soul, Transform(soul));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(mind.CharacterName))
|
||||
metaDataSystem.SetEntityName(soul, mind.CharacterName);
|
||||
|
||||
_mind.Visit(mindId, soul, mind);
|
||||
component.SoulEntity = soul;
|
||||
component.IsSoulSummoned = true;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("stone-soul-summoned"), user, user);
|
||||
}
|
||||
|
||||
private void RetractSoul(EntityUid stone, StoneSoulComponent component, EntityUid user)
|
||||
{
|
||||
if (component.SoulEntity == null || !_entityManager.EntityExists(component.SoulEntity.Value))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("stone-soul-empty"), user, user);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_mind.TryGetMind(component.SoulEntity.Value, out var mindId, out var mind))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("stone-soul-empty"), user, user);
|
||||
return;
|
||||
}
|
||||
|
||||
_mind.UnVisit(mindId, mind);
|
||||
QueueDel(component.SoulEntity.Value);
|
||||
component.SoulEntity = null;
|
||||
component.IsSoulSummoned = false;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("stone-soul-retracted"), user);
|
||||
}
|
||||
|
||||
private void OnSoulStoneMindAdded(Entity<StoneSoulComponent> entity, ref MindAddedMessage args)
|
||||
{
|
||||
_appearance.SetData(entity, StoneSoulVisuals.HasSoul, true);
|
||||
}
|
||||
|
||||
private void OnSoulStoneMindRemoved(Entity<StoneSoulComponent> entity, ref MindRemovedMessage args)
|
||||
{
|
||||
_appearance.SetData(entity, StoneSoulVisuals.HasSoul, false);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ShuttleCurse
|
||||
private void OnShuttleCurse(Entity<BloodShuttleCurseComponent> entity, ref UseInHandEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (args.Handled || !HasComp<BloodCultistComponent>(user))
|
||||
return;
|
||||
|
||||
if (_curses > 0)
|
||||
{
|
||||
_roundEndSystem.CancelRoundEndCountdown(user);
|
||||
_entityManager.DeleteEntity(entity);
|
||||
_curses--;
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-curse-failed"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
args.Handled = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Veil Shifter
|
||||
private void OnVeilShifter(EntityUid uid, VeilShifterComponent component, UseInHandEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (args.Handled || !HasComp<BloodCultistComponent>(user))
|
||||
{
|
||||
var dropEvent = new DropHandItemsEvent();
|
||||
RaiseLocalEvent(user, ref dropEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.ActivationsCount > 0)
|
||||
{
|
||||
component.ActivationsCount--;
|
||||
var alignedDirection = GetAlignedDirection(user);
|
||||
var randomDistance = _random.NextFloat(1f, 9f);
|
||||
|
||||
var transform = Transform(user);
|
||||
var targetPosition = transform.Coordinates.Offset(alignedDirection * randomDistance);
|
||||
_transform.SetCoordinates(user, targetPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-veil-shifter-failed"), user, user, PopupType.SmallCaution);
|
||||
}
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private Vector2 GetAlignedDirection(EntityUid uid)
|
||||
{
|
||||
var transform = Transform(uid);
|
||||
var direction = transform.LocalRotation.ToWorldVec().Normalized();
|
||||
if (Math.Abs(direction.X) > Math.Abs(direction.Y))
|
||||
{
|
||||
return direction.X > 0 ? Vector2.UnitX : -Vector2.UnitX;
|
||||
}
|
||||
else
|
||||
{
|
||||
return direction.Y > 0 ? Vector2.UnitY : -Vector2.UnitY;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Construct
|
||||
private void OnConstructInteract(Entity<ConstructComponent> cosntruct, ref InteractHandEvent args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (args.Handled || !HasComp<BloodCultistComponent>(user))
|
||||
return;
|
||||
|
||||
if (TryComp<ItemSlotsComponent>(cosntruct, out var itemSlotsComponent))
|
||||
{
|
||||
foreach (var slot in itemSlotsComponent.Slots.Values)
|
||||
{
|
||||
if (slot.HasItem)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
var user = _entityManager.GetEntity(args.Uid);
|
||||
var construct = _entityManager.GetEntity(args.ConstructUid);
|
||||
var mind = _entityManager.GetEntity(args.Mind);
|
||||
|
||||
if (mind == EntityUid.Invalid)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-no-mind"), user, user, PopupType.SmallCaution);
|
||||
return;
|
||||
}
|
||||
|
||||
var constructMobe = _entityManager.SpawnEntity(args.ConstructProto, Transform(construct).Coordinates);
|
||||
_mind.TransferTo(mind, constructMobe);
|
||||
_entityManager.DeleteEntity(construct);
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("blood-construct-succses"), user, user);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Structures
|
||||
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 remainingTime = (component.ActivateTime - 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));
|
||||
}
|
||||
|
||||
private void OnStructureItemSelect(BloodStructureMenuClosedEvent 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 remainingTime = (structureComp.ActivateTime - currentTime).TotalSeconds;
|
||||
_popup.PopupEntity(Loc.GetString("blood-structure-failed", ("time", Math.Ceiling(remainingTime))), user, user, PopupType.Small);
|
||||
return;
|
||||
}
|
||||
|
||||
structureComp.ActivateTime = currentTime + TimeSpan.FromMinutes(4);
|
||||
|
||||
var item = _entityManager.SpawnEntity(args.Item, Transform(structure).Coordinates);
|
||||
_audio.PlayPvs(structureComp.Sound, structure);
|
||||
|
||||
var cultistPosition = _transform.GetWorldPosition(user);
|
||||
var structurePosition = _transform.GetWorldPosition(structure);
|
||||
var distance = (structurePosition - cultistPosition).Length();
|
||||
if (distance < 3f)
|
||||
_hands.TryPickupAnyHand(user, item);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region God Check
|
||||
private string GetCurrentGod()
|
||||
{
|
||||
var query = EntityQueryEnumerator<BloodCultRuleComponent>();
|
||||
while (query.MoveNext(out var cult))
|
||||
{
|
||||
if (cult.SelectedGod == null)
|
||||
{
|
||||
return "Narsie";
|
||||
}
|
||||
return cult.SelectedGod;
|
||||
}
|
||||
return "Narsie";
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
884
Content.Server/_Wega/BloodCult/RuneSystem.cs
Normal file
884
Content.Server/_Wega/BloodCult/RuneSystem.cs
Normal file
@@ -0,0 +1,884 @@
|
||||
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);
|
||||
// Wylab: ToggleGhostBarActionEntity doesn't exist (Ghost Bar feature not ported)
|
||||
// _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)
|
||||
{
|
||||
Color bloodColor;
|
||||
if (TryComp<BloodstreamComponent>(cultist, out var bloodStreamComponent))
|
||||
{
|
||||
// Use BloodReferenceSolution (upstream renamed from BloodReagents)
|
||||
var firstReagent = bloodStreamComponent.BloodReferenceSolution.Contents.FirstOrDefault();
|
||||
if (firstReagent.Quantity > 0 &&
|
||||
_prototypeManager.TryIndex<ReagentPrototype>(firstReagent.Reagent.Prototype, out var reagentPrototype))
|
||||
{
|
||||
bloodColor = reagentPrototype.SubstanceColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
bloodColor = Color.White;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bloodColor = Color.White;
|
||||
}
|
||||
return bloodColor;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
282
Content.Server/_Wega/GameTicking/Rules/BloodCultRuleSystem.cs
Normal file
282
Content.Server/_Wega/GameTicking/Rules/BloodCultRuleSystem.cs
Normal file
@@ -0,0 +1,282 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Actions;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Antag;
|
||||
using Content.Server.Blood.Cult;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Shared.Blood.Cult;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Clumsy;
|
||||
using Content.Shared.CombatMode.Pacification;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.NPC.Prototypes;
|
||||
using Content.Shared.NPC.Systems;
|
||||
using Content.Shared.Zombies;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules
|
||||
{
|
||||
public sealed class BloodCultRuleSystem : GameRuleSystem<BloodCultRuleComponent>
|
||||
{
|
||||
[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!;
|
||||
[Dependency] private readonly MetabolizerSystem _metabolism = default!;
|
||||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
|
||||
[Dependency] private readonly RoleSystem _role = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
||||
|
||||
public readonly ProtoId<NpcFactionPrototype> BloodCultNpcFaction = "BloodCult";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BloodCultRuleComponent, ComponentStartup>(OnRuleStartup);
|
||||
SubscribeLocalEvent<BloodCultRuleComponent, AfterAntagEntitySelectedEvent>(OnCultistSelected);
|
||||
|
||||
SubscribeLocalEvent<GodCalledEvent>(OnGodCalled);
|
||||
SubscribeLocalEvent<RitualConductedEvent>(OnRitualConducted);
|
||||
|
||||
SubscribeLocalEvent<AutoCultistComponent, ComponentStartup>(OnAutoCultistAdded);
|
||||
SubscribeLocalEvent<BloodCultistComponent, ComponentRemove>(OnComponentRemove);
|
||||
SubscribeLocalEvent<BloodCultistComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
SubscribeLocalEvent<BloodCultistComponent, EntityZombifiedEvent>(OnOperativeZombified);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void OnCultistSelected(Entity<BloodCultRuleComponent> mindId, ref AfterAntagEntitySelectedEvent args)
|
||||
{
|
||||
var ent = args.EntityUid;
|
||||
|
||||
MakeCultist(ent);
|
||||
_antag.SendBriefing(ent, MakeBriefing(ent), Color.Red, null);
|
||||
}
|
||||
|
||||
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[]
|
||||
{
|
||||
typeof(PacifiedComponent),
|
||||
typeof(ClumsyComponent)
|
||||
};
|
||||
|
||||
foreach (var compType in componentsToRemove)
|
||||
{
|
||||
if (HasComp(ent, compType))
|
||||
RemComp(ent, compType);
|
||||
}
|
||||
|
||||
HandleMetabolism(ent);
|
||||
}
|
||||
|
||||
private string MakeBriefing(EntityUid ent)
|
||||
{
|
||||
string selectedGod = Loc.GetString("current-god-narsie");
|
||||
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"),
|
||||
_ => Loc.GetString("current-god-narsie")
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
var isHuman = HasComp<HumanoidAppearanceComponent>(ent);
|
||||
var briefing = isHuman
|
||||
? Loc.GetString("blood-cult-role-greeting-human", ("god", selectedGod))
|
||||
: Loc.GetString("blood-cult-role-greeting-animal", ("god", selectedGod));
|
||||
|
||||
return briefing;
|
||||
}
|
||||
|
||||
private void OnAutoCultistAdded(EntityUid uid, AutoCultistComponent comp, ComponentStartup args)
|
||||
{
|
||||
if (!_mind.TryGetMind(uid, out var mindId, out var mind) || HasComp<BloodCultistComponent>(uid))
|
||||
{
|
||||
RemComp<AutoCultistComponent>(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
_npcFaction.AddFaction(uid, BloodCultNpcFaction);
|
||||
var culsistComp = EnsureComp<BloodCultistComponent>(uid);
|
||||
_adminLogManager.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(uid)} converted into a Blood Cult");
|
||||
if (mindId == default || !_role.MindHasRole<BloodCultistComponent>(mindId))
|
||||
_role.MindAddRole(mindId, "MindRoleBloodCultist");
|
||||
if (mind is { UserId: not null } && _player.TryGetSessionById(mind.UserId, out var session))
|
||||
_antag.SendBriefing(session, MakeBriefing(uid), Color.Red, new SoundPathSpecifier("/Audio/_Wega/Ambience/Antag/bloodcult_start.ogg"));
|
||||
RemComp<AutoCultistComponent>(uid);
|
||||
|
||||
MakeCultist(uid);
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out _, out _, out var cult, out _))
|
||||
{
|
||||
string selectedDagger = cult.SelectedGod switch
|
||||
{
|
||||
"Narsie" => "WeaponBloodDagger",
|
||||
"Reaper" => "WeaponDeathDagger",
|
||||
"Kharin" => "WeaponHellDagger",
|
||||
_ => "WeaponBloodDagger"
|
||||
};
|
||||
|
||||
var dagger = _entityManager.SpawnEntity(selectedDagger, Transform(uid).Coordinates);
|
||||
culsistComp.RecallDaggerActionEntity = dagger;
|
||||
_hands.TryPickupAnyHand(uid, dagger);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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, "Cultist");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void AppendRoundEndText(EntityUid uid,
|
||||
BloodCultRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
ref RoundEndTextAppendEvent args)
|
||||
{
|
||||
var winText = Loc.GetString($"blood-cult-{component.WinType.ToString().ToLower()}");
|
||||
args.AddLine(winText);
|
||||
|
||||
foreach (var cond in component.BloodCultWinCondition)
|
||||
{
|
||||
var text = Loc.GetString($"blood-cult-cond-{cond.ToString().ToLower()}");
|
||||
args.AddLine(text);
|
||||
}
|
||||
|
||||
args.AddLine(Loc.GetString("blood-cultist-list-start"));
|
||||
|
||||
var antags = _antag.GetAntagIdentifiers(uid);
|
||||
foreach (var (_, sessionData, name) in antags)
|
||||
{
|
||||
args.AddLine(Loc.GetString("blood-cultist-list-name-user", ("name", name), ("user", sessionData.UserName)));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGodCalled(GodCalledEvent ev)
|
||||
{
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out _, out _, out var cult, out _))
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOperativeZombified(EntityUid uid, BloodCultistComponent component, EntityZombifiedEvent args)
|
||||
{
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out var ruleUid, out _, out var cult, out _))
|
||||
{
|
||||
CheckCultLose(ruleUid, cult);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckCultLose(EntityUid uid, BloodCultRuleComponent cult)
|
||||
{
|
||||
var hasLivingCultists = EntityManager.EntityQuery<BloodCultistComponent>().Any();
|
||||
if (!hasLivingCultists && !cult.BloodCultWinCondition.Contains(BloodCultWinType.GodCalled)
|
||||
&& !cult.BloodCultWinCondition.Contains(BloodCultWinType.RitualConducted))
|
||||
{
|
||||
cult.BloodCultWinCondition.Add(BloodCultWinType.CultLose);
|
||||
cult.WinType = BloodCultWinType.CultLose;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Content.Server.GameTicking.Rules.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Stores data for <see cref="BloodCultRuleSystem"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(BloodCultRuleSystem))]
|
||||
public sealed partial class BloodCultRuleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string? SelectedGod;
|
||||
|
||||
[DataField]
|
||||
public BloodCultWinType WinType = BloodCultWinType.Neutral;
|
||||
|
||||
[DataField]
|
||||
public List<BloodCultWinType> BloodCultWinCondition = new();
|
||||
}
|
||||
|
||||
public enum BloodCultWinType : byte
|
||||
{
|
||||
GodCalled,
|
||||
RitualConducted,
|
||||
Neutral,
|
||||
CultLose
|
||||
}
|
||||
68
Content.Server/_Wega/ItemSelector/ItemSelectorSystem.cs
Normal file
68
Content.Server/_Wega/ItemSelector/ItemSelectorSystem.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Item.Selector.UI;
|
||||
using Content.Shared.Item.Selector.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
|
||||
namespace Content.Server.Item.Selector;
|
||||
|
||||
public sealed partial class ItemSelectorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IAdminLogManager _admin = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ItemSelectorComponent, BoundUIOpenedEvent>(OnUiOpened);
|
||||
SubscribeLocalEvent<ItemSelectorComponent, ItemSelectorSelectionMessage>(OnSelection);
|
||||
}
|
||||
|
||||
private void OnUiOpened(EntityUid uid, ItemSelectorComponent comp, BoundUIOpenedEvent args)
|
||||
{
|
||||
if (!CheckComponents(args.Actor, comp.WhitelistComponents, comp.BlacklistComponents))
|
||||
{
|
||||
_ui.CloseUi(uid, ItemSelectorUiKey.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateUi(uid, comp.Items);
|
||||
}
|
||||
|
||||
private bool CheckComponents(EntityUid entity, List<string> whitelist, List<string> blacklist)
|
||||
{
|
||||
if (whitelist.Count > 0 && !whitelist.All(component =>
|
||||
_componentFactory.TryGetRegistration(component, out var reg) && HasComp(entity, reg.Type)))
|
||||
return false;
|
||||
|
||||
if (blacklist.Count > 0 && blacklist.Any(component =>
|
||||
_componentFactory.TryGetRegistration(component, out var reg) && HasComp(entity, reg.Type)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateUi(EntityUid uid, List<EntProtoId> items)
|
||||
{
|
||||
if (!_ui.HasUi(uid, ItemSelectorUiKey.Key))
|
||||
return;
|
||||
|
||||
_ui.ServerSendUiMessage(uid, ItemSelectorUiKey.Key,
|
||||
new ItemSelectorUserMessage(items));
|
||||
}
|
||||
|
||||
private void OnSelection(EntityUid uid, ItemSelectorComponent comp, ItemSelectorSelectionMessage args)
|
||||
{
|
||||
var ent = Spawn(args.SelectedId, Transform(uid).Coordinates);
|
||||
_hands.TryForcePickupAnyHand(GetEntity(args.User), ent);
|
||||
|
||||
_admin.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(GetEntity(args.User)):user} selects a {ToPrettyString(ent):entity} instead of {ToPrettyString(uid):entity}");
|
||||
|
||||
QueueDel(uid);
|
||||
}
|
||||
}
|
||||
9
Content.Server/_Wega/Roles/BloodCultistRoleComponent.cs
Normal file
9
Content.Server/_Wega/Roles/BloodCultistRoleComponent.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Content.Shared.Roles.Components;
|
||||
|
||||
namespace Content.Server.Roles;
|
||||
|
||||
/// <summary>
|
||||
/// Added to mind role entities to tag that they are a blood cultist.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodCultistRoleComponent : BaseMindRoleComponent;
|
||||
@@ -784,6 +784,17 @@ namespace Content.Shared.Cuffs
|
||||
cuff.Removing = false;
|
||||
}
|
||||
|
||||
// Corvax-Wega-BloodCult-start
|
||||
/// <summary>
|
||||
/// Marks handcuffs as used. Required when applying cuffs programmatically
|
||||
/// (outside of normal DoAfter flow) to allow uncuffing.
|
||||
/// </summary>
|
||||
public void CuffUsed(HandcuffComponent cuff)
|
||||
{
|
||||
cuff.Used = true;
|
||||
}
|
||||
// Corvax-Wega-BloodCult-end
|
||||
|
||||
#region ActionBlocker
|
||||
|
||||
private void CheckAct(EntityUid uid, CuffableComponent component, CancellableEntityEventArgs args)
|
||||
|
||||
@@ -122,6 +122,25 @@ public abstract class SharedEmpSystem : EntitySystem
|
||||
return ev.Affected;
|
||||
}
|
||||
|
||||
// Corvax-Wega-BloodCult-start
|
||||
/// <summary>
|
||||
/// Triggers an EMP pulse at the given location, excluding specified entities.
|
||||
/// Used by Blood Cult to let cultists use EMP without affecting fellow cultists.
|
||||
/// </summary>
|
||||
public void EmpPulseExclusions(MapCoordinates coordinates, float range, float energyConsumption, float duration, IEnumerable<EntityUid> exclusions)
|
||||
{
|
||||
var exclusionsSet = new HashSet<EntityUid>(exclusions);
|
||||
foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range))
|
||||
{
|
||||
if (exclusionsSet.Contains(uid))
|
||||
continue;
|
||||
TryEmpEffects(uid, energyConsumption, TimeSpan.FromSeconds(duration));
|
||||
}
|
||||
if (_net.IsServer)
|
||||
Spawn(EmpPulseEffectPrototype, coordinates);
|
||||
}
|
||||
// Corvax-Wega-BloodCult-end
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
180
Content.Shared/_Wega/BloodCult/BloodCultComponents.cs
Normal file
180
Content.Shared/_Wega/BloodCult/BloodCultComponents.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using Content.Shared.StatusIcon;
|
||||
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]
|
||||
public sealed partial class BloodCultistComponent : Component
|
||||
{
|
||||
public bool BloodMagicActive = false;
|
||||
|
||||
public EntityUid? SelectedSpell { get; set; }
|
||||
|
||||
public List<EntityUid?> SelectedEmpoweringSpells = new();
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? RecallDaggerActionEntity;
|
||||
|
||||
public EntityUid? RecallSpearAction { get; set; }
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
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";
|
||||
|
||||
[DataField("cultistStatusIcon")]
|
||||
public ProtoId<FactionIconPrototype> StatusIcon { get; set; } = "BloodCultistFaction";
|
||||
}
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ShowCultistIconsComponent : Component;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class AutoCultistComponent : Component;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodCultObjectComponent : Component;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodDaggerComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public bool IsSharpered = false;
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodSpellComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<string> Prototype = new();
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodRuneComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string Prototype = default!;
|
||||
|
||||
public bool IsActive = true;
|
||||
|
||||
public bool BarrierActive = false;
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodRitualDimensionalRendingComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField]
|
||||
public TimeSpan ActivateTime = TimeSpan.Zero;
|
||||
|
||||
public bool Activate = false;
|
||||
|
||||
public float NextTimeTick { get; set; }
|
||||
}
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodStructureComponent : Component
|
||||
{
|
||||
[DataField("structureGear")]
|
||||
public List<string> StructureGear { get; private set; } = new();
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly), DataField]
|
||||
public TimeSpan ActivateTime = TimeSpan.Zero;
|
||||
|
||||
[DataField("fixture")]
|
||||
public string FixtureId = string.Empty;
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier? Sound { get; private set; }
|
||||
|
||||
[DataField]
|
||||
public bool CanInteract = true;
|
||||
|
||||
public bool IsActive = true;
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodPylonComponent : Component
|
||||
{
|
||||
public float NextTimeTick { get; set; }
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodOrbComponent : Component
|
||||
{
|
||||
public int Blood = 0;
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class StoneSoulComponent : Component
|
||||
{
|
||||
[DataField("soulProto", required: true)]
|
||||
public string SoulProto { get; set; } = default!;
|
||||
|
||||
public EntityUid? SoulEntity;
|
||||
|
||||
[ViewVariables]
|
||||
public ContainerSlot SoulContainer = default!;
|
||||
|
||||
public bool IsSoulSummoned = false;
|
||||
}
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ConstructComponent : Component;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodCultConstructComponent : Component;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodShuttleCurseComponent : Component;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class VeilShifterComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public int ActivationsCount = 4;
|
||||
}
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BloodSharpenerComponent : Component;
|
||||
|
||||
/// <summary>
|
||||
/// Заглушка для логики
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CultistEyesComponent : 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
|
||||
}
|
||||
316
Content.Shared/_Wega/BloodCult/BloodCultEvents.cs
Normal file
316
Content.Shared/_Wega/BloodCult/BloodCultEvents.cs
Normal file
@@ -0,0 +1,316 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Blood.Cult;
|
||||
|
||||
// Events
|
||||
public sealed class GodCalledEvent : EntityEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
public sealed class RitualConductedEvent : EntityEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodMagicPressedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
|
||||
public BloodMagicPressedEvent(NetEntity uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class BloodMagicMenuClosedEvent : EntityEventArgs
|
||||
{
|
||||
public NetEntity Uid { get; }
|
||||
public string SelectedSpell { get; }
|
||||
|
||||
public BloodMagicMenuClosedEvent(NetEntity uid, string selectedSpell)
|
||||
{
|
||||
Uid = uid;
|
||||
SelectedSpell = selectedSpell;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class BloodMagicDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
public string SelectedSpell { get; }
|
||||
|
||||
public BloodMagicDoAfterEvent(string selectedSpell)
|
||||
{
|
||||
SelectedSpell = selectedSpell;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
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 EmpoweringDoAfterEvent(string 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
|
||||
{
|
||||
public string SelectedRune { get; }
|
||||
public NetEntity Rune { get; }
|
||||
|
||||
public BloodRuneDoAfterEvent(string selectedRune, NetEntity rune)
|
||||
{
|
||||
SelectedRune = selectedRune;
|
||||
Rune = rune;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
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
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultStunActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultTeleportActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultElectromagneticPulseActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultShadowShacklesActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultTwistedConstructionActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultSummonEquipmentActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
public sealed partial class BloodCultSummonDaggerActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class RecallBloodDaggerEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public sealed partial class BloodCultHallucinationsActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultConcealPresenceActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultBloodRitesActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultBloodOrbActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultBloodRechargeActionEvent : EntityTargetActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultBloodSpearActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class RecallBloodSpearEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
|
||||
public sealed partial class BloodCultBloodBoltBarrageActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
66
Content.Shared/_Wega/BloodCult/SharedBloodCultSystem.cs
Normal file
66
Content.Shared/_Wega/BloodCult/SharedBloodCultSystem.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Actions.Components;
|
||||
using Content.Shared.Blood.Cult.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Stunnable;
|
||||
|
||||
namespace Content.Shared.Blood.Cult;
|
||||
|
||||
public abstract class SharedBloodCultSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedActionsSystem _action = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stun = default!;
|
||||
|
||||
#region Deconvertation
|
||||
public void CultistDeconvertation(EntityUid cultist)
|
||||
{
|
||||
if (!TryComp<BloodCultistComponent>(cultist, out var bloodCultist))
|
||||
return;
|
||||
|
||||
if (TryComp<ActionsContainerComponent>(cultist, out var actionsContainer))
|
||||
{
|
||||
foreach (var actionId in actionsContainer.Container.ContainedEntities.ToArray())
|
||||
{
|
||||
if (!TryComp(actionId, out MetaDataComponent? meta))
|
||||
continue;
|
||||
|
||||
var protoId = meta.EntityPrototype?.ID;
|
||||
if (protoId == BloodCultistComponent.CultObjective.Id
|
||||
|| protoId == BloodCultistComponent.CultCommunication.Id
|
||||
|| protoId == BloodCultistComponent.BloodMagic.Id
|
||||
|| protoId == BloodCultistComponent.RecallBloodDagger.Id)
|
||||
{
|
||||
_action.RemoveAction(cultist, actionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bloodCultist.RecallSpearActionEntity != null)
|
||||
_action.RemoveAction(cultist, bloodCultist.RecallSpearActionEntity);
|
||||
|
||||
if (bloodCultist.SelectedSpell != null)
|
||||
_action.RemoveAction(cultist, bloodCultist.SelectedSpell.Value);
|
||||
|
||||
foreach (var spell in bloodCultist.SelectedEmpoweringSpells)
|
||||
{
|
||||
if (spell != null)
|
||||
{
|
||||
_action.RemoveAction(cultist, spell.Value);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
RemComp<BloodCultistComponent>(cultist);
|
||||
if (HasComp<CultistEyesComponent>(cultist)) RemComp<CultistEyesComponent>(cultist);
|
||||
if (HasComp<PentagramDisplayComponent>(cultist)) RemComp<PentagramDisplayComponent>(cultist);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Content.Shared.Clothing.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class TearableClothingComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float Delay = 8f;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Clothing.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ToggleableSpriteClothingComponent : Component
|
||||
{
|
||||
[DataField("defaultSuffix")]
|
||||
public string DefaultSuffix = string.Empty;
|
||||
|
||||
[DataField("activeSuffix")]
|
||||
public string ActiveSuffix = string.Empty;
|
||||
|
||||
[ViewVariables]
|
||||
public bool IsToggled => !string.IsNullOrEmpty(ActiveSuffix);
|
||||
|
||||
[DataField]
|
||||
public float DoAfterTime = 0.75f;
|
||||
|
||||
public SoundPathSpecifier Sound = new SoundPathSpecifier("/Audio/Items/jumpsuit_equip.ogg");
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ToggleableSpriteClothingComponentState : ComponentState
|
||||
{
|
||||
public string ActiveSuffix;
|
||||
|
||||
public ToggleableSpriteClothingComponentState(string activeSuffix)
|
||||
{
|
||||
ActiveSuffix = activeSuffix;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Clothing;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class TearClothingDoAfterEvent : SimpleDoAfterEvent { }
|
||||
85
Content.Shared/_Wega/Clothing/TearableClothingSystem.cs
Normal file
85
Content.Shared/_Wega/Clothing/TearableClothingSystem.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Clothing;
|
||||
|
||||
public sealed class TearableClothingSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly DamageableSystem _damage = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
|
||||
private static readonly ProtoId<DamageTypePrototype> Damage = "Slash";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<TearableClothingComponent, GetVerbsEvent<AlternativeVerb>>(AddTearVerb);
|
||||
SubscribeLocalEvent<TearableClothingComponent, TearClothingDoAfterEvent>(OnDoAfter);
|
||||
}
|
||||
|
||||
private void AddTearVerb(Entity<TearableClothingComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (!HasComp<ClothingComponent>(entity) || !HasComp<DamageableComponent>(entity))
|
||||
return;
|
||||
|
||||
var text = Loc.GetString("tearable-clothing-verb-tear");
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Text = text,
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/zap.svg.192dpi.png")),
|
||||
Act = () => StartTearing(user, entity),
|
||||
Priority = 1
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
public void StartTearing(EntityUid user, Entity<TearableClothingComponent> entity)
|
||||
{
|
||||
if (!TryComp<PhysicsComponent>(user, out var physics) || physics.Mass <= 60f)
|
||||
{
|
||||
_popup.PopupClient(Loc.GetString("tearable-clothing-too-weakness"), user, user);
|
||||
return;
|
||||
}
|
||||
|
||||
var args = new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(entity.Comp.Delay),
|
||||
new TearClothingDoAfterEvent(), entity, entity)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
NeedHand = true
|
||||
};
|
||||
|
||||
_popup.PopupCoordinates(Loc.GetString("tearable-clothing-try-tear",
|
||||
("user", Identity.Name(user, EntityManager)), ("clothing", Name(entity))),
|
||||
Transform(user).Coordinates, type: PopupType.Medium);
|
||||
|
||||
_doAfter.TryStartDoAfter(args);
|
||||
}
|
||||
|
||||
private void OnDoAfter(Entity<TearableClothingComponent> entity, ref TearClothingDoAfterEvent args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled || args.Args.Target == null)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
_popup.PopupClient(Loc.GetString("tearable-clothing-successed", ("clothing", Name(entity))), args.User, args.User);
|
||||
|
||||
var damageSpec = new DamageSpecifier { DamageDict = { { Damage, 60 } } };
|
||||
_damage.TryChangeDamage(args.Args.Target.Value, damageSpec, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Clothing;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class ToggleSpriteClothingDoAfterEvent : SimpleDoAfterEvent { }
|
||||
@@ -0,0 +1,79 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Clothing;
|
||||
|
||||
public sealed class ToggleableSpriteClothingSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ToggleableSpriteClothingComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<ToggleableSpriteClothingComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleVerb);
|
||||
|
||||
SubscribeLocalEvent<BodyComponent, ToggleSpriteClothingDoAfterEvent>(OnDoAfter); // Fuck, I'm too lazy to think of something
|
||||
}
|
||||
|
||||
private static void OnGetState(EntityUid uid, ToggleableSpriteClothingComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new ToggleableSpriteClothingComponentState(component.ActiveSuffix);
|
||||
}
|
||||
|
||||
private void AddToggleVerb(Entity<ToggleableSpriteClothingComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
var user = args.User;
|
||||
if (!args.CanAccess || !args.CanInteract || Transform(entity).ParentUid != user
|
||||
|| !HasComp<ClothingComponent>(entity))
|
||||
return;
|
||||
|
||||
var text = entity.Comp.IsToggled
|
||||
? Loc.GetString("toggleable-clothing-verb-reset")
|
||||
: Loc.GetString("toggleable-clothing-verb-toggle");
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Text = text,
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/_Wega/Interface/VerbIcons/clothing.svg.192.dpi.png")),
|
||||
Act = () => ToggleClothing(user, entity)
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
public void ToggleClothing(EntityUid user, Entity<ToggleableSpriteClothingComponent> entity)
|
||||
{
|
||||
var args = new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(entity.Comp.DoAfterTime),
|
||||
new ToggleSpriteClothingDoAfterEvent(), user, entity)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
NeedHand = true
|
||||
};
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(args);
|
||||
}
|
||||
|
||||
private void OnDoAfter(Entity<BodyComponent> entity, ref ToggleSpriteClothingDoAfterEvent args)
|
||||
{
|
||||
if (args.Handled || args.Target == null)
|
||||
return;
|
||||
|
||||
if (!TryComp<ToggleableSpriteClothingComponent>(args.Target, out var toggleable))
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
toggleable.ActiveSuffix = toggleable.IsToggled
|
||||
? string.Empty
|
||||
: toggleable.DefaultSuffix;
|
||||
|
||||
_audio.PlayLocal(toggleable.Sound, args.Target.Value, args.Target);
|
||||
Dirty(args.Target.Value, toggleable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.DirtVisuals;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DirtSourceComponent : Component;
|
||||
48
Content.Shared/_Wega/Dirt/Components/DirtableComponent.cs
Normal file
48
Content.Shared/_Wega/Dirt/Components/DirtableComponent.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.DirtVisuals;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DirtableComponent : Component
|
||||
{
|
||||
[DataField("threshold")]
|
||||
public FixedPoint2 Threshold { get; set; } = 20;
|
||||
|
||||
[DataField("dirtSprite")]
|
||||
public string DirtSpritePath { get; set; } = "_Wega/Mobs/Effects/dirt_overlay.rsi";
|
||||
|
||||
[DataField("dirtState")]
|
||||
public string DirtState { get; set; } = "jumpsuit";
|
||||
|
||||
[DataField("foldingDirtState")]
|
||||
public string? FoldingDirtState { get; set; }
|
||||
|
||||
[DataField("equippedDirtState")]
|
||||
public string EquippedDirtState { get; set; } = "equipped-jumpsuit";
|
||||
|
||||
[ViewVariables]
|
||||
public FixedPoint2 CurrentDirtLevel { get; set; }
|
||||
|
||||
[ViewVariables]
|
||||
public Color DirtColor { get; set; } = Color.White;
|
||||
|
||||
[ViewVariables]
|
||||
public bool IsDirty => CurrentDirtLevel >= Threshold;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class DirtableComponentState : ComponentState
|
||||
{
|
||||
public FixedPoint2 CurrentDirtLevel;
|
||||
public Color DirtColor;
|
||||
public bool IsDirty;
|
||||
|
||||
public DirtableComponentState(FixedPoint2 currentDirtLevel, Color dirtColor, bool isDirty)
|
||||
{
|
||||
CurrentDirtLevel = currentDirtLevel;
|
||||
DirtColor = dirtColor;
|
||||
IsDirty = isDirty;
|
||||
}
|
||||
}
|
||||
229
Content.Shared/_Wega/Dirt/SharedDirtSystem.cs
Normal file
229
Content.Shared/_Wega/Dirt/SharedDirtSystem.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Foldable;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Shared.DirtVisuals;
|
||||
|
||||
public sealed class SharedDirtSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
public const float MaxDirtLevel = 100f;
|
||||
private const float DirtAccumulationRate = 0.01f;
|
||||
private ProtoId<TagPrototype> _hardsuit = "Hardsuit";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<DirtableComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<DirtableComponent, FoldedEvent>(OnFolded);
|
||||
SubscribeLocalEvent<DirtableComponent, ExaminedEvent>(OnExamined);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, DirtableComponent comp, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new DirtableComponentState(
|
||||
comp.CurrentDirtLevel,
|
||||
comp.DirtColor,
|
||||
comp.IsDirty
|
||||
);
|
||||
}
|
||||
|
||||
private void OnFolded(EntityUid uid, DirtableComponent comp, ref FoldedEvent args)
|
||||
{
|
||||
// Finally update this shit
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<DirtableComponent> entity, ref ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange || entity.Comp.CurrentDirtLevel < entity.Comp.Threshold)
|
||||
return;
|
||||
|
||||
float dirtPercentage = Math.Clamp(entity.Comp.CurrentDirtLevel.Float() / MaxDirtLevel * 100f, 0f, 100f);
|
||||
string colorHex = entity.Comp.DirtColor.ToHex();
|
||||
|
||||
string dirtLevel = dirtPercentage switch
|
||||
{
|
||||
< 30 => Loc.GetString("dirt-examined-level-low"),
|
||||
< 70 => Loc.GetString("dirt-examined-level-medium"),
|
||||
_ => Loc.GetString("dirt-examined-level-high")
|
||||
};
|
||||
|
||||
args.PushMarkup(
|
||||
Loc.GetString("dirt-examined-message", ("color", colorHex), ("percentage", (int)dirtPercentage), ("level", dirtLevel))
|
||||
);
|
||||
}
|
||||
|
||||
public void AddBloodDirtFromDamage(EntityUid target, EntityUid attacker, DamageSpecifier damage, bool isGunshot = false)
|
||||
{
|
||||
if (!TryComp<BloodstreamComponent>(target, out var bloodstream))
|
||||
return;
|
||||
|
||||
var bloodTypes = new[] { "Slash", "Piercing", "Blunt" };
|
||||
|
||||
FixedPoint2 bloodAmount = 0;
|
||||
foreach (var type in bloodTypes)
|
||||
{
|
||||
if (damage.DamageDict.TryGetValue(type, out var amount))
|
||||
bloodAmount += amount;
|
||||
}
|
||||
|
||||
if (bloodAmount <= 0)
|
||||
return;
|
||||
|
||||
var bloodSolution = new Solution();
|
||||
// Use BloodReferenceSolution (upstream renamed from BloodReagents)
|
||||
var bloodReagent = bloodstream.BloodReferenceSolution.Contents.Count > 0
|
||||
? bloodstream.BloodReferenceSolution.Contents[0].Reagent.Prototype
|
||||
: "Blood";
|
||||
bloodSolution.AddReagent(bloodReagent, bloodAmount * (0.2f / DirtAccumulationRate));
|
||||
|
||||
var slots = new List<string> { "outerClothing", "jumpsuit", "gloves", "belt", "mask", "head" };
|
||||
ApplyDirtToClothing(target, bloodSolution, _random.Pick(slots));
|
||||
|
||||
if (attacker != target)
|
||||
{
|
||||
if (isGunshot)
|
||||
{
|
||||
var targetPosition = _transform.GetWorldPosition(target);
|
||||
var attackerPosition = _transform.GetWorldPosition(attacker);
|
||||
var distance = (attackerPosition - targetPosition).Length();
|
||||
if (distance > 2.5f)
|
||||
return;
|
||||
}
|
||||
ApplyDirtToClothing(attacker, bloodSolution, _random.Pick(slots));
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyDirtToClothing(EntityUid wearer, Solution solution)
|
||||
{
|
||||
var slots = new List<string> { "shoes" };
|
||||
|
||||
var isLyingDown = TryComp<StandingStateComponent>(wearer, out var standing) && !standing.Standing;
|
||||
if (isLyingDown)
|
||||
{
|
||||
slots.AddRange(new[] { "outerClothing", "jumpsuit", "gloves", "belt", "mask", "head" });
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_inventory.TryGetSlotEntity(wearer, "outerClothing", out var outerClothing)
|
||||
&& _tag.HasTag(outerClothing.Value, _hardsuit))
|
||||
slots.Add("outerClothing");
|
||||
}
|
||||
|
||||
foreach (var slot in slots)
|
||||
{
|
||||
if (_inventory.TryGetSlotEntity(wearer, slot, out var clothing))
|
||||
UpdateDirtFromSolution(clothing.Value, solution);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyDirtToClothing(EntityUid wearer, Solution solution, string slot)
|
||||
{
|
||||
if (_inventory.TryGetSlotEntity(wearer, slot, out var clothing))
|
||||
UpdateDirtFromSolution(clothing.Value, solution);
|
||||
}
|
||||
|
||||
private void UpdateDirtFromSolution(EntityUid uid, Solution solution, DirtableComponent? comp = null)
|
||||
{
|
||||
if (!TryComp(uid, out comp) || solution.Volume == 0)
|
||||
return;
|
||||
|
||||
bool isOnlyWater = solution.Contents.Count == 1
|
||||
&& solution.Contents[0].Reagent.Prototype == "Water";
|
||||
|
||||
if (isOnlyWater)
|
||||
{
|
||||
float removedDirt = Math.Min(solution.Volume.Float() * DirtAccumulationRate * 2f, comp.CurrentDirtLevel.Float());
|
||||
CleanDirt(uid, removedDirt);
|
||||
return;
|
||||
}
|
||||
|
||||
float addedDirt = Math.Min(solution.Volume.Float() * DirtAccumulationRate, 10f);
|
||||
comp.CurrentDirtLevel = FixedPoint2.New(
|
||||
Math.Min(comp.CurrentDirtLevel.Float() + addedDirt, MaxDirtLevel)
|
||||
);
|
||||
|
||||
if (comp.CurrentDirtLevel >= MaxDirtLevel)
|
||||
return;
|
||||
|
||||
var colors = new List<Color>();
|
||||
foreach (var reagent in solution.Contents)
|
||||
{
|
||||
if (reagent.Reagent.Prototype == "Water")
|
||||
continue;
|
||||
|
||||
if (!_prototype.TryIndex<ReagentPrototype>(reagent.Reagent.Prototype, out var proto))
|
||||
continue;
|
||||
|
||||
colors.Add(proto.SubstanceColor);
|
||||
}
|
||||
|
||||
if (colors.Count > 0)
|
||||
{
|
||||
comp.DirtColor = BlendColorsProperly(comp.DirtColor, colors);
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
}
|
||||
|
||||
public void CleanDirt(EntityUid uid, float amount, float efficiency = 1f, DirtableComponent? comp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp, false) || amount <= 0)
|
||||
return;
|
||||
|
||||
var actualRemoval = amount * efficiency;
|
||||
comp.CurrentDirtLevel = FixedPoint2.Max(comp.CurrentDirtLevel - actualRemoval, 0);
|
||||
|
||||
if (comp.CurrentDirtLevel <= 0)
|
||||
comp.DirtColor = Color.White;
|
||||
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
|
||||
private Color BlendColorsProperly(Color currentColor, List<Color> newColors)
|
||||
{
|
||||
if (newColors.Count == 1 && currentColor == Color.White)
|
||||
return newColors[0];
|
||||
|
||||
float rNew = 0, gNew = 0, bNew = 0;
|
||||
foreach (var color in newColors)
|
||||
{
|
||||
rNew += color.R / 255f;
|
||||
gNew += color.G / 255f;
|
||||
bNew += color.B / 255f;
|
||||
}
|
||||
rNew /= newColors.Count;
|
||||
gNew /= newColors.Count;
|
||||
bNew /= newColors.Count;
|
||||
|
||||
float rCurrent = currentColor.R / 255f;
|
||||
float gCurrent = currentColor.G / 255f;
|
||||
float bCurrent = currentColor.B / 255f;
|
||||
|
||||
float r = rCurrent * 0.85f + rNew * 0.15f;
|
||||
float g = gCurrent * 0.85f + gNew * 0.15f;
|
||||
float b = bCurrent * 0.85f + bNew * 0.15f;
|
||||
|
||||
r = Math.Clamp(r, 0f, 1f) * 255f;
|
||||
g = Math.Clamp(g, 0f, 1f) * 255f;
|
||||
b = Math.Clamp(b, 0f, 1f) * 255f;
|
||||
|
||||
return new Color(r, g, b);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Content.Shared.Disease.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Value added to clothing to give its wearer
|
||||
/// protection against infection from diseases
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class DiseaseProtectionComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Float value between 0 and 1, will be subtracted
|
||||
/// from the infection chance (which is base 0.7)
|
||||
/// Reference guide is a full biosuit w/gloves & mask
|
||||
/// should add up to exactly 0.7
|
||||
/// </summary>
|
||||
[DataField("protection")]
|
||||
public float Protection = 0.1f;
|
||||
/// <summary>
|
||||
/// Is the component currently being worn and affecting someone's disease
|
||||
/// resistance? Making the unequip check not totally CBT
|
||||
/// </summary>
|
||||
public bool IsActive = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Content.Shared.DirtVisuals;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.EntityEffects.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// Cleans dirt from dirtable entities.
|
||||
/// The cleaning amount is equal to <see cref="WashDirt.CleaningAmount"/> modified by scale.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
|
||||
public sealed partial class WashDirtEntityEffectSystem : EntityEffectSystem<DirtableComponent, WashDirt>
|
||||
{
|
||||
[Dependency] private readonly SharedDirtSystem _dirt = default!;
|
||||
|
||||
protected override void Effect(Entity<DirtableComponent> entity, ref EntityEffectEvent<WashDirt> args)
|
||||
{
|
||||
if (entity.Comp.CurrentDirtLevel <= 0)
|
||||
return;
|
||||
|
||||
var cleaningAmount = args.Effect.CleaningAmount * args.Scale;
|
||||
_dirt.CleanDirt(entity, cleaningAmount);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="EntityEffect"/>
|
||||
public sealed partial class WashDirt : EntityEffectBase<WashDirt>
|
||||
{
|
||||
/// <summary>
|
||||
/// Amount of dirt to clean.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float CleaningAmount = 5f;
|
||||
|
||||
public override string EntityEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-wash-dirt-reaction");
|
||||
}
|
||||
27
Content.Shared/_Wega/ItemSelector/ItemSelectorComponent.cs
Normal file
27
Content.Shared/_Wega/ItemSelector/ItemSelectorComponent.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Item.Selector.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class ItemSelectorComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// List of item prototype IDs that can be selected.
|
||||
/// </summary>
|
||||
[DataField("items")]
|
||||
public List<EntProtoId> Items = new();
|
||||
|
||||
/// <summary>
|
||||
/// Components that an entity must have to display the UI (whitelist)
|
||||
/// If it is empty, the check is not performed.
|
||||
/// </summary>
|
||||
[DataField("requiredComponents")]
|
||||
public List<string> WhitelistComponents = new();
|
||||
|
||||
/// <summary>
|
||||
/// Components that an entity should not have to display the UI (blacklist)
|
||||
/// If it is empty, the check is not performed.
|
||||
/// </summary>
|
||||
[DataField("forbiddenComponents")]
|
||||
public List<string> BlacklistComponents = new();
|
||||
}
|
||||
34
Content.Shared/_Wega/ItemSelector/ItemSelectorUi.cs
Normal file
34
Content.Shared/_Wega/ItemSelector/ItemSelectorUi.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Item.Selector.UI;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum ItemSelectorUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ItemSelectorUserMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public List<EntProtoId> Items;
|
||||
|
||||
public ItemSelectorUserMessage(List<EntProtoId> items)
|
||||
{
|
||||
Items = items;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ItemSelectorSelectionMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public NetEntity User;
|
||||
public EntProtoId SelectedId;
|
||||
|
||||
public ItemSelectorSelectionMessage(NetEntity user, EntProtoId selectedId)
|
||||
{
|
||||
User = user;
|
||||
SelectedId = selectedId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Content.Shared.Surgery.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class ClothingSterilityComponent : Component
|
||||
{
|
||||
[DataField("modifier")]
|
||||
public float Modifier = 1f;
|
||||
}
|
||||
BIN
Resources/Audio/_Wega/Ambience/Antag/bloodcult_eyes.ogg
Normal file
BIN
Resources/Audio/_Wega/Ambience/Antag/bloodcult_eyes.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Ambience/Antag/bloodcult_halos.ogg
Normal file
BIN
Resources/Audio/_Wega/Ambience/Antag/bloodcult_halos.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Ambience/Antag/bloodcult_scribe.ogg
Normal file
BIN
Resources/Audio/_Wega/Ambience/Antag/bloodcult_scribe.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Ambience/Antag/bloodcult_start.ogg
Normal file
BIN
Resources/Audio/_Wega/Ambience/Antag/bloodcult_start.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Effects/Objects/tear_clothing1.ogg
Normal file
BIN
Resources/Audio/_Wega/Effects/Objects/tear_clothing1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Effects/Objects/tear_clothing2.ogg
Normal file
BIN
Resources/Audio/_Wega/Effects/Objects/tear_clothing2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Effects/anvil.ogg
Normal file
BIN
Resources/Audio/_Wega/Effects/anvil.ogg
Normal file
Binary file not shown.
96
Resources/Locale/ru-RU/_wega/bloodcult/bloodcult.ftl
Normal file
96
Resources/Locale/ru-RU/_wega/bloodcult/bloodcult.ftl
Normal file
@@ -0,0 +1,96 @@
|
||||
# UI
|
||||
select-constuct-juggernaut = Джаггернаут
|
||||
select-constuct-wraith = Фантом
|
||||
select-constuct-artificer = Созидатель
|
||||
select-constuct-proteon = Пилон
|
||||
|
||||
select-spell-stun = Ошеломление
|
||||
select-spell-teleport = Телепорт
|
||||
select-spell-electromagnetic-pulse = Электромагнитный Испульс
|
||||
select-spell-shadow-shackles = Теневые Оковы
|
||||
select-spell-twisted-construction = Искаженное Строительство
|
||||
select-spell-summon-equipment = Призыв Снаряжения
|
||||
select-spell-summon-dagger = Призыв Кинжала
|
||||
select-spell-hallucinations = Галлюцинации
|
||||
select-spell-conceal-presence = Маскировка Присутствия
|
||||
select-spell-blood-rites = Кровавый Обряд
|
||||
|
||||
select-blood-orb = Кровавая Сфера
|
||||
select-blood-recharge = Кровавая Перезарядка
|
||||
select-blood-spear = Кровавое Копье
|
||||
select-blood-bolt-barrage = Кровавый Шквал Болтов
|
||||
|
||||
runes-ui-default-title = Руны
|
||||
offering-rune = Руна Предложения
|
||||
teleport-rune = Руна Телепорта
|
||||
empowering-rune = Руна Усиления
|
||||
revive-rune = Руна Возрождения
|
||||
barrier-rune = Руна Барьера
|
||||
summoning-rune = Руна Призыва
|
||||
bloodboil-rune = Руна Вскипания Крови
|
||||
spiritrealm-rune = Руна Царства Духов
|
||||
ritual-dimensional-rending-rune = Ритуал Разрыва Измерений
|
||||
|
||||
# System
|
||||
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-sharpener-success = точило обратилось в прах
|
||||
blood-sharpener-failed = кинжал уже был заточен
|
||||
blood-cult-failed-attack = вы не можете навредить членам культа
|
||||
stone-soul-empty = камень души пустой
|
||||
stone-soul-already-summoned = душа уже была призвана
|
||||
stone-soul-summoned = душа призвана
|
||||
stone-soul-retracted = душа возвратилось в камень
|
||||
blood-curse-failed = кровавое проклятие не удалось
|
||||
blood-veil-shifter-failed = ничего не произошло
|
||||
blood-construct-no-mind = камень души пустой
|
||||
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 = вы уже имеете кинжал
|
||||
blood-orb-dialog-title = Передача крови
|
||||
blood-orb-dialog-prompt = Количество
|
||||
blood-orb-invalid-input = Невозможное значение, укажите числовое значение, которое хотите передать
|
||||
blood-orb-not-enough-blood = У вас не достаточно собранной крови
|
||||
blood-orb-success = Вы выделили { $amount } единиц крови
|
||||
blood-orb-absorbed = сфера растекается в лужу крови и поглащается
|
||||
blood-cult-spear-failed = недостаточно крови для призыва копья
|
||||
cult-spear-not-found = кровавого копья не существует
|
||||
cult-spear-too-far = расстояние до копья слишком велико
|
||||
cult-spear-recalled = копье образуется перед вами
|
||||
blood-cult-bolt-barrage-failed = недостаточно крови для призыва...
|
||||
blood-cult-shadow-shackles-failed = ничего не произошло
|
||||
blood-cult-twisted-failed = ничего не произошло
|
||||
blood-cult-blood-rites-failed = ничего не произошло
|
||||
blood-cult-spell-failed = ничего не произошло
|
||||
|
||||
rune-ritual-failed = ритуал не может быть начат
|
||||
rune-select-complete = надрезав свою руку вы начертали руну
|
||||
ritual-activate-too-soon = РИТУАЛ МОЖНО БУДЕТ НАЧАТЬ ПОВТОРНО ЧЕРЕЗ { $time } СЕКУНД
|
||||
ritual-activate-failed = НЕВОЗМОЖНО НАЧАТЬ РИТУАЛ
|
||||
rune-activate-failed = невозможно активировать руну
|
||||
blood-ritual-warning = Образы древнего богоподобного существа соединяюстя воедино { $location }. Прервите ритуал любой целой, пока станция не была уничтожена!
|
||||
blood-ritual-activate-warning = Был обнаружен сдвиг пространства { $location }. Прекратите распространение всеми доступными средствами. Ожидаемое расширение через 45 секунд.
|
||||
ritual-failed = РИТУАЛ ПРОВАЛИ
|
||||
|
||||
blood-cultist-offering-message = Mah'weyh pleggh at e'ntrath!
|
||||
blood-cultist-teleport-message = Sas'so c'arta forbici!
|
||||
blood-cultist-empowering-message = H'drak v'loso, mir'kanas verbot!
|
||||
blood-cultist-revive-message = Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!
|
||||
blood-cultist-barrier-message = Khari'd! Eske'te tannin!
|
||||
blood-cultist-summoning-message = N'ath reth sh'yro eth d'rekkathnor!
|
||||
blood-cultist-bloodboil-message = Dedo ol'btoh!
|
||||
blood-cultist-spiritrealm-message = Gal'h'rfikk harfrandid mud'gib!
|
||||
blood-cultist-ritual-message = TOK-LYR RQA-NAP G'OLT-ULOFT!
|
||||
blood-cultist-default-message = Durn'koth ya'riska thol'mar!
|
||||
7
Resources/Locale/ru-RU/_wega/clothing/clothing.ftl
Normal file
7
Resources/Locale/ru-RU/_wega/clothing/clothing.ftl
Normal file
@@ -0,0 +1,7 @@
|
||||
toggleable-clothing-verb-toggle = Изменить вид
|
||||
toggleable-clothing-verb-reset = Вернуть исходный вид
|
||||
|
||||
tearable-clothing-verb-tear = Порвать одежду
|
||||
tearable-clothing-too-weakness = Вы слишком слабы, чтобы сделать это
|
||||
tearable-clothing-try-tear = {$user} пытается порвать {$clothing}!
|
||||
tearable-clothing-successed = Вы разорвали {$clothing}
|
||||
7
Resources/Locale/ru-RU/_wega/dirt/dirt.ftl
Normal file
7
Resources/Locale/ru-RU/_wega/dirt/dirt.ftl
Normal file
@@ -0,0 +1,7 @@
|
||||
dirt-examined-message = [color={$color}]Загрязняно на {$percentage}% ({$level})[/color]
|
||||
dirt-examined-level-low = слабое
|
||||
dirt-examined-level-medium = среднее
|
||||
dirt-examined-level-high = сильное
|
||||
washing-machine-verb-start = Начать стирку
|
||||
shower-verb-start = Включить
|
||||
shower-verb-stop = Выключить
|
||||
@@ -0,0 +1,36 @@
|
||||
blood-cult-title = Культ крови
|
||||
blood-cult-description = Верные последователи крови среди нас...
|
||||
|
||||
blood-cult-role-greeting-human =
|
||||
Вы — Культист Крови!
|
||||
Вы — часть тёмного культа, что служит Геометриви Крови, { $god }.
|
||||
Ваша цель — призвать аватар и привести культ к победе.
|
||||
В ваших руках ритуальный кинжал и руны для создания страшных структур. Жертвы должны быть принесены в дар высокопоставленные члены экипажа или охраны.
|
||||
Призовите божество в укромном месте с помощью 9 культистов и ритуала.
|
||||
Только так вы обеспечите победу!
|
||||
blood-cult-role-greeting-animal = Вы — Существо Крови! Вы — часть тени, служите Геометрии Крови, { $god }. Помогите своим братьям в призыве и принесении жертв.
|
||||
|
||||
current-god-narsie = Нар'Си
|
||||
current-god-reaper = Жнецу
|
||||
current-god-kharin = Кха'Рину
|
||||
|
||||
blood-cult-break-control =
|
||||
Туман перед глазами { $name } рассеялся, { GENDER($name) ->
|
||||
[male] он приходит в себя.
|
||||
[female] она приходит в себя.
|
||||
[epicene] они приходят в себя.
|
||||
*[neuter] оно приходит в себя.
|
||||
}
|
||||
|
||||
blood-cult-godcalled = [color=crimson]Победа Культа Крови[/color]
|
||||
blood-cult-ritualconducted = [color=blue]Малая победа Культа Крови[/color]
|
||||
blood-cult-neutral = [color=yellow]Ничейный исход[/color]
|
||||
blood-cult-cultlose = [color=grey]Поражение Культа Крови[/color]
|
||||
|
||||
blood-cult-cond-godcalled = Божество Крови было призвано, его тёмная сила охватила станцию!
|
||||
blood-cult-cond-ritualconducted = Ритуал не был завершён, Культ Крови только собрал силу, чтобы призвать Божество Крови!
|
||||
blood-cult-cond-neutral = Цели не выполнены, Культ Крови ничего не достиг.
|
||||
blood-cult-cond-cultlose = Культ Крови потерпел поражение, жертвы не были принесены, и Божество Крови не явилось.
|
||||
|
||||
blood-cultist-list-start = Культистами были:
|
||||
blood-cultist-list-name-user = - [color=White]{ $name }[/color] ([color=gray]{ $user }[/color])
|
||||
1
Resources/Locale/ru-RU/_wega/materials/materials.ftl
Normal file
1
Resources/Locale/ru-RU/_wega/materials/materials.ftl
Normal file
@@ -0,0 +1 @@
|
||||
materials-runemetal = рунический метал
|
||||
27
Resources/Locale/ru-RU/_wega/stack/stacks.ftl
Normal file
27
Resources/Locale/ru-RU/_wega/stack/stacks.ftl
Normal file
@@ -0,0 +1,27 @@
|
||||
stack-runemetal =
|
||||
{ $amount ->
|
||||
[1] лист
|
||||
[few] листа
|
||||
*[other] листов
|
||||
} рунической стали
|
||||
stack-capacitor =
|
||||
{ $amount ->
|
||||
[1] конденсатор
|
||||
[few] конденсатора
|
||||
*[other] конденсаторов
|
||||
}
|
||||
stack-matter-bin =
|
||||
{ $amount ->
|
||||
[1] ёмкость материи
|
||||
[few] ёмкостей материи
|
||||
*[other] ёмкостей материи
|
||||
}
|
||||
stack-sepia-floor = стальная светлая плитка
|
||||
|
||||
stack-tyriumpack = пакет тириума
|
||||
stack-tourniquet =
|
||||
{ $amount ->
|
||||
[1] турникет
|
||||
[few] турникета
|
||||
*[other] турникетов
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
# Basic
|
||||
ent-ActionBloodCultObjective = [color=red]Цель[/color]
|
||||
.desc = Показывает текущую цель культа.
|
||||
ent-ActionBloodCultComms = [color=red]Общение[/color]
|
||||
.desc = Позволяет разговаривать со своими собратьями.
|
||||
ent-ActionBloodMagic = [color=red]Магия крови[/color]
|
||||
.desc = Вызывайте способности своей кровью.
|
||||
ent-ActionRecallBloodDagger = [color=red]Вернуть кинжал[/color]
|
||||
.desc = Если он существует, он обязательно вернется к вам.
|
||||
|
||||
# Blood Magic
|
||||
ent-ActionBloodCultStun = [color=red]Ошеломление[/color]
|
||||
.desc = Мощное заклинание, которое вырубит и обеззвучит жертв при контакте. Простое, чистое и весьма эффективное средство для множества ситуаций.
|
||||
ent-ActionBloodCultTeleport = [color=red]Телепорт[/color]
|
||||
.desc = Телепортирует цель на случайную руну телепорта.
|
||||
ent-ActionBloodCultElectromagneticPulse = [color=red]Электромагнитный импульс[/color]
|
||||
.desc = Вызовет ЭМИ импульс поражающий всех кроме культистов.
|
||||
ent-ActionBloodCultShadowShackles = [color=red]Теневые оковы[/color]
|
||||
.desc = Применение закует жертву в оковы.
|
||||
ent-ActionBloodCultTwistedConstruction = [color=red]Искаженное строительство[/color]
|
||||
.desc = Зловещее заклинание, используемое для преобразования.
|
||||
ent-ActionBloodCultSummonEquipment = [color=red]Призыв снаряжения[/color]
|
||||
.desc = Это заклинание позволяет вам призвать для себя или другого культиста полный комплект боевого снаряжения.
|
||||
ent-ActionBloodCultSummonDagger = [color=red]Призыв кинжала[/color]
|
||||
.desc = Призовите ваш личный ритуальный кинжал.
|
||||
ent-ActionBloodCultHallucinations = [color=red]Галлюцинации[/color]
|
||||
.desc = Заклинание полезное для скрытности, которое разрушит сознание жертвы кошмарными галлюцинациями. Весёлое для жертв, редко полезное на практике.
|
||||
ent-ActionBloodCultConcealPresence = [color=red]Маскировка присутствия[/color]
|
||||
.desc = Многофункциональное заклинание, которое чередуется между сокрытием и раскрытием поблизости рун и культистских сооружений.
|
||||
ent-ActionBloodCultBloodRites = [color=red]Кровавый обряд[/color]
|
||||
.desc = Уникальное заклинание для сбора крови или лечения союзников. Также используется для создания мощного оружия, такого как кровавое копьё, или активации атакующих способностей.
|
||||
ent-ActionBloodCultOrb = [color=red]Кровавая сфера[/color]
|
||||
.desc = Способность позволяющая передать кровь другому культисту.
|
||||
ent-ActionBloodCultRecharge = [color=red]Кровавая перезарядка[/color]
|
||||
.desc = Способность позволяющая перезарядить магическое снаряжение.
|
||||
ent-ActionBloodCultSpear = [color=red]Кровавое копье[/color]
|
||||
.desc = Способность позволяющая призвать кровавое копье.
|
||||
ent-RecallBloodCultSpear = [color=red]Вернуть копье[/color]
|
||||
.desc = Способность позволяющая призвать кровавое копье.
|
||||
ent-ActionBloodCultBoltBarrage = [color=red]Кровавое шквал болтов[/color]
|
||||
.desc = Способность позволяющая призвать кровавое копье.
|
||||
|
||||
# Construct
|
||||
ent-TeleportConstructSpell = Бестелестность
|
||||
.desc = Способность позволяющая пройти сквозь видимое и невидимое.
|
||||
ent-WallBuildConstructSpell = Построить стену
|
||||
.desc = Возвести стену.
|
||||
ent-ConstructBuildConstructSpell = Построить конструкт
|
||||
.desc = Возвести конструкт.
|
||||
ent-SoulStoneConstructSpell = Создать камень души
|
||||
.desc = Призывает пустой камень души.
|
||||
ent-CloneConstructSpell = Призвать жнеца
|
||||
.desc = Призывает вашу точную копию.
|
||||
@@ -0,0 +1 @@
|
||||
ent-BloodCultOrb = кровавая сфера
|
||||
@@ -0,0 +1,14 @@
|
||||
ent-MobObserverIfrit = ифрит
|
||||
.desc = ???
|
||||
ent-MobBanshee = банши
|
||||
.desc = Жуткий призрак.
|
||||
ent-MobConstructJuggernaut = джаггернаут
|
||||
.desc = Ужасное, нечестивое создание, порождение самого дьявола!
|
||||
ent-MobConstructWraith = Фантом
|
||||
.desc = { ent-MobConstructJuggernaut.desc }
|
||||
ent-MobConstructArtificer = Созидатель
|
||||
.desc = { ent-MobConstructJuggernaut.desc }
|
||||
ent-MobConstructHarvester = Жнец
|
||||
.desc = { ent-MobConstructJuggernaut.desc }
|
||||
ent-MobConstructProteon = Протеон
|
||||
.desc = { ent-MobConstructJuggernaut.desc }
|
||||
@@ -0,0 +1,25 @@
|
||||
ent-BaseBloodRune = руна
|
||||
ent-BloodRuneOffering = { ent-BaseBloodRune }
|
||||
ent-BloodRuneTeleport = { ent-BaseBloodRune }
|
||||
ent-BloodRuneEmpowering = { ent-BaseBloodRune }
|
||||
ent-BloodRuneRevive = { ent-BaseBloodRune }
|
||||
ent-BloodRuneBarrier = { ent-BaseBloodRune }
|
||||
ent-BloodRuneSummoning = { ent-BaseBloodRune }
|
||||
ent-BloodRuneBloodBoil = { ent-BaseBloodRune }
|
||||
ent-BloodRuneSpiritealm = { ent-BaseBloodRune }
|
||||
ent-BloodRuneRitualDimensionalRending = { ent-BaseBloodRune }
|
||||
ent-BloodCultConstruct = конструкт
|
||||
.desc = Cтранная парящая в воздухе конструкция.
|
||||
.suffix = НЕ МАППИТЬ
|
||||
ent-BloodCultStructureArchives = архивы
|
||||
.desc = Письменный стол, покрытый загадочными рукописями и томами на неизвестных языках. Глядя на текст, проходят мурашки.
|
||||
.suffix = НЕ МАППИТЬ
|
||||
ent-BloodCultStructureAltar = алтарь крови
|
||||
.desc = Алтарь некой богини.
|
||||
.suffix = НЕ МАППИТЬ
|
||||
ent-BloodCultStructureForge = кузница душ
|
||||
.desc = Оккультная кузня. Здесь творят не только зло, но и снаряжения зла.
|
||||
.suffix = НЕ МАППИТЬ
|
||||
ent-BloodCultStructurePylon = пилон
|
||||
.desc = Таинственное лицо смотрит на вас.
|
||||
.suffix = НЕ МАППИТЬ
|
||||
@@ -0,0 +1,2 @@
|
||||
roles-antag-blood-cultist-name = Культист крови
|
||||
roles-antag-blood-cultist-objective = Выполните обряд и призовите божество.
|
||||
368
Resources/Prototypes/_Wega/Actions/bloodcult.yml
Normal file
368
Resources/Prototypes/_Wega/Actions/bloodcult.yml
Normal file
@@ -0,0 +1,368 @@
|
||||
# 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
|
||||
name: "[color=red]Blood magic[/color]"
|
||||
description: "Summon abilities with your blood."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "blood_magic" }
|
||||
useDelay: 15
|
||||
priority: 1
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultBloodMagicActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionRecallBloodDagger
|
||||
parent: BaseAction
|
||||
name: "[color=red]Recall dagger[/color]"
|
||||
description: "If it exists, it will definitely come back to you."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "recall_dagger" }
|
||||
useDelay: 5
|
||||
- type: InstantAction
|
||||
event: !type:RecallBloodDaggerEvent
|
||||
|
||||
# Blood Magic
|
||||
- type: entity
|
||||
id: ActionBloodCultStun
|
||||
parent: BaseAction
|
||||
name: "[color=red]Stun[/color]"
|
||||
description: "A powerful spell that will knock out and deafen victims upon contact. A simple, clean and very effective tool for a variety of situations."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "stun" }
|
||||
useDelay: 5
|
||||
- type: LimitedCharges
|
||||
maxCharges: 1
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultStunActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultTeleport
|
||||
parent: BaseAction
|
||||
name: "[color=red]Teleport[/color]"
|
||||
description: "Teleports the target to a random teleport rune."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "teleport" }
|
||||
useDelay: 5
|
||||
- type: LimitedCharges
|
||||
maxCharges: 1
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultTeleportActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultElectromagneticPulse
|
||||
parent: BaseAction
|
||||
name: "[color=red]Electromagnetic Pulse[/color]"
|
||||
description: "It will trigger an EMP pulse that affects everyone except the cultists."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "electromagneticpulse" }
|
||||
useDelay: 5
|
||||
- type: LimitedCharges
|
||||
maxCharges: 1
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultElectromagneticPulseActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultShadowShackles
|
||||
parent: BaseAction
|
||||
name: "[color=red]Shadow Shackles[/color]"
|
||||
description: "The use will put the victim in chains."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "shadowshackles" }
|
||||
useDelay: 20
|
||||
- type: LimitedCharges
|
||||
maxCharges: 4
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultShadowShacklesActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultTwistedConstruction
|
||||
parent: BaseAction
|
||||
name: "[color=red]Twisted Construction[/color]"
|
||||
description: "A sinister spell used to transform."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "twistedconstruction" }
|
||||
useDelay: 5
|
||||
- type: LimitedCharges
|
||||
maxCharges: 1
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultTwistedConstructionActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultSummonEquipment
|
||||
parent: BaseAction
|
||||
name: "[color=red]Summon Equipment[/color]"
|
||||
description: "A sinister spell used to transform."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "summonequipment" }
|
||||
useDelay: 5
|
||||
- type: LimitedCharges
|
||||
maxCharges: 1
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultSummonEquipmentActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultSummonDagger
|
||||
parent: BaseAction
|
||||
name: "[color=red]Summon Dagger[/color]"
|
||||
description: ""
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "dagger" }
|
||||
useDelay: 5
|
||||
- type: LimitedCharges
|
||||
maxCharges: 1
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultSummonDaggerActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultHallucinations
|
||||
parent: BaseAction
|
||||
name: "[color=red]Hallucinations[/color]"
|
||||
description: "A spell useful for stealth that will destroy the victim's consciousness with nightmarish hallucinations. Fun for victims, rarely useful in practice."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "hallucinations" }
|
||||
itemIconStyle: BigAction
|
||||
useDelay: 20
|
||||
- type: TargetAction
|
||||
range: 6
|
||||
- type: LimitedCharges
|
||||
maxCharges: 4
|
||||
- type: EntityTargetAction
|
||||
event: !type:BloodCultHallucinationsActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultConcealPresence
|
||||
parent: BaseAction
|
||||
name: "[color=red]Conceal Presence[/color]"
|
||||
description: "A multifunctional spell that alternates between hiding and revealing nearby runes and cultist structures."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "concealpresence" }
|
||||
useDelay: 5
|
||||
- type: LimitedCharges
|
||||
maxCharges: 10
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultConcealPresenceActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultBloodRites
|
||||
parent: BaseAction
|
||||
name: "[color=red]Blood rites[/color]"
|
||||
description: "A unique spell for collecting blood or healing allies. It is also used to create powerful weapons such as the Blood Spear, or to activate attacking abilities."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "blood_rites" }
|
||||
useDelay: 15
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultBloodRitesActionEvent
|
||||
|
||||
# Blood Rites
|
||||
- type: entity
|
||||
id: ActionBloodCultOrb
|
||||
parent: BaseAction
|
||||
name: "[color=red]Blood orb[/color]"
|
||||
description: "An ability that allows you to transfer blood to another cultist."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "orb" }
|
||||
useDelay: 5
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultBloodOrbActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultRecharge
|
||||
parent: BaseAction
|
||||
name: "[color=red]Blood recharge[/color]"
|
||||
description: "An ability that allows you to recharge magical equipment."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "recharge" }
|
||||
itemIconStyle: BigAction
|
||||
useDelay: 5
|
||||
- type: TargetAction
|
||||
- type: EntityTargetAction
|
||||
event: !type:BloodCultBloodRechargeActionEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultSpear
|
||||
parent: BaseAction
|
||||
name: "[color=red]Blood spear[/color]"
|
||||
description: "An ability that allows you to summon a blood spear."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "spear" }
|
||||
useDelay: 5
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultBloodSpearActionEvent
|
||||
|
||||
- type: entity
|
||||
id: RecallBloodCultSpear
|
||||
parent: BaseAction
|
||||
name: "[color=red]Recall spear[/color]"
|
||||
description: "Returns the spear to his hands if it is nearby."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "recall_spear" }
|
||||
useDelay: 5
|
||||
- type: InstantAction
|
||||
event: !type:RecallBloodSpearEvent
|
||||
|
||||
- type: entity
|
||||
id: ActionBloodCultBoltBarrage
|
||||
parent: BaseAction
|
||||
name: "[color=red]Blood barrage[/color]"
|
||||
description: ""
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "barrage" }
|
||||
useDelay: 5
|
||||
- type: InstantAction
|
||||
event: !type:BloodCultBloodBoltBarrageActionEvent
|
||||
|
||||
# Construct
|
||||
- type: entity
|
||||
id: TeleportConstructSpell
|
||||
parent: BaseAction
|
||||
name: Disembodied
|
||||
description: "An ability that allows you to descri pass through the visible and invisible."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
useDelay: 20
|
||||
itemIconStyle: BigAction
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "wraith_teleport" }
|
||||
- type: TargetAction
|
||||
range: 100
|
||||
- type: WorldTargetAction
|
||||
event: !type:TeleportSpellEvent
|
||||
|
||||
- type: entity
|
||||
id: WallBuildConstructSpell
|
||||
parent: BaseAction
|
||||
name: Build wall
|
||||
description: "Build a wall."
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: Structures/Walls/cult.rsi, state: "full" }
|
||||
itemIconStyle: BigAction
|
||||
useDelay: 60
|
||||
- type: TargetAction
|
||||
checkCanAccess: false
|
||||
range: 3
|
||||
- type: WorldTargetAction
|
||||
event: !type:WorldSpawnSpellEvent
|
||||
prototypes:
|
||||
- id: WallCult
|
||||
amount: 1
|
||||
|
||||
- type: entity
|
||||
id: ConstructBuildConstructSpell
|
||||
parent: BaseAction
|
||||
name: Build construct
|
||||
description: "Build a construct."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Structures/Specific/bloodcult_structures.rsi, state: "construct-cult" }
|
||||
itemIconStyle: BigAction
|
||||
useDelay: 180
|
||||
- type: TargetAction
|
||||
range: 3
|
||||
- type: WorldTargetAction
|
||||
event: !type:WorldSpawnSpellEvent
|
||||
prototypes:
|
||||
- id: BloodCultConstruct
|
||||
amount: 1
|
||||
|
||||
- type: entity
|
||||
id: SoulStoneConstructSpell
|
||||
parent: BaseAction
|
||||
name: Create soul stone
|
||||
description: "Summons an empty soul stone."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Objects/Specific/BloodCult/stone.rsi, state: "stone" }
|
||||
itemIconStyle: BigAction
|
||||
useDelay: 300
|
||||
- type: TargetAction
|
||||
range: 3
|
||||
- type: WorldTargetAction
|
||||
event: !type:WorldSpawnSpellEvent
|
||||
prototypes:
|
||||
- id: BloodCultSoulStone
|
||||
amount: 1
|
||||
|
||||
- type: entity
|
||||
id: CloneConstructSpell
|
||||
parent: BaseAction
|
||||
name: Summoning harvester
|
||||
description: "Summons your exact copy."
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: _Wega/Interface/Actions/actions_bloodcult.rsi, state: "harvester_clone" }
|
||||
itemIconStyle: BigAction
|
||||
startDelay: true
|
||||
useDelay: 60
|
||||
- type: TargetAction
|
||||
range: 9
|
||||
- type: WorldTargetAction
|
||||
event: !type:WorldSpawnSpellEvent
|
||||
prototypes:
|
||||
- id: MobConstructHarvester
|
||||
amount: 1
|
||||
4
Resources/Prototypes/_Wega/Damage/containers.yml
Normal file
4
Resources/Prototypes/_Wega/Damage/containers.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- type: damageContainer
|
||||
id: Clothing
|
||||
supportedTypes:
|
||||
- Slash
|
||||
@@ -0,0 +1,26 @@
|
||||
- type: entity
|
||||
parent: ClothingBackpack
|
||||
id: ClothingBackpackBlueShield
|
||||
name: officer backpack "Blue Shield"
|
||||
description: It looks like a military development, although the coloring is unusual. A very stylish and practical backpack.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Back/Backpacks/blueshield.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingBackpack
|
||||
id: ClothingBackpackPostman
|
||||
name: postman backpack
|
||||
description: "The postman's backpack is designed in deep blue, and its durable fabric can withstand any weather."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Back/Backpacks/postman.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingBackpack
|
||||
id: ClothingBackpackBloodCult
|
||||
name: trophy rack
|
||||
description: A special backpack for storing trophies.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Back/Backpacks/bloodcultbackpack.rsi
|
||||
17
Resources/Prototypes/_Wega/Entities/Clothing/Back/duffel.yml
Normal file
17
Resources/Prototypes/_Wega/Entities/Clothing/Back/duffel.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
- type: entity
|
||||
parent: ClothingBackpackDuffel
|
||||
id: ClothingBackpackDuffelBlueShield
|
||||
name: officer duffel bag "Blue Shield"
|
||||
description: It looks like a military development, although the coloring is unusual. A very stylish and practical duffel bag. It does not hinder movements, despite its size.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Back/Duffels/blueshield.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingBackpackDuffel
|
||||
id: ClothingDuffelPostman
|
||||
name: postman duffel bag
|
||||
description: "A large canvas bag keeps all your parcels safe on the road."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Back/Duffels/postman.rsi
|
||||
@@ -0,0 +1,17 @@
|
||||
- type: entity
|
||||
parent: ClothingBackpackSatchel
|
||||
id: ClothingBackpackSatchelBlueShield
|
||||
name: officer satchel "Blue Shield"
|
||||
description: It looks like a military development, although the coloring is unusual. A very stylish and practical bag.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Back/Satchels/blueshield.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingBackpackSatchel
|
||||
id: ClothingBackpackSatchelPostman
|
||||
name: postman satchel
|
||||
description: "The night sky-colored shoulder bag is made of durable canvas for everyday use."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Back/Satchels/postman.rsi
|
||||
@@ -0,0 +1,27 @@
|
||||
- type: entity
|
||||
parent: ClothingHandsButcherable
|
||||
id: ClothingHandsGlovesLatexSurgeon
|
||||
name: latex gloves
|
||||
description: Thin sterile latex gloves. Basic PPE for any doctor.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Hands/Gloves/latex_surgeon.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Hands/Gloves/latex_surgeon.rsi
|
||||
- type: DiseaseProtection # Corvax-Wega-Disease
|
||||
protection: 0.1 # Corvax-Wega-Disease
|
||||
- type: Fiber
|
||||
fiberMaterial: fibers-latex
|
||||
- type: FingerprintMask
|
||||
- type: ClothingSterility # Corvax-Wega-Surgery
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsGlovesCombat
|
||||
id: ClothingHandsGlovesCombatBlueShield
|
||||
name: purple combat gloves
|
||||
description: These tactical gloves are fireproof and impact resistant. Unlike simple combat gloves, they have a purple hue.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Hands/Gloves/combatblueshield.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Hands/Gloves/combatblueshield.rsi
|
||||
@@ -0,0 +1,44 @@
|
||||
- type: entity
|
||||
abstract: true
|
||||
id: ClothingHeadDamageableBase
|
||||
components:
|
||||
- type: TearableClothing
|
||||
- type: Damageable
|
||||
damageContainer: Clothing
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 17 # 1 saber strikes
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: TearClothing
|
||||
- !type:EmptyContainersBehaviour
|
||||
containers:
|
||||
- storagebase
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
MaterialCloth1:
|
||||
min: 1
|
||||
max: 1
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
id: ClothingHeadBaseBeret
|
||||
parent: ClothingHeadBase
|
||||
components:
|
||||
- type: Dirtable
|
||||
dirtState: beret
|
||||
equippedDirtState: equipped-beret
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
id: ClothingHeadBaseSurgcap
|
||||
parent: ClothingHeadBase
|
||||
components:
|
||||
- type: Dirtable
|
||||
dirtState: surgcap
|
||||
equippedDirtState: equipped-surgcap
|
||||
10
Resources/Prototypes/_Wega/Entities/Clothing/Head/hats.yml
Normal file
10
Resources/Prototypes/_Wega/Entities/Clothing/Head/hats.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
- type: entity
|
||||
parent: ClothingHeadBaseBeret
|
||||
id: ClothingHeadHatBeretBlueShield
|
||||
name: officer beret "Blue Shield"
|
||||
description: The gold embroidery of the shield is visible on the beret and looks solid. It is given to the best bodyguards of the best as a sign of distinctive qualities.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Head/Hats/beret_blueshield.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Head/Hats/beret_blueshield.rsi
|
||||
32
Resources/Prototypes/_Wega/Entities/Clothing/Head/hoods.yml
Normal file
32
Resources/Prototypes/_Wega/Entities/Clothing/Head/hoods.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
- type: entity
|
||||
parent: ClothingHeadHatHoodWinterBase
|
||||
id: ClothingHeadHatHoodWinterBlueShield
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: blue shield winter coat hood
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Head/Hoods/Coat/hoodblueshield.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Head/Hoods/Coat/hoodblueshield.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadHatHoodWinterBase
|
||||
id: ClothingHeadHatHoodPostman
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: postman coat hood
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Head/Hoods/Coat/postmanhood.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Head/Hoods/Coat/postmanhood.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadHatHoodWinterBase
|
||||
id: ClothingHeadHatHoodCultrobesAlt
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: hood cult
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Head/Hoods/Coat/cult_hoodalt.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Head/Hoods/Coat/cult_hoodalt.rsi
|
||||
15
Resources/Prototypes/_Wega/Entities/Clothing/Head/soft.yml
Normal file
15
Resources/Prototypes/_Wega/Entities/Clothing/Head/soft.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
- type: entity
|
||||
parent: ClothingHeadHeadHatBaseFlippable
|
||||
id: ClothingHeadHatPostmansoft
|
||||
name: postman cap
|
||||
description: A classic cap with a thickened visor, the main element of the uniform style.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Head/Soft/postmansoft.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Head/Soft/postmansoft.rsi
|
||||
|
||||
- type: entity
|
||||
parent: [ClothingHeadHeadHatBaseFlipped, ClothingHeadHatPostmansoft]
|
||||
id: ClothingHeadHatPostmansoftFlipped
|
||||
name: postman cap
|
||||
@@ -0,0 +1,23 @@
|
||||
- type: entity
|
||||
parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing]
|
||||
id: ClothingOuterArmorBlueShield
|
||||
name: officer bulletproof "Blue Shield"
|
||||
description: A standard armored breastplate that provides protection and at the same time a certain mobility. The blue and white Blue Shield emblem is on the chest.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/OuterClothing/Armor/blueshield.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/OuterClothing/Armor/blueshield.rsi
|
||||
- type: Armor
|
||||
modifiers:
|
||||
coefficients:
|
||||
Blunt: 0.5
|
||||
Slash: 0.5
|
||||
Piercing: 0.6
|
||||
Heat: 0.5
|
||||
- type: ExplosionResistance
|
||||
damageCoefficient: 0.65
|
||||
- type: ClothingSpeedModifier
|
||||
walkModifier: 1.0
|
||||
sprintModifier: 1.0
|
||||
- type: HeldSpeedModifier
|
||||
@@ -0,0 +1,34 @@
|
||||
- type: entity
|
||||
parent: ClothingOuterStorageBase
|
||||
id: ClothingOuterCoatPostman
|
||||
name: postman coat
|
||||
description: "A short, windproof coat that provides reliable protection from the elements."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/OuterClothing/Coats/postman.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/OuterClothing/Coats/postman.rsi
|
||||
- type: ToggleableClothing
|
||||
clothingPrototype: ClothingHeadHatHoodPostman
|
||||
|
||||
- type: entity
|
||||
parent: ClothingOuterStorageBase
|
||||
id: ClothingOuterCultRobesAlt
|
||||
name: cult robe
|
||||
description: "A set of robes worn by followers of the blood cult. Put on your hood and remove your ID card to hide your identity."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/OuterClothing/Coats/cultrobesalt.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/OuterClothing/Coats/cultrobesalt.rsi
|
||||
- type: ToggleableClothing
|
||||
clothingPrototype: ClothingHeadHatHoodCultrobesAlt
|
||||
- type: Armor
|
||||
modifiers:
|
||||
coefficients:
|
||||
Blunt: 0.7
|
||||
Slash: 0.7
|
||||
Piercing: 0.7
|
||||
Heat: 0.8
|
||||
- type: ExplosionResistance
|
||||
damageCoefficient: 0.9
|
||||
@@ -0,0 +1,22 @@
|
||||
- type: entity
|
||||
parent: [AllowSuitStorageClothing, ClothingOuterWinterCoatToggleable]
|
||||
id: ClothingOuterWinterBlueShield
|
||||
name: officer "Blue Shield" armored winter coat
|
||||
description: Insulated armor winter coat with a minimalistic design made of durable material.
|
||||
components:
|
||||
- type: Armor
|
||||
modifiers:
|
||||
coefficients:
|
||||
Blunt: 0.6
|
||||
Slash: 0.6
|
||||
Piercing: 0.6
|
||||
Heat: 0.6
|
||||
Caustic: 0.75
|
||||
- type: ExplosionResistance
|
||||
damageCoefficient: 0.9
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/OuterClothing/WinterCoats/blueshield.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/OuterClothing/WinterCoats/blueshield.rsi
|
||||
- type: ToggleableClothing
|
||||
clothingPrototype: ClothingHeadHatHoodWinterBlueShield
|
||||
@@ -0,0 +1,8 @@
|
||||
- type: entity
|
||||
parent: ClothingShoesBootsJack
|
||||
id: ClothingShoesBootsJackBlue
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Shoes/Boots/jackboots_blue.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Shoes/Boots/jackboots_blue.rsi
|
||||
@@ -0,0 +1,42 @@
|
||||
- type: entity
|
||||
abstract: true
|
||||
id: ClothingUniformDamageableBase
|
||||
components:
|
||||
- type: TearableClothing
|
||||
- type: Damageable
|
||||
damageContainer: Clothing
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 51 # 3 saber strikes
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: TearClothing
|
||||
- !type:EmptyContainersBehaviour
|
||||
containers:
|
||||
- storagebase
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
MaterialCloth1:
|
||||
min: 3
|
||||
max: 3
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformToggleableBase
|
||||
components:
|
||||
- type: ToggleableSpriteClothing
|
||||
defaultSuffix: "-down"
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: ClothingUniformSkirtBase
|
||||
id: ClothingUniformSkirtToggleableBase
|
||||
components:
|
||||
- type: ToggleableSpriteClothing
|
||||
defaultSuffix: "-down"
|
||||
@@ -0,0 +1,35 @@
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtSurgeon
|
||||
name: surgeon skirt
|
||||
description: "Is there bloodstains on it..?"
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpskirt/surgeon.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpskirt/surgeon.rsi
|
||||
- type: DiseaseProtection
|
||||
protection: 0.1
|
||||
- type: ClothingSterility
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpskirtBlueShield
|
||||
name: blue shield officer's jumpsuit skirt
|
||||
description: The purple uniform of the officer "Blue Shield" is made of dense materials.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpskirt/blueshield.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpskirt/blueshield.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformSkirtToggleableBase
|
||||
id: ClothingUniformJumpskirtPostman
|
||||
name: postman jumpsuit skirt
|
||||
description: "A practical jumpsuit skirt, perfect for quick gathering and active work."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpskirt/postman.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpskirt/postman.rsi
|
||||
@@ -0,0 +1,46 @@
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitSurgeon
|
||||
name: surgeon suit
|
||||
description: "Is there bloodstains on it..?"
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpsuit/surgeon.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpsuit/surgeon.rsi
|
||||
- type: DiseaseProtection
|
||||
protection: 0.1
|
||||
- type: ClothingSterility
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitBlueShield
|
||||
name: blue shield officer's jumpsuit
|
||||
description: The purple uniform of the officer "Blue Shield" is made of dense materials.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpsuit/blueshield.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpsuit/blueshield.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformBase
|
||||
id: ClothingUniformJumpsuitAltBlueShield
|
||||
name: officer turtleneck "Blue Shield"
|
||||
description: Dark turtleneck made of dense materials.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpsuit/alt_blueshield.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpsuit/alt_blueshield.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingUniformToggleableBase
|
||||
id: ClothingUniformJumpsuitPostman
|
||||
name: postman jumpsuit
|
||||
description: "A comfortable, loose-fitting jumpsuit that allows for easy movement during long walks."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpsuit/postman.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Clothing/Uniforms/Jumpsuit/postman.rsi
|
||||
143
Resources/Prototypes/_Wega/Entities/Effects/bloodcult.yml
Normal file
143
Resources/Prototypes/_Wega/Entities/Effects/bloodcult.yml
Normal file
@@ -0,0 +1,143 @@
|
||||
- type: entity
|
||||
id: BloodCultFloorGlowEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Effects/floorglow.rsi
|
||||
state: floorglow
|
||||
- type: TimedDespawn
|
||||
lifetime: 0.5
|
||||
|
||||
- type: entity
|
||||
id: BloodCultOrb
|
||||
parent: BaseItem
|
||||
name: blood orb
|
||||
description: ""
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Effects/bloodorb.rsi
|
||||
state: blood_orb
|
||||
- type: BloodOrb
|
||||
|
||||
- type: entity
|
||||
id: BloodCultOutEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Effects/bloodcultteleport.rsi
|
||||
state: cultout
|
||||
- type: TimedDespawn
|
||||
lifetime: 1.2
|
||||
|
||||
- type: entity
|
||||
id: BloodCultInEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Effects/bloodcultteleport.rsi
|
||||
state: cultin
|
||||
- type: TimedDespawn
|
||||
lifetime: 1.2
|
||||
|
||||
- type: entity
|
||||
id: BaseBloodCultRuneEffect
|
||||
abstract: true
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures.rsi
|
||||
- type: Appearance
|
||||
appearanceDataInit:
|
||||
enum.RuneColorVisuals.Color:
|
||||
!type:String
|
||||
"#ff0000"
|
||||
- type: BloodRune
|
||||
prototype: default
|
||||
- type: TimedDespawn
|
||||
lifetime: 4.0
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneOfferingEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
state: offering_anim
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneTeleportEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
state: teleport_anim
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneEmpoweringEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
state: empowering_anim
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneReviveEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
state: revive_anim
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneBarrierEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
state: barrier_anim
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneSummoningEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
state: summoning_anim
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneBloodBoilEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
state: bloodboil_anim
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneSpiritealmEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
state: spiritrealm_anim
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneRitualDimensionalRendingEffect
|
||||
parent: BaseBloodCultRuneEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures_large.rsi
|
||||
state: rune_large_anim
|
||||
- type: TimedDespawn
|
||||
lifetime: 9.75
|
||||
|
||||
- type: entity
|
||||
id: BloodCultDistortedEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures_large.rsi
|
||||
state: rune_large_distorted
|
||||
color: "#800000"
|
||||
- type: TimedDespawn
|
||||
lifetime: 1.0
|
||||
531
Resources/Prototypes/_Wega/Entities/Mobs/Player/bloodcult.yml
Normal file
531
Resources/Prototypes/_Wega/Entities/Mobs/Player/bloodcult.yml
Normal file
@@ -0,0 +1,531 @@
|
||||
- type: entity
|
||||
id: MobObserverIfrit
|
||||
parent:
|
||||
- Incorporeal
|
||||
- BaseMob
|
||||
name: ifrit
|
||||
description: "???"
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Mobs/Demons/bloodcultmobs.rsi
|
||||
state: ifrit
|
||||
- type: ContentEye
|
||||
maxZoom: 1.44,1.44
|
||||
- type: Eye
|
||||
drawFov: false
|
||||
- type: Input
|
||||
context: "ghost"
|
||||
- type: Examiner
|
||||
skipChecks: true
|
||||
- type: Ghost
|
||||
- type: Spectral
|
||||
|
||||
- type: entity
|
||||
id: MobBanshee
|
||||
parent:
|
||||
- Incorporeal
|
||||
- BaseMob
|
||||
name: banshee
|
||||
description: A spooky ghostie.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Mobs/Demons/bloodcultmobs.rsi
|
||||
state: banshee
|
||||
- type: GhostRole
|
||||
allowMovement: true
|
||||
allowSpeech: true
|
||||
makeSentient: true
|
||||
name: ghost-role-information-banshee-name
|
||||
description: ghost-role-information-banshee-description
|
||||
rules: ghost-role-information-familiar-rules
|
||||
raffle:
|
||||
settings: default
|
||||
- type: GhostTakeoverAvailable
|
||||
- type: Damageable
|
||||
damageContainer: ManifestedSpirit
|
||||
damageModifierSet: ManifestedSpirit
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 5
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/demon_dies.ogg
|
||||
- type: NoSlip
|
||||
- type: ContentEye
|
||||
maxZoom: 1.2, 1.2
|
||||
- type: CombatMode
|
||||
- type: MeleeWeapon
|
||||
altDisarm: false
|
||||
hidden: true
|
||||
animation: WeaponArcSlash
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
attackRate: 0.90
|
||||
damage:
|
||||
types:
|
||||
Blunt: 2.5
|
||||
Slash: 5
|
||||
- type: Input
|
||||
context: "ghost"
|
||||
- type: ShowCultistIcons
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 5
|
||||
baseSprintSpeed: 5
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
id: SimpleMobConstruct
|
||||
parent: SimpleSpaceMobBase
|
||||
components:
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.StrippingUiKey.Key:
|
||||
type: StrippableBoundUserInterface
|
||||
- type: Physics
|
||||
bodyType: KinematicController
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.40
|
||||
density: 100
|
||||
mask:
|
||||
- FlyingMobMask
|
||||
layer:
|
||||
- FlyingMobLayer
|
||||
- type: MovementAlwaysTouching
|
||||
- type: TemperatureProtection
|
||||
heatingCoefficient: 0.001
|
||||
coolingCoefficient: 0.001
|
||||
- type: FlashImmunity
|
||||
- type: PressureImmunity
|
||||
- type: ZombieImmune
|
||||
- type: Puller
|
||||
needsHands: false
|
||||
- type: Prying
|
||||
pryPowered: true
|
||||
force: true
|
||||
speedModifier: 1.5
|
||||
useSound:
|
||||
path: /Audio/Items/crowbar.ogg
|
||||
- type: CombatMode
|
||||
- type: Hands
|
||||
showInHands: false
|
||||
- type: NoSlip
|
||||
- type: HTN
|
||||
rootTask:
|
||||
task: SimpleHostileCompound
|
||||
blackboard:
|
||||
NavClimb: !type:Bool
|
||||
true
|
||||
NavInteract: !type:Bool
|
||||
true
|
||||
NavPry: !type:Bool
|
||||
true
|
||||
NavSmash: !type:Bool
|
||||
true
|
||||
- type: TypingIndicator
|
||||
proto: guardian
|
||||
- type: PointLight
|
||||
color: red
|
||||
radius: 3
|
||||
softness: 1
|
||||
autoRot: true
|
||||
- type: GhostTakeoverAvailable
|
||||
- type: GhostRole
|
||||
allowMovement: true
|
||||
allowSpeech: true
|
||||
makeSentient: true
|
||||
rules: ghost-role-information-construct-rules
|
||||
- type: Speech
|
||||
- type: Bloodstream
|
||||
bloodReferenceSolution:
|
||||
reagents:
|
||||
- ReagentId: Blood
|
||||
Quantity: 75
|
||||
bloodlossDamage:
|
||||
types:
|
||||
Bloodloss:
|
||||
0.1
|
||||
bloodlossHealDamage:
|
||||
types:
|
||||
Bloodloss:
|
||||
-1
|
||||
- type: NpcFactionMember
|
||||
factions:
|
||||
- BloodCult
|
||||
- type: ShowCultistIcons
|
||||
- type: BloodCultConstruct
|
||||
- type: Barotrauma
|
||||
damage:
|
||||
types:
|
||||
Blunt: 0
|
||||
- type: Metabolizer
|
||||
solutionOnBody: false
|
||||
metabolizerTypes: [ Bloodsucker ]
|
||||
groups:
|
||||
- id: Medicine
|
||||
- id: Poison
|
||||
- type: Tag
|
||||
tags:
|
||||
- DoorBumpOpener
|
||||
- CannotSuicide
|
||||
|
||||
- type: entity
|
||||
parent: SimpleMobConstruct
|
||||
id: MobConstructJuggernaut
|
||||
name: juggernaut
|
||||
description: A terrifying, unholy creature, the product of the devil himself!
|
||||
components:
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
250: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
130: 0.8
|
||||
170: 0.7
|
||||
220: 0.5
|
||||
- type: Stamina
|
||||
baseCritThreshold: 300
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 2.4
|
||||
baseSprintSpeed : 3.8
|
||||
- type: Reflect
|
||||
reflectProb: 0.4
|
||||
spread: 90
|
||||
reflects:
|
||||
- Energy
|
||||
- type: Sprite
|
||||
sprite: _Wega/Mobs/Demons/bloodcultmobs.rsi
|
||||
noRot: true
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: juggernaut
|
||||
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
state: glow_juggernaut_cult
|
||||
shader: unshaded
|
||||
- type: GhostRole
|
||||
name: ghost-role-information-juggernaut-name
|
||||
description: ghost-role-information-juggernaut-description
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 250
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/demon_dies.ogg
|
||||
- !type:ExplodeBehavior
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
Ash:
|
||||
min: 1
|
||||
max: 4
|
||||
- type: Tool
|
||||
speedModifier: 1.5
|
||||
qualities:
|
||||
- Prying
|
||||
useSound:
|
||||
path: /Audio/Items/crowbar.ogg
|
||||
- type: MeleeWeapon
|
||||
altDisarm: false
|
||||
hidden: true
|
||||
angle: 30
|
||||
animation: WeaponArcBite
|
||||
soundHit:
|
||||
path: /Audio/Weapons/block_metal1.ogg
|
||||
attackRate: 0.70
|
||||
damage:
|
||||
types:
|
||||
Blunt: 25
|
||||
Structural: 60
|
||||
|
||||
- type: entity
|
||||
parent: SimpleMobConstruct
|
||||
id: MobConstructWraith
|
||||
name: wraith
|
||||
components:
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- TeleportConstructSpell
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
100: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
70: 0.8
|
||||
85: 0.5
|
||||
- type: Stamina
|
||||
baseCritThreshold: 150
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 3.5
|
||||
baseSprintSpeed : 4.9
|
||||
- type: Sprite
|
||||
sprite: _Wega/Mobs/Demons/bloodcultmobs.rsi
|
||||
noRot: true
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: wraith
|
||||
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
state: glow_wraith_cult
|
||||
shader: unshaded
|
||||
- type: GhostRole
|
||||
name: ghost-role-information-wraith-name
|
||||
description: ghost-role-information-wraith-description
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 100
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/demon_dies.ogg
|
||||
- !type:ExplodeBehavior
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
Ash:
|
||||
min: 1
|
||||
max: 2
|
||||
- type: MeleeWeapon
|
||||
altDisarm: false
|
||||
hidden: true
|
||||
animation: WeaponArcSlash
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
attackRate: 0.90
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
Piercing: 6
|
||||
Slash: 10
|
||||
|
||||
- type: entity
|
||||
parent: SimpleMobConstruct
|
||||
id: MobConstructArtificer
|
||||
name: artificer
|
||||
components:
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- WallBuildConstructSpell
|
||||
- ConstructBuildConstructSpell
|
||||
- SoulStoneConstructSpell
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
50: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
40: 0.8
|
||||
- type: Stamina
|
||||
baseCritThreshold: 80
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 3.5
|
||||
baseSprintSpeed : 4.5
|
||||
- type: Sprite
|
||||
sprite: _Wega/Mobs/Demons/bloodcultmobs.rsi
|
||||
noRot: true
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: artificer
|
||||
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
state: glow_artificer_cult
|
||||
shader: unshaded
|
||||
- type: GhostRole
|
||||
name: ghost-role-information-artificer-name
|
||||
description: ghost-role-information-artificer-description
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 50
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/demon_dies.ogg
|
||||
- !type:ExplodeBehavior
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
Ash:
|
||||
min: 1
|
||||
max: 1
|
||||
- type: Tool
|
||||
speedModifier: 1.5
|
||||
qualities:
|
||||
- Prying
|
||||
useSound:
|
||||
path: /Audio/Items/crowbar.ogg
|
||||
- type: MeleeWeapon
|
||||
altDisarm: false
|
||||
hidden: true
|
||||
animation: WeaponArcBite
|
||||
soundHit:
|
||||
path: /Audio/Weapons/genhit3.ogg
|
||||
attackRate: 0.75
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
Piercing: 5
|
||||
Structural: 25
|
||||
|
||||
- type: entity
|
||||
parent: SimpleMobConstruct
|
||||
id: MobConstructHarvester
|
||||
name: harvester
|
||||
components:
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- WallBuildConstructSpell
|
||||
- CloneConstructSpell
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
150: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
100: 0.9
|
||||
130: 0.7
|
||||
- type: Stamina
|
||||
baseCritThreshold: 300
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 3.5
|
||||
baseSprintSpeed : 4.8
|
||||
- type: Sprite
|
||||
sprite: _Wega/Mobs/Demons/bloodcultmobs.rsi
|
||||
noRot: true
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: harvester
|
||||
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
state: glow_harvester_cult
|
||||
shader: unshaded
|
||||
- type: GhostRole
|
||||
name: ghost-role-information-harvester-name
|
||||
description: ghost-role-information-harvester-description
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 150
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/demon_dies.ogg
|
||||
- !type:ExplodeBehavior
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
Ash:
|
||||
min: 1
|
||||
max: 3
|
||||
- type: Tool
|
||||
speedModifier: 1.5
|
||||
qualities:
|
||||
- Prying
|
||||
useSound:
|
||||
path: /Audio/Items/crowbar.ogg
|
||||
- type: MeleeWeapon
|
||||
altDisarm: false
|
||||
hidden: true
|
||||
animation: WeaponArcSlash
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
attackRate: 0.80
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
Piercing: 10
|
||||
Slash: 10
|
||||
- type: StaminaDamageOnHit
|
||||
damage: 40
|
||||
|
||||
- type: entity
|
||||
parent: SimpleMobConstruct
|
||||
id: MobConstructProteon
|
||||
name: proteon
|
||||
components:
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
100: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
70: 0.8
|
||||
85: 0.5
|
||||
- type: Stamina
|
||||
baseCritThreshold: 100
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 3.5
|
||||
baseSprintSpeed : 4.6
|
||||
- type: Sprite
|
||||
sprite: _Wega/Mobs/Demons/bloodcultmobs.rsi
|
||||
noRot: true
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: proteon
|
||||
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
state: glow_proteon_cult
|
||||
shader: unshaded
|
||||
- type: GhostRole
|
||||
name: ghost-role-information-proteon-name
|
||||
description: ghost-role-information-proteon-description
|
||||
- type: HTN
|
||||
rootTask:
|
||||
task: SimpleRangedHostileCompound
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 100
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/demon_dies.ogg
|
||||
- !type:ExplodeBehavior
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
Ash:
|
||||
min: 1
|
||||
max: 1
|
||||
- type: MeleeWeapon
|
||||
altDisarm: false
|
||||
hidden: true
|
||||
animation: WeaponArcSlash
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
attackRate: 0.90
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
Slash: 10
|
||||
- type: RechargeBasicEntityAmmo
|
||||
rechargeCooldown: 0.5
|
||||
- type: BasicEntityAmmoProvider
|
||||
proto: ProjectileBloodBolt
|
||||
capacity: 1
|
||||
count: 1
|
||||
- type: Gun
|
||||
fireRate: 0.5
|
||||
useKey: false
|
||||
selectedMode: FullAuto
|
||||
availableModes:
|
||||
- FullAuto
|
||||
soundGunshot: /Audio/Weapons/Guns/Gunshots/Magic/staff_animation.ogg
|
||||
@@ -0,0 +1,35 @@
|
||||
- type: entity
|
||||
parent: SheetOtherBase
|
||||
id: SheetRuneMetal
|
||||
name: runemetal
|
||||
suffix: Full, DO NOT MAPP
|
||||
components:
|
||||
- type: Material
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
RuneMetal: 100
|
||||
- type: Stack
|
||||
stackType: RuneMetal
|
||||
baseLayer: base
|
||||
layerStates:
|
||||
- runemetal
|
||||
- runemetal_2
|
||||
- runemetal_3
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Materials/Sheets/metal.rsi
|
||||
state: runemetal_3
|
||||
layers:
|
||||
- state: runemetal_3
|
||||
map: ["base"]
|
||||
- type: Appearance
|
||||
- type: Item
|
||||
heldPrefix: runemetal
|
||||
|
||||
- type: entity
|
||||
parent: SheetRuneMetal
|
||||
id: SheetRuneMetal1
|
||||
name: runemetal
|
||||
suffix: Single, DO NOT MAPP
|
||||
components:
|
||||
- type: Stack
|
||||
count: 1
|
||||
@@ -0,0 +1,54 @@
|
||||
- type: entity
|
||||
id: BloodCultSoulStone
|
||||
parent: BaseItem
|
||||
name: soul stone
|
||||
description: A shiny red stone with a mysterious aura.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Specific/BloodCult/stone.rsi
|
||||
layers:
|
||||
- state: stone_soul
|
||||
map: ["enum.StoneSoulVisualLayers.Soul"]
|
||||
visible: false
|
||||
- state: stone
|
||||
map: ["enum.StoneSoulVisualLayers.Base"]
|
||||
- type: MindContainer
|
||||
- type: BlockMovement
|
||||
- type: GhostRole
|
||||
allowMovement: false
|
||||
allowSpeech: false
|
||||
name: ghost-role-information-soul-stone-name
|
||||
description: ghost-role-information-soul-stone-description
|
||||
rules: ghost-role-information-familiar-rules
|
||||
raffle:
|
||||
settings: default
|
||||
- type: GhostTakeoverAvailable
|
||||
- type: Appearance
|
||||
- type: StoneSoul
|
||||
soulProto: MobBanshee
|
||||
- type: Tag
|
||||
tags:
|
||||
- CannotSuicide
|
||||
- SoulStone
|
||||
|
||||
- type: entity
|
||||
id: BloodCultShuttleCurse
|
||||
parent: BaseItem
|
||||
name: cursed sphere
|
||||
description: It looks ominous.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Specific/BloodCult/stone.rsi
|
||||
state: shuttlecurse
|
||||
- type: BloodShuttleCurse
|
||||
|
||||
- type: entity
|
||||
id: BloodCultEldritchSharpener
|
||||
parent: BaseItem
|
||||
name: eldritch sharpener
|
||||
description: He looks extremely fragile.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Specific/BloodCult/stone.rsi
|
||||
state: sharpener
|
||||
- type: BloodSharpener
|
||||
@@ -0,0 +1,14 @@
|
||||
- type: entity
|
||||
parent: BaseBullet
|
||||
id: ProjectileBloodBolt
|
||||
name: ""
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Guns/Projectiles/magic.rsi
|
||||
layers:
|
||||
- state: blood_bolt
|
||||
- type: Projectile
|
||||
damage:
|
||||
types:
|
||||
Blunt: 15
|
||||
@@ -0,0 +1,81 @@
|
||||
- type: entity
|
||||
name: combat crowbar
|
||||
parent: [BaseKnife, BaseRestrictedContraband]
|
||||
id: CombatCrowbar
|
||||
description: A deadly knife designed for close combat. Thanks to the improved handle, it also works as a crowbar.
|
||||
components:
|
||||
- type: Tag
|
||||
tags:
|
||||
- CombatKnife
|
||||
- Knife
|
||||
- Crowbar
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/combat_crowbar.rsi
|
||||
state: icon
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: -135
|
||||
attackRate: 1.5
|
||||
damage:
|
||||
types:
|
||||
Slash: 12
|
||||
- type: EmbeddableProjectile
|
||||
sound: /Audio/Weapons/star_hit.ogg
|
||||
offset: -0.15,0.0
|
||||
- type: LandAtCursor
|
||||
- type: DamageOtherOnHit
|
||||
damage:
|
||||
types:
|
||||
Slash: 10
|
||||
- type: Item
|
||||
sprite: _Wega/Objects/Weapons/Melee/combat_crowbar.rsi
|
||||
storedSprite:
|
||||
state: storage
|
||||
sprite: _Wega/Objects/Weapons/Melee/combat_crowbar.rsi
|
||||
- type: DisarmMalus
|
||||
malus: 0.225
|
||||
- type: ThrowingAngle
|
||||
angle: 225
|
||||
- type: Tool
|
||||
qualities:
|
||||
- Prying
|
||||
useSound:
|
||||
path: /Audio/Items/crowbar.ogg
|
||||
- type: Prying
|
||||
- type: ToolTileCompatible
|
||||
|
||||
- type: entity
|
||||
parent: BaseKnife
|
||||
id: ArrhythmicKnife
|
||||
name: arrhythmic knife
|
||||
description: They say that fear kills the mind, but sticking a knife in your head also works.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/arrhythmic_knife.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/arrhythmic_knife.rsi
|
||||
slots:
|
||||
- Belt
|
||||
- type: MeleeWeapon
|
||||
attackRate: 2.25
|
||||
damage:
|
||||
types:
|
||||
Slash: 15
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
- type: EmbeddableProjectile
|
||||
sound: /Audio/Weapons/star_hit.ogg
|
||||
offset: -0.15,0.0
|
||||
- type: LandAtCursor
|
||||
- type: DamageOtherOnHit
|
||||
damage:
|
||||
types:
|
||||
Slash: 15
|
||||
- type: DisarmMalus
|
||||
malus: 0.225
|
||||
- type: ThrowingAngle
|
||||
angle: 225
|
||||
- type: ClothingSpeedModifier
|
||||
walkModifier: 1.1
|
||||
sprintModifier: 1.1
|
||||
- type: HeldSpeedModifier
|
||||
@@ -40,3 +40,475 @@
|
||||
types:
|
||||
Slash: 15
|
||||
animation: WeaponArcClaw
|
||||
|
||||
# Null Rod
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: WeaponNullRod
|
||||
name: null rod
|
||||
description: "An obsidian rod that strikes paranormal things."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/nullrod.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/nullrod.rsi
|
||||
slots: [belt]
|
||||
- type: Item
|
||||
size: Normal
|
||||
- type: NullRod
|
||||
- type: ItemSelector
|
||||
requiredComponents: [ BibleUser ]
|
||||
items:
|
||||
- WeaponHandOfGod
|
||||
- Claymore
|
||||
- WeaponChainsword
|
||||
- WeaponForceSword
|
||||
- WeaponHanzoSteel
|
||||
- WeaponMultiverseSword
|
||||
- WeaponUnrealSword
|
||||
- WeaponReaperScythe
|
||||
- WeaponHighFrequencyBlade
|
||||
- WeaponPossessedBlade
|
||||
- ArrhythmicKnife
|
||||
- type: ActivatableUI
|
||||
key: enum.ItemSelectorUiKey.Key
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.ItemSelectorUiKey.Key:
|
||||
type: ItemSelectorBoundUserInterface
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
types:
|
||||
Blunt: 15
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: WeaponHandOfGod
|
||||
name: hand of god
|
||||
description: "Your hand is now glowing amazingly!"
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/magic_hand.rsi
|
||||
state: icon
|
||||
color: "#d2314e"
|
||||
- type: NullRod
|
||||
- type: Unremoveable
|
||||
- type: DeleteOnDrop
|
||||
- type: Item
|
||||
size: Ginormous
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#d2314e"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#d2314e"
|
||||
- type: MeleeWeapon
|
||||
autoAttack: true
|
||||
attackRate: 1.5
|
||||
wideAnimationRotation: 180
|
||||
damage:
|
||||
types:
|
||||
Heat: 15
|
||||
animation: WeaponArcClaw
|
||||
- type: IgniteOnMeleeHit
|
||||
fireStacks: 1
|
||||
|
||||
# Blood Cult Weapons
|
||||
- type: entity
|
||||
parent: BaseKnife
|
||||
id: WeaponBloodDagger
|
||||
name: ritual dagger
|
||||
description: An old, worn dagger.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/blood_dagger.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
slots:
|
||||
- belt
|
||||
- type: BloodDagger
|
||||
- type: Tool
|
||||
qualities:
|
||||
- Slicing
|
||||
- BloodDagger
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: -135
|
||||
attackRate: 0.75
|
||||
damage:
|
||||
types:
|
||||
Slash: 12
|
||||
|
||||
- type: entity
|
||||
parent: BaseKnife
|
||||
id: WeaponDeathDagger
|
||||
name: ritual dagger
|
||||
description: An old, worn dagger.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/death_dagger.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
slots:
|
||||
- belt
|
||||
- type: BloodDagger
|
||||
- type: Tool
|
||||
qualities:
|
||||
- Slicing
|
||||
- BloodDagger
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: -135
|
||||
attackRate: 0.75
|
||||
damage:
|
||||
types:
|
||||
Slash: 12
|
||||
|
||||
- type: entity
|
||||
parent: BaseKnife
|
||||
id: WeaponHellDagger
|
||||
name: ritual dagger
|
||||
description: An old, worn dagger.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/hell_dagger.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
slots:
|
||||
- belt
|
||||
- type: BloodDagger
|
||||
- type: Tool
|
||||
qualities:
|
||||
- Slicing
|
||||
- BloodDagger
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: -135
|
||||
attackRate: 0.75
|
||||
damage:
|
||||
types:
|
||||
Slash: 12
|
||||
|
||||
- type: entity
|
||||
id: WeaponBloodBlade
|
||||
parent: BaseItem
|
||||
name: blood blade
|
||||
description: The red formation of liquid blood in the shape of a sword is a very mysterious sight.
|
||||
components:
|
||||
- type: Sharp
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/blood_blade.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
slots:
|
||||
- back
|
||||
- suitStorage
|
||||
- type: Item
|
||||
size: Normal
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: -135
|
||||
attackRate: 0.75
|
||||
damage:
|
||||
types:
|
||||
Slash: 25
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
- type: DisarmMalus
|
||||
|
||||
- type: entity
|
||||
id: WeaponDeathBlade
|
||||
parent: BaseItem
|
||||
name: death blade
|
||||
description: A scythe-like weapon, very sharp...
|
||||
components:
|
||||
- type: Sharp
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/death_blade.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
slots:
|
||||
- back
|
||||
- suitStorage
|
||||
- type: Item
|
||||
size: Normal
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: -135
|
||||
attackRate: 0.75
|
||||
damage:
|
||||
types:
|
||||
Slash: 25
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
- type: DisarmMalus
|
||||
|
||||
- type: entity
|
||||
id: WeaponHellBlade
|
||||
parent: BaseItem
|
||||
name: hell blade
|
||||
description: A blazing axe of agony, straight from the underworld.
|
||||
components:
|
||||
- type: Sharp
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/hell_blade.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
slots:
|
||||
- back
|
||||
- suitStorage
|
||||
- type: Item
|
||||
size: Normal
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: -135
|
||||
attackRate: 0.75
|
||||
damage:
|
||||
types:
|
||||
Slash: 25
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
- type: DisarmMalus
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: BloodCultSpear
|
||||
name: blood spear
|
||||
description: The spear formed from blood clots looks quite fragile.
|
||||
components:
|
||||
- type: ThrowingAngle
|
||||
angle: 225
|
||||
- type: LandAtCursor
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape: !type:PolygonShape
|
||||
vertices:
|
||||
- -0.40,-0.30
|
||||
- -0.30,-0.40
|
||||
- 0.40,0.30
|
||||
- 0.30,0.40
|
||||
density: 20
|
||||
mask:
|
||||
- ItemMask
|
||||
restitution: 0.3
|
||||
friction: 0.2
|
||||
- type: Sharp
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/blood_spear.rsi
|
||||
state: icon
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
slots:
|
||||
- back
|
||||
- suitStorage
|
||||
- type: Item
|
||||
size: Ginormous
|
||||
- type: Wieldable
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Glass
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 5
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: GlassBreak
|
||||
- !type:SpillBehavior { }
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
PuddleBlood:
|
||||
min: 1
|
||||
max: 1
|
||||
transferForensics: true
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: -135
|
||||
damage:
|
||||
types:
|
||||
Piercing: 29
|
||||
angle: 0
|
||||
animation: WeaponArcThrust
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
- type: DamageOtherOnHit
|
||||
damage:
|
||||
types:
|
||||
Piercing: 37
|
||||
- type: IncreaseDamageOnWield
|
||||
damage:
|
||||
types:
|
||||
Piercing: 4
|
||||
- type: DamageOnLand
|
||||
ignoreResistances: true
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
|
||||
# Blood Cult Spells
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: BaseBloodCultSpell
|
||||
name: blood magic
|
||||
description: Magic from the other world.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/magic_hand.rsi
|
||||
state: icon
|
||||
- type: DeleteOnDrop
|
||||
- type: EdibleMatter
|
||||
canBeEaten: false
|
||||
- type: Item
|
||||
size: Ginormous
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultSpell
|
||||
id: BloodCultSpellStun
|
||||
components:
|
||||
- type: Sprite
|
||||
color: "#e20205"
|
||||
- type: BloodSpell
|
||||
prototype:
|
||||
- stun
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#e20205"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#e20205"
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultSpell
|
||||
id: BloodCultSpellTeleport
|
||||
components:
|
||||
- type: Sprite
|
||||
color: "#4e1459"
|
||||
- type: BloodSpell
|
||||
prototype:
|
||||
- teleport
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#4e1459"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#4e1459"
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultSpell
|
||||
id: BloodCultSpellShadowShackles
|
||||
components:
|
||||
- type: Sprite
|
||||
color: "#000002"
|
||||
- type: BloodSpell
|
||||
prototype:
|
||||
- shadowshackles
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#000002"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#000002"
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultSpell
|
||||
id: BloodCultSpellTwistedConstruction
|
||||
components:
|
||||
- type: Sprite
|
||||
color: "#000002"
|
||||
- type: BloodSpell
|
||||
prototype:
|
||||
- twistedconstruction
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#000002"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#000002"
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultSpell
|
||||
id: BloodCultSpellSummonEquipment
|
||||
components:
|
||||
- type: Sprite
|
||||
color: "#448d33"
|
||||
- type: BloodSpell
|
||||
prototype:
|
||||
- summonequipment
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#448d33"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#448d33"
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultSpell
|
||||
id: BloodCultSpellBloodRites
|
||||
components:
|
||||
- type: Sprite
|
||||
color: "#6f0f13"
|
||||
- type: BloodSpell
|
||||
prototype:
|
||||
- bloodrites
|
||||
- type: UseDelay
|
||||
delay: 5
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#6f0f13"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#6f0f13"
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: BloodCultVeilShifter
|
||||
name: veil shifter
|
||||
description: A small staff emitting a strange glow.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/blood_shifter.rsi
|
||||
state: icon
|
||||
- type: VeilShifter
|
||||
- type: UseDelay
|
||||
delay: 4
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultSpell
|
||||
id: BloodCultSpellBloodBarrage
|
||||
components:
|
||||
- type: Sprite
|
||||
state: pulse
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
color: "#ff0000"
|
||||
right:
|
||||
- state: inhand-right
|
||||
color: "#ff0000"
|
||||
- type: Gun
|
||||
fireRate: 2
|
||||
soundGunshot:
|
||||
path: /Audio/Weapons/Guns/Gunshots/Magic/staff_animation.ogg
|
||||
- type: BasicEntityAmmoProvider
|
||||
proto: ProjectileBloodBolt
|
||||
capacity: 24
|
||||
count: 24
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
- type: entity
|
||||
parent: Claymore
|
||||
id: WeaponChainsword
|
||||
name: chainsword
|
||||
description: Do not allow the heretic vulpa to live.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/chainsword.rsi
|
||||
- type: MeleeWeapon
|
||||
soundHit:
|
||||
path: /Audio/Weapons/chainsaw.ogg
|
||||
params:
|
||||
volume: -3
|
||||
- type: Item
|
||||
storedSprite:
|
||||
state: icon
|
||||
sprite: _Wega/Objects/Weapons/Melee/chainsword.rsi
|
||||
shape:
|
||||
- 0,0,0,3
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/chainsword.rsi
|
||||
slots:
|
||||
- Belt
|
||||
|
||||
- type: entity
|
||||
parent: Claymore
|
||||
id: WeaponForceSword
|
||||
name: force sword
|
||||
description: It shines with the power of faith. Or the energy of a battery.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/force_sword.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/force_sword.rsi
|
||||
- type: Item
|
||||
storedSprite:
|
||||
state: icon
|
||||
sprite: _Wega/Objects/Weapons/Melee/force_sword.rsi
|
||||
|
||||
- type: entity
|
||||
parent: [ Katana, Claymore ]
|
||||
id: WeaponHanzoSteel
|
||||
name: force sword
|
||||
description: This katana can cut through a holy Claymore. Along.
|
||||
components:
|
||||
- type: Item
|
||||
storedSprite:
|
||||
state: icon
|
||||
sprite: Objects/Weapons/Melee/katana.rsi
|
||||
|
||||
- type: entity
|
||||
parent: Claymore
|
||||
id: WeaponMultiverseSword
|
||||
name: multiverse sword
|
||||
description: Once a messenger of interdimensional war, now it's just a dormant souvenir. But still sharp.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/multiverse_sword.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/multiverse_sword.rsi
|
||||
- type: Item
|
||||
storedSprite:
|
||||
state: icon
|
||||
sprite: _Wega/Objects/Weapons/Melee/multiverse_sword.rsi
|
||||
|
||||
- type: entity
|
||||
parent: BaseSword
|
||||
id: WeaponUnrealSword
|
||||
name: UNREAL SORD
|
||||
description: He is so indescribably HOLY that you will have problems just holding him.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/unreal_sword.rsi
|
||||
- type: NullRod
|
||||
firstNullDamage: 99.99
|
||||
nullDamage: 0.01
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
types:
|
||||
Asphyxiation: 0.42
|
||||
Bloodloss: 0.31
|
||||
Blunt: 0.15
|
||||
Cellular: 0.27
|
||||
Caustic: 0.33
|
||||
Cold: 0.18
|
||||
Heat: 0.22
|
||||
Piercing: 0.11
|
||||
Poison: 0.49
|
||||
Radiation: 0.25
|
||||
Shock: 0.19
|
||||
Slash: 0.14
|
||||
Structural: 0.01
|
||||
Holy: 1.07
|
||||
soundHit:
|
||||
path: /Audio/_Wega/Effects/null.ogg
|
||||
- type: PointLight
|
||||
radius: 1.2
|
||||
energy: 2.20 # ///...\\\
|
||||
castShadows: false
|
||||
color: "#0639f9"
|
||||
- type: Item
|
||||
shape:
|
||||
- 0,0,0,3
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/unreal_sword.rsi
|
||||
slots:
|
||||
- Belt
|
||||
|
||||
- type: entity
|
||||
parent: BaseSword
|
||||
id: WeaponReaperScythe
|
||||
name: reaper scythe
|
||||
description: Don't ask who the bell is tolling for...
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/reaper_scythe.rsi
|
||||
- type: NullRod
|
||||
- type: MeleeWeapon
|
||||
attackRate: 2
|
||||
damage:
|
||||
types:
|
||||
Slash: 17.5
|
||||
soundHit:
|
||||
path: /Audio/Weapons/bladeslice.ogg
|
||||
- type: Item
|
||||
shape:
|
||||
- 0,0,1,3
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/reaper_scythe.rsi
|
||||
slots:
|
||||
- Back
|
||||
- SuitStorage
|
||||
- type: DisarmMalus
|
||||
|
||||
- type: entity
|
||||
parent: WeaponReaperScythe
|
||||
id: WeaponHighFrequencyBlade
|
||||
name: high frequency blade
|
||||
description: Bad references are the DNA of the soul.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/hfrequency_sword.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/hfrequency_sword.rsi
|
||||
|
||||
- type: entity
|
||||
parent: WeaponReaperScythe
|
||||
id: WeaponPossessedBlade
|
||||
name: possessed blade
|
||||
description: When the station is in chaos, it's nice to have a friend by your side.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Melee/possessed_blade.rsi
|
||||
- type: Clothing
|
||||
sprite: _Wega/Objects/Weapons/Melee/possessed_blade.rsi
|
||||
slots:
|
||||
- Belt
|
||||
- type: GhostRole
|
||||
allowSpeech: true
|
||||
makeSentient: true
|
||||
name: ghost-role-information-possessed-blade-name
|
||||
description: ghost-role-information-possessed-blade-description
|
||||
rules: ghost-role-information-familiar-rules
|
||||
raffle:
|
||||
settings: default
|
||||
- type: GhostTakeoverAvailable
|
||||
@@ -0,0 +1,9 @@
|
||||
- type: entity
|
||||
name: bola
|
||||
parent: Bola
|
||||
id: CultBola
|
||||
description: There are some runes depicted on it.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Objects/Weapons/Throwable/cult_bola.rsi
|
||||
state: icon
|
||||
@@ -0,0 +1,404 @@
|
||||
- type: entity
|
||||
id: BaseBloodRune
|
||||
name: rune
|
||||
abstract: true
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures.rsi
|
||||
- type: Clickable
|
||||
- type: InteractionOutline
|
||||
- type: Appearance
|
||||
appearanceDataInit:
|
||||
enum.RuneColorVisuals.Color:
|
||||
!type:String
|
||||
"#ff0000"
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: UseDelay
|
||||
delay: 5
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneOffering
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
state: offering
|
||||
- type: BloodRune
|
||||
prototype: offering
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneTeleport
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
state: teleport
|
||||
- type: BloodRune
|
||||
prototype: teleport
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneEmpowering
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
state: empowering
|
||||
- type: BloodRune
|
||||
prototype: empowering
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneRevive
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
state: revive
|
||||
- type: BloodRune
|
||||
prototype: revive
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneBarrier
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
state: barrier
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
canCollide: false
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
barrier:
|
||||
shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.45
|
||||
layer:
|
||||
- WallLayer
|
||||
hard: false
|
||||
- type: Damageable
|
||||
damageContainer: StructuralInorganic
|
||||
damageModifierSet: Metallic
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 100
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: BloodRune
|
||||
prototype: barrier
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneSummoning
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
state: summoning
|
||||
- type: BloodRune
|
||||
prototype: summoning
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneBloodBoil
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
state: bloodboil
|
||||
- type: BloodRune
|
||||
prototype: bloodboil
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneSpiritealm
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
state: spiritrealm
|
||||
- type: BloodRune
|
||||
prototype: spiritrealm
|
||||
|
||||
- type: entity
|
||||
id: BloodRuneRitualDimensionalRending
|
||||
parent: BaseBloodRune
|
||||
name: rune
|
||||
description: ""
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures_large.rsi
|
||||
state: rune_large
|
||||
- type: BloodRitualDimensionalRending
|
||||
- type: NavMapBeacon
|
||||
color: "#ff0000"
|
||||
text: "???"
|
||||
enabled: true
|
||||
|
||||
- type: entity
|
||||
id: BloodCultConstruct
|
||||
parent: BaseStructure
|
||||
name: construct
|
||||
description: A strange floating structure in the air.
|
||||
suffix: DO NOT MAP
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures.rsi
|
||||
state: construct-cult
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
- type: Construct
|
||||
- type: Damageable
|
||||
damageContainer: StructuralInorganic
|
||||
damageModifierSet: StructuralMetallic
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 150
|
||||
behaviors:
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
SheetSteel10:
|
||||
min: 1
|
||||
max: 1
|
||||
- !type:EmptyContainersBehaviour
|
||||
containers:
|
||||
- item
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: MetalBreak
|
||||
- type: Anchorable
|
||||
tool: BloodDagger
|
||||
- type: InteractionOutline
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
item: !type:ContainerSlot
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
item:
|
||||
name: ""
|
||||
whitelist:
|
||||
tags:
|
||||
- SoulStone
|
||||
|
||||
- type: entity
|
||||
id: BaseBloodCultStructure
|
||||
parent: BaseStructure
|
||||
abstract: true
|
||||
components:
|
||||
- type: Anchorable
|
||||
tool: BloodDagger
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
- type: InteractionOutline
|
||||
- type: BloodStructure
|
||||
fixture: fix1
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultStructure
|
||||
id: BloodCultStructureArchives
|
||||
name: archives
|
||||
description: A desk covered with mysterious manuscripts and volumes in unknown languages. Looking at the text, goosebumps pass.
|
||||
suffix: DO NOT MAP
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures.rsi
|
||||
state: archive
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.4,-0.4,0.4,0.4"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: Appearance
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Metallic
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 200
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/break_stone.ogg
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
SheetRuneMetal1:
|
||||
min: 0
|
||||
max: 2
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: BloodStructure
|
||||
fixture: fix1
|
||||
structureGear:
|
||||
- ClothingEyesZealotBlindfold
|
||||
- BloodCultVeilShifter
|
||||
- BloodCultShuttleCurse
|
||||
- type: Construction
|
||||
graph: BloodCultStructureArchivesGraph
|
||||
node: BloodCultStructureArchives
|
||||
|
||||
- type: entity
|
||||
id: BloodCultStructureAltar
|
||||
parent: BaseBloodCultStructure
|
||||
name: altar of blood
|
||||
description: The altar of a certain goddess.
|
||||
suffix: DO NOT MAP
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures.rsi
|
||||
state: altar
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.4,-0.4,0.4,0.4"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Metallic
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 125
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/break_stone.ogg
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
SheetRuneMetal1:
|
||||
min: 0
|
||||
max: 2
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: BloodStructure
|
||||
fixture: fix1
|
||||
structureGear:
|
||||
- BloodCultEldritchSharpener
|
||||
- DrinkUnholyFlaskFull
|
||||
- BloodCultConstruct
|
||||
- type: PointLight
|
||||
radius: 1.1
|
||||
energy: 1
|
||||
color: "#f08080"
|
||||
- type: Construction
|
||||
graph: BloodCultStructureAltarGraph
|
||||
node: BloodCultStructureAltar
|
||||
|
||||
- type: entity
|
||||
parent: BaseBloodCultStructure
|
||||
id: BloodCultStructureForge
|
||||
name: forge of souls
|
||||
description: An occult forge. Not only evil is being done here, but also a lot of evil.
|
||||
suffix: DO NOT MAP
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures.rsi
|
||||
state: forge
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.4,-0.4,0.4,0.4"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: Appearance
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Metallic
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 200
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/break_stone.ogg
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
SheetRuneMetal1:
|
||||
min: 0
|
||||
max: 2
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: BloodStructure
|
||||
fixture: fix1
|
||||
sound: "/Audio/_Wega/Effects/anvil.ogg"
|
||||
structureGear:
|
||||
- ClothingOuterArmorCult
|
||||
- ClothingOuterFlagellantRobe
|
||||
- MirrorShield
|
||||
- type: Construction
|
||||
graph: BloodCultStructureForgeGraph
|
||||
node: BloodCultStructureForge
|
||||
|
||||
- type: entity
|
||||
id: BloodCultStructurePylon
|
||||
parent: BaseBloodCultStructure
|
||||
name: pylon
|
||||
description: A mysterious face is looking at you.
|
||||
suffix: DO NOT MAP
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures.rsi
|
||||
state: pylon
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
- type: BloodPylon
|
||||
- type: BloodStructure
|
||||
fixture: fix1
|
||||
canInteract: false
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Metallic
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 50
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
path: /Audio/Effects/break_stone.ogg
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
SheetRuneMetal1:
|
||||
min: 0
|
||||
max: 3
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: Construction
|
||||
graph: BloodCultStructurePylonGraph
|
||||
node: BloodCultStructurePylon
|
||||
@@ -1,3 +1,32 @@
|
||||
# Blood Cult Game Rule
|
||||
- type: entity
|
||||
parent: BaseGameRule
|
||||
id: BloodCult
|
||||
components:
|
||||
- type: GameRule
|
||||
minPlayers: 10
|
||||
- type: BloodCultRule
|
||||
- type: AntagSelection
|
||||
definitions:
|
||||
- prefRoles: [ BloodCultist ]
|
||||
max: 4
|
||||
playerRatio: 10
|
||||
blacklist:
|
||||
components:
|
||||
- AntagImmune
|
||||
- BibleUser
|
||||
- Ipc
|
||||
lateJoinAdditional: true
|
||||
components:
|
||||
- type: BloodCultist
|
||||
- type: NpcFactionMember
|
||||
factions:
|
||||
- BloodCult
|
||||
mindRoles:
|
||||
- MindRoleBloodCultist
|
||||
briefing:
|
||||
sound: "/Audio/_Wega/Ambience/Antag/bloodcult_start.ogg"
|
||||
|
||||
# Blood Brothers Game Rule
|
||||
- type: entity
|
||||
parent: BaseGameRule
|
||||
|
||||
@@ -15,6 +15,34 @@
|
||||
- AntagImmune
|
||||
- Pacified # Diona ha-ha-ha
|
||||
|
||||
# Blood Cult Sub-Gamemode
|
||||
- type: entity
|
||||
parent: BloodCult
|
||||
id: SubBloodCult
|
||||
components:
|
||||
- type: GameRule
|
||||
minPlayers: 10
|
||||
- type: AntagSelection
|
||||
definitions:
|
||||
- prefRoles: [ BloodCultist ]
|
||||
max: 3
|
||||
playerRatio: 15
|
||||
blacklist:
|
||||
components:
|
||||
- AntagImmune
|
||||
- BibleUser
|
||||
- Ipc
|
||||
lateJoinAdditional: true
|
||||
components:
|
||||
- type: BloodCultist
|
||||
- type: NpcFactionMember
|
||||
factions:
|
||||
- BloodCult
|
||||
mindRoles:
|
||||
- MindRoleBloodCultist
|
||||
briefing:
|
||||
sound: "/Audio/_Wega/Ambience/Antag/bloodcult_start.ogg"
|
||||
|
||||
# Vampire Sub-Gamemode
|
||||
- type: entity
|
||||
parent: Vampire
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
- type: entity
|
||||
id: GuidebookDistortedEffect
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _Wega/Structures/Specific/bloodcult_structures_large.rsi
|
||||
state: rune_large_distorted
|
||||
color: "#800000"
|
||||
@@ -4,6 +4,12 @@
|
||||
name: guide-entry-vampires
|
||||
text: "/ServerInfo/_Wega/Guidebook/Antagonist/Vampires.xml"
|
||||
|
||||
# Blood Cult Guidebook Entry
|
||||
- type: guideEntry
|
||||
id: BloodCult
|
||||
name: guide-entry-blood-cult
|
||||
text: "/ServerInfo/_Wega/Guidebook/Antagonist/BloodCult.xml"
|
||||
|
||||
# Blood Brothers Guidebook Entry
|
||||
- type: guideEntry
|
||||
id: BloodBrothers
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
- type: material
|
||||
id: RuneMetal
|
||||
stackEntity: SheetRuneMetal1
|
||||
name: materials-runemetal
|
||||
icon: { sprite: _Wega/Objects/Materials/Sheets/metal.rsi, state: runemetal }
|
||||
color: "#3f4857"
|
||||
price: 0.05
|
||||
@@ -0,0 +1,107 @@
|
||||
- type: constructionGraph
|
||||
id: BloodCultStructureAltarGraph
|
||||
start: start
|
||||
graph:
|
||||
- node: start
|
||||
actions:
|
||||
- !type:DestroyEntity {}
|
||||
edges:
|
||||
- to: BloodCultStructureAltar
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- material: RuneMetal
|
||||
amount: 3
|
||||
doAfter: 1
|
||||
- node: BloodCultStructureAltar
|
||||
entity: BloodCultStructureAltar
|
||||
edges:
|
||||
- to: start
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetRuneMetal1
|
||||
amount: 3
|
||||
steps:
|
||||
- tool: Screwing
|
||||
doAfter: 4
|
||||
|
||||
- type: constructionGraph
|
||||
id: BloodCultStructureArchivesGraph
|
||||
start: start
|
||||
graph:
|
||||
- node: start
|
||||
actions:
|
||||
- !type:DestroyEntity {}
|
||||
edges:
|
||||
- to: BloodCultStructureArchives
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- material: RuneMetal
|
||||
amount: 3
|
||||
doAfter: 1
|
||||
- node: BloodCultStructureArchives
|
||||
entity: BloodCultStructureArchives
|
||||
edges:
|
||||
- to: start
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetRuneMetal1
|
||||
amount: 3
|
||||
steps:
|
||||
- tool: Screwing
|
||||
doAfter: 8
|
||||
|
||||
- type: constructionGraph
|
||||
id: BloodCultStructureForgeGraph
|
||||
start: start
|
||||
graph:
|
||||
- node: start
|
||||
actions:
|
||||
- !type:DestroyEntity {}
|
||||
edges:
|
||||
- to: BloodCultStructureForge
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- material: RuneMetal
|
||||
amount: 3
|
||||
doAfter: 1
|
||||
- node: BloodCultStructureForge
|
||||
entity: BloodCultStructureForge
|
||||
edges:
|
||||
- to: start
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetRuneMetal1
|
||||
amount: 3
|
||||
steps:
|
||||
- tool: Screwing
|
||||
doAfter: 8
|
||||
|
||||
- type: constructionGraph
|
||||
id: BloodCultStructurePylonGraph
|
||||
start: start
|
||||
graph:
|
||||
- node: start
|
||||
actions:
|
||||
- !type:DestroyEntity {}
|
||||
edges:
|
||||
- to: BloodCultStructurePylon
|
||||
completed:
|
||||
- !type:SnapToGrid { }
|
||||
steps:
|
||||
- material: RuneMetal
|
||||
amount: 4
|
||||
doAfter: 1
|
||||
- node: BloodCultStructurePylon
|
||||
entity: BloodCultStructurePylon
|
||||
edges:
|
||||
- to: start
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetRuneMetal1
|
||||
amount: 4
|
||||
steps:
|
||||
- tool: Screwing
|
||||
doAfter: 8
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user