Merge branch 'master' into Alchemy-Redux
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using Content.Client._CP14.Discord;
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client.Chat.Managers;
|
||||
@@ -43,6 +44,9 @@ namespace Content.Client.Entry
|
||||
{
|
||||
public sealed class EntryPoint : GameClient
|
||||
{
|
||||
//CP14
|
||||
[Dependency] private readonly DiscordAuthManager _discordAuth = default!;
|
||||
//CP14 end
|
||||
[Dependency] private readonly IBaseClient _baseClient = default!;
|
||||
[Dependency] private readonly IGameController _gameController = default!;
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
@@ -160,7 +164,10 @@ namespace Content.Client.Entry
|
||||
|
||||
_parallaxManager.LoadDefaultParallax();
|
||||
|
||||
_overlayManager.AddOverlay(new CP14BasePostProcessOverlay()); // CP14-PostProcess
|
||||
//CP14
|
||||
_overlayManager.AddOverlay(new CP14BasePostProcessOverlay());
|
||||
_discordAuth.Initialize();
|
||||
//CP14 end
|
||||
_overlayManager.AddOverlay(new SingularityOverlay());
|
||||
_overlayManager.AddOverlay(new RadiationPulseOverlay());
|
||||
_chatManager.Initialize();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Client._CP14.Discord;
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Changelog;
|
||||
using Content.Client.Chat.Managers;
|
||||
@@ -33,6 +34,9 @@ namespace Content.Client.IoC
|
||||
{
|
||||
var collection = IoCManager.Instance!;
|
||||
|
||||
//CP14
|
||||
collection.Register<DiscordAuthManager>();
|
||||
//CP14 end
|
||||
collection.Register<IParallaxManager, ParallaxManager>();
|
||||
collection.Register<IChatManager, ChatManager>();
|
||||
collection.Register<ISharedChatManager, ChatManager>();
|
||||
|
||||
27
Content.Client/_CP14/Discord/CP14DiscordAuthManager.cs
Normal file
27
Content.Client/_CP14/Discord/CP14DiscordAuthManager.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Content.Shared._CP14.Discord;
|
||||
using Robust.Client.State;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Client._CP14.Discord;
|
||||
|
||||
public sealed class DiscordAuthManager
|
||||
{
|
||||
[Dependency] private readonly IClientNetManager _netManager = default!;
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
|
||||
public string AuthUrl { get; private set; } = "";
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgDiscordAuthCheck>();
|
||||
_netManager.RegisterNetMessage<MsgDiscordAuthRequired>(OnDiscordAuthRequired);
|
||||
}
|
||||
|
||||
private void OnDiscordAuthRequired(MsgDiscordAuthRequired msg)
|
||||
{
|
||||
if (_stateManager.CurrentState is DiscordAuthState)
|
||||
return;
|
||||
AuthUrl = msg.AuthUrl;
|
||||
_stateManager.RequestStateChange<DiscordAuthState>();
|
||||
}
|
||||
}
|
||||
36
Content.Client/_CP14/Discord/CP14DiscordAuthState.cs
Normal file
36
Content.Client/_CP14/Discord/CP14DiscordAuthState.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Threading;
|
||||
using Content.Shared._CP14.Discord;
|
||||
using Robust.Client.State;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Network;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
|
||||
namespace Content.Client._CP14.Discord;
|
||||
|
||||
public sealed class DiscordAuthState : State
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IClientNetManager _netManager = default!;
|
||||
|
||||
private DiscordAuthGui? _gui;
|
||||
private readonly CancellationTokenSource _checkTimerCancel = new();
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
_gui = new DiscordAuthGui();
|
||||
_userInterfaceManager.StateRoot.AddChild(_gui);
|
||||
|
||||
Timer.SpawnRepeating(TimeSpan.FromSeconds(5),
|
||||
() =>
|
||||
{
|
||||
_netManager.ClientSendMessage(new MsgDiscordAuthCheck());
|
||||
},
|
||||
_checkTimerCancel.Token);
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
_checkTimerCancel.Cancel();
|
||||
_gui!.Dispose();
|
||||
}
|
||||
}
|
||||
29
Content.Client/_CP14/Discord/DiscordAuthGui.xaml
Normal file
29
Content.Client/_CP14/Discord/DiscordAuthGui.xaml
Normal file
@@ -0,0 +1,29 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:parallax="clr-namespace:Content.Client.Parallax"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls">
|
||||
<parallax:ParallaxControl />
|
||||
<Control HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<PanelContainer StyleClasses="AngleRect" />
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Margin="8 0 0 0" Text="{Loc 'cp14-discord-auth-title'}"
|
||||
StyleClasses="LabelHeading" VAlign="Center" />
|
||||
<Button Name="QuitButton" Text="{Loc 'cp14-discord-auth-quit-btn'}"
|
||||
HorizontalAlignment="Right" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<controls:HighDivider />
|
||||
<BoxContainer Orientation="Vertical" Margin="50 20 50 20">
|
||||
<RichTextLabel Name="InfoLabel" />
|
||||
</BoxContainer>
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<LineEdit Editable="False" Name="AuthLinkEdit" HorizontalExpand="True" />
|
||||
<LineEdit Editable="False" Name="DLinkEdit" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Button Name="AuthorizeButton" Text="{Loc 'cp14-discord-auth-text'}" HorizontalExpand="True" StyleClasses="OpenRight" />
|
||||
<Button Name="DiscordButton" Text="{Loc 'cp14-discord-auth-browser-btn'}" HorizontalExpand="True" StyleClasses="OpenRight" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
</Control>
|
||||
46
Content.Client/_CP14/Discord/DiscordAuthGui.xaml.cs
Normal file
46
Content.Client/_CP14/Discord/DiscordAuthGui.xaml.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._CP14.Discord;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class DiscordAuthGui : Control
|
||||
{
|
||||
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
||||
[Dependency] private readonly DiscordAuthManager _discordAuthManager = default!;
|
||||
|
||||
private const string DiscordLink = "https://discord.com/invite/Sud2DMfhCC"; //TODO: Unhardcode
|
||||
|
||||
public DiscordAuthGui()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
LayoutContainer.SetAnchorPreset(this, LayoutContainer.LayoutPreset.Wide);
|
||||
|
||||
var link = _discordAuthManager.AuthUrl;
|
||||
|
||||
AuthLinkEdit.SetText(link);
|
||||
DLinkEdit.SetText(DiscordLink);
|
||||
InfoLabel.SetMessage(Loc.GetString("cp14-discord-info"));
|
||||
|
||||
var uriOpener = IoCManager.Resolve<IUriOpener>();
|
||||
|
||||
QuitButton.OnPressed += _ =>
|
||||
{
|
||||
_consoleHost.ExecuteCommand("quit");
|
||||
};
|
||||
|
||||
AuthorizeButton.OnPressed += _ =>
|
||||
{
|
||||
uriOpener.OpenUri(link);
|
||||
};
|
||||
|
||||
DiscordButton.OnPressed += _ =>
|
||||
{
|
||||
uriOpener.OpenUri(DiscordLink);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,14 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<GridContainer Columns="2">
|
||||
<EntityPrototypeView
|
||||
Name="EntityView"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
MaxSize="48 48"
|
||||
Scale="2,2"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalExpand="True" />
|
||||
<TextureRect
|
||||
Name="View"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
MaxSize="48 48"
|
||||
HorizontalAlignment="Left"
|
||||
Stretch="KeepAspectCentered" />
|
||||
<Label Name="Name" />
|
||||
</GridContainer>
|
||||
<Button Name="Button">
|
||||
<GridContainer Columns="2">
|
||||
<EntityPrototypeView Name="View"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
MaxSize="48 48"
|
||||
Scale="2,2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalExpand="True"/>
|
||||
<Label Name="Name"/>
|
||||
</GridContainer>
|
||||
</Button>
|
||||
</Control>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
@@ -13,13 +13,14 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.Client._CP14.Workbench;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14WorkbenchRecipeControl : Control
|
||||
public sealed partial class CP14WorkbenchRequirementControl : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
|
||||
public CP14WorkbenchRecipeControl()
|
||||
public CP14WorkbenchRequirementControl()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
@@ -27,25 +28,22 @@ public sealed partial class CP14WorkbenchRecipeControl : Control
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
}
|
||||
|
||||
public CP14WorkbenchRecipeControl(EntityPrototype prototype, int count) : this()
|
||||
public CP14WorkbenchRequirementControl(CP14WorkbenchCraftRequirement requirement) : this()
|
||||
{
|
||||
var entityName = prototype.Name;
|
||||
Name.Text = count <= 1 ? entityName : $"{entityName} x{count}";
|
||||
Name.Text = requirement.GetRequirementTitle(_proto);
|
||||
|
||||
View.Visible = false;
|
||||
EntityView.SetPrototype(prototype);
|
||||
}
|
||||
var texture = requirement.GetRequirementTexture(_proto);
|
||||
if (texture is not null)
|
||||
{
|
||||
View.Visible = true;
|
||||
View.Texture = _sprite.Frame0(texture);
|
||||
}
|
||||
|
||||
public CP14WorkbenchRecipeControl(StackPrototype prototype, int count) : this()
|
||||
{
|
||||
var entityName = Loc.GetString(prototype.Name);
|
||||
Name.Text = $"{entityName} x{count}";
|
||||
|
||||
var icon = prototype.Icon;
|
||||
if (icon is null)
|
||||
return;
|
||||
|
||||
EntityView.Visible = false;
|
||||
View.Texture = _sprite.Frame0(icon);
|
||||
var entityView = requirement.GetRequirementEntityView(_proto);
|
||||
if (entityView is not null)
|
||||
{
|
||||
EntityView.Visible = true;
|
||||
EntityView.SetPrototype(entityView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<Button Name="Button">
|
||||
<GridContainer Columns="2">
|
||||
<EntityPrototypeView Name="View"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
MaxSize="48 48"
|
||||
Scale="2,2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalExpand="True"/>
|
||||
<Label Name="Name"/>
|
||||
</GridContainer>
|
||||
</Button>
|
||||
<GridContainer Columns="2">
|
||||
<EntityPrototypeView
|
||||
Name="EntityView"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
MaxSize="48 48"
|
||||
Scale="2,2"
|
||||
HorizontalAlignment="Left"
|
||||
Visible="False"
|
||||
VerticalExpand="True" />
|
||||
<TextureRect
|
||||
Name="View"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
MaxSize="48 48"
|
||||
HorizontalAlignment="Left"
|
||||
Visible="False"
|
||||
Stretch="KeepAspectCentered" />
|
||||
<Label Name="Name" />
|
||||
</GridContainer>
|
||||
</Control>
|
||||
|
||||
@@ -14,7 +14,7 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.Client._CP14.Workbench;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14WorkbenchRequirementControl : Control
|
||||
public sealed partial class CP14WorkbenchRecipeControl : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
@@ -26,7 +26,7 @@ public sealed partial class CP14WorkbenchRequirementControl : Control
|
||||
private readonly CP14WorkbenchRecipePrototype _recipePrototype;
|
||||
private readonly bool _craftable;
|
||||
|
||||
public CP14WorkbenchRequirementControl(CP14WorkbenchUiRecipesEntry entry)
|
||||
public CP14WorkbenchRecipeControl(CP14WorkbenchUiRecipesEntry entry)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
@@ -74,7 +74,7 @@ public sealed partial class CP14WorkbenchWindow : DefaultWindow
|
||||
|
||||
if (entry.Craftable)
|
||||
{
|
||||
var control = new CP14WorkbenchRequirementControl(entry);
|
||||
var control = new CP14WorkbenchRecipeControl(entry);
|
||||
control.OnSelect += RecipeSelect;
|
||||
CraftsContainer.AddChild(control);
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public sealed partial class CP14WorkbenchWindow : DefaultWindow
|
||||
|
||||
foreach (var entry in uncraftableList)
|
||||
{
|
||||
var control = new CP14WorkbenchRequirementControl(entry);
|
||||
var control = new CP14WorkbenchRecipeControl(entry);
|
||||
control.OnSelect += RecipeSelect;
|
||||
CraftsContainer.AddChild(control);
|
||||
}
|
||||
@@ -119,14 +119,10 @@ public sealed partial class CP14WorkbenchWindow : DefaultWindow
|
||||
ItemDescription.Text = result.Description;
|
||||
|
||||
ItemRequirements.RemoveAllChildren();
|
||||
foreach (var (entProtoId, count) in recipe.Entities)
|
||||
{
|
||||
ItemRequirements.AddChild(new CP14WorkbenchRecipeControl(_prototype.Index(entProtoId), count));
|
||||
}
|
||||
|
||||
foreach (var (stackProtoId, count) in recipe.Stacks)
|
||||
foreach (var requirement in recipe.Requirements)
|
||||
{
|
||||
ItemRequirements.AddChild(new CP14WorkbenchRecipeControl(_prototype.Index(stackProtoId), count));
|
||||
ItemRequirements.AddChild(new CP14WorkbenchRequirementControl(requirement));
|
||||
}
|
||||
|
||||
CraftButton.Disabled = !entry.Craftable;
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace Content.IntegrationTests.Tests
|
||||
.Where(p => !p.Abstract)
|
||||
.Where(p => !pair.IsTestPrototype(p))
|
||||
.Where(p => !p.Components.ContainsKey("MapGrid")) // This will smash stuff otherwise.
|
||||
.Where(p => !p.Components.ContainsKey("RoomFill"))
|
||||
.Select(p => p.ID)
|
||||
.ToList();
|
||||
|
||||
@@ -101,6 +102,7 @@ namespace Content.IntegrationTests.Tests
|
||||
.Where(p => !p.Abstract)
|
||||
.Where(p => !pair.IsTestPrototype(p))
|
||||
.Where(p => !p.Components.ContainsKey("MapGrid")) // This will smash stuff otherwise.
|
||||
.Where(p => !p.Components.ContainsKey("RoomFill"))
|
||||
.Select(p => p.ID)
|
||||
.ToList();
|
||||
foreach (var protoId in protoIds)
|
||||
@@ -341,6 +343,7 @@ namespace Content.IntegrationTests.Tests
|
||||
"DebugExceptionInitialize",
|
||||
"DebugExceptionStartup",
|
||||
"GridFill",
|
||||
"RoomFill",
|
||||
"Map", // We aren't testing a map entity in this test
|
||||
"MapGrid",
|
||||
"Broadphase",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server._CP14.Discord;
|
||||
using Content.Server.Acz;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Administration.Logs;
|
||||
@@ -101,6 +102,10 @@ namespace Content.Server.Entry
|
||||
logManager.GetSawmill("Storage").Level = LogLevel.Info;
|
||||
logManager.GetSawmill("db.ef").Level = LogLevel.Info;
|
||||
|
||||
//CP14
|
||||
IoCManager.Resolve<DiscordAuthManager>().Initialize();
|
||||
//CP14 end
|
||||
|
||||
IoCManager.Resolve<IAdminLogManager>().Initialize();
|
||||
IoCManager.Resolve<IConnectionManager>().Initialize();
|
||||
_dbManager.Init();
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Content.Server.GameTicking
|
||||
|
||||
// Make the player actually join the game.
|
||||
// timer time must be > tick length
|
||||
Timer.Spawn(0, () => _playerManager.JoinGame(args.Session));
|
||||
//Timer.Spawn(0, () => _playerManager.JoinGame(args.Session)); //CP14 Discord AuthManager
|
||||
|
||||
var record = await _db.GetPlayerRecordByUserId(args.Session.UserId);
|
||||
var firstConnection = record != null &&
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server._CP14.Discord;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Administration.Managers;
|
||||
@@ -36,6 +37,9 @@ namespace Content.Server.IoC
|
||||
{
|
||||
public static void Register()
|
||||
{
|
||||
//CP14
|
||||
IoCManager.Register<DiscordAuthManager>();
|
||||
//CP14 end
|
||||
IoCManager.Register<IChatManager, ChatManager>();
|
||||
IoCManager.Register<ISharedChatManager, ChatManager>();
|
||||
IoCManager.Register<IChatSanitizationManager, ChatSanitizationManager>();
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
}
|
||||
|
||||
// Convert smokable item into reagents to be smoked
|
||||
private bool TryTransferReagents(Entity<SmokingPipeComponent> entity, Entity<SmokableComponent> smokable)
|
||||
public bool TryTransferReagents(Entity<SmokingPipeComponent> entity, Entity<SmokableComponent> smokable) //CP14 make it public
|
||||
{
|
||||
if (entity.Comp.BowlSlot.Item == null)
|
||||
return false;
|
||||
|
||||
@@ -130,31 +130,31 @@ public sealed partial class DungeonSystem
|
||||
|
||||
var finalRoomRotation = roomTransform.Rotation();
|
||||
|
||||
if (clearExisting)
|
||||
{
|
||||
var point1 = Vector2.Transform(-room.Size / 2, roomTransform);
|
||||
var point2 = Vector2.Transform(room.Size / 2, roomTransform);
|
||||
|
||||
var gridBounds = GetRotatedBox(point1, point2, finalRoomRotation);
|
||||
|
||||
entitySet.Clear();
|
||||
// Polygon skin moment
|
||||
gridBounds = gridBounds.Enlarged(-0.05f);
|
||||
_lookup.GetLocalEntitiesIntersecting(gridUid, gridBounds, entitySet, LookupFlags.Uncontained);
|
||||
|
||||
foreach (var templateEnt in entitySet)
|
||||
{
|
||||
Del(templateEnt);
|
||||
}
|
||||
|
||||
if (TryComp(gridUid, out DecalGridComponent? decalGrid))
|
||||
{
|
||||
foreach (var decal in _decals.GetDecalsIntersecting(gridUid, gridBounds, decalGrid))
|
||||
{
|
||||
_decals.RemoveDecal(gridUid, decal.Index, decalGrid);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (clearExisting) //CP14 disable default clearExisting
|
||||
//{
|
||||
// var point1 = Vector2.Transform(-room.Size / 2, roomTransform);
|
||||
// var point2 = Vector2.Transform(room.Size / 2, roomTransform);
|
||||
//
|
||||
// var gridBounds = GetRotatedBox(point1, point2, finalRoomRotation);
|
||||
//
|
||||
// entitySet.Clear();
|
||||
// // Polygon skin moment
|
||||
// gridBounds = gridBounds.Enlarged(-0.05f);
|
||||
// _lookup.GetLocalEntitiesIntersecting(gridUid, gridBounds, entitySet, LookupFlags.Uncontained);
|
||||
//
|
||||
// foreach (var templateEnt in entitySet)
|
||||
// {
|
||||
// Del(templateEnt);
|
||||
// }
|
||||
//
|
||||
// if (TryComp(gridUid, out DecalGridComponent? decalGrid))
|
||||
// {
|
||||
// foreach (var decal in _decals.GetDecalsIntersecting(gridUid, gridBounds, decalGrid))
|
||||
// {
|
||||
// _decals.RemoveDecal(gridUid, decal.Index, decalGrid);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
var roomCenter = (room.Offset + room.Size / 2f) * grid.TileSize;
|
||||
var tileOffset = -roomCenter + grid.TileSizeHalfVector;
|
||||
@@ -183,14 +183,14 @@ public sealed partial class DungeonSystem
|
||||
_tiles.Add((rounded, tileRef.Tile));
|
||||
|
||||
//CP14 clearExisting variant
|
||||
//if (clearExisting)
|
||||
//{
|
||||
// var anchored = _maps.GetAnchoredEntities((gridUid, grid), rounded);
|
||||
// foreach (var ent in anchored)
|
||||
// {
|
||||
// QueueDel(ent);
|
||||
// }
|
||||
//}
|
||||
if (clearExisting)
|
||||
{
|
||||
var anchored = _maps.GetAnchoredEntities((gridUid, grid), rounded);
|
||||
foreach (var ent in anchored)
|
||||
{
|
||||
QueueDel(ent);
|
||||
}
|
||||
}
|
||||
//CP14 clearExisting variant end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
using System.Linq;
|
||||
using Content.Server._CP14.BiomeSpawner.Components;
|
||||
using Content.Server._CP14.RoundSeed;
|
||||
using Content.Server.Decals;
|
||||
using Content.Server.Parallax;
|
||||
using Content.Shared.Whitelist;
|
||||
@@ -13,6 +12,7 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.BiomeSpawner.EntitySystems;
|
||||
|
||||
@@ -24,12 +24,21 @@ public sealed class CP14BiomeSpawnerSystem : EntitySystem
|
||||
[Dependency] private readonly SharedMapSystem _maps = default!;
|
||||
[Dependency] private readonly DecalSystem _decals = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly CP14RoundSeedSystem _roundSeed = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private int _globalSeed = 0;
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14BiomeSpawnerComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<Shared.GameTicking.RoundEndMessageEvent>(OnRoundEnd);
|
||||
|
||||
UpdateSeed();
|
||||
}
|
||||
|
||||
private void OnRoundEnd(Shared.GameTicking.RoundEndMessageEvent ev)
|
||||
{
|
||||
UpdateSeed();
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CP14BiomeSpawnerComponent> ent, ref MapInitEvent args)
|
||||
@@ -38,6 +47,11 @@ public sealed class CP14BiomeSpawnerSystem : EntitySystem
|
||||
QueueDel(ent);
|
||||
}
|
||||
|
||||
private void UpdateSeed()
|
||||
{
|
||||
_globalSeed = _random.Next(int.MinValue, int.MaxValue);
|
||||
}
|
||||
|
||||
private void SpawnBiome(Entity<CP14BiomeSpawnerComponent> ent)
|
||||
{
|
||||
var biome = _proto.Index(ent.Comp.Biome);
|
||||
@@ -50,11 +64,9 @@ public sealed class CP14BiomeSpawnerSystem : EntitySystem
|
||||
if (!TryComp<MapGridComponent>(gridUid, out var map))
|
||||
return;
|
||||
|
||||
var seed = _roundSeed.GetSeed();
|
||||
|
||||
var vec = _transform.GetGridOrMapTilePosition(ent);
|
||||
|
||||
if (!_biome.TryGetTile(vec, biome.Layers, seed, map, out var tile))
|
||||
if (!_biome.TryGetTile(vec, biome.Layers, _globalSeed, map, out var tile))
|
||||
return;
|
||||
|
||||
// Set new tile
|
||||
@@ -70,7 +82,7 @@ public sealed class CP14BiomeSpawnerSystem : EntitySystem
|
||||
}
|
||||
|
||||
//Add decals
|
||||
if (_biome.TryGetDecals(vec, biome.Layers, seed, map, out var decals))
|
||||
if (_biome.TryGetDecals(vec, biome.Layers, _globalSeed, map, out var decals))
|
||||
{
|
||||
foreach (var decal in decals)
|
||||
{
|
||||
@@ -87,7 +99,7 @@ public sealed class CP14BiomeSpawnerSystem : EntitySystem
|
||||
QueueDel(entToRemove);
|
||||
}
|
||||
|
||||
if (_biome.TryGetEntity(vec, biome.Layers, tile.Value, seed, map, out var entityProto))
|
||||
if (_biome.TryGetEntity(vec, biome.Layers, tile.Value, _globalSeed, map, out var entityProto))
|
||||
Spawn(entityProto, new EntityCoordinates(gridUid, tileCenterVec));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,20 +14,20 @@ public sealed partial class CP14DemiplaneSystem
|
||||
private void OnRiftInit(Entity<CP14DemiplaneRiftComponent> rift, ref MapInitEvent args)
|
||||
{
|
||||
var map = Transform(rift).MapUid;
|
||||
if (TryComp<CP14DemiplaneComponent>(map, out var demiplan)) // In demiplan
|
||||
if (_demiplaneQuery.TryComp(map, out var demiplane)) // In demiplane
|
||||
{
|
||||
if (rift.Comp.TryAutoLinkToMap)
|
||||
rift.Comp.Demiplane = map.Value;
|
||||
|
||||
if (rift.Comp.ActiveTeleport)
|
||||
AddDemiplanRandomEntryPoint((map.Value, demiplan), rift);
|
||||
AddDemiplaneRandomEntryPoint((map.Value, demiplane), rift);
|
||||
}
|
||||
else if (rift.Comp.Demiplane is not null) //We out of demiplan
|
||||
else if (rift.Comp.Demiplane is not null) //We out of demiplane
|
||||
{
|
||||
if (TryComp<CP14DemiplaneComponent>(rift.Comp.Demiplane, out var riftDemiplane))
|
||||
if (_demiplaneQuery.TryComp(rift.Comp.Demiplane, out var riftDemiplane))
|
||||
{
|
||||
if (rift.Comp.ActiveTeleport)
|
||||
AddDemiplanRandomExitPoint((rift.Comp.Demiplane.Value, riftDemiplane), rift);
|
||||
AddDemiplaneRandomExitPoint((rift.Comp.Demiplane.Value, riftDemiplane), rift);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,38 +37,35 @@ public sealed partial class CP14DemiplaneSystem
|
||||
if (rift.Comp.Demiplane is null)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14DemiplaneComponent>(rift.Comp.Demiplane, out var riftDemiplane))
|
||||
if (!_demiplaneQuery.TryComp(rift.Comp.Demiplane, out var riftDemiplane))
|
||||
return;
|
||||
|
||||
RemoveDemiplanRandomEntryPoint((rift.Comp.Demiplane.Value, riftDemiplane), rift);
|
||||
RemoveDemiplaneRandomEntryPoint((rift.Comp.Demiplane.Value, riftDemiplane), rift);
|
||||
RemoveDemiplanRandomExitPoint((rift.Comp.Demiplane.Value, riftDemiplane), rift);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///Add a position in the real world where you can get out of this demiplan
|
||||
///Add a position in the real world where you can get out of this demiplane
|
||||
/// </summary>
|
||||
private void AddDemiplanRandomExitPoint(Entity<CP14DemiplaneComponent> demiplan,
|
||||
private void AddDemiplaneRandomExitPoint(Entity<CP14DemiplaneComponent> demiplane,
|
||||
Entity<CP14DemiplaneRiftComponent> exitPoint)
|
||||
{
|
||||
if (demiplan.Comp.ExitPoints.Contains(exitPoint))
|
||||
return;
|
||||
|
||||
demiplan.Comp.ExitPoints.Add(exitPoint);
|
||||
exitPoint.Comp.Demiplane = demiplan;
|
||||
demiplane.Comp.ExitPoints.Add(exitPoint);
|
||||
exitPoint.Comp.Demiplane = demiplane;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removing the demiplan exit point, one of which the player can exit to
|
||||
/// Removing the demiplane exit point, one of which the player can exit to
|
||||
/// </summary>
|
||||
private void RemoveDemiplanRandomExitPoint(Entity<CP14DemiplaneComponent>? demiplan,
|
||||
private void RemoveDemiplanRandomExitPoint(Entity<CP14DemiplaneComponent>? demiplane,
|
||||
EntityUid exitPoint)
|
||||
{
|
||||
if (!TryComp<CP14DemiplaneRiftComponent>(exitPoint, out var riftComp))
|
||||
return;
|
||||
|
||||
if (demiplan is not null && demiplan.Value.Comp.ExitPoints.Contains(exitPoint))
|
||||
if (demiplane is not null && demiplane.Value.Comp.ExitPoints.Contains(exitPoint))
|
||||
{
|
||||
demiplan.Value.Comp.ExitPoints.Remove(exitPoint);
|
||||
demiplane.Value.Comp.ExitPoints.Remove(exitPoint);
|
||||
riftComp.Demiplane = null;
|
||||
}
|
||||
|
||||
@@ -77,27 +74,24 @@ public sealed partial class CP14DemiplaneSystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a position within the demiplan that can be entered into the demiplan
|
||||
/// Add a position within the demiplane that can be entered into the demiplane
|
||||
/// </summary>
|
||||
private void AddDemiplanRandomEntryPoint(Entity<CP14DemiplaneComponent> demiplan,
|
||||
private void AddDemiplaneRandomEntryPoint(Entity<CP14DemiplaneComponent> demiplane,
|
||||
Entity<CP14DemiplaneRiftComponent> entryPoint)
|
||||
{
|
||||
if (demiplan.Comp.EntryPoints.Contains(entryPoint))
|
||||
return;
|
||||
|
||||
demiplan.Comp.EntryPoints.Add(entryPoint);
|
||||
entryPoint.Comp.Demiplane = demiplan;
|
||||
demiplane.Comp.EntryPoints.Add(entryPoint);
|
||||
entryPoint.Comp.Demiplane = demiplane;
|
||||
}
|
||||
|
||||
private void RemoveDemiplanRandomEntryPoint(Entity<CP14DemiplaneComponent>? demiplan,
|
||||
private void RemoveDemiplaneRandomEntryPoint(Entity<CP14DemiplaneComponent>? demiplane,
|
||||
EntityUid entryPoint)
|
||||
{
|
||||
if (!TryComp<CP14DemiplaneRiftComponent>(entryPoint, out var riftComp))
|
||||
return;
|
||||
|
||||
if (demiplan is not null && demiplan.Value.Comp.EntryPoints.Contains(entryPoint))
|
||||
if (demiplane is not null && demiplane.Value.Comp.EntryPoints.Contains(entryPoint))
|
||||
{
|
||||
demiplan.Value.Comp.EntryPoints.Remove(entryPoint);
|
||||
demiplane.Value.Comp.EntryPoints.Remove(entryPoint);
|
||||
riftComp.Demiplane = null;
|
||||
}
|
||||
|
||||
@@ -105,26 +99,26 @@ public sealed partial class CP14DemiplaneSystem
|
||||
QueueDel(entryPoint);
|
||||
}
|
||||
|
||||
public bool TryGetDemiplanEntryPoint(Entity<CP14DemiplaneComponent> demiplan, out EntityUid? entryPoint)
|
||||
public bool TryGetDemiplaneEntryPoint(Entity<CP14DemiplaneComponent> demiplane, out EntityUid? entryPoint)
|
||||
{
|
||||
entryPoint = null;
|
||||
|
||||
if (demiplan.Comp.EntryPoints.Count == 0)
|
||||
if (demiplane.Comp.EntryPoints.Count == 0)
|
||||
return false;
|
||||
|
||||
entryPoint = _random.Pick(demiplan.Comp.EntryPoints);
|
||||
entryPoint = _random.Pick(demiplane.Comp.EntryPoints);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetDemiplanExitPoint(Entity<CP14DemiplaneComponent> demiplan,
|
||||
public bool TryGetDemiplaneExitPoint(Entity<CP14DemiplaneComponent> demiplane,
|
||||
out EntityUid? exitPoint)
|
||||
{
|
||||
exitPoint = null;
|
||||
|
||||
if (demiplan.Comp.ExitPoints.Count == 0)
|
||||
if (demiplane.Comp.ExitPoints.Count == 0)
|
||||
return false;
|
||||
|
||||
exitPoint = _random.Pick(demiplan.Comp.ExitPoints);
|
||||
exitPoint = _random.Pick(demiplane.Comp.ExitPoints);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
34
Content.Server/_CP14/Demiplane/CP14DemiplaneSystem.Echoes.cs
Normal file
34
Content.Server/_CP14/Demiplane/CP14DemiplaneSystem.Echoes.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Content.Server.Chat.Systems;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane;
|
||||
|
||||
public sealed partial class CP14DemiplaneSystem
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
|
||||
private void InitEchoes()
|
||||
{
|
||||
SubscribeLocalEvent<EntitySpokeEvent>(OnSpeak);
|
||||
}
|
||||
|
||||
private void OnSpeak(EntitySpokeEvent ev)
|
||||
{
|
||||
var map = Transform(ev.Source).MapUid;
|
||||
|
||||
if (!_demiplaneQuery.TryComp(map, out var demiplane))
|
||||
return;
|
||||
|
||||
//Get random exit, and send message there
|
||||
if (demiplane.ExitPoints.Count == 0)
|
||||
return;
|
||||
var exit = _random.Pick(demiplane.ExitPoints);
|
||||
|
||||
_chat.TrySendInGameICMessage(exit,
|
||||
ev.Message,
|
||||
InGameICChatType.Whisper,
|
||||
ChatTransmitRange.NoGhosts,
|
||||
nameOverride: Loc.GetString("cp14-demiplane-echoes"),
|
||||
hideLog: true);
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,9 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using Content.Server._CP14.Demiplane.Components;
|
||||
using Content.Server._CP14.Demiplane.Jobs;
|
||||
using Content.Server._CP14.RoundEnd;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Content.Shared._CP14.MagicManacostModify;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Verbs;
|
||||
@@ -112,11 +110,11 @@ public sealed partial class CP14DemiplaneSystem
|
||||
/// <summary>
|
||||
/// Generates a new random demiplane based on the specified parameters
|
||||
/// </summary>
|
||||
public void SpawnRandomDemiplane(ProtoId<CP14DemiplaneLocationPrototype> location, List<ProtoId<CP14DemiplaneModifierPrototype>> modifiers, out Entity<CP14DemiplaneComponent> demiplan, out MapId mapId)
|
||||
public void SpawnRandomDemiplane(ProtoId<CP14DemiplaneLocationPrototype> location, List<ProtoId<CP14DemiplaneModifierPrototype>> modifiers, out Entity<CP14DemiplaneComponent>? demiplane, out MapId mapId)
|
||||
{
|
||||
var mapUid = _mapSystem.CreateMap(out mapId, runMapInit: false);
|
||||
var demiComp = EntityManager.EnsureComponent<CP14DemiplaneComponent>(mapUid);
|
||||
demiplan = (mapUid, demiComp);
|
||||
demiplane = (mapUid, demiComp);
|
||||
|
||||
var cancelToken = new CancellationTokenSource();
|
||||
var job = new CP14SpawnRandomDemiplaneJob(
|
||||
@@ -141,25 +139,43 @@ public sealed partial class CP14DemiplaneSystem
|
||||
|
||||
private void GeneratorUsedInHand(Entity<CP14DemiplaneGeneratorDataComponent> generator, ref UseInHandEvent args)
|
||||
{
|
||||
if (generator.Comp.Location is null)
|
||||
return;
|
||||
|
||||
//block the opening of demiplanes after the end of a round
|
||||
if (_gameTicker.RunLevel != GameRunLevel.InRound)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-demiplan-cannot-open-end-round"), generator, args.User);
|
||||
return;
|
||||
}
|
||||
//We cant open demiplan in another demiplan or if parent is not Map
|
||||
if (HasComp<CP14DemiplaneComponent>(Transform(generator).MapUid) || !HasComp<MapGridComponent>(_transform.GetParentUid(args.User)))
|
||||
//We cant open demiplane in another demiplane or if parent is not Map
|
||||
if (_demiplaneQuery.HasComp(Transform(generator).MapUid) || !HasComp<MapGridComponent>(_transform.GetParentUid(args.User)))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-demiplan-cannot-open", ("name", MetaData(generator).EntityName)), generator, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnRandomDemiplane(generator.Comp.Location.Value, generator.Comp.SelectedModifiers, out var demiplane, out var mapId);
|
||||
if (generator.Comp.Location is null)
|
||||
return;
|
||||
|
||||
//an attempt to open demiplanes can be intercepted by other systems that substitute a map instead of generating the planned demiplane.
|
||||
Entity<CP14DemiplaneComponent>? demiplane = null;
|
||||
var ev = new CP14DemiplaneGenerationCatchAttemptEvent();
|
||||
RaiseLocalEvent(ev);
|
||||
|
||||
if (ev.Demiplane is null)
|
||||
{
|
||||
SpawnRandomDemiplane(generator.Comp.Location.Value, generator.Comp.SelectedModifiers, out demiplane, out var mapId);
|
||||
}
|
||||
else
|
||||
{
|
||||
demiplane = ev.Demiplane;
|
||||
}
|
||||
|
||||
_statistic.TrackAdd(generator.Comp.Statistic, 1);
|
||||
|
||||
if (demiplane is null)
|
||||
return;
|
||||
|
||||
//Admin log needed
|
||||
EnsureComp<CP14DemiplaneDestroyWithoutStabilizationComponent>(demiplane);
|
||||
EnsureComp<CP14DemiplaneDestroyWithoutStabilizationComponent>(demiplane.Value);
|
||||
|
||||
//Ура, щиткод и магические переменные!
|
||||
var tempRift = EntityManager.Spawn("CP14DemiplaneTimedRadiusPassway");
|
||||
@@ -169,8 +185,8 @@ public sealed partial class CP14DemiplaneSystem
|
||||
|
||||
var connection = EnsureComp<CP14DemiplaneRiftComponent>(tempRift);
|
||||
var connection2 = EnsureComp<CP14DemiplaneRiftComponent>(tempRift2);
|
||||
AddDemiplanRandomExitPoint(demiplane, (tempRift, connection));
|
||||
AddDemiplanRandomExitPoint(demiplane, (tempRift2, connection2));
|
||||
AddDemiplaneRandomExitPoint(demiplane.Value, (tempRift, connection));
|
||||
AddDemiplaneRandomExitPoint(demiplane.Value, (tempRift2, connection2));
|
||||
|
||||
#if !DEBUG
|
||||
QueueDel(generator); //wtf its crash debug build!
|
||||
@@ -370,3 +386,9 @@ public sealed partial class CP14DemiplaneSystem
|
||||
throw new InvalidOperationException($"Invalid weighted pick in CP14DemiplanSystem.Generation!");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CP14DemiplaneGenerationCatchAttemptEvent : EntityEventArgs
|
||||
{
|
||||
public bool Handled = false;
|
||||
public Entity<CP14DemiplaneComponent>? Demiplane;
|
||||
}
|
||||
@@ -81,10 +81,20 @@ public sealed partial class CP14DemiplaneSystem
|
||||
if (TryTeleportOutDemiplane(demiplane, uid))
|
||||
{
|
||||
if (!safe)
|
||||
{
|
||||
var ev = new CP14DemiplaneUnsafeExit();
|
||||
RaiseLocalEvent(uid, ev);
|
||||
|
||||
_body.GibBody(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QueueDel(demiplane);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CP14DemiplaneUnsafeExit : EntityEventArgs
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
using Content.Server._CP14.Demiplane.Components;
|
||||
using Content.Server._CP14.RoundStatistic;
|
||||
using Content.Server.Flash;
|
||||
using Content.Server.Procedural;
|
||||
using Content.Shared._CP14.Demiplane;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
@@ -25,16 +28,45 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
|
||||
[Dependency] private readonly FlashSystem _flash = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly CP14RoundStatTrackerSystem _statistic = default!;
|
||||
|
||||
private EntityQuery<CP14DemiplaneComponent> _demiplaneQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_demiplaneQuery = GetEntityQuery<CP14DemiplaneComponent>();
|
||||
|
||||
InitGeneration();
|
||||
InitConnections();
|
||||
InitStabilization();
|
||||
InitEchoes();
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneComponent, ComponentShutdown>(OnDemiplanShutdown);
|
||||
SubscribeLocalEvent<CP14SpawnOutOfDemiplaneComponent, MapInitEvent>(OnSpawnOutOfDemiplane);
|
||||
}
|
||||
|
||||
private void OnSpawnOutOfDemiplane(Entity<CP14SpawnOutOfDemiplaneComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
//Check if entity is in demiplane
|
||||
var map = Transform(ent).MapUid;
|
||||
if (!_demiplaneQuery.TryComp(map, out var demiplane))
|
||||
return;
|
||||
|
||||
//Get random exit demiplane point and spawn entity there
|
||||
if (demiplane.ExitPoints.Count == 0)
|
||||
return;
|
||||
|
||||
var exit = _random.Pick(demiplane.ExitPoints);
|
||||
var coordinates = Transform(exit).Coordinates;
|
||||
|
||||
var proto = ent.Comp.Proto;
|
||||
|
||||
if (proto is null)
|
||||
proto = MetaData(ent).EntityPrototype?.ID;
|
||||
|
||||
Spawn(proto, coordinates);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
@@ -51,32 +83,45 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
|
||||
/// <param name="demiplane">The demiplane the entity will be teleported to</param>
|
||||
/// <param name="entity">The entity to be teleported</param>
|
||||
/// <returns></returns>
|
||||
public bool TryTeleportIntoDemiplane(Entity<CP14DemiplaneComponent> demiplane, EntityUid? entity)
|
||||
public override bool TryTeleportIntoDemiplane(Entity<CP14DemiplaneComponent> demiplane, EntityUid? entity)
|
||||
{
|
||||
if (entity is null)
|
||||
return false;
|
||||
|
||||
if (!TryGetDemiplanEntryPoint(demiplane, out var entryPoint) || entryPoint is null)
|
||||
if (!TryGetDemiplaneEntryPoint(demiplane, out var entryPoint) || entryPoint is null)
|
||||
{
|
||||
Log.Error($"{entity} cant get in demiplane {demiplane}: no active entry points!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var targetCoord = Transform(entryPoint.Value).Coordinates;
|
||||
_flash.Flash(entity.Value, null, null, 3000f, 0.5f);
|
||||
_transform.SetCoordinates(entity.Value, targetCoord);
|
||||
_audio.PlayGlobal(demiplane.Comp.ArrivalSound, entity.Value);
|
||||
TeleportEntityToCoordinate(entity.Value, Transform(entryPoint.Value).Coordinates, demiplane.Comp.ArrivalSound);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple teleportation, with common special effects for all the game's teleportation mechanics
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="coordinates"></param>
|
||||
/// <param name="sound"></param>
|
||||
public void TeleportEntityToCoordinate(EntityUid? entity, EntityCoordinates coordinates, SoundSpecifier? sound = null)
|
||||
{
|
||||
if (entity is null)
|
||||
return;
|
||||
|
||||
_flash.Flash(entity.Value, null, null, 3000f, 0.5f);
|
||||
_transform.SetCoordinates(entity.Value, coordinates);
|
||||
_audio.PlayGlobal(sound, entity.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Teleports an entity from the demiplane to the real world, to one of the random exit points in the real world.
|
||||
/// </summary>
|
||||
/// <param name="demiplane">The demiplane from which the entity will be teleported</param>
|
||||
/// <param name="entity">An entity that will be teleported into the real world. This entity must be in the demiplane, otherwise the function will not work.</param>
|
||||
/// <returns></returns>
|
||||
public bool TryTeleportOutDemiplane(Entity<CP14DemiplaneComponent> demiplane, EntityUid? entity)
|
||||
public override bool TryTeleportOutDemiplane(Entity<CP14DemiplaneComponent> demiplane, EntityUid? entity)
|
||||
{
|
||||
if (entity is null)
|
||||
return false;
|
||||
@@ -84,17 +129,13 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
|
||||
if (Transform(entity.Value).MapUid != demiplane.Owner)
|
||||
return false;
|
||||
|
||||
if (!TryGetDemiplanExitPoint(demiplane, out var connection) || connection is null)
|
||||
if (!TryGetDemiplaneExitPoint(demiplane, out var connection) || connection is null)
|
||||
{
|
||||
Log.Error($"{entity} cant get out of demiplane {demiplane}: no active connections!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var targetCoord = Transform(connection.Value).Coordinates;
|
||||
_flash.Flash(entity.Value, null, null, 3000f, 0.5f);
|
||||
_transform.SetCoordinates(entity.Value, targetCoord);
|
||||
_audio.PlayGlobal(demiplane.Comp.DepartureSound, entity.Value);
|
||||
|
||||
TeleportEntityToCoordinate(entity.Value, Transform(connection.Value).Coordinates, demiplane.Comp.DepartureSound);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -117,7 +158,7 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
|
||||
|
||||
foreach (var entry in demiplane.Comp.EntryPoints)
|
||||
{
|
||||
RemoveDemiplanRandomEntryPoint(demiplane, entry);
|
||||
RemoveDemiplaneRandomEntryPoint(demiplane, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Content.Shared._CP14.RoundStatistic;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane.Components;
|
||||
@@ -22,5 +23,8 @@ public sealed partial class CP14DemiplaneGeneratorDataComponent : Component
|
||||
public Dictionary<int, float> TiersContent = new();
|
||||
|
||||
[DataField(required: true)]
|
||||
public Dictionary<ProtoId<CP14DemiplaneModifierCategoryPrototype>, float> Limits;
|
||||
public Dictionary<ProtoId<CP14DemiplaneModifierCategoryPrototype>, float> Limits = new();
|
||||
|
||||
[DataField]
|
||||
public ProtoId<CP14RoundStatTrackerPrototype> Statistic = "DemiplaneOpen";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an entity on demiplane exit points when that entity appears.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14SpawnOutOfDemiplaneComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// If null, the ProtoId of this entity is taken from the entity itself.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId? Proto;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Content.Server._CP14.Demiplane;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Server._CP14.DemiplaneAdmin;
|
||||
|
||||
public sealed partial class CP14DemiplaneAdminSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneGenerationCatchAttemptEvent>(OnAdminDemiplaneCatch);
|
||||
}
|
||||
|
||||
private void OnAdminDemiplaneCatch(CP14DemiplaneGenerationCatchAttemptEvent ev)
|
||||
{
|
||||
if (ev.Handled)
|
||||
return;
|
||||
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneRiftCatcherComponent, MapComponent, CP14DemiplaneComponent>();
|
||||
while (query.MoveNext(out var uid, out var catcher, out var map, out var demiplane))
|
||||
{
|
||||
ev.Demiplane = (uid, demiplane);
|
||||
ev.Handled = true;
|
||||
RemCompDeferred(uid, catcher);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Content.Server._CP14.DemiplaneAdmin;
|
||||
|
||||
/// <summary>
|
||||
/// This demiplane can be added to a map by the admins, which will redirect the next opened demiplane key to that map
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14DemiplaneRiftCatcherComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server._CP14.Demiplane;
|
||||
using Content.Server._CP14.RoundEnd;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Popups;
|
||||
@@ -28,13 +29,74 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneRadiusTimedPasswayComponent, MapInitEvent>(RadiusMapInit);
|
||||
SubscribeLocalEvent<CP14MonolithTimedPasswayComponent, MapInitEvent>(MonolithMapInit);
|
||||
SubscribeLocalEvent<CP14DemiplaneRiftOpenedComponent, CP14DemiplanPasswayUseDoAfter>(OnOpenRiftInteractDoAfter);
|
||||
}
|
||||
|
||||
// !!!SHITCODE WARNING!!!
|
||||
// This whole module is saturated with shieldcode, code duplication and other delights. Why? Because.
|
||||
//TODO: Refactor this shitcode
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
DemiplaneTeleportUpdate();
|
||||
|
||||
var query = EntityQueryEnumerator<CP14MonolithTimedPasswayComponent>();
|
||||
while (query.MoveNext(out var uid, out var passWay))
|
||||
{
|
||||
if (_timing.CurTime < passWay.NextTimeTeleport)
|
||||
continue;
|
||||
|
||||
passWay.NextTimeTeleport = _timing.CurTime + passWay.Delay;
|
||||
|
||||
//Get all teleporting entities
|
||||
HashSet<EntityUid> teleportedEnts = new();
|
||||
var nearestEnts = _lookup.GetEntitiesInRange(uid, passWay.Radius);
|
||||
foreach (var ent in nearestEnts)
|
||||
{
|
||||
if (HasComp<GhostComponent>(ent))
|
||||
continue;
|
||||
|
||||
if (!_mind.TryGetMind(ent, out var mindId, out var mind))
|
||||
continue;
|
||||
|
||||
if (!_interaction.InRangeUnobstructed(ent, uid))
|
||||
continue;
|
||||
|
||||
teleportedEnts.Add(ent);
|
||||
}
|
||||
|
||||
while (teleportedEnts.Count > passWay.MaxEntities)
|
||||
{
|
||||
teleportedEnts.Remove(_random.Pick(teleportedEnts));
|
||||
}
|
||||
|
||||
//Aaaand teleport it
|
||||
var monoliths = EntityQueryEnumerator<CP14MagicContainerRoundFinisherComponent>();
|
||||
while (monoliths.MoveNext(out var monolithUid, out var monolith))
|
||||
{
|
||||
var coord = Transform(monolithUid).Coordinates;
|
||||
|
||||
//Shitcode select first one
|
||||
foreach (var ent in teleportedEnts)
|
||||
{
|
||||
if (TryComp<PullerComponent>(ent, out var puller))
|
||||
_demiplan.TeleportEntityToCoordinate(puller.Pulling, coord);
|
||||
|
||||
_demiplan.TeleportEntityToCoordinate(ent, coord);
|
||||
_audio.PlayPvs(passWay.ArrivalSound, ent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_audio.PlayPvs(passWay.DepartureSound, Transform(uid).Coordinates);
|
||||
QueueDel(uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void DemiplaneTeleportUpdate()
|
||||
{
|
||||
//Radius passway
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneRadiusTimedPasswayComponent, CP14DemiplaneRiftComponent>();
|
||||
while (query.MoveNext(out var uid, out var passWay, out var rift))
|
||||
@@ -70,7 +132,7 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
|
||||
var map = Transform(uid).MapUid;
|
||||
if (TryComp<CP14DemiplaneComponent>(map, out var demiplan))
|
||||
{
|
||||
if (!_demiplan.TryGetDemiplanExitPoint((map.Value, demiplan), out _))
|
||||
if (!_demiplan.TryGetDemiplaneExitPoint((map.Value, demiplan), out _))
|
||||
break;
|
||||
|
||||
foreach (var ent in teleportedEnts) //We in demiplan, tp OUT
|
||||
@@ -87,7 +149,7 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
|
||||
if (rift.Demiplane is not null &&
|
||||
TryComp<CP14DemiplaneComponent>(rift.Demiplane.Value, out var riftDemiplane))
|
||||
{
|
||||
if (!_demiplan.TryGetDemiplanEntryPoint((rift.Demiplane.Value, riftDemiplane), out _))
|
||||
if (!_demiplan.TryGetDemiplaneEntryPoint((rift.Demiplane.Value, riftDemiplane), out _))
|
||||
break;
|
||||
|
||||
foreach (var ent in teleportedEnts) //We out demiplan, tp IN
|
||||
@@ -111,6 +173,11 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
|
||||
radiusPassWay.Comp.NextTimeTeleport = _timing.CurTime + radiusPassWay.Comp.Delay;
|
||||
}
|
||||
|
||||
private void MonolithMapInit(Entity<CP14MonolithTimedPasswayComponent> radiusPassWay, ref MapInitEvent args)
|
||||
{
|
||||
radiusPassWay.Comp.NextTimeTeleport = _timing.CurTime + radiusPassWay.Comp.Delay;
|
||||
}
|
||||
|
||||
private void OnOpenRiftInteractDoAfter(Entity<CP14DemiplaneRiftOpenedComponent> passWay,
|
||||
ref CP14DemiplanPasswayUseDoAfter args)
|
||||
{
|
||||
|
||||
138
Content.Server/_CP14/Discord/DiscordAuthManager.cs
Normal file
138
Content.Server/_CP14/Discord/DiscordAuthManager.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Shared._CP14.Discord;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
|
||||
namespace Content.Server._CP14.Discord;
|
||||
|
||||
public sealed class DiscordAuthManager
|
||||
{
|
||||
[Dependency] private readonly IServerNetManager _netMgr = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerMgr = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
private readonly HttpClient _httpClient = new();
|
||||
private bool _enabled = false;
|
||||
private string _apiUrl = string.Empty;
|
||||
private string _apiKey = string.Empty;
|
||||
|
||||
public event EventHandler<ICommonSession>? PlayerVerified;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_sawmill = Logger.GetSawmill("discordAuth");
|
||||
|
||||
_cfg.OnValueChanged(CCVars.DiscordAuthEnabled, v => _enabled = v, true);
|
||||
_cfg.OnValueChanged(CCVars.DiscordAuthUrl, v => _apiUrl = v, true);
|
||||
_cfg.OnValueChanged(CCVars.DiscordAuthToken, v => _apiKey = v, true);
|
||||
|
||||
_netMgr.RegisterNetMessage<MsgDiscordAuthRequired>();
|
||||
_netMgr.RegisterNetMessage<MsgDiscordAuthCheck>(OnAuthCheck);
|
||||
|
||||
_playerMgr.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
PlayerVerified += OnPlayerVerified;
|
||||
}
|
||||
|
||||
private void OnPlayerVerified(object? obj, ICommonSession session)
|
||||
{
|
||||
Timer.Spawn(0, () => _playerMgr.JoinGame(session));
|
||||
}
|
||||
|
||||
private async void OnAuthCheck(MsgDiscordAuthCheck msg)
|
||||
{
|
||||
var verified = await IsVerified(msg.MsgChannel.UserId);
|
||||
if (!verified)
|
||||
return;
|
||||
|
||||
var session = _playerMgr.GetSessionById(msg.MsgChannel.UserId);
|
||||
PlayerVerified?.Invoke(this, session);
|
||||
}
|
||||
|
||||
private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs args)
|
||||
{
|
||||
if (args.NewStatus != SessionStatus.Connected)
|
||||
return;
|
||||
|
||||
if (!_enabled)
|
||||
{
|
||||
PlayerVerified?.Invoke(this, args.Session);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.NewStatus == SessionStatus.Connected)
|
||||
{
|
||||
var verified = await IsVerified(args.Session.UserId);
|
||||
if (verified)
|
||||
{
|
||||
PlayerVerified?.Invoke(this, args.Session);
|
||||
return;
|
||||
}
|
||||
|
||||
var message = new MsgDiscordAuthRequired();
|
||||
message.AuthUrl = await GenerateLink(args.Session.UserId) ?? string.Empty;
|
||||
args.Session.Channel.SendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> IsVerified(NetUserId userId, CancellationToken cancel = default)
|
||||
{
|
||||
_sawmill.Debug($"Player {userId} check Discord verification");
|
||||
|
||||
var requestUrl = $"{_apiUrl}/api/uuid?method=uid&id={userId}";
|
||||
_sawmill.Debug($"Auth request url:{requestUrl}");
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _apiKey);
|
||||
|
||||
var response = await _httpClient.SendAsync(request, cancel);
|
||||
|
||||
_sawmill.Debug($"{await response.Content.ReadAsStringAsync(cancel)}");
|
||||
_sawmill.Debug($"{(int) response.StatusCode}");
|
||||
return response.StatusCode == HttpStatusCode.OK;
|
||||
}
|
||||
|
||||
public async Task<string?> GenerateLink(NetUserId userId, CancellationToken cancel = default)
|
||||
{
|
||||
_sawmill.Debug($"Generating link for {userId}");
|
||||
var requestUrl = $"{_apiUrl}/api/link?uid={userId}";
|
||||
|
||||
// try catch block to catch HttpRequestExceptions due to remote service unavailability
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.GetAsync(requestUrl, cancel);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return null;
|
||||
|
||||
var link = await response.Content.ReadFromJsonAsync<DiscordLinkResponse>(cancel);
|
||||
return link!.Link;
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
_sawmill.Error("Remote auth service is unreachable. Check if its online!");
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_sawmill.Error($"Unexpected error verifying user via auth service. Error: {e.Message}. Stack: \n{e.StackTrace}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DiscordLinkResponse
|
||||
{
|
||||
[JsonPropertyName("link")]
|
||||
public string Link { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
|
||||
private void OnSpellSpoken(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14VerbalAspectSpeechEvent args)
|
||||
{
|
||||
if (args.Performer is not null && args.Speech is not null)
|
||||
_chat.TrySendInGameICMessage(args.Performer.Value, args.Speech, InGameICChatType.Speak, true);
|
||||
_chat.TrySendInGameICMessage(args.Performer.Value, args.Speech, args.Emote ? InGameICChatType.Emote : InGameICChatType.Speak, true);
|
||||
}
|
||||
|
||||
private void OnSpawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using Content.Server._CP14.Objectives.Systems;
|
||||
using Content.Shared._CP14.RoundStatistic;
|
||||
using Content.Shared.Destructible.Thresholds;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14StatisticRangeConditionSystem))]
|
||||
public sealed partial class CP14StatisticRangeConditionComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14RoundStatTrackerPrototype> Statistic;
|
||||
|
||||
[DataField(required: true)]
|
||||
public MinMax Range;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId ObjectiveText;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId ObjectiveDescription;
|
||||
|
||||
[DataField(required: true)]
|
||||
public SpriteSpecifier? ObjectiveSprite;
|
||||
}
|
||||
@@ -38,5 +38,5 @@ public sealed partial class CP14TownSendConditionComponent : Component
|
||||
public LocId ObjectiveText;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId DescriptionText;
|
||||
public LocId ObjectiveDescription;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using Content.Server._CP14.Objectives.Components;
|
||||
using Content.Server._CP14.RoundStatistic;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Objectives.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Systems;
|
||||
|
||||
public sealed class CP14StatisticRangeConditionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||
[Dependency] private readonly CP14RoundStatTrackerSystem _statistic = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14StatisticRangeConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
|
||||
SubscribeLocalEvent<CP14StatisticRangeConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
|
||||
}
|
||||
|
||||
private void OnAfterAssign(Entity<CP14StatisticRangeConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
|
||||
{
|
||||
var title = Loc.GetString(condition.Comp.ObjectiveText,
|
||||
("min", condition.Comp.Range.Min),
|
||||
("max", condition.Comp.Range.Max));
|
||||
|
||||
var description = Loc.GetString(condition.Comp.ObjectiveDescription,
|
||||
("min", condition.Comp.Range.Min),
|
||||
("max", condition.Comp.Range.Max));
|
||||
|
||||
_metaData.SetEntityName(condition.Owner, title, args.Meta);
|
||||
_metaData.SetEntityDescription(condition.Owner, description, args.Meta);
|
||||
if (condition.Comp.ObjectiveSprite is not null)
|
||||
_objectives.SetIcon(condition.Owner, condition.Comp.ObjectiveSprite, args.Objective);
|
||||
}
|
||||
|
||||
private void OnGetProgress(Entity<CP14StatisticRangeConditionComponent> ent, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
var statValue = _statistic.GetTrack(ent.Comp.Statistic);
|
||||
|
||||
if (statValue is null || statValue > ent.Comp.Range.Max || statValue < ent.Comp.Range.Min)
|
||||
{
|
||||
args.Progress = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
args.Progress = 1;
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ public sealed class CP14TownSendConditionSystem : EntitySystem
|
||||
_stealQuery = GetEntityQuery<StealTargetComponent>();
|
||||
_stackQuery = GetEntityQuery<StackComponent>();
|
||||
|
||||
SubscribeLocalEvent<CP14TownSendConditionComponent, ObjectiveAssignedEvent>(OnAssigned);
|
||||
SubscribeLocalEvent<CP14TownSendConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
|
||||
SubscribeLocalEvent<CP14TownSendConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
|
||||
|
||||
@@ -72,12 +71,6 @@ public sealed class CP14TownSendConditionSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAssigned(Entity<CP14TownSendConditionComponent> condition, ref ObjectiveAssignedEvent args)
|
||||
{
|
||||
//TODO: Add ability to create mindfree objectives to Wizden
|
||||
//condition.Comp.CollectionSize = _random.Next(condition.Comp.MinCollectionSize, condition.Comp.MaxCollectionSize);
|
||||
}
|
||||
|
||||
//Set the visual, name, icon for the objective.
|
||||
private void OnAfterAssign(Entity<CP14TownSendConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
|
||||
{
|
||||
@@ -86,7 +79,7 @@ public sealed class CP14TownSendConditionSystem : EntitySystem
|
||||
var group = _proto.Index(condition.Comp.CollectGroup);
|
||||
|
||||
var title = Loc.GetString(condition.Comp.ObjectiveText, ("itemName", Loc.GetString(group.Name)), ("count", condition.Comp.CollectionSize));
|
||||
var description = Loc.GetString(condition.Comp.DescriptionText, ("itemName", Loc.GetString(group.Name)), ("count", condition.Comp.CollectionSize));
|
||||
var description = Loc.GetString(condition.Comp.ObjectiveDescription, ("itemName", Loc.GetString(group.Name)), ("count", condition.Comp.CollectionSize));
|
||||
|
||||
_metaData.SetEntityName(condition.Owner, title, args.Meta);
|
||||
_metaData.SetEntityDescription(condition.Owner, description, args.Meta);
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* All right reserved to CrystallEdge.
|
||||
*
|
||||
* BUT this file is sublicensed under MIT License
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Content.Server._CP14.RoundSeed;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for round seed
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14RoundSeedSystem))]
|
||||
public sealed partial class CP14RoundSeedComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
public static int MaxValue = 10000;
|
||||
|
||||
[ViewVariables]
|
||||
public int Seed;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* All right reserved to CrystallEdge.
|
||||
*
|
||||
* BUT this file is sublicensed under MIT License
|
||||
*
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.RoundSeed;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a round seed for another systems
|
||||
/// </summary>
|
||||
public sealed class CP14RoundSeedSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14RoundSeedComponent, ComponentStartup>(OnComponentStartup);
|
||||
}
|
||||
|
||||
private void OnComponentStartup(Entity<CP14RoundSeedComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
ent.Comp.Seed = _random.Next(CP14RoundSeedComponent.MaxValue);
|
||||
}
|
||||
|
||||
private int SetupSeed()
|
||||
{
|
||||
return AddComp<CP14RoundSeedComponent>(Spawn(null, MapCoordinates.Nullspace)).Seed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the round seed if assigned, otherwise assigns the round seed itself.
|
||||
/// </summary>
|
||||
/// <returns>seed of the round</returns>
|
||||
public int GetSeed()
|
||||
{
|
||||
var query = EntityQuery<CP14RoundSeedComponent>();
|
||||
foreach (var comp in query)
|
||||
{
|
||||
return comp.Seed;
|
||||
}
|
||||
|
||||
var seed = SetupSeed();
|
||||
Log.Warning($"Missing RoundSeed. Seed set to {seed}");
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Text;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared._CP14.RoundStatistic;
|
||||
using Content.Shared.GameTicking;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.RoundStatistic;
|
||||
|
||||
public sealed partial class CP14RoundStatTrackerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
private readonly Dictionary<ProtoId<CP14RoundStatTrackerPrototype>, int> _tracking = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
InitializeDemiplaneDeath();
|
||||
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundReset);
|
||||
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRoundEndTextAppend);
|
||||
ClearStatistic();
|
||||
}
|
||||
|
||||
private void OnRoundReset(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
ClearStatistic();
|
||||
}
|
||||
|
||||
private void OnRoundEndTextAppend(RoundEndTextAppendEvent ev)
|
||||
{
|
||||
//TODO: Move to separate UI Text block
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append($"[head=3]{Loc.GetString("cp14-tracker-header")}[/head] \n");
|
||||
foreach (var pair in _tracking)
|
||||
{
|
||||
if (!_proto.TryIndex(pair.Key, out var indexedTracker))
|
||||
continue;
|
||||
|
||||
sb.Append($"- {Loc.GetString(indexedTracker.Text)}: {pair.Value}\n");
|
||||
}
|
||||
ev.AddLine(sb.ToString());
|
||||
}
|
||||
|
||||
private void ClearStatistic()
|
||||
{
|
||||
_tracking.Clear();
|
||||
|
||||
foreach (var statTracker in _proto.EnumeratePrototypes<CP14RoundStatTrackerPrototype>())
|
||||
{
|
||||
_tracking.Add(statTracker.ID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void TrackAdd(ProtoId<CP14RoundStatTrackerPrototype> proto, int dif)
|
||||
{
|
||||
_tracking[proto] += Math.Max(dif, 0);
|
||||
}
|
||||
|
||||
public int? GetTrack(ProtoId<CP14RoundStatTrackerPrototype> proto)
|
||||
{
|
||||
if (!_tracking.TryGetValue(proto, out var stat))
|
||||
{
|
||||
Log.Error($"Failed to get round statistic: {proto}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Content.Shared._CP14.RoundStatistic;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.RoundStatistic.DemiplaneDeath;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the destruction or full-blown death of this entity.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14DeathDemiplaneStatisticComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public ProtoId<CP14RoundStatTrackerPrototype> Statistic = "DemiplaneDeaths";
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Content.Server._CP14.Demiplane;
|
||||
using Content.Server._CP14.RoundStatistic.DemiplaneDeath;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared.GameTicking;
|
||||
|
||||
namespace Content.Server._CP14.RoundStatistic;
|
||||
|
||||
public sealed partial class CP14RoundStatTrackerSystem
|
||||
{
|
||||
private void InitializeDemiplaneDeath()
|
||||
{
|
||||
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnSpawnComplete);
|
||||
SubscribeLocalEvent<CP14DeathDemiplaneStatisticComponent, EntityTerminatingEvent>(OnEntityTerminated);
|
||||
SubscribeLocalEvent<CP14DeathDemiplaneStatisticComponent, CP14DemiplaneUnsafeExit>(OnDemiplaneUnsafeExit);
|
||||
}
|
||||
|
||||
private void OnSpawnComplete(PlayerSpawnCompleteEvent ev)
|
||||
{
|
||||
EnsureComp<CP14DeathDemiplaneStatisticComponent>(ev.Mob);
|
||||
}
|
||||
|
||||
private void OnDemiplaneUnsafeExit(Entity<CP14DeathDemiplaneStatisticComponent> ent, ref CP14DemiplaneUnsafeExit args)
|
||||
{
|
||||
TrackAdd(ent.Comp.Statistic, 1);
|
||||
}
|
||||
|
||||
//For round remove variants, like gibs or chasm falls
|
||||
private void OnEntityTerminated(Entity<CP14DeathDemiplaneStatisticComponent> ent, ref EntityTerminatingEvent args)
|
||||
{
|
||||
if (!HasComp<CP14DemiplaneComponent>(Transform(ent).MapUid))
|
||||
return;
|
||||
|
||||
TrackAdd(ent.Comp.Statistic, 1);
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,12 @@ using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Server.Nutrition.EntitySystems;
|
||||
using Content.Shared._CP14.Temperature;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Smoking;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
@@ -25,6 +27,7 @@ public sealed partial class CP14FireSpreadSystem : CP14SharedFireSpreadSystem
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
[Dependency] private readonly TileSystem _tile = default!;
|
||||
[Dependency] private readonly ITileDefinitionManager _tileDef = default!;
|
||||
[Dependency] private readonly SmokingSystem _smoking = default!;
|
||||
|
||||
private readonly EntProtoId _fireProto = "CP14Fire";
|
||||
|
||||
@@ -35,6 +38,8 @@ public sealed partial class CP14FireSpreadSystem : CP14SharedFireSpreadSystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FlammableComponent, CP14IgnitionDoAfter>(OnFlammableIgnited);
|
||||
SubscribeLocalEvent<SmokableComponent, CP14IgnitionDoAfter>(OnDelayedIgnite);
|
||||
SubscribeLocalEvent<SmokingPipeComponent, CP14IgnitionDoAfter>(OnDelayedPipeIgnite);
|
||||
SubscribeLocalEvent<CP14FlammableBonusDamageComponent, MeleeHitEvent>(OnFlammableMeleeHit);
|
||||
}
|
||||
|
||||
@@ -59,6 +64,22 @@ public sealed partial class CP14FireSpreadSystem : CP14SharedFireSpreadSystem
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
//For smokable cigars
|
||||
private void OnDelayedIgnite(Entity<SmokableComponent> ent, ref CP14IgnitionDoAfter args)
|
||||
{
|
||||
_smoking.SetSmokableState(ent, SmokableState.Lit, ent.Comp);
|
||||
}
|
||||
|
||||
//For smokable pipes
|
||||
private void OnDelayedPipeIgnite(Entity<SmokingPipeComponent> pipe, ref CP14IgnitionDoAfter args)
|
||||
{
|
||||
if (!TryComp<SmokableComponent>(pipe, out var smokable))
|
||||
return;
|
||||
|
||||
if (_smoking.TryTransferReagents(pipe, (pipe.Owner, smokable)))
|
||||
_smoking.SetSmokableState(pipe, SmokableState.Lit, smokable);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
@@ -30,11 +30,11 @@ public sealed partial class CP14WorkbenchSystem
|
||||
if (!_proto.TryIndex(recipeId, out var indexedRecipe))
|
||||
continue;
|
||||
|
||||
if (indexedRecipe.KnowledgeRequired is not null)
|
||||
{
|
||||
if (!_knowledge.HasKnowledge(user, indexedRecipe.KnowledgeRequired.Value))
|
||||
continue;
|
||||
}
|
||||
//if (indexedRecipe.KnowledgeRequired is not null)
|
||||
//{
|
||||
// if (!_knowledge.HasKnowledge(user, indexedRecipe.KnowledgeRequired.Value))
|
||||
// continue;
|
||||
//}
|
||||
|
||||
var entry = new CP14WorkbenchUiRecipesEntry(recipeId, CanCraftRecipe(indexedRecipe, placedEntities, user));
|
||||
|
||||
|
||||
@@ -87,99 +87,16 @@ public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (recipe.KnowledgeRequired is not null)
|
||||
_knowledge.UseKnowledge(args.User, recipe.KnowledgeRequired.Value);
|
||||
|
||||
var resultEntities = new HashSet<EntityUid>();
|
||||
for (int i = 0; i < recipe.ResultCount; i++)
|
||||
{
|
||||
var resultEntity = Spawn(recipe.Result);
|
||||
|
||||
resultEntities.Add(resultEntity);
|
||||
|
||||
if (recipe.TryMergeSolutions)
|
||||
{
|
||||
_solutionContainer.TryGetSolution(resultEntity, recipe.Solution, out var resultSolution, out _);
|
||||
|
||||
if (resultSolution is not null)
|
||||
{
|
||||
resultSolution.Value.Comp.Solution.MaxVolume = 0;
|
||||
_solutionContainer.RemoveAllSolution(resultSolution
|
||||
.Value); //If we combine ingredient solutions, we do not use the default solution prescribed in the entity.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var requiredIngredient in recipe.Entities)
|
||||
foreach (var req in recipe.Requirements)
|
||||
{
|
||||
var requiredCount = requiredIngredient.Value;
|
||||
foreach (var placedEntity in placedEntities)
|
||||
{
|
||||
if (!TryComp<MetaDataComponent>(placedEntity, out var metaData))
|
||||
continue;
|
||||
|
||||
if (metaData.EntityPrototype is null)
|
||||
continue;
|
||||
|
||||
var placedProto = metaData.EntityPrototype.ID;
|
||||
if (placedProto == requiredIngredient.Key && requiredCount > 0)
|
||||
{
|
||||
// Trying merge solutions
|
||||
if (recipe.TryMergeSolutions)
|
||||
{
|
||||
_solutionContainer.TryGetSolution(placedEntity,
|
||||
recipe.Solution,
|
||||
out var ingredientSoln,
|
||||
out var ingredientSolution);
|
||||
|
||||
if (ingredientSoln is not null &&
|
||||
ingredientSolution is not null)
|
||||
{
|
||||
var splitted = _solutionContainer.SplitSolution(ingredientSoln.Value,
|
||||
ingredientSolution.Volume / recipe.ResultCount);
|
||||
|
||||
foreach (var resultEntity in resultEntities)
|
||||
{
|
||||
_solutionContainer.TryGetSolution(resultEntity,
|
||||
recipe.Solution,
|
||||
out var resultSolution,
|
||||
out _);
|
||||
if (resultSolution is not null)
|
||||
{
|
||||
resultSolution.Value.Comp.Solution.MaxVolume +=
|
||||
ingredientSoln.Value.Comp.Solution.MaxVolume / recipe.ResultCount;
|
||||
_solutionContainer.TryAddSolution(resultSolution.Value, splitted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
requiredCount--;
|
||||
Del(placedEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var requiredStack in recipe.Stacks)
|
||||
{
|
||||
var requiredCount = requiredStack.Value;
|
||||
foreach (var placedEntity in placedEntities)
|
||||
{
|
||||
if (!_stackQuery.TryGetComponent(placedEntity, out var stack))
|
||||
continue;
|
||||
|
||||
if (stack.StackTypeId != requiredStack.Key)
|
||||
continue;
|
||||
|
||||
var count = (int)MathF.Min(requiredCount, stack.Count);
|
||||
|
||||
if (stack.Count - count <= 0)
|
||||
Del(placedEntity);
|
||||
else
|
||||
_stack.SetCount(placedEntity, stack.Count - count, stack);
|
||||
|
||||
requiredCount -= count;
|
||||
}
|
||||
req.PostCraft(EntityManager, placedEntities, args.User);
|
||||
}
|
||||
|
||||
//We teleport result to workbench AFTER craft.
|
||||
@@ -219,56 +136,12 @@ public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
|
||||
private bool CanCraftRecipe(CP14WorkbenchRecipePrototype recipe, HashSet<EntityUid> entities, EntityUid user)
|
||||
{
|
||||
//Knowledge check
|
||||
if (recipe.KnowledgeRequired is not null && !_knowledge.HasKnowledge(user, recipe.KnowledgeRequired.Value))
|
||||
return false;
|
||||
|
||||
//Ingredients check
|
||||
var indexedIngredients = IndexIngredients(entities);
|
||||
foreach (var requiredIngredient in recipe.Entities)
|
||||
foreach (var req in recipe.Requirements)
|
||||
{
|
||||
if (!indexedIngredients.TryGetValue(requiredIngredient.Key, out var availableQuantity) ||
|
||||
availableQuantity < requiredIngredient.Value)
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var (key, value) in recipe.Stacks)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var ent in entities)
|
||||
{
|
||||
if (_stackQuery.TryGetComponent(ent, out var stack))
|
||||
{
|
||||
if (stack.StackTypeId != key)
|
||||
continue;
|
||||
|
||||
count += stack.Count;
|
||||
}
|
||||
}
|
||||
|
||||
if (count < value)
|
||||
if (!req.CheckRequirement(EntityManager, _proto, entities, user))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Dictionary<EntProtoId, int> IndexIngredients(HashSet<EntityUid> ingredients)
|
||||
{
|
||||
var indexedIngredients = new Dictionary<EntProtoId, int>();
|
||||
|
||||
foreach (var ingredient in ingredients)
|
||||
{
|
||||
var protoId = _metaQuery.GetComponent(ingredient).EntityPrototype?.ID;
|
||||
if (protoId == null)
|
||||
continue;
|
||||
|
||||
if (indexedIngredients.ContainsKey(protoId))
|
||||
indexedIngredients[protoId]++;
|
||||
else
|
||||
indexedIngredients[protoId] = 1;
|
||||
}
|
||||
|
||||
return indexedIngredients;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<ProjectReference Include="..\RobustToolbox\Lidgren.Network\Lidgren.Network.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\RobustToolbox\Robust.Client\Robust.Client.csproj" />
|
||||
<ProjectReference Include="..\RobustToolbox\Robust.Shared.Maths\Robust.Shared.Maths.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
|
||||
15
Content.Shared/_CP14/CCvar/CCvars.CP14DiscordAuth.cs
Normal file
15
Content.Shared/_CP14/CCvar/CCvars.CP14DiscordAuth.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Shared.CCVar;
|
||||
|
||||
public sealed partial class CCVars
|
||||
{
|
||||
public static readonly CVarDef<bool> DiscordAuthEnabled =
|
||||
CVarDef.Create("cp14.discord_auth_enabled", false, CVar.SERVERONLY);
|
||||
|
||||
public static readonly CVarDef<string> DiscordAuthUrl =
|
||||
CVarDef.Create("cp14.discord_auth_url", "http://localhost:8000/sponsors", CVar.SERVERONLY | CVar.CONFIDENTIAL);
|
||||
|
||||
public static readonly CVarDef<string> DiscordAuthToken =
|
||||
CVarDef.Create("cp14.discord_auth_token", "token", CVar.SERVERONLY | CVar.CONFIDENTIAL);
|
||||
}
|
||||
9
Content.Shared/_CP14/CCvar/CCvars.CP14JoinQueue.cs
Normal file
9
Content.Shared/_CP14/CCvar/CCvars.CP14JoinQueue.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Shared.CCVar;
|
||||
|
||||
public sealed partial class CCVars
|
||||
{
|
||||
public static readonly CVarDef<bool> QueueEnabled =
|
||||
CVarDef.Create("cp14.join_queue_enabled", true, CVar.SERVERONLY);
|
||||
}
|
||||
12
Content.Shared/_CP14/CCvar/CCvars.CP14Sponsors.cs
Normal file
12
Content.Shared/_CP14/CCvar/CCvars.CP14Sponsors.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Shared.CCVar;
|
||||
|
||||
public sealed partial class CCVars
|
||||
{
|
||||
public static readonly CVarDef<string> SponsorsApiUrl =
|
||||
CVarDef.Create("cp14.sponsor_api_url", "http://localhost:8000/sponsors", CVar.SERVERONLY | CVar.CONFIDENTIAL);
|
||||
|
||||
public static readonly CVarDef<string> SponsorsApiKey =
|
||||
CVarDef.Create("cp14.sponsor_api_key", "token", CVar.SERVERONLY | CVar.CONFIDENTIAL);
|
||||
}
|
||||
@@ -14,10 +14,10 @@ public abstract partial class CP14SharedDemiplaneSystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneRiftOpenedComponent, InteractHandEvent>(OnDemiplanPasswayInteract);
|
||||
SubscribeLocalEvent<CP14DemiplaneRiftOpenedComponent, InteractHandEvent>(OnDemiplanePasswayInteract);
|
||||
}
|
||||
|
||||
private void OnDemiplanPasswayInteract(Entity<CP14DemiplaneRiftOpenedComponent> passway, ref InteractHandEvent args)
|
||||
private void OnDemiplanePasswayInteract(Entity<CP14DemiplaneRiftOpenedComponent> passway, ref InteractHandEvent args)
|
||||
{
|
||||
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager,
|
||||
args.User,
|
||||
@@ -33,6 +33,16 @@ public abstract partial class CP14SharedDemiplaneSystem : EntitySystem
|
||||
MovementThreshold = 0.2f,
|
||||
});
|
||||
}
|
||||
|
||||
public virtual bool TryTeleportIntoDemiplane(Entity<CP14DemiplaneComponent> demiplane, EntityUid? entity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool TryTeleportOutDemiplane(Entity<CP14DemiplaneComponent> demiplane, EntityUid? entity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Shared._CP14.DemiplaneTraveling;
|
||||
|
||||
/// <summary>
|
||||
/// teleports a certain number of entities to coordinate with a delay
|
||||
/// </summary>
|
||||
[RegisterComponent, AutoGenerateComponentPause]
|
||||
public sealed partial class CP14MonolithTimedPasswayComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public int MaxEntities = 3;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan Delay = TimeSpan.FromSeconds(10f);
|
||||
|
||||
[DataField]
|
||||
public float Radius = 3f;
|
||||
|
||||
[DataField]
|
||||
[AutoPausedField]
|
||||
public TimeSpan NextTimeTeleport = TimeSpan.Zero;
|
||||
|
||||
[DataField("arrivalSound")]
|
||||
public SoundSpecifier ArrivalSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg");
|
||||
|
||||
[DataField("departureSound")]
|
||||
public SoundSpecifier DepartureSound = new SoundPathSpecifier("/Audio/Effects/teleport_departure.ogg");
|
||||
}
|
||||
18
Content.Shared/_CP14/Discord/MsgDiscordAuthCheck.cs
Normal file
18
Content.Shared/_CP14/Discord/MsgDiscordAuthCheck.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Discord;
|
||||
|
||||
public sealed class MsgDiscordAuthCheck : NetMessage
|
||||
{
|
||||
public override MsgGroups MsgGroup => MsgGroups.Command;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
}
|
||||
}
|
||||
21
Content.Shared/_CP14/Discord/MsgDiscordAuthRequired.cs
Normal file
21
Content.Shared/_CP14/Discord/MsgDiscordAuthRequired.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Lidgren.Network;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Discord;
|
||||
|
||||
public sealed class MsgDiscordAuthRequired : NetMessage
|
||||
{
|
||||
public override MsgGroups MsgGroup => MsgGroups.Command;
|
||||
public string AuthUrl { get; set; } = string.Empty;
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
AuthUrl = buffer.ReadString();
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||
{
|
||||
buffer.Write(AuthUrl);
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,8 @@ public abstract partial class CP14SharedMagicSystem
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.StartSpeech,
|
||||
Speech = Loc.GetString(ent.Comp.StartSpeech),
|
||||
Emote = ent.Comp.Emote
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
@@ -108,7 +109,8 @@ public abstract partial class CP14SharedMagicSystem
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.EndSpeech,
|
||||
Speech = Loc.GetString(ent.Comp.EndSpeech),
|
||||
Emote = ent.Comp.Emote
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,13 @@ namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
public sealed partial class CP14MagicEffectVerbalAspectComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string StartSpeech = string.Empty;
|
||||
public string StartSpeech = string.Empty; //Not LocId!
|
||||
|
||||
[DataField]
|
||||
public string EndSpeech = string.Empty;
|
||||
public string EndSpeech = string.Empty; //Not LocId!
|
||||
|
||||
[DataField]
|
||||
public bool Emote = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -22,4 +25,6 @@ public sealed class CP14VerbalAspectSpeechEvent : EntityEventArgs
|
||||
public EntityUid? Performer { get; init; }
|
||||
|
||||
public string? Speech { get; init; }
|
||||
|
||||
public bool Emote { get; init; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using Content.Shared._CP14.Demiplane;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Spells;
|
||||
|
||||
public sealed partial class CP14SpellDemiplaneInfiltration : CP14SpellEffect
|
||||
{
|
||||
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
if (args.User is null)
|
||||
return;
|
||||
|
||||
if (!entManager.TryGetComponent<CP14DemiplaneRiftComponent>(args.Target, out var rift))
|
||||
return;
|
||||
|
||||
if (rift.Demiplane is null)
|
||||
return;
|
||||
|
||||
if (!entManager.TryGetComponent<CP14DemiplaneComponent>(rift.Demiplane.Value, out var demiplane))
|
||||
return;
|
||||
|
||||
var demiplaneSystem = entManager.System<CP14SharedDemiplaneSystem>();
|
||||
|
||||
demiplaneSystem.TryTeleportIntoDemiplane((rift.Demiplane.Value, demiplane), args.User.Value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Content.Shared.Throwing;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Spells;
|
||||
|
||||
public sealed partial class CP14SpellThrowFromUser : CP14SpellEffect
|
||||
{
|
||||
[DataField]
|
||||
public float ThrowPower = 10f;
|
||||
|
||||
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
if (args.Target is null)
|
||||
return;
|
||||
|
||||
var targetEntity = args.Target.Value;
|
||||
|
||||
var throwing = entManager.System<ThrowingSystem>();
|
||||
var xfom = entManager.System<SharedTransformSystem>();
|
||||
|
||||
if (!entManager.TryGetComponent<TransformComponent>(args.User, out var userTransform))
|
||||
return;
|
||||
|
||||
if (!entManager.TryGetComponent<TransformComponent>(targetEntity, out var targetTransform))
|
||||
return;
|
||||
|
||||
var worldPos = xfom.GetWorldPosition(args.User.Value);
|
||||
var foo = xfom.GetWorldPosition(args.Target.Value) - worldPos;
|
||||
|
||||
throwing.TryThrow(targetEntity, foo * 2.5f, ThrowPower, args.User, doSpin: true);
|
||||
}
|
||||
}
|
||||
11
Content.Shared/_CP14/Material/CP14MaterialComponent.cs
Normal file
11
Content.Shared/_CP14/Material/CP14MaterialComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Content.Shared.Materials;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Material;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14MaterialComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public Dictionary<ProtoId<MaterialPrototype>, int> Materials = new();
|
||||
}
|
||||
39
Content.Shared/_CP14/Material/CP14MaterialSystem.cs
Normal file
39
Content.Shared/_CP14/Material/CP14MaterialSystem.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Text;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Material;
|
||||
|
||||
public sealed partial class CP14MaterialSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14MaterialComponent, ExaminedEvent>(OnMaterialExamined);
|
||||
}
|
||||
|
||||
private void OnMaterialExamined(Entity<CP14MaterialComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
TryComp<StackComponent>(ent, out var stack);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append($"{Loc.GetString("cp14-material-examine")}\n");
|
||||
foreach (var material in ent.Comp.Materials)
|
||||
{
|
||||
if (!_proto.TryIndex(material.Key, out var indexedMaterial))
|
||||
continue;
|
||||
|
||||
var count = material.Value;
|
||||
if (stack is not null)
|
||||
count *= stack.Count;
|
||||
|
||||
sb.Append($"[color={indexedMaterial.Color.ToHex()}]{Loc.GetString(indexedMaterial.Name)}[/color] ({count})\n");
|
||||
}
|
||||
args.PushMarkup(sb.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public sealed partial class CP14ModularCraftPartPrototype : IPrototype
|
||||
public EntProtoId? SourcePart;
|
||||
|
||||
[DataField]
|
||||
public float DestroyProb = 0.25f;
|
||||
public float DestroyProb = 0.0f;
|
||||
|
||||
[DataField(serverOnly: true)]
|
||||
public List<CP14ModularCraftModifier> Modifiers = new();
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.RoundStatistic;
|
||||
|
||||
[Prototype("statisticTracker")]
|
||||
public sealed partial class CP14RoundStatTrackerPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId Text;
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -26,27 +24,12 @@ public sealed class CP14WorkbenchRecipePrototype : IPrototype
|
||||
[DataField]
|
||||
public SoundSpecifier? OverrideCraftSound;
|
||||
|
||||
[DataField]
|
||||
public Dictionary<EntProtoId, int> Entities = new();
|
||||
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<StackPrototype>, int> Stacks = new();
|
||||
[DataField(required: true)]
|
||||
public List<CP14WorkbenchCraftRequirement> Requirements = new();
|
||||
|
||||
[DataField(required: true)]
|
||||
public EntProtoId Result;
|
||||
|
||||
[DataField]
|
||||
public int ResultCount = 1;
|
||||
|
||||
[DataField]
|
||||
public bool TryMergeSolutions = false;
|
||||
|
||||
[DataField]
|
||||
public string Solution = "food";
|
||||
|
||||
/// <summary>
|
||||
/// If the player does not have this knowledge, the recipe will not be displayed in the workbench.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<CP14KnowledgePrototype>? KnowledgeRequired;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using Content.Shared._CP14.Knowledge;
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class KnowledgeRequired : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// If the player does not have this knowledge, the recipe will not be displayed in the workbench.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14KnowledgePrototype> Knowledge;
|
||||
|
||||
public override bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user)
|
||||
{
|
||||
var knowledgeSystem = entManager.System<SharedCP14KnowledgeSystem>();
|
||||
|
||||
return knowledgeSystem.HasKnowledge(user, Knowledge);
|
||||
}
|
||||
|
||||
public override void PostCraft(EntityManager entManager, HashSet<EntityUid> placedEntities, EntityUid user)
|
||||
{
|
||||
var knowledgeSystem = entManager.System<SharedCP14KnowledgeSystem>();
|
||||
knowledgeSystem.UseKnowledge(user, Knowledge);
|
||||
}
|
||||
|
||||
public override string GetRequirementTitle(IPrototypeManager protoManager)
|
||||
{
|
||||
return !protoManager.TryIndex(Knowledge, out var indexedKnowledge)
|
||||
? "Error knowledge"
|
||||
: $"{Loc.GetString("cp14-knowledge")}: {Loc.GetString(indexedKnowledge.Name)}";
|
||||
}
|
||||
|
||||
public override EntityPrototype? GetRequirementEntityView(IPrototypeManager protoManager)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override SpriteSpecifier? GetRequirementTexture(IPrototypeManager protoManager)
|
||||
{
|
||||
return new SpriteSpecifier.Texture(new("/Textures/Interface/students-cap.svg.192dpi.png"));
|
||||
}
|
||||
}
|
||||
112
Content.Shared/_CP14/Workbench/Requirements/MaterialResource.cs
Normal file
112
Content.Shared/_CP14/Workbench/Requirements/MaterialResource.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is sublicensed under MIT License
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Material;
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<MaterialPrototype> Material;
|
||||
|
||||
[DataField]
|
||||
public int Count = 1;
|
||||
|
||||
public override bool CheckRequirement(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid user)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var ent in placedEntities)
|
||||
{
|
||||
if (!entManager.TryGetComponent<CP14MaterialComponent>(ent, out var material))
|
||||
continue;
|
||||
|
||||
entManager.TryGetComponent<StackComponent>(ent, out var stack);
|
||||
|
||||
foreach (var (key, value) in material.Materials)
|
||||
{
|
||||
if (key != Material)
|
||||
continue;
|
||||
|
||||
if (stack is null)
|
||||
{
|
||||
count += value;
|
||||
}
|
||||
else
|
||||
{
|
||||
count += value * stack.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count < Count)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void PostCraft(EntityManager entManager, HashSet<EntityUid> placedEntities, EntityUid user)
|
||||
{
|
||||
var stackSystem = entManager.System<SharedStackSystem>();
|
||||
|
||||
var requiredCount = Count;
|
||||
foreach (var placedEntity in placedEntities)
|
||||
{
|
||||
if (!entManager.TryGetComponent<CP14MaterialComponent>(placedEntity, out var material))
|
||||
continue;
|
||||
|
||||
entManager.TryGetComponent<StackComponent>(placedEntity, out var stack);
|
||||
|
||||
foreach (var mat in material.Materials)
|
||||
{
|
||||
if (mat.Key != Material)
|
||||
continue;
|
||||
|
||||
if (stack is null)
|
||||
{
|
||||
var value = (int)MathF.Min(requiredCount, mat.Value);
|
||||
requiredCount -= value;
|
||||
entManager.DeleteEntity(placedEntity);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
var materialValue = mat.Value * stack.Count;
|
||||
var countToRemove = (int)MathF.Min(requiredCount, materialValue);
|
||||
var newStackCount = (int)MathF.Ceiling((materialValue - countToRemove) / (float)mat.Value);
|
||||
|
||||
if (newStackCount <= 0)
|
||||
entManager.DeleteEntity(placedEntity);
|
||||
else
|
||||
stackSystem.SetCount(placedEntity, newStackCount, stack);
|
||||
|
||||
requiredCount -= countToRemove;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetRequirementTitle(IPrototypeManager protoManager)
|
||||
{
|
||||
if (!protoManager.TryIndex(Material, out var indexedMaterial))
|
||||
return "Error material";
|
||||
|
||||
return $"{Loc.GetString(indexedMaterial.Name)} x{Count}";
|
||||
}
|
||||
|
||||
public override EntityPrototype? GetRequirementEntityView(IPrototypeManager protoManager)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override SpriteSpecifier? GetRequirementTexture(IPrototypeManager protoManager)
|
||||
{
|
||||
return !protoManager.TryIndex(Material, out var indexedMaterial) ? null : indexedMaterial.Icon;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is sublicensed under MIT License
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class ProtoIdResource : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public EntProtoId ProtoId;
|
||||
|
||||
[DataField]
|
||||
public int Count = 1;
|
||||
|
||||
public override bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user)
|
||||
{
|
||||
var indexedIngredients = IndexIngredients(entManager, placedEntities);
|
||||
|
||||
return indexedIngredients.TryGetValue(ProtoId, out var availableQuantity) && availableQuantity >= Count;
|
||||
}
|
||||
|
||||
public override void PostCraft(EntityManager entManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user)
|
||||
{
|
||||
var requiredCount = Count;
|
||||
|
||||
foreach (var placedEntity in placedEntities)
|
||||
{
|
||||
if (!entManager.TryGetComponent<MetaDataComponent>(placedEntity, out var metaData))
|
||||
continue;
|
||||
|
||||
if (metaData.EntityPrototype is null)
|
||||
continue;
|
||||
|
||||
var placedProto = metaData.EntityPrototype.ID;
|
||||
if (placedProto != ProtoId || requiredCount <= 0)
|
||||
continue;
|
||||
|
||||
requiredCount--;
|
||||
entManager.DeleteEntity(placedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetRequirementTitle(IPrototypeManager protoManager)
|
||||
{
|
||||
if (!protoManager.TryIndex(ProtoId, out var indexedProto))
|
||||
return "Error entity";
|
||||
|
||||
return $"{indexedProto.Name} x{Count}";
|
||||
}
|
||||
|
||||
public override EntityPrototype? GetRequirementEntityView(IPrototypeManager protoManager)
|
||||
{
|
||||
if (!protoManager.TryIndex(ProtoId, out var indexedProto))
|
||||
return null;
|
||||
|
||||
return indexedProto;
|
||||
}
|
||||
|
||||
public override SpriteSpecifier? GetRequirementTexture(IPrototypeManager protoManager)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private Dictionary<EntProtoId, int> IndexIngredients(EntityManager entManager, HashSet<EntityUid> ingredients)
|
||||
{
|
||||
var indexedIngredients = new Dictionary<EntProtoId, int>();
|
||||
|
||||
foreach (var ingredient in ingredients)
|
||||
{
|
||||
if (!entManager.TryGetComponent<MetaDataComponent>(ingredient, out var metaData))
|
||||
continue;
|
||||
|
||||
var protoId = metaData.EntityPrototype?.ID;
|
||||
if (protoId == null)
|
||||
continue;
|
||||
|
||||
if (indexedIngredients.ContainsKey(protoId))
|
||||
indexedIngredients[protoId]++;
|
||||
else
|
||||
indexedIngredients[protoId] = 1;
|
||||
}
|
||||
|
||||
return indexedIngredients;
|
||||
}
|
||||
}
|
||||
86
Content.Shared/_CP14/Workbench/Requirements/StackResource.cs
Normal file
86
Content.Shared/_CP14/Workbench/Requirements/StackResource.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is sublicensed under MIT License
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class StackResource : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<StackPrototype> Stack;
|
||||
|
||||
[DataField]
|
||||
public int Count = 1;
|
||||
|
||||
public override bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var ent in placedEntities)
|
||||
{
|
||||
if (!entManager.TryGetComponent<StackComponent>(ent, out var stack))
|
||||
continue;
|
||||
|
||||
if (stack.StackTypeId != Stack)
|
||||
continue;
|
||||
|
||||
count += stack.Count;
|
||||
}
|
||||
|
||||
if (count < Count)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void PostCraft(EntityManager entManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user)
|
||||
{
|
||||
var stackSystem = entManager.System<SharedStackSystem>();
|
||||
|
||||
var requiredCount = Count;
|
||||
foreach (var placedEntity in placedEntities)
|
||||
{
|
||||
if (!entManager.TryGetComponent<StackComponent>(placedEntity, out var stack))
|
||||
continue;
|
||||
|
||||
if (stack.StackTypeId != Stack)
|
||||
continue;
|
||||
|
||||
var count = (int)MathF.Min(requiredCount, stack.Count);
|
||||
|
||||
if (stack.Count - count <= 0)
|
||||
entManager.DeleteEntity(placedEntity);
|
||||
else
|
||||
stackSystem.SetCount(placedEntity, stack.Count - count, stack);
|
||||
|
||||
requiredCount -= count;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetRequirementTitle(IPrototypeManager protoManager)
|
||||
{
|
||||
if (!protoManager.TryIndex(Stack, out var indexedStack))
|
||||
return "Error stack";
|
||||
|
||||
return $"{Loc.GetString(indexedStack.Name)} x{Count}";
|
||||
}
|
||||
|
||||
public override EntityPrototype? GetRequirementEntityView(IPrototypeManager protoManager)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override SpriteSpecifier? GetRequirementTexture(IPrototypeManager protoManager)
|
||||
{
|
||||
return !protoManager.TryIndex(Stack, out var indexedStack) ? null : indexedStack.Icon;
|
||||
}
|
||||
}
|
||||
46
Content.Shared/_CP14/Workbench/WorkbenchCraftRequirement.cs
Normal file
46
Content.Shared/_CP14/Workbench/WorkbenchCraftRequirement.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is sublicensed under MIT License
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Workbench;
|
||||
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
[MeansImplicitUse]
|
||||
public abstract partial class CP14WorkbenchCraftRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Here a check is made that the recipe as a whole can be fulfilled at the current moment. Do not add anything that affects gameplay here, and only perform checks here.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user);
|
||||
|
||||
/// <summary>
|
||||
/// An event that is triggered after crafting. This is the place to put important things like removing items, spending stacks or other things.
|
||||
/// </summary>
|
||||
public abstract void PostCraft(EntityManager entManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user);
|
||||
|
||||
/// <summary>
|
||||
/// This text will be displayed in the description of the craft recipe. Write something like ‘Wooden planks: х10’ here
|
||||
/// </summary>
|
||||
public abstract string GetRequirementTitle(IPrototypeManager protoManager);
|
||||
|
||||
/// <summary>
|
||||
/// You can specify an icon generated from an entity. It will support layering, colour changes and other layer options. Return null to disable.
|
||||
/// </summary>
|
||||
public abstract EntityPrototype? GetRequirementEntityView(IPrototypeManager protoManager);
|
||||
|
||||
/// <summary>
|
||||
/// You can specify the texture directly. Return null to disable.
|
||||
/// </summary>
|
||||
public abstract SpriteSpecifier? GetRequirementTexture(IPrototypeManager protoManager);
|
||||
}
|
||||
@@ -58,8 +58,12 @@
|
||||
copyright: 'by egomassive of Freesound.org.'
|
||||
source: "https://freesound.org/people/egomassive/sounds/536728/"
|
||||
|
||||
|
||||
- files: ["ghost_ambi.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: 'by Litruv of Freesound.org.'
|
||||
source: "https://freesound.org/people/Litruv/sounds/175944/"
|
||||
|
||||
- files: ["frog1.ogg, frog2.ogg, frog3.ogg"]
|
||||
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/"
|
||||
|
||||
BIN
Resources/Audio/_CP14/Animals/frog1.ogg
Normal file
BIN
Resources/Audio/_CP14/Animals/frog1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_CP14/Animals/frog2.ogg
Normal file
BIN
Resources/Audio/_CP14/Animals/frog2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_CP14/Animals/frog3.ogg
Normal file
BIN
Resources/Audio/_CP14/Animals/frog3.ogg
Normal file
Binary file not shown.
@@ -15,9 +15,10 @@ max_connections = 100
|
||||
|
||||
[game]
|
||||
hostname = "⚔️ CrystallEdge Alpha ⚔️ "
|
||||
desc = "History of the City of Sword and Magic. A social economic sandbox reinventing the Space Station 14 concept in"
|
||||
desc = "History of the City of Sword and Magic. A social economic sandbox reinventing the Space Station 14 concept in fantasy style"
|
||||
lobbyenabled = true
|
||||
soft_max_players = 40
|
||||
lobbyduration = 300
|
||||
|
||||
[server]
|
||||
rules_file = "CP14SandboxRU"
|
||||
@@ -50,4 +51,11 @@ deadmin_on_join = true
|
||||
flavor_text = true
|
||||
|
||||
[tips]
|
||||
dataset = "CP14Tips"
|
||||
dataset = "CP14Tips"
|
||||
|
||||
[ooc]
|
||||
show_ooc_patron_color = false
|
||||
enable_during_round = true
|
||||
|
||||
[cp14]
|
||||
discord_auth_enabled = true
|
||||
|
||||
6
Resources/Locale/en-US/_CP14/connection_messages.ftl
Normal file
6
Resources/Locale/en-US/_CP14/connection_messages.ftl
Normal file
@@ -0,0 +1,6 @@
|
||||
cp14-discord-info = To play on the server you need to go to our server in discord to authorise your account.
|
||||
cp14-discord-auth-quit-btn = Exit
|
||||
cp14-discord-auth-title = Authorisation
|
||||
cp14-discord-auth-link = https://discord.com/invite/Sud2DMfhCC
|
||||
cp14-discord-auth-browser-btn = Discord Server
|
||||
cp14-discord-auth-text = Authorize
|
||||
@@ -7,3 +7,6 @@ cp14-round-end-monolith-50 = The demiplane link crystal is half discharged.
|
||||
cp14-round-end-monolith-discharged = You feel the connection to the other worlds begin to break.... The demiplane link crystal power will run out in { $time } { $units } if you don't charge it with mana completely...
|
||||
cp14-round-end-monolith-recharged = Contact with the other worlds is being re-established. The demiplane link crystal is fully charged.
|
||||
cp14-round-end = The demiplane link crystal was completely discharged. The connection to the other worlds has been severed. The "interesting" part of the story is over here....
|
||||
|
||||
|
||||
cp14-demiplane-echoes = Echoes of voices
|
||||
5
Resources/Locale/en-US/_CP14/discord/queue.ftl
Normal file
5
Resources/Locale/en-US/_CP14/discord/queue.ftl
Normal file
@@ -0,0 +1,5 @@
|
||||
queue-title = Queue
|
||||
queue-quit = Disconnect
|
||||
queue-position = Position
|
||||
queue-total = Total
|
||||
queue-priority-join = Priority join
|
||||
@@ -1 +1,2 @@
|
||||
cp14-knowledge-info-title = Character knowledge
|
||||
cp14-knowledge-info-title = Character knowledge
|
||||
cp14-knowledge = Knowledge
|
||||
@@ -42,6 +42,15 @@ cp14-loadout-guard-spells = Guard's spells
|
||||
cp14-loadout-bank-head = Bank employee hat
|
||||
cp14-loadout-commandant-head = Commandant's hat
|
||||
cp14-loadout-commandant-cloak = Commandant's cloak
|
||||
cp14-loadout-banker-outer = Banker's waistcoat
|
||||
cp14-loadout-bank-shirt = Bank Employee shirt
|
||||
cp14-loadout-bank-pants = Bank Employee pants
|
||||
cp14-loadout-bank-shoes = Bank Employee shoes
|
||||
|
||||
# Guildmaster
|
||||
|
||||
cp14-loadout-guildmaster-cloak = Guildmaster cloak
|
||||
cp14-loadout-guildmaster-shirt = Guildmaster shirt
|
||||
cp14-loadout-guildmaster-pants = Guildmaster pants
|
||||
cp14-loadout-guildmaster-shoes = Guildmaster shoes
|
||||
cp14-loadout-guildmaster-spells = Guildmaster spells
|
||||
@@ -14,9 +14,11 @@ cp14-lock-shape-tavern-dorm5 = tavern room №5
|
||||
|
||||
cp14-lock-shape-alchemist1 = alchemist's lab №1
|
||||
cp14-lock-shape-alchemist2 = alchemist's lab №2
|
||||
cp14-lock-shape-alchemist3 = alchemist's lab №3
|
||||
|
||||
cp14-lock-shape-blacksmith1 = forge №1
|
||||
cp14-lock-shape-blacksmith2 = forge №2
|
||||
cp14-lock-shape-blacksmith3 = forge №3
|
||||
|
||||
cp14-lock-shape-personalhouse1 = house №1
|
||||
cp14-lock-shape-personalhouse2 = house №2
|
||||
@@ -33,9 +35,12 @@ cp14-lock-shape-personalhouse12 = house №12
|
||||
cp14-lock-shape-personalhouse13 = house №13
|
||||
cp14-lock-shape-personalhouse14 = house №14
|
||||
cp14-lock-shape-personalhouse15 = house №15
|
||||
cp14-lock-shape-personalhouse16 = house №16
|
||||
|
||||
cp14-lock-shaper-guard-entrance = barracks, entrance
|
||||
cp14-lock-shaper-guard-staff = barracks
|
||||
cp14-lock-shaper-guard-commander = guardhouse
|
||||
cp14-lock-shaper-guard-weapon-storage = weapons storage
|
||||
cp14-lock-shape-guildmaster = guildmaster
|
||||
|
||||
cp14-lock-shape-guildmaster = guildmaster
|
||||
cp14-lock-shape-demiplane-crystal = demiplane crystal
|
||||
1
Resources/Locale/en-US/_CP14/magicSpells/speech.ftl
Normal file
1
Resources/Locale/en-US/_CP14/magicSpells/speech.ftl
Normal file
@@ -0,0 +1 @@
|
||||
cp14-kick-emote = makes a strong kick
|
||||
@@ -2,10 +2,9 @@ cp14-magic-type-fire = Fire
|
||||
cp14-magic-type-water = Water
|
||||
cp14-magic-type-earth = Earth
|
||||
cp14-magic-type-healing = Healing
|
||||
cp14-magic-type-light-darkness = Light and darkness
|
||||
cp14-magic-type-light = Light
|
||||
cp14-magic-type-darkness = Darkness
|
||||
cp14-magic-type-meta = Metamagic
|
||||
cp14-magic-type-gate = Gate
|
||||
cp14-magic-type-movement = Movement
|
||||
cp14-magic-type-necro = Necromancy
|
||||
|
||||
cp14-magic-manacost = Manacost
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
cp14-material-examine = Consists of materials:
|
||||
|
||||
cp14-material-wooden-planks = wooden planks
|
||||
cp14-material-dirt-block = dirt
|
||||
cp14-material-stone-block = stone
|
||||
|
||||
@@ -4,4 +4,7 @@ cp14-objective-town-send-title = Extract { $count } { $itemName }
|
||||
cp14-objective-town-send-desc = Your task is to mine and ship { $count } { $itemName } to the city on a merchant ship.
|
||||
|
||||
cp14-objective-bank-earning-title = Accumulate in the vault{ $coins }
|
||||
cp14-objective-bank-earning-desc = There must be at least{ $coins } in the bank vault. You can use any methods of earning money that do not violate the law.
|
||||
cp14-objective-bank-earning-desc = There must be at least{ $coins } in the bank vault. You can use any methods of earning money that do not violate the law.
|
||||
|
||||
cp14-objective-no-demiplane-death-title = Prevent deaths in the demiplanes
|
||||
cp14-objective-no-demiplane-death-desc = I need to control the work of the adventurers so they don't die in the demiplanes. No more {$max} deaths!
|
||||
@@ -3,4 +3,5 @@ cp14-stamp-salary = Intendant of the Guard
|
||||
cp14-stamp-denied = Denied
|
||||
cp14-stamp-approved = Approved
|
||||
cp14-stamp-bank = Commandant
|
||||
cp14-stamp-guard-commander = Guard commander
|
||||
cp14-stamp-guard-commander = Guard commander
|
||||
cp14-stamp-guildmaster = Guildmaster
|
||||
@@ -0,0 +1,4 @@
|
||||
cp14-tracker-header = Round statistic:
|
||||
|
||||
cp14-tracker-demiplane-open = Demiplanes opened
|
||||
cp14-tracker-demiplane-deaths = Players died in demiplanes
|
||||
@@ -1,2 +0,0 @@
|
||||
cp14-world-edge-pre-remove-message = [color=red]CAUTION![/color] You are leaving the game zone! If you do not return within [color=red]{$second}[/color] seconds, you will be permanently removed from the round!
|
||||
cp14-world-edge-cancel-removing-message = The exit round has been canceled.
|
||||
@@ -427,6 +427,9 @@ ent-CP14ClothingCloakGuardBlue = { ent-CP14ClothingCloakGuardBase }
|
||||
ent-CP14ClothingCloakGuardCommander = бронированный плащ командира гвардии
|
||||
.desc = Это чрезвычайно прочная и легкая накидка, разработанная специально для командиров Имперской гвардии.
|
||||
|
||||
ent-CP14ClothingCloakFurCoat = Меховая шуба
|
||||
.desc = Тепло под дождем, тепло под снегом, тепло на ветру. Славно.
|
||||
|
||||
ent-CP14ClothingEyesMonocle = монокль
|
||||
.desc = Аристократично и красиво.
|
||||
|
||||
|
||||
6
Resources/Locale/ru-RU/_CP14/connection_messages.ftl
Normal file
6
Resources/Locale/ru-RU/_CP14/connection_messages.ftl
Normal file
@@ -0,0 +1,6 @@
|
||||
cp14-discord-info = Для игры на сервере вам необходимо пройти на наш сервер в дискорд для авторизации вашего аккаунта.
|
||||
cp14-discord-auth-quit-btn = Выход
|
||||
cp14-discord-auth-title = Авторизация
|
||||
cp14-discord-auth-link = https://discord.com/invite/Sud2DMfhCC
|
||||
cp14-discord-auth-browser-btn = Сервер Discord
|
||||
cp14-discord-auth-text = Авторизоваться
|
||||
@@ -7,3 +7,6 @@ cp14-round-end-monolith-50 = Кристалл связи с демипланам
|
||||
cp14-round-end-monolith-discharged = Вы чувствуете, что связь с другими мирами начинает рваться... Сила кристалла связи иссякнет через { $time } { $units }, если не запитать его маной полностью...
|
||||
cp14-round-end-monolith-recharged = Связь с другими мирами восстанавливается. Энергия кристалла связи восстановлена.
|
||||
cp14-round-end = Кристалл связи с демипланами окончательно разрядился. Связь с другими мирами оборвалась. "Интересная" часть этой истории окончена...
|
||||
|
||||
|
||||
cp14-demiplane-echoes = Эхо голосов
|
||||
5
Resources/Locale/ru-RU/_CP14/discord/queue.ftl
Normal file
5
Resources/Locale/ru-RU/_CP14/discord/queue.ftl
Normal file
@@ -0,0 +1,5 @@
|
||||
queue-title = Очередь
|
||||
queue-quit = Отключиться
|
||||
queue-position = Позиция
|
||||
queue-total = Всего
|
||||
queue-priority-join = Приоритетный вход
|
||||
@@ -1 +1,2 @@
|
||||
cp14-knowledge-info-title = Знания персонажа
|
||||
cp14-knowledge-info-title = Знания персонажа
|
||||
cp14-knowledge = Знания
|
||||
@@ -44,6 +44,15 @@ cp14-loadout-guard-spells = Заклинания стражи
|
||||
cp14-loadout-bank-head = Шляпа работника банка
|
||||
cp14-loadout-commandant-head = Шляпа коменданта
|
||||
cp14-loadout-commandant-cloak = Накидка коменданта
|
||||
cp14-loadout-banker-outer = Жилет банкира
|
||||
cp14-loadout-bank-shirt = Рубашка работника банка
|
||||
cp14-loadout-bank-pants = Штаны работника банка
|
||||
cp14-loadout-bank-shoes = Ботинки работника банка
|
||||
|
||||
# Guildmaster
|
||||
|
||||
cp14-loadout-guildmaster-cloak = Накидка гильдмастера
|
||||
cp14-loadout-guildmaster-shirt = Рубашка гильдмастера
|
||||
cp14-loadout-guildmaster-pants = Штаны гильдмастера
|
||||
cp14-loadout-guildmaster-shoes = Ботинки гильдмастера
|
||||
cp14-loadout-guildmaster-spells = Заклинания гильдмастера
|
||||
@@ -14,9 +14,11 @@ cp14-lock-shape-tavern-dorm5 = комната таверны №5
|
||||
|
||||
cp14-lock-shape-alchemist1 = лаборатория алхимика №1
|
||||
cp14-lock-shape-alchemist2 = лаборатория алхимика №2
|
||||
cp14-lock-shape-alchemist3 = лаборатория алхимика №3
|
||||
|
||||
cp14-lock-shape-blacksmith1 = кузня №1
|
||||
cp14-lock-shape-blacksmith2 = кузня №2
|
||||
cp14-lock-shape-blacksmith3 = кузня №3
|
||||
|
||||
cp14-lock-shape-personalhouse1 = дом №1
|
||||
cp14-lock-shape-personalhouse2 = дом №2
|
||||
@@ -33,9 +35,12 @@ cp14-lock-shape-personalhouse12 = дом №12
|
||||
cp14-lock-shape-personalhouse13 = дом №13
|
||||
cp14-lock-shape-personalhouse14 = дом №14
|
||||
cp14-lock-shape-personalhouse15 = дом №15
|
||||
cp14-lock-shape-personalhouse16 = дом №16
|
||||
|
||||
cp14-lock-shaper-guard-entrance = казармы, вход
|
||||
cp14-lock-shaper-guard-staff = казармы
|
||||
cp14-lock-shaper-guard-commander = дом главы стражи
|
||||
cp14-lock-shaper-guard-weapon-storage = хранилище оружия
|
||||
cp14-lock-shape-guildmaster = гильдмастер
|
||||
|
||||
cp14-lock-shape-guildmaster = гильдмастер
|
||||
cp14-lock-shape-demiplane-crystal = кристалл демиплана
|
||||
1
Resources/Locale/ru-RU/_CP14/magicSpells/speech.ftl
Normal file
1
Resources/Locale/ru-RU/_CP14/magicSpells/speech.ftl
Normal file
@@ -0,0 +1 @@
|
||||
cp14-kick-emote = совершает сильный пинок
|
||||
@@ -2,10 +2,9 @@ cp14-magic-type-fire = Огонь
|
||||
cp14-magic-type-water = Вода
|
||||
cp14-magic-type-earth = Земля
|
||||
cp14-magic-type-healing = Исцеление
|
||||
cp14-magic-type-light-darkness = Свет и тьма
|
||||
cp14-magic-type-light = Свет
|
||||
cp14-magic-type-darkness = Тьма
|
||||
cp14-magic-type-meta = Метамагия
|
||||
cp14-magic-type-gate = Пространство
|
||||
cp14-magic-type-movement = Движение
|
||||
cp14-magic-type-necro = Некромантия
|
||||
|
||||
cp14-magic-manacost = Затраты маны
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
cp14-material-examine = Состоит из материалов:
|
||||
|
||||
cp14-material-wooden-planks = деревянные доски
|
||||
cp14-material-dirt-block = земля
|
||||
cp14-material-stone-block = камень
|
||||
|
||||
@@ -4,4 +4,7 @@ cp14-objective-town-send-title = Добыть { $count } { $itemName }
|
||||
cp14-objective-town-send-desc = Ваша задача - добыть и отправить { $count } { $itemName } в город на торговом корабле.
|
||||
|
||||
cp14-objective-bank-earning-title = Накопить в хранилище{ $coins }
|
||||
cp14-objective-bank-earning-desc = В банковском хранилище должно находиться не меньше{ $coins }. Вы можете использовать любые методы заработка, не нарушающие закон.
|
||||
cp14-objective-bank-earning-desc = В банковском хранилище должно находиться не меньше{ $coins }. Вы можете использовать любые методы заработка, не нарушающие закон.
|
||||
|
||||
cp14-objective-no-demiplane-death-title = Не допустить смертей в демипланах
|
||||
cp14-objective-no-demiplane-death-desc = Мне нужно контролировать работу авантюристов, чтобы они не погибали в демипланах. Не больше {$max} смертей!
|
||||
@@ -3,4 +3,5 @@ cp14-stamp-salary = Интендант гвардии
|
||||
cp14-stamp-denied = Отказано
|
||||
cp14-stamp-approved = Утверждено
|
||||
cp14-stamp-bank = Комендант
|
||||
cp14-stamp-guard-commander = Командир стражи
|
||||
cp14-stamp-guard-commander = Командир стражи
|
||||
cp14-stamp-guildmaster = Гильдмастер
|
||||
@@ -0,0 +1,4 @@
|
||||
cp14-tracker-header = Статистика раунда:
|
||||
|
||||
cp14-tracker-demiplane-open = Открыто демипланов
|
||||
cp14-tracker-demiplane-deaths = Умерло игроков в демипланах
|
||||
@@ -1,2 +0,0 @@
|
||||
cp14-world-edge-pre-remove-message = [color=red]ВНИМАНИЕ![/color] Вы покидаете игровую зону! Если вы не вернетесь назад в течении [color=red]{$second}[/color] секунд, вы будете окончательно удалены из раунда!
|
||||
cp14-world-edge-cancel-removing-message = Выход из раунда отменен.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -140,8 +140,8 @@
|
||||
sprite: _CP14/Objects/Materials/copper_bar.rsi
|
||||
state: bar_3
|
||||
price:
|
||||
min: 40
|
||||
max: 60
|
||||
min: 200
|
||||
max: 300
|
||||
services:
|
||||
- !type:CP14BuyItemsService
|
||||
product:
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
sprite: _CP14/Objects/Materials/copper_bar.rsi
|
||||
state: bar_3
|
||||
price:
|
||||
min: 20
|
||||
max: 30
|
||||
min: 100
|
||||
max: 150
|
||||
service: !type:CP14SellStackService
|
||||
stackId: CP14CopperBar
|
||||
count: 10
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user