Skip to content

Commit 1500208

Browse files
RemuchiVMSolidus
andauthored
The Blood Cult (Simple-Station#1001)
<!-- This is a semi-strict format, you can add/remove sections as needed but the order/format should be kept the same Remove these comments before submitting --> # Description Adds a new game mode - The Blood Cult. Hail to Nar'Sie! --- # TODO - [x] Gamemode - [x] Roles - [x] Runes - [x] Constructs - [x] Structures - [x] Forge - [x] Archives - [x] Altar - [x] Pylon - [x] Structure - [x] Placement System - [x] Airlocks - [x] Repulsor system - [x] Construction system - [x] Items - [x] Eldritch Whetstone - [x] Construct Shell - [x] Mirror Shield - [x] True Nar'sian Hardened Armor - [x] Flagellant's Robe - [x] Eldritch Longsword - [x] Zealot's Blindfold - [ ] Night vision system - [x] Shuttle Curse - [x] Veil Shifter - [x] Void Torch - [x] Reagents - [x] Holy Water - [ ] Actions - [x] Cult Magic - [x] Stun - [x] Teleport - [x] Electromagnetic Pulse - [x] Shadow Shackles - [x] Twisted Construction - [x] Summon Combat Equipment - [x] Summon Ritual Dagger - [x] Blood Rites - [ ] Cult Leader Magic - [ ] Final Reckoning - [ ] Mark Target - [ ] Eldritch Pulse - [ ] Construct's Magic - [ ] Artificer - [ ] Summon Cult Floor - [ ] Summon Cult Wall - [ ] Greater Conjuration - [ ] Summon Soulstone - [ ] Wraith - [ ] Phase Shift - [ ] Juggernaut - [ ] Shield - [ ] Gauntlet Echo - [x] Cult leader selection system - [ ] Rending/Apocalypse rune placement markers EXTRA: - [ ] Spirit Realm rune - [x] Eldritch language - [ ] Conceal magic - [ ] Ru locale --- <!-- This is default collapsed, readers click to expand it and see all your media The PR media section can get very large at times, so this is a good way to keep it clean The title is written using HTML tags The title must be within the <summary> tags or you won't see it --> <details><summary><h1>Media</h1></summary> <p> ![Example Media Embed](https://example.com/thisimageisntreal.png) </p> </details> --- # Changelog :cl: - add: Added Blood Cult Gamemode. --------- Signed-off-by: VMSolidus <[email protected]> Signed-off-by: Remuchi <[email protected]> Co-authored-by: VMSolidus <[email protected]>
1 parent 09d5900 commit 1500208

File tree

408 files changed

+10442
-303
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

408 files changed

+10442
-303
lines changed

Content.Client/Antag/AntagStatusIconSystem.cs

+14-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
using Content.Shared.Revolutionary.Components;
33
using Content.Shared.StatusIcon;
44
using Content.Shared.StatusIcon.Components;
5+
using Content.Shared.WhiteDream.BloodCult.BloodCultist;
6+
using Content.Shared.WhiteDream.BloodCult.Components;
7+
using Content.Shared.WhiteDream.BloodCult.Constructs;
58
using Content.Shared.Zombies;
69
using Robust.Client.Player;
710
using Robust.Shared.Prototypes;
@@ -23,6 +26,10 @@ public override void Initialize()
2326
SubscribeLocalEvent<ZombieComponent, GetStatusIconsEvent>(GetIcon);
2427
SubscribeLocalEvent<HeadRevolutionaryComponent, GetStatusIconsEvent>(GetIcon);
2528
SubscribeLocalEvent<InitialInfectedComponent, GetStatusIconsEvent>(GetIcon);
29+
30+
SubscribeLocalEvent<ConstructComponent, GetStatusIconsEvent>(GetIcon);
31+
SubscribeLocalEvent<BloodCultistComponent, GetStatusIconsEvent>(GetBloodCultIcon);
32+
SubscribeLocalEvent<BloodCultLeaderComponent, GetStatusIconsEvent>(GetIcon);
2633
}
2734

2835
/// <summary>
@@ -39,7 +46,6 @@ private void GetIcon<T>(EntityUid uid, T comp, ref GetStatusIconsEvent ev) where
3946
ev.StatusIcons.Add(_prototype.Index(comp.StatusIcon));
4047
}
4148

42-
4349
/// <summary>
4450
/// Adds the Rev Icon on an entity if the player is supposed to see it. This additional function is needed to deal
4551
/// with a special case where if someone is a head rev we only want to display the headrev icon.
@@ -50,6 +56,13 @@ private void GetRevIcon(EntityUid uid, RevolutionaryComponent comp, ref GetStatu
5056
return;
5157

5258
GetIcon(uid, comp, ref ev);
59+
}
5360

61+
private void GetBloodCultIcon(EntityUid uid, BloodCultistComponent comp, ref GetStatusIconsEvent ev)
62+
{
63+
if (HasComp<BloodCultLeaderComponent>(uid))
64+
return;
65+
66+
GetIcon(uid, comp, ref ev);
5467
}
5568
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using Content.Client.Lathe.UI;
2+
using Content.Client.UserInterface.Controls;
3+
using Content.Shared.ListViewSelector;
4+
using JetBrains.Annotations;
5+
using Robust.Client.UserInterface.Controls;
6+
using Robust.Shared.Prototypes;
7+
8+
// ReSharper disable InconsistentNaming
9+
10+
namespace Content.Client.ListViewSelector;
11+
12+
[UsedImplicitly]
13+
public sealed class ListViewSelectorBUI(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
14+
{
15+
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
16+
17+
private FancyWindow _window = new();
18+
private BoxContainer? _itemsContainer;
19+
private Dictionary<string, object> _metaData = new();
20+
21+
protected override void Open()
22+
{
23+
_window = FormWindow();
24+
_window.OnClose += Close;
25+
_window.OpenCentered();
26+
}
27+
28+
protected override void UpdateState(BoundUserInterfaceState state)
29+
{
30+
base.UpdateState(state);
31+
if (state is not ListViewSelectorState listViewSelectorState)
32+
return;
33+
34+
PopulateWindow(listViewSelectorState.Items);
35+
_metaData = listViewSelectorState.MetaData;
36+
}
37+
38+
protected override void Dispose(bool disposing)
39+
{
40+
base.Dispose(disposing);
41+
42+
if (disposing)
43+
_window.Close();
44+
}
45+
46+
private FancyWindow FormWindow()
47+
{
48+
var window = new FancyWindow
49+
{
50+
HorizontalExpand = true,
51+
VerticalExpand = true,
52+
MinWidth = 350,
53+
MinHeight = 400,
54+
Title = Loc.GetString("list-view-window-default-title")
55+
};
56+
57+
var scrollContainer = new ScrollContainer
58+
{
59+
HorizontalExpand = true,
60+
VerticalExpand = true
61+
};
62+
63+
var itemsContainer = new BoxContainer
64+
{
65+
Orientation = BoxContainer.LayoutOrientation.Vertical
66+
};
67+
68+
scrollContainer.AddChild(itemsContainer);
69+
window.AddChild(scrollContainer);
70+
71+
_itemsContainer = itemsContainer;
72+
73+
return window;
74+
}
75+
76+
private void PopulateWindow(List<ListViewSelectorEntry> items)
77+
{
78+
if (_itemsContainer is null)
79+
return;
80+
81+
_itemsContainer.Children.Clear();
82+
83+
foreach (var item in items)
84+
{
85+
var itemName = item.Name;
86+
var itemDesc = item.Description;
87+
if (_prototypeManager.TryIndex(item.Id, out var itemPrototype))
88+
{
89+
itemName = itemPrototype.Name;
90+
itemDesc = itemPrototype.Description;
91+
}
92+
93+
var button = new Button
94+
{
95+
Text = itemName,
96+
};
97+
98+
if (!string.IsNullOrEmpty(itemDesc))
99+
button.TooltipSupplier = _ => new RecipeTooltip(itemDesc);
100+
101+
button.OnButtonUp += _ =>
102+
{
103+
var msg = new ListViewItemSelectedMessage(item, items.IndexOf(item), _metaData);
104+
SendMessage(msg);
105+
Close();
106+
};
107+
108+
_itemsContainer.AddChild(button);
109+
}
110+
}
111+
}

Content.Client/ShortConstruction/ShortConstructionSystem.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Content.Client.Construction;
2+
// using Content.Client.WhiteDream.BloodCult.UI;
23
using Content.Shared.Construction.Prototypes;
34
using Content.Shared.RadialSelector;
45
using Content.Shared.ShortConstruction;
@@ -36,11 +37,13 @@ private void OnItemRecieved(Entity<ShortConstructionComponent> ent, ref RadialSe
3637
return;
3738
}
3839

40+
var hijack = new ConstructionPlacementHijack(_construction, prototype);
41+
3942
_placement.BeginPlacing(new PlacementInformation
4043
{
4144
IsTile = false,
4245
PlacementOption = prototype.PlacementMode
4346
},
44-
new ConstructionPlacementHijack(_construction, prototype));
47+
hijack);
4548
}
4649
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System.Numerics;
2+
using Content.Shared.Antag;
3+
using Content.Shared.Ghost;
4+
using Content.Shared.StatusIcon.Components;
5+
using Content.Shared.WhiteDream.BloodCult;
6+
using Content.Shared.WhiteDream.BloodCult.BloodCultist;
7+
using Content.Shared.WhiteDream.BloodCult.Components;
8+
using Content.Shared.WhiteDream.BloodCult.Constructs;
9+
using Robust.Client.GameObjects;
10+
using Robust.Shared.Random;
11+
using Robust.Shared.Utility;
12+
13+
namespace Content.Client.WhiteDream.BloodCult;
14+
15+
public sealed class BloodCultistSystem : EntitySystem
16+
{
17+
[Dependency] private readonly IRobustRandom _random = default!;
18+
19+
public override void Initialize()
20+
{
21+
SubscribeLocalEvent<PentagramComponent, ComponentStartup>(OnPentagramAdded);
22+
SubscribeLocalEvent<PentagramComponent, ComponentShutdown>(OnPentagramRemoved);
23+
24+
SubscribeLocalEvent<ConstructComponent, CanDisplayStatusIconsEvent>(OnCanShowCultIcon);
25+
SubscribeLocalEvent<BloodCultistComponent, CanDisplayStatusIconsEvent>(OnCanShowCultIcon);
26+
SubscribeLocalEvent<BloodCultLeaderComponent, CanDisplayStatusIconsEvent>(OnCanShowCultIcon);
27+
}
28+
29+
private void OnPentagramAdded(EntityUid uid, PentagramComponent component, ComponentStartup args)
30+
{
31+
if (!TryComp<SpriteComponent>(uid, out var sprite) || sprite.LayerMapTryGet(PentagramKey.Key, out _))
32+
return;
33+
34+
var adj = sprite.Bounds.Height / 2 + 1.0f / 32 * 10.0f;
35+
36+
var randomState = _random.Pick(component.States);
37+
38+
var layer = sprite.AddLayer(new SpriteSpecifier.Rsi(component.RsiPath, randomState));
39+
40+
sprite.LayerMapSet(PentagramKey.Key, layer);
41+
sprite.LayerSetOffset(layer, new Vector2(0.0f, adj));
42+
}
43+
44+
private void OnPentagramRemoved(EntityUid uid, PentagramComponent component, ComponentShutdown args)
45+
{
46+
if (!TryComp<SpriteComponent>(uid, out var sprite) || !sprite.LayerMapTryGet(PentagramKey.Key, out var layer))
47+
return;
48+
49+
sprite.RemoveLayer(layer);
50+
}
51+
52+
/// <summary>
53+
/// Determine whether a client should display the cult icon.
54+
/// </summary>
55+
private void OnCanShowCultIcon<T>(EntityUid uid, T comp, ref CanDisplayStatusIconsEvent args)
56+
where T : IAntagStatusIconComponent
57+
{
58+
if (!CanDisplayIcon(args.User, comp.IconVisibleToGhost))
59+
args.Cancelled = true;
60+
}
61+
62+
/// <summary>
63+
/// The criteria that determine whether a client should see Cult/Cult leader icons.
64+
/// </summary>
65+
private bool CanDisplayIcon(EntityUid? uid, bool visibleToGhost)
66+
{
67+
if (HasComp<BloodCultistComponent>(uid) || HasComp<BloodCultLeaderComponent>(uid) ||
68+
HasComp<ConstructComponent>(uid))
69+
return true;
70+
71+
return visibleToGhost && HasComp<GhostComponent>(uid);
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Content.Client.Light.Components;
2+
using Content.Shared.WhiteDream.BloodCult;
3+
using Content.Shared.WhiteDream.BloodCult.Items.VoidTorch;
4+
using Robust.Client.GameObjects;
5+
6+
namespace Content.Client.WhiteDream.BloodCult.Items.VoidTorch;
7+
8+
public sealed class VoidTorchSystem : VisualizerSystem<VoidTorchComponent>
9+
{
10+
protected override void OnAppearanceChange(EntityUid uid,
11+
VoidTorchComponent component,
12+
ref AppearanceChangeEvent args)
13+
{
14+
if (args.Sprite == null)
15+
return;
16+
if (!AppearanceSystem.TryGetData<bool>(uid, GenericCultVisuals.State, out var state)
17+
|| !TryComp<LightBehaviourComponent>(uid, out var lightBehaviour))
18+
return;
19+
20+
lightBehaviour.StopLightBehaviour();
21+
lightBehaviour.StartLightBehaviour(state ? component.TurnOnLightBehaviour : component.TurnOffLightBehaviour);
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using Content.Client.UserInterface.Controls;
2+
using Content.Shared.WhiteDream.BloodCult.UI;
3+
using JetBrains.Annotations;
4+
using Robust.Client.UserInterface.Controls;
5+
6+
// ReSharper disable InconsistentNaming
7+
8+
namespace Content.Client.WhiteDream.BloodCult.NameSelector;
9+
10+
[UsedImplicitly]
11+
public sealed class NameSelectorBUI(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
12+
{
13+
private readonly FancyWindow _window = new();
14+
15+
protected override void Open()
16+
{
17+
base.Open();
18+
19+
FormWindow();
20+
_window.OpenCentered();
21+
_window.OnClose += Close;
22+
}
23+
24+
protected override void Dispose(bool disposing)
25+
{
26+
base.Dispose(disposing);
27+
28+
if (disposing)
29+
_window.Close();
30+
}
31+
32+
private void FormWindow()
33+
{
34+
var container = new BoxContainer
35+
{
36+
Orientation = BoxContainer.LayoutOrientation.Vertical
37+
};
38+
39+
var label = new Label
40+
{
41+
Text = Loc.GetString("name-selector-title")
42+
};
43+
44+
var lineEdit = new LineEdit
45+
{
46+
HorizontalExpand = true
47+
};
48+
49+
var button = new Button
50+
{
51+
Text = Loc.GetString("name-selector-accept-button")
52+
};
53+
54+
button.OnButtonUp += _ =>
55+
{
56+
var msg = new NameSelectedMessage(lineEdit.Text);
57+
SendMessage(msg);
58+
Close();
59+
};
60+
61+
container.AddChild(label);
62+
container.AddChild(lineEdit);
63+
container.AddChild(button);
64+
65+
_window.AddChild(container);
66+
}
67+
}

0 commit comments

Comments
 (0)