Files
crystall-punk-14/Content.Server/_CP14/Demiplane/CP14DemiplaneSystem.Station.cs
Red fa22152b42 Demiplane redesign again (again) (#1640)
* rooms generation fix??

* demiplane map returns

* wawa

* fix
2025-08-08 17:37:16 +03:00

174 lines
6.0 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Linq;
using System.Numerics;
using Content.Server._CP14.Demiplane.Components;
using Content.Server.Station.Systems;
using Content.Shared._CP14.Demiplane;
using Content.Shared._CP14.Demiplane.Components;
using Content.Shared._CP14.Procedural.Prototypes;
using Content.Shared.UserInterface;
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._CP14.Demiplane;
public sealed partial class CP14DemiplaneSystem
{
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
[Dependency] private readonly StationSystem _station = default!;
private readonly ProtoId<CP14ProceduralModifierPrototype> _firstPointProto = "DemiplaneArcSingle";
private readonly ProtoId<CP14ProceduralModifierPrototype> _secondPointProto = "CP14DemiplanEnterRoom";
private void InitializeStation()
{
SubscribeLocalEvent<CP14StationDemiplaneMapComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<CP14DemiplaneNavigationMapComponent, BeforeActivatableUIOpenEvent>(
OnBeforeActivatableUiOpen);
}
private void OnMapInit(Entity<CP14StationDemiplaneMapComponent> ent, ref MapInitEvent args)
{
GenerateDemiplaneMap(ent);
}
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 UpdateNodesStatus(Entity<CP14StationDemiplaneMapComponent> ent)
{
var openedMaps = new List<Vector2i>();
var query = EntityQueryEnumerator<CP14DemiplaneMapComponent>();
while (query.MoveNext(out var uid, out var demiplane))
{
openedMaps.Add(demiplane.Position);
}
foreach (var node in ent.Comp.Nodes)
{
node.Value.Opened = openedMaps.Contains(node.Key);
}
}
private void GenerateDemiplaneMap(Entity<CP14StationDemiplaneMapComponent> ent)
{
ent.Comp.Nodes.Clear();
ent.Comp.Edges.Clear();
var directions = new[] { new Vector2i(1, 0), new Vector2i(-1, 0), new Vector2i(0, 1), new Vector2i(0, -1) };
// Generate village node
var villageNode = new CP14DemiplaneMapNode(Vector2.Zero, null, null)
{
Start = true,
};
ent.Comp.Nodes.Add(Vector2i.Zero, villageNode);
// Generate first node
var firstNodePosition = _random.Pick(directions);
var location = SelectLocation(0);
var modifiers = SelectModifiers(0, location, GetLimits(0));
var firstNode = new CP14DemiplaneMapNode(firstNodePosition, location, modifiers)
{
Opened = true
};
firstNode.Modifiers.Add(_secondPointProto);
ent.Comp.Nodes.Add(firstNodePosition, firstNode);
ent.Comp.Edges.Add((Vector2i.Zero, firstNodePosition));
//In a loop, take a random existing node, find an empty spot next to it on the grid, add a new room there, and connect them.
while (ent.Comp.Nodes.Count < ent.Comp.TotalCount)
{
//Get random existing node
var randomNode = _random.Pick(ent.Comp.Nodes);
if (randomNode.Value.Start)
continue;
var randomNodePosition = randomNode.Key;
// Find a random empty adjacent position
var emptyPositions = directions
.Select(dir => randomNodePosition + dir)
.Where(pos => !ent.Comp.Nodes.ContainsKey(pos))
.ToList();
if (emptyPositions.Count == 0)
continue;
var newPosition = emptyPositions[_random.Next(emptyPositions.Count)];
// Add the new node and connect it with an edge
var lvl = randomNode.Value.Level + 1;
location = SelectLocation(lvl);
modifiers = SelectModifiers(lvl, location, GetLimits(lvl));
var newNode = new CP14DemiplaneMapNode(newPosition, location, modifiers)
{
Level = lvl,
};
ent.Comp.Nodes[newPosition] = newNode;
ent.Comp.Edges.Add((randomNodePosition, newPosition));
randomNode.Value.Modifiers.Add(_firstPointProto);
newNode.Modifiers.Add(_secondPointProto);
}
foreach (var (position, node) in ent.Comp.Nodes)
{
//Random minor UI offset
node.UiPosition += new Vector2(
_random.NextFloat(-0.2f, 0.2f),
_random.NextFloat(-0.2f, 0.2f));
}
}
private Dictionary<ProtoId<CP14ProceduralModifierCategoryPrototype>, float> GetLimits(int level)
{
return new Dictionary<ProtoId<CP14ProceduralModifierCategoryPrototype>, float>
{
{ "Danger", Math.Max(level * 0.2f, 0.5f) },
{ "GhostRoleDanger", 1f },
{ "Reward", Math.Max(level * 0.3f, 0.5f) },
{ "Ore", Math.Max(level * 0.5f, 1f) },
{ "Fun", 1f },
{ "Weather", 1f },
{ "MapLight", 1f },
};
}
private Vector2i? GetRandomNeighbourNotGeneratedMap(Entity<CP14StationDemiplaneMapComponent> ent, Vector2i origin)
{
if (!ent.Comp.Nodes.ContainsKey(origin))
return null;
//Проверить, есть ли у этой ноды исходящие ребра
var paths = new List<Vector2i>();
foreach (var edge in ent.Comp.Edges)
{
if (edge.Item1 == origin && !ent.Comp.GeneratedNodes.Contains(edge.Item2))
paths.Add(edge.Item2);
}
if (paths.Count == 0)
return null;
return _random.Pick(paths);
}
}