Merge branch 'master' into ed-10-06-2025-upstream-sync

This commit is contained in:
Ed
2025-06-15 21:44:16 +03:00
230 changed files with 4770 additions and 400 deletions

View File

@@ -1,7 +0,0 @@
contact_links:
- name: Report a Security Vulnerability
url: https://github.com/space-wizards/space-station-14/blob/master/SECURITY.md
about: Please report security vulnerabilities privately so we can fix them before they are publicly disclosed.
- name: Request a Feature
url: https://discord.gg/rGvu9hKffJ
about: Submit feature requests on our Discord server (https://discord.gg/rGvu9hKffJ).

View File

@@ -1,20 +0,0 @@
---
name: Report an Issue
about: "..."
title: ''
labels: ''
assignees: ''
---
## Description
<!-- Explain your issue in detail. Issues without proper explanation are liable to be closed by maintainers. -->
**Reproduction**
<!-- Include the steps to reproduce if applicable. -->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Additional context**
<!-- Add any other context about the problem here. Anything you think is related to the issue. -->

View File

@@ -1,18 +0,0 @@
---
name: Toolshed feature request
about: Suggest a feature for Toolshed (for game admins/developers)
title: "[TOOLSHED REQUEST]"
labels: Toolshed
assignees: moonheart08
---
**Is your feature request related to a problem/bug? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the command you'd like**
A clear and concise description of what you want and what it should do.
If you're a technical user (i.e. programmer) including type signatures is helpful.
**Additional context**
Add any other context or screenshots about the feature request here.

View 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);
}
public 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;
}
}

View File

@@ -0,0 +1,34 @@
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)
{
}
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);
}
}

View 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>

View File

@@ -0,0 +1,74 @@
using System.Text;
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)
{
var sb = new StringBuilder();
sb.Append(Loc.GetString("cp14-god-ui-follower-percentage", ("count", state.FollowerPercentage * 100)) + "\n");
sb.Append(Loc.GetString("cp14-god-ui-mana-percentage", ("count", state.ManaPercentage * 100)) + "\n");
return sb.ToString();
}
}

View File

@@ -0,0 +1,146 @@
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++;
}
}
}

View File

@@ -13,6 +13,9 @@ namespace Content.Client._CP14.UserInterface.Systems.NodeTree;
[GenerateTypedNameReferences]
public sealed partial class CP14NodeTreeGraphControl : BoxContainer
{
private const float LocalUIScaleMax = 4f;
private const float LocalUIScaleMin = 1f;
[Dependency] private readonly IEntityManager _entManager = default!;
private CP14NodeTreeUiState? _state;
@@ -25,6 +28,9 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
private bool _dragging = false;
private Vector2 _previousMousePosition = Vector2.Zero;
private Vector2 _globalOffset = new (60,60);
private float _localUIScale = LocalUIScaleMin;
private float Scale => UIScale * _localUIScale;
public event Action<CP14NodeTreeElement?>? OnNodeSelected;
public event Action<Vector2>? OnOffsetChanged;
@@ -50,6 +56,16 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
OnOffsetChanged?.Invoke(_globalOffset);
}
protected override void MouseWheel(GUIMouseWheelEventArgs args)
{
base.MouseWheel(args);
if (args.Handled)
return;
_localUIScale = MathHelper.Clamp(_localUIScale + 0.1f * args.Delta.Y, LocalUIScaleMin, LocalUIScaleMax);
}
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{
base.KeyBindDown(args);
@@ -72,6 +88,7 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
if (args.Function == EngineKeyFunctions.UIRightClick)
{
_globalOffset = new Vector2(60, 60); // Reset offset on right click
_localUIScale = LocalUIScaleMin;
OnOffsetChanged?.Invoke(_globalOffset);
}
}
@@ -107,7 +124,7 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
if (_dragging)
{
var delta = cursor - _previousMousePosition;
_globalOffset += delta;
_globalOffset += delta;
OnOffsetChanged?.Invoke(_globalOffset);
}
@@ -118,8 +135,8 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
{
var node1 = _nodeDict[edge.Item1];
var node2 = _nodeDict[edge.Item2];
var fromPos = node1.UiPosition * UIScale + _globalOffset;
var toPos = node2.UiPosition * UIScale + _globalOffset;
var fromPos = node1.UiPosition * Scale + _globalOffset;
var toPos = node2.UiPosition * Scale + _globalOffset;
var lineColor = node1.Gained || node2.Gained ? _state.ActiveLineColor : _state.LineColor;
handle.DrawLine(fromPos, toPos, lineColor);
@@ -128,11 +145,11 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
//Draw Node icons over lines
foreach (var node in _state.Nodes)
{
var pos = node.UiPosition * UIScale + _globalOffset;
var pos = node.UiPosition * Scale + _globalOffset;
// Frame
var frameTexture = _state.FrameIcon.Frame0();
var frameSize = new Vector2(frameTexture.Width, frameTexture.Height) * 1.5f * UIScale;
var frameSize = new Vector2(frameTexture.Width, frameTexture.Height) * 1.5f * Scale;
var frameQuad = new UIBox2(pos - frameSize / 2, pos + frameSize / 2);
handle.DrawTextureRect(frameTexture, frameQuad);
@@ -140,7 +157,7 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
if (_selectedNode == node)
{
var selectedTexture = _state.SelectedIcon.Frame0();
var selectedSize = new Vector2(selectedTexture.Width, selectedTexture.Height) * 1.5f * UIScale;
var selectedSize = new Vector2(selectedTexture.Width, selectedTexture.Height) * 1.5f * Scale;
var selectedQuad = new UIBox2(pos - selectedSize / 2, pos + selectedSize / 2);
handle.DrawTextureRect(selectedTexture, selectedQuad);
}
@@ -151,7 +168,7 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
{
_hoveredNode = node;
var hoveredTexture = _state.HoveredIcon.Frame0();
var hoveredSize = new Vector2(hoveredTexture.Width, hoveredTexture.Height) * 1.5f * UIScale;
var hoveredSize = new Vector2(hoveredTexture.Width, hoveredTexture.Height) * 1.5f * Scale;
var hoveredQuad = new UIBox2(pos - hoveredSize / 2, pos + hoveredSize / 2);
handle.DrawTextureRect(hoveredTexture, hoveredQuad);
}
@@ -160,7 +177,7 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
if (node.Gained)
{
var learnedTexture = _state.LearnedIcon.Frame0();
var learnedSize = new Vector2(learnedTexture.Width, learnedTexture.Height) * 1.5f * UIScale;
var learnedSize = new Vector2(learnedTexture.Width, learnedTexture.Height) * 1.5f * Scale;
var learnedQuad = new UIBox2(pos - learnedSize / 2, pos + learnedSize / 2);
handle.DrawTextureRect(learnedTexture, learnedQuad);
}
@@ -169,7 +186,7 @@ public sealed partial class CP14NodeTreeGraphControl : BoxContainer
if (node.Icon is not null)
{
var baseTexture = node.Icon.Frame0();
var baseSize = new Vector2(baseTexture.Width, baseTexture.Height) * 1.5f * UIScale;
var baseSize = new Vector2(baseTexture.Width, baseTexture.Height) * 1.5f * Scale;
var baseQuad = new UIBox2(pos - baseSize / 2, pos + baseSize / 2);
var tint = node.Gained || node.Active ? Color.White : Color.FromSrgb(new Color(0.6f, 0.6f, 0.6f));
handle.DrawTextureRect(baseTexture, baseQuad, tint);

View File

@@ -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();
}

View File

@@ -401,7 +401,7 @@ namespace Content.IntegrationTests.Tests
var jobs = new HashSet<ProtoId<JobPrototype>>(comp.SetupAvailableJobs.Keys);
var spawnPoints = entManager.EntityQuery<SpawnPointComponent>()
.Where(x => x.SpawnType == SpawnPointType.Job && x.Job != null)
.Where(x => x.SpawnType is SpawnPointType.Job or SpawnPointType.Unset && x.Job != null) //CP14 Job or Unset (only Job in upstream)
.Select(x => x.Job.Value);
jobs.ExceptWith(spawnPoints);

View File

@@ -1,11 +1,11 @@
using System.Globalization;
using System.Linq;
using System.Text;
using Content.Server._CP14.Religion;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.Players.RateLimiting;
using Content.Server.Speech.Prototypes;
using Content.Server.Speech.EntitySystems;
using Content.Server.Station.Components;
@@ -193,6 +193,13 @@ public sealed partial class ChatSystem : SharedChatSystem
if (!CanSendInGame(message, shell, player))
return;
//CP14 Prevent god from default speaking. In waiting of chatcode refactor
var ev = new CP14SpokeAttemptEvent(message, desiredType, player);
RaiseLocalEvent(source, ev);
if (ev.Cancelled)
return;
//CP14 end
ignoreActionBlocker = CheckIgnoreSpeechBlocker(source, ignoreActionBlocker);
// this method is a disaster

View File

@@ -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.Unset && (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);

View File

@@ -83,26 +83,13 @@ public sealed partial class CP14DemiplaneSystem
while (query.MoveNext(out var uid, out var stabilizer, out var xform))
{
if (!stabilizer.Enabled)
continue;
if (TryTeleportOutDemiplane(demiplane, uid))
{
if (!safe)
{
var ev = new CP14DemiplaneUnsafeExit();
RaiseLocalEvent(uid, ev);
_body.GibBody(uid);
}
}
}
QueueDel(demiplane);
}
}
public sealed class CP14DemiplaneUnsafeExit : EntityEventArgs
{
}

View File

@@ -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;
@@ -114,6 +117,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;

View File

@@ -25,6 +25,9 @@ public sealed partial class CP14PassportSystem : EntitySystem
private void OnPlayerSpawning(PlayerSpawnCompleteEvent ev)
{
if (!TryComp<InventoryComponent>(ev.Mob, out var inventory))
return;
var passport = Spawn(PassportProto, Transform(ev.Mob).Coordinates);
if (!TryComp<PaperComponent>(passport, out var paper))
@@ -39,7 +42,7 @@ public sealed partial class CP14PassportSystem : EntitySystem
StampedName = Loc.GetString("cp14-passport-stamp")
},
"");
_inventory.TryEquip(ev.Mob, passport, "pocket1");
_inventory.TryEquip(ev.Mob, passport, "pocket1", inventory: inventory);
}
private string GeneratePassportText(PlayerSpawnCompleteEvent ev)

View File

@@ -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 = new();
[DataField(required: true)]
public MinMax Count = new(1, 1);
[DataField]
public float Prob = 1f;
}

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,79 @@
using Content.Shared._CP14.MagicEnergy.Components;
using Content.Shared._CP14.Religion.Components;
using Content.Shared._CP14.Religion.Systems;
using Content.Shared.FixedPoint;
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);
FixedPoint2 manaPercentage = 0f;
if (TryComp<CP14MagicEnergyContainerComponent>(ent, out var manaContainerComponent))
{
manaPercentage = manaContainerComponent.Energy / manaContainerComponent.MaxEnergy;
}
_userInterface.SetUiState(ent.Owner, CP14ReligionEntityUiKey.Key, new CP14ReligionEntityUiState(altars, followers, followerPercentage, manaPercentage));
}
}

View File

@@ -0,0 +1,247 @@
using Content.Server._CP14.MagicEnergy;
using Content.Server.Chat.Managers;
using Content.Server.Chat.Systems;
using Content.Server.Speech;
using Content.Shared._CP14.MagicEnergy.Components;
using Content.Shared._CP14.Religion.Components;
using Content.Shared._CP14.Religion.Prototypes;
using Content.Shared._CP14.Religion.Systems;
using Content.Shared.Chat;
using Content.Shared.FixedPoint;
using Robust.Server.GameStates;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Server._CP14.Religion;
public sealed partial class CP14ReligionGodSystem : CP14SharedReligionGodSystem
{
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly ChatSystem _chatSys = default!;
[Dependency] private readonly PvsOverrideSystem _pvs = default!;
[Dependency] private readonly CP14MagicEnergySystem _magicEnergy = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
/// <summary>
/// If ReligionObserver receives a radius higher than this value, this entity will automatically be placed in PvsOverride for the god in order to function correctly outside of the player's PVS.
/// </summary>
/// <remarks> Maybe there is a variable for the distance outside the screen in PVS, I don't know. This number works best</remarks>
private const float ObservationOverrideRadius = 6.5f;
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<CP14ReligionSpeakerComponent, CP14SpokeAttemptEvent>(OnSpokeAttempt);
SubscribeLocalEvent<CP14ReligionAltarComponent, ListenEvent>(OnListen);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<CP14ReligionFollowerComponent, CP14MagicEnergyContainerComponent>();
while (query.MoveNext(out var uid, out var follower, out var energy))
{
if (follower.NextUpdateTime >= _gameTiming.CurTime)
continue;
if (follower.Religion is null)
continue;
follower.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(follower.ManaTransferDelay);
foreach (var god in GetGods(follower.Religion.Value))
{
_magicEnergy.TransferEnergy((uid, energy), god.Owner, follower.EnergyToGodTransfer, out _, out _, safe: true);
}
}
}
private void OnSpokeAttempt(Entity<CP14ReligionSpeakerComponent> ent, ref CP14SpokeAttemptEvent args)
{
args.Cancel();
if (!TryComp<CP14ReligionEntityComponent>(ent, out var god) || god.Religion is null)
return;
if (ent.Comp.RestrictedReligionZone && !InVision(ent, (ent, god)))
return;
_magicEnergy.ChangeEnergy(ent.Owner, -ent.Comp.ManaCost, out _, out _);
var speaker = Spawn(ent.Comp.Speaker);
_transform.DropNextTo(speaker, ent.Owner);
var message = args.Message;
var type = args.Type;
Timer.Spawn(333,
() =>
{
_chatSys.TrySendInGameICMessage(speaker, message, type, ChatTransmitRange.Normal, nameOverride: MetaData(ent).EntityName, ignoreActionBlocker: true);
});
}
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);
}
public 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 FixedPoint2 GetFollowerPercentage(Entity<CP14ReligionEntityComponent> god)
{
FixedPoint2 total = 0;
FixedPoint2 followers = 0;
var allHumans = Mind.GetAliveHumans();
foreach (var human in allHumans)
{
total += 1;
if (!TryComp<CP14ReligionFollowerComponent>(human.Comp.CurrentEntity, out var relFollower))
continue;
if (relFollower.Religion != god.Comp.Religion)
continue;
followers += 1;
}
if (total == 0)
return 0f;
return 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] <= ObservationOverrideRadius)
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);
}
}
public sealed class CP14SpokeAttemptEvent(string message, InGameICChatType type, ICommonSession? player) : CancellableEntityEventArgs
{
public string Message = message;
public InGameICChatType Type = type;
public ICommonSession? Player = player;
}

View File

@@ -0,0 +1,63 @@
using System.Text;
using Content.Server.Cargo.Systems;
using Content.Shared._CP14.Currency;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Tag;
using Content.Shared._CP14.Trading.Components;
namespace Content.Server._CP14.Trading;
public sealed class CP14PriceScannerSystem : EntitySystem
{
[Dependency] private readonly PricingSystem _price = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly InventorySystem _invSystem = default!;
[Dependency] private readonly CP14SharedCurrencySystem _currency = default!;
public override void Initialize()
{
SubscribeLocalEvent<MetaDataComponent, ExaminedEvent>(OnExamined);
}
private bool IsAbleExamine(EntityUid uid)
{
if (_invSystem.TryGetSlotEntity(uid, "eyes", out var huds)
&& HasComp<CP14PriceScannerComponent>(huds))
{
return true;
}
else if (HasComp<CP14PriceScannerComponent>(uid))
{
return true;
}
return false;
}
private void OnExamined(EntityUid eid, MetaDataComponent component, ExaminedEvent args)
{
if (!IsAbleExamine(args.Examiner))
{
return;
}
else if (_tag.HasTag(args.Examined, "CP14Coin"))
{
return;
}
var getPrice = _price.GetPrice(args.Examined);
var price = Math.Round(getPrice);
var priceMsg = Loc.GetString("cp14-currency-examine-title");
priceMsg += _currency.GetCurrencyPrettyString((int)price);
args.PushMarkup(priceMsg);
}
}

View File

@@ -1,6 +1,5 @@
using Content.Server._CP14.GameTicking.Rules;
using Content.Shared._CP14.WeatherControl;
using Content.Shared.Destructible.Thresholds;
namespace Content.Server._CP14.WeatherControl;

View File

@@ -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;

View File

@@ -1,5 +1,6 @@
using Content.Shared._CP14.MagicEssence;
using Content.Shared._CP14.MagicSpell.Events;
using Content.Shared._CP14.Skill;
using Content.Shared.Armor;
using Content.Shared.Atmos;
using Content.Shared.Chat;
@@ -39,6 +40,7 @@ public partial class InventorySystem
//CP14 Relayed events
SubscribeLocalEvent<InventoryComponent, CP14MagicEssenceScanEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, CP14CalculateManacostEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, CP14SkillScanEvent>(RelayInventoryEvent);
//CP14 End
SubscribeLocalEvent<InventoryComponent, DamageModifyEvent>(RelayInventoryEvent);

View File

@@ -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 =

View File

@@ -14,8 +14,7 @@ public partial class CP14SharedCurrencySystem : EntitySystem
{
var total = currency;
if (total <= 0)
return string.Empty;
var sb = new StringBuilder();
var gp = total / 100;
total %= 100;
@@ -25,14 +24,15 @@ public partial class CP14SharedCurrencySystem : EntitySystem
var cp = total;
var sb = new StringBuilder();
if (gp > 0)
sb.Append( " " + Loc.GetString("cp14-currency-examine-gp", ("coin", gp)));
sb.Append(" " + Loc.GetString("cp14-currency-examine-gp", ("coin", gp)));
if (sp > 0)
sb.Append( " " + Loc.GetString("cp14-currency-examine-sp", ("coin", sp)));
sb.Append(" " + Loc.GetString("cp14-currency-examine-sp", ("coin", sp)));
if (cp > 0)
sb.Append( " " + Loc.GetString("cp14-currency-examine-cp", ("coin", cp)));
sb.Append(" " + Loc.GetString("cp14-currency-examine-cp", ("coin", cp)));
if (gp <= 0 && sp <= 0 && cp <= 0)
sb.Append(" " + Loc.GetString("cp14-trading-empty-price"));
return sb.ToString();
return sb.ToString();
}

View File

@@ -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,35 @@ public abstract partial class CP14SharedMagicSystem
}
}
private void OnReligionRestrictedCheck(Entity<CP14MagicEffectReligionRestrictedComponent> ent,
ref CP14CastMagicEffectAttemptEvent args)
{
if (!TryComp<CP14ReligionEntityComponent>(args.Performer, out var religionComp))
return;
var position = args.Position;
if (args.Target is not null)
position ??= Transform(args.Target.Value).Coordinates;
if (ent.Comp.OnlyInReligionZone)
{
if (position is null || !_god.InVision(position.Value, (args.Performer, religionComp)))
{
args.Cancel();
}
}
if (ent.Comp.OnlyOnFollowers)
{
if (args.Target is null || !TryComp<CP14ReligionFollowerComponent>(args.Target, out var follower) || follower.Religion != religionComp.Religion)
{
args.PushReason(Loc.GetString("cp14-magic-spell-target-god-follower"));
args.Cancel();
}
}
}
private void OnVerbalAspectStartCast(Entity<CP14MagicEffectVerbalAspectComponent> ent,
ref CP14StartCastMagicEffectEvent args)
{

View File

@@ -10,6 +10,7 @@ public abstract partial class CP14SharedMagicSystem
{
SubscribeLocalEvent<CP14InstantActionEvent>(OnMagicInstantAction);
SubscribeLocalEvent<CP14EntityWorldTargetActionEvent>(OnMagicEntityWorldTargetAction);
SubscribeLocalEvent<CP14WorldTargetActionEvent>(OnMagicWorldTargetAction);
SubscribeLocalEvent<CP14EntityTargetActionEvent>(OnMagicEntityTargetAction);
}
@@ -47,6 +48,23 @@ public abstract partial class CP14SharedMagicSystem
_action.SetCooldown(args.Action.Owner, args.Cooldown);
}
private void OnMagicWorldTargetAction(CP14WorldTargetActionEvent args)
{
if (args.Handled)
return;
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
return;
var spellArgs = new CP14SpellEffectBaseArgs(args.Performer, magicEffect.SpellStorage, null, args.Target);
if (!CanCastSpell((args.Action, magicEffect), spellArgs))
return;
CastSpell((args.Action, magicEffect), spellArgs);
_action.CP14StartCustomDelay(args.Action, args.Cooldown);
}
private void OnMagicEntityTargetAction(CP14EntityTargetActionEvent args)
{
if (args.Handled)

View File

@@ -0,0 +1,20 @@
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))]
public sealed partial class CP14MagicEffectReligionRestrictedComponent : Component
{
/// <summary>
/// does not allow the spell to be used outside the god's area of influence
/// </summary>
[DataField]
public bool OnlyInReligionZone = true;
/// <summary>
/// allows the spell to be used only on followers
/// </summary>
[DataField]
public bool OnlyOnFollowers = false;
}

View File

@@ -13,6 +13,12 @@ public sealed partial class CP14EntityWorldTargetActionEvent : WorldTargetAction
public TimeSpan Cooldown { get; private set; } = TimeSpan.FromSeconds(1f);
}
public sealed partial class CP14WorldTargetActionEvent : WorldTargetActionEvent, ICP14MagicEffect
{
[DataField]
public TimeSpan Cooldown { get; private set; } = TimeSpan.FromSeconds(1f);
}
public sealed partial class CP14EntityTargetActionEvent : EntityTargetActionEvent, ICP14MagicEffect
{
[DataField]

View File

@@ -0,0 +1,22 @@
using Content.Shared._CP14.Skill;
namespace Content.Shared._CP14.MagicSpell.Spells;
public sealed partial class CP14SpellAddMemoryPoint : CP14SpellEffect
{
[DataField]
public float AddedPoints = 0.5f;
[DataField]
public float Limit = 6.5f;
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
{
if (args.Target is null)
return;
var skillSys = entManager.System<CP14SharedSkillSystem>();
skillSys.AddMemoryPoints(args.Target.Value, AddedPoints, Limit);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,25 @@
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;
}

View File

@@ -1,7 +1,9 @@
using System.Numerics;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.Map;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared._CP14.MagicSpell.Spells;
@@ -10,6 +12,15 @@ public sealed partial class CP14SpellProjectile : CP14SpellEffect
[DataField(required: true)]
public EntProtoId Prototype;
[DataField]
public float ProjectileSpeed = 20f;
[DataField]
public float Spread = 0f;
[DataField]
public int ProjectileCount = 1;
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
{
EntityCoordinates? targetPoint = null;
@@ -27,6 +38,7 @@ public sealed partial class CP14SpellProjectile : CP14SpellEffect
var physics = entManager.System<SharedPhysicsSystem>();
var gunSystem = entManager.System<SharedGunSystem>();
var mapManager = IoCManager.Resolve<IMapManager>();
var random = IoCManager.Resolve<IRobustRandom>();
if (!entManager.TryGetComponent<TransformComponent>(args.User, out var xform))
return;
@@ -40,14 +52,24 @@ public sealed partial class CP14SpellProjectile : CP14SpellEffect
// If applicable, this ensures the projectile is parented to grid on spawn, instead of the map.
var fromMap = transform.ToMapCoordinates(fromCoords);
var spawnCoords = mapManager.TryFindGridAt(fromMap, out var gridUid, out _)
? transform.WithEntityId(fromCoords, gridUid)
: new(mapManager.GetMapEntityId(fromMap.MapId), fromMap.Position);
for (var i = 0; i < ProjectileCount; i++)
{
//Apply spread to target point
var offsetedTargetPoint = targetPoint.Value.Offset(new Vector2(
(float) (random.NextDouble() * 2 - 1) * Spread,
(float) (random.NextDouble() * 2 - 1) * Spread));
var ent = entManager.SpawnAtPosition(Prototype, spawnCoords);
var direction = targetPoint.Value.ToMapPos(entManager, transform) -
spawnCoords.ToMapPos(entManager, transform);
gunSystem.ShootProjectile(ent, direction, userVelocity, args.User.Value, args.User);
var ent = entManager.SpawnAtPosition(Prototype, spawnCoords);
var direction = offsetedTargetPoint.ToMapPos(entManager, transform) -
spawnCoords.ToMapPos(entManager, transform);
gunSystem.ShootProjectile(ent, direction, userVelocity, args.User.Value, args.User, ProjectileSpeed);
}
}
}

View File

@@ -0,0 +1,19 @@
using Content.Shared._CP14.Skill;
namespace Content.Shared._CP14.MagicSpell.Spells;
public sealed partial class CP14SpellRemoveMemoryPoint : CP14SpellEffect
{
[DataField]
public float RemovedPoints = 0.5f;
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
{
if (args.Target is null)
return;
var skillSys = entManager.System<CP14SharedSkillSystem>();
skillSys.RemoveMemoryPoints(args.Target.Value, RemovedPoints);
}
}

View File

@@ -0,0 +1,25 @@
using Content.Shared._CP14.Religion.Components;
using Content.Shared._CP14.Religion.Systems;
namespace Content.Shared._CP14.MagicSpell.Spells;
public sealed partial class CP14SpellSendMessageToGod : CP14SpellEffect
{
[DataField]
public LocId? Message;
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
{
if (!entManager.TryGetComponent<CP14ReligionFollowerComponent>(args.User, out var follower))
return;
if (!entManager.TryGetComponent<MetaDataComponent>(args.User, out var metaData))
return;
if (follower.Religion is null)
return;
var religionSys = entManager.System<CP14SharedReligionGodSystem>();
religionSys.SendMessageToGods(follower.Religion.Value, Loc.GetString("cp14-call-follower-message", ("name", metaData.EntityName)) + " " + Loc.GetString(Message?? ""), args.User.Value);
}
}

View File

@@ -0,0 +1,37 @@
using Content.Shared._CP14.MagicEnergy;
using Content.Shared._CP14.Religion.Components;
using Content.Shared._CP14.Religion.Systems;
using Content.Shared.FixedPoint;
namespace Content.Shared._CP14.MagicSpell.Spells;
public sealed partial class CP14SpellTransferManaToGod : CP14SpellEffect
{
[DataField]
public FixedPoint2 Amount = 10f;
[DataField]
public bool Safe = false;
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
{
if (args.User is null)
return;
if (!entManager.TryGetComponent<CP14ReligionFollowerComponent>(args.User, out var follower))
return;
if (follower.Religion is null)
return;
var religionSys = entManager.System<CP14SharedReligionGodSystem>();
var magicEnergySys = entManager.System<SharedCP14MagicEnergySystem>();
var gods = religionSys.GetGods(follower.Religion.Value);
var manaAmount = Amount / gods.Count;
foreach (var god in gods)
{
magicEnergySys.TransferEnergy(args.User.Value, god.Owner, manaAmount, out _, out _, safe: Safe);
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,50 @@
using Content.Shared._CP14.Religion.Prototypes;
using Content.Shared._CP14.Religion.Systems;
using Content.Shared.FixedPoint;
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 EntProtoId AppealToGofProto = "CP14ActionAppealToGod";
[DataField]
public EntityUid? RenounceAction;
[DataField]
public EntityUid? AppealAction;
/// <summary>
/// how much energy does the entity transfer to its god
/// </summary>
[DataField]
public FixedPoint2 EnergyToGodTransfer = 0.5f;
/// <summary>
/// how often will the entity transfer mana to its patreon
/// </summary>
[DataField]
public float ManaTransferDelay = 3f;
/// <summary>
/// the time of the next magic energy change
/// </summary>
[DataField]
public TimeSpan NextUpdateTime { get; set; } = TimeSpan.Zero;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,28 @@
using Content.Shared._CP14.Religion.Systems;
using Content.Shared.FixedPoint;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Religion.Components;
/// <summary>
/// Disables standard communication. Instead, attempts to say anything will consume mana, will be limited by the zone
/// of influence of religion, and will be spoken through the created entity of the “speaker.”
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(CP14SharedReligionGodSystem))]
public sealed partial class CP14ReligionSpeakerComponent : Component
{
[DataField]
public FixedPoint2 ManaCost = 5f;
[DataField(required: true)]
public EntProtoId Speaker;
/// <summary>
/// You can only talk within the sphere of influence of religion.
/// </summary>
[DataField]
public bool RestrictedReligionZone = true;
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -0,0 +1,100 @@
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<AlternativeVerb>>(GetAltVerb);
}
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
{
}

View File

@@ -0,0 +1,204 @@
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.Follower;
using Content.Shared.Mind;
using Content.Shared.Mobs;
using Content.Shared.Verbs;
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!;
[Dependency] private readonly FollowerSystem _follower = default!;
[ValidatePrototypeId<AlertPrototype>]
public const string AlertProto = "CP14DivineOffer";
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);
SubscribeLocalEvent<CP14ReligionFollowerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetAltVerbs);
SubscribeLocalEvent<CP14ReligionFollowerComponent, MobStateChangedEvent>(OnFollowerStateChange);
}
private void OnFollowerStateChange(Entity<CP14ReligionFollowerComponent> ent, ref MobStateChangedEvent args)
{
if (ent.Comp.Religion is null)
return;
switch (args.NewMobState)
{
case MobState.Critical:
SendMessageToGods(ent.Comp.Religion.Value, Loc.GetString("cp14-critical-follower-message", ("name", MetaData(ent).EntityName)), ent);
break;
case MobState.Dead:
SendMessageToGods(ent.Comp.Religion.Value, Loc.GetString("cp14-dead-follower-message", ("name", MetaData(ent).EntityName)), ent);
break;
}
}
private void OnGetAltVerbs(EntityUid uid, CP14ReligionFollowerComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!TryComp<CP14ReligionEntityComponent>(args.User, out var god))
return;
if (god.Religion != component.Religion)
return;
args.Verbs.Add(new AlternativeVerb
{
Text = Loc.GetString("admin-player-actions-follow"),
Act = () =>
{
_follower.StartFollowingEntity(args.User, uid);
},
});
}
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, AlertProto);
}
private void OnPendingFollowerShutdown(Entity<CP14ReligionPendingFollowerComponent> ent, ref ComponentShutdown args)
{
_alerts.ClearAlert(ent, AlertProto);
}
private bool CanBecomeFollower(EntityUid target, ProtoId<CP14ReligionPrototype> religion)
{
if (HasComp<CP14ReligionEntityComponent>(target))
return false;
EnsureComp<CP14ReligionFollowerComponent>(target, out var follower);
if (follower.Religion is not null)
return false;
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);
_actions.AddAction(pending, ref follower.AppealAction, follower.AppealToGofProto);
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);
_actions.RemoveAction(target, follower.AppealAction);
}
}
public sealed partial class CP14BreakDivineOfferEvent : BaseAlertEvent;
public sealed partial class CP14RenounceFromGodEvent : InstantActionEvent;

View File

@@ -0,0 +1,93 @@
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;
}
}

View File

@@ -0,0 +1,25 @@
using Content.Shared.FixedPoint;
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, FixedPoint2 followerPercentage, FixedPoint2 manaPercentage) : BoundUserInterfaceState
{
public Dictionary<NetEntity, string> Altars = altars;
public Dictionary<NetEntity, string> Followers = followers;
public FixedPoint2 FollowerPercentage = followerPercentage;
public FixedPoint2 ManaPercentage = manaPercentage;
}
[Serializable, NetSerializable]
public sealed class CP14ReligionEntityTeleportAttempt(NetEntity entity) : BoundUserInterfaceMessage
{
public readonly NetEntity Entity = entity;
}

View File

@@ -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;
}
public 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;
}

View File

@@ -2,8 +2,10 @@ using System.Linq;
using System.Text;
using Content.Shared._CP14.Skill.Components;
using Content.Shared._CP14.Skill.Prototypes;
using Content.Shared._CP14.Skill.Restrictions;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared._CP14.Skill;
@@ -21,6 +23,7 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
InitializeAdmin();
InitializeChecks();
InitializeScanning();
}
private void OnMapInit(Entity<CP14SkillStorageComponent> ent, ref MapInitEvent args)
@@ -174,6 +177,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;
@@ -244,6 +251,39 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
return sb.ToString();
}
/// <summary>
/// Obtaining all skills that are not prerequisites for other skills of this creature
/// </summary>
public HashSet<ProtoId<CP14SkillPrototype>> GetFrontierSkills(EntityUid target,
CP14SkillStorageComponent? component = null)
{
var skills = new HashSet<ProtoId<CP14SkillPrototype>>();
if (!Resolve(target, ref component, false))
return skills;
var frontier = component.LearnedSkills.ToHashSet();
foreach (var skill in component.LearnedSkills)
{
if (!_proto.TryIndex(skill, out var indexedSkill))
continue;
if (HaveFreeSkill(target, skill))
continue;
foreach (var req in indexedSkill.Restrictions)
{
if (req is NeedPrerequisite prerequisite)
{
if (frontier.Contains(prerequisite.Prerequisite))
frontier.Remove(prerequisite.Prerequisite);
}
}
}
return frontier;
}
/// <summary>
/// Helper function to reset skills to only learned skills
/// </summary>
@@ -264,6 +304,45 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
}
return true;
}
/// <summary>
/// Increases the number of memory points for a character, limited to a certain amount.
/// </summary>
public void AddMemoryPoints(EntityUid target, FixedPoint2 points, FixedPoint2 limit, CP14SkillStorageComponent? component = null)
{
if (!Resolve(target, ref component, false))
return;
component.ExperienceMaxCap = FixedPoint2.Min(component.ExperienceMaxCap + points, limit);
Dirty(target, component);
_popup.PopupEntity(Loc.GetString("cp14-skill-popup-added-points", ("count", points)), target, target);
}
/// <summary>
/// Removes memory points. If a character has accumulated skills exceeding the new memory limit, random skills will be removed.
/// </summary>
public void RemoveMemoryPoints(EntityUid target, FixedPoint2 points, CP14SkillStorageComponent? component = null)
{
if (!Resolve(target, ref component, false))
return;
component.ExperienceMaxCap = FixedPoint2.Max(component.ExperienceMaxCap - points, 0);
Dirty(target, component);
_popup.PopupEntity(Loc.GetString("cp14-skill-popup-removed-points", ("count", points)), target, target);
while (component.SkillsSumExperience > component.ExperienceMaxCap)
{
var frontier = GetFrontierSkills(target, component);
if (frontier.Count == 0)
break;
//Randomly remove one of the frontier skills
var skill = _random.Pick(frontier);
TryRemoveSkill(target, skill, component);
}
}
}
[ByRefEvent]

View File

@@ -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);
},
});
}
}

View File

@@ -0,0 +1,75 @@
using System.Text;
using Content.Shared._CP14.Skill.Components;
using Content.Shared.Examine;
using Content.Shared.Inventory;
using Content.Shared.Verbs;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Skill;
public abstract partial class CP14SharedSkillSystem
{
[Dependency] private readonly ExamineSystemShared _examine = default!;
private void InitializeScanning()
{
SubscribeLocalEvent<CP14SkillScannerComponent, CP14SkillScanEvent>(OnSkillScan);
SubscribeLocalEvent<CP14SkillScannerComponent, InventoryRelayedEvent<CP14SkillScanEvent>>((e, c, ev) => OnSkillScan(e, c, ev.Args));
SubscribeLocalEvent<CP14SkillStorageComponent, GetVerbsEvent<ExamineVerb>>(OnExamined);
}
private void OnExamined(Entity<CP14SkillStorageComponent> ent, ref GetVerbsEvent<ExamineVerb> args)
{
var scanEvent = new CP14SkillScanEvent();
RaiseLocalEvent(args.User, scanEvent);
if (!scanEvent.CanScan)
return;
var markup = GetSkillExamine(ent);
_examine.AddDetailedExamineVerb(
args,
ent.Comp,
markup,
Loc.GetString("cp14-skill-info-title"),
"/Textures/Interface/students-cap.svg.192dpi.png");
}
private FormattedMessage GetSkillExamine(Entity<CP14SkillStorageComponent> ent)
{
var msg = new FormattedMessage();
var sb = new StringBuilder();
sb.Append(Loc.GetString("cp14-skill-examine-title") + "\n");
foreach (var skill in ent.Comp.LearnedSkills)
{
if (!_proto.TryIndex(skill, out var indexedSkill))
continue;
if(!_proto.TryIndex(indexedSkill.Tree, out var indexedTree))
continue;
var skillName = GetSkillName(skill);
sb.Append($"• [color={indexedTree.Color.ToHex()}]{skillName}[/color]\n");
}
sb.Append($"\n{Loc.GetString("cp14-skill-menu-level")} {ent.Comp.SkillsSumExperience}/{ent.Comp.ExperienceMaxCap}\n");
msg.AddMarkupOrThrow(sb.ToString());
return msg;
}
private void OnSkillScan(EntityUid uid, CP14SkillScannerComponent component, CP14SkillScanEvent args)
{
args.CanScan = true;
}
}
public sealed class CP14SkillScanEvent : EntityEventArgs, IInventoryRelayEvent
{
public bool CanScan;
public SlotFlags TargetSlots { get; } = SlotFlags.EYES;
}

View File

@@ -0,0 +1,11 @@
using Robust.Shared.GameStates;
namespace Content.Shared._CP14.Skill.Components;
/// <summary>
/// Allows you to see what skills the creature possesses
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class CP14SkillScannerComponent : Component
{
}

View File

@@ -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();

View File

@@ -41,7 +41,4 @@ public sealed partial class CP14SkillTreePrototype : IPrototype
[DataField]
public SoundSpecifier LearnSound = new SoundCollectionSpecifier("CP14LearnSkill");
[DataField]
public SpriteSpecifier? Icon = null;
}

View File

@@ -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));
}
}

View File

@@ -0,0 +1,6 @@
using Robust.Shared.GameStates;
namespace Content.Shared._CP14.Trading.Components;
[RegisterComponent, NetworkedComponent]
public sealed partial class CP14PriceScannerComponent : Component { }

View File

@@ -11,7 +11,7 @@ public sealed class CP14WeatherData
public ProtoId<WeatherPrototype>? Visuals { get; set; } = null;
[DataField]
public MinMax Duration { get; set; } = new(30, 300);
public MinMax Duration { get; set; } = new(120, 600);
[DataField]
public float Weight { get; set; } = 1f;

View File

@@ -67,3 +67,8 @@
license: "CC-BY-4.0"
copyright: 'by iainmccurdy of Freesound.org. Cropped and mixed from stereo to mono.'
source: "https://freesound.org/people/iainmccurdy/sounds/743820/"
- files: ["flem1.ogg, flem2.ogg, flem3.ogg"]
license: "CC0-1.0"
copyright: 'by muckypete7 of Freesound.org. Cropped and mixed from stereo to mono.'
source: "https://freesound.org/people/mucky_pete7/sounds/574208/"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -91,4 +91,14 @@
- files: ["cash.ogg"]
license: "CC0-1.0"
copyright: 'Created by Zott820 on Freesound.org'
source: "https://freesound.org/people/Zott820/sounds/209578/"
source: "https://freesound.org/people/Zott820/sounds/209578/"
- files: ["ritual_begin.ogg", "ritual_end.ogg"]
license: "CC-BY-4.0"
copyright: 'Created by SilverIllusionist on Freesound.org'
source: "https://freesound.org/people/SilverIllusionist/sounds/671928/"
- files: ["moon_strike1.ogg", "moon_strike2.ogg", "moon_strike3.ogg", "moon_strike4.ogg"]
license: "CC-BY-4.0"
copyright: 'Created by EminYILDIRIM on Freesound.org'
source: "https://freesound.org/people/EminYILDIRIM/sounds/668244/"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -320,3 +320,93 @@
id: 8084
time: '2025-06-10T08:07:13.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1412
- author: gogenych
changes:
- message: Copper tools and weapons are now displayed correctly in loadout
type: Fix
id: 8085
time: '2025-06-10T10:40:19.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1414
- author: firebat4321
changes:
- message: Added new combat-focused T2 Pryokinetic spell, Firebolt!
type: Add
id: 8086
time: '2025-06-10T11:14:08.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1354
- author: Sefaia
changes:
- message: Added Quiver filled with Big Iron Crossbow Bolts to Entity Spawn Menu
for Admins/Testers
type: Add
- message: Fixed Quiver to hold Big Crossbow Bolts.
type: Fix
id: 8087
time: '2025-06-13T07:34:32.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1418
- author: SenorJaba
changes:
- message: Merchant's monocle has been added to replace appraisal tool.
type: Add
- message: Added a new trader's wit skill which works similarly to merchant's monocle.
type: Add
- message: Alchemist's glasses and monocle, and merchant's monocle were added into
the buying platform.
type: Add
- message: Appraisal tool has been removed from the merchant's closet.
type: Remove
- message: Alchemist's glasses and monocle were removed from the alchemist's loadout.
type: Remove
id: 8088
time: '2025-06-13T09:24:36.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1413
- author: Fr0goo
changes:
- message: Added new creature named Flem! You can find them in demiplanes.
type: Add
- message: Added fish suit and mask!
type: Add
- message: Added a probaly temporary way to make fish pie!
type: Add
id: 8089
time: '2025-06-13T10:25:33.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1402
- author: TheShuEd
changes:
- message: A patron system has been added. By interacting with the primordial statues,
you can become a follower of a patron. For more details, please refer to the
in-game guidebooks.
type: Add
- message: "The divine patron of the night sky and knowledge, \u201CLumera,\u201D\
\ has been added. This is a game role that gains new abilities based on the\
\ number of followers and is capable of interacting with areas of visibility\
\ and granting (or taking away) memory points from other players."
type: Add
id: 8090
time: '2025-06-15T15:00:33.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1427
- author: TheShuEd
changes:
- message: Added firewave spell. Now it looks like a shotgun, only made of fire.
type: Add
- message: Removed firebolt spell.
type: Remove
- message: Spiders' health reduced by half
type: Tweak
id: 8091
time: '2025-06-15T15:03:38.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1430
- author: TheShuEd
changes:
- message: you can buy wheat and cotton into victorian gardens trade faction
type: Add
- message: Demiplanes can no longer devour patrons if they close while the patron
is inside the demoplan.
type: Fix
- message: Patron saints can no longer occupy entry slots into the demiplane.
type: Fix
- message: Passports removed from the gods-patrons
type: Fix
id: 8092
time: '2025-06-15T18:25:58.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1432

View File

@@ -4,7 +4,7 @@ cp14-currency-examine-gp = [color=#ebad3b]{$coin}gp[/color]
cp14-currency-examine-sp = [color=#bad1d6]{$coin}sp[/color]
cp14-currency-examine-cp = [color=#824e27]{$coin}cp[/color]
cp14-currency-converter-insert = {$cash}cp ddeposited!
cp14-currency-converter-insert = {$cash}cp deposited!
cp14-verb-categories-currency-converter = Withdraw currency:
cp14-currency-converter-get-cp = As cp (1cp)
cp14-currency-converter-get-sp = As sp (10cp)

View File

@@ -24,6 +24,7 @@ cp14-modifier-air-lily = air lilies
cp14-modifier-shadow-kudzu = spreading astral haze
cp14-modifier-night = darkness
cp14-modifier-spiders = spider's web
cp14-modifier-flem = flemings
cp14-modifier-storm = storm
cp14-modifier-fire-storm = fire storm

View File

@@ -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.

View File

@@ -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 sky and knowledge. Expand your influence by helping mortals gain new knowledge.

View File

@@ -22,4 +22,5 @@ cp14-magic-spell-pacified = It could hurt someone!
cp14-magic-spell-target-not-mob = The target must be a living thing!
cp14-magic-spell-target-dead = Can't be used on the dead!
cp14-magic-spell-target-alive = Can't be used on the living!
cp14-magic-spell-target-alive = Can't be used on the living!
cp14-magic-spell-target-god-follower = Your target should be your follower!

View File

@@ -0,0 +1,23 @@
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-call-follower-message = [bold]{$name}[/bold] appeals to you!
cp14-critical-follower-message = [bold]{$name}[/bold] is falling into critical condition!
cp14-dead-follower-message = [bold]{$name}[/bold] is dead!
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-god-ui-mana-percentage = Divine energy: {$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.

View File

@@ -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}%

View File

@@ -31,4 +31,7 @@ cp14-skill-copper-melt-name = Copper melting
cp14-skill-iron-melt-name = Iron melting
cp14-skill-gold-melt-name = Gold melting
cp14-skill-mithril-melt-name = Mithril melting
cp14-skill-glass-melt-name = Glasswork
cp14-skill-glass-melt-name = Glasswork
cp14-skill-trader-wit-name = Trader's wit
cp14-skill-trader-wit-desc = You are able to estimate the exact value of any item in the empire at a first glance.

View File

@@ -0,0 +1,6 @@
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
cp14-skill-lumera-mind-scan-name = Study of minds
cp14-skill-lumera-mind-scan-desc = You are able to discern the skills possessed by mortals. You can see what spells they are capable of casting and what they are capable of doing.

View File

@@ -29,8 +29,14 @@ cp14-skill-tree-martial-desc = Master the secrets of deadly weapons, or make you
# Job
cp14-skill-tree-thaumaturgy-name = Alchemy
cp14-skill-tree-thaumaturgy-desc = The art of creating magical potions that can kill, raise from the dead, or turn creatures into sheep.
#cp14-skill-tree-thaumaturgy-name = Alchemy
#cp14-skill-tree-thaumaturgy-desc = The art of creating magical potions that can kill, raise from the dead, or turn creatures into sheep.
cp14-skill-tree-blacksmithing-name = Blacksmithing
cp14-skill-tree-blacksmithing-desc = The art of turning metal into various useful things.
#cp14-skill-tree-blacksmithing-name = Blacksmithing
#cp14-skill-tree-blacksmithing-desc = The art of turning metal into various useful things.
#cp14-skill-tree-trading-name = Trading
#cp14-skill-tree-trading-desc = The art of understanding where, when and for how much to sell and buy different items.
cp14-skill-tree-craftsman-name = Craftsmanship
cp14-skill-tree-craftsman-desc = Learn the arts and crafts that let you create and use all kinds of useful things.

View File

@@ -14,4 +14,9 @@ cp14-research-recipe-list = Research costs:
cp14-research-craft = Research
cp14-skill-desc-add-mana = Increases your character's mana amount by {$mana}.
cp14-skill-desc-unlock-recipes = Opens up the possibility of crafting:
cp14-skill-desc-unlock-recipes = Opens up the possibility of crafting:
cp14-skill-popup-added-points = The boundaries of your consciousness are expanding. New memory points: {$count}
cp14-skill-examine-title = This character has the following skills:
cp14-skill-popup-forced-remove-skill = You are beginning to forget your past... Memory points lost: {$count}

View File

@@ -8,4 +8,6 @@ cp14-trading-faction-prefix = Trading with:
cp14-trading-failure-popup-money = Not enough funds on the platform!
cp14-trading-contract-use = Trade with "{$name}" unlocked!
cp14-trading-contract-use = Trade with "{$name}" unlocked!
cp14-trading-empty-price = None!

View File

@@ -754,6 +754,9 @@ ent-CP14ClothingEyesAlchemyGlasses = алхимические очки
ent-CP14ClothingEyesAlchemyMonocle = алхимический монокль
.desc = Специальный магический монокль, позволяющий четко видеть состав любых смесей.
ent-CP14ClothingEyesMerchantMonocle = монокль торговца
.desc = Магический увеличительный монокль высочайшего качества, позволяющий вам определить точную цену любого товара.
ent-CP14ClothingEyesThaumaturgyGlasses = тауматургические очки
.desc = Очки, позволяющие сканировать магические предметы и существ, чтобы четко видеть количество оставшейся в них энергии.

View File

@@ -11,4 +11,7 @@ department-CP14Guard = Стража
department-CP14Guard-desc = Защитники и войны, следящие за безопасностью и правопорядком во всех уголках империи.
department-CP14Artisan = Ремесленники
department-CP14Artisan-desc = Освоившие мирные профессии, люди, которые помогают поселению своими знаниями и умениями.
department-CP14Artisan-desc = Освоившие мирные профессии, люди, которые помогают поселению своими знаниями и умениями.
department-CP14Demigods = Покровители
department-CP14Demigods-desc = Высшие сущности, играющие в свои собственные игры, где обычные существа лишь пешки в их планах.

View File

@@ -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 = Покровительница ночного неба и знаний. Расширяйте свое влияние, помогая смертным обретать новые знания.

View File

@@ -22,4 +22,5 @@ cp14-magic-spell-pacified = Это может навредить кому либ
cp14-magic-spell-target-not-mob = Цель должна быть живым существом!
cp14-magic-spell-target-dead = Нельзя использовать на мертвых!
cp14-magic-spell-target-alive = Нельзя использовать на живых!
cp14-magic-spell-target-alive = Нельзя использовать на живых!
cp14-magic-spell-target-god-follower = Цель должна быть вашим последователем!

View File

@@ -0,0 +1,23 @@
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-call-follower-message = [bold]{$name}[/bold] взывает к вам!
cp14-critical-follower-message = [bold]{$name}[/bold] падает в критическое состояние!
cp14-dead-follower-message = [bold]{$name}[/bold] погибает!
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-god-ui-mana-percentage = Божественная энергия: {$count}%
cp14-altar-become-follower = Стать последователем
cp14-altar-become-follower-desc = Вы предлагаете себя в службу покровителю. Если он согласится, ваша связь укрепится.
cp14-alert-offer = Предложение о покровительстве
cp14-alert-offer-desc = Вы хотите стать последователем покровителя, но пока от него нет ответа. Нажмите, чтобы отменить предложение.

View File

@@ -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}%

View File

@@ -31,4 +31,7 @@ cp14-skill-copper-melt-name = Плавка меди
cp14-skill-iron-melt-name = Плавка железа
cp14-skill-gold-melt-name = Плавка золота
cp14-skill-mithril-melt-name = Плавка мифрила
cp14-skill-glass-melt-name = Работа со стеклом
cp14-skill-glass-melt-name = Работа со стеклом
cp14-skill-trader-wit-name = Торговая смекалка
cp14-skill-trader-wit-desc = Вы способны одним взглядом оценить и вычислить точную стоимость предмета в империи.

View File

@@ -0,0 +1,6 @@
cp14-skill-lumera-t1-name = Истоки тайной ночи
cp14-skill-lumera-t2-name = Растущая луна
cp14-skill-lumera-t3-name = Полнолуние Лумеры
cp14-skill-lumera-mind-scan-name = Изучение разумов
cp14-skill-lumera-mind-scan-desc = Вы способны узнавать какими навыками владеют смертные. Видеть, какие заклинания им подвластны, и на что они способны.

View File

@@ -1,6 +1,3 @@
cp14-skill-tree-blaksmithing-name = Кузнечное дело
cp14-skill-tree-blaksmithing-desc = Исследуйте и создавайте новые предметы из металла.
# Magic
cp14-skill-tree-pyrokinetic-name = Пирокинетика
@@ -31,8 +28,14 @@ cp14-skill-tree-martial-desc = Овладейте секретами смерт
# Job
cp14-skill-tree-thaumaturgy-name = Алхимия
cp14-skill-tree-thaumaturgy-desc = Исскуство создания волшебных зелий, способных убивать, воскрешать из мертвых или превращать существ в овечек.
#cp14-skill-tree-thaumaturgy-name = Алхимия
#cp14-skill-tree-thaumaturgy-desc = Исскуство создания волшебных зелий, способных убивать, воскрешать из мертвых или превращать существ в овечек.
cp14-skill-tree-blacksmithing-name = Кузнечное дело
cp14-skill-tree-blacksmithing-desc = Исскуство превращения металла в различные полезные вещи.
#cp14-skill-tree-blacksmithing-name = Кузнечное дело
#cp14-skill-tree-blacksmithing-desc = Исскуство превращения металла в различные полезные вещи.
#cp14-skill-tree-trading-name = Торговля
#cp14-skill-tree-trading-desc = Исскуство познания где, когда, и за сколько продавать и покупать различные предметы.
cp14-skill-tree-craftsman-name = Ремесленничество
cp14-skill-tree-craftsman-desc = Изучайте навыки и умения для создания и использования различных полезных вещей.

View File

@@ -14,4 +14,9 @@ cp14-research-recipe-list = Затраты на исследование:
cp14-research-craft = Исследовать
cp14-skill-desc-add-mana = Увеличивает объем маны вашего персонажа на {$mana}.
cp14-skill-desc-unlock-recipes = Открывает возможность создания:
cp14-skill-desc-unlock-recipes = Открывает возможность создания:
cp14-skill-popup-added-points = Границы вашего сознания расширяются. Новых очков памяти: {$count}
cp14-skill-popup-forced-remove-skill = Вы начинаете забывать свое прошлое... Потеряно очков памяти: {$count}
cp14-skill-examine-title = Этот персонаж владеет следующими навыками:

View File

@@ -8,4 +8,6 @@ cp14-trading-faction-prefix = Торговля с:
cp14-trading-failure-popup-money = Недостаточно средств на платформе!
cp14-trading-contract-use = Торговля с "{$name}" разблокирована!
cp14-trading-contract-use = Торговля с "{$name}" разблокирована!
cp14-trading-empty-price = Отсутствует!

View File

@@ -4,8 +4,8 @@ meta:
engineVersion: 260.2.0
forkId: ""
forkVersion: ""
time: 06/04/2025 21:43:51
entityCount: 15261
time: 06/15/2025 11:12:00
entityCount: 15254
maps:
- 1
grids:
@@ -190,7 +190,7 @@ entities:
version: 7
0,-3:
ind: 0,-3
tiles: AgAAAAAAAAIAAAAAAAAcAAAAAAAAAgAAAAABAAIAAAAADwAcAAAAAAUAAgAAAAAHAAIAAAAACgACAAAAAAIAHAAAAAAEABwAAAAABQAcAAAAAAEAHAAAAAABABwAAAAAAQAeAAAAAAEAHgAAAAAAAAMAAAAAAAADAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAADAAAAAAgAAwAAAAAAAAMAAAAAAAADAAAAAAQAAwAAAAAAAAMAAAAAAAAQAAAAAAAAEAAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAAAwAAAAAAAAMAAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAAMAAAAABAABAAAAAAIAAQAAAAADAAEAAAAAAgANAAAAAAAAHgAAAAAAACEAAAAAAAACAAAAAAYAHAAAAAAAABwAAAAAAAAcAAAAAAAAHAAAAAAAABwAAAAAAAAcAAAAAAAAHAAAAAAAAB4AAAAAAgADAAAAAAAAAQAAAAACAB4AAAAAAAABAAAAAAQAAQAAAAABAAEAAAAAAwAhAAAAAAAAAgAAAAANAB4AAAAAAAAcAAAAAAAAHAAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB0AAAAAAAAeAAAAAAIAAwAAAAAAAB4AAAAAAwABAAAAAAQAAQAAAAADAAEAAAAAAQABAAAAAAQAIQAAAAAAAAIAAAAABAAeAAAAAAAAHgAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB4AAAAAAAAdAAAAAAAAHgAAAAAFAAMAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAQAHgAAAAAEACEAAAAAAAAeAAAAAAUAHAAAAAAAAB4AAAAAAAAdAAAAAAAAHQAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAABQADAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAgAhAAAAAAAAHgAAAAAAAB0AAAAAAAAeAAAAAAAAHQAAAAAAAB0AAAAAAAAcAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAMAAwAAAAAAAAEAAAAAAQABAAAAAAQAAQAAAAAEAAEAAAAAAgABAAAAAAAAIQAAAAAAAB4AAAAAAQAdAAAAAAAAHQAAAAAAAB0AAAAAAAAcAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAAMAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAQAAQAAAAAAACEAAAAAAAACAAAAAA0AHAAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB0AAAAAAAAdAAAAAAAAHgAAAAAAAB4AAAAAAQADAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAQAAQAAAAADAAEAAAAAAgAhAAAAAAAAHAAAAAAAAB4AAAAAAQAeAAAAAAAAHgAAAAACAB4AAAAABAAeAAAAAAIAHQAAAAAAAAIAAAAABgAeAAAAAAEAAwAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAEAIQAAAAAAAB4AAAAABQAGAAAAAAIABgAAAAAAAAYAAAAAAgAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAIAHgAAAAABAAMAAAAAAgAeAAAAAAUAAQAAAAADAAEAAAAABAABAAAAAAAAAQAAAAACACEAAAAAAAAeAAAAAAEABgAAAAACAAUAAAAAAwAFAAAAAAMABQAAAAADAAUAAAAAAgAFAAAAAAIABgAAAAADAB4AAAAABAADAAAAAAAAHgAAAAAAAB4AAAAAAgAeAAAAAAQAHgAAAAAAAAEAAAAAAAACAAAAAAAAAgAAAAAEAAYAAAAAAgAFAAAAAAMABQAAAAABAAUAAAAAAQAGAAAAAAEABgAAAAADAAYAAAAAAQAeAAAAAAEAAwAAAAAAAB4AAAAABQAeAAAAAAIAHgAAAAABAB4AAAAAAwAeAAAAAAUAAgAAAAAAAAIAAAAACgAGAAAAAAEABQAAAAACAAUAAAAAAAAFAAAAAAAABQAAAAABAAUAAAAAAgAGAAAAAAEAHgAAAAAFAAMAAAAABgADAAAAAAQAAwAAAAADAAMAAAAABAADAAAAAAMAAwAAAAABAA==
tiles: AgAAAAAAAAIAAAAAAAAcAAAAAAAAAgAAAAABAAIAAAAADwAcAAAAAAUAAgAAAAAHAAIAAAAACgACAAAAAAIAHAAAAAAEABwAAAAABQAcAAAAAAEAHAAAAAABABwAAAAAAQAeAAAAAAEAHgAAAAAAAAMAAAAAAAADAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAADAAAAAAgAAwAAAAAAAAMAAAAAAAADAAAAAAQAAwAAAAAAAAMAAAAAAAAQAAAAAAAAEAAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAAAwAAAAAAAAMAAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAA0AAAAAAAANAAAAAAAADQAAAAAAAAMAAAAABAABAAAAAAIAAQAAAAADAAEAAAAAAgANAAAAAAAAHgAAAAAAACEAAAAAAAACAAAAAAYAHAAAAAAAABwAAAAAAAAcAAAAAAAAHAAAAAAAABwAAAAAAAAcAAAAAAAAHAAAAAAAAB4AAAAAAgADAAAAAAAAAQAAAAACAB4AAAAAAAABAAAAAAQAAQAAAAABAAEAAAAAAwAhAAAAAAAAAgAAAAANAB4AAAAAAAAcAAAAAAAAHAAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB0AAAAAAAAeAAAAAAIAAwAAAAAAAB4AAAAAAwABAAAAAAQAAQAAAAADAAEAAAAAAQABAAAAAAQAIQAAAAAAAAIAAAAABAAeAAAAAAAAHgAAAAAAAB0AAAAAAAAdAAAAAAAAHQAAAAAAAB4AAAAAAAAdAAAAAAAAHgAAAAAFAAMAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAQAHgAAAAAEACEAAAAAAAAeAAAAAAUAHAAAAAAAAB4AAAAAAAAdAAAAAAAAHQAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAABQADAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAgAhAAAAAAAAHgAAAAAAAB0AAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAcAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAMAAwAAAAAAAAEAAAAAAQABAAAAAAQAAQAAAAAEAAEAAAAAAgABAAAAAAAAIQAAAAAAAB4AAAAAAQAdAAAAAAAAEAAAAAAAABEAAAAAAAAQAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAAMAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAQAAQAAAAAAACEAAAAAAAACAAAAAA0AHAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAB0AAAAAAAAdAAAAAAAAHgAAAAAAAB4AAAAAAQADAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAQAAQAAAAADAAEAAAAAAgAhAAAAAAAAHAAAAAAAAB4AAAAAAQAeAAAAAAAAHgAAAAACAB4AAAAABAAeAAAAAAIAHQAAAAAAAAIAAAAABgAeAAAAAAEAAwAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAEAIQAAAAAAAB4AAAAABQAGAAAAAAIABgAAAAAAAAYAAAAAAgAGAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAIAHgAAAAABAAMAAAAAAgAeAAAAAAUAAQAAAAADAAEAAAAABAABAAAAAAAAAQAAAAACACEAAAAAAAAeAAAAAAEABgAAAAACAAUAAAAAAwAFAAAAAAMABQAAAAADAAUAAAAAAgAFAAAAAAIABgAAAAADAB4AAAAABAADAAAAAAAAHgAAAAAAAB4AAAAAAgAeAAAAAAQAHgAAAAAAAAEAAAAAAAACAAAAAAAAAgAAAAAEAAYAAAAAAgAFAAAAAAMABQAAAAABAAUAAAAAAQAGAAAAAAEABgAAAAADAAYAAAAAAQAeAAAAAAEAAwAAAAAAAB4AAAAABQAeAAAAAAIAHgAAAAABAB4AAAAAAwAeAAAAAAUAAgAAAAAAAAIAAAAACgAGAAAAAAEABQAAAAACAAUAAAAAAAAFAAAAAAAABQAAAAABAAUAAAAAAgAGAAAAAAEAHgAAAAAFAAMAAAAABgADAAAAAAQAAwAAAAADAAMAAAAABAADAAAAAAMAAwAAAAABAA==
version: 7
1,-3:
ind: 1,-3
@@ -730,6 +730,26 @@ entities:
decals:
168: -22,-69
169: -22,-71
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneInnerNe
decals:
231: 3,-40
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneInnerNw
decals:
232: 5,-40
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneInnerSe
decals:
229: 3,-38
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneInnerSw
decals:
230: 5,-38
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneLineE
@@ -738,6 +758,7 @@ entities:
115: 21,-44
128: 18,-44
129: 18,-43
228: 3,-39
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneLineN
@@ -756,6 +777,7 @@ entities:
203: -3,-20
204: -10,-20
205: -9,-20
225: 4,-40
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneLineS
@@ -764,6 +786,7 @@ entities:
119: 19,-45
120: 20,-42
121: 19,-42
226: 4,-38
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneLineW
@@ -772,6 +795,7 @@ entities:
117: 21,-43
126: 18,-44
127: 18,-43
227: 5,-39
- node:
cleanable: True
color: '#6EAAEBFF'
@@ -892,6 +916,14 @@ entities:
- type: Transform
pos: 15.5,0.5
parent: 1
- proto: CP14AltarPrimordialGodLumera
entities:
- uid: 7335
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 4.5,-38.5
parent: 1
- proto: CP14BarrelWater
entities:
- uid: 10
@@ -10860,12 +10892,6 @@ entities:
rot: -1.5707963267948966 rad
pos: 7.5,-38.5
parent: 1
- uid: 26
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 4.5,-39.5
parent: 1
- uid: 1861
components:
- type: Transform
@@ -30774,18 +30800,6 @@ entities:
- type: Transform
pos: 103.5,59.5
parent: 1
- uid: 7335
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 4.5,-38.5
parent: 1
- uid: 8737
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 5.5,-38.5
parent: 1
- uid: 8901
components:
- type: Transform
@@ -30923,18 +30937,6 @@ entities:
- type: Transform
pos: 109.5,58.5
parent: 1
- uid: 11070
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 5.5,-37.5
parent: 1
- uid: 11140
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 3.5,-37.5
parent: 1
- uid: 11141
components:
- type: Transform
@@ -30987,12 +30989,6 @@ entities:
- type: Transform
pos: 34.5,-2.5
parent: 1
- uid: 13907
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 6.5,-38.5
parent: 1
- uid: 14556
components:
- type: Transform
@@ -31034,12 +31030,6 @@ entities:
rot: -1.5707963267948966 rad
pos: 7.5,-39.5
parent: 1
- uid: 14623
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 5.5,-40.5
parent: 1
- uid: 14624
components:
- type: Transform
@@ -31052,24 +31042,12 @@ entities:
rot: -1.5707963267948966 rad
pos: 6.5,-40.5
parent: 1
- uid: 14626
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 6.5,-39.5
parent: 1
- uid: 14632
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 2.5,-41.5
parent: 1
- uid: 14633
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 4.5,-37.5
parent: 1
- uid: 14636
components:
- type: Transform
@@ -31100,12 +31078,6 @@ entities:
rot: -1.5707963267948966 rad
pos: -2.5,-40.5
parent: 1
- uid: 14946
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 5.5,-39.5
parent: 1
- uid: 14963
components:
- type: Transform
@@ -38165,6 +38137,13 @@ entities:
- type: Transform
pos: 18.607292,16.662266
parent: 1
- proto: CP14BlueAmanita
entities:
- uid: 26
components:
- type: Transform
pos: 4.5032434,-39.154808
parent: 1
- proto: CP14BlueBottle
entities:
- uid: 7125
@@ -38296,6 +38275,28 @@ entities:
- type: Transform
pos: -17.264824,5.8419228
parent: 1
- proto: CP14CandleBlue
entities:
- uid: 8737
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 5.330699,-38.98751
parent: 1
- uid: 9582
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 3.902204,-39.324844
parent: 1
- proto: CP14CandleBlueSmall
entities:
- uid: 9583
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 3.6772437,-38.26787
parent: 1
- proto: CP14CandleGreen
entities:
- uid: 7165
@@ -40719,17 +40720,17 @@ entities:
rot: 3.141592653589793 rad
pos: -5.5,-34.5
parent: 1
- uid: 11655
- uid: 11140
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 5.5,-34.5
rot: 1.5707963267948966 rad
pos: 3.5,-31.5
parent: 1
- uid: 11656
- uid: 11311
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 4.5,-34.5
rot: 1.5707963267948966 rad
pos: 3.5,-32.5
parent: 1
- proto: CP14Dayflin
entities:
@@ -65910,12 +65911,6 @@ entities:
rot: 1.5707963267948966 rad
pos: -7.5,-43.5
parent: 1
- uid: 15366
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 6.5,-36.5
parent: 1
- uid: 15367
components:
- type: Transform
@@ -67628,11 +67623,6 @@ entities:
- type: Transform
pos: 12.5,-43.5
parent: 1
- uid: 15370
components:
- type: Transform
pos: 3.5,-36.5
parent: 1
- uid: 15371
components:
- type: Transform
@@ -68827,6 +68817,14 @@ entities:
fixtures: {}
- proto: CP14WallmountLampEmpty
entities:
- uid: 11070
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 3.5,-30.5
parent: 1
- type: Fixtures
fixtures: {}
- uid: 11758
components:
- type: Transform
@@ -68956,14 +68954,6 @@ entities:
parent: 1
- type: Fixtures
fixtures: {}
- uid: 11836
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 3.5,-32.5
parent: 1
- type: Fixtures
fixtures: {}
- uid: 11837
components:
- type: Transform
@@ -82689,6 +82679,16 @@ entities:
- type: Transform
pos: 2.5,21.5
parent: 1
- uid: 11393
components:
- type: Transform
pos: 4.5,-35.5
parent: 1
- uid: 11394
components:
- type: Transform
pos: 5.5,-35.5
parent: 1
- uid: 14358
components:
- type: Transform
@@ -83812,16 +83812,6 @@ entities:
- type: Transform
pos: -6.5,1.5
parent: 1
- uid: 14579
components:
- type: Transform
pos: 2.5,-32.5
parent: 1
- uid: 14581
components:
- type: Transform
pos: 2.5,-31.5
parent: 1
- uid: 14582
components:
- type: Transform
@@ -85516,15 +85506,17 @@ entities:
rot: -1.5707963267948966 rad
pos: 6.5,19.5
parent: 1
- uid: 14592
- uid: 11312
components:
- type: Transform
pos: 4.5,-35.5
rot: 1.5707963267948966 rad
pos: 2.5,-32.5
parent: 1
- uid: 14608
- uid: 11370
components:
- type: Transform
pos: 5.5,-35.5
rot: 1.5707963267948966 rad
pos: 2.5,-31.5
parent: 1
- uid: 14695
components:

View File

@@ -4,8 +4,8 @@ meta:
engineVersion: 260.2.0
forkId: ""
forkVersion: ""
time: 06/07/2025 21:12:48
entityCount: 15201
time: 06/15/2025 11:14:05
entityCount: 15204
maps:
- 2
grids:
@@ -96,7 +96,7 @@ entities:
version: 7
0,-1:
ind: 0,-1
tiles: IAAAAAAEACAAAAAABAAgAAAAAAEAIAAAAAAEACAAAAAABAAgAAAAAAEAIAAAAAAEACAAAAAAAwACAAAAAAoAAgAAAAAEAAIAAAAAAAACAAAAAAkAAgAAAAACAAIAAAAABwACAAAAAAcAAgAAAAALACAAAAAAAwAgAAAAAAEAIAAAAAAEACAAAAAAAwAgAAAAAAMAAgAAAAAGACAAAAAAAgAgAAAAAAEAIAAAAAAAACAAAAAAAwACAAAAAAsAAgAAAAAOAAIAAAAAAwACAAAAAAsAAgAAAAAJACAAAAAAAQAgAAAAAAEAIAAAAAADACAAAAAABAAgAAAAAAMAIAAAAAADAAIAAAAADQACAAAAAAwAIAAAAAABAAIAAAAADgACAAAAAA8AAgAAAAAGACAAAAAAAAAgAAAAAAQAIAAAAAADACAAAAAABAAgAAAAAAMAAgAAAAAMAAIAAAAAAgACAAAAAAkAAgAAAAAAAAIAAAAABAACAAAAAAkAIAAAAAADACAAAAAAAgACAAAAAAkAAgAAAAACAAIAAAAADwAgAAAAAAQAIAAAAAADAAIAAAAABAACAAAAAA8AAgAAAAAMAAIAAAAAAQACAAAAAA8AAgAAAAADAAIAAAAAAgACAAAAAAsAAgAAAAAJAAIAAAAADgACAAAAAAgAAgAAAAAEAAIAAAAABAACAAAAAAgAAgAAAAACAB0AAAAAAAAeAAAAAAIAHgAAAAACAB4AAAAAAwAdAAAAAAMAHQAAAAADAB4AAAAAAwAeAAAAAAQAHgAAAAACAB4AAAAAAQAeAAAAAAIAHQAAAAACAB0AAAAAAAAdAAAAAAEAHQAAAAAEAB4AAAAAAAAeAAAAAAQAHQAAAAABAAIAAAAAAgAgAAAAAAMAAgAAAAALAAIAAAAACAACAAAAAA0AAgAAAAANAAIAAAAACwACAAAAAAMAAgAAAAAKAAIAAAAABwAgAAAAAAEAIAAAAAACACAAAAAAAgACAAAAAAoAAgAAAAACAAIAAAAADAACAAAAAAAAAgAAAAALACAAAAAAAQACAAAAAA4AAgAAAAAGACAAAAAAAQAgAAAAAAAAIAAAAAADACAAAAAAAQACAAAAAAgAAgAAAAABAAIAAAAAAQACAAAAAAsAAgAAAAAFAAIAAAAACQACAAAAAAQAIAAAAAADAAIAAAAACgAcAAAAAAUAHAAAAAAAABwAAAAAAgAcAAAAAAUAHAAAAAAFAB0AAAAABAAdAAAAAAEAHQAAAAACAB0AAAAAAgAdAAAAAAQAHQAAAAAFAB0AAAAABAAdAAAAAAMAHQAAAAADACAAAAAAAwAgAAAAAAIAHAAAAAACABwAAAAAAQAcAAAAAAMAHAAAAAABAB0AAAAAAgAdAAAAAAQAHQAAAAADAB4AAAAABAAFAAAAAAAABQAAAAABAAUAAAAAAAAFAAAAAAMABQAAAAADAB0AAAAABQAgAAAAAAIAIAAAAAAEAB0AAAAAAQAdAAAAAAAAHAAAAAABABwAAAAAAwAdAAAAAAEAHQAAAAADAB4AAAAABAAeAAAAAAUABQAAAAABAAUAAAAAAQAFAAAAAAMABQAAAAAAAAUAAAAAAAAHAAAAAAIABQAAAAAAAAUAAAAAAAAeAAAAAAEAHQAAAAACABwAAAAAAgAcAAAAAAMABQAAAAADAAUAAAAAAwAHAAAAAAMABwAAAAACAAcAAAAAAAAHAAAAAAAABQAAAAACAAYAAAAAAwAFAAAAAAEABQAAAAACAAUAAAAAAQAFAAAAAAEAHgAAAAABAB0AAAAAAgAdAAAAAAAAHAAAAAADAAUAAAAAAwAFAAAAAAMABwAAAAADAAcAAAAAAAAHAAAAAAMABwAAAAACAAUAAAAAAQAGAAAAAAAABQAAAAABAAUAAAAAAgAHAAAAAAAABwAAAAACAA4AAAAAAAAOAAAAAAQAHgAAAAABAB0AAAAABQAFAAAAAAEABQAAAAACAAcAAAAAAAAHAAAAAAMABwAAAAACAAcAAAAAAAAFAAAAAAMABQAAAAACAAUAAAAAAgAFAAAAAAAABwAAAAABAAcAAAAAAAAOAAAAAAQADgAAAAAEAA4AAAAAAAAdAAAAAAQABQAAAAADAAUAAAAAAwAFAAAAAAEABQAAAAADAAUAAAAAAQAFAAAAAAEABQAAAAACAAUAAAAAAgAFAAAAAAMABQAAAAAAAAcAAAAAAwAHAAAAAAAAIQAAAAAEAA4AAAAAAgAOAAAAAAMAHQAAAAAAAAUAAAAAAAAFAAAAAAIABQAAAAADAAYAAAAAAQAGAAAAAAMABgAAAAADAAUAAAAAAgAFAAAAAAIABQAAAAACAAUAAAAAAwAFAAAAAAMABQAAAAACAA==
tiles: IAAAAAAEACAAAAAABAAgAAAAAAEAIAAAAAAEACAAAAAABAAgAAAAAAEAIAAAAAAEACAAAAAAAwACAAAAAAoAAgAAAAAEAAIAAAAAAAACAAAAAAkAAgAAAAACAAIAAAAABwACAAAAAAcAAgAAAAALACAAAAAAAwAgAAAAAAEAIAAAAAAEACAAAAAAAwAgAAAAAAMAAgAAAAAGACAAAAAAAgAgAAAAAAEAIAAAAAAAACAAAAAAAwACAAAAAAsAAgAAAAAOAAIAAAAAAwACAAAAAAsAAgAAAAAJACAAAAAAAQAgAAAAAAEAIAAAAAADACAAAAAABAAgAAAAAAMAIAAAAAADAAIAAAAADQACAAAAAAwAIAAAAAABAAIAAAAADgACAAAAAA8AAgAAAAAGACAAAAAAAAAgAAAAAAQAIAAAAAADACAAAAAABAAgAAAAAAMAAgAAAAAMAAIAAAAAAgACAAAAAAkAAgAAAAAAAAIAAAAABAACAAAAAAkAIAAAAAADACAAAAAAAgACAAAAAAkAAgAAAAACAAIAAAAADwAgAAAAAAQAIAAAAAADAAIAAAAABAACAAAAAA8AAgAAAAAMAAIAAAAAAQACAAAAAA8AAgAAAAADAAIAAAAAAgACAAAAAAsAAgAAAAAJAAIAAAAADgACAAAAAAgAAgAAAAAEAAIAAAAABAACAAAAAAgAAgAAAAACAB0AAAAAAAAeAAAAAAIAHgAAAAACAB4AAAAAAwAdAAAAAAMAHQAAAAADAB4AAAAAAwAeAAAAAAQAHgAAAAACAB4AAAAAAQAeAAAAAAIAHQAAAAACAB0AAAAAAAAdAAAAAAEAHQAAAAAEAB4AAAAAAAAeAAAAAAQAHQAAAAABAAIAAAAAAgAgAAAAAAMAAgAAAAALAAIAAAAACAACAAAAAA0AAgAAAAANAAIAAAAACwACAAAAAAMAAgAAAAAKAAIAAAAABwAgAAAAAAEAIAAAAAACACAAAAAAAgACAAAAAAoAAgAAAAACAAIAAAAADAACAAAAAAAAAgAAAAALACAAAAAAAQACAAAAAA4AAgAAAAAGACAAAAAAAQAgAAAAAAAAIAAAAAADACAAAAAAAQACAAAAAAgAAgAAAAABAAIAAAAAAQACAAAAAAsAAgAAAAAFAAIAAAAACQACAAAAAAQAIAAAAAADAAIAAAAACgAcAAAAAAUAHAAAAAAAABwAAAAAAgAcAAAAAAUAHAAAAAAFAB0AAAAABAAdAAAAAAEAHQAAAAACAB0AAAAAAgAdAAAAAAQAHQAAAAAFAB0AAAAABAAdAAAAAAMAHQAAAAADACAAAAAAAwAgAAAAAAIAEAAAAAAAABAAAAAAAAAQAAAAAAAAHAAAAAABAB0AAAAAAgAdAAAAAAQAHQAAAAADAB4AAAAABAAFAAAAAAAABQAAAAABAAUAAAAAAAAFAAAAAAMABQAAAAADAB0AAAAABQAgAAAAAAIAIAAAAAAEABAAAAAAAAARAAAAAAAAEAAAAAAAABwAAAAAAwAdAAAAAAEAHQAAAAADAB4AAAAABAAeAAAAAAUABQAAAAABAAUAAAAAAQAFAAAAAAMABQAAAAAAAAUAAAAAAAAHAAAAAAIABQAAAAAAAAUAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAcAAAAAAMABQAAAAADAAUAAAAAAwAHAAAAAAMABwAAAAACAAcAAAAAAAAHAAAAAAAABQAAAAACAAYAAAAAAwAFAAAAAAEABQAAAAACAAUAAAAAAQAFAAAAAAEAHgAAAAABAB0AAAAAAgAdAAAAAAAAHAAAAAADAAUAAAAAAwAFAAAAAAMABwAAAAADAAcAAAAAAAAHAAAAAAMABwAAAAACAAUAAAAAAQAGAAAAAAAABQAAAAABAAUAAAAAAgAHAAAAAAAABwAAAAACAA4AAAAAAAAOAAAAAAQAHgAAAAABAB0AAAAABQAFAAAAAAEABQAAAAACAAcAAAAAAAAHAAAAAAMABwAAAAACAAcAAAAAAAAFAAAAAAMABQAAAAACAAUAAAAAAgAFAAAAAAAABwAAAAABAAcAAAAAAAAOAAAAAAQADgAAAAAEAA4AAAAAAAAdAAAAAAQABQAAAAADAAUAAAAAAwAFAAAAAAEABQAAAAADAAUAAAAAAQAFAAAAAAEABQAAAAACAAUAAAAAAgAFAAAAAAMABQAAAAAAAAcAAAAAAwAHAAAAAAAAIQAAAAAEAA4AAAAAAgAOAAAAAAMAHQAAAAAAAAUAAAAAAAAFAAAAAAIABQAAAAADAAYAAAAAAQAGAAAAAAMABgAAAAADAAUAAAAAAgAFAAAAAAIABQAAAAACAAUAAAAAAwAFAAAAAAMABQAAAAACAA==
version: 7
0,0:
ind: 0,0
@@ -500,11 +500,24 @@ entities:
id: CP14BrickTileStoneInnerNe
decals:
79: 8,-31
142: 0,-7
143: 0,-7
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneInnerNw
decals:
144: 2,-7
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneInnerSe
decals:
78: 8,-28
140: 0,-5
- node:
color: '#FFFFFFFF'
id: CP14BrickTileStoneInnerSw
decals:
141: 2,-5
- node:
color: '#DE3A3A96'
id: CP14BrickTileStoneLineE
@@ -519,6 +532,7 @@ entities:
51: 24,-24
74: 8,-30
75: 8,-29
138: 0,-6
- node:
color: '#DE3A3A96'
id: CP14BrickTileStoneLineN
@@ -532,6 +546,7 @@ entities:
47: 22,-23
48: 23,-23
77: 9,-31
139: 1,-7
- node:
color: '#DE3A3A96'
id: CP14BrickTileStoneLineS
@@ -545,6 +560,7 @@ entities:
42: 22,-27
43: 23,-27
76: 9,-28
136: 1,-5
- node:
color: '#DE3A3A96'
id: CP14BrickTileStoneLineW
@@ -557,6 +573,7 @@ entities:
44: 21,-26
45: 21,-25
46: 21,-24
137: 2,-6
- node:
color: '#FFFFFFFF'
id: CP14FloraGrass10
@@ -753,6 +770,13 @@ entities:
rot: 1.5707963267948966 rad
pos: 5.5,0.5
parent: 2
- proto: CP14AltarPrimordialGodLumera
entities:
- uid: 12327
components:
- type: Transform
pos: 1.5,-5.5
parent: 2
- proto: CP14BarrelBloodGoblin
entities:
- uid: 8065
@@ -30239,6 +30263,25 @@ entities:
rot: -1.5707963267948966 rad
pos: 48.210453,-20.351133
parent: 2
- proto: CP14CandleBlue
entities:
- uid: 12328
components:
- type: Transform
pos: 0.7710935,-5.9935446
parent: 2
- uid: 15201
components:
- type: Transform
pos: 2.2783234,-5.80239
parent: 2
- proto: CP14CandleBlueSmall
entities:
- uid: 15202
components:
- type: Transform
pos: 1.5022119,-4.666708
parent: 2
- proto: CP14CarpetBlue
entities:
- uid: 1836
@@ -33924,6 +33967,13 @@ entities:
- type: Transform
pos: -25.5,-33.5
parent: 2
- proto: CP14ClothingBlueCollarDress
entities:
- uid: 15203
components:
- type: Transform
pos: 1.5201155,-6.2672186
parent: 2
- proto: CP14ClothingSatchelLeather
entities:
- uid: 1484
@@ -34254,7 +34304,7 @@ entities:
pos: 14.5,-24.5
parent: 2
- type: Door
secondsUntilStateChange: -8969.771
secondsUntilStateChange: -9077.496
state: Closing
- uid: 1792
components:
@@ -52183,12 +52233,6 @@ entities:
- type: Transform
pos: 24.5,-42.5
parent: 2
- uid: 12328
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 3.5,-6.5
parent: 2
- uid: 12329
components:
- type: Transform
@@ -52292,12 +52336,6 @@ entities:
rot: -1.5707963267948966 rad
pos: -0.5,-10.5
parent: 2
- uid: 12327
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 1.5,-4.5
parent: 2
- uid: 12334
components:
- type: Transform
@@ -77711,6 +77749,13 @@ entities:
rot: 3.141592653589793 rad
pos: 44.5,-28.5
parent: 2
- proto: CP14TableMarble
entities:
- uid: 15204
components:
- type: Transform
pos: 1.5,-6.5
parent: 2
- proto: CP14TableWooden
entities:
- uid: 1459
@@ -79091,13 +79136,6 @@ entities:
parent: 2
- type: Fixtures
fixtures: {}
- uid: 15201
components:
- type: Transform
pos: 4.5,-5.5
parent: 2
- type: Fixtures
fixtures: {}
- proto: CP14WallmountFlagBank
entities:
- uid: 7830

View File

@@ -88,6 +88,7 @@
#- type: WirelessNetworkConnection
# range: 500
#- type: StationLimitedNetwork
- type: CP14SkillScanner
- type: Thieving
stripTimeReduction: 9999
stealthy: true

View File

@@ -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

View File

@@ -47,7 +47,6 @@
- id: CP14StampDenied
- id: CP14StampApproved
- id: CP14ManaOperationGlove
- id: AppraisalTool
- id: CP14PaperFolderRed
amount: 2
- id: CP14PaperFolderBlue

View File

@@ -16,3 +16,8 @@
- Toxin
- Genetic
- CP14Magic
- type: damageContainer
id: CP14Spectral
supportedGroups:
- CP14Magic

Some files were not shown because too many files have changed in this diff Show More