Gathering resourses redesign (#1594)
* Add Crash to Windlands survival gamemode and map Introduces the CP14CrashToWindlandsRule and its component for a new survival gamemode where a ship crashes into wildlands. Adds the 'nautilus_ship' map, updates English and Russian locale files with new gamemode titles and descriptions, and modifies relevant prototype and map pool files to support the new mode. * fix FTL map * firebombing is real * fix biome dungen all grid overriding * Update PostMapInitTest.cs * Update DungeonJob.CP14Biome.cs * Refactor demiplane generation and crash rules Replaces the old demiplane job system with a new procedural location generation system (CP14LocationGenerationSystem and CP14SpawnProceduralLocationJob). Splits the crash-to-windlands rule into CP14CrashingShipRule (handles explosions) and CP14ExpeditionToWindlandsRule (handles map generation and FTL), with corresponding new components. Updates roundstart game rule prototype and moves/renames several files for clarity and modularity. * Refactor location generation to support optional seed and position Updated the GenerateLocation method to accept an optional seed and position, defaulting to a random seed if none is provided. Adjusted all call sites and the procedural job to support these changes, improving flexibility and consistency in procedural location generation. * procedural integration into game map * Demiplanes deletion * clear demiplane content * remapping procedural + frigid coast deletion * clear demiplane guidebook * dungeons generations * Refactor procedural location configs and add ComossIsland Consolidated and renamed procedural location and dungeonConfig prototypes for demiplane locations, replacing T1-prefixed and legacy IDs with new, consistent names. Updated map YAMLs to reference new location IDs and configs. Added a new ComossIsland location and dungeonConfig. Refactored code to support passing custom dungeon layers and removed unused ExamineProb field from CP14ProceduralLocationPrototype. * Enhance procedural world gen and location configs Improved procedural world generation by adding location generation probability, adjusting level ranges, and refining modifier uniqueness. Updated CP14ProceduralLocationPrototype and CP14ProceduralModifierPrototype, refactored node data generation logic, and made related test and map changes. Added new venicialis_fort station map and updated several procedural location and modifier YAMLs for consistency. * fix * connections room spawners * track finishing global world generation * real connection * Update PostMapInitTest.cs * Update venicialis.yml * Update venicialis.yml * fix raids, decrease city island sizes * Update migration.yml * Update migration.yml * fix shutdowning * Update CP14SpawnProceduralLocationJob.cs
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
|
||||
namespace Content.Client._CP14.DemiplaneTraveling;
|
||||
|
||||
public sealed partial class CP14ClientStationDemiplaneMapSystem : CP14SharedStationDemiplaneMapSystem
|
||||
{
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._CP14.DemiplaneTraveling;
|
||||
|
||||
public sealed class CP14DemiplaneMapBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private CP14DemiplaneMapWindow? _window;
|
||||
|
||||
public CP14DemiplaneMapBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = this.CreateWindow<CP14DemiplaneMapWindow>();
|
||||
|
||||
_window.OnEject += pos => SendMessage(new CP14DemiplaneMapEjectMessage(pos));
|
||||
//_window.OnRevoke += pos => SendMessage(new CP14DemiplaneMapRevokeMessage(pos));
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (_window == null || state is not CP14DemiplaneMapUiState mapState)
|
||||
return;
|
||||
|
||||
_window?.UpdateState(mapState);
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
<demiplaneTraveling:CP14DemiplaneMapWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
xmlns:parallax="clr-namespace:Content.Client.Parallax"
|
||||
xmlns:nodeTree="clr-namespace:Content.Client._CP14.UserInterface.Systems.NodeTree"
|
||||
xmlns:demiplaneTraveling="clr-namespace:Content.Client._CP14.DemiplaneTraveling"
|
||||
Title="{Loc 'cp14-demiplane-map-title'}"
|
||||
MinSize="1000 650"
|
||||
SetSize="1800 950">
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
|
||||
<!-- Selected Location -->
|
||||
<BoxContainer Margin="10 10 10 10" MaxWidth="240" SetWidth="240" Orientation="Vertical"
|
||||
HorizontalExpand="False" VerticalExpand="True">
|
||||
<!-- Location View -->
|
||||
<PanelContainer Name="BackPanel" HorizontalAlignment="Center">
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxTexture Modulate="#1B1B1E" PatchMarginBottom="10" PatchMarginLeft="10"
|
||||
PatchMarginRight="10" PatchMarginTop="10" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True">
|
||||
<TextureRect Stretch="Scale" Name="LocationView" SetSize="64 64" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" MinSize="64 64"
|
||||
HorizontalExpand="True" VerticalExpand="True" Access="Public" />
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<customControls:HSeparator StyleClasses="HighDivider" Margin="0 15 0 10" />
|
||||
<!-- Location Data -->
|
||||
<BoxContainer Name="NodeViewContainer" Orientation="Vertical" VerticalExpand="True">
|
||||
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="False" VerticalExpand="True">
|
||||
<BoxContainer Name="InfoContainer" Orientation="Vertical" HorizontalExpand="True"
|
||||
VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Name="Name" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
|
||||
HorizontalExpand="True" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
<!-- Description -->
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<RichTextLabel Name="Description" HorizontalExpand="True" Access="Public" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<Control MinHeight="5" />
|
||||
<!-- Buttons -->
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Button Name="EjectButton" Text="{Loc 'cp14-demiplane-map-eject'}"
|
||||
ToolTip="{Loc 'cp14-demiplane-map-eject-tooltip'}" StyleClasses="OpenRight"
|
||||
HorizontalExpand="True" MinHeight="35" Access="Public" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Button Name="RevokeButton" Text="{Loc 'cp14-demiplane-map-revoke'}"
|
||||
ToolTip="{Loc 'cp14-demiplane-map-revoke-tooltip'}" StyleClasses="OpenRight"
|
||||
HorizontalExpand="True" MinHeight="35" Access="Public" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<customControls:VSeparator StyleClasses="LowDivider" />
|
||||
|
||||
<!-- Demiplane map Tree -->
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Name="TreeName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
|
||||
HorizontalExpand="True" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
<PanelContainer Margin="10 10 10 10" HorizontalExpand="True" VerticalExpand="True" RectClipContent="True">
|
||||
<parallax:ParallaxControl Name="ParallaxBackground" ScaleX="4" ScaleY="4"
|
||||
ParallaxPrototype="KettleStation" Access="Public" SpeedX="10" SpeedY="5" />
|
||||
<BoxContainer Margin="10 10 10 10" Orientation="Horizontal" HorizontalExpand="True"
|
||||
VerticalExpand="True">
|
||||
<nodeTree:CP14NodeTreeGraphControl Name="GraphControl" HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch" Access="Public" />
|
||||
</BoxContainer>
|
||||
<!-- Admin Description -->
|
||||
<BoxContainer Name="AdminPanel" Visible="False" HorizontalExpand="True" HorizontalAlignment="Right" VerticalAlignment="Top">
|
||||
<RichTextLabel Name="AdminDescription" HorizontalExpand="True" Access="Public" />
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</demiplaneTraveling:CP14DemiplaneMapWindow>
|
||||
@@ -1,266 +0,0 @@
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using Content.Client._CP14.UserInterface.Systems.NodeTree;
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client._CP14.DemiplaneTraveling;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14DemiplaneMapWindow : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly ILogManager _log = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IClientAdminManager _admin = default!;
|
||||
|
||||
private CP14DemiplaneMapUiState? _cachedState;
|
||||
private CP14DemiplaneMapNode? _selectedNode;
|
||||
|
||||
public event Action<Vector2i>? OnEject;
|
||||
public event Action<Vector2i>? OnRevoke;
|
||||
private ISawmill Sawmill { get; init; }
|
||||
|
||||
public CP14DemiplaneMapWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Sawmill = _log.GetSawmill("cp14_demiplane_map_window");
|
||||
|
||||
EjectButton.OnPressed += EjectPressed;
|
||||
RevokeButton.OnPressed += RevokePressed;
|
||||
GraphControl.OnOffsetChanged += offset =>
|
||||
{
|
||||
ParallaxBackground.Offset = -offset * 0.25f + new Vector2(1000, 1000); //hardcoding is bad
|
||||
};
|
||||
GraphControl.OnNodeSelected += SelectNode;
|
||||
}
|
||||
|
||||
private void RevokePressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (_selectedNode == null)
|
||||
return;
|
||||
|
||||
if (_cachedState == null)
|
||||
return;
|
||||
|
||||
foreach (var node in _cachedState.Nodes)
|
||||
{
|
||||
if (node.Value != _selectedNode)
|
||||
continue;
|
||||
|
||||
OnRevoke?.Invoke(node.Key);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void EjectPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (_selectedNode == null)
|
||||
return;
|
||||
|
||||
if (_cachedState == null)
|
||||
return;
|
||||
|
||||
foreach (var node in _cachedState.Nodes)
|
||||
{
|
||||
if (node.Value != _selectedNode)
|
||||
continue;
|
||||
|
||||
OnEject?.Invoke(node.Key);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateState(CP14DemiplaneMapUiState state)
|
||||
{
|
||||
_cachedState = state;
|
||||
|
||||
HashSet<CP14NodeTreeElement> nodeTreeElements = new();
|
||||
foreach (var node in state.Nodes)
|
||||
{
|
||||
if (node.Value.Start)
|
||||
{
|
||||
var startElement = new CP14NodeTreeElement(
|
||||
nodeKey: node.Key.ToString(),
|
||||
gained: true,
|
||||
active: false,
|
||||
node.Value.UiPosition * 100,
|
||||
icon: new SpriteSpecifier.Rsi(new ResPath("_CP14/Interface/NodeTree/demiplane_map.rsi"), "center"));
|
||||
nodeTreeElements.Add(startElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
_prototype.TryIndex(node.Value.LocationConfig, out var location);
|
||||
|
||||
var treeElement = new CP14NodeTreeElement(
|
||||
nodeKey: node.Key.ToString(),
|
||||
gained: node.Value.Completed,
|
||||
active: node.Value.InFrontierZone || node.Value.Completed,
|
||||
node.Value.UiPosition * 100,
|
||||
icon: location?.Icon);
|
||||
nodeTreeElements.Add(treeElement);
|
||||
}
|
||||
}
|
||||
|
||||
var edges = new HashSet<(string, string)>();
|
||||
foreach (var edge in state.Edges)
|
||||
{
|
||||
edges.Add((edge.Item1.ToString(), edge.Item2.ToString()));
|
||||
}
|
||||
GraphControl.UpdateState(
|
||||
new CP14NodeTreeUiState(
|
||||
nodeTreeElements,
|
||||
edges: edges,
|
||||
frameIcon: new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Interface/NodeTree/demiplane_map.rsi"),
|
||||
"frame"),
|
||||
hoveredIcon: new SpriteSpecifier.Rsi(
|
||||
new ResPath("/Textures/_CP14/Interface/NodeTree/demiplane_map.rsi"),
|
||||
"hovered"),
|
||||
selectedIcon: new SpriteSpecifier.Rsi(
|
||||
new ResPath("/Textures/_CP14/Interface/NodeTree/demiplane_map.rsi"),
|
||||
"selected"),
|
||||
learnedIcon: new SpriteSpecifier.Rsi(
|
||||
new ResPath("/Textures/_CP14/Interface/NodeTree/demiplane_map.rsi"),
|
||||
"learned"),
|
||||
activeLineColor: new Color(172, 102, 190),
|
||||
lineColor: new Color(83, 40, 121)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void SelectNode(CP14NodeTreeElement? node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
DeselectNode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cachedState == null)
|
||||
{
|
||||
Sawmill.Error("Tried to select node without a cached state.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.NodeKey.Trim('(', ')').Split(',') is { Length: 2 } parts
|
||||
&& int.TryParse(parts[0], out var x)
|
||||
&& int.TryParse(parts[1], out var y)
|
||||
&& _cachedState.Nodes.TryGetValue(new Vector2i(x, y), out var mapNode))
|
||||
{
|
||||
SelectNode(mapNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Sawmill.Error($"Tried to select node {node.NodeKey} that doesn't exist in the map.");
|
||||
DeselectNode();
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectNode(CP14DemiplaneMapNode? node)
|
||||
{
|
||||
_selectedNode = node;
|
||||
|
||||
var isAdmin = _admin.IsAdmin();
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
DeselectNode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cachedState == null)
|
||||
{
|
||||
Sawmill.Error("Tried to select node without a cached state.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.LocationConfig != null && _prototype.TryIndex(node.LocationConfig, out var location))
|
||||
{
|
||||
if (location.Name is not null)
|
||||
Name.Text = Loc.GetString(location.Name);
|
||||
|
||||
//Generate description
|
||||
HashSet<LocId> modifierNames = new();
|
||||
foreach (var modifier in node.Modifiers)
|
||||
{
|
||||
if (!_prototype.TryIndex(modifier, out var indexedModifier))
|
||||
continue;
|
||||
|
||||
if (indexedModifier.Name is null)
|
||||
continue;
|
||||
|
||||
modifierNames.Add(indexedModifier.Name.Value);
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var name in modifierNames)
|
||||
{
|
||||
sb.Append("- " + Loc.GetString(name) + "\n");
|
||||
}
|
||||
|
||||
sb.Append("\n");
|
||||
if (!node.InFrontierZone && !node.Completed)
|
||||
sb.Append(Loc.GetString("cp14-demiplane-map-status-blocked"));
|
||||
else if (node.InFrontierZone && !node.InUsing)
|
||||
sb.Append(Loc.GetString("cp14-demiplane-map-status-allowed"));
|
||||
else if (node.InUsing)
|
||||
sb.Append(Loc.GetString("cp14-demiplane-map-status-used"));
|
||||
else if (node.Completed)
|
||||
sb.Append(Loc.GetString("cp14-demiplane-map-status-scanned"));
|
||||
|
||||
sb.Append("\n \n");
|
||||
|
||||
if (node.AdditionalLevel > 0 && !node.Completed)
|
||||
{
|
||||
sb.Append(Loc.GetString("cp14-demiplane-map-add-level", ("count", node.AdditionalLevel))+"\n");
|
||||
sb.Append(Loc.GetString("cp14-demiplane-map-add-level-tooltip")+"\n");
|
||||
}
|
||||
|
||||
Description.Text = sb.ToString();
|
||||
LocationView.Texture = location.Icon?.Frame0();
|
||||
}
|
||||
else
|
||||
{
|
||||
Name.Text = string.Empty;
|
||||
Description.Text = string.Empty;
|
||||
LocationView.Texture = null;
|
||||
}
|
||||
|
||||
EjectButton.Disabled = !node.InFrontierZone || node.InUsing;
|
||||
RevokeButton.Disabled = !node.InUsing;
|
||||
|
||||
//Admin part
|
||||
AdminPanel.Visible = isAdmin;
|
||||
|
||||
var adminSb = new StringBuilder();
|
||||
|
||||
adminSb.Append("Modifiers: \n");
|
||||
foreach (var modifier in node.Modifiers)
|
||||
{
|
||||
adminSb.Append("- " + Loc.GetString(modifier.Id) + "\n");
|
||||
}
|
||||
AdminDescription.Text = adminSb.ToString();
|
||||
}
|
||||
|
||||
private void DeselectNode()
|
||||
{
|
||||
Name.Text = string.Empty;
|
||||
Description.Text = string.Empty;
|
||||
LocationView.Texture = null;
|
||||
EjectButton.Disabled = true;
|
||||
RevokeButton.Disabled = true;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
using Content.Client._CP14.DemiplaneTraveling;
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
<customControls:VSeparator StyleClasses="LowDivider" />
|
||||
|
||||
<!-- Demiplane map Tree -->
|
||||
<!-- Trading positions map Tree -->
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Name="TreeName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Content.IntegrationTests.Tests
|
||||
"MeteorArena",
|
||||
"Comoss",
|
||||
"Venicialis",
|
||||
"Frigid_Coast",
|
||||
//"NautilusShip",
|
||||
//CrystallEdge Map replacement end
|
||||
};
|
||||
|
||||
|
||||
@@ -223,6 +223,12 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
|
||||
case CP14RoomsDunGen cp14RoomsDunGen:
|
||||
await PostGen(cp14RoomsDunGen, dungeons, reservedTiles, random);
|
||||
break;
|
||||
case CP14BiomeDunGen cp14BiomesDunGen:
|
||||
await PostGen(cp14BiomesDunGen, dungeons, reservedTiles, random);
|
||||
break;
|
||||
case CP14ReserveGrid cp14ReserveGrid:
|
||||
await PostGen(cp14ReserveGrid, reservedTiles);
|
||||
break;
|
||||
//CP14 zone end
|
||||
case AutoCablingDunGen cabling:
|
||||
await PostGen(cabling, dungeons[^1], reservedTiles, random);
|
||||
|
||||
@@ -137,6 +137,23 @@ public sealed partial class ShuttleSystem
|
||||
var parallax = EnsureComp<ParallaxComponent>(mapUid);
|
||||
parallax.Parallax = ftlMap.Parallax;
|
||||
|
||||
//CP14 FTL map tweaks
|
||||
var mapLight = EnsureComp<MapLightComponent>(mapUid);
|
||||
mapLight.AmbientLightColor = ftlMap.AmbientColor;
|
||||
|
||||
var moles = new float[Atmospherics.AdjustedNumberOfGases];
|
||||
moles[(int) Gas.Oxygen] = 21.824779f;
|
||||
moles[(int) Gas.Nitrogen] = 82.10312f;
|
||||
|
||||
var mixture = new GasMixture(moles, Atmospherics.T20C);
|
||||
|
||||
_atmos.SetMapAtmosphere(mapUid, false, mixture);
|
||||
|
||||
var gravity = EnsureComp<GravityComponent>(mapUid);
|
||||
gravity.Enabled = true;
|
||||
gravity.Inherent = true;
|
||||
//CP14 FTL map tweaks ends
|
||||
|
||||
return mapUid;
|
||||
}
|
||||
|
||||
@@ -465,7 +482,7 @@ public sealed partial class ShuttleSystem
|
||||
var xform = _xformQuery.GetComponent(uid);
|
||||
var body = _physicsQuery.GetComponent(uid);
|
||||
var comp = entity.Comp1;
|
||||
//DoTheDinosaur(xform); //CP14 without stunning
|
||||
DoTheDinosaur(xform);
|
||||
_dockSystem.SetDockBolts(entity, false);
|
||||
|
||||
_physics.SetLinearVelocity(uid, Vector2.Zero, body: body);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Buckle.Systems;
|
||||
using Content.Server.Parallax;
|
||||
@@ -63,6 +64,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||
[Dependency] private readonly ThrusterSystem _thruster = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
[Dependency] private readonly TurfSystem _turf = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
||||
|
||||
private EntityQuery<BuckleComponent> _buckleQuery;
|
||||
private EntityQuery<MapGridComponent> _gridQuery;
|
||||
@@ -104,7 +106,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||
return;
|
||||
|
||||
EnsureComp<ShuttleComponent>(ev.EntityUid);
|
||||
EnsureComp<ImplicitRoofComponent>(ev.EntityUid);
|
||||
//EnsureComp<ImplicitRoofComponent>(ev.EntityUid); //CP14 - grids (ships) without roofs!
|
||||
}
|
||||
|
||||
private void OnShuttleStartup(EntityUid uid, ShuttleComponent component, ComponentStartup args)
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane;
|
||||
|
||||
public sealed partial class CP14DemiplaneSystem
|
||||
{
|
||||
private void InitConnections()
|
||||
{
|
||||
SubscribeLocalEvent<CP14DemiplaneRiftComponent, MapInitEvent>(OnRiftInit);
|
||||
SubscribeLocalEvent<CP14DemiplaneRiftComponent, ComponentShutdown>(OnRiftShutdown);
|
||||
}
|
||||
|
||||
private void OnRiftInit(Entity<CP14DemiplaneRiftComponent> rift, ref MapInitEvent args)
|
||||
{
|
||||
var map = Transform(rift).MapUid;
|
||||
if (_demiplaneQuery.TryComp(map, out var demiplane)) // In demiplane
|
||||
{
|
||||
if (rift.Comp.TryAutoLinkToMap)
|
||||
rift.Comp.Demiplane = map.Value;
|
||||
|
||||
if (rift.Comp.ActiveTeleport)
|
||||
AddDemiplaneRandomEntryPoint((map.Value, demiplane), rift);
|
||||
}
|
||||
else if (rift.Comp.Demiplane is not null) //We out of demiplane
|
||||
{
|
||||
if (_demiplaneQuery.TryComp(rift.Comp.Demiplane, out var riftDemiplane))
|
||||
{
|
||||
if (rift.Comp.ActiveTeleport)
|
||||
AddDemiplaneRandomExitPoint((rift.Comp.Demiplane.Value, riftDemiplane), rift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRiftShutdown(Entity<CP14DemiplaneRiftComponent> rift, ref ComponentShutdown args)
|
||||
{
|
||||
if (rift.Comp.Demiplane is null)
|
||||
return;
|
||||
|
||||
if (!_demiplaneQuery.TryComp(rift.Comp.Demiplane, out var riftDemiplane))
|
||||
return;
|
||||
|
||||
RemoveDemiplaneRandomEntryPoint((rift.Comp.Demiplane.Value, riftDemiplane), rift);
|
||||
RemoveDemiplaneRandomExitPoint((rift.Comp.Demiplane.Value, riftDemiplane), rift);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///Add a position in the real world where you can get out of this demiplane
|
||||
/// </summary>
|
||||
private void AddDemiplaneRandomExitPoint(Entity<CP14DemiplaneComponent> demiplane,
|
||||
Entity<CP14DemiplaneRiftComponent> exitPoint)
|
||||
{
|
||||
demiplane.Comp.ExitPoints.Add(exitPoint);
|
||||
exitPoint.Comp.Demiplane = demiplane;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removing the demiplane exit point, one of which the player can exit to
|
||||
/// </summary>
|
||||
private void RemoveDemiplaneRandomExitPoint(Entity<CP14DemiplaneComponent>? demiplane,
|
||||
EntityUid exitPoint)
|
||||
{
|
||||
if (!TryComp<CP14DemiplaneRiftComponent>(exitPoint, out var riftComp))
|
||||
return;
|
||||
|
||||
if (demiplane is not null && demiplane.Value.Comp.ExitPoints.Contains(exitPoint))
|
||||
{
|
||||
demiplane.Value.Comp.ExitPoints.Remove(exitPoint);
|
||||
riftComp.Demiplane = null;
|
||||
}
|
||||
|
||||
if (riftComp.DeleteAfterDisconnect && exitPoint.Valid)
|
||||
QueueDel(exitPoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a position within the demiplane that can be entered into the demiplane
|
||||
/// </summary>
|
||||
private void AddDemiplaneRandomEntryPoint(Entity<CP14DemiplaneComponent> demiplane,
|
||||
Entity<CP14DemiplaneRiftComponent> entryPoint)
|
||||
{
|
||||
demiplane.Comp.EntryPoints.Add(entryPoint);
|
||||
entryPoint.Comp.Demiplane = demiplane;
|
||||
}
|
||||
|
||||
private void RemoveDemiplaneRandomEntryPoint(Entity<CP14DemiplaneComponent>? demiplane,
|
||||
EntityUid entryPoint)
|
||||
{
|
||||
if (!TryComp<CP14DemiplaneRiftComponent>(entryPoint, out var riftComp))
|
||||
return;
|
||||
|
||||
if (demiplane is not null && demiplane.Value.Comp.EntryPoints.Contains(entryPoint))
|
||||
{
|
||||
demiplane.Value.Comp.EntryPoints.Remove(entryPoint);
|
||||
riftComp.Demiplane = null;
|
||||
}
|
||||
|
||||
if (riftComp.DeleteAfterDisconnect && entryPoint.Valid)
|
||||
QueueDel(entryPoint);
|
||||
}
|
||||
|
||||
public bool TryGetDemiplaneEntryPoint(Entity<CP14DemiplaneComponent> demiplane, out EntityUid? entryPoint)
|
||||
{
|
||||
entryPoint = null;
|
||||
|
||||
if (demiplane.Comp.EntryPoints.Count == 0)
|
||||
return false;
|
||||
|
||||
entryPoint = _random.Pick(demiplane.Comp.EntryPoints);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetDemiplaneExitPoint(Entity<CP14DemiplaneComponent> demiplane,
|
||||
out EntityUid? exitPoint)
|
||||
{
|
||||
exitPoint = null;
|
||||
|
||||
if (demiplane.Comp.ExitPoints.Count == 0)
|
||||
return false;
|
||||
|
||||
exitPoint = _random.Pick(demiplane.Comp.ExitPoints);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
using Content.Server._CP14.WeatherControl;
|
||||
using Content.Server.Weather;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared.Weather;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane;
|
||||
|
||||
public sealed partial class CP14DemiplaneSystem
|
||||
{
|
||||
[Dependency] private readonly WeatherSystem _weather = default!;
|
||||
private void InitDestruction()
|
||||
{
|
||||
SubscribeLocalEvent<CP14DemiplaneTimedDestructionComponent, ComponentAdd>(OnDestructionStarted);
|
||||
}
|
||||
|
||||
public void StartDestructDemiplane(Entity<CP14DemiplaneComponent> demiplane)
|
||||
{
|
||||
if (!TryComp<MapComponent>(demiplane, out var map))
|
||||
return;
|
||||
|
||||
if (HasComp<CP14DemiplaneTimedDestructionComponent>(demiplane))
|
||||
return;
|
||||
|
||||
EnsureComp<CP14DemiplaneTimedDestructionComponent>(demiplane);
|
||||
|
||||
if (HasComp<CP14WeatherControllerComponent>(demiplane))
|
||||
{
|
||||
RemCompDeferred<CP14WeatherControllerComponent>(demiplane);
|
||||
}
|
||||
|
||||
if (!_proto.TryIndex<WeatherPrototype>("CP14DemiplaneDestructionStorm", out var indexedWeather))
|
||||
return;
|
||||
|
||||
_weather.SetWeather(map.MapId, indexedWeather, null);
|
||||
}
|
||||
|
||||
private void OnDestructionStarted(Entity<CP14DemiplaneTimedDestructionComponent> ent, ref ComponentAdd args)
|
||||
{
|
||||
ent.Comp.EndTime = _timing.CurTime + ent.Comp.TimeToDestruction;
|
||||
ent.Comp.SelectedSong = new SoundPathSpecifier(_audio.GetSound(ent.Comp.Sound));
|
||||
}
|
||||
|
||||
private void UpdateDestruction(float frameTime)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneTimedDestructionComponent, CP14DemiplaneComponent>();
|
||||
while (query.MoveNext(out var uid, out var destruction, out var demiplane))
|
||||
{
|
||||
var remaining = destruction.EndTime - _timing.CurTime;
|
||||
|
||||
if (destruction.SelectedSong is null)
|
||||
continue;
|
||||
|
||||
var audioLength = _audio.GetAudioLength(destruction.SelectedSong.Path.ToString());
|
||||
|
||||
if (destruction.Stream is null && remaining < audioLength)
|
||||
{
|
||||
var audio = _audio.PlayPvs(destruction.Sound, uid);
|
||||
destruction.Stream = audio?.Entity;
|
||||
_audio.SetMapAudio(audio);
|
||||
Dirty(uid, destruction);
|
||||
DemiplaneAnnounce(uid, Loc.GetString("cp14-demiplane-countdown", ("duration", audioLength.Minutes)));
|
||||
}
|
||||
|
||||
if (remaining <= TimeSpan.Zero)
|
||||
{
|
||||
_audio.Stop(destruction.Stream);
|
||||
DeleteDemiplane((uid, demiplane));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using Content.Server.Chat.Systems;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane;
|
||||
|
||||
public sealed partial class CP14DemiplaneSystem
|
||||
{
|
||||
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.Normal,
|
||||
true,
|
||||
checkRadioPrefix: false,
|
||||
nameOverride: Loc.GetString("cp14-demiplane-echoes"),
|
||||
ignoreActionBlocker: false);
|
||||
}
|
||||
}
|
||||
@@ -1,419 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Content.Server._CP14.Demiplane.Components;
|
||||
using Content.Server._CP14.Demiplane.Jobs;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.CPUJob.JobQueues;
|
||||
using Robust.Shared.CPUJob.JobQueues.Queues;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
|
||||
namespace Content.Server._CP14.Demiplane;
|
||||
|
||||
public sealed partial class CP14DemiplaneSystem
|
||||
{
|
||||
private readonly JobQueue _expeditionQueue = new();
|
||||
private readonly List<(CP14SpawnRandomDemiplaneJob Job, CancellationTokenSource CancelToken)> _expeditionJobs = new();
|
||||
private const double JobMaxTime = 0.002;
|
||||
|
||||
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
||||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||
|
||||
private void InitGeneration()
|
||||
{
|
||||
SubscribeLocalEvent<CP14DemiplaneRandomGeneratorComponent, MapInitEvent>(GeneratorMapInit);
|
||||
SubscribeLocalEvent<CP14DemiplaneUsingOpenComponent, UseInHandEvent>(GeneratorUsedInHand);
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneDataComponent, GetVerbsEvent<ExamineVerb>>(OnVerbExamine);
|
||||
}
|
||||
|
||||
private void GeneratorMapInit(Entity<CP14DemiplaneRandomGeneratorComponent> generator, ref MapInitEvent args)
|
||||
{
|
||||
if (!TryComp<CP14DemiplaneDataComponent>(generator, out var data))
|
||||
return;
|
||||
|
||||
CP14DemiplaneLocationPrototype? selectedConfig = null;
|
||||
//Location generation
|
||||
if (data.Location is null || generator.Comp.OverrideLocation)
|
||||
{
|
||||
selectedConfig = GenerateDemiplaneLocation(generator.Comp.Level);
|
||||
data.Location = selectedConfig;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_proto.TryIndex(data.Location, out selectedConfig))
|
||||
return;
|
||||
}
|
||||
|
||||
//Modifier generation
|
||||
var newModifiers = GenerateDemiplaneModifiers(
|
||||
generator.Comp.Level,
|
||||
selectedConfig,
|
||||
generator.Comp.Limits);
|
||||
|
||||
foreach (var mod in newModifiers)
|
||||
{
|
||||
data.SelectedModifiers.Add(mod);
|
||||
}
|
||||
}
|
||||
|
||||
private void GeneratorUsedInHand(Entity<CP14DemiplaneUsingOpenComponent> ent, ref UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14DemiplaneDataComponent>(ent, out var generator))
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
UseGenerator((ent, generator), args.User);
|
||||
|
||||
QueueDel(ent);
|
||||
}
|
||||
|
||||
//Ed: I hate this function.
|
||||
private void UseGenerator(Entity<CP14DemiplaneDataComponent> generator, EntityUid? user = null)
|
||||
{
|
||||
//block the opening of demiplanes after the end of a round
|
||||
if (_gameTicker.RunLevel != GameRunLevel.InRound)
|
||||
{
|
||||
if (user is not null)
|
||||
_popup.PopupEntity(Loc.GetString("cp14-demiplan-cannot-open-end-round"), generator, user.Value);
|
||||
return;
|
||||
}
|
||||
//We cant open demiplane in another demiplane or if parent is not Map
|
||||
if (_demiplaneQuery.HasComp(Transform(generator).MapUid))
|
||||
{
|
||||
if (user is not null)
|
||||
_popup.PopupEntity(Loc.GetString("cp14-demiplan-cannot-open", ("name", MetaData(generator).EntityName)), generator, user.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
if (demiplane is not null && TryComp<CP14DemiplaneMapNodeBlockerComponent>(generator, out var blocker))
|
||||
{
|
||||
EnsureComp<CP14DemiplaneMapNodeBlockerComponent>(demiplane.Value, out var blockerMap);
|
||||
blockerMap.Position = blocker.Position;
|
||||
blockerMap.Station = blocker.Station;
|
||||
blockerMap.IncreaseNodeDifficulty = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
demiplane = ev.Demiplane;
|
||||
}
|
||||
|
||||
if (demiplane is null)
|
||||
return;
|
||||
|
||||
//Admin log needed
|
||||
EnsureComp<CP14DemiplaneDestroyWithoutStabilizationComponent>(demiplane.Value);
|
||||
|
||||
//Rifts spawning
|
||||
foreach (var rift in generator.Comp.AutoRifts)
|
||||
{
|
||||
var spawnedRift = EntityManager.Spawn(rift);
|
||||
_transform.SetCoordinates(spawnedRift, Transform(generator).Coordinates);
|
||||
_transform.AttachToGridOrMap(spawnedRift);
|
||||
var connection = EnsureComp<CP14DemiplaneRiftComponent>(spawnedRift);
|
||||
AddDemiplaneRandomExitPoint(demiplane.Value, (spawnedRift, connection));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVerbExamine(Entity<CP14DemiplaneDataComponent> ent, ref GetVerbsEvent<ExamineVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess)
|
||||
return;
|
||||
|
||||
var markup = GetDemiplanExamine(ent.Comp);
|
||||
_examine.AddDetailedExamineVerb(
|
||||
args,
|
||||
ent.Comp,
|
||||
markup,
|
||||
Loc.GetString("cp14-demiplan-examine"),
|
||||
"/Textures/Interface/VerbIcons/dot.svg.192dpi.png"); //TODO custom icon
|
||||
}
|
||||
|
||||
private FormattedMessage GetDemiplanExamine(CP14DemiplaneDataComponent comp)
|
||||
{
|
||||
var msg = new FormattedMessage();
|
||||
|
||||
if (!_proto.TryIndex(comp.Location, out var indexedLocation))
|
||||
return msg;
|
||||
|
||||
msg.AddMarkupOrThrow(
|
||||
indexedLocation.Name is not null/* && _random.Prob(indexedLocation.ExamineProb)*/
|
||||
? Loc.GetString("cp14-demiplane-examine-title", ("location", Loc.GetString(indexedLocation.Name)))
|
||||
: Loc.GetString("cp14-demiplane-examine-title-unknown"));
|
||||
|
||||
List<LocId> modifierNames = new();
|
||||
foreach (var modifier in comp.SelectedModifiers)
|
||||
{
|
||||
if (!_proto.TryIndex(modifier, out var indexedModifier))
|
||||
continue;
|
||||
|
||||
//if (!_random.Prob(indexedModifier.ExamineProb)) //temp disable
|
||||
// continue;
|
||||
|
||||
if (indexedModifier.Name is null)
|
||||
continue;
|
||||
|
||||
if (modifierNames.Contains(indexedModifier.Name.Value))
|
||||
continue;
|
||||
|
||||
modifierNames.Add(indexedModifier.Name.Value);
|
||||
}
|
||||
|
||||
if (modifierNames.Count > 0)
|
||||
{
|
||||
msg.AddMarkupOrThrow("\n" + Loc.GetString("cp14-demiplane-examine-modifiers"));
|
||||
foreach (var name in modifierNames)
|
||||
{
|
||||
msg.AddMarkupOrThrow("\n- " + Loc.GetString(name));
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void UpdateGeneration(float frameTime)
|
||||
{
|
||||
_expeditionQueue.Process();
|
||||
|
||||
foreach (var (job, cancelToken) in _expeditionJobs.ToArray())
|
||||
{
|
||||
switch (job.Status)
|
||||
{
|
||||
case JobStatus.Finished:
|
||||
_expeditionJobs.Remove((job, cancelToken));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>? demiplane, out MapId mapId)
|
||||
{
|
||||
var mapUid = _mapSystem.CreateMap(out mapId, runMapInit: false);
|
||||
var demiComp = EntityManager.EnsureComponent<CP14DemiplaneComponent>(mapUid);
|
||||
demiplane = (mapUid, demiComp);
|
||||
|
||||
var cancelToken = new CancellationTokenSource();
|
||||
var job = new CP14SpawnRandomDemiplaneJob(
|
||||
JobMaxTime,
|
||||
EntityManager,
|
||||
_logManager,
|
||||
_proto,
|
||||
_dungeon,
|
||||
_metaData,
|
||||
_mapSystem,
|
||||
mapUid,
|
||||
mapId,
|
||||
location,
|
||||
modifiers,
|
||||
_random.Next(-10000, 10000),
|
||||
cancelToken.Token);
|
||||
|
||||
_expeditionJobs.Add((job, cancelToken));
|
||||
_expeditionQueue.EnqueueJob(job);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a suitable demiplane location for the specified difficulty level.
|
||||
/// </summary>
|
||||
public CP14DemiplaneLocationPrototype GenerateDemiplaneLocation(int level)
|
||||
{
|
||||
CP14DemiplaneLocationPrototype? selectedConfig = null;
|
||||
|
||||
HashSet<CP14DemiplaneLocationPrototype> suitableConfigs = new();
|
||||
foreach (var locationConfig in _proto.EnumeratePrototypes<CP14DemiplaneLocationPrototype>())
|
||||
{
|
||||
suitableConfigs.Add(locationConfig);
|
||||
}
|
||||
|
||||
while (suitableConfigs.Count > 0)
|
||||
{
|
||||
var randomConfig = _random.Pick(suitableConfigs);
|
||||
|
||||
//LevelRange filter
|
||||
if (level < randomConfig.Levels.Min || level > randomConfig.Levels.Max)
|
||||
{
|
||||
suitableConfigs.Remove(randomConfig);
|
||||
continue;
|
||||
}
|
||||
|
||||
selectedConfig = randomConfig;
|
||||
break;
|
||||
}
|
||||
|
||||
if (selectedConfig is null)
|
||||
throw new Exception($"No suitable demiplane location config found for level {level}!");
|
||||
|
||||
return selectedConfig;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a set of modifiers under the specified difficulty level that are appropriate for the specified demiplane location
|
||||
/// </summary>
|
||||
public List<CP14DemiplaneModifierPrototype> GenerateDemiplaneModifiers(
|
||||
int level,
|
||||
CP14DemiplaneLocationPrototype location,
|
||||
Dictionary<ProtoId<CP14DemiplaneModifierCategoryPrototype>,float> modifierLimits)
|
||||
{
|
||||
List<CP14DemiplaneModifierPrototype> selectedModifiers = new();
|
||||
|
||||
//Modifier generation
|
||||
Dictionary<CP14DemiplaneModifierPrototype, float> suitableModifiersWeights = new();
|
||||
foreach (var modifier in _proto.EnumeratePrototypes<CP14DemiplaneModifierPrototype>())
|
||||
{
|
||||
var passed = true;
|
||||
|
||||
//Random prob filter
|
||||
if (passed)
|
||||
{
|
||||
if (!_random.Prob(modifier.GenerationProb))
|
||||
{
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Levels filter
|
||||
if (passed)
|
||||
{
|
||||
if (level < modifier.Levels.Min || level > modifier.Levels.Max)
|
||||
{
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Tag blacklist filter
|
||||
foreach (var configTag in location.Tags)
|
||||
{
|
||||
if (modifier.BlacklistTags.Count != 0 && modifier.BlacklistTags.Contains(configTag))
|
||||
{
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Tag required filter
|
||||
if (passed)
|
||||
{
|
||||
foreach (var reqTag in modifier.RequiredTags)
|
||||
{
|
||||
if (!location.Tags.Contains(reqTag))
|
||||
{
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (passed)
|
||||
suitableModifiersWeights.Add(modifier, modifier.GenerationWeight);
|
||||
}
|
||||
|
||||
|
||||
//Limits calculation
|
||||
Dictionary<ProtoId<CP14DemiplaneModifierCategoryPrototype>, float> limits = new();
|
||||
foreach (var limit in modifierLimits)
|
||||
{
|
||||
limits.Add(limit.Key, limit.Value);
|
||||
}
|
||||
|
||||
|
||||
while (suitableModifiersWeights.Count > 0)
|
||||
{
|
||||
var selectedModifier = ModifierPick(suitableModifiersWeights, _random);
|
||||
|
||||
//Fill demiplane under limits
|
||||
var passed = true;
|
||||
foreach (var category in selectedModifier.Categories)
|
||||
{
|
||||
if (!limits.ContainsKey(category.Key))
|
||||
{
|
||||
suitableModifiersWeights.Remove(selectedModifier);
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (limits[category.Key] - category.Value < 0)
|
||||
{
|
||||
suitableModifiersWeights.Remove(selectedModifier);
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!passed)
|
||||
continue;
|
||||
|
||||
selectedModifiers.Add(selectedModifier);
|
||||
|
||||
foreach (var category in selectedModifier.Categories)
|
||||
{
|
||||
limits[category.Key] -= category.Value;
|
||||
}
|
||||
|
||||
if (selectedModifier.Unique)
|
||||
suitableModifiersWeights.Remove(selectedModifier);
|
||||
}
|
||||
|
||||
return selectedModifiers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimization moment: avoid re-indexing for weight selection
|
||||
/// </summary>
|
||||
private static CP14DemiplaneModifierPrototype ModifierPick(Dictionary<CP14DemiplaneModifierPrototype, float> weights, IRobustRandom random)
|
||||
{
|
||||
var picks = weights;
|
||||
var sum = picks.Values.Sum();
|
||||
var accumulated = 0f;
|
||||
|
||||
var rand = random.NextFloat() * sum;
|
||||
|
||||
foreach (var (key, weight) in picks)
|
||||
{
|
||||
accumulated += weight;
|
||||
|
||||
if (accumulated >= rand)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
// Shouldn't happen
|
||||
throw new InvalidOperationException($"Invalid weighted pick in CP14DemiplanSystem.Generation!");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CP14DemiplaneGenerationCatchAttemptEvent : EntityEventArgs
|
||||
{
|
||||
public bool Handled = false;
|
||||
public Entity<CP14DemiplaneComponent>? Demiplane;
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.SSDIndicator;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane;
|
||||
|
||||
public sealed partial class CP14DemiplaneSystem
|
||||
{
|
||||
private readonly TimeSpan _checkFrequency = TimeSpan.FromSeconds(15f);
|
||||
private TimeSpan _nextCheckTime = TimeSpan.Zero;
|
||||
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
|
||||
private void InitStabilization()
|
||||
{
|
||||
_nextCheckTime = _timing.CurTime + _checkFrequency;
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneDestroyWithoutStabilizationComponent, MapInitEvent>(OnStabilizationMapInit);
|
||||
}
|
||||
|
||||
private void OnStabilizationMapInit(Entity<CP14DemiplaneDestroyWithoutStabilizationComponent> ent,
|
||||
ref MapInitEvent args)
|
||||
{
|
||||
ent.Comp.EndProtectionTime = _timing.CurTime + ent.Comp.ProtectedSpawnTime;
|
||||
}
|
||||
|
||||
private void UpdateStabilization(float frameTime)
|
||||
{
|
||||
if (_timing.CurTime < _nextCheckTime)
|
||||
return;
|
||||
|
||||
_nextCheckTime = _timing.CurTime + _checkFrequency;
|
||||
|
||||
HashSet<EntityUid> stabilizedMaps = new();
|
||||
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneStabilizerComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var uid, out var stabilizer, out var transform))
|
||||
{
|
||||
var map = transform.MapUid;
|
||||
|
||||
if (map is null)
|
||||
continue;
|
||||
|
||||
if (!stabilizer.Enabled)
|
||||
continue;
|
||||
|
||||
if (stabilizer.RequireAlive && !(_mobState.IsAlive(uid) || _mobState.IsCritical(uid)))
|
||||
continue;
|
||||
|
||||
if (stabilizedMaps.Contains(map.Value))
|
||||
continue;
|
||||
if (TryComp(uid, out SSDIndicatorComponent? ssd) && ssd.IsSSD)
|
||||
continue;
|
||||
stabilizedMaps.Add(map.Value);
|
||||
}
|
||||
|
||||
var query2 = EntityQueryEnumerator<CP14DemiplaneComponent, CP14DemiplaneDestroyWithoutStabilizationComponent>();
|
||||
while (query2.MoveNext(out var uid, out var demiplane, out var stabilization))
|
||||
{
|
||||
if (_timing.CurTime < stabilization.EndProtectionTime)
|
||||
continue;
|
||||
|
||||
if (!stabilizedMaps.Contains(uid))
|
||||
DeleteDemiplane((uid, demiplane));
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteAllDemiplanes(bool safe = true)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var demiplane))
|
||||
{
|
||||
DeleteDemiplane((uid, demiplane), safe);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteDemiplane(Entity<CP14DemiplaneComponent> demiplane, bool safe = false)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneForceExtractComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var extract, out var xform))
|
||||
{
|
||||
if (!extract.Enabled)
|
||||
continue;
|
||||
|
||||
if (!TryTeleportOutDemiplane(demiplane, uid))
|
||||
continue;
|
||||
|
||||
if (!safe)
|
||||
_damageable.TryChangeDamage(uid, extract.ExtractDamage);
|
||||
}
|
||||
|
||||
QueueDel(demiplane);
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
using Content.Server._CP14.Demiplane.Components;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Flash;
|
||||
using Content.Server.Procedural;
|
||||
using Content.Shared._CP14.Demiplane;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane;
|
||||
|
||||
public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly DungeonSystem _dungeon = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly FlashSystem _flash = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
|
||||
private EntityQuery<CP14DemiplaneComponent> _demiplaneQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_demiplaneQuery = GetEntityQuery<CP14DemiplaneComponent>();
|
||||
|
||||
InitGeneration();
|
||||
InitConnections();
|
||||
InitStabilization();
|
||||
InitEchoes();
|
||||
InitDestruction();
|
||||
|
||||
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)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
UpdateGeneration(frameTime);
|
||||
UpdateStabilization(frameTime);
|
||||
UpdateDestruction(frameTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Teleports the entity inside the demiplane, to one of the random entry points.
|
||||
/// </summary>
|
||||
/// <param name="demiplane">The demiplane the entity will be teleported to</param>
|
||||
/// <param name="entity">The entity to be teleported</param>
|
||||
/// <returns></returns>
|
||||
public override bool TryTeleportIntoDemiplane(Entity<CP14DemiplaneComponent> demiplane, EntityUid? entity)
|
||||
{
|
||||
if (entity is null)
|
||||
return false;
|
||||
|
||||
if (!TryGetDemiplaneEntryPoint(demiplane, out var entryPoint) || entryPoint is null)
|
||||
{
|
||||
Log.Error($"{entity} cant get in demiplane {demiplane}: no active entry points!");
|
||||
return false;
|
||||
}
|
||||
|
||||
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, TimeSpan.FromSeconds(3f), 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 override bool TryTeleportOutDemiplane(Entity<CP14DemiplaneComponent> demiplane, EntityUid? entity)
|
||||
{
|
||||
if (entity is null)
|
||||
return false;
|
||||
|
||||
if (Transform(entity.Value).MapUid != demiplane.Owner)
|
||||
return false;
|
||||
|
||||
if (!TryGetDemiplaneExitPoint(demiplane, out var connection) || connection is null)
|
||||
{
|
||||
Log.Error($"{entity} cant get out of demiplane {demiplane}: no active connections!");
|
||||
return false;
|
||||
}
|
||||
|
||||
TeleportEntityToCoordinate(entity.Value, Transform(connection.Value).Coordinates, demiplane.Comp.DepartureSound);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnDemiplanShutdown(Entity<CP14DemiplaneComponent> demiplane, ref ComponentShutdown args)
|
||||
{
|
||||
//We stop asynchronous generation of a demiplane early if for some reason this demiplane is deleted before generation is complete
|
||||
foreach (var (job, cancelToken) in _expeditionJobs.ToArray())
|
||||
{
|
||||
if (job.DemiplaneMapUid == demiplane.Owner)
|
||||
{
|
||||
cancelToken.Cancel();
|
||||
_expeditionJobs.Remove((job, cancelToken));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var exit in demiplane.Comp.ExitPoints)
|
||||
{
|
||||
RemoveDemiplaneRandomExitPoint(demiplane, exit);
|
||||
}
|
||||
|
||||
foreach (var entry in demiplane.Comp.EntryPoints)
|
||||
{
|
||||
RemoveDemiplaneRandomEntryPoint(demiplane, entry);
|
||||
}
|
||||
}
|
||||
|
||||
private void DemiplaneAnnounce(EntityUid mapUid, string text)
|
||||
{
|
||||
var mapId = Comp<MapComponent>(mapUid).MapId;
|
||||
|
||||
_chatManager.ChatMessageToManyFiltered(
|
||||
Filter.BroadcastMap(mapId),
|
||||
ChatChannel.Radio,
|
||||
text,
|
||||
text,
|
||||
_mapManager.GetMapEntityId(mapId),
|
||||
false,
|
||||
true,
|
||||
null);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Content.Server._CP14.DemiplaneTraveling;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Demiplane Core - stores a position on the demiplane map to mark it as “passed” when all conditions are met
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14DemiplaneSystem), typeof(CP14StationDemiplaneMapSystem))]
|
||||
public sealed partial class CP14DemiplaneCoreComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? Demiplane;
|
||||
|
||||
[DataField]
|
||||
public EntityUid? Station;
|
||||
|
||||
[DataField]
|
||||
public Vector2i Position;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Content.Server._CP14.DemiplaneTraveling;
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Stores all the information needed to generate a new demiplane
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14DemiplaneSystem), typeof(CP14StationDemiplaneMapSystem))]
|
||||
public sealed partial class CP14DemiplaneDataComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public ProtoId<CP14DemiplaneLocationPrototype>? Location;
|
||||
|
||||
[DataField]
|
||||
public List<ProtoId<CP14DemiplaneModifierPrototype>> SelectedModifiers = new();
|
||||
|
||||
[DataField]
|
||||
public List<EntProtoId> AutoRifts = new() { "CP14DemiplaneTimedRadiusPassway", "CP14DemiplanRiftCore" };
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Content.Server._CP14.DemiplaneTraveling;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// The existence of an entity with this component will block the discovery of a particular coordinate in the demiplane navigation map.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14StationDemiplaneMapSystem), typeof(CP14DemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneMapNodeBlockerComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? Station = null;
|
||||
|
||||
[DataField]
|
||||
public Vector2i Position = new (0,0);
|
||||
|
||||
[DataField]
|
||||
public int IncreaseNodeDifficulty = 0;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Fills the DemiplaneDataComponent with random modifiers and location
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14DemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneRandomGeneratorComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public bool OverrideLocation = false;
|
||||
|
||||
/// <summary>
|
||||
/// Demiplane Difficulty Level. By design, the plan so far is for a framework of 1 to 10, but technically could support more.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public int Level = 1;
|
||||
|
||||
[DataField(required: true)]
|
||||
public Dictionary<ProtoId<CP14DemiplaneModifierCategoryPrototype>, float> Limits = new();
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace Content.Server._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Open demiplane from using in hand
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14DemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneUsingOpenComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Procedural;
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Procedural;
|
||||
using Robust.Shared.CPUJob.JobQueues;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane.Jobs;
|
||||
|
||||
public sealed class CP14SpawnRandomDemiplaneJob : Job<bool>
|
||||
{
|
||||
private readonly IEntityManager _entManager;
|
||||
//private readonly IGameTiming _timing;
|
||||
private readonly IPrototypeManager _prototypeManager;
|
||||
//private readonly AnchorableSystem _anchorable;
|
||||
private readonly DungeonSystem _dungeon;
|
||||
private readonly MetaDataSystem _metaData;
|
||||
//private readonly SharedTransformSystem _xforms;
|
||||
private readonly SharedMapSystem _map;
|
||||
|
||||
private readonly ProtoId<CP14DemiplaneLocationPrototype> _config;
|
||||
private readonly List<ProtoId<CP14DemiplaneModifierPrototype>> _modifiers;
|
||||
private readonly int _seed;
|
||||
|
||||
public readonly EntityUid DemiplaneMapUid;
|
||||
private readonly MapId _demiplaneMapId;
|
||||
|
||||
private readonly ISawmill _sawmill;
|
||||
|
||||
public CP14SpawnRandomDemiplaneJob(
|
||||
double maxTime,
|
||||
IEntityManager entManager,
|
||||
ILogManager logManager,
|
||||
IPrototypeManager protoManager,
|
||||
DungeonSystem dungeon,
|
||||
MetaDataSystem metaData,
|
||||
SharedMapSystem map,
|
||||
EntityUid demiplaneMapUid,
|
||||
MapId demiplaneMapId,
|
||||
ProtoId<CP14DemiplaneLocationPrototype> config,
|
||||
List<ProtoId<CP14DemiplaneModifierPrototype>> modifiers,
|
||||
int seed,
|
||||
CancellationToken cancellation = default) : base(maxTime, cancellation)
|
||||
{
|
||||
_entManager = entManager;
|
||||
_prototypeManager = protoManager;
|
||||
_dungeon = dungeon;
|
||||
_metaData = metaData;
|
||||
_map = map;
|
||||
DemiplaneMapUid = demiplaneMapUid;
|
||||
_demiplaneMapId = demiplaneMapId;
|
||||
_config = config;
|
||||
_modifiers = modifiers;
|
||||
_seed = seed;
|
||||
|
||||
_sawmill = logManager.GetSawmill("cp14_demiplane_job");
|
||||
}
|
||||
|
||||
protected override async Task<bool> Process()
|
||||
{
|
||||
_sawmill.Debug($"Spawning demiplane `{_config.Id}` with seed {_seed}");
|
||||
var gridComp = _entManager.EnsureComponent<MapGridComponent>(DemiplaneMapUid);
|
||||
|
||||
MetaDataComponent? metadata = null;
|
||||
DungeonConfigPrototype dungeonConfig = new();
|
||||
|
||||
_metaData.SetEntityName(DemiplaneMapUid, $"Demiplane {_config.Id} - {_seed}");
|
||||
|
||||
//Setup demiplane config
|
||||
var expeditionConfig = _prototypeManager.Index(_config);
|
||||
var indexedLocation = _prototypeManager.Index(expeditionConfig.LocationConfig);
|
||||
|
||||
dungeonConfig.Layers.AddRange(indexedLocation.Layers);
|
||||
dungeonConfig.ReserveTiles = indexedLocation.ReserveTiles;
|
||||
|
||||
//Add map components
|
||||
_entManager.AddComponents(DemiplaneMapUid, expeditionConfig.Components);
|
||||
|
||||
//Apply modifiers
|
||||
foreach (var modifier in _modifiers)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex(modifier, out var indexedModifier))
|
||||
continue;
|
||||
|
||||
if (indexedModifier.Layers != null)
|
||||
dungeonConfig.Layers.AddRange(indexedModifier.Layers);
|
||||
if (indexedModifier.Components != null)
|
||||
_entManager.AddComponents(DemiplaneMapUid, indexedModifier.Components);
|
||||
|
||||
_sawmill.Debug($"Added modifier: {_seed} - {modifier.Id}");
|
||||
}
|
||||
|
||||
//Setup gravity
|
||||
var gravity = _entManager.EnsureComponent<GravityComponent>(DemiplaneMapUid);
|
||||
gravity.Enabled = true;
|
||||
_entManager.Dirty(DemiplaneMapUid, gravity, metadata);
|
||||
|
||||
// Setup default atmos
|
||||
var moles = new float[Atmospherics.AdjustedNumberOfGases];
|
||||
moles[(int) Gas.Oxygen] = 21.824779f;
|
||||
moles[(int) Gas.Nitrogen] = 82.10312f;
|
||||
var mixture = new GasMixture(moles, Atmospherics.T20C);
|
||||
_entManager.System<AtmosphereSystem>().SetMapAtmosphere(DemiplaneMapUid, false, mixture);
|
||||
|
||||
_map.InitializeMap(_demiplaneMapId);
|
||||
_map.SetPaused(_demiplaneMapId, false);
|
||||
|
||||
//Spawn modified config
|
||||
_dungeon.GenerateDungeon(dungeonConfig,
|
||||
DemiplaneMapUid,
|
||||
gridComp,
|
||||
Vector2i.Zero,
|
||||
_seed); //TODO: Transform to Async
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
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,229 +0,0 @@
|
||||
using Content.Server._CP14.Demiplane;
|
||||
using Content.Server._CP14.RoundEnd;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared._CP14.Demiplane;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
using Content.Shared._CP14.Religion.Components;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._CP14.DemiplaneTraveling;
|
||||
|
||||
public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly CP14DemiplaneSystem _demiplan = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly InteractionSystem _interaction = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneRadiusTimedPasswayComponent, MapInitEvent>(RadiusMapInit);
|
||||
SubscribeLocalEvent<CP14MonolithTimedPasswayComponent, MapInitEvent>(MonolithMapInit);
|
||||
SubscribeLocalEvent<CP14DemiplaneRiftOpenedComponent, CP14DemiplanPasswayUseDoAfter>(OnOpenRiftInteractDoAfter);
|
||||
}
|
||||
|
||||
// !!!SHITCODE WARNING!!!
|
||||
// This whole module is saturated with shitcode, 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 (HasComp<CP14ReligionEntityComponent>(ent)) //TODO: make some generic way to whitelist entities from teleporting
|
||||
continue;
|
||||
|
||||
if (!_mind.TryGetMind(ent, out var mindId, out var mind))
|
||||
continue;
|
||||
|
||||
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))
|
||||
{
|
||||
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 (HasComp<CP14ReligionEntityComponent>(ent)) //TODO: make some generic way to whitelist entities from teleporting
|
||||
continue;
|
||||
|
||||
if (!_mind.TryGetMind(ent, out var mindId, out var mind))
|
||||
continue;
|
||||
|
||||
if (!_interaction.InRangeUnobstructed(ent, uid))
|
||||
continue;
|
||||
|
||||
// Talking swords are not party members, and should not be teleported separately from their wielders
|
||||
if (HasComp<ItemComponent>(ent))
|
||||
continue;
|
||||
|
||||
teleportedEnts.Add(ent);
|
||||
}
|
||||
|
||||
while (teleportedEnts.Count > passWay.MaxEntities)
|
||||
{
|
||||
teleportedEnts.Remove(_random.Pick(teleportedEnts));
|
||||
}
|
||||
|
||||
//Aaaand teleport it
|
||||
var map = Transform(uid).MapUid;
|
||||
if (TryComp<CP14DemiplaneComponent>(map, out var demiplan))
|
||||
{
|
||||
if (!_demiplan.TryGetDemiplaneExitPoint((map.Value, demiplan), out _))
|
||||
break;
|
||||
|
||||
foreach (var ent in teleportedEnts) //We in demiplan, tp OUT
|
||||
{
|
||||
if (TryComp<PullerComponent>(ent, out var puller))
|
||||
_demiplan.TryTeleportOutDemiplane((map.Value, demiplan), puller.Pulling);
|
||||
|
||||
_demiplan.TryTeleportOutDemiplane((map.Value, demiplan), ent);
|
||||
_audio.PlayPvs(passWay.ArrivalSound, ent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rift.Demiplane is not null &&
|
||||
TryComp<CP14DemiplaneComponent>(rift.Demiplane.Value, out var riftDemiplane))
|
||||
{
|
||||
if (!_demiplan.TryGetDemiplaneEntryPoint((rift.Demiplane.Value, riftDemiplane), out _))
|
||||
break;
|
||||
|
||||
foreach (var ent in teleportedEnts) //We out demiplan, tp IN
|
||||
{
|
||||
if (TryComp<PullerComponent>(ent, out var puller))
|
||||
_demiplan.TryTeleportIntoDemiplane((rift.Demiplane.Value, riftDemiplane), puller.Pulling);
|
||||
|
||||
_demiplan.TryTeleportIntoDemiplane((rift.Demiplane.Value, riftDemiplane), ent);
|
||||
_audio.PlayPvs(passWay.ArrivalSound, ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_audio.PlayPvs(passWay.DepartureSound, Transform(uid).Coordinates);
|
||||
QueueDel(uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void RadiusMapInit(Entity<CP14DemiplaneRadiusTimedPasswayComponent> radiusPassWay, ref MapInitEvent args)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
|
||||
var used = false;
|
||||
var map = Transform(passWay).MapUid;
|
||||
if (TryComp<CP14DemiplaneComponent>(map, out var demiplan))
|
||||
{
|
||||
if (TryComp<PullerComponent>(args.User, out var puller))
|
||||
_demiplan.TryTeleportOutDemiplane((map.Value, demiplan), puller.Pulling);
|
||||
|
||||
used = _demiplan.TryTeleportOutDemiplane((map.Value, demiplan), args.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TryComp<CP14DemiplaneRiftComponent>(passWay, out var exitPoint) && exitPoint.Demiplane is not null &&
|
||||
TryComp<CP14DemiplaneComponent>(exitPoint.Demiplane.Value, out var exitDemiplane))
|
||||
{
|
||||
if (TryComp<PullerComponent>(args.User, out var puller))
|
||||
_demiplan.TryTeleportIntoDemiplane((exitPoint.Demiplane.Value, exitDemiplane), puller.Pulling);
|
||||
|
||||
used = _demiplan.TryTeleportIntoDemiplane((exitPoint.Demiplane.Value, exitDemiplane), args.User);
|
||||
}
|
||||
}
|
||||
|
||||
if (used)
|
||||
{
|
||||
_audio.PlayPvs(passWay.Comp.DepartureSound, Transform(passWay).Coordinates);
|
||||
_audio.PlayPvs(passWay.Comp.ArrivalSound, args.User);
|
||||
if (passWay.Comp.MaxUse > 0)
|
||||
{
|
||||
passWay.Comp.MaxUse--;
|
||||
if (passWay.Comp.MaxUse == 0)
|
||||
QueueDel(passWay);
|
||||
}
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
@@ -1,356 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server._CP14.Demiplane;
|
||||
using Content.Server._CP14.Demiplane.Components;
|
||||
using Content.Server.Destructible;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Destructible;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Pulling.Events;
|
||||
using Content.Shared.UserInterface;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.DemiplaneTraveling;
|
||||
|
||||
public sealed partial class CP14StationDemiplaneMapSystem : CP14SharedStationDemiplaneMapSystem
|
||||
{
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly CP14DemiplaneSystem _demiplane = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly DestructibleSystem _destructible = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14StationDemiplaneMapComponent, MapInitEvent>(OnMapInit);
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneNavigationMapComponent, CP14DemiplaneMapEjectMessage>(DemiplaneEjectAttempt);
|
||||
SubscribeLocalEvent<CP14DemiplaneNavigationMapComponent, CP14DemiplaneMapRevokeMessage>(DemiplaneRevokeAttempt);
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneNavigationMapComponent, BeforeActivatableUIOpenEvent>(OnBeforeActivatableUiOpen);
|
||||
SubscribeLocalEvent<CP14DemiplaneMapNodeBlockerComponent, ComponentShutdown>(OnNodeBlockerShutdown);
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneCoreComponent, MapInitEvent>(OnCoreInit);
|
||||
SubscribeLocalEvent<CP14DemiplaneCoreComponent, DestructionEventArgs>(OnCoreShutdown);
|
||||
}
|
||||
|
||||
private void OnCoreShutdown(Entity<CP14DemiplaneCoreComponent> ent, ref DestructionEventArgs args)
|
||||
{
|
||||
if (TryComp<CP14DemiplaneComponent>(ent.Comp.Demiplane, out var demiplane))
|
||||
{
|
||||
_demiplane.StartDestructDemiplane((ent.Comp.Demiplane.Value, demiplane));
|
||||
}
|
||||
|
||||
var query = EntityQueryEnumerator<CP14StationDemiplaneMapComponent>();
|
||||
while (query.MoveNext(out var uid, out var stationMap))
|
||||
{
|
||||
if (stationMap.Nodes.TryGetValue(ent.Comp.Position, out var node))
|
||||
{
|
||||
node.Completed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCoreInit(Entity<CP14DemiplaneCoreComponent> core, ref MapInitEvent args)
|
||||
{
|
||||
core.Comp.Demiplane = Transform(core).MapUid;
|
||||
if (!TryComp<CP14DemiplaneMapNodeBlockerComponent>(core.Comp.Demiplane, out var demiBlocker))
|
||||
return;
|
||||
|
||||
core.Comp.Station = demiBlocker.Station;
|
||||
core.Comp.Position = demiBlocker.Position;
|
||||
|
||||
EnsureComp<CP14DemiplaneMapNodeBlockerComponent>(core, out var coreBlocker);
|
||||
|
||||
coreBlocker.Position = core.Comp.Position;
|
||||
coreBlocker.Station = core.Comp.Station;
|
||||
coreBlocker.IncreaseNodeDifficulty = 0;
|
||||
}
|
||||
|
||||
private void OnNodeBlockerShutdown(Entity<CP14DemiplaneMapNodeBlockerComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (!TryComp<CP14StationDemiplaneMapComponent>(ent.Comp.Station, out var stationMap))
|
||||
return;
|
||||
|
||||
if (!stationMap.Nodes.TryGetValue(ent.Comp.Position, out var node))
|
||||
return;
|
||||
|
||||
if (ent.Comp.IncreaseNodeDifficulty == 0)
|
||||
return;
|
||||
|
||||
node.AdditionalLevel += ent.Comp.IncreaseNodeDifficulty;
|
||||
GenerateNodeData(node, clearOldModifiers: true);
|
||||
}
|
||||
|
||||
private void DemiplaneEjectAttempt(Entity<CP14DemiplaneNavigationMapComponent> ent, ref CP14DemiplaneMapEjectMessage args)
|
||||
{
|
||||
var station = _station.GetOwningStation(ent, Transform(ent));
|
||||
|
||||
if (!TryComp<CP14StationDemiplaneMapComponent>(station, out var stationMap))
|
||||
return;
|
||||
|
||||
if (!stationMap.Nodes.TryGetValue(args.Position, out var node))
|
||||
return;
|
||||
|
||||
if (!node.InFrontierZone)
|
||||
return;
|
||||
|
||||
//Eject!
|
||||
var key = SpawnAttachedTo(ent.Comp.KeyProto, Transform(ent).Coordinates);
|
||||
_audio.PlayPvs(ent.Comp.EjectSound, Transform(key).Coordinates);
|
||||
|
||||
if (TryComp<CP14DemiplaneDataComponent>(key, out var demiData))
|
||||
{
|
||||
demiData.Location = node.LocationConfig;
|
||||
demiData.SelectedModifiers.AddRange(node.Modifiers);
|
||||
}
|
||||
|
||||
EnsureComp<CP14DemiplaneMapNodeBlockerComponent>(key, out var blockerComp);
|
||||
blockerComp.Position = args.Position;
|
||||
blockerComp.Station = station;
|
||||
}
|
||||
|
||||
private void DemiplaneRevokeAttempt(Entity<CP14DemiplaneNavigationMapComponent> ent, ref CP14DemiplaneMapRevokeMessage args)
|
||||
{
|
||||
var station = _station.GetOwningStation(ent, Transform(ent));
|
||||
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneMapNodeBlockerComponent>();
|
||||
while (query.MoveNext(out var uid, out var blocker))
|
||||
{
|
||||
if (blocker.Station != station)
|
||||
continue;
|
||||
|
||||
if (blocker.Position != args.Position)
|
||||
continue;
|
||||
|
||||
if (!TryComp<CP14StationDemiplaneMapComponent>(station, out var demiStation))
|
||||
continue;
|
||||
|
||||
if (!demiStation.Nodes.TryGetValue(args.Position, out var node))
|
||||
continue;
|
||||
|
||||
SpawnAttachedTo("CP14ImpactEffectMagicSplitting", Transform(ent).Coordinates);
|
||||
|
||||
//If it's a demiplane, initiate closure. If not, just delete it.
|
||||
if (TryComp<CP14DemiplaneComponent>(uid, out var demiplane))
|
||||
{
|
||||
_demiplane.StartDestructDemiplane((uid, demiplane));
|
||||
_popup.PopupEntity(Loc.GetString("cp14-demiplane-revoke-map"), ent);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpawnAttachedTo("CP14ImpactEffectMagicSplitting", Transform(uid).Coordinates);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-demiplane-revoke-item"), ent);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-demiplane-revoke-item"), uid);
|
||||
_damageable.TryChangeDamage(uid, ent.Comp.RevokeDamage, true);
|
||||
_destructible.DestroyEntity(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBeforeActivatableUiOpen(Entity<CP14DemiplaneNavigationMapComponent> ent,
|
||||
ref BeforeActivatableUIOpenEvent args)
|
||||
{
|
||||
var station = _station.GetOwningStation(ent, Transform(ent));
|
||||
|
||||
if (!TryComp<CP14StationDemiplaneMapComponent>(station, out var stationMap))
|
||||
return;
|
||||
|
||||
UpdateNodesStatus((station.Value, stationMap));
|
||||
|
||||
_userInterface.SetUiState(ent.Owner,
|
||||
CP14DemiplaneMapUiKey.Key,
|
||||
new CP14DemiplaneMapUiState(stationMap.Nodes, stationMap.Edges));
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CP14StationDemiplaneMapComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
GenerateDemiplaneMap(ent);
|
||||
}
|
||||
|
||||
private void GenerateDemiplaneMap(Entity<CP14StationDemiplaneMapComponent> ent)
|
||||
{
|
||||
ent.Comp.Nodes.Clear();
|
||||
ent.Comp.Edges.Clear();
|
||||
|
||||
var allSpecials = _proto.EnumeratePrototypes<CP14SpecialDemiplanePrototype>().ToList();
|
||||
_random.Shuffle(allSpecials);
|
||||
|
||||
var grid = new Dictionary<Vector2i, CP14DemiplaneMapNode>();
|
||||
|
||||
//Spawn start room at 0 0
|
||||
var startPos = new Vector2i(0, 0);
|
||||
var startNode = new CP14DemiplaneMapNode(0, startPos, true);
|
||||
grid[startPos] = startNode;
|
||||
|
||||
//Spawn special rooms
|
||||
var specialCount = _random.Next(ent.Comp.Specials.Min, ent.Comp.Specials.Max + 1);
|
||||
var placedSpecials = 0;
|
||||
var specialPositions = new List<Vector2i>();
|
||||
|
||||
foreach (var special in allSpecials)
|
||||
{
|
||||
if (placedSpecials >= specialCount)
|
||||
break;
|
||||
|
||||
var specialLevel = special.Levels.Next(_random);
|
||||
|
||||
var possiblePositions = new List<Vector2i>();
|
||||
for (var x = -specialLevel; x <= specialLevel; x++)
|
||||
{
|
||||
var y = specialLevel - Math.Abs(x);
|
||||
if (y != 0)
|
||||
possiblePositions.Add(new Vector2i(x, y));
|
||||
possiblePositions.Add(new Vector2i(x, -y));
|
||||
}
|
||||
|
||||
_random.Shuffle(possiblePositions);
|
||||
|
||||
var specialPos = new Vector2i(0, 0);
|
||||
foreach (var pos in possiblePositions)
|
||||
{
|
||||
if (!grid.ContainsKey(pos))
|
||||
{
|
||||
specialPos = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (grid.ContainsKey(specialPos))
|
||||
continue;
|
||||
|
||||
var specialNode = new CP14DemiplaneMapNode(
|
||||
specialLevel,
|
||||
new Vector2(specialPos.X, specialPos.Y),
|
||||
false,
|
||||
locationConfig: special.Location,
|
||||
modifiers: [..special.Modifiers]
|
||||
);
|
||||
grid[specialPos] = specialNode;
|
||||
specialPositions.Add(specialPos);
|
||||
placedSpecials++;
|
||||
}
|
||||
|
||||
// Build meandering paths to each special room and add edges
|
||||
foreach (var specialPos in specialPositions)
|
||||
{
|
||||
var current = startPos;
|
||||
|
||||
while (current != specialPos)
|
||||
{
|
||||
var delta = specialPos - current;
|
||||
var options = new List<Vector2i>();
|
||||
|
||||
if (delta.X != 0)
|
||||
options.Add(new Vector2i(Math.Sign(delta.X), 0));
|
||||
if (delta.Y != 0)
|
||||
options.Add(new Vector2i(0, Math.Sign(delta.Y)));
|
||||
|
||||
// Add the possibility of a "mistaken" step to the side
|
||||
if (_random.Prob(0.3f)) // 30% chance to take a side step
|
||||
{
|
||||
if (delta.X != 0 && delta.Y != 0)
|
||||
{
|
||||
options.Add(new Vector2i(0, Math.Sign(delta.Y)) * -1);
|
||||
options.Add(new Vector2i(Math.Sign(delta.X), 0) * -1);
|
||||
}
|
||||
}
|
||||
|
||||
_random.Shuffle(options);
|
||||
var step = options[0];
|
||||
var next = current + step;
|
||||
|
||||
if (!grid.TryGetValue(next, out var nextNode))
|
||||
{
|
||||
nextNode = new CP14DemiplaneMapNode(Math.Abs(next.X) + Math.Abs(next.Y),
|
||||
new Vector2(next.X, next.Y),
|
||||
false);
|
||||
grid[next] = nextNode;
|
||||
}
|
||||
|
||||
ent.Comp.Edges.Add((current, next));
|
||||
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
//Fill nodes with random data
|
||||
foreach (var node in grid.Values)
|
||||
{
|
||||
GenerateNodeData(node);
|
||||
}
|
||||
|
||||
// Random visual offset
|
||||
foreach (var node in grid.Values)
|
||||
{
|
||||
var x = node.UiPosition.X + _random.NextFloat(-0.2f, 0.2f);
|
||||
var y = node.UiPosition.Y + _random.NextFloat(-0.2f, 0.2f);
|
||||
node.UiPosition = new Vector2(x, y);
|
||||
}
|
||||
|
||||
//Add all rooms into component
|
||||
ent.Comp.Nodes = grid;
|
||||
}
|
||||
|
||||
private void GenerateNodeData(CP14DemiplaneMapNode node, bool clearOldModifiers = false)
|
||||
{
|
||||
if (node.Level == 0)
|
||||
return;
|
||||
|
||||
var location = _demiplane.GenerateDemiplaneLocation(node.Level);
|
||||
node.LocationConfig ??= location;
|
||||
|
||||
var limits = new Dictionary<ProtoId<CP14DemiplaneModifierCategoryPrototype>, float>
|
||||
{
|
||||
{ "Danger", (node.Level + node.AdditionalLevel) * 0.2f },
|
||||
{ "GhostRoleDanger", 1f },
|
||||
{ "Reward", Math.Max(node.Level * 0.2f, 0.5f) },
|
||||
{ "Ore", Math.Max(node.Level * 0.2f, 0.5f) },
|
||||
{ "Fun", 1f },
|
||||
{ "Weather", 1f },
|
||||
{ "MapLight", 1f },
|
||||
};
|
||||
var mods = _demiplane.GenerateDemiplaneModifiers(node.Level, location, limits);
|
||||
|
||||
if (clearOldModifiers)
|
||||
node.Modifiers.Clear();
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
node.Modifiers.Add(mod);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateNodesStatus(Entity<CP14StationDemiplaneMapComponent> ent)
|
||||
{
|
||||
foreach (var node in ent.Comp.Nodes)
|
||||
{
|
||||
node.Value.InFrontierZone = NodeInFronrierZone(ent.Comp.Nodes, ent.Comp.Edges, node.Key);
|
||||
node.Value.InUsing = false;
|
||||
}
|
||||
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneMapNodeBlockerComponent>();
|
||||
while (query.MoveNext(out var uid, out var blocker))
|
||||
{
|
||||
if (!TryComp<CP14StationDemiplaneMapComponent>(blocker.Station, out var stationMap))
|
||||
continue;
|
||||
|
||||
if (!stationMap.Nodes.TryGetValue(blocker.Position, out var node))
|
||||
continue;
|
||||
|
||||
node.InUsing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server._CP14.GameTicking.Rules.Components;
|
||||
using Content.Server._CP14.Procedural;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules;
|
||||
|
||||
public sealed class CP14ExpeditionToWindlandsRule : GameRuleSystem<CP14ExpeditionToWindlandsRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly ShuttleSystem _shuttles = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
[Dependency] private readonly CP14LocationGenerationSystem _generation = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_sawmill = _logManager.GetSawmill("cp14_expedition_to_windlands_rule");
|
||||
}
|
||||
|
||||
protected override void Started(EntityUid uid,
|
||||
CP14ExpeditionToWindlandsRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
GameRuleStartedEvent args)
|
||||
{
|
||||
base.Started(uid, component, gameRule, args);
|
||||
|
||||
var station = _station.GetStations().First();
|
||||
if (!TryComp<StationDataComponent>(station, out var stationData))
|
||||
{
|
||||
_sawmill.Error($"Station {station} does not have a StationDataComponent.");
|
||||
return;
|
||||
}
|
||||
|
||||
var largestStationGrid = _station.GetLargestGrid(stationData);
|
||||
|
||||
if (largestStationGrid is null)
|
||||
{
|
||||
_sawmill.Error($"Station {station} does not have a grid.");
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureComp<ShuttleComponent>(largestStationGrid.Value, out var shuttleComp);
|
||||
|
||||
var windlands = _mapSystem.CreateMap(out var mapId, runMapInit: false);
|
||||
|
||||
_generation.GenerateLocation(windlands, mapId, component.Location, component.Modifiers);
|
||||
_shuttles.FTLToCoordinates(largestStationGrid.Value, shuttleComp, new EntityCoordinates(windlands, Vector2.Zero), 0f, 0f, component.FloatingTime);
|
||||
}
|
||||
}
|
||||
116
Content.Server/_CP14/GameTicking/Rules/CP14CrashingShipRule.cs
Normal file
116
Content.Server/_CP14/GameTicking/Rules/CP14CrashingShipRule.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System.Linq;
|
||||
using Content.Server._CP14.GameTicking.Rules.Components;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Server.Shuttles.Events;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules;
|
||||
|
||||
public sealed class CP14CrashingShipRule : GameRuleSystem<CP14CrashingShipRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_sawmill = _logManager.GetSawmill("cp14_crashing_ship_rule");
|
||||
|
||||
SubscribeLocalEvent<CP14CrashingShipComponent, FTLCompletedEvent>(OnFTLCompleted);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
UpdateExplosions(frameTime);
|
||||
}
|
||||
|
||||
protected override void Started(EntityUid uid,
|
||||
CP14CrashingShipRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
GameRuleStartedEvent args)
|
||||
{
|
||||
base.Started(uid, component, gameRule, args);
|
||||
|
||||
var station = _station.GetStations().First();
|
||||
if (!TryComp<StationDataComponent>(station, out var stationData))
|
||||
{
|
||||
_sawmill.Error($"Station {station} does not have a StationDataComponent.");
|
||||
return;
|
||||
}
|
||||
|
||||
var largestStationGrid = _station.GetLargestGrid(stationData);
|
||||
|
||||
if (largestStationGrid is null)
|
||||
{
|
||||
_sawmill.Error($"Station {station} does not have a grid.");
|
||||
return;
|
||||
}
|
||||
|
||||
component.StartExplosionTime += _timing.CurTime;
|
||||
component.Ship = largestStationGrid.Value;
|
||||
}
|
||||
|
||||
private void OnFTLCompleted(Entity<CP14CrashingShipComponent> ent, ref FTLCompletedEvent args)
|
||||
{
|
||||
SpawnRandomExplosion(ent, ent.Comp.FinalExplosionProto, 10);
|
||||
RemCompDeferred<CP14CrashingShipComponent>(ent);
|
||||
}
|
||||
|
||||
private void UpdateExplosions(float frameTime)
|
||||
{
|
||||
var ruleQuery = EntityQueryEnumerator<CP14CrashingShipRuleComponent>();
|
||||
while (ruleQuery.MoveNext(out var uid, out var rule))
|
||||
{
|
||||
if (!rule.PendingExplosions)
|
||||
continue;
|
||||
|
||||
if (_timing.CurTime < rule.StartExplosionTime)
|
||||
continue;
|
||||
|
||||
if (rule.Ship is null)
|
||||
continue;
|
||||
|
||||
AddComp<CP14CrashingShipComponent>(rule.Ship.Value);
|
||||
rule.PendingExplosions = false;
|
||||
}
|
||||
|
||||
var query = EntityQueryEnumerator<CP14CrashingShipComponent>();
|
||||
while (query.MoveNext(out var uid, out var ship))
|
||||
{
|
||||
if (_timing.CurTime < ship.NextExplosionTime)
|
||||
continue;
|
||||
|
||||
ship.NextExplosionTime = _timing.CurTime + TimeSpan.FromSeconds(_random.Next(2, 10));
|
||||
SpawnRandomExplosion((uid, ship), ship.ExplosionProto, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SpawnRandomExplosion(Entity<CP14CrashingShipComponent> grid, EntProtoId explosionProto, int count)
|
||||
{
|
||||
var station = _station.GetOwningStation(grid);
|
||||
|
||||
if (station is null)
|
||||
return;
|
||||
|
||||
TryFindRandomTileOnStation((station.Value, Comp<StationDataComponent>(station.Value)),
|
||||
out var tile,
|
||||
out var targetGrid,
|
||||
out var targetCoords);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
Spawn(explosionProto, targetCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules.Components;
|
||||
|
||||
/// <summary>
|
||||
///When attached to shuttle, start firebombing it until FTL ends.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14CrashingShipRule))]
|
||||
public sealed partial class CP14CrashingShipComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public TimeSpan NextExplosionTime = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public EntProtoId ExplosionProto = "CP14ShipExplosion";
|
||||
|
||||
[DataField]
|
||||
public EntProtoId FinalExplosionProto = "CP14ShipExplosionBig";
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Content.Server._CP14.GameTicking.Rules.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A rule that assigns common goals to different roles. Common objectives are generated once at the beginning of a round and are shared between players.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14CrashingShipRule))]
|
||||
public sealed partial class CP14CrashingShipRuleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? Ship;
|
||||
|
||||
[DataField]
|
||||
public bool PendingExplosions = true;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan StartExplosionTime = TimeSpan.FromMinutes(1);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Content.Shared._CP14.Procedural.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A rule that assigns common goals to different roles. Common objectives are generated once at the beginning of a round and are shared between players.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14ExpeditionToWindlandsRule))]
|
||||
public sealed partial class CP14ExpeditionToWindlandsRuleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public ProtoId<CP14ProceduralLocationPrototype> Location = "T1GrasslandIsland";
|
||||
|
||||
[DataField]
|
||||
public List<ProtoId<CP14ProceduralModifierPrototype>> Modifiers = [];
|
||||
|
||||
[DataField]
|
||||
public float FloatingTime = 120;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Content.Server._CP14.Procedural.GlobalWorld.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Added to cards on which procedural generation occurs, and removed when generation is successfully completed.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14ActiveJobGenerationComponent : Component
|
||||
{
|
||||
}
|
||||
109
Content.Server/_CP14/Procedural/CP14LocationGenerationSystem.cs
Normal file
109
Content.Server/_CP14/Procedural/CP14LocationGenerationSystem.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System.Threading;
|
||||
using Content.Server._CP14.Procedural.GlobalWorld.Components;
|
||||
using Content.Server.Procedural;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared._CP14.Procedural.Prototypes;
|
||||
using Content.Shared.Procedural;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.CPUJob.JobQueues;
|
||||
using Robust.Shared.CPUJob.JobQueues.Queues;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Procedural;
|
||||
|
||||
public sealed class CP14LocationGenerationSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly DungeonSystem _dungeon = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private const double JobMaxTime = 0.002;
|
||||
private readonly JobQueue _expeditionQueue = new();
|
||||
private readonly List<(CP14SpawnProceduralLocationJob Job, CancellationTokenSource CancelToken)> _jobs = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14ActiveJobGenerationComponent, ComponentShutdown>(OnGenerationShutdown);
|
||||
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_expeditionQueue.Process();
|
||||
|
||||
foreach (var (job, cancelToken) in _jobs.ToArray())
|
||||
{
|
||||
switch (job.Status)
|
||||
{
|
||||
case JobStatus.Finished:
|
||||
if (job.JobName is not null)
|
||||
{
|
||||
var ev = new CP14LocationGeneratedEvent(job.JobName);
|
||||
RaiseLocalEvent(ev);
|
||||
}
|
||||
RemComp<CP14ActiveJobGenerationComponent>(job.MapUid);
|
||||
|
||||
_jobs.Remove((job, cancelToken));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a new procedural location on the specified map and coordinates.
|
||||
/// Essentially, this is a wrapper for _dungeon.GenerateDungeon, which collects the necessary settings for the
|
||||
/// dungeon based on the location and modifiers.
|
||||
/// </summary>
|
||||
public void GenerateLocation(EntityUid mapUid, MapId mapId, ProtoId<CP14ProceduralLocationPrototype> location, List<ProtoId<CP14ProceduralModifierPrototype>> modifiers, Vector2i position = new(), int? seed = null, string? jobName = null)
|
||||
{
|
||||
var cancelToken = new CancellationTokenSource();
|
||||
|
||||
EnsureComp<CP14ActiveJobGenerationComponent>(mapUid);
|
||||
|
||||
var job = new CP14SpawnProceduralLocationJob(
|
||||
JobMaxTime,
|
||||
EntityManager,
|
||||
_logManager,
|
||||
_proto,
|
||||
_dungeon,
|
||||
_mapSystem,
|
||||
mapUid,
|
||||
mapId,
|
||||
position,
|
||||
seed ?? _random.Next(-10000, 10000),
|
||||
location,
|
||||
modifiers,
|
||||
jobName,
|
||||
cancelToken.Token);
|
||||
|
||||
_jobs.Add((job, cancelToken));
|
||||
_expeditionQueue.EnqueueJob(job);
|
||||
}
|
||||
|
||||
|
||||
private void OnGenerationShutdown(Entity<CP14ActiveJobGenerationComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
//We stop asynchronous generation of a location early if for some reason this location is deleted before generation is complete
|
||||
foreach (var (job, cancelToken) in _jobs.ToArray())
|
||||
{
|
||||
if (job.MapUid == ent.Owner)
|
||||
{
|
||||
cancelToken.Cancel();
|
||||
_jobs.Remove((job, cancelToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class CP14LocationGeneratedEvent(string jobName) : EntityEventArgs
|
||||
{
|
||||
public string JobName = jobName;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Procedural;
|
||||
using Content.Shared._CP14.Procedural.Prototypes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Procedural.DungeonLayers;
|
||||
using Robust.Shared.CPUJob.JobQueues;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Procedural;
|
||||
|
||||
public sealed class CP14SpawnProceduralLocationJob(
|
||||
double maxTime,
|
||||
IEntityManager entManager,
|
||||
ILogManager logManager,
|
||||
IPrototypeManager protoManager,
|
||||
DungeonSystem dungeon,
|
||||
SharedMapSystem map,
|
||||
EntityUid mapUid,
|
||||
MapId mapId,
|
||||
Vector2i position,
|
||||
int seed,
|
||||
ProtoId<CP14ProceduralLocationPrototype> config,
|
||||
List<ProtoId<CP14ProceduralModifierPrototype>> modifiers,
|
||||
string? jobName = null,
|
||||
CancellationToken cancellation = default)
|
||||
: Job<bool>(maxTime, cancellation)
|
||||
{
|
||||
public readonly EntityUid MapUid = mapUid;
|
||||
public string? JobName = jobName;
|
||||
|
||||
private readonly ISawmill _sawmill = logManager.GetSawmill("cp14_procedural_location_job");
|
||||
|
||||
protected override async Task<bool> Process()
|
||||
{
|
||||
_sawmill.Debug($"Spawning procedural location `{config.Id}` with seed {seed}");
|
||||
var gridComp = entManager.EnsureComponent<MapGridComponent>(MapUid);
|
||||
|
||||
MetaDataComponent? metadata = null;
|
||||
DungeonConfigPrototype dungeonConfig = new();
|
||||
|
||||
//Boilerplate: reserve all old grid tiles
|
||||
dungeonConfig.Layers.Add(new CP14ReserveGrid());
|
||||
|
||||
//Setup location config
|
||||
var locationConfig = protoManager.Index(config);
|
||||
var indexedLocation = protoManager.Index(locationConfig.LocationConfig);
|
||||
|
||||
dungeonConfig.Layers.AddRange(indexedLocation.Layers);
|
||||
dungeonConfig.ReserveTiles = indexedLocation.ReserveTiles;
|
||||
|
||||
//Add map components
|
||||
entManager.AddComponents(MapUid, locationConfig.Components);
|
||||
|
||||
//Apply modifiers
|
||||
foreach (var modifier in modifiers)
|
||||
{
|
||||
if (!protoManager.TryIndex(modifier, out var indexedModifier))
|
||||
continue;
|
||||
|
||||
if (indexedModifier.Layers != null)
|
||||
dungeonConfig.Layers.AddRange(indexedModifier.Layers);
|
||||
if (indexedModifier.Components != null)
|
||||
entManager.AddComponents(MapUid, indexedModifier.Components);
|
||||
|
||||
_sawmill.Debug($"Added modifier: {seed} - {modifier.Id}");
|
||||
}
|
||||
|
||||
//Setup gravity
|
||||
var gravity = entManager.EnsureComponent<GravityComponent>(MapUid);
|
||||
gravity.Enabled = true;
|
||||
entManager.Dirty(MapUid, gravity, metadata);
|
||||
|
||||
// Setup default atmos
|
||||
var moles = new float[Atmospherics.AdjustedNumberOfGases];
|
||||
moles[(int)Gas.Oxygen] = 21.824779f;
|
||||
moles[(int)Gas.Nitrogen] = 82.10312f;
|
||||
var mixture = new GasMixture(moles, Atmospherics.T20C);
|
||||
entManager.System<AtmosphereSystem>().SetMapAtmosphere(MapUid, false, mixture);
|
||||
|
||||
if (!map.IsInitialized(mapId))
|
||||
map.InitializeMap(mapId);
|
||||
map.SetPaused(mapId, false);
|
||||
|
||||
//Spawn modified config
|
||||
await WaitAsyncTask(dungeon.GenerateDungeonAsync(dungeonConfig,
|
||||
MapUid,
|
||||
gridComp,
|
||||
position,
|
||||
seed));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Parallax;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Procedural.DungeonLayers;
|
||||
using Content.Shared.Procedural.PostGeneration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Procedural.DungeonJob;
|
||||
|
||||
public sealed partial class DungeonJob
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="BiomeDunGen"/>
|
||||
/// </summary>
|
||||
private async Task PostGen(CP14BiomeDunGen dunGen,
|
||||
List<Dungeon> dungeons,
|
||||
HashSet<Vector2i> reservedTiles,
|
||||
Random random)
|
||||
{
|
||||
if (!_prototype.TryIndex(dunGen.BiomeTemplate, out var indexedBiome))
|
||||
return;
|
||||
|
||||
var biomeSystem = _entManager.System<BiomeSystem>();
|
||||
|
||||
var seed = random.Next();
|
||||
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
||||
|
||||
foreach (var dun in dungeons)
|
||||
{
|
||||
foreach (var node in dun.AllTiles)
|
||||
{
|
||||
var tileRef = _maps.GetTileRef(_gridUid, _grid, node);
|
||||
|
||||
if (reservedTiles.Contains(node))
|
||||
continue;
|
||||
|
||||
if (dunGen.TileMask is not null)
|
||||
{
|
||||
if (!dunGen.TileMask.Contains(((ContentTileDefinition)_tileDefManager[tileRef.Tile.TypeId]).ID))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dunGen.TileMask is not null)
|
||||
{
|
||||
if (!dunGen.TileMask.Contains(((ContentTileDefinition) _tileDefManager[tileRef.Tile.TypeId]).ID))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Need to set per-tile to override data.
|
||||
if (biomeSystem.TryGetTile(node, indexedBiome.Layers, seed, (_gridUid, _grid), out var tile))
|
||||
{
|
||||
_maps.SetTile(_gridUid, _grid, node, tile.Value);
|
||||
}
|
||||
|
||||
if (biomeSystem.TryGetDecals(node, indexedBiome.Layers, seed, (_gridUid, _grid), out var decals))
|
||||
{
|
||||
foreach (var decal in decals)
|
||||
{
|
||||
_decals.TryAddDecal(decal.ID, new EntityCoordinates(_gridUid, decal.Position), out _);
|
||||
}
|
||||
}
|
||||
|
||||
if (biomeSystem.TryGetEntity(node, indexedBiome.Layers, tile ?? tileRef.Tile, seed, (_gridUid, _grid), out var entityProto))
|
||||
{
|
||||
var ent = _entManager.SpawnEntity(entityProto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector));
|
||||
var xform = xformQuery.Get(ent);
|
||||
|
||||
if (!xform.Comp.Anchored)
|
||||
{
|
||||
_transform.AnchorEntity(ent, xform);
|
||||
}
|
||||
|
||||
// TODO: Engine bug with SpawnAtPosition
|
||||
DebugTools.Assert(xform.Comp.Anchored);
|
||||
}
|
||||
|
||||
await SuspendDungeon();
|
||||
if (!ValidateResume())
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Procedural.DungeonLayers;
|
||||
|
||||
namespace Content.Server.Procedural.DungeonJob;
|
||||
|
||||
public sealed partial class DungeonJob
|
||||
{
|
||||
private async Task PostGen(CP14ReserveGrid dunGen,
|
||||
HashSet<Vector2i> reservedTiles)
|
||||
{
|
||||
var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid);
|
||||
while (tiles.MoveNext(out var tileRef))
|
||||
{
|
||||
var node = tileRef.Value.GridIndices;
|
||||
|
||||
reservedTiles.Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Content.Server._CP14.Procedural.GlobalWorld.Components;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Shared._CP14.Procedural.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Procedural.GlobalWorld;
|
||||
|
||||
public sealed partial class CP14GlobalWorldSystem
|
||||
{
|
||||
private void GenerateGlobalWorldMap(Entity<CP14StationGlobalWorldComponent> ent)
|
||||
{
|
||||
ent.Comp.Nodes.Clear();
|
||||
ent.Comp.Edges.Clear();
|
||||
|
||||
//For first - check station integration, and put station into (0,0) global map position
|
||||
if (TryComp<CP14StationGlobalWorldIntegrationComponent>(ent, out var integration) &&
|
||||
TryComp<StationDataComponent>(ent, out var stationData))
|
||||
{
|
||||
var largestStationGrid = _station.GetLargestGrid(stationData);
|
||||
|
||||
Debug.Assert(largestStationGrid is not null);
|
||||
|
||||
var mapId = _transform.GetMapId(largestStationGrid.Value);
|
||||
var zeroNode =
|
||||
new CP14GlobalWorldNode
|
||||
{
|
||||
MapUid = mapId,
|
||||
LocationConfig = integration.Location,
|
||||
Modifiers = integration.Modifiers,
|
||||
Level = 0,
|
||||
};
|
||||
GenerateNodeData(zeroNode);
|
||||
ent.Comp.Nodes.Add(
|
||||
Vector2i.Zero,
|
||||
zeroNode
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
var zeroNode = new CP14GlobalWorldNode();
|
||||
GenerateNodeData(zeroNode);
|
||||
ent.Comp.Nodes.Add(Vector2i.Zero, zeroNode);
|
||||
}
|
||||
|
||||
//Generate nodes with random data until limits
|
||||
while (ent.Comp.Nodes.Count < ent.Comp.LocationCount + 1)
|
||||
{
|
||||
// Get a random existing node
|
||||
var randomNode = _random.Pick(ent.Comp.Nodes);
|
||||
var randomNodePosition = randomNode.Key;
|
||||
|
||||
// Find a random empty adjacent position
|
||||
var directions = new[] { new Vector2i(1, 0), new Vector2i(-1, 0), new Vector2i(0, 1), new Vector2i(0, -1) };
|
||||
var emptyPositions = directions
|
||||
.Select(dir => randomNodePosition + dir)
|
||||
.Where(pos => !ent.Comp.Nodes.ContainsKey(pos))
|
||||
.ToList();
|
||||
|
||||
if (emptyPositions.Count == 0)
|
||||
continue;
|
||||
|
||||
var newPosition = emptyPositions[Random.Shared.Next(emptyPositions.Count)];
|
||||
|
||||
// Add the new node and connect it with an edge
|
||||
var newNode = new CP14GlobalWorldNode
|
||||
{
|
||||
Level = Math.Abs(newPosition.X) + Math.Abs(newPosition.Y),
|
||||
};
|
||||
GenerateNodeData(newNode);
|
||||
ent.Comp.Nodes.Add(newPosition, newNode);
|
||||
ent.Comp.Edges.Add((randomNodePosition, newPosition));
|
||||
|
||||
//Add connections to each other
|
||||
if (_proto.TryIndex(newNode.LocationConfig, out var indexedNewNodeLocation) && _proto.TryIndex(randomNode.Value.LocationConfig, out var indexedRandomNodeLocation))
|
||||
{
|
||||
newNode.Modifiers.Add(indexedNewNodeLocation.Connection);
|
||||
randomNode.Value.Modifiers.Add(indexedRandomNodeLocation.Connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateNodeData(CP14GlobalWorldNode node,
|
||||
bool overrideLocation = false,
|
||||
bool clearOldModifiers = false)
|
||||
{
|
||||
if (node.LocationConfig is null || overrideLocation)
|
||||
{
|
||||
var location = SelectLocation(node.Level);
|
||||
node.LocationConfig ??= location;
|
||||
}
|
||||
|
||||
if (!_proto.TryIndex(node.LocationConfig, out var indexedLocation))
|
||||
throw new Exception($"No location config found for node at level {node.Level}!");
|
||||
|
||||
var limits = new Dictionary<ProtoId<CP14ProceduralModifierCategoryPrototype>, float>
|
||||
{
|
||||
{ "Danger", Math.Max(node.Level * 0.2f, 0.5f) },
|
||||
{ "GhostRoleDanger", 1f },
|
||||
{ "Reward", Math.Max(node.Level * 0.3f, 0.5f) },
|
||||
{ "Ore", Math.Max(node.Level * 0.5f, 1f) },
|
||||
{ "Fun", 1f },
|
||||
{ "Weather", 1f },
|
||||
{ "MapLight", 1f },
|
||||
};
|
||||
var mods = SelectModifiers(node.Level, indexedLocation, limits);
|
||||
|
||||
if (clearOldModifiers)
|
||||
node.Modifiers.Clear();
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
node.Modifiers.Add(mod);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a suitable location for the specified difficulty level.
|
||||
/// </summary>
|
||||
public CP14ProceduralLocationPrototype SelectLocation(int level)
|
||||
{
|
||||
CP14ProceduralLocationPrototype? selectedConfig = null;
|
||||
|
||||
HashSet<CP14ProceduralLocationPrototype> suitableConfigs = new();
|
||||
foreach (var locationConfig in _proto.EnumeratePrototypes<CP14ProceduralLocationPrototype>())
|
||||
{
|
||||
suitableConfigs.Add(locationConfig);
|
||||
}
|
||||
|
||||
while (suitableConfigs.Count > 0)
|
||||
{
|
||||
var randomConfig = _random.Pick(suitableConfigs);
|
||||
|
||||
var passed = true;
|
||||
|
||||
//Random prob filter
|
||||
if (passed)
|
||||
{
|
||||
if (!_random.Prob(randomConfig.GenerationProb))
|
||||
{
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Levels filter
|
||||
if (passed)
|
||||
{
|
||||
if (level < randomConfig.Levels.Min || level > randomConfig.Levels.Max)
|
||||
{
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!passed)
|
||||
{
|
||||
suitableConfigs.Remove(randomConfig);
|
||||
continue;
|
||||
}
|
||||
|
||||
selectedConfig = randomConfig;
|
||||
break;
|
||||
}
|
||||
|
||||
if (selectedConfig is null)
|
||||
throw new Exception($"No suitable procedural location config found for level {level}!");
|
||||
|
||||
return selectedConfig;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a set of modifiers under the specified difficulty level that are appropriate for the specified location
|
||||
/// </summary>
|
||||
public List<CP14ProceduralModifierPrototype> SelectModifiers(
|
||||
int level,
|
||||
CP14ProceduralLocationPrototype location,
|
||||
Dictionary<ProtoId<CP14ProceduralModifierCategoryPrototype>, float> modifierLimits)
|
||||
{
|
||||
List<CP14ProceduralModifierPrototype> selectedModifiers = new();
|
||||
|
||||
//Modifier generation
|
||||
Dictionary<CP14ProceduralModifierPrototype, float> suitableModifiersWeights = new();
|
||||
foreach (var modifier in _proto.EnumeratePrototypes<CP14ProceduralModifierPrototype>())
|
||||
{
|
||||
var passed = true;
|
||||
|
||||
//Random prob filter
|
||||
if (passed)
|
||||
{
|
||||
if (!_random.Prob(modifier.GenerationProb))
|
||||
{
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Levels filter
|
||||
if (passed)
|
||||
{
|
||||
if (level < modifier.Levels.Min || level > modifier.Levels.Max)
|
||||
{
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Tag blacklist filter
|
||||
foreach (var configTag in location.Tags)
|
||||
{
|
||||
if (modifier.BlacklistTags.Count != 0 && modifier.BlacklistTags.Contains(configTag))
|
||||
{
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Tag required filter
|
||||
if (passed)
|
||||
{
|
||||
foreach (var reqTag in modifier.RequiredTags)
|
||||
{
|
||||
if (!location.Tags.Contains(reqTag))
|
||||
{
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (passed)
|
||||
suitableModifiersWeights.Add(modifier, modifier.GenerationWeight);
|
||||
}
|
||||
|
||||
|
||||
//Limits calculation
|
||||
Dictionary<ProtoId<CP14ProceduralModifierCategoryPrototype>, float> limits = new();
|
||||
foreach (var limit in modifierLimits)
|
||||
{
|
||||
limits.Add(limit.Key, limit.Value);
|
||||
}
|
||||
|
||||
|
||||
while (suitableModifiersWeights.Count > 0)
|
||||
{
|
||||
var selectedModifier = ModifierPick(suitableModifiersWeights, _random);
|
||||
|
||||
//Fill location under limits
|
||||
var passed = true;
|
||||
foreach (var category in selectedModifier.Categories)
|
||||
{
|
||||
if (!limits.ContainsKey(category.Key))
|
||||
{
|
||||
suitableModifiersWeights.Remove(selectedModifier);
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (limits[category.Key] - category.Value < 0)
|
||||
{
|
||||
suitableModifiersWeights.Remove(selectedModifier);
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!passed)
|
||||
continue;
|
||||
|
||||
selectedModifiers.Add(selectedModifier);
|
||||
|
||||
foreach (var category in selectedModifier.Categories)
|
||||
{
|
||||
limits[category.Key] -= category.Value;
|
||||
}
|
||||
|
||||
if (selectedModifier.Unique)
|
||||
suitableModifiersWeights.Remove(selectedModifier);
|
||||
}
|
||||
|
||||
return selectedModifiers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimization moment: avoid re-indexing for weight selection
|
||||
/// </summary>
|
||||
private static CP14ProceduralModifierPrototype ModifierPick(
|
||||
Dictionary<CP14ProceduralModifierPrototype, float> weights,
|
||||
IRobustRandom random)
|
||||
{
|
||||
var picks = weights;
|
||||
var sum = picks.Values.Sum();
|
||||
var accumulated = 0f;
|
||||
|
||||
var rand = random.NextFloat() * sum;
|
||||
|
||||
foreach (var (key, weight) in picks)
|
||||
{
|
||||
accumulated += weight;
|
||||
|
||||
if (accumulated >= rand)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
// Shouldn't happen
|
||||
throw new InvalidOperationException($"Invalid weighted pick in CP14DemiplanSystem.Generation!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using Content.Server._CP14.Procedural.GlobalWorld.Components;
|
||||
using Content.Server.Shuttles.Systems;
|
||||
using Content.Server.Station.Events;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.Teleportation.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Procedural.GlobalWorld;
|
||||
|
||||
public sealed partial class CP14GlobalWorldSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ShuttleSystem _shuttles = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly CP14LocationGenerationSystem _generation = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly MetaDataSystem _meta = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly LinkedEntitySystem _link = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_sawmill = _logManager.GetSawmill("cp14_global_world");
|
||||
|
||||
SubscribeLocalEvent<CP14StationGlobalWorldComponent, StationPostInitEvent>(OnIntegratedPostInit);
|
||||
SubscribeLocalEvent<CP14LocationGeneratedEvent>(OnLocationGenerated);
|
||||
SubscribeLocalEvent<CP14StationGlobalWorldComponent, CP14GlobalWorldGeneratedEvent>(OnGlobalWorldGenerated);
|
||||
}
|
||||
|
||||
private void OnLocationGenerated(CP14LocationGeneratedEvent args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14StationGlobalWorldComponent>();
|
||||
while (query.MoveNext(out var ent, out var comp))
|
||||
{
|
||||
//Theres no support for multiple GlobalWorld
|
||||
if (comp.LocationInGeneration.Contains(args.JobName))
|
||||
{
|
||||
comp.LocationInGeneration.Remove(args.JobName);
|
||||
_sawmill.Debug($"Location {args.JobName} generated successfully. Remaining: {comp.LocationInGeneration.Count}");
|
||||
}
|
||||
|
||||
if (comp.LocationInGeneration.Count == 0)
|
||||
{
|
||||
//All locations are generated, we can now spawn the global world map
|
||||
_sawmill.Debug("All locations generated, spawning global world map.");
|
||||
var ev = new CP14GlobalWorldGeneratedEvent();
|
||||
RaiseLocalEvent(ent, ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIntegratedPostInit(Entity<CP14StationGlobalWorldComponent> ent, ref StationPostInitEvent args)
|
||||
{
|
||||
GenerateGlobalWorldMap(ent);
|
||||
SpawnGlobalWorldMap(ent);
|
||||
}
|
||||
|
||||
private void OnGlobalWorldGenerated(Entity<CP14StationGlobalWorldComponent> ent, ref CP14GlobalWorldGeneratedEvent ev)
|
||||
{
|
||||
ConnectGlobalWorldMap(ent);
|
||||
}
|
||||
|
||||
private void SpawnGlobalWorldMap(Entity<CP14StationGlobalWorldComponent> ent)
|
||||
{
|
||||
foreach (var (position, node) in ent.Comp.Nodes)
|
||||
{
|
||||
if (node.LocationConfig is null)
|
||||
continue;
|
||||
|
||||
if (node.MapUid is null)
|
||||
{
|
||||
_map.CreateMap(out var newMapId, runMapInit: false);
|
||||
node.MapUid = newMapId;
|
||||
}
|
||||
|
||||
var mapId = node.MapUid.Value;
|
||||
var mapUid = _map.GetMap(mapId);
|
||||
var jobName = $"job_GW_{position}";
|
||||
ent.Comp.LocationInGeneration.Add(jobName);
|
||||
|
||||
_generation.GenerateLocation(
|
||||
mapUid,
|
||||
mapId,
|
||||
node.LocationConfig.Value,
|
||||
node.Modifiers,
|
||||
jobName: jobName
|
||||
);
|
||||
|
||||
// Avoid renaming the settlement
|
||||
if (position != Vector2i.Zero)
|
||||
{
|
||||
var newName = $"{position} - {node.LocationConfig.Value}";
|
||||
_meta.SetEntityName(mapUid, newName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectGlobalWorldMap(Entity<CP14StationGlobalWorldComponent> ent)
|
||||
{
|
||||
foreach (var edge in ent.Comp.Edges)
|
||||
{
|
||||
var firstNodeMapUid = ent.Comp.Nodes[edge.Item1].MapUid;
|
||||
var secondNodeMapUid = ent.Comp.Nodes[edge.Item2].MapUid;
|
||||
|
||||
EntityUid? firstConnector = null;
|
||||
EntityUid? secondConnector = null;
|
||||
|
||||
//Get random connector from map
|
||||
var query = EntityQueryEnumerator<CP14GlobalWorldConnectorComponent>();
|
||||
while (query.MoveNext(out var uid, out _))
|
||||
{
|
||||
if (_transform.GetMapId(uid) == firstNodeMapUid)
|
||||
firstConnector = uid;
|
||||
|
||||
if (_transform.GetMapId(uid) == secondNodeMapUid)
|
||||
secondConnector = uid;
|
||||
|
||||
}
|
||||
|
||||
if (firstConnector == null || secondConnector == null)
|
||||
{
|
||||
_sawmill.Error($"Failed to find connectors for edge {edge.Item1} - {edge.Item2}. " +
|
||||
$"First: {firstConnector}, Second: {secondConnector}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var firstPortal = Spawn("CP14LocationPassway", Transform(firstConnector.Value).Coordinates);
|
||||
var secondPortal = Spawn("CP14LocationPassway", Transform(secondConnector.Value).Coordinates);
|
||||
|
||||
_link.TryLink(firstPortal, secondPortal, true);
|
||||
|
||||
Del(firstConnector);
|
||||
Del(secondConnector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CP14GlobalWorldGeneratedEvent : EntityEventArgs
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Content.Server._CP14.Procedural.GlobalWorld.Components;
|
||||
|
||||
/// <summary>
|
||||
/// The GlobalWorld system connects worlds by creating connecting portals at the location of these markers.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14GlobalWorldSystem))]
|
||||
public sealed partial class CP14GlobalWorldConnectorComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Content.Shared._CP14.Procedural.Prototypes;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Procedural.GlobalWorld.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Generates the surrounding procedural world on the game map, surrounding the mapped settlement.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14GlobalWorldSystem))]
|
||||
public sealed partial class CP14StationGlobalWorldComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public Dictionary<Vector2i, CP14GlobalWorldNode> Nodes = new();
|
||||
|
||||
[DataField]
|
||||
public HashSet<(Vector2i, Vector2i)> Edges = new();
|
||||
|
||||
[DataField]
|
||||
public int LocationCount = 5;
|
||||
|
||||
/// <summary>
|
||||
/// A list of jobName names that are waiting for generation to complete. This is a hack, but I don't know a better way to do it.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<string> LocationInGeneration = new();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class CP14GlobalWorldNode()
|
||||
{
|
||||
public MapId? MapUid;
|
||||
public int Level = 0;
|
||||
|
||||
public ProtoId<CP14ProceduralLocationPrototype>? LocationConfig;
|
||||
public List<ProtoId<CP14ProceduralModifierPrototype>> Modifiers = new();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Content.Shared._CP14.Procedural.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Procedural.GlobalWorld.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Generates the surrounding procedural world on the game map, surrounding the mapped settlement.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14GlobalWorldSystem))]
|
||||
public sealed partial class CP14StationGlobalWorldIntegrationComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14ProceduralLocationPrototype> Location;
|
||||
|
||||
[DataField]
|
||||
public List<ProtoId<CP14ProceduralModifierPrototype>> Modifiers = [];
|
||||
|
||||
[DataField]
|
||||
public Vector2i GenerationOffset = Vector2i.Zero;
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
using Content.Server._CP14.Demiplane;
|
||||
|
||||
namespace Content.Server._CP14.RoundEnd;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14DemiplaneSystem))]
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14MagicContainerRoundFinisherComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Content.Server._CP14.Demiplane;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared.GameTicking;
|
||||
@@ -15,7 +13,6 @@ public sealed partial class CP14RoundEndSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly CP14DemiplaneSystem _demiplane = default!;
|
||||
[Dependency] private readonly RoundEndSystem _roundEnd = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
@@ -49,7 +46,6 @@ public sealed partial class CP14RoundEndSystem : EntitySystem
|
||||
if (_roundEndMoment > _timing.CurTime)
|
||||
return;
|
||||
|
||||
_demiplane.DeleteAllDemiplanes();
|
||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("cp14-round-end"),
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Announce/event_boom.ogg"));
|
||||
_roundEnd.EndRound();
|
||||
|
||||
@@ -18,13 +18,13 @@ public sealed partial class FTLMapComponent : Component
|
||||
/// What parallax to use for the background, immediately gets deffered to ParallaxComponent.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string Parallax = "CP14Ocean"; //CP14 parallax replacement
|
||||
public string Parallax = "Sky"; //CP14 parallax replacement
|
||||
|
||||
/// <summary>
|
||||
/// CP14 FTL map ambient color
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Color AmbientColor = new(34, 90, 122);
|
||||
public Color AmbientColor = new(47, 51, 54);
|
||||
|
||||
/// <summary>
|
||||
/// Can FTL on this map only be done to beacons.
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared._CP14.DemiplaneTraveling;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Interaction;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Demiplane;
|
||||
|
||||
public abstract partial class CP14SharedDemiplaneSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14DemiplaneRiftOpenedComponent, InteractHandEvent>(OnDemiplanePasswayInteract);
|
||||
SubscribeLocalEvent<CP14DemiplaneHintComponent, MapInitEvent>(OnDemiplaneHintMapInit);
|
||||
}
|
||||
|
||||
private void OnDemiplaneHintMapInit(Entity<CP14DemiplaneHintComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14DemiplaneRiftOpenedComponent, TransformComponent>();
|
||||
|
||||
var xformHint = Transform(ent);
|
||||
var hintPos = _transform.GetWorldPosition(xformHint);
|
||||
|
||||
while (query.MoveNext(out _, out _, out var xformRift))
|
||||
{
|
||||
if (xformRift.MapUid != xformHint.MapUid)
|
||||
continue;
|
||||
|
||||
var riftPos = _transform.GetWorldPosition(xformRift);
|
||||
|
||||
//Calculate the rotation
|
||||
Angle angle = new(riftPos - hintPos);
|
||||
|
||||
_transform.SetWorldRotation(ent, angle + Angle.FromDegrees(90));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDemiplanePasswayInteract(Entity<CP14DemiplaneRiftOpenedComponent> passway, ref InteractHandEvent args)
|
||||
{
|
||||
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager,
|
||||
args.User,
|
||||
passway.Comp.DoAfter,
|
||||
new CP14DemiplanPasswayUseDoAfter(),
|
||||
args.Target,
|
||||
args.Target)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnMove = true,
|
||||
BreakOnHandChange = true,
|
||||
NeedHand = true,
|
||||
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]
|
||||
public sealed partial class CP14DemiplanPasswayUseDoAfter : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Shared._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Designates this entity as holding a demiplane.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// All entities in the real world that are connected to this demiplane
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField]
|
||||
public HashSet<EntityUid> ExitPoints = new();
|
||||
|
||||
/// <summary>
|
||||
/// All entities in the demiplane in which the objects entered in the demiplane appear
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField]
|
||||
public HashSet<EntityUid> EntryPoints = new();
|
||||
|
||||
/// <summary>
|
||||
/// The sound of entering a demiplane, played locally to the player who entered it.
|
||||
/// Consider more as an intro sound “You have entered the demiplane. Good luck.”
|
||||
/// </summary>
|
||||
[DataField("arrivalSound")]
|
||||
public SoundSpecifier ArrivalSound = new SoundCollectionSpecifier("CP14DemiplaneIntro");
|
||||
|
||||
/// <summary>
|
||||
/// The sound of exiting the demiplane, played locally to the player who exited the demiplane.
|
||||
/// Consider it more as an ending sound
|
||||
/// </summary>
|
||||
[DataField("departureSound")]
|
||||
public SoundSpecifier DepartureSound = new SoundCollectionSpecifier("CP14DemiplaneIntro");
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
namespace Content.Shared._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// is automatically delete over time if there are no active stabilizers inside this demiplane.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem)), AutoGenerateComponentPause]
|
||||
public sealed partial class CP14DemiplaneDestroyWithoutStabilizationComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// how many time after generation the demiplane cannot be destroyed.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan ProtectedSpawnTime = TimeSpan.FromMinutes(1);
|
||||
|
||||
[DataField]
|
||||
[AutoPausedField]
|
||||
public TimeSpan EndProtectionTime = TimeSpan.Zero;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Shared.Damage;
|
||||
|
||||
namespace Content.Shared._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// When closing the demiplane, all entities with this component will be thrown out instead of being deleted.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneForceExtractComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public bool Enabled = true;
|
||||
|
||||
[DataField]
|
||||
public DamageSpecifier ExtractDamage = new()
|
||||
{
|
||||
DamageDict = new()
|
||||
{
|
||||
{ "Blunt", 111 },
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Content.Shared._CP14.Demiplane.Components;
|
||||
|
||||
using Demiplane;
|
||||
|
||||
/// <summary>
|
||||
/// A very small and silly component that simply turns the entity toward the nearest demiplane rift
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneHintComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
namespace Content.Shared._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// An entity that is the link between the demiplane and the real world. Depending on whether it is in the real world or in the demiplane
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneRiftComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField]
|
||||
public EntityUid? Demiplane;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the map on which this rift is initialized is a demiplane to automatically bind to it. QoL thing.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField]
|
||||
public bool TryAutoLinkToMap = true;
|
||||
|
||||
/// <summary>
|
||||
/// will this rift become one of the random entry or exit points of the demiplane
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField]
|
||||
public bool ActiveTeleport = true;
|
||||
|
||||
[DataField]
|
||||
public bool DeleteAfterDisconnect = true;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace Content.Shared._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Keeps the demiplanes from being destroyed while they're in it.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneStabilizerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// must be a being and be alive to work as a stabilizer
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool RequireAlive = false;
|
||||
|
||||
[DataField]
|
||||
public bool Enabled = true;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._CP14.Demiplane.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Destroy demiplane after time
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause, Access(typeof(CP14SharedDemiplaneSystem))]
|
||||
public sealed partial class CP14DemiplaneTimedDestructionComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public TimeSpan TimeToDestruction = TimeSpan.FromSeconds(240f);
|
||||
|
||||
[DataField, AutoPausedField]
|
||||
public TimeSpan EndTime = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Countdown audio stream.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? Stream = null;
|
||||
|
||||
/// <summary>
|
||||
/// Sound that plays when the demiplane start to collapse.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier Sound = new SoundCollectionSpecifier("ExpeditionEnd")
|
||||
{
|
||||
Params = AudioParams.Default.WithVolume(-5),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Song selected on MapInit so we can predict the audio countdown properly.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundPathSpecifier? SelectedSong;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Demiplane.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Prototype("cp14DemiplaneModifierCategory")]
|
||||
public sealed partial class CP14DemiplaneModifierCategoryPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Content.Shared.Destructible.Thresholds;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Demiplane.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
/// A prototype “Special Demiplane” that can appear on the demiplane map as the final room of a chain of demiplanes.
|
||||
/// It is supposed to be used as a special demiplane with special modifiers, and mining resources and
|
||||
/// equipment from here is the main task of adventurers
|
||||
/// </summary>
|
||||
[Prototype("cp14SpecialDemiplane")]
|
||||
public sealed partial class CP14SpecialDemiplanePrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The difficulty levels at which this location can be generated.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public MinMax Levels = new(1, 10);
|
||||
|
||||
/// <summary>
|
||||
/// The location config that will be used to generate the demiplane. May be null, and if so, the location will be generated using the default way.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<CP14DemiplaneLocationPrototype>? Location;
|
||||
|
||||
/// <summary>
|
||||
/// Modifiers that will be automatically added to the demiplane when it is generated.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<CP14DemiplaneModifierPrototype>> Modifiers = new();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.DemiplaneTraveling;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum CP14DemiplaneMapUiKey
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14DemiplaneMapUiState(Dictionary<Vector2i, CP14DemiplaneMapNode> nodes, HashSet<(Vector2i, Vector2i)>? edges = null) : BoundUserInterfaceState
|
||||
{
|
||||
public Dictionary<Vector2i, CP14DemiplaneMapNode> Nodes = nodes;
|
||||
public HashSet<(Vector2i, Vector2i)> Edges = edges ?? new();
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14DemiplaneMapNode(int level, Vector2 uiPosition, bool start, ProtoId<CP14DemiplaneLocationPrototype>? locationConfig = null, List<ProtoId<CP14DemiplaneModifierPrototype>>? modifiers = null)
|
||||
{
|
||||
public int Level = level;
|
||||
public int AdditionalLevel = 0;
|
||||
public Vector2 UiPosition = uiPosition;
|
||||
public bool Start = start;
|
||||
|
||||
public bool InFrontierZone = false;
|
||||
public bool InUsing = false;
|
||||
public bool Completed = start;
|
||||
|
||||
public ProtoId<CP14DemiplaneLocationPrototype>? LocationConfig = locationConfig;
|
||||
public List<ProtoId<CP14DemiplaneModifierPrototype>> Modifiers = modifiers ?? new();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.DemiplaneTraveling;
|
||||
|
||||
/// <summary>
|
||||
/// Component for opening demiplane map UI and interacting with StationDemiplaneMapComponent
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14DemiplaneNavigationMapComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Extracting coordinates from the demiplane node will create this entity and synchronize its modifiers, location and other parameters.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId KeyProto = "CP14BaseDemiplaneKey";
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier EjectSound = new SoundPathSpecifier("/Audio/Magic/ethereal_exit.ogg");
|
||||
|
||||
[DataField]
|
||||
public DamageSpecifier RevokeDamage = new()
|
||||
{
|
||||
DamageDict = new()
|
||||
{
|
||||
{ "Blunt", 100 },
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Shared._CP14.DemiplaneTraveling;
|
||||
|
||||
/// <summary>
|
||||
/// teleports a certain number of entities between demiplanes with a delay
|
||||
/// </summary>
|
||||
[RegisterComponent, AutoGenerateComponentPause]
|
||||
public sealed partial class CP14DemiplaneRadiusTimedPasswayComponent : 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");
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Shared._CP14.DemiplaneTraveling;
|
||||
|
||||
/// <summary>
|
||||
/// if located on an entity with a CP14DemiplanRiftComponent, allows users to move through that rift via an interaction with doAfter
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14DemiplaneRiftOpenedComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of teleportations this teleporter can make before disappearing. Use the negative number to make infinite.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int MaxUse = -1;
|
||||
|
||||
[DataField]
|
||||
public float DoAfter = 4f;
|
||||
|
||||
[DataField("arrivalSound")]
|
||||
public SoundSpecifier ArrivalSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg");
|
||||
|
||||
[DataField("departureSound")]
|
||||
public SoundSpecifier DepartureSound = new SoundPathSpecifier("/Audio/Effects/teleport_departure.ogg");
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
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");
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.DemiplaneTraveling;
|
||||
|
||||
public abstract partial class CP14SharedStationDemiplaneMapSystem : EntitySystem
|
||||
{
|
||||
public static bool NodeInFronrierZone(Dictionary<Vector2i,CP14DemiplaneMapNode> nodes, HashSet<(Vector2i, Vector2i)> edges, Vector2i key)
|
||||
{
|
||||
if (!nodes.TryGetValue(key, out var node))
|
||||
return false;
|
||||
|
||||
if (node.Completed || node.Start)
|
||||
return false;
|
||||
|
||||
//return false if no finished or start nodes near
|
||||
var near = new List<Vector2i>();
|
||||
foreach (var edge in edges)
|
||||
{
|
||||
var node1 = nodes[edge.Item1];
|
||||
var node2 = nodes[edge.Item2];
|
||||
|
||||
if (node1 != node && node2 != node)
|
||||
continue;
|
||||
|
||||
if (node1.Completed || node1.Start || node2.Completed || node2.Start)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14DemiplaneMapEjectMessage(Vector2i position) : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly Vector2i Position = position;
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14DemiplaneMapRevokeMessage(Vector2i position) : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly Vector2i Position = position;
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Shared.Destructible.Thresholds;
|
||||
|
||||
namespace Content.Shared._CP14.DemiplaneTraveling;
|
||||
|
||||
/// <summary>
|
||||
/// A station component that stores information about the current map of demiplanes, their research status and relationships.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14StationDemiplaneMapComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public Dictionary<Vector2i, CP14DemiplaneMapNode> Nodes = new();
|
||||
|
||||
[DataField]
|
||||
public HashSet<(Vector2i, Vector2i)> Edges = new();
|
||||
|
||||
/// <summary>
|
||||
/// Count of special rooms that can be generated in the demiplane map.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public MinMax Specials = new(30, 30);
|
||||
}
|
||||
@@ -19,6 +19,9 @@ public sealed partial class CP14SpellConsumeManaEffect : CP14SpellEffect
|
||||
|
||||
var targetEntity = args.Target.Value;
|
||||
|
||||
if (!entManager.HasComponent<CP14MagicEnergyContainerComponent>(targetEntity))
|
||||
return;
|
||||
|
||||
var magicEnergy = entManager.System<SharedCP14MagicEnergySystem>();
|
||||
|
||||
//First - used object
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.Shared._CP14.ModularCraft.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Adds all details to the item when initializing. This is useful for spawning modular items directly when mapping or as loot in demiplanes.
|
||||
/// Adds all details to the item when initializing. This is useful for spawning modular items directly when mapping or as loot in dungeons
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedModularCraftSystem))]
|
||||
public sealed partial class CP14ModularCraftAutoAssembleComponent : Component
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Procedural.DungeonLayers;
|
||||
|
||||
[Virtual]
|
||||
public partial class CP14BiomeDunGen : IDunGenLayer
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<BiomeTemplatePrototype> BiomeTemplate;
|
||||
|
||||
/// <summary>
|
||||
/// creates a biome only on the specified tiles
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public HashSet<ProtoId<ContentTileDefinition>>? TileMask;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Procedural.DungeonLayers;
|
||||
|
||||
[Virtual]
|
||||
public partial class CP14ReserveGrid : IDunGenLayer
|
||||
{
|
||||
}
|
||||
@@ -4,13 +4,13 @@ using Content.Shared.Tag;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Demiplane.Prototypes;
|
||||
namespace Content.Shared._CP14.Procedural.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
/// procedural location template. The answer to the question “Where” as far as the combinatorics of the expedition is concerned.
|
||||
/// procedural location template. The answer to the question “Where” as far as the combinatorics of the generation is concerned.
|
||||
/// </summary>
|
||||
[Prototype("cp14DemiplaneLocation")]
|
||||
public sealed partial class CP14DemiplaneLocationPrototype : IPrototype
|
||||
[Prototype("cp14Location")]
|
||||
public sealed partial class CP14ProceduralLocationPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
@@ -18,13 +18,22 @@ public sealed partial class CP14DemiplaneLocationPrototype : IPrototype
|
||||
/// The difficulty levels at which this location can be generated.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public MinMax Levels = new(1, 10);
|
||||
public MinMax Levels = new(0, 10);
|
||||
|
||||
[DataField(required: true)]
|
||||
public ProtoId<DungeonConfigPrototype> LocationConfig;
|
||||
|
||||
/// <summary>
|
||||
/// Components that will be automatically added to the demiplane when it is generated
|
||||
/// This modifier will be added to all adjacent connected locations leading to this location.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14ProceduralModifierPrototype> Connection;
|
||||
|
||||
[DataField]
|
||||
public float GenerationProb = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Components that will be automatically added to the location map when it is generated
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ComponentRegistry Components = new();
|
||||
@@ -34,13 +43,4 @@ public sealed partial class CP14DemiplaneLocationPrototype : IPrototype
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<TagPrototype>> Tags = new();
|
||||
|
||||
[DataField]
|
||||
public LocId? Name;
|
||||
|
||||
[DataField]
|
||||
public float ExamineProb = 0.75f;
|
||||
|
||||
[DataField]
|
||||
public SpriteSpecifier? Icon = null;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Procedural.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Prototype("cp14LocationModifierCategory")]
|
||||
public sealed partial class CP14ProceduralModifierCategoryPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
}
|
||||
@@ -3,13 +3,13 @@ using Content.Shared.Procedural;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Demiplane.Prototypes;
|
||||
namespace Content.Shared._CP14.Procedural.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
/// Demiplane modifier prototype. The answer to the question “Which” in terms of the combinatorics of demiplane generation is
|
||||
/// Location modifier prototype. The answer to the question “What's inside" from the point of view of the combinatorics of creating locations
|
||||
/// </summary>
|
||||
[Prototype("cp14DemiplaneModifier")]
|
||||
public sealed partial class CP14DemiplaneModifierPrototype : IPrototype
|
||||
[Prototype("cp14LocationModifier")]
|
||||
public sealed partial class CP14ProceduralModifierPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
@@ -23,7 +23,7 @@ public sealed partial class CP14DemiplaneModifierPrototype : IPrototype
|
||||
/// Each modifier belongs to specific categories. Used by the generator to determine what to generate
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<CP14DemiplaneModifierCategoryPrototype>, float> Categories = new();
|
||||
public Dictionary<ProtoId<CP14ProceduralModifierCategoryPrototype>, float> Categories = new();
|
||||
|
||||
/// <summary>
|
||||
/// How often can this modifier be generated? Determined by weight from all modifiers available for the location
|
||||
@@ -40,10 +40,10 @@ public sealed partial class CP14DemiplaneModifierPrototype : IPrototype
|
||||
public float GenerationProb = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Can this modifier be generated multiple times within a single demiplane?
|
||||
/// Can this modifier be generated multiple times within a single location?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool Unique = true;
|
||||
public bool Unique = false;
|
||||
|
||||
/// <summary>
|
||||
/// Generation layers that will be added to the location generation after the main layers.
|
||||
@@ -71,7 +71,4 @@ public sealed partial class CP14DemiplaneModifierPrototype : IPrototype
|
||||
|
||||
[DataField]
|
||||
public LocId? Name;
|
||||
|
||||
[DataField]
|
||||
public float ExamineProb = 0.75f;
|
||||
}
|
||||
@@ -1,5 +1,2 @@
|
||||
cp14-gamepreset-resource-harvest = Resource Collection
|
||||
cp14-gamepreset-resource-harvest-desc = Your expedition has been sent to a dangerous place to collect valuable natural resources. Get the necessary materials and return.
|
||||
|
||||
cp14-judge-night-title = Judgment Night
|
||||
cp14-judge-night-desc = Once a decade, a blood moon rises in the heavens, twisting minds and blackening hearts. On this night, brother goes against brother, blood is shed and terrible crimes are committed. Will the curse of the moon consume you tonight? Will you survive this night of judgment?
|
||||
cp14-gamemode-survival-title = Survival
|
||||
cp14-gamemode-survival-description = Your ship is in distress and crashing into wild, dangerous lands. What will you do to survive? Which of you will find the way back to civilization? And who... or what is watching you from the darkness...
|
||||
@@ -1,5 +1,2 @@
|
||||
cp14-gamepreset-resource-harvest = Сбор ресурсов
|
||||
cp14-gamepreset-resource-harvest-desc = Ваша экспедиция была направлена в опасное место для сбора ценных природных ресурсов. Добудьте необходимые материалы, и возвращайтесь.
|
||||
|
||||
cp14-judge-night-title = Судная ночь
|
||||
cp14-judge-night-desc = Раз в десятилетие на небеса восходит кровавая луна, извращая умы и очерняя сердца. В эту ночь брат идет на брата, льется кровь и совершаются ужасные преступления. Поглотит ли вас сегодня проклятье луны? Переживете ли вы эту судную ночь?
|
||||
cp14-gamemode-survival-title = Выживание
|
||||
cp14-gamemode-survival-description = Ваш корабль терпит бедствие и падает в дикие, опасные земли. На что вы пойдете, чтобы выжить? Кто из вас найдет путь обратно в цивилизацию? И кто... или что это наблюдает за вами из темноты...
|
||||
911
Resources/Maps/_CP14/Dungeon/location_connections.yml
Normal file
911
Resources/Maps/_CP14/Dungeon/location_connections.yml
Normal file
@@ -0,0 +1,911 @@
|
||||
meta:
|
||||
format: 7
|
||||
category: Map
|
||||
engineVersion: 264.0.0
|
||||
forkId: ""
|
||||
forkVersion: ""
|
||||
time: 08/02/2025 22:54:12
|
||||
entityCount: 150
|
||||
maps:
|
||||
- 1
|
||||
grids:
|
||||
- 1
|
||||
orphans: []
|
||||
nullspace: []
|
||||
tilemap:
|
||||
0: Space
|
||||
21: CP14FloorBase
|
||||
20: CP14FloorCobblestone
|
||||
25: CP14FloorDirt
|
||||
9: CP14FloorFoundation
|
||||
13: CP14FloorGrass
|
||||
14: CP14FloorGrassLight
|
||||
15: CP14FloorGrassTall
|
||||
26: CP14FloorMycelium
|
||||
27: CP14FloorMyceliumLight
|
||||
10: CP14FloorOakWoodPlanksBig
|
||||
12: CP14FloorOakWoodPlanksBroken
|
||||
11: CP14FloorOakWoodPlanksCruciform
|
||||
22: CP14FloorSnow
|
||||
23: CP14FloorSnowDeep
|
||||
24: CP14FloorSnowDeepDeep
|
||||
17: CP14FloorStonebricks
|
||||
16: CP14FloorStonebricksSmallCarved1
|
||||
19: CP14FloorStonebricksSmallCarved2
|
||||
18: CP14FloorStonebricksSquareCarved
|
||||
2: FloorAsteroidSand
|
||||
6: FloorAsteroidSandUnvariantized
|
||||
5: FloorAsteroidTile
|
||||
8: FloorBrokenWood
|
||||
82: FloorShuttleOrange
|
||||
1: FloorShuttlePurple
|
||||
89: FloorSteel
|
||||
7: FloorWood
|
||||
3: Plating
|
||||
4: PlatingAsteroid
|
||||
entities:
|
||||
- proto: ""
|
||||
entities:
|
||||
- uid: 1
|
||||
components:
|
||||
- type: MetaData
|
||||
- type: Transform
|
||||
- type: Map
|
||||
mapPaused: True
|
||||
- type: GridTree
|
||||
- type: Broadphase
|
||||
- type: OccluderTree
|
||||
- type: MapGrid
|
||||
chunks:
|
||||
-1,-1:
|
||||
ind: -1,-1
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAACAA==
|
||||
version: 7
|
||||
0,0:
|
||||
ind: 0,0
|
||||
tiles: AQAAAAABAAEAAAAAAAABAAAAAAMAFAAAAAACABUAAAAABAAVAAAAAAcAAQAAAAABAAEAAAAAAQABAAAAAAEAFQAAAAAEABUAAAAACwAVAAAAAAUAFQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAAAVAAAAAAoAFQAAAAAEABUAAAAABgAVAAAAAAQAFQAAAAACABUAAAAAAQABAAAAAAEAFQAAAAALABUAAAAABQAVAAAAAAQAFQAAAAANABUAAAAACwAVAAAAAAYAAQAAAAABAAEAAAAAAQAVAAAAAAoAFQAAAAAMABUAAAAABgAUAAAAAAQAFAAAAAAEABUAAAAABwAVAAAAAAsAAQAAAAACABUAAAAACAAVAAAAAAsAFAAAAAADABQAAAAABAAVAAAAAAUAFAAAAAACABUAAAAAAgABAAAAAAEAFAAAAAAAABUAAAAADAAVAAAAAAsAFAAAAAABABUAAAAACAAVAAAAAAcAFQAAAAAFAAEAAAAAAAAVAAAAAAIAFQAAAAACABUAAAAABwAUAAAAAAEAFQAAAAALABUAAAAAAQAVAAAAAAoAAQAAAAAAABUAAAAAAgAVAAAAAAQAFQAAAAADABUAAAAAAAAVAAAAAAkAFQAAAAAFABUAAAAAAQABAAAAAAEAFQAAAAAIABUAAAAABQAVAAAAAAEAFQAAAAANABUAAAAACQAVAAAAAAcAFQAAAAADAAEAAAAAAgAVAAAAAAwAFQAAAAANABUAAAAAAQAVAAAAAAgAFQAAAAAGABUAAAAABQABAAAAAAAAAQAAAAACABUAAAAACwAVAAAAAAYAFAAAAAAEABUAAAAADAAVAAAAAAsAFQAAAAAIAAEAAAAAAAABAAAAAAIAAQAAAAABABUAAAAAAgAVAAAAAA0AFQAAAAAHABUAAAAABgABAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAIAFQAAAAAHABUAAAAADAAVAAAAAAUAFQAAAAACAAEAAAAAAAABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAAAAA0AAAAAAwANAAAAAAMAAQAAAAADAAEAAAAAAgANAAAAAAIAAQAAAAACAAEAAAAAAQANAAAAAAEADQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAAABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAMADQAAAAACAA0AAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAwANAAAAAAUADwAAAAACAA0AAAAAAAANAAAAAAEADQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAAAAA0AAAAABQAOAAAAAAMADwAAAAAAAA8AAAAAAQAOAAAAAAAADQAAAAAFAAEAAAAAAQABAAAAAAEADQAAAAABAA8AAAAAAAAOAAAAAAIADQAAAAACAA0AAAAAAgANAAAAAAQAAQAAAAAAAAEAAAAAAAABAAAAAAMADgAAAAADAA4AAAAAAAAPAAAAAAMADwAAAAACAA8AAAAAAwANAAAAAAIAAQAAAAABAA0AAAAABAAOAAAAAAMADgAAAAAEAA4AAAAAAgAOAAAAAAEADQAAAAACAAEAAAAAAwABAAAAAAEADQAAAAAEAAEAAAAAAAANAAAAAAEADQAAAAADAA4AAAAABAAOAAAAAAIADQAAAAAAAAEAAAAAAQABAAAAAAMADQAAAAABAA4AAAAAAwAPAAAAAAIADwAAAAACAA8AAAAABQANAAAAAAQAAQAAAAACAAEAAAAAAQABAAAAAAEADQAAAAABAA0AAAAAAwABAAAAAAEADQAAAAAFAAEAAAAAAgABAAAAAAIAAQAAAAABAA0AAAAABQAOAAAAAAEADwAAAAAFAA8AAAAAAQAPAAAAAAAADQAAAAAFAAEAAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAMADQAAAAABAA0AAAAAAQANAAAAAAEADQAAAAABAAEAAAAAAAABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAAABAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAACAA==
|
||||
version: 7
|
||||
0,1:
|
||||
ind: 0,1
|
||||
tiles: AQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAAAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAAAAAEAAAAAAQABAAAAAAIAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAAABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAIAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAIAAQAAAAADAAEAAAAAAQABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAQABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAACAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAgABAAAAAAAAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAACAA==
|
||||
version: 7
|
||||
0,-1:
|
||||
ind: 0,-1
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAAAAA==
|
||||
version: 7
|
||||
-1,0:
|
||||
ind: -1,0
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAA==
|
||||
version: 7
|
||||
-1,1:
|
||||
ind: -1,1
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAABAA==
|
||||
version: 7
|
||||
1,-1:
|
||||
ind: 1,-1
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAACAAEAAAAAAAABAAAAAAIAAQAAAAACAA==
|
||||
version: 7
|
||||
1,0:
|
||||
ind: 1,0
|
||||
tiles: AQAAAAACAAEAAAAAAgAWAAAAAAQAFgAAAAABABYAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAEAFgAAAAACABYAAAAABAABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAAAWAAAAAAAAFwAAAAABABcAAAAAAwAXAAAAAAEAFgAAAAAEAAEAAAAAAAABAAAAAAEAGAAAAAAFABcAAAAAAwAXAAAAAAAAFgAAAAAAABYAAAAABAABAAAAAAMAAQAAAAACAAEAAAAAAwAWAAAAAAIAFwAAAAABABcAAAAAAQAYAAAAAAAAFwAAAAABABcAAAAAAwAWAAAAAAMAAQAAAAADABgAAAAABQAYAAAAAAAAGAAAAAAAABgAAAAAAgAWAAAAAAUAFgAAAAAFAAEAAAAAAwABAAAAAAAAFgAAAAACABcAAAAAAwAYAAAAAAMAGAAAAAABABgAAAAAAQAXAAAAAAUAFgAAAAACAAEAAAAAAQAWAAAAAAUAGAAAAAADABgAAAAAAgAYAAAAAAMAGAAAAAAFABYAAAAABQAWAAAAAAUAAQAAAAADABYAAAAAAwAXAAAAAAUAGAAAAAAFABgAAAAAAQAXAAAAAAQAFwAAAAAFABYAAAAABAABAAAAAAAAFgAAAAACABYAAAAAAgAYAAAAAAMAGAAAAAACABgAAAAABAAXAAAAAAUAFgAAAAADAAEAAAAAAgABAAAAAAEAFgAAAAACABcAAAAABAAXAAAAAAQAFgAAAAAFABYAAAAABQAWAAAAAAMAAQAAAAACAAEAAAAAAQAWAAAAAAQAFgAAAAABABcAAAAAAwAXAAAAAAMAFwAAAAABABcAAAAAAAABAAAAAAAAAQAAAAADABYAAAAABAAWAAAAAAAAFgAAAAABABYAAAAABQABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAQAWAAAAAAUAFgAAAAABABYAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAACAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAQABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAEAAQAAAAABAA==
|
||||
version: 7
|
||||
1,1:
|
||||
ind: 1,1
|
||||
tiles: AQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAACAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAAABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAwABAAAAAAEAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAABAA==
|
||||
version: 7
|
||||
-1,2:
|
||||
ind: -1,2
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
version: 7
|
||||
0,2:
|
||||
ind: 0,2
|
||||
tiles: AQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAQABAAAAAAIAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAIAAQAAAAADAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
version: 7
|
||||
1,2:
|
||||
ind: 1,2
|
||||
tiles: AQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
version: 7
|
||||
2,-1:
|
||||
ind: 2,-1
|
||||
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAADAA==
|
||||
version: 7
|
||||
2,0:
|
||||
ind: 2,0
|
||||
tiles: AQAAAAADABkAAAAAAQAaAAAAAAYAGgAAAAABABoAAAAABgAZAAAAAAoAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAACABoAAAAABwAZAAAAAAYAGQAAAAACABoAAAAABAABAAAAAAMAAQAAAAAAAAEAAAAAAgAaAAAAAAIAGgAAAAABABoAAAAABAAaAAAAAAEAGgAAAAAIABkAAAAABgABAAAAAAAAAQAAAAADABkAAAAACQAaAAAAAAsAGgAAAAADABoAAAAACwAZAAAAAAUAGQAAAAADAAEAAAAAAwAaAAAAAAoAGgAAAAALABsAAAAABAAbAAAAAAkAGwAAAAAHABoAAAAACAAaAAAAAAkAAQAAAAADAAEAAAAAAQAaAAAAAAsAGwAAAAAGABsAAAAABgAaAAAAAAkAGgAAAAAGABkAAAAACAABAAAAAAAAGgAAAAAKABsAAAAABAAbAAAAAAEAGwAAAAABABsAAAAAAwAaAAAAAAIAGgAAAAAKAAEAAAAAAgABAAAAAAEAGgAAAAACABoAAAAACgAbAAAAAAsAGwAAAAAJABoAAAAABAABAAAAAAAAAQAAAAAAABkAAAAADwAaAAAAAAYAGwAAAAAGABsAAAAABgAbAAAAAAUAGgAAAAAJAAEAAAAAAwABAAAAAAAAGQAAAAAPABoAAAAACAAbAAAAAAcAGwAAAAAKABsAAAAABQAaAAAAAAsAAQAAAAABAAEAAAAAAQABAAAAAAIAAQAAAAAAABoAAAAACwAZAAAAAAcAGQAAAAAHABoAAAAABQABAAAAAAMAAQAAAAABABkAAAAAAAAaAAAAAAoAGwAAAAALABoAAAAABgAaAAAAAAgAGgAAAAAHAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAgAZAAAAAAYAGQAAAAAAABoAAAAABwABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAAAGgAAAAAIABkAAAAADgAZAAAAAAMAGQAAAAAMAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAACAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAIAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAABAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAABAA==
|
||||
version: 7
|
||||
2,1:
|
||||
ind: 2,1
|
||||
tiles: AQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAAAAQAAAAACAA==
|
||||
version: 7
|
||||
2,2:
|
||||
ind: 2,2
|
||||
tiles: AQAAAAADAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAgABAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAQABAAAAAAIAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAABAAEAAAAAAwABAAAAAAAAAQAAAAABAAEAAAAAAwABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAEAAQAAAAABAAEAAAAAAwABAAAAAAEAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAACAAEAAAAAAQABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAIAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAACAAEAAAAAAQABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAAAAQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
|
||||
version: 7
|
||||
- type: Gravity
|
||||
gravityShakeSound: !type:SoundPathSpecifier
|
||||
path: /Audio/Effects/alert.ogg
|
||||
- type: DecalGrid
|
||||
chunkCollection:
|
||||
version: 2
|
||||
nodes: []
|
||||
- type: SpreaderGrid
|
||||
- type: GridPathfinding
|
||||
- type: RadiationGridResistance
|
||||
- proto: CP14CrystalQuartzWater
|
||||
entities:
|
||||
- uid: 123
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 26.508047,4.3724494
|
||||
parent: 1
|
||||
- uid: 142
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 20.48077,2.4310699
|
||||
parent: 1
|
||||
- proto: CP14FenceBigWooden
|
||||
entities:
|
||||
- uid: 20
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 5.5,11.5
|
||||
parent: 1
|
||||
- uid: 94
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 12.5,10.5
|
||||
parent: 1
|
||||
- uid: 96
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 9.5,10.5
|
||||
parent: 1
|
||||
- uid: 118
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 11.5,10.5
|
||||
parent: 1
|
||||
- uid: 131
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 2.5,8.5
|
||||
parent: 1
|
||||
- proto: CP14GatherableLumiMushroom
|
||||
entities:
|
||||
- uid: 18
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 10.5,2.5
|
||||
parent: 1
|
||||
- uid: 122
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 2.5,2.5
|
||||
parent: 1
|
||||
- proto: CP14MushroomTree1Glowing
|
||||
entities:
|
||||
- uid: 126
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 34.5,0.5
|
||||
parent: 1
|
||||
- proto: CP14MushroomTree2
|
||||
entities:
|
||||
- uid: 128
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 40.5,5.5
|
||||
parent: 1
|
||||
- proto: CP14MushroomTree3
|
||||
entities:
|
||||
- uid: 87
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 33.5,4.5
|
||||
parent: 1
|
||||
- proto: CP14MushroomTree3Glowing
|
||||
entities:
|
||||
- uid: 147
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 42.5,2.5
|
||||
parent: 1
|
||||
- proto: CP14MushroomTree4
|
||||
entities:
|
||||
- uid: 2
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 37.5,2.5
|
||||
parent: 1
|
||||
- uid: 121
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 45.5,0.5
|
||||
parent: 1
|
||||
- proto: CP14RockBig
|
||||
entities:
|
||||
- uid: 6
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 5.5,1.5
|
||||
parent: 1
|
||||
- uid: 46
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 9.5,0.5
|
||||
parent: 1
|
||||
- proto: CP14RockSmall
|
||||
entities:
|
||||
- uid: 38
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 9.5,4.5
|
||||
parent: 1
|
||||
- uid: 72
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 1.5,3.5
|
||||
parent: 1
|
||||
- proto: CP14Snowdrift
|
||||
entities:
|
||||
- uid: 11
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 19.5,2.5
|
||||
parent: 1
|
||||
- uid: 15
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 21.5,2.5
|
||||
parent: 1
|
||||
- uid: 16
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 18.5,5.5
|
||||
parent: 1
|
||||
- uid: 23
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 22.5,4.5
|
||||
parent: 1
|
||||
- uid: 24
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 16.5,2.5
|
||||
parent: 1
|
||||
- uid: 25
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 19.5,5.5
|
||||
parent: 1
|
||||
- uid: 90
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 20.5,1.5
|
||||
parent: 1
|
||||
- proto: CP14SpawnerLocationConnection
|
||||
entities:
|
||||
- uid: 8
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 11.5,3.5
|
||||
parent: 1
|
||||
- uid: 22
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 3.5,11.5
|
||||
parent: 1
|
||||
- uid: 39
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 19.5,3.5
|
||||
parent: 1
|
||||
- uid: 61
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 12.5,13.5
|
||||
parent: 1
|
||||
- uid: 74
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 3.5,3.5
|
||||
parent: 1
|
||||
- uid: 99
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 28.5,5.5
|
||||
parent: 1
|
||||
- uid: 103
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 35.5,3.5
|
||||
parent: 1
|
||||
- uid: 107
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 44.5,5.5
|
||||
parent: 1
|
||||
- proto: CP14WallDirt
|
||||
entities:
|
||||
- uid: 12
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 1.5,10.5
|
||||
parent: 1
|
||||
- uid: 13
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 2.5,13.5
|
||||
parent: 1
|
||||
- uid: 14
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 3.5,9.5
|
||||
parent: 1
|
||||
- uid: 17
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 4.5,9.5
|
||||
parent: 1
|
||||
- uid: 19
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 3.5,8.5
|
||||
parent: 1
|
||||
- uid: 21
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 5.5,12.5
|
||||
parent: 1
|
||||
- uid: 75
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 3.5,12.5
|
||||
parent: 1
|
||||
- uid: 76
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 3.5,13.5
|
||||
parent: 1
|
||||
- uid: 85
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 33.5,3.5
|
||||
parent: 1
|
||||
- uid: 86
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 33.5,2.5
|
||||
parent: 1
|
||||
- uid: 91
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 42.5,1.5
|
||||
parent: 1
|
||||
- uid: 92
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 10.5,8.5
|
||||
parent: 1
|
||||
- uid: 93
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 43.5,5.5
|
||||
parent: 1
|
||||
- uid: 95
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 10.5,10.5
|
||||
parent: 1
|
||||
- uid: 97
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 12.5,14.5
|
||||
parent: 1
|
||||
- uid: 101
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 44.5,6.5
|
||||
parent: 1
|
||||
- uid: 102
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 36.5,3.5
|
||||
parent: 1
|
||||
- uid: 104
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 36.5,2.5
|
||||
parent: 1
|
||||
- uid: 105
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 34.5,2.5
|
||||
parent: 1
|
||||
- uid: 106
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 43.5,0.5
|
||||
parent: 1
|
||||
- uid: 108
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 46.5,1.5
|
||||
parent: 1
|
||||
- uid: 109
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 36.5,4.5
|
||||
parent: 1
|
||||
- uid: 110
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 37.5,4.5
|
||||
parent: 1
|
||||
- uid: 112
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 37.5,3.5
|
||||
parent: 1
|
||||
- uid: 114
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 46.5,2.5
|
||||
parent: 1
|
||||
- uid: 116
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 43.5,6.5
|
||||
parent: 1
|
||||
- uid: 117
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 13.5,14.5
|
||||
parent: 1
|
||||
- uid: 124
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 36.5,5.5
|
||||
parent: 1
|
||||
- uid: 125
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 34.5,1.5
|
||||
parent: 1
|
||||
- uid: 127
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 11.5,14.5
|
||||
parent: 1
|
||||
- uid: 134
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 13.5,13.5
|
||||
parent: 1
|
||||
- uid: 135
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 45.5,5.5
|
||||
parent: 1
|
||||
- uid: 136
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 14.5,13.5
|
||||
parent: 1
|
||||
- uid: 137
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 41.5,2.5
|
||||
parent: 1
|
||||
- uid: 141
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 4.5,12.5
|
||||
parent: 1
|
||||
- uid: 143
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 35.5,4.5
|
||||
parent: 1
|
||||
- uid: 145
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 40.5,4.5
|
||||
parent: 1
|
||||
- uid: 148
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 41.5,1.5
|
||||
parent: 1
|
||||
- uid: 149
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 9.5,8.5
|
||||
parent: 1
|
||||
- uid: 150
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 8.5,9.5
|
||||
parent: 1
|
||||
- proto: CP14WallSnow
|
||||
entities:
|
||||
- uid: 5
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 22.5,2.5
|
||||
parent: 1
|
||||
- uid: 28
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 17.5,3.5
|
||||
parent: 1
|
||||
- uid: 29
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 20.5,0.5
|
||||
parent: 1
|
||||
- uid: 30
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 17.5,1.5
|
||||
parent: 1
|
||||
- uid: 31
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 20.5,4.5
|
||||
parent: 1
|
||||
- uid: 33
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 18.5,0.5
|
||||
parent: 1
|
||||
- uid: 34
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 20.5,3.5
|
||||
parent: 1
|
||||
- uid: 37
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 19.5,6.5
|
||||
parent: 1
|
||||
- uid: 41
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 18.5,4.5
|
||||
parent: 1
|
||||
- uid: 42
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 18.5,3.5
|
||||
parent: 1
|
||||
- uid: 43
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 19.5,4.5
|
||||
parent: 1
|
||||
- uid: 60
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 27.5,5.5
|
||||
parent: 1
|
||||
- uid: 98
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 25.5,2.5
|
||||
parent: 1
|
||||
- uid: 100
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 28.5,3.5
|
||||
parent: 1
|
||||
- uid: 139
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 24.5,4.5
|
||||
parent: 1
|
||||
- proto: CP14WallStone
|
||||
entities:
|
||||
- uid: 7
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 1.5,4.5
|
||||
parent: 1
|
||||
- uid: 10
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 3.5,5.5
|
||||
parent: 1
|
||||
- uid: 35
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 8.5,1.5
|
||||
parent: 1
|
||||
- uid: 47
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 8.5,5.5
|
||||
parent: 1
|
||||
- uid: 48
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 12.5,0.5
|
||||
parent: 1
|
||||
- uid: 49
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 14.5,2.5
|
||||
parent: 1
|
||||
- uid: 50
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 11.5,0.5
|
||||
parent: 1
|
||||
- uid: 51
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 11.5,1.5
|
||||
parent: 1
|
||||
- uid: 52
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 12.5,4.5
|
||||
parent: 1
|
||||
- uid: 53
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 10.5,4.5
|
||||
parent: 1
|
||||
- uid: 54
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 11.5,4.5
|
||||
parent: 1
|
||||
- uid: 55
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 14.5,4.5
|
||||
parent: 1
|
||||
- uid: 56
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 8.5,4.5
|
||||
parent: 1
|
||||
- uid: 57
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 10.5,0.5
|
||||
parent: 1
|
||||
- uid: 58
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 10.5,3.5
|
||||
parent: 1
|
||||
- uid: 59
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 10.5,6.5
|
||||
parent: 1
|
||||
- uid: 65
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 1.5,6.5
|
||||
parent: 1
|
||||
- uid: 66
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 9.5,3.5
|
||||
parent: 1
|
||||
- uid: 67
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 12.5,1.5
|
||||
parent: 1
|
||||
- uid: 68
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 5.5,5.5
|
||||
parent: 1
|
||||
- uid: 69
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 5.5,4.5
|
||||
parent: 1
|
||||
- uid: 70
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 6.5,4.5
|
||||
parent: 1
|
||||
- uid: 71
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 12.5,3.5
|
||||
parent: 1
|
||||
- uid: 73
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 5.5,3.5
|
||||
parent: 1
|
||||
- uid: 77
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 4.5,4.5
|
||||
parent: 1
|
||||
- uid: 78
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 4.5,3.5
|
||||
parent: 1
|
||||
- uid: 79
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 2.5,3.5
|
||||
parent: 1
|
||||
- uid: 80
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 3.5,4.5
|
||||
parent: 1
|
||||
- uid: 81
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 1.5,1.5
|
||||
parent: 1
|
||||
- uid: 82
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 4.5,0.5
|
||||
parent: 1
|
||||
- uid: 83
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 6.5,1.5
|
||||
parent: 1
|
||||
- uid: 84
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 2.5,4.5
|
||||
parent: 1
|
||||
- proto: CP14WindowIceBlock
|
||||
entities:
|
||||
- uid: 3
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 28.5,2.5
|
||||
parent: 1
|
||||
- uid: 4
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 30.5,3.5
|
||||
parent: 1
|
||||
- uid: 9
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 20.5,5.5
|
||||
parent: 1
|
||||
- uid: 26
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 28.5,6.5
|
||||
parent: 1
|
||||
- uid: 27
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 29.5,5.5
|
||||
parent: 1
|
||||
- uid: 32
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 18.5,1.5
|
||||
parent: 1
|
||||
- uid: 36
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 21.5,4.5
|
||||
parent: 1
|
||||
- uid: 40
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 21.5,3.5
|
||||
parent: 1
|
||||
- uid: 44
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 19.5,1.5
|
||||
parent: 1
|
||||
- uid: 45
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 17.5,2.5
|
||||
parent: 1
|
||||
- uid: 62
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 16.5,4.5
|
||||
parent: 1
|
||||
- uid: 63
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 16.5,3.5
|
||||
parent: 1
|
||||
- uid: 64
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 22.5,3.5
|
||||
parent: 1
|
||||
- uid: 88
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 19.5,0.5
|
||||
parent: 1
|
||||
- uid: 89
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 17.5,6.5
|
||||
parent: 1
|
||||
- uid: 111
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 25.5,1.5
|
||||
parent: 1
|
||||
- uid: 113
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 28.5,1.5
|
||||
parent: 1
|
||||
- uid: 115
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 27.5,6.5
|
||||
parent: 1
|
||||
- uid: 119
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 30.5,5.5
|
||||
parent: 1
|
||||
- uid: 120
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 25.5,0.5
|
||||
parent: 1
|
||||
- uid: 129
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 26.5,0.5
|
||||
parent: 1
|
||||
- uid: 130
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 29.5,3.5
|
||||
parent: 1
|
||||
- uid: 132
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 24.5,2.5
|
||||
parent: 1
|
||||
- uid: 133
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 29.5,2.5
|
||||
parent: 1
|
||||
- uid: 138
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 29.5,6.5
|
||||
parent: 1
|
||||
- uid: 140
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 27.5,1.5
|
||||
parent: 1
|
||||
- uid: 144
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 26.5,5.5
|
||||
parent: 1
|
||||
- uid: 146
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 24.5,1.5
|
||||
parent: 1
|
||||
...
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
5445
Resources/Maps/_CP14/nautilus_ship.yml
Normal file
5445
Resources/Maps/_CP14/nautilus_ship.yml
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,7 @@
|
||||
id: AdminInstantEffectFlash
|
||||
suffix: Flash
|
||||
parent: AdminInstantEffectBase
|
||||
categories: [ ForkFiltered ] #Allow in for CE
|
||||
components:
|
||||
- type: FlashOnTrigger
|
||||
range: 7
|
||||
@@ -42,6 +43,7 @@
|
||||
id: AdminInstantEffectSmoke3
|
||||
suffix: Smoke (03 sec)
|
||||
parent: AdminInstantEffectBase
|
||||
categories: [ ForkFiltered ] #Allow in for CE
|
||||
components:
|
||||
- type: SmokeOnTrigger
|
||||
duration: 3
|
||||
@@ -56,6 +58,7 @@
|
||||
id: AdminInstantEffectSmoke10
|
||||
suffix: Smoke (10 sec)
|
||||
parent: AdminInstantEffectBase
|
||||
categories: [ ForkFiltered ] #Allow in for CE
|
||||
components:
|
||||
- type: SmokeOnTrigger
|
||||
duration: 10
|
||||
@@ -70,6 +73,7 @@
|
||||
id: AdminInstantEffectSmoke30
|
||||
suffix: Smoke (30 sec)
|
||||
parent: AdminInstantEffectBase
|
||||
categories: [ ForkFiltered ] #Allow in for CE
|
||||
components:
|
||||
- type: SmokeOnTrigger
|
||||
duration: 30
|
||||
@@ -97,6 +101,7 @@
|
||||
id: AdminInstantEffectGravityWell
|
||||
suffix: Gravity Well
|
||||
parent: AdminInstantEffectBase
|
||||
categories: [ ForkFiltered ] #Allow in for CE
|
||||
components:
|
||||
- type: SoundOnTrigger
|
||||
removeOnTrigger: true
|
||||
|
||||
@@ -125,7 +125,6 @@
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: CP14GuidebookDemiplanes
|
||||
- id: CP14ClothingCloakGuildmasterCape
|
||||
prob: 1
|
||||
- id: CP14ClothingShirtCottonWhite
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
- type: entity
|
||||
id: CP14ActionSpellDemiplaneInfiltration
|
||||
parent: CP14ActionSpellBase
|
||||
name: Demiplane infiltration
|
||||
description: You get inside the demiplane of your choice.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _CP14/Actions/Spells/dimension.rsi
|
||||
state: rift_arrow
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 25
|
||||
- type: CP14MagicEffect
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
- CP14ImpactEffectShadowStep
|
||||
effects:
|
||||
- !type:CP14SpellDemiplaneInfiltration
|
||||
- type: CP14MagicEffectVerbalAspect
|
||||
startSpeech: "Ego intrabo et..."
|
||||
endSpeech: "salvabo socios meos"
|
||||
- type: CP14MagicEffectCastingVisual
|
||||
proto: CP14RuneDemiplaneInfiltration
|
||||
- type: Action
|
||||
icon:
|
||||
sprite: _CP14/Actions/Spells/dimension.rsi
|
||||
state: rift_arrow
|
||||
- type: TargetAction
|
||||
checkCanAccess: true
|
||||
range: 3
|
||||
- type: EntityTargetAction
|
||||
whitelist:
|
||||
components:
|
||||
- CP14DemiplaneRift
|
||||
canTargetSelf: false
|
||||
event: !type:CP14DelayedEntityTargetActionEvent
|
||||
cooldown: 50
|
||||
castDelay: 5
|
||||
distanceThreshold: 3
|
||||
breakOnMove: true
|
||||
|
||||
- type: entity
|
||||
id: CP14RuneDemiplaneInfiltration
|
||||
parent: CP14BaseMagicRune
|
||||
categories: [ HideSpawnMenu ]
|
||||
save: false
|
||||
components:
|
||||
- type: PointLight
|
||||
color: "#5e427e"
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: sun
|
||||
color: "#5e427e"
|
||||
shader: unshaded
|
||||
|
||||
- type: entity
|
||||
parent: CP14BaseSpellScrollDimension
|
||||
id: CP14SpellScrollDemiplaneInfiltration
|
||||
name: demiplane infiltration spell scroll
|
||||
components:
|
||||
- type: CP14SpellStorage
|
||||
spells:
|
||||
- CP14ActionSpellDemiplaneInfiltration
|
||||
@@ -1,76 +0,0 @@
|
||||
- type: entity
|
||||
id: CP14ActionSpellMonolithWarp
|
||||
parent: CP14ActionSpellBase
|
||||
name: Monolith warp
|
||||
description: You open a dimensional rift that transports the creatures around it to the demiplane link crystal
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _CP14/Actions/Spells/dimension.rsi
|
||||
state: demi_arrow
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 25
|
||||
- type: CP14MagicEffect
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
- CP14ImpactEffectShadowStep
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
- CP14GuildmaterTimedTeleport
|
||||
- type: CP14MagicEffectVerbalAspect
|
||||
startSpeech: "Crystal, ego..."
|
||||
endSpeech: "vado ad vos"
|
||||
- type: CP14MagicEffectCastingVisual
|
||||
proto: CP14RuneDemiplaneInfiltration
|
||||
- type: Action
|
||||
icon:
|
||||
sprite: _CP14/Actions/Spells/dimension.rsi
|
||||
state: demi_arrow
|
||||
- type: TargetAction
|
||||
range: 7
|
||||
- type: WorldTargetAction
|
||||
event: !type:CP14DelayedWorldTargetActionEvent
|
||||
cooldown: 50
|
||||
|
||||
- type: entity
|
||||
id: CP14GuildmaterTimedTeleport
|
||||
categories: [ ForkFiltered ]
|
||||
suffix: Teleport to demiplane crystal
|
||||
name: pulsating demiplane rift
|
||||
description: This rift is gaining strength, and will trap all nearby creatures in a demiplane in a second!
|
||||
save: false
|
||||
components:
|
||||
- type: Transform
|
||||
anchored: True
|
||||
- type: Clickable
|
||||
- type: Physics
|
||||
canCollide: false
|
||||
bodyType: Static
|
||||
- type: Sprite
|
||||
drawdepth: Effects
|
||||
sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift.rsi
|
||||
layers:
|
||||
- state: pulse
|
||||
shader: unshaded
|
||||
- type: PointLight
|
||||
radius: 8
|
||||
color: "#5e427e"
|
||||
- type: SingularityDistortion
|
||||
falloffPower: 1.5
|
||||
intensity: 50
|
||||
- type: AmbientSound
|
||||
volume: -3
|
||||
range: 7
|
||||
sound:
|
||||
path: /Audio/Ambience/Objects/gravity_gen_hum.ogg
|
||||
- type: CP14MonolithTimedPassway
|
||||
|
||||
- type: entity
|
||||
parent: CP14BaseSpellScrollDimension
|
||||
id: CP14SpellScrollMonolithWarp
|
||||
name: demiplane link spell scroll
|
||||
components:
|
||||
- type: CP14SpellStorage
|
||||
spells:
|
||||
- CP14ActionSpellMonolithWarp
|
||||
@@ -43,5 +43,4 @@
|
||||
drawdepth: Effects
|
||||
sprite: _CP14/Effects/Magic/cast_impact.rsi
|
||||
noRot: true
|
||||
- type: CP14SpawnOutOfDemiplane
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
- type: entity
|
||||
id: CP14ShipExplosion
|
||||
parent: AdminInstantEffectBase
|
||||
categories: [ ForkFiltered ]
|
||||
suffix: Fire Explosion
|
||||
components:
|
||||
- type: Explosive
|
||||
totalIntensity: 75
|
||||
intensitySlope: 1
|
||||
maxIntensity: 400
|
||||
explosionType: FireBomb
|
||||
- type: ExplodeOnTrigger
|
||||
|
||||
- type: entity
|
||||
id: CP14ShipExplosionBig
|
||||
parent: AdminInstantEffectBase
|
||||
categories: [ ForkFiltered ]
|
||||
suffix: Big Fire Explosion
|
||||
components:
|
||||
- type: Explosive
|
||||
totalIntensity: 90
|
||||
intensitySlope: 0.1
|
||||
maxIntensity: 400
|
||||
explosionType: Default
|
||||
- type: ExplodeOnTrigger
|
||||
- type: FlashOnTrigger
|
||||
range: 30
|
||||
- type: SpawnOnTrigger
|
||||
proto: GrenadeFlashEffect
|
||||
@@ -0,0 +1,36 @@
|
||||
- type: entity
|
||||
parent: MarkerBase
|
||||
id: CP14SpawnerLocationConnection
|
||||
name: Location connection
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: green
|
||||
- sprite: _CP14/Structures/Flora/demiplane_cracks.rsi
|
||||
state: crack
|
||||
- type: CP14GlobalWorldConnector
|
||||
|
||||
- type: entity
|
||||
id: CP14LocationPassway
|
||||
parent: BasePortal
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: location passway
|
||||
description: A gap in space that allows you to travel between worlds.
|
||||
components:
|
||||
- type: Sprite
|
||||
drawdepth: Effects
|
||||
sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift.rsi
|
||||
layers:
|
||||
- state: anom
|
||||
shader: unshaded
|
||||
- type: SingularityDistortion
|
||||
falloffPower: 1.5
|
||||
intensity: 50
|
||||
- type: AmbientSound
|
||||
volume: -3
|
||||
range: 7
|
||||
sound:
|
||||
path: /Audio/Ambience/Objects/gravity_gen_hum.ogg
|
||||
- type: Portal
|
||||
canTeleportToOtherMaps: true
|
||||
@@ -1,12 +0,0 @@
|
||||
- type: entity
|
||||
parent: MarkerBase
|
||||
id: CP14DemiplaneEntryPointMarker
|
||||
name: demiplane entry point
|
||||
categories: [ ForkFiltered ]
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: green
|
||||
- sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift.rsi
|
||||
state: pulse
|
||||
- type: CP14DemiplaneRift
|
||||
@@ -67,7 +67,6 @@
|
||||
types:
|
||||
CP14ManaDepletion: 1
|
||||
- type: CP14ZLevelMover
|
||||
- type: CP14DemiplaneForceExtract
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.CP14ReligionEntityUiKey.Key:
|
||||
|
||||
@@ -213,9 +213,6 @@
|
||||
- type: Tag
|
||||
tags:
|
||||
- FootstepSound
|
||||
- type: CP14DemiplaneForceExtract
|
||||
- type: CP14DemiplaneStabilizer
|
||||
requireAlive: true
|
||||
- type: CP14IgnitionModifier
|
||||
ignitionTimeModifier: 2.5
|
||||
- type: MovementAlwaysTouching
|
||||
|
||||
@@ -112,10 +112,6 @@
|
||||
- type: Inventory
|
||||
templateId: CP14Human
|
||||
- type: TransferMindOnGib
|
||||
- type: CP14DemiplaneForceExtract
|
||||
enabled: false
|
||||
- type: CP14DemiplaneStabilizer
|
||||
enabled: false
|
||||
- type: GhostTakeoverAvailable
|
||||
|
||||
- type: entity
|
||||
|
||||
@@ -39,25 +39,3 @@
|
||||
guides:
|
||||
- CP14_RU_Alchemy
|
||||
- CP14_EN_Alchemy
|
||||
|
||||
- type: entity
|
||||
id: CP14GuidebookDemiplanes
|
||||
parent: CP14GuidebookBase
|
||||
name: demiplane research guide
|
||||
description: "A 20-minute adventure: in and out."
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: paper
|
||||
- state: cover_base
|
||||
color: "#5f1280"
|
||||
- state: decor_frame
|
||||
color: "#ffe269"
|
||||
- state: icon_magic
|
||||
shader: unshaded
|
||||
- state: bookmark_short
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- CP14_RU_Demiplanes
|
||||
- CP14_EN_Demiplanes
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: CP14BaseDemiplaneKey
|
||||
categories: [ ForkFiltered ]
|
||||
name: demiplane coordinate key
|
||||
description: A temporary blob of energy linking the real world and the demiplane. Use it before it dissipates.
|
||||
components:
|
||||
- type: Item
|
||||
size: Ginormous
|
||||
- type: Sprite
|
||||
noRot: true
|
||||
drawdepth: Effects
|
||||
sprite: _CP14/Structures/Dungeon/demiplan_rift_core.rsi
|
||||
layers:
|
||||
- state: coord
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- CP14_RU_Demiplanes
|
||||
- CP14_EN_Demiplanes
|
||||
- type: CP14DemiplaneUsingOpen
|
||||
- type: CP14DemiplaneData
|
||||
selectedModifiers:
|
||||
- DemiplaneDecor
|
||||
- Core
|
||||
- EntryRoom
|
||||
- Exit
|
||||
- type: TimedDespawn
|
||||
lifetime: 120
|
||||
- type: CanMoveInAir
|
||||
- type: RandomWalk
|
||||
minSpeed: 0.25
|
||||
maxSpeed: 0.75
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
bodyStatus: InAir
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.25,-0.25,0.25,0.25"
|
||||
density: 20
|
||||
mask:
|
||||
#- ItemMask # CP14 swap ItemMask to Impassable only
|
||||
- Impassable
|
||||
restitution: 0.3 # fite me
|
||||
friction: 0.2
|
||||
- type: PointLight
|
||||
enabled: true
|
||||
color: "#8f42ff"
|
||||
energy: 1
|
||||
radius: 2
|
||||
netsync: false
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
- CP14ActionSpellShadowStep
|
||||
- CP14ActionSpellShadowGrab
|
||||
- CP14ActionSpellShadowSwap
|
||||
- CP14ActionSpellDemiplaneInfiltration
|
||||
- type: Sprite
|
||||
sprite: _CP14/Objects/Weapons/Magic/TwoHandedStaff/shadow_staff.rsi
|
||||
- type: Clothing
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
- BaseStationAlertLevels
|
||||
- BaseStationRecords # Required for lobby manifest + cryo leave
|
||||
- CP14BaseStationCommonObjectives
|
||||
- CP14BaseStationDemiplaneMap
|
||||
- CP14BaseStationEconomy
|
||||
#- CP14BaseStationGods
|
||||
|
||||
@@ -18,12 +17,6 @@
|
||||
components:
|
||||
- type: CP14StationCommonObjectives
|
||||
|
||||
- type: entity
|
||||
id: CP14BaseStationDemiplaneMap
|
||||
abstract: true
|
||||
components:
|
||||
- type: CP14StationDemiplaneMap
|
||||
|
||||
- type: entity
|
||||
id: CP14BaseStationEconomy
|
||||
abstract: true
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
- type: entity
|
||||
id: CP14DemiplaneHint
|
||||
name: astral crack
|
||||
description: Those cracks always lead to a way out of the damn place
|
||||
categories: [ ForkFiltered ]
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
components:
|
||||
- type: Clickable
|
||||
- type: Sprite
|
||||
sprite: /Textures/_CP14/Structures/Flora/demiplane_cracks.rsi
|
||||
layers:
|
||||
- state: crack3
|
||||
shader: unshaded
|
||||
drawdepth: LowFloors
|
||||
- type: SyncSprite
|
||||
- type: RequiresTile
|
||||
- type: CP14DemiplaneHint
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- 0:
|
||||
crack: ""
|
||||
crack2: ""
|
||||
crack3: ""
|
||||
crack4: ""
|
||||
- type: PointLight
|
||||
netSync: false
|
||||
radius: 1.3
|
||||
color: "#c6529f"
|
||||
energy: 1
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
children:
|
||||
- id: CP14GuidebookImperialLaws
|
||||
- id: CP14GuidebookAlchemy
|
||||
- id: CP14GuidebookDemiplanes
|
||||
#Lore books
|
||||
- !type:GroupSelector
|
||||
children:
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
- type: entity
|
||||
id: CP14DemiplanRiftCore
|
||||
categories: [ ForkFiltered ]
|
||||
name: demiplan rift core
|
||||
description: A subtle connection between the real world and the demiplane where the adventurers went. Sooner or later they will return from there.
|
||||
components:
|
||||
- type: CP14DemiplaneRift
|
||||
- type: Transform
|
||||
anchored: True
|
||||
- type: Clickable
|
||||
- type: Physics
|
||||
canCollide: false
|
||||
bodyType: Static
|
||||
- type: Sprite
|
||||
noRot: true
|
||||
drawdepth: Effects
|
||||
sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift_core.rsi
|
||||
layers:
|
||||
- state: connective
|
||||
shader: unshaded
|
||||
- type: PointLight
|
||||
radius: 2
|
||||
energy: 2
|
||||
color: "#371c5c"
|
||||
netsync: false
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- CP14_RU_Demiplanes
|
||||
- CP14_EN_Demiplanes
|
||||
- type: Speech
|
||||
speechVerb: Ghost
|
||||
|
||||
|
||||
- type: entity
|
||||
id: CP14DemiplaneTimedRadiusPassway
|
||||
parent: CP14DemiplanRiftCore
|
||||
name: pulsating demiplane rift
|
||||
description: This rift is gaining strength, and will trap all nearby creatures in a demiplane in a second!
|
||||
components:
|
||||
- type: CP14DemiplaneRift
|
||||
activeTeleport: false
|
||||
- type: CP14DemiplaneRadiusTimedPassway
|
||||
maxEntities: 4
|
||||
delay: 4
|
||||
- type: Sprite
|
||||
drawdepth: Effects
|
||||
sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift.rsi
|
||||
layers:
|
||||
- state: pulse
|
||||
shader: unshaded
|
||||
- type: PointLight
|
||||
radius: 8
|
||||
- type: SingularityDistortion
|
||||
falloffPower: 1.5
|
||||
intensity: 50
|
||||
- type: AmbientSound
|
||||
volume: -3
|
||||
range: 7
|
||||
sound:
|
||||
path: /Audio/Ambience/Objects/gravity_gen_hum.ogg
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- CP14_RU_Demiplanes
|
||||
- CP14_EN_Demiplanes
|
||||
|
||||
- type: entity
|
||||
id: CP14DemiplanePassway
|
||||
parent: CP14DemiplanRiftCore
|
||||
name: demiplane rift
|
||||
description: A gap in space that allows you to travel between world and demiplanes.
|
||||
components:
|
||||
- type: CP14DemiplaneRiftOpened
|
||||
- type: CP14DemiplaneRift
|
||||
activeTeleport: false
|
||||
- type: Sprite
|
||||
drawdepth: Effects
|
||||
sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift.rsi
|
||||
layers:
|
||||
- state: anom
|
||||
shader: unshaded
|
||||
- type: SingularityDistortion
|
||||
falloffPower: 1.5
|
||||
intensity: 50
|
||||
- type: AmbientSound
|
||||
volume: -3
|
||||
range: 7
|
||||
sound:
|
||||
path: /Audio/Ambience/Objects/gravity_gen_hum.ogg
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- CP14_RU_Demiplanes
|
||||
- CP14_EN_Demiplanes
|
||||
|
||||
- type: entity
|
||||
id: CP14DemiplanePasswayRed
|
||||
parent: CP14DemiplanePassway
|
||||
components:
|
||||
- type: Sprite
|
||||
drawdepth: Effects
|
||||
sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift.rsi
|
||||
layers:
|
||||
- state: anom
|
||||
shader: unshaded
|
||||
color: red
|
||||
- type: PointLight
|
||||
color: red
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
- !type:PulseBehaviour
|
||||
interpolate: Cubic
|
||||
maxDuration: 5
|
||||
startValue: 1.0
|
||||
endValue: 40.0
|
||||
startValue: 0.1
|
||||
endValue: 2.0
|
||||
property: Energy
|
||||
isLooped: true
|
||||
enabled: true
|
||||
@@ -52,15 +52,6 @@
|
||||
range: 10
|
||||
sound:
|
||||
path: /Audio/_CP14/Effects/demiplane_heartbeat.ogg
|
||||
- type: ActivatableUI
|
||||
key: enum.CP14DemiplaneMapUiKey.Key
|
||||
requiresComplex: true
|
||||
singleUser: true
|
||||
- type: CP14DemiplaneNavigationMap
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.CP14DemiplaneMapUiKey.Key:
|
||||
type: CP14DemiplaneMapBoundUserInterface
|
||||
|
||||
- type: entity
|
||||
id: CP14PortalFrameCrystal
|
||||
@@ -112,89 +103,4 @@
|
||||
- type: PointLight
|
||||
color: "#9c34e6"
|
||||
energy: 2.5
|
||||
radius: 8
|
||||
|
||||
- type: entity
|
||||
id: CP14DemiplaneCore
|
||||
categories: [ ForkFiltered ]
|
||||
parent: BaseStructure
|
||||
name: demiplane core
|
||||
description: The heart of the demiplane. Your task is to break it and escape from this place before it collapses.
|
||||
components:
|
||||
- type: CP14DemiplaneCore
|
||||
- type: Transform
|
||||
anchored: true
|
||||
- type: Clickable
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.25,-0.25,0.25,0.25"
|
||||
density: 600
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MidImpassable
|
||||
- LowImpassable
|
||||
- type: Tag
|
||||
tags:
|
||||
- Structure
|
||||
- type: Sprite
|
||||
noRot: true
|
||||
sprite: _CP14/Structures/Specific/Thaumaturgy/energy_monolith_big.rsi
|
||||
layers:
|
||||
- state: dimension_core
|
||||
drawdepth: Mobs
|
||||
offset: 0,0.4
|
||||
- type: PointLight
|
||||
enabled: true
|
||||
color: "#8f42ff"
|
||||
castShadows: false
|
||||
energy: 1
|
||||
radius: 5
|
||||
netsync: false
|
||||
- type: LightBehaviour
|
||||
behaviours:
|
||||
- !type:PulseBehaviour
|
||||
interpolate: Cubic
|
||||
maxDuration: 5
|
||||
startValue: 1.0
|
||||
endValue: 40.0
|
||||
property: Energy
|
||||
isLooped: true
|
||||
enabled: true
|
||||
- type: AmbientSound
|
||||
volume: 5
|
||||
range: 10
|
||||
sound:
|
||||
path: /Audio/_CP14/Effects/demiplane_heartbeat.ogg
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: CP14Rock
|
||||
- type: MeleeSound
|
||||
soundGroups:
|
||||
Brute:
|
||||
collection: GlassSmash
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 50
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: GlassBreak
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
CP14DimensitCrystal:
|
||||
min: 2
|
||||
max: 5
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
CP14SkyLightningPurple:
|
||||
min: 1
|
||||
max: 1
|
||||
radius: 8
|
||||
@@ -32,6 +32,20 @@
|
||||
CP14Innkeeper:
|
||||
- CP14PersonalCurrencyCollectObjectiveGroup
|
||||
|
||||
# crashing
|
||||
|
||||
#- type: entity
|
||||
# id: CP14CrashToWindlandsRule
|
||||
# parent: CP14BaseGameRule
|
||||
# components:
|
||||
# - type: CP14CrashingShipRule
|
||||
# - type: CP14ExpeditionToWindlandsRule
|
||||
# modifiers:
|
||||
# - WeatherInfinityStorm
|
||||
# - MapLightCycleDefault
|
||||
# - Ruins
|
||||
# - Geodes
|
||||
|
||||
# event schedulers
|
||||
|
||||
- type: entity
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user