Gods and religions (#1405)
* basic religion vision * block god interactions * skill tree mob specify * silvania setup?? * clustering shader optimization * gods department & job * random gods jobs * Luxian god * Update Nature.png * Update sphere_of_light.yml * god chat * Update ChatSystem.cs * OBSERVATION * public observation and basic follower api * shader tweaks * improve shaders * spawning and praying on altars * altars ppvs override * move pvs overridiation from altars to observers * shader coloration * spectral z mover * god magic radius restricted * guide how to believe in god * sends messages to god when smoeone wanna become follower * follower doAfter * goodbye luxian, welcome lumera * goodbye silvania, welcome merkas * som polish and renamings * gods fast travel * Update altar.ftl * some lumera sfx * renouncing patrons! * renounce followers * followewr percentage calculation * remove from player-facing * fix * Update sphere_of_light.yml * Update base.yml
83
Content.Client/_CP14/Religion/CP14ClientReligionGodSystem.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Religion;
|
||||
|
||||
public sealed partial class CP14ClientReligionGodSystem : CP14SharedReligionGodSystem
|
||||
{
|
||||
[Dependency] private readonly IOverlayManager _overlayMgr = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
|
||||
private CP14ReligionVisionOverlay? _overlay;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14ReligionVisionComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<CP14ReligionVisionComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
|
||||
SubscribeLocalEvent<CP14ReligionVisionComponent, ComponentInit>(OnOverlayInit);
|
||||
SubscribeLocalEvent<CP14ReligionVisionComponent, ComponentRemove>(OnOverlayRemove);
|
||||
}
|
||||
|
||||
protected override void SendMessageToGods(ProtoId<CP14ReligionPrototype> religion, string msg, EntityUid source) { }
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
_overlayMgr.RemoveOverlay<CP14ReligionVisionOverlay>();
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(Entity<CP14ReligionVisionComponent> ent, ref LocalPlayerAttachedEvent args)
|
||||
{
|
||||
AddOverlay();
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(Entity<CP14ReligionVisionComponent> ent, ref LocalPlayerDetachedEvent args)
|
||||
{
|
||||
RemoveOverlay();
|
||||
}
|
||||
|
||||
private void OnOverlayInit(Entity<CP14ReligionVisionComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
var attachedEnt = _player.LocalEntity;
|
||||
|
||||
if (attachedEnt != ent.Owner)
|
||||
return;
|
||||
|
||||
AddOverlay();
|
||||
}
|
||||
|
||||
private void OnOverlayRemove(Entity<CP14ReligionVisionComponent> ent, ref ComponentRemove args)
|
||||
{
|
||||
var attachedEnt = _player.LocalEntity;
|
||||
|
||||
if (attachedEnt != ent.Owner)
|
||||
return;
|
||||
|
||||
RemoveOverlay();
|
||||
}
|
||||
|
||||
private void AddOverlay()
|
||||
{
|
||||
if (_overlay != null)
|
||||
return;
|
||||
|
||||
_overlay = new CP14ReligionVisionOverlay();
|
||||
_overlayMgr.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void RemoveOverlay()
|
||||
{
|
||||
if (_overlay == null)
|
||||
return;
|
||||
|
||||
_overlayMgr.RemoveOverlay(_overlay);
|
||||
_overlay = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Content.Client._CP14.DemiplaneTraveling;
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._CP14.Religion;
|
||||
|
||||
public sealed class CP14ReligionEntityBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private CP14ReligionEntityWindow? _window;
|
||||
|
||||
public CP14ReligionEntityBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = this.CreateWindow<CP14ReligionEntityWindow>();
|
||||
|
||||
_window.OnTeleportAttempt += netId => SendMessage(new CP14ReligionEntityTeleportAttempt(netId));
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (_window == null || state is not CP14ReligionEntityUiState mapState)
|
||||
return;
|
||||
|
||||
_window?.UpdateState(mapState);
|
||||
}
|
||||
}
|
||||
28
Content.Client/_CP14/Religion/CP14ReligionEntityWindow.xaml
Normal file
@@ -0,0 +1,28 @@
|
||||
<religion:CP14ReligionEntityWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:religion="clr-namespace:Content.Client._CP14.Religion"
|
||||
Title="{Loc 'cp14-god-ui-title'}"
|
||||
SetSize="600 500"
|
||||
MinSize="600 100">
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
|
||||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<Label Name="Altars" Text="{Loc 'cp14-god-ui-altars'}" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center" HorizontalExpand="True" HorizontalAlignment="Center"/>
|
||||
<BoxContainer
|
||||
Name="AltarsContainer"
|
||||
Orientation="Vertical"
|
||||
HorizontalExpand="True" />
|
||||
|
||||
<Label Name="Followers" Text="{Loc 'cp14-god-ui-follower'}" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center" HorizontalExpand="True" HorizontalAlignment="Center" Margin="0, 30, 0, 0"/>
|
||||
<BoxContainer
|
||||
Name="FollowersContainer"
|
||||
Orientation="Vertical"
|
||||
HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<RichTextLabel Name="Status"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</religion:CP14ReligionEntityWindow>
|
||||
@@ -0,0 +1,69 @@
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._CP14.Religion;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14ReligionEntityWindow : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly ILogManager _log = default!;
|
||||
private ISawmill Sawmill { get; init; }
|
||||
|
||||
public event Action<NetEntity>? OnTeleportAttempt;
|
||||
|
||||
public CP14ReligionEntityWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Sawmill = _log.GetSawmill("cp14_religion_entity_window");
|
||||
}
|
||||
|
||||
public void UpdateState(CP14ReligionEntityUiState state)
|
||||
{
|
||||
AltarsContainer.RemoveAllChildren();
|
||||
FollowersContainer.RemoveAllChildren();
|
||||
|
||||
Altars.Visible = state.Altars.Count > 0;
|
||||
Followers.Visible = state.Followers.Count > 0;
|
||||
|
||||
foreach (var (netId, name) in state.Altars)
|
||||
{
|
||||
var btn = new Button
|
||||
{
|
||||
Text = name,
|
||||
HorizontalAlignment = HAlignment.Center
|
||||
};
|
||||
|
||||
btn.OnPressed += _ =>
|
||||
{
|
||||
OnTeleportAttempt?.Invoke(netId);
|
||||
};
|
||||
AltarsContainer.AddChild(btn);
|
||||
}
|
||||
|
||||
foreach (var (netId, name) in state.Followers)
|
||||
{
|
||||
var btn = new Button
|
||||
{
|
||||
Text = name,
|
||||
HorizontalAlignment = HAlignment.Center
|
||||
};
|
||||
|
||||
btn.OnPressed += _ =>
|
||||
{
|
||||
OnTeleportAttempt?.Invoke(netId);
|
||||
};
|
||||
FollowersContainer.AddChild(btn);
|
||||
}
|
||||
Status.Text = GetStatusText(state);
|
||||
}
|
||||
|
||||
private string GetStatusText(CP14ReligionEntityUiState state)
|
||||
{
|
||||
return Loc.GetString("cp14-god-ui-follower-percentage", ("count", state.FollowerPercentage * 100));
|
||||
}
|
||||
}
|
||||
148
Content.Client/_CP14/Religion/CP14ReligionVisionOverlay.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Religion;
|
||||
|
||||
public sealed class CP14ReligionVisionOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
private readonly SharedTransformSystem _transform;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of observers zones that can be shown on screen at a time.
|
||||
/// If this value is changed, the shader itself also needs to be updated.
|
||||
/// </summary>
|
||||
public const int MaxCount = 64;
|
||||
|
||||
public override bool RequestScreenTexture => true;
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
private readonly ProtoId<CP14ReligionPrototype>? _religion = null;
|
||||
|
||||
private readonly ShaderInstance _religionShader;
|
||||
private readonly Vector2[] _positions = new Vector2[MaxCount];
|
||||
private readonly float[] _radii = new float[MaxCount];
|
||||
private int _count = 0;
|
||||
public CP14ReligionVisionOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_religionShader = _proto.Index<ShaderPrototype>("CP14ReligionVision").InstanceUnique();
|
||||
|
||||
_transform = _entManager.System<SharedTransformSystem>();
|
||||
|
||||
if (_entManager.TryGetComponent<CP14ReligionEntityComponent>(_player.LocalEntity, out var vision))
|
||||
{
|
||||
_religion = vision.Religion;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (args.Viewport.Eye == null)
|
||||
return false;
|
||||
|
||||
_count = 0;
|
||||
|
||||
var clusters = new List<Cluster>();
|
||||
var religionQuery = _entManager.AllEntityQueryEnumerator<CP14ReligionObserverComponent, TransformComponent>();
|
||||
while (religionQuery.MoveNext(out var uid, out var rel, out var xform))
|
||||
{
|
||||
if (_religion is null)
|
||||
continue;
|
||||
|
||||
var observation = rel.Observation;
|
||||
if (!observation.ContainsKey(_religion.Value))
|
||||
continue;
|
||||
|
||||
if (!rel.Active || xform.MapID != args.MapId)
|
||||
continue;
|
||||
|
||||
var mapPos = _transform.GetWorldPosition(uid);
|
||||
|
||||
// To be clear, this needs to use "inside-viewport" pixels.
|
||||
// In other words, specifically NOT IViewportControl.WorldToScreen (which uses outer coordinates).
|
||||
var tempCoords = args.Viewport.WorldToLocal(mapPos);
|
||||
tempCoords.Y = args.Viewport.Size.Y - tempCoords.Y; // Local space to fragment space.
|
||||
|
||||
// try find cluster to merge with
|
||||
bool merged = false;
|
||||
foreach (var cluster in clusters)
|
||||
{
|
||||
if ((cluster.Position - tempCoords).Length() < 150f)
|
||||
{
|
||||
cluster.Add(tempCoords, rel.Observation[_religion.Value]);
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!merged)
|
||||
clusters.Add(new Cluster(tempCoords, rel.Observation[_religion.Value]));
|
||||
|
||||
if (clusters.Count >= MaxCount)
|
||||
break;
|
||||
}
|
||||
|
||||
_count = 0;
|
||||
foreach (var cluster in clusters)
|
||||
{
|
||||
_positions[_count] = cluster.Position;
|
||||
_radii[_count] = cluster.Radius;
|
||||
_count++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (ScreenTexture == null || args.Viewport.Eye == null)
|
||||
return;
|
||||
|
||||
if (!_entManager.TryGetComponent<CP14ReligionVisionComponent>(_player.LocalEntity, out var visionComponent))
|
||||
return;
|
||||
|
||||
_religionShader?.SetParameter("shaderColor", visionComponent.ShaderColor);
|
||||
_religionShader?.SetParameter("renderScale", args.Viewport.RenderScale * args.Viewport.Eye.Scale);
|
||||
_religionShader?.SetParameter("count", _count);
|
||||
_religionShader?.SetParameter("position", _positions);
|
||||
_religionShader?.SetParameter("radius", _radii);
|
||||
_religionShader?.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
||||
|
||||
var worldHandle = args.WorldHandle;
|
||||
worldHandle.UseShader(_religionShader);
|
||||
worldHandle.DrawRect(args.WorldAABB, Color.White);
|
||||
worldHandle.UseShader(null);
|
||||
}
|
||||
|
||||
private sealed class Cluster
|
||||
{
|
||||
public Vector2 Position;
|
||||
public float Radius;
|
||||
public int Count;
|
||||
|
||||
public Cluster(Vector2 pos, float radius)
|
||||
{
|
||||
Position = pos;
|
||||
Radius = radius;
|
||||
Count = 1;
|
||||
}
|
||||
|
||||
public void Add(Vector2 pos, float radius)
|
||||
{
|
||||
Position = (Position * Count + pos) / (Count + 1);
|
||||
Radius = Math.Max(Radius, radius);
|
||||
Count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,6 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
private EntityUid? _targetPlayer;
|
||||
|
||||
private IEnumerable<CP14SkillPrototype> _allSkills = [];
|
||||
private IEnumerable<CP14SkillTreePrototype> _allTrees = [];
|
||||
|
||||
private CP14SkillPrototype? _selectedSkill;
|
||||
private CP14SkillTreePrototype? _selectedSkillTree;
|
||||
@@ -72,7 +71,6 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
private void CacheSkillProto()
|
||||
{
|
||||
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>();
|
||||
_allTrees = _proto.EnumeratePrototypes<CP14SkillTreePrototype>().OrderBy(tree => Loc.GetString(tree.Name));
|
||||
}
|
||||
|
||||
public void OnStateExited(GameplayState state)
|
||||
@@ -293,9 +291,9 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
//If tree not selected, select the first one
|
||||
if (_selectedSkillTree == null)
|
||||
{
|
||||
var firstTree = _allTrees.First();
|
||||
var firstTree = storage.AvailableSkillTrees.First();
|
||||
|
||||
SelectTree(firstTree, storage); // Set the first tree from the player's progress
|
||||
SelectTree(firstTree); // Set the first tree from the player's progress
|
||||
}
|
||||
|
||||
if (_selectedSkillTree == null)
|
||||
@@ -308,8 +306,11 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
_window.LevelLabel.Text = $"{storage.SkillsSumExperience}/{storage.ExperienceMaxCap}";
|
||||
|
||||
_window.TreeTabsContainer.RemoveAllChildren();
|
||||
foreach (var tree in _allTrees)
|
||||
foreach (var tree in storage.AvailableSkillTrees)
|
||||
{
|
||||
if (!_proto.TryIndex(tree, out var indexedTree))
|
||||
return;
|
||||
|
||||
float learnedPoints = 0;
|
||||
foreach (var skillId in storage.LearnedSkills)
|
||||
{
|
||||
@@ -322,25 +323,28 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
}
|
||||
}
|
||||
|
||||
var treeButton2 = new CP14SkillTreeButtonControl(tree.Color, Loc.GetString(tree.Name), learnedPoints);
|
||||
treeButton2.ToolTip = Loc.GetString(tree.Desc ?? string.Empty);
|
||||
var treeButton2 = new CP14SkillTreeButtonControl(indexedTree.Color, Loc.GetString(indexedTree.Name), learnedPoints);
|
||||
treeButton2.ToolTip = Loc.GetString(indexedTree.Desc ?? string.Empty);
|
||||
treeButton2.OnPressed += () =>
|
||||
{
|
||||
SelectTree(tree, storage);
|
||||
SelectTree(indexedTree);
|
||||
};
|
||||
|
||||
_window.TreeTabsContainer.AddChild(treeButton2);
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectTree(CP14SkillTreePrototype tree, CP14SkillStorageComponent storage)
|
||||
private void SelectTree(ProtoId<CP14SkillTreePrototype> tree)
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
_selectedSkillTree = tree;
|
||||
_window.ParallaxBackground.ParallaxPrototype = tree.Parallax;
|
||||
_window.TreeName.Text = Loc.GetString(tree.Name);
|
||||
if (!_proto.TryIndex(tree, out var indexedTree))
|
||||
return;
|
||||
|
||||
_selectedSkillTree = indexedTree;
|
||||
_window.ParallaxBackground.ParallaxPrototype = indexedTree.Parallax;
|
||||
_window.TreeName.Text = Loc.GetString(indexedTree.Name);
|
||||
|
||||
UpdateGraphControl();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ using Content.Server.Administration.Managers;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Players.RateLimiting;
|
||||
using Content.Server.Radio.EntitySystems;
|
||||
using Content.Server.Speech.Prototypes;
|
||||
using Content.Server.Speech.EntitySystems;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
@@ -60,6 +62,9 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
[Dependency] private readonly ReplacementAccentSystem _wordreplacement = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly ExamineSystemShared _examineSystem = default!;
|
||||
//CP14
|
||||
[Dependency] private readonly RadioSystem _radio = default!;
|
||||
//CP14 end
|
||||
|
||||
public const int VoiceRange = 10; // how far voice goes in world units
|
||||
public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units
|
||||
@@ -174,6 +179,15 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
bool ignoreActionBlocker = false
|
||||
)
|
||||
{
|
||||
//CP14 Zone
|
||||
if (HasComp<CP14ReligionEntityComponent>(source))
|
||||
{
|
||||
TryProccessRadioMessage(source, message, out var modMessage, out var channel);
|
||||
_radio.SendRadioMessage(source, modMessage, "CP14Gods", source);
|
||||
return;
|
||||
}
|
||||
//CP14 Zone end
|
||||
|
||||
if (HasComp<GhostComponent>(source))
|
||||
{
|
||||
// Ghosts can only send dead chat messages, so we'll forward it to InGame OOC.
|
||||
|
||||
@@ -27,4 +27,7 @@ public enum SpawnPointType
|
||||
LateJoin,
|
||||
Job,
|
||||
Observer,
|
||||
//CP14
|
||||
Always, //Always use only these spawn point, and latejoin, and roundstart
|
||||
//CP14 end
|
||||
}
|
||||
|
||||
@@ -32,6 +32,15 @@ public sealed class SpawnPointSystem : EntitySystem
|
||||
if (args.Station != null && _stationSystem.GetOwningStation(uid, xform) != args.Station)
|
||||
continue;
|
||||
|
||||
//CP14 always spawn gods on gods spawnpoints
|
||||
if (spawnPoint.SpawnType == SpawnPointType.Always && (args.Job == null || spawnPoint.Job == args.Job))
|
||||
{
|
||||
possiblePositions.Clear();
|
||||
possiblePositions.Add(xform.Coordinates);
|
||||
break;
|
||||
}
|
||||
//CP14end
|
||||
|
||||
if (_gameTicker.RunLevel == GameRunLevel.InRound && spawnPoint.SpawnType == SpawnPointType.LateJoin)
|
||||
{
|
||||
possiblePositions.Add(xform.Coordinates);
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.Popups;
|
||||
using Content.Shared._CP14.Demiplane;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
@@ -58,6 +59,8 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
|
||||
{
|
||||
if (HasComp<GhostComponent>(ent))
|
||||
continue;
|
||||
if (HasComp<CP14ReligionEntityComponent>(ent)) //TODO: make some generic way to whitelist entities from teleporting
|
||||
continue;
|
||||
|
||||
if (!_mind.TryGetMind(ent, out var mindId, out var mind))
|
||||
continue;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
using Content.Shared.Destructible.Thresholds;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.RandomJobs;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14StationRandomJobsSystem))]
|
||||
public sealed partial class CP14StationRandomJobsComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<CP14RandomJobEntry> Entries = new();
|
||||
}
|
||||
|
||||
[Serializable, DataDefinition]
|
||||
public sealed partial class CP14RandomJobEntry
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public List<ProtoId<JobPrototype>> Jobs = default!;
|
||||
|
||||
[DataField(required: true)]
|
||||
public MinMax Count = new(1, 1);
|
||||
|
||||
[DataField]
|
||||
public float Prob = 1f;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
using Content.Server.Station.Events;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.RandomJobs;
|
||||
|
||||
public sealed partial class CP14StationRandomJobsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly StationJobsSystem _jobs = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<StationInitializedEvent>(OnInit, after: new[] { typeof(StationJobsSystem) });
|
||||
}
|
||||
|
||||
private void OnInit(StationInitializedEvent args)
|
||||
{
|
||||
if (!TryComp<CP14StationRandomJobsComponent>(args.Station, out var randomJobs))
|
||||
return;
|
||||
|
||||
foreach (var entry in randomJobs.Entries)
|
||||
{
|
||||
if (!_random.Prob(entry.Prob))
|
||||
continue;
|
||||
|
||||
var count = entry.Count.Next(_random);
|
||||
|
||||
var tempList = new List<ProtoId<JobPrototype>>(entry.Jobs);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (tempList.Count == 0)
|
||||
break;
|
||||
|
||||
var job = _random.Pick(tempList);
|
||||
tempList.Remove(job);
|
||||
|
||||
if (!_proto.TryIndex(job, out var jobProto))
|
||||
continue;
|
||||
|
||||
_jobs.TryAdjustJobSlot(args.Station, jobProto, 1, createSlot: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
Content.Server/_CP14/Religion/CP14ReligionSystem.UI.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Content.Shared.Follower;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server._CP14.Religion;
|
||||
|
||||
public sealed partial class CP14ReligionGodSystem
|
||||
{
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
|
||||
[Dependency] private readonly FollowerSystem _follower = default!;
|
||||
private void InitializeUI()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ReligionEntityComponent, OpenBoundInterfaceMessage>(OnOpenInterface);
|
||||
SubscribeLocalEvent<CP14ReligionEntityComponent, CP14ReligionEntityTeleportAttempt>(OnTeleportAttempt);
|
||||
}
|
||||
|
||||
private void OnTeleportAttempt(Entity<CP14ReligionEntityComponent> ent, ref CP14ReligionEntityTeleportAttempt args)
|
||||
{
|
||||
var target = GetEntity(args.Entity);
|
||||
|
||||
var canTeleport = false;
|
||||
if (TryComp<CP14ReligionAltarComponent>(target, out var altar))
|
||||
{
|
||||
if (altar.Religion == ent.Comp.Religion)
|
||||
{
|
||||
canTeleport = true;
|
||||
}
|
||||
}
|
||||
else if (TryComp<CP14ReligionFollowerComponent>(target, out var follower))
|
||||
{
|
||||
if (follower.Religion == ent.Comp.Religion)
|
||||
{
|
||||
canTeleport = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!canTeleport)
|
||||
return;
|
||||
|
||||
_follower.StartFollowingEntity(ent, target);
|
||||
}
|
||||
|
||||
private void OnOpenInterface(Entity<CP14ReligionEntityComponent> ent, ref OpenBoundInterfaceMessage args)
|
||||
{
|
||||
if (ent.Comp.Religion is null)
|
||||
return;
|
||||
|
||||
var altars = new Dictionary<NetEntity, string>();
|
||||
var queryAltars = EntityQueryEnumerator<CP14ReligionAltarComponent, MetaDataComponent>();
|
||||
while (queryAltars.MoveNext(out var uid, out var altar, out var meta))
|
||||
{
|
||||
if (altar.Religion != ent.Comp.Religion)
|
||||
continue;
|
||||
|
||||
altars.TryAdd(GetNetEntity(uid), meta.EntityName);
|
||||
}
|
||||
|
||||
var followers = new Dictionary<NetEntity, string>();
|
||||
var queryFollowers = EntityQueryEnumerator<CP14ReligionFollowerComponent, MetaDataComponent>();
|
||||
while (queryFollowers.MoveNext(out var uid, out var follower, out var meta))
|
||||
{
|
||||
if (follower.Religion != ent.Comp.Religion)
|
||||
continue;
|
||||
|
||||
followers.TryAdd(GetNetEntity(uid), meta.EntityName);
|
||||
}
|
||||
|
||||
var followerPercentage = GetFollowerPercentage(ent);
|
||||
ent.Comp.FollowerPercentage = followerPercentage;
|
||||
Dirty(ent);
|
||||
|
||||
_userInterface.SetUiState(ent.Owner, CP14ReligionEntityUiKey.Key, new CP14ReligionEntityUiState(altars, followers, followerPercentage));
|
||||
}
|
||||
}
|
||||
177
Content.Server/_CP14/Religion/CP14ReligionSystem.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Speech;
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Religion;
|
||||
|
||||
public sealed partial class CP14ReligionGodSystem : CP14SharedReligionGodSystem
|
||||
{
|
||||
[Dependency] private readonly IChatManager _chat = default!;
|
||||
[Dependency] private readonly PvsOverrideSystem _pvs = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
InitializeUI();
|
||||
|
||||
SubscribeLocalEvent<CP14ReligionObserverComponent, ComponentInit>(OnObserverInit);
|
||||
SubscribeLocalEvent<CP14ReligionObserverComponent, AfterAutoHandleStateEvent>(OnObserverHandleState);
|
||||
|
||||
SubscribeLocalEvent<CP14ReligionEntityComponent, ComponentInit>(OnGodInit);
|
||||
SubscribeLocalEvent<CP14ReligionEntityComponent, ComponentShutdown>(OnGodShutdown);
|
||||
SubscribeLocalEvent<CP14ReligionEntityComponent, PlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<CP14ReligionEntityComponent, PlayerDetachedEvent>(OnPlayerDetached);
|
||||
|
||||
SubscribeLocalEvent<CP14ReligionAltarComponent, ListenEvent>(OnListen);
|
||||
}
|
||||
|
||||
private void OnObserverHandleState(Entity<CP14ReligionObserverComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14ReligionEntityComponent>();
|
||||
while (query.MoveNext(out var uid, out var god))
|
||||
{
|
||||
UpdatePvsOverrides(new Entity<CP14ReligionEntityComponent>(uid, god));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnObserverInit(Entity<CP14ReligionObserverComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
foreach (var (religion, _) in ent.Comp.Observation)
|
||||
{
|
||||
var gods = GetGods(religion);
|
||||
|
||||
foreach (var god in gods)
|
||||
{
|
||||
UpdatePvsOverrides(god);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGodInit(Entity<CP14ReligionEntityComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
AddPvsOverrides(ent);
|
||||
}
|
||||
|
||||
private void OnGodShutdown(Entity<CP14ReligionEntityComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
RemovePvsOverrides(ent);
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(Entity<CP14ReligionEntityComponent> ent, ref PlayerAttachedEvent args)
|
||||
{
|
||||
AddPvsOverrides(ent);
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(Entity<CP14ReligionEntityComponent> ent, ref PlayerDetachedEvent args)
|
||||
{
|
||||
RemovePvsOverrides(ent);
|
||||
}
|
||||
|
||||
private void OnListen(Entity<CP14ReligionAltarComponent> ent, ref ListenEvent args)
|
||||
{
|
||||
if (ent.Comp.Religion is null)
|
||||
return;
|
||||
|
||||
var wrappedMessage =
|
||||
Loc.GetString("cp14-altar-wrapped-message", ("name", MetaData(args.Source).EntityName), ("msg", args.Message));
|
||||
|
||||
SendMessageToGods(ent.Comp.Religion.Value, wrappedMessage, args.Source);
|
||||
}
|
||||
|
||||
protected override void SendMessageToGods(ProtoId<CP14ReligionPrototype> religion, string msg, EntityUid source)
|
||||
{
|
||||
var gods = GetGods(religion);
|
||||
|
||||
HashSet<INetChannel> channels = new();
|
||||
foreach (var god in gods)
|
||||
{
|
||||
if (!TryComp<ActorComponent>(god, out var godActor))
|
||||
continue;
|
||||
|
||||
channels.Add(godActor.PlayerSession.Channel);
|
||||
}
|
||||
|
||||
_chat.ChatMessageToMany(ChatChannel.Notifications, msg, msg, source, false, true, channels, colorOverride: Color.Aqua);
|
||||
}
|
||||
|
||||
public float GetFollowerPercentage(Entity<CP14ReligionEntityComponent> god)
|
||||
{
|
||||
var total = 0;
|
||||
var followers = 0;
|
||||
|
||||
var allHumans = Mind.GetAliveHumans();
|
||||
foreach (var human in allHumans)
|
||||
{
|
||||
total++;
|
||||
|
||||
if (!TryComp<CP14ReligionFollowerComponent>(human.Comp.CurrentEntity, out var relFollower))
|
||||
continue;
|
||||
if (relFollower.Religion != god.Comp.Religion)
|
||||
continue;
|
||||
|
||||
followers++;
|
||||
}
|
||||
|
||||
if (total == 0)
|
||||
return 0f;
|
||||
|
||||
return (float)followers / total;
|
||||
}
|
||||
|
||||
private void AddPvsOverrides(Entity<CP14ReligionEntityComponent> ent)
|
||||
{
|
||||
if (ent.Comp.Religion is null)
|
||||
return;
|
||||
|
||||
if (!TryComp<ActorComponent>(ent, out var actor))
|
||||
return;
|
||||
|
||||
ent.Comp.Session = actor.PlayerSession;
|
||||
|
||||
var query = EntityQueryEnumerator<CP14ReligionObserverComponent>();
|
||||
while (query.MoveNext(out var uid, out var observer))
|
||||
{
|
||||
if (!observer.Observation.ContainsKey(ent.Comp.Religion.Value))
|
||||
continue;
|
||||
|
||||
if (observer.Observation[ent.Comp.Religion.Value] <= 6.5f) //Maybe there is a variable for the distance outside the screen in PVS, I don't know. This number works best
|
||||
continue;
|
||||
|
||||
ent.Comp.PvsOverridedObservers.Add(uid);
|
||||
_pvs.AddSessionOverride(uid, actor.PlayerSession);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemovePvsOverrides(Entity<CP14ReligionEntityComponent> ent)
|
||||
{
|
||||
if (ent.Comp.Religion is null)
|
||||
return;
|
||||
|
||||
if (ent.Comp.Session is null)
|
||||
return;
|
||||
|
||||
foreach (var altar in ent.Comp.PvsOverridedObservers)
|
||||
{
|
||||
_pvs.RemoveSessionOverride(altar, ent.Comp.Session);
|
||||
}
|
||||
|
||||
ent.Comp.Session = null;
|
||||
ent.Comp.PvsOverridedObservers.Clear();
|
||||
}
|
||||
|
||||
private void UpdatePvsOverrides(Entity<CP14ReligionEntityComponent> ent)
|
||||
{
|
||||
if (ent.Comp.Session is null)
|
||||
return;
|
||||
|
||||
RemovePvsOverrides(ent);
|
||||
AddPvsOverrides(ent);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.ZLevel;
|
||||
using Content.Shared.Ghost;
|
||||
using Robust.Shared.Map;
|
||||
@@ -9,11 +8,13 @@ public sealed partial class CP14StationZLevelsSystem
|
||||
{
|
||||
private void InitActions()
|
||||
{
|
||||
SubscribeLocalEvent<GhostComponent, CP14ZLevelActionUp>(OnZLevelUp);
|
||||
SubscribeLocalEvent<GhostComponent, CP14ZLevelActionDown>(OnZLevelDown);
|
||||
SubscribeLocalEvent<GhostComponent, CP14ZLevelActionUp>(OnZLevelUpGhost);
|
||||
SubscribeLocalEvent<GhostComponent, CP14ZLevelActionDown>(OnZLevelDownGhost);
|
||||
SubscribeLocalEvent<SpectralComponent, CP14ZLevelActionUp>(OnZLevelUp);
|
||||
SubscribeLocalEvent<SpectralComponent, CP14ZLevelActionDown>(OnZLevelDown);
|
||||
}
|
||||
|
||||
private void OnZLevelDown(Entity<GhostComponent> ent, ref CP14ZLevelActionDown args)
|
||||
private void OnZLevelDownGhost(Entity<GhostComponent> ent, ref CP14ZLevelActionDown args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
@@ -23,7 +24,27 @@ public sealed partial class CP14StationZLevelsSystem
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnZLevelUp(Entity<GhostComponent> ent, ref CP14ZLevelActionUp args)
|
||||
private void OnZLevelUpGhost(Entity<GhostComponent> ent, ref CP14ZLevelActionUp args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
ZLevelMove(ent, 1);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnZLevelDown(Entity<SpectralComponent> ent, ref CP14ZLevelActionDown args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
ZLevelMove(ent, -1);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnZLevelUp(Entity<SpectralComponent> ent, ref CP14ZLevelActionUp args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
@@ -49,12 +49,6 @@ namespace Content.Shared.Verbs
|
||||
public static readonly VerbCategory CP14RitualBook = new("cp14-verb-categories-ritual-book", null);
|
||||
|
||||
public static readonly VerbCategory CP14CurrencyConvert = new("cp14-verb-categories-currency-converter", null); //CP14
|
||||
|
||||
public static readonly VerbCategory CP14AdminSkillAdd =
|
||||
new ("cp14-verb-categories-admin-skill-add", null, iconsOnly: true) { Columns = 6 };
|
||||
|
||||
public static readonly VerbCategory CP14AdminSkillRemove =
|
||||
new ("cp14-verb-categories-admin-skill-remove", null, iconsOnly: true) { Columns = 6 };
|
||||
//CP14 verbs
|
||||
|
||||
public static readonly VerbCategory Admin =
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Content.Shared.CombatMode.Pacification;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Hands.Components;
|
||||
@@ -7,12 +10,14 @@ using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Speech.Muting;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
public abstract partial class CP14SharedMagicSystem
|
||||
{
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly CP14SharedReligionGodSystem _god = default!;
|
||||
|
||||
private void InitializeChecks()
|
||||
{
|
||||
@@ -22,12 +27,14 @@ public abstract partial class CP14SharedMagicSystem
|
||||
SubscribeLocalEvent<CP14MagicEffectStaminaCostComponent, CP14CastMagicEffectAttemptEvent>(OnStaminaCheck);
|
||||
SubscribeLocalEvent<CP14MagicEffectPacifiedBlockComponent, CP14CastMagicEffectAttemptEvent>(OnPacifiedCheck);
|
||||
SubscribeLocalEvent<CP14MagicEffectAliveTargetRequiredComponent, CP14CastMagicEffectAttemptEvent>(OnMobStateCheck);
|
||||
SubscribeLocalEvent<CP14MagicEffectReligionRestrictedComponent, CP14CastMagicEffectAttemptEvent>(OnReligionRestrictedCheck);
|
||||
|
||||
//Verbal speaking
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14StartCastMagicEffectEvent>(OnVerbalAspectStartCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14MagicEffectConsumeResourceEvent>(OnVerbalAspectAfterCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectEmotingComponent, CP14StartCastMagicEffectEvent>(OnEmoteStartCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectEmotingComponent, CP14MagicEffectConsumeResourceEvent>(OnEmoteEndCast);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -148,6 +155,18 @@ public abstract partial class CP14SharedMagicSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReligionRestrictedCheck(Entity<CP14MagicEffectReligionRestrictedComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
|
||||
if (!TryComp<CP14ReligionEntityComponent>(args.Performer, out var religionComp))
|
||||
return;
|
||||
|
||||
if (args.Position is not null && _god.InVision(args.Position.Value, (args.Performer, religionComp)))
|
||||
return;
|
||||
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnVerbalAspectStartCast(Entity<CP14MagicEffectVerbalAspectComponent> ent,
|
||||
ref CP14StartCastMagicEffectEvent args)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Content.Shared._CP14.MagicSpellStorage;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// If the user belongs to a religion, this spell can only be used within the area of influence of that religion
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem), typeof(CP14SpellStorageSystem))]
|
||||
public sealed partial class CP14MagicEffectReligionRestrictedComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Spells;
|
||||
|
||||
public sealed partial class CP14SpellGodRenounce : CP14SpellEffect
|
||||
{
|
||||
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
if (args.Target is null)
|
||||
return;
|
||||
|
||||
if (!entManager.TryGetComponent<CP14ReligionEntityComponent>(args.User, out var god) || god.Religion is null)
|
||||
return;
|
||||
|
||||
if (!entManager.TryGetComponent<CP14ReligionFollowerComponent>(args.Target.Value, out var follower) || follower.Religion != god.Religion)
|
||||
return;
|
||||
|
||||
var religionSys = entManager.System<CP14SharedReligionGodSystem>();
|
||||
|
||||
religionSys.ToDisbelieve(args.Target.Value);
|
||||
}
|
||||
}
|
||||
24
Content.Shared/_CP14/MagicSpell/Spells/CP14SpellGodTouch.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Spells;
|
||||
|
||||
public sealed partial class CP14SpellGodTouch : CP14SpellEffect
|
||||
{
|
||||
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
if (args.Target is null)
|
||||
return;
|
||||
|
||||
if (!entManager.TryGetComponent<CP14ReligionEntityComponent>(args.User, out var god) || god.Religion is null)
|
||||
return;
|
||||
|
||||
var ev = new CP14GodTouchEvent(god.Religion.Value);
|
||||
entManager.EventBus.RaiseLocalEvent(args.Target.Value, ev);
|
||||
}
|
||||
}
|
||||
public sealed class CP14GodTouchEvent(ProtoId<CP14ReligionPrototype> religion) : EntityEventArgs
|
||||
{
|
||||
public ProtoId<CP14ReligionPrototype> Religion = religion;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14SharedReligionGodSystem))]
|
||||
public sealed partial class CP14ReligionAltarComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<CP14ReligionPrototype>? Religion;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool CanBeConverted = true;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Components;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14SharedReligionGodSystem))]
|
||||
public sealed partial class CP14ReligionEntityComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14ReligionPrototype>? Religion;
|
||||
|
||||
public HashSet<EntityUid> PvsOverridedObservers = new();
|
||||
public ICommonSession? Session;
|
||||
|
||||
/// <summary>
|
||||
/// Number of followers as a percentage. Automatically calculated on the server and sent to the client for data synchronization.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public FixedPoint2 FollowerPercentage = 0;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the entity is a follower of God, or may never be able to become one
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14SharedReligionGodSystem))]
|
||||
public sealed partial class CP14ReligionFollowerComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<CP14ReligionPrototype>? Religion;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public HashSet<ProtoId<CP14ReligionPrototype>> RejectedReligions = new();
|
||||
|
||||
[DataField]
|
||||
public EntProtoId RenounceActionProto = "CP14ActionRenounceFromGod";
|
||||
|
||||
[DataField]
|
||||
public EntityUid? RenounceAction;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Allows the god of a particular religion to see within a radius around the observer.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), Access(typeof(CP14SharedReligionGodSystem))]
|
||||
public sealed partial class CP14ReligionObserverComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public Dictionary<ProtoId<CP14ReligionPrototype>, float> Observation = new(); //DAMNATION
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Active = true;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Content.Shared.Alert;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Components;
|
||||
|
||||
/// <summary>
|
||||
/// This entity has not yet become a follower of God, but wants to become one. Confirmation from god is expected
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14SharedReligionGodSystem))]
|
||||
public sealed partial class CP14ReligionPendingFollowerComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<CP14ReligionPrototype>? Religion;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Limits the vision of entities, allowing them to see only areas within a radius around observers of their religion.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(CP14SharedReligionGodSystem))]
|
||||
public sealed partial class CP14ReligionVisionComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public Vector3 ShaderColor = new (1f, 1f, 1f);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Prototype("cp14Religion")]
|
||||
public sealed partial class CP14ReligionPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField]
|
||||
public float FollowerObservationRadius = 8f;
|
||||
|
||||
[DataField]
|
||||
public float AltarObservationRadius = 25f;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Systems;
|
||||
|
||||
public abstract partial class CP14SharedReligionGodSystem
|
||||
{
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
private void InitializeAltars()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ReligionAltarComponent, GetVerbsEvent<ActivationVerb>>(GetBaseVerb);
|
||||
SubscribeLocalEvent<CP14ReligionAltarComponent, GetVerbsEvent<AlternativeVerb>>(GetAltVerb);
|
||||
}
|
||||
|
||||
private void GetBaseVerb(Entity<CP14ReligionAltarComponent> ent, ref GetVerbsEvent<ActivationVerb> args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void GetAltVerb(Entity<CP14ReligionAltarComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (ent.Comp.Religion is null)
|
||||
return;
|
||||
|
||||
var disabled = !CanBecomeFollower(args.User, ent.Comp.Religion.Value);
|
||||
|
||||
if (!disabled && TryComp<CP14ReligionPendingFollowerComponent>(args.User, out var pendingFollower))
|
||||
{
|
||||
if (pendingFollower.Religion is not null)
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
if (disabled)
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
args.Verbs.Add(new AlternativeVerb()
|
||||
{
|
||||
Text = Loc.GetString("cp14-altar-become-follower"),
|
||||
Message = Loc.GetString("cp14-altar-become-follower-desc"),
|
||||
Act = () =>
|
||||
{
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager, user, 5f, new CP14AltarOfferDoAfter(), ent, used: ent)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnMove = true,
|
||||
};
|
||||
_doAfter.TryStartDoAfter(doAfterArgs);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public bool TryConvertAltar(EntityUid target, ProtoId<CP14ReligionPrototype> religion)
|
||||
{
|
||||
if (!_proto.TryIndex(religion, out var indexedReligion))
|
||||
return false;
|
||||
|
||||
EnsureComp<CP14ReligionAltarComponent>(target, out var altar);
|
||||
|
||||
if (!altar.CanBeConverted)
|
||||
return false;
|
||||
|
||||
var oldReligion = altar.Religion;
|
||||
altar.Religion = religion;
|
||||
Dirty(target, altar);
|
||||
|
||||
EditObservation(target, religion, indexedReligion.AltarObservationRadius);
|
||||
|
||||
var ev = new CP14ReligionChangedEvent(oldReligion, religion);
|
||||
RaiseLocalEvent(target, ev);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void DeconvertAltar(EntityUid target)
|
||||
{
|
||||
if (!TryComp<CP14ReligionAltarComponent>(target, out var altar))
|
||||
return;
|
||||
|
||||
if (altar.Religion is null)
|
||||
return;
|
||||
|
||||
if (!_proto.TryIndex(altar.Religion, out var indexedReligion))
|
||||
return;
|
||||
|
||||
EditObservation(target, altar.Religion.Value, -indexedReligion.AltarObservationRadius);
|
||||
|
||||
var oldReligion = altar.Religion;
|
||||
altar.Religion = null;
|
||||
|
||||
var ev = new CP14ReligionChangedEvent(oldReligion, null);
|
||||
RaiseLocalEvent(target, ev);
|
||||
|
||||
Dirty(target, altar);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14AltarOfferDoAfter : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Systems;
|
||||
|
||||
public abstract partial class CP14SharedReligionGodSystem
|
||||
{
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] protected readonly SharedMindSystem Mind = default!;
|
||||
private void InitializeFollowers()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ReligionPendingFollowerComponent, MapInitEvent>(OnPendingFollowerInit);
|
||||
SubscribeLocalEvent<CP14ReligionPendingFollowerComponent, ComponentShutdown>(OnPendingFollowerShutdown);
|
||||
SubscribeLocalEvent<CP14ReligionPendingFollowerComponent, CP14BreakDivineOfferEvent>(OnBreakDivineOffer);
|
||||
SubscribeLocalEvent<CP14ReligionPendingFollowerComponent, CP14GodTouchEvent>(OnGodTouch);
|
||||
|
||||
SubscribeLocalEvent<CP14ReligionAltarComponent, CP14AltarOfferDoAfter>(OnOfferDoAfter);
|
||||
|
||||
SubscribeLocalEvent<CP14ReligionFollowerComponent, CP14RenounceFromGodEvent>(OnRenounceFromGod);
|
||||
}
|
||||
|
||||
private void OnRenounceFromGod(Entity<CP14ReligionFollowerComponent> ent, ref CP14RenounceFromGodEvent args)
|
||||
{
|
||||
ToDisbelieve(ent);
|
||||
}
|
||||
|
||||
private void OnOfferDoAfter(Entity<CP14ReligionAltarComponent> ent, ref CP14AltarOfferDoAfter args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled)
|
||||
return;
|
||||
|
||||
if (ent.Comp.Religion is null)
|
||||
return;
|
||||
|
||||
TryAddPendingFollower(args.User, ent.Comp.Religion.Value);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnGodTouch(Entity<CP14ReligionPendingFollowerComponent> ent, ref CP14GodTouchEvent args)
|
||||
{
|
||||
if (args.Religion != ent.Comp.Religion)
|
||||
return;
|
||||
|
||||
TryToBelieve(ent);
|
||||
}
|
||||
|
||||
private void OnBreakDivineOffer(Entity<CP14ReligionPendingFollowerComponent> ent, ref CP14BreakDivineOfferEvent args)
|
||||
{
|
||||
RemCompDeferred<CP14ReligionPendingFollowerComponent>(ent);
|
||||
|
||||
if (ent.Comp.Religion is null)
|
||||
return;
|
||||
|
||||
SendMessageToGods(ent.Comp.Religion.Value, Loc.GetString("cp14-unoffer-soul-god-message", ("name", MetaData(ent).EntityName)), ent);
|
||||
}
|
||||
|
||||
private void OnPendingFollowerInit(Entity<CP14ReligionPendingFollowerComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
_alerts.ShowAlert(ent, "CP14DivineOffer");
|
||||
}
|
||||
|
||||
private void OnPendingFollowerShutdown(Entity<CP14ReligionPendingFollowerComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
_alerts.ClearAlert(ent, "CP14DivineOffer");
|
||||
}
|
||||
|
||||
private bool CanBecomeFollower(EntityUid target, ProtoId<CP14ReligionPrototype> religion)
|
||||
{
|
||||
if (HasComp<CP14ReligionEntityComponent>(target))
|
||||
return false;
|
||||
|
||||
EnsureComp<CP14ReligionFollowerComponent>(target, out var follower);
|
||||
|
||||
return !follower.RejectedReligions.Contains(religion);
|
||||
}
|
||||
|
||||
private void TryAddPendingFollower(EntityUid target, ProtoId<CP14ReligionPrototype> religion)
|
||||
{
|
||||
if (!CanBecomeFollower(target, religion))
|
||||
return;
|
||||
|
||||
EnsureComp<CP14ReligionPendingFollowerComponent>(target, out var pendingFollower);
|
||||
pendingFollower.Religion = religion;
|
||||
|
||||
SendMessageToGods(religion, Loc.GetString("cp14-offer-soul-god-message", ("name", MetaData(target).EntityName)), target);
|
||||
}
|
||||
|
||||
private bool TryToBelieve(Entity<CP14ReligionPendingFollowerComponent> pending)
|
||||
{
|
||||
if (pending.Comp.Religion is null)
|
||||
return false;
|
||||
|
||||
if (!_proto.TryIndex(pending.Comp.Religion, out var indexedReligion))
|
||||
return false;
|
||||
|
||||
if (!CanBecomeFollower(pending, pending.Comp.Religion.Value))
|
||||
return false;
|
||||
|
||||
EnsureComp<CP14ReligionFollowerComponent>(pending, out var follower);
|
||||
|
||||
var oldReligion = follower.Religion;
|
||||
follower.Religion = pending.Comp.Religion;
|
||||
Dirty(pending, follower);
|
||||
|
||||
EditObservation(pending, pending.Comp.Religion.Value, indexedReligion.FollowerObservationRadius);
|
||||
|
||||
var ev = new CP14ReligionChangedEvent(oldReligion, pending.Comp.Religion);
|
||||
RaiseLocalEvent(pending, ev);
|
||||
|
||||
RemCompDeferred<CP14ReligionPendingFollowerComponent>(pending);
|
||||
SendMessageToGods(pending.Comp.Religion.Value, Loc.GetString("cp14-become-follower-message", ("name", MetaData(pending).EntityName)), pending);
|
||||
|
||||
_actions.AddAction(pending, ref follower.RenounceAction, follower.RenounceActionProto);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ToDisbelieve(EntityUid target)
|
||||
{
|
||||
if (!TryComp<CP14ReligionFollowerComponent>(target, out var follower))
|
||||
return;
|
||||
|
||||
if (follower.Religion is null)
|
||||
return;
|
||||
|
||||
if (!_proto.TryIndex(follower.Religion, out var indexedReligion))
|
||||
return;
|
||||
|
||||
SendMessageToGods(follower.Religion.Value, Loc.GetString("cp14-remove-follower-message", ("name", MetaData(target).EntityName)), target);
|
||||
EditObservation(target, follower.Religion.Value, -indexedReligion.FollowerObservationRadius);
|
||||
|
||||
var oldReligion = follower.Religion;
|
||||
follower.Religion = null;
|
||||
if (oldReligion is not null)
|
||||
follower.RejectedReligions.Add(oldReligion.Value);
|
||||
|
||||
var ev = new CP14ReligionChangedEvent(oldReligion, null);
|
||||
RaiseLocalEvent(target, ev);
|
||||
|
||||
Dirty(target, follower);
|
||||
|
||||
_actions.RemoveAction(target, follower.RenounceAction);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class CP14BreakDivineOfferEvent : BaseAlertEvent;
|
||||
|
||||
public sealed partial class CP14RenounceFromGodEvent : InstantActionEvent;
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Systems;
|
||||
|
||||
public abstract partial class CP14SharedReligionGodSystem
|
||||
{
|
||||
private void InitializeObservation()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ReligionEntityComponent, InRangeOverrideEvent>(OnGodInRange);
|
||||
SubscribeLocalEvent<CP14ReligionEntityComponent, MenuVisibilityEvent>(OnGodMenu);
|
||||
}
|
||||
|
||||
private void OnGodInRange(Entity<CP14ReligionEntityComponent> ent, ref InRangeOverrideEvent args)
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
args.InRange = InVision(args.Target, ent);
|
||||
}
|
||||
|
||||
private void OnGodMenu(Entity<CP14ReligionEntityComponent> ent, ref MenuVisibilityEvent args)
|
||||
{
|
||||
args.Visibility &= ~MenuVisibility.NoFov;
|
||||
}
|
||||
|
||||
public void EditObservation(EntityUid target, ProtoId<CP14ReligionPrototype> religion, float range)
|
||||
{
|
||||
EnsureComp<CP14ReligionObserverComponent>(target, out var observer);
|
||||
|
||||
if (observer.Observation.ContainsKey(religion))
|
||||
{
|
||||
var newRange = Math.Clamp(observer.Observation[religion] + range, 0, float.MaxValue);
|
||||
|
||||
if (newRange <= 0)
|
||||
{
|
||||
observer.Observation.Remove(religion);
|
||||
}
|
||||
else
|
||||
{
|
||||
observer.Observation[religion] = newRange;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, add a new observation for the religion.
|
||||
observer.Observation.Add(religion, range);
|
||||
}
|
||||
Dirty(target, observer);
|
||||
}
|
||||
|
||||
public bool InVision(EntityUid target, Entity<CP14ReligionEntityComponent> user)
|
||||
{
|
||||
var position = Transform(target).Coordinates;
|
||||
|
||||
return InVision(position, user);
|
||||
}
|
||||
|
||||
public bool InVision(EntityCoordinates coords, Entity<CP14ReligionEntityComponent> user)
|
||||
{
|
||||
if (!HasComp<CP14ReligionVisionComponent>(user))
|
||||
return true;
|
||||
|
||||
var userXform = Transform(user);
|
||||
var query = EntityQueryEnumerator<CP14ReligionObserverComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var uid, out var observer, out var xform))
|
||||
{
|
||||
if (!observer.Active)
|
||||
continue;
|
||||
|
||||
if (xform.MapID != userXform.MapID)
|
||||
continue;
|
||||
|
||||
if (user.Comp.Religion is null)
|
||||
continue;
|
||||
|
||||
if (!observer.Observation.ContainsKey(user.Comp.Religion.Value))
|
||||
continue;
|
||||
|
||||
|
||||
var obsPos = _transform.GetWorldPosition(uid);
|
||||
var targetPos = coords.Position;
|
||||
if (Vector2.Distance(obsPos, targetPos) <= observer.Observation[user.Comp.Religion.Value])
|
||||
{
|
||||
// If the observer is within range of the target, they can see it.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Systems;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum CP14ReligionEntityUiKey
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14ReligionEntityUiState(Dictionary<NetEntity, string> altars, Dictionary<NetEntity, string> followers, float followerPercentage) : BoundUserInterfaceState
|
||||
{
|
||||
public Dictionary<NetEntity, string> Altars = altars;
|
||||
public Dictionary<NetEntity, string> Followers = followers;
|
||||
public float FollowerPercentage = followerPercentage;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14ReligionEntityTeleportAttempt(NetEntity entity) : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly NetEntity Entity = entity;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Religion.Systems;
|
||||
|
||||
public abstract partial class CP14SharedReligionGodSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
InitializeObservation();
|
||||
InitializeFollowers();
|
||||
InitializeAltars();
|
||||
}
|
||||
|
||||
public HashSet<Entity<CP14ReligionEntityComponent>> GetGods(ProtoId<CP14ReligionPrototype> religion)
|
||||
{
|
||||
HashSet<Entity<CP14ReligionEntityComponent>> gods = new();
|
||||
|
||||
var query = EntityQueryEnumerator<CP14ReligionEntityComponent>();
|
||||
while (query.MoveNext(out var uid, out var god))
|
||||
{
|
||||
if (god.Religion != religion)
|
||||
continue;
|
||||
|
||||
gods.Add(new Entity<CP14ReligionEntityComponent>(uid, god));
|
||||
}
|
||||
|
||||
return gods;
|
||||
}
|
||||
|
||||
protected abstract void SendMessageToGods(ProtoId<CP14ReligionPrototype> religion, string msg, EntityUid source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// It is invoked on altars and followers when they change their religion.
|
||||
/// </summary>
|
||||
public sealed class CP14ReligionChangedEvent(ProtoId<CP14ReligionPrototype>? oldRel, ProtoId<CP14ReligionPrototype>? newRel) : EntityEventArgs
|
||||
{
|
||||
public ProtoId<CP14ReligionPrototype>? OldReligion = oldRel;
|
||||
public ProtoId<CP14ReligionPrototype>? NewReligion = newRel;
|
||||
}
|
||||
@@ -174,6 +174,10 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
if (HaveSkill(target, skill, component))
|
||||
return false;
|
||||
|
||||
//Check if the skill is in the available skill trees
|
||||
if (!component.AvailableSkillTrees.Contains(skill.Tree))
|
||||
return false;
|
||||
|
||||
//Check max cap
|
||||
if (component.SkillsSumExperience + skill.LearnCost > component.ExperienceMaxCap)
|
||||
return false;
|
||||
|
||||
@@ -51,58 +51,16 @@ public abstract partial class CP14SharedSkillSystem
|
||||
|
||||
var target = args.Target;
|
||||
|
||||
//Add Skill
|
||||
foreach (var skill in _allSkills)
|
||||
{
|
||||
if (ent.Comp.LearnedSkills.Contains(skill))
|
||||
continue;
|
||||
|
||||
var name = Loc.GetString(GetSkillName(skill));
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = name,
|
||||
Message = name + ": " + Loc.GetString(GetSkillDescription(skill)),
|
||||
Category = VerbCategory.CP14AdminSkillAdd,
|
||||
Icon = skill.Icon,
|
||||
Act = () =>
|
||||
{
|
||||
TryAddSkill(target, skill);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
//Remove Skill
|
||||
foreach (var skill in ent.Comp.LearnedSkills)
|
||||
{
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
continue;
|
||||
|
||||
var name = Loc.GetString(GetSkillName(skill));
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = name,
|
||||
Message = name + ": " + Loc.GetString(GetSkillDescription(skill)),
|
||||
Category = VerbCategory.CP14AdminSkillRemove,
|
||||
Icon = indexedSkill.Icon,
|
||||
Act = () =>
|
||||
{
|
||||
TryRemoveSkill(target, skill);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
//Reset/Remove All Skills
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = "Reset skills",
|
||||
Message = "Remove all learned skills",
|
||||
Category = VerbCategory.CP14AdminSkillRemove,
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/_CP14/Interface/Misc/reroll.rsi"), "reroll"),
|
||||
Act = () =>
|
||||
{
|
||||
TryResetSkills(target);
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,15 @@ namespace Content.Shared._CP14.Skill.Components;
|
||||
[Access(typeof(CP14SharedSkillSystem), typeof(CP14SharedResearchSystem))]
|
||||
public sealed partial class CP14SkillStorageComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Skill trees displayed in the skill tree interface. Only skills from these trees can be learned by this player.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public HashSet<ProtoId<CP14SkillTreePrototype>> AvailableSkillTrees = new();
|
||||
|
||||
/// <summary>
|
||||
/// Tracks skills that are learned without spending memory points.
|
||||
/// the skills that are here are DUBLED in the LearnedSkills,
|
||||
/// the skills that are here are DOUBLED in the LearnedSkills,
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<ProtoId<CP14SkillPrototype>> FreeLearnedSkills = new();
|
||||
|
||||
@@ -41,7 +41,4 @@ public sealed partial class CP14SkillTreePrototype : IPrototype
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier LearnSound = new SoundCollectionSpecifier("CP14LearnSkill");
|
||||
|
||||
[DataField]
|
||||
public SpriteSpecifier? Icon = null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Restrictions;
|
||||
|
||||
public sealed partial class GodFollowerPercentage : CP14SkillRestriction
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 Percentage = 0.5f;
|
||||
public override bool Check(IEntityManager entManager, EntityUid target, CP14SkillPrototype skill)
|
||||
{
|
||||
if (!entManager.TryGetComponent<CP14ReligionEntityComponent>(target, out var god))
|
||||
return false;
|
||||
|
||||
if (god.Religion is null)
|
||||
return false;
|
||||
|
||||
return god.FollowerPercentage >= Percentage;
|
||||
}
|
||||
|
||||
public override string GetDescription(IEntityManager entManager, IPrototypeManager protoManager)
|
||||
{
|
||||
return Loc.GetString("cp14-skill-req-god-follower-percentage", ("count", Percentage * 100));
|
||||
}
|
||||
}
|
||||
1
Resources/Locale/en-US/_CP14/headset/radio.ftl
Normal file
@@ -0,0 +1 @@
|
||||
cp14-chat-radio-gods = Divine
|
||||
@@ -11,4 +11,7 @@ department-CP14Guard = Guards
|
||||
department-CP14Guard-desc = Protectors and warriors who oversee security and law and order in all corners of the Empire.
|
||||
|
||||
department-CP14Artisan = Artisans
|
||||
department-CP14Artisan-desc = People who have learnt peaceful professions, people who help the settlement with their knowledge and skills.
|
||||
department-CP14Artisan-desc = People who have learnt peaceful professions, people who help the settlement with their knowledge and skills.
|
||||
|
||||
department-CP14Demigods = Patrons
|
||||
department-CP14Demigods-desc = Higher beings playing their own games, where ordinary creatures are merely pawns in their plans.
|
||||
@@ -34,4 +34,12 @@ cp14-job-name-blacksmith = Blacksmith
|
||||
cp14-job-desc-blacksmith = Create and improve equipment for everyone in need! You have the power of metal and fire in your hands, and only you know how to use them carefully to create masterpieces.
|
||||
|
||||
cp14-job-name-apprentice = Apprentice
|
||||
cp14-job-desc-apprentice = A peaceful citizen of the empire, just beginning to learn the subtleties of various sciences. Choose a specialisation in equipment, and try to help others in their work, in exchange for a salary and invaluable experience.
|
||||
cp14-job-desc-apprentice = A peaceful citizen of the empire, just beginning to learn the subtleties of various sciences. Try to help others in their work, in exchange for a salary and invaluable experience.
|
||||
|
||||
# Demigods
|
||||
|
||||
cp14-job-name-god-merkas = Merkas
|
||||
cp14-job-desc-god-merkas = God of purity and healing. TODO
|
||||
|
||||
cp14-job-name-god-lumera = Lumera
|
||||
cp14-job-desc-god-lumera = Patroness of the night and the starry sky. TODO
|
||||
19
Resources/Locale/en-US/_CP14/religion/altar.ftl
Normal file
@@ -0,0 +1,19 @@
|
||||
cp14-altar-wrapped-message = [bold]{$name}[/bold] prays, {$msg}
|
||||
cp14-offer-soul-god-message = [bold]{$name}[/bold] [color=green]wants to become your follower[/color]. Touch him to establish a connection.
|
||||
cp14-unoffer-soul-god-message = [bold]{$name}[/bold] [color=red]has changed his mind about becoming your follower.[/color]
|
||||
cp14-become-follower-message = [bold]{$name}[/bold] [color=green]becomes your follower[/color]!
|
||||
cp14-remove-follower-message = [bold]{$name}[/bold] [color=red]rejects you and will never be able to return to you![/color]
|
||||
|
||||
cp14-renounce-action-popup = YOU ARE RENOUNCING YOUR PATRON! To confirm, perform the action again.
|
||||
cp-renounce-action-god-popup = YOU ARE REJECTING YOUR FOLLOWER! To confirm, perform the action again.
|
||||
|
||||
cp14-god-ui-title = Fast Travel
|
||||
cp14-god-ui-follower = Followers
|
||||
cp14-god-ui-altars = Altars
|
||||
cp14-god-ui-follower-percentage = Follower percentage: {$count}%
|
||||
|
||||
cp14-altar-become-follower = Become a follower
|
||||
cp14-altar-become-follower-desc = You offer yourself into the service of your patron. If he agrees, your bond will be strengthened.
|
||||
|
||||
cp14-alert-offer = Offer of patronage
|
||||
cp14-alert-offer-desc = You want to become a follower of the patron, but there is no response from him yet. Click to cancel the offer.
|
||||
@@ -1,4 +1,5 @@
|
||||
cp14-skill-req-prerequisite = Skill "{$name}" must be learned
|
||||
cp14-skill-req-species = You must be the race of “{$name}”
|
||||
cp14-skill-req-researched = A study needs to be done on the research table
|
||||
cp14-skill-req-impossible = Unable to explore during a round at the current moment
|
||||
cp14-skill-req-impossible = Unable to explore during a round at the current moment
|
||||
cp14-skill-req-god-follower-percentage = The number of your followers should be more than {$count}%
|
||||
3
Resources/Locale/en-US/_CP14/skill/skill_meta_gods.ftl
Normal file
@@ -0,0 +1,3 @@
|
||||
cp14-skill-lumera-t1-name = The origins of the secret night
|
||||
cp14-skill-lumera-t2-name = The waxing moon
|
||||
cp14-skill-lumera-t3-name = The full moon of Lumera
|
||||
1
Resources/Locale/ru-RU/_CP14/headset/radio.ftl
Normal file
@@ -0,0 +1 @@
|
||||
cp14-chat-radio-gods = Божественный
|
||||
@@ -11,4 +11,7 @@ department-CP14Guard = Стража
|
||||
department-CP14Guard-desc = Защитники и войны, следящие за безопасностью и правопорядком во всех уголках империи.
|
||||
|
||||
department-CP14Artisan = Ремесленники
|
||||
department-CP14Artisan-desc = Освоившие мирные профессии, люди, которые помогают поселению своими знаниями и умениями.
|
||||
department-CP14Artisan-desc = Освоившие мирные профессии, люди, которые помогают поселению своими знаниями и умениями.
|
||||
|
||||
department-CP14Demigods = Покровители
|
||||
department-CP14Demigods-desc = Высшие сущности, играющие в свои собственные игры, где обычные существа лишь пешки в их планах.
|
||||
@@ -34,4 +34,12 @@ cp14-job-name-blacksmith = Кузнец
|
||||
cp14-job-desc-blacksmith = Создавайте и улучшайте экипировку для всех нуждающихся! В ваших руках мощь металла и огня, и только вы знаете как аккуратно использовать их, чтобы создавать шедевры.
|
||||
|
||||
cp14-job-name-apprentice = Подмастерье
|
||||
cp14-job-desc-apprentice = Мирный житель империи, только начинающий постигать тонкости различных наук. Выберите специализацию в экипировке, и постарайтесь помочь другим в их работе, в обмен на зарплату и бесценный опыт.
|
||||
cp14-job-desc-apprentice = Мирный житель империи, только начинающий постигать тонкости различных наук. Постарайтесь помочь другим в их работе, в обмен на зарплату и бесценный опыт.
|
||||
|
||||
# Demigods
|
||||
|
||||
cp14-job-name-god-merkas = Меркас
|
||||
cp14-job-desc-god-merkas = Бог света и исцеления. TODO
|
||||
|
||||
cp14-job-name-god-lumera = Лумера
|
||||
cp14-job-desc-god-lumera = Покровительница ночи и звёздного неба. TODO
|
||||
19
Resources/Locale/ru-RU/_CP14/religion/altar.ftl
Normal file
@@ -0,0 +1,19 @@
|
||||
cp14-altar-wrapped-message = [bold]{$name}[/bold] молится, {$msg}
|
||||
cp14-offer-soul-god-message = [bold]{$name}[/bold] [color=green]хочет стать вашим последователем[/color]. Прикоснитесь к нему, чтобы установить связь.
|
||||
cp14-unoffer-soul-god-message = [bold]{$name}[/bold] [color=red]передумал становиться вашим последователем.[/color]
|
||||
cp14-become-follower-message = [bold]{$name}[/bold] [color=green]становится вашим последователем[/color]!
|
||||
cp14-remove-follower-message = [bold]{$name}[/bold] [color=red]отвергает вас, и больше никогда не сможет вернться к вам![/color]
|
||||
|
||||
cp14-renounce-action-popup = ВЫ ОТРЕКАЕТЕСЬ ОТ ПОКРОВИТЕЛЯ! Для подтверждения выполните действие еще раз.
|
||||
cp-renounce-action-god-popup = ВЫ ОТВЕРГАЕТЕ СВОЕГО ПОСЛЕДОВАТЕЛЯ! Для подтверждения выполните действие еще раз.
|
||||
|
||||
cp14-god-ui-title = Быстрое перемещение
|
||||
cp14-god-ui-follower = Последователи
|
||||
cp14-god-ui-altars = Алтари
|
||||
cp14-god-ui-follower-percentage = Процент последователей: {$count}%
|
||||
|
||||
cp14-altar-become-follower = Стать последователем
|
||||
cp14-altar-become-follower-desc = Вы предлагаете себя в службу покровителю. Если он согласится, ваша связь укрепится.
|
||||
|
||||
cp14-alert-offer = Предложение о покровительстве
|
||||
cp14-alert-offer-desc = Вы хотите стать последователем покровителя, но пока от него нет ответа. Нажмите, чтобы отменить предложение.
|
||||
@@ -1,4 +1,5 @@
|
||||
cp14-skill-req-prerequisite = Навык "{$name}" должен быть изучен
|
||||
cp14-skill-req-species = Вы должны быть расы "{$name}"
|
||||
cp14-skill-req-researched = Необходимо провести исследование на исследовательском столе
|
||||
cp14-skill-req-impossible = Невозможно изучить во время раунда на текущий момент
|
||||
cp14-skill-req-impossible = Невозможно изучить во время раунда на текущий момент
|
||||
cp14-skill-req-god-follower-percentage = Количество ваших последователей должно быть больше {$count}%
|
||||
3
Resources/Locale/ru-RU/_CP14/skill/skill_meta_gods.ftl
Normal file
@@ -0,0 +1,3 @@
|
||||
cp14-skill-lumera-t1-name = Истоки тайной ночи
|
||||
cp14-skill-lumera-t2-name = Растущая луна
|
||||
cp14-skill-lumera-t3-name = Полнолуние Лумеры
|
||||
@@ -48,3 +48,11 @@
|
||||
name: alerts-hunger-name
|
||||
description: alerts-hunger-desc
|
||||
|
||||
- type: alert
|
||||
id: CP14DivineOffer
|
||||
icons:
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/divine_offer.rsi
|
||||
state: offer
|
||||
name: cp14-alert-offer
|
||||
description: cp14-alert-offer-desc
|
||||
clickEvent: !type:CP14BreakDivineOfferEvent
|
||||
@@ -0,0 +1,45 @@
|
||||
- type: entity
|
||||
id: CP14ActionSpellGodLumeraRenounce
|
||||
name: Renunciation of a follower
|
||||
description: You are rejecting the chosen follower. They lose the opportunity to become your follower at any time.
|
||||
components:
|
||||
- type: CP14MagicEffect
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
- CP14LumeraRenounceImpact
|
||||
- !type:CP14SpellGodRenounce
|
||||
- type: ConfirmableAction
|
||||
popup: cp-renounce-action-god-popup
|
||||
- type: EntityWorldTargetAction
|
||||
repeat: true
|
||||
checkCanAccess: false
|
||||
itemIconStyle: BigAction
|
||||
range: 100
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Magic/rumble.ogg
|
||||
icon:
|
||||
sprite: _CP14/Actions/DemigodSpells/lumera.rsi
|
||||
state: renounce
|
||||
event: !type:CP14EntityWorldTargetActionEvent
|
||||
cooldown: 0.5
|
||||
|
||||
- type: entity
|
||||
id: CP14LumeraRenounceImpact
|
||||
categories: [ ForkFiltered ]
|
||||
parent: CP14BaseMagicImpact
|
||||
save: false
|
||||
components:
|
||||
- type: PointLight
|
||||
color: "#94154e"
|
||||
enabled: true
|
||||
radius: 5
|
||||
energy: 4
|
||||
netsync: false
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: stars
|
||||
color: "#94154e"
|
||||
shader: unshaded
|
||||
- type: LightFade
|
||||
duration: 1
|
||||
@@ -0,0 +1,49 @@
|
||||
- type: entity
|
||||
id: CP14ActionSpellGodLumeraTouch
|
||||
name: Touch of Lumera
|
||||
description: "Multitasking effects on the world: depending on what you click on, the effect may vary. Using it on an empty space will create a glowing sign that attracts the attention of mortals."
|
||||
components:
|
||||
- type: CP14MagicEffectReligionRestricted
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 5
|
||||
- type: CP14MagicEffect
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
- CP14LumeraTouchImpact
|
||||
- !type:CP14SpellGodTouch
|
||||
- !type:CP14SpellApplyEntityEffect
|
||||
effects:
|
||||
- !type:Jitter
|
||||
- type: EntityWorldTargetAction
|
||||
repeat: true
|
||||
checkCanAccess: false
|
||||
itemIconStyle: BigAction
|
||||
range: 100
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Magic/rumble.ogg
|
||||
icon:
|
||||
sprite: _CP14/Actions/DemigodSpells/lumera.rsi
|
||||
state: touch
|
||||
event: !type:CP14EntityWorldTargetActionEvent
|
||||
cooldown: 0.5
|
||||
|
||||
- type: entity
|
||||
id: CP14LumeraTouchImpact
|
||||
categories: [ ForkFiltered ]
|
||||
parent: CP14BaseMagicImpact
|
||||
save: false
|
||||
components:
|
||||
- type: PointLight
|
||||
color: "#3843a8"
|
||||
enabled: true
|
||||
radius: 5
|
||||
energy: 4
|
||||
netsync: false
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: stars
|
||||
color: "#3843a8"
|
||||
shader: unshaded
|
||||
- type: LightFade
|
||||
duration: 1
|
||||
@@ -0,0 +1,12 @@
|
||||
- type: entity
|
||||
id: CP14ActionSpellGodLumeraWarp
|
||||
name: Fast travel
|
||||
description: Allows you to quickly teleport to your altars and followers.
|
||||
components:
|
||||
- type: InstantAction
|
||||
icon:
|
||||
sprite: _CP14/Actions/DemigodSpells/lumera.rsi
|
||||
state: warp
|
||||
priority: -8
|
||||
event: !type:ToggleIntrinsicUIEvent
|
||||
key: enum.CP14ReligionEntityUiKey.Key
|
||||
@@ -0,0 +1,13 @@
|
||||
- type: entity
|
||||
id: CP14ActionRenounceFromGod
|
||||
name: Renounce patron
|
||||
description: You renounce your patron by severing your connection with him. After that, you can never become his follower again, but you can become a follower of another patron.
|
||||
components:
|
||||
- type: InstantAction
|
||||
icon:
|
||||
sprite: _CP14/Interface/Alerts/divine_offer.rsi
|
||||
state: unoffer
|
||||
priority: -8
|
||||
event: !type:CP14RenounceFromGodEvent
|
||||
- type: ConfirmableAction
|
||||
popup: cp14-renounce-action-popup
|
||||
@@ -0,0 +1,113 @@
|
||||
- type: entity
|
||||
id: CP14MobGodBase
|
||||
parent:
|
||||
- Incorporeal
|
||||
- BaseMob
|
||||
- CP14MobMagical
|
||||
name: god
|
||||
description: The supreme entity formed from the beliefs, desires, and fears of the human race.
|
||||
abstract: true
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _CP14/Mobs/Demigods/temp_icons.rsi
|
||||
color: "#ffffff99"
|
||||
- type: PointLight
|
||||
radius: 10
|
||||
softness: 1
|
||||
castShadows: false
|
||||
- type: Input
|
||||
context: "ghost"
|
||||
- type: Spectral
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 3
|
||||
baseSprintSpeed: 6
|
||||
friction: 0.5
|
||||
acceleration: 3
|
||||
- type: NoSlip
|
||||
- type: Eye
|
||||
drawFov: false
|
||||
visMask:
|
||||
- Normal
|
||||
- Ghost
|
||||
- type: Visibility
|
||||
layer: 2 #ghost vis layer
|
||||
- type: ContentEye
|
||||
maxZoom: 1.2, 1.2
|
||||
- type: Speech
|
||||
speechVerb: Ghost
|
||||
- type: CP14ReligionVision
|
||||
- type: CP14MagicEnergyContainer
|
||||
magicAlert: CP14MagicEnergy
|
||||
maxEnergy: 1000
|
||||
energy: 1000
|
||||
unsafeSupport: false
|
||||
- type: CP14MagicEnergyDraw
|
||||
energy: 5
|
||||
delay: 6 # 20m to full restore
|
||||
- type: IntrinsicRadioTransmitter
|
||||
channels:
|
||||
- CP14Gods
|
||||
- type: IntrinsicRadioReceiver
|
||||
- type: ActiveRadio
|
||||
receiveAllChannels: true
|
||||
globalReceive: true
|
||||
channels:
|
||||
- CP14Gods
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionZLevelUp
|
||||
- CP14ActionZLevelDown
|
||||
- ActionToggleLighting
|
||||
- ActionToggleFov
|
||||
- type: CP14DemiplaneStabilizer # teleports gods outside when the demiplane closes
|
||||
enabled: false
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.CP14ReligionEntityUiKey.Key:
|
||||
type: CP14ReligionEntityBoundUserInterface
|
||||
|
||||
- type: entity
|
||||
parent: CP14MobGodBase
|
||||
id: CP14MobGodMerkas
|
||||
name: Merkas
|
||||
categories: [ HideSpawnMenu ]
|
||||
description: Merkas is the god of purity and healing. In his presence, decay is destroyed. He does not save — he purifies. Those who remain can start anew.
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: merkas
|
||||
shader: unshaded
|
||||
- type: PointLight
|
||||
color: "#9bf2b5"
|
||||
- type: CP14SkillStorage
|
||||
availableSkillTrees:
|
||||
- GodMerkas
|
||||
- type: CP14ReligionEntity
|
||||
religion: Merkas
|
||||
- type: CP14ReligionVision
|
||||
shaderColor: 0.02, 0.36, 0.05
|
||||
|
||||
- type: entity
|
||||
parent: CP14MobGodBase
|
||||
id: CP14MobGodLumera
|
||||
name: Lumera
|
||||
description: The goddess of the night and the night sky. Her stars hold so many secrets, which she protects with her wings.
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: lumera
|
||||
shader: unshaded
|
||||
- type: PointLight
|
||||
color: "#4367ba"
|
||||
- type: CP14SkillStorage
|
||||
availableSkillTrees:
|
||||
- GodLumera
|
||||
- type: CP14ReligionEntity
|
||||
religion: Lumera
|
||||
- type: CP14ReligionVision
|
||||
shaderColor: 0.29, 0.66, 0.87
|
||||
- type: IntrinsicUI
|
||||
uis:
|
||||
enum.CP14ReligionEntityUiKey.Key:
|
||||
toggleAction: CP14ActionSpellGodLumeraWarp
|
||||
@@ -231,7 +231,6 @@
|
||||
types:
|
||||
Cold: 0.25
|
||||
Bloodloss: 0.25
|
||||
- type: CP14SkillStorage
|
||||
- type: CP14TradingReputation
|
||||
|
||||
|
||||
|
||||
@@ -57,6 +57,16 @@
|
||||
delay: 3 # 5m to full restore
|
||||
- type: CP14MagicUnsafeDamage
|
||||
- type: CP14MagicUnsafeSleep
|
||||
- type: CP14SkillStorage
|
||||
availableSkillTrees:
|
||||
- Pyrokinetic
|
||||
- Hydrosophistry
|
||||
- Illusion
|
||||
- Metamagic
|
||||
- Healing
|
||||
- Atlethic
|
||||
- MartialArts
|
||||
- Craftsmanship
|
||||
|
||||
|
||||
- type: entity
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
- CP14BaseStationCommonObjectives
|
||||
- CP14BaseStationDemiplaneMap
|
||||
- CP14BaseStationEconomy
|
||||
#- CP14BaseStationGods
|
||||
|
||||
- type: entity
|
||||
id: CP14BaseStationCommonObjectives
|
||||
@@ -35,3 +36,16 @@
|
||||
abstract: true
|
||||
components:
|
||||
- type: CP14StationEconomy
|
||||
|
||||
#- type: entity
|
||||
# id: CP14BaseStationGods
|
||||
# abstract: true
|
||||
# components:
|
||||
# - type: CP14StationRandomJobs
|
||||
# entries:
|
||||
# - jobs:
|
||||
# - CP14GodMerkas
|
||||
# - CP14GodLumera
|
||||
# count:
|
||||
# min: 2
|
||||
# max: 2
|
||||
@@ -470,4 +470,3 @@
|
||||
CP14BirchWoodLog:
|
||||
min: 3
|
||||
max: 6
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
- type: entity
|
||||
id: CP14BaseAltar
|
||||
parent: BaseStructure
|
||||
abstract: true
|
||||
name: altar
|
||||
description: TODO
|
||||
categories: [ ForkFiltered ]
|
||||
components:
|
||||
- type: Sprite
|
||||
noRot: true
|
||||
drawdepth: Mobs
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.45,-0.45,0.45,0.45"
|
||||
density: 60
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: CP14ReligionAltar
|
||||
- type: ActiveListener
|
||||
range: 1
|
||||
|
||||
- type: entity
|
||||
parent: CP14BaseAltar
|
||||
id: CP14BaseAltarPrimordial
|
||||
abstract: true
|
||||
components:
|
||||
- type: CP14ReligionAltar
|
||||
canBeConverted: false
|
||||
- type: SpawnPoint
|
||||
spawn_type: Always
|
||||
@@ -0,0 +1,35 @@
|
||||
- type: entity
|
||||
parent: CP14BaseAltarPrimordial
|
||||
id: CP14AltarPrimordialGodLumera
|
||||
name: primordial statue of Lumera
|
||||
description: "The enchanting statue of Lumera, patroness of the starry sky, night, and mysteries. She does not demand worship—she simply observes. And waits for you to ask."
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Structures/Furniture/Altars/Gods/convertaltar.rsi
|
||||
layers:
|
||||
- state: white
|
||||
- type: CP14ReligionAltar
|
||||
religion: Lumera
|
||||
- type: CP14ReligionObserver
|
||||
observation:
|
||||
Lumera: 25
|
||||
- type: SpawnPoint
|
||||
job_id: CP14GodLumera
|
||||
|
||||
- type: entity
|
||||
parent: CP14BaseAltarPrimordial
|
||||
id: CP14AltarPrimordialGodMerkas
|
||||
name: primordial statue of Merkas
|
||||
description: A beautiful, overgrown statue of Sylvania, revered as a goddess of nature.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Structures/Furniture/Altars/Gods/nanotrasen.rsi
|
||||
layers:
|
||||
- state: druid
|
||||
- type: CP14ReligionAltar
|
||||
religion: Merkas
|
||||
- type: CP14ReligionObserver
|
||||
observation:
|
||||
Merkas: 25
|
||||
- type: SpawnPoint
|
||||
job_id: CP14GodMerkas
|
||||
5
Resources/Prototypes/_CP14/Religion/religions.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
- type: cp14Religion
|
||||
id: Merkas
|
||||
|
||||
- type: cp14Religion
|
||||
id: Lumera
|
||||
16
Resources/Prototypes/_CP14/Roles/Jobs/Demigods/lumera.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
- type: job
|
||||
id: CP14GodLumera
|
||||
name: cp14-job-name-god-lumera
|
||||
description: cp14-job-desc-god-lumera
|
||||
setPreference: false
|
||||
playTimeTracker: CP14GodLumera
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 36000 # 10 hrs
|
||||
canBeAntag: false
|
||||
icon: CP14JobIconGodLumera
|
||||
jobEntity: CP14MobGodLumera
|
||||
joinNotifyCrew: false
|
||||
requireAdminNotify: true
|
||||
jobPreviewEntity: CP14MobGodLumera
|
||||
applyTraits: false
|
||||
16
Resources/Prototypes/_CP14/Roles/Jobs/Demigods/merkas.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
- type: job
|
||||
id: CP14GodMerkas
|
||||
name: cp14-job-name-god-merkas
|
||||
description: cp14-job-desc-god-merkas
|
||||
setPreference: false
|
||||
playTimeTracker: CP14GodMerkas
|
||||
requirements:
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 36000 # 10 hrs
|
||||
canBeAntag: false
|
||||
icon: CP14JobIconGodMerkas
|
||||
jobEntity: CP14MobGodMerkas
|
||||
joinNotifyCrew: false
|
||||
requireAdminNotify: true
|
||||
jobPreviewEntity: CP14MobGodMerkas
|
||||
applyTraits: false
|
||||
@@ -1,3 +1,14 @@
|
||||
- type: department
|
||||
id: CP14Demigods
|
||||
name: department-CP14Demigods
|
||||
description: department-CP14Demigods-desc
|
||||
weight: 666 # >:)
|
||||
color: "#ffffff"
|
||||
editorHidden: true #temp
|
||||
roles:
|
||||
- CP14GodLumera
|
||||
- CP14GodMerkas
|
||||
|
||||
- type: department
|
||||
id: CP14Command
|
||||
name: department-CP14Command
|
||||
@@ -5,6 +16,7 @@
|
||||
primary: false
|
||||
weight: 10
|
||||
color: "#3ec8fa"
|
||||
editorHidden: true #temp
|
||||
roles:
|
||||
- CP14GuardCommander
|
||||
- CP14Guildmaster
|
||||
@@ -15,6 +27,7 @@
|
||||
description: department-CP14Guard-desc
|
||||
weight: 9
|
||||
color: "#576384"
|
||||
editorHidden: true #temp
|
||||
roles:
|
||||
- CP14GuardCommander
|
||||
- CP14Guard
|
||||
@@ -40,5 +53,4 @@
|
||||
color: "#588151"
|
||||
roles:
|
||||
- CP14Guildmaster
|
||||
- CP14Adventurer
|
||||
|
||||
- CP14Adventurer
|
||||
@@ -37,3 +37,9 @@
|
||||
- type: playTimeTracker
|
||||
id: CP14JobMerchant
|
||||
|
||||
# Gods
|
||||
- type: playTimeTracker
|
||||
id: CP14GodMerkas
|
||||
|
||||
- type: playTimeTracker
|
||||
id: CP14GodLumera
|
||||
@@ -19,3 +19,8 @@
|
||||
FalloffStrength: 0.75
|
||||
FalloffPow: 3.0
|
||||
HDR: 1.5
|
||||
|
||||
- type: shader
|
||||
id: CP14ReligionVision
|
||||
kind: source
|
||||
path: "/Textures/_CP14/Shaders/religion.swsl"
|
||||
@@ -3,72 +3,48 @@
|
||||
name: cp14-skill-tree-pyrokinetic-name
|
||||
desc: cp14-skill-tree-pyrokinetic-desc
|
||||
color: "#d6933c"
|
||||
icon:
|
||||
sprite: _CP14/Actions/skill_tree.rsi
|
||||
state: pyro
|
||||
|
||||
- type: cp14SkillTree
|
||||
id: Hydrosophistry
|
||||
name: cp14-skill-tree-hydrosophistry-name
|
||||
desc: cp14-skill-tree-hydrosophistry-desc
|
||||
color: "#1554a1"
|
||||
icon:
|
||||
sprite: _CP14/Actions/skill_tree.rsi
|
||||
state: water
|
||||
|
||||
- type: cp14SkillTree
|
||||
id: Illusion
|
||||
name: cp14-skill-tree-illusion-name
|
||||
desc: cp14-skill-tree-illusion-desc
|
||||
color: "#f55faf"
|
||||
icon:
|
||||
sprite: _CP14/Actions/skill_tree.rsi
|
||||
state: light
|
||||
|
||||
- type: cp14SkillTree
|
||||
id: Metamagic
|
||||
name: cp14-skill-tree-metamagic-name
|
||||
desc: cp14-skill-tree-metamagic-desc
|
||||
color: "#56e5f5"
|
||||
icon:
|
||||
sprite: _CP14/Actions/skill_tree.rsi
|
||||
state: meta
|
||||
|
||||
- type: cp14SkillTree
|
||||
id: Healing
|
||||
name: cp14-skill-tree-healing-name
|
||||
desc: cp14-skill-tree-healing-desc
|
||||
color: "#51cf72"
|
||||
icon:
|
||||
sprite: _CP14/Actions/skill_tree.rsi
|
||||
state: heal
|
||||
|
||||
- type: cp14SkillTree
|
||||
id: Atlethic
|
||||
name: cp14-skill-tree-atlethic-name
|
||||
desc: cp14-skill-tree-atlethic-desc
|
||||
color: "#b32e37"
|
||||
icon:
|
||||
sprite: _CP14/Actions/skill_tree.rsi
|
||||
state: atlethic
|
||||
|
||||
#- type: cp14SkillTree
|
||||
# id: Dimension
|
||||
# name: cp14-skill-tree-dimension-name
|
||||
# desc: cp14-skill-tree-dimension-desc
|
||||
# color: "#ac66be"
|
||||
# icon:
|
||||
# sprite: _CP14/Actions/skill_tree.rsi
|
||||
# state: dimension
|
||||
|
||||
- type: cp14SkillTree
|
||||
id: MartialArts
|
||||
name: cp14-skill-tree-martial-name
|
||||
desc: cp14-skill-tree-martial-desc
|
||||
color: "#f54242"
|
||||
icon:
|
||||
sprite: _CP14/Actions/skill_tree.rsi
|
||||
state: martial
|
||||
|
||||
#
|
||||
|
||||
75
Resources/Prototypes/_CP14/Skill/Demigods/lumera.yml
Normal file
@@ -0,0 +1,75 @@
|
||||
# T1
|
||||
|
||||
- type: cp14Skill
|
||||
id: LumeraT1
|
||||
skillUiPosition: 1, 0
|
||||
tree: GodLumera
|
||||
name: cp14-skill-lumera-t1-name
|
||||
learnCost: 0.5
|
||||
icon:
|
||||
sprite: _CP14/Actions/DemigodSpells/lumera.rsi
|
||||
state: t1
|
||||
|
||||
- type: cp14Skill
|
||||
id: LumeraTouch
|
||||
skillUiPosition: 0, 3
|
||||
tree: GodLumera
|
||||
learnCost: 0.0
|
||||
icon:
|
||||
sprite: _CP14/Actions/DemigodSpells/lumera.rsi
|
||||
state: touch
|
||||
effects:
|
||||
- !type:AddAction
|
||||
action: CP14ActionSpellGodLumeraTouch
|
||||
restrictions:
|
||||
- !type:NeedPrerequisite
|
||||
prerequisite: LumeraT1
|
||||
|
||||
- type: cp14Skill
|
||||
id: LumeraRenounce
|
||||
skillUiPosition: 2, 3
|
||||
tree: GodLumera
|
||||
learnCost: 0.0
|
||||
icon:
|
||||
sprite: _CP14/Actions/DemigodSpells/lumera.rsi
|
||||
state: renounce
|
||||
effects:
|
||||
- !type:AddAction
|
||||
action: CP14ActionSpellGodLumeraRenounce
|
||||
restrictions:
|
||||
- !type:NeedPrerequisite
|
||||
prerequisite: LumeraT1
|
||||
|
||||
# T2
|
||||
|
||||
- type: cp14Skill
|
||||
id: LumeraT2
|
||||
skillUiPosition: 7, 0
|
||||
tree: GodLumera
|
||||
name: cp14-skill-lumera-t2-name
|
||||
learnCost: 0.5
|
||||
icon:
|
||||
sprite: _CP14/Actions/DemigodSpells/lumera.rsi
|
||||
state: t2
|
||||
restrictions:
|
||||
- !type:NeedPrerequisite
|
||||
prerequisite: LumeraT1
|
||||
- !type:GodFollowerPercentage
|
||||
percentage: 0.3
|
||||
|
||||
# T3
|
||||
|
||||
- type: cp14Skill
|
||||
id: LumeraT3
|
||||
skillUiPosition: 13, 0
|
||||
tree: GodLumera
|
||||
name: cp14-skill-lumera-t3-name
|
||||
learnCost: 0.5
|
||||
icon:
|
||||
sprite: _CP14/Actions/DemigodSpells/lumera.rsi
|
||||
state: t3
|
||||
restrictions:
|
||||
- !type:NeedPrerequisite
|
||||
prerequisite: LumeraT2
|
||||
- !type:GodFollowerPercentage
|
||||
percentage: 0.6
|
||||
12
Resources/Prototypes/_CP14/Skill/Demigods/merkas.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
- type: cp14Skill
|
||||
id: NatureGodT1
|
||||
skillUiPosition: 1, 0
|
||||
tree: GodMerkas
|
||||
name: cp14-skill-life-t1-name
|
||||
learnCost: 0.5
|
||||
icon:
|
||||
sprite: _CP14/Actions/skill_tree.rsi
|
||||
state: heal
|
||||
effects:
|
||||
- !type:AddAction
|
||||
action: CP14ActionSpellBloodPurification
|
||||
12
Resources/Prototypes/_CP14/Skill/Demigods/trees.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
- type: cp14SkillTree
|
||||
id: GodMerkas
|
||||
name: cp14-job-name-god-merkas
|
||||
desc: cp14-job-desc-god-merkas
|
||||
color: "#51cf72"
|
||||
|
||||
- type: cp14SkillTree
|
||||
id: GodLumera
|
||||
name: cp14-job-name-god-lumera
|
||||
desc: cp14-job-desc-god-lumera
|
||||
color: "#5632a8"
|
||||
parallax: Default
|
||||
15
Resources/Prototypes/_CP14/StatusIcon/god_job.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
- type: jobIcon
|
||||
parent: CP14JobIcon
|
||||
id: CP14JobIconGodMerkas
|
||||
icon:
|
||||
sprite: /Textures/_CP14/Interface/Misc/job_god_icons.rsi
|
||||
state: Merkas
|
||||
jobName: cp14-job-name-god-merkas
|
||||
|
||||
- type: jobIcon
|
||||
parent: CP14JobIcon
|
||||
id: CP14JobIconGodLumera
|
||||
icon:
|
||||
sprite: /Textures/_CP14/Interface/Misc/job_god_icons.rsi
|
||||
state: Lumera
|
||||
jobName: cp14-job-name-god-lumera
|
||||
7
Resources/Prototypes/_CP14/radio_channels.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
- type: radioChannel
|
||||
id: CP14Gods
|
||||
name: cp14-chat-radio-gods
|
||||
keycode: 'g'
|
||||
frequency: 666
|
||||
color: "#fad634"
|
||||
longRange: true
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "All right reserved",
|
||||
"copyright": "Created by TheShuEd",
|
||||
"states": [
|
||||
{
|
||||
"name": "touch"
|
||||
},
|
||||
{
|
||||
"name": "warp"
|
||||
},
|
||||
{
|
||||
"name": "renounce"
|
||||
},
|
||||
{
|
||||
"name": "t1"
|
||||
},
|
||||
{
|
||||
"name": "t2"
|
||||
},
|
||||
{
|
||||
"name": "t3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 422 B |
BIN
Resources/Textures/_CP14/Actions/DemigodSpells/lumera.rsi/t1.png
Normal file
|
After Width: | Height: | Size: 229 B |
BIN
Resources/Textures/_CP14/Actions/DemigodSpells/lumera.rsi/t2.png
Normal file
|
After Width: | Height: | Size: 358 B |
BIN
Resources/Textures/_CP14/Actions/DemigodSpells/lumera.rsi/t3.png
Normal file
|
After Width: | Height: | Size: 375 B |
|
After Width: | Height: | Size: 359 B |
|
After Width: | Height: | Size: 477 B |
@@ -81,6 +81,21 @@
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stars",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
BIN
Resources/Textures/_CP14/Effects/Magic/cast_impact.rsi/stars.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Created by TheShuEd",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "offer",
|
||||
"directions": 1
|
||||
},
|
||||
{
|
||||
"name": "unoffer",
|
||||
"directions": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 396 B |
|
After Width: | Height: | Size: 776 B |
|
After Width: | Height: | Size: 247 B |
|
After Width: | Height: | Size: 214 B |
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 13,
|
||||
"y": 13
|
||||
},
|
||||
"license": "CC-BY-SA-4.0",
|
||||
"copyright": "Created by TheShuEd (Github)",
|
||||
"states": [
|
||||
{
|
||||
"name": "Merkas"
|
||||
},
|
||||
{
|
||||
"name": "Lumera"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/_CP14/Mobs/Demigods/temp_icons.rsi/lumera.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
Resources/Textures/_CP14/Mobs/Demigods/temp_icons.rsi/merkas.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "All right reserved",
|
||||
"copyright": "Created by Jaraten (discord/Github)",
|
||||
"size": {
|
||||
"x": 48,
|
||||
"y": 48
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "lumera",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "merkas",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||