Files
tbd-station-14/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs
metalgearsloth 816ee2e1ab Gateway destinations (#21040)
* Gateway generation

* Gateway stuff

* gatewehs

* mercenaries

* play area

* Range fixes and tweaks

* weh

* Gateway UI polish

* Lots of fixes

* Knock some items off

* Fix dungeon spawning

Realistically we should probably be using a salvage job.

* wahwah

* wehvs

* expression

* weh

* eee

* a

* a

* WEH

* frfr

* Gatwey

* Fix gateway windows

* Fix gateway windows

* a

* a

* Better layer masking

* a

* a

* Noise fixes

* a

* Fix fractal calculations

* a

* More fixes

* Fixes

* Add layers back in

* Fixes

* namespaces and ftl

* Other TODO

* Fix distance

* Cleanup

* Fix test
2023-11-14 19:23:40 -07:00

235 lines
8.8 KiB
C#

using System.Linq;
using System.Numerics;
using Content.Server.Gateway.Components;
using Content.Server.Parallax;
using Content.Server.Procedural;
using Content.Shared.Dataset;
using Content.Shared.Movement.Components;
using Content.Shared.Parallax.Biomes;
using Content.Shared.Physics;
using Content.Shared.Procedural;
using Content.Shared.Salvage;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Gateway.Systems;
/// <summary>
/// Generates gateway destinations regularly and indefinitely that can be chosen from.
/// </summary>
public sealed class GatewayGeneratorSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
[Dependency] private readonly BiomeSystem _biome = default!;
[Dependency] private readonly DungeonSystem _dungeon = default!;
[Dependency] private readonly FixtureSystem _fixtures = default!;
[Dependency] private readonly GatewaySystem _gateway = default!;
[Dependency] private readonly MetaDataSystem _metadata = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[ValidatePrototypeId<DatasetPrototype>]
private const string PlanetNames = "names_borer";
// TODO:
// Fix shader some more
// Show these in UI
// Use regular mobs for thingo.
// Use salvage mission params
// Add the funny song
// Put salvage params in the UI
// Re-use salvage config stuff for the RNG
// Have it in the UI like expeditions.
// Also add weather coz it's funny.
// Add songs (incl. the downloaded one) to the ambient music playlist for planet probably.
// Copy most of salvage mission spawner
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GatewayGeneratorComponent, EntityUnpausedEvent>(OnGeneratorUnpaused);
SubscribeLocalEvent<GatewayGeneratorComponent, MapInitEvent>(OnGeneratorMapInit);
SubscribeLocalEvent<GatewayGeneratorComponent, ComponentShutdown>(OnGeneratorShutdown);
SubscribeLocalEvent<GatewayGeneratorDestinationComponent, AttemptGatewayOpenEvent>(OnGeneratorAttemptOpen);
SubscribeLocalEvent<GatewayGeneratorDestinationComponent, GatewayOpenEvent>(OnGeneratorOpen);
}
private void OnGeneratorShutdown(EntityUid uid, GatewayGeneratorComponent component, ComponentShutdown args)
{
foreach (var genUid in component.Generated)
{
if (Deleted(genUid))
continue;
QueueDel(genUid);
}
}
private void OnGeneratorUnpaused(Entity<GatewayGeneratorComponent> ent, ref EntityUnpausedEvent args)
{
ent.Comp.NextUnlock += args.PausedTime;
}
private void OnGeneratorMapInit(EntityUid uid, GatewayGeneratorComponent generator, MapInitEvent args)
{
for (var i = 0; i < 3; i++)
{
GenerateDestination(uid, generator);
}
Dirty(uid, generator);
}
private void GenerateDestination(EntityUid uid, GatewayGeneratorComponent? generator = null)
{
if (!Resolve(uid, ref generator))
return;
var tileDef = _tileDefManager["FloorSteel"];
const int MaxOffset = 256;
var tiles = new List<(Vector2i Index, Tile Tile)>();
var seed = _random.Next();
var random = new Random(seed);
var mapId = _mapManager.CreateMap();
var mapUid = _mapManager.GetMapEntityId(mapId);
var origin = new Vector2i(random.Next(-MaxOffset, MaxOffset), random.Next(-MaxOffset, MaxOffset));
var restriction = AddComp<RestrictedRangeComponent>(mapUid);
restriction.Origin = origin;
_biome.EnsurePlanet(mapUid, _protoManager.Index<BiomeTemplatePrototype>("Continental"), seed);
var grid = Comp<MapGridComponent>(mapUid);
for (var x = -2; x <= 2; x++)
{
for (var y = -2; y <= 2; y++)
{
tiles.Add((new Vector2i(x, y) + origin, new Tile(tileDef.TileId, variant: random.NextByte(tileDef.Variants))));
}
}
// Clear area nearby as a sort of landing pad.
_maps.SetTiles(mapUid, grid, tiles);
var gatewayName = SharedSalvageSystem.GetFTLName(_protoManager.Index<DatasetPrototype>(PlanetNames), seed);
_metadata.SetEntityName(mapUid, gatewayName);
var originCoords = new EntityCoordinates(mapUid, origin);
var genDest = AddComp<GatewayGeneratorDestinationComponent>(mapUid);
genDest.Origin = origin;
genDest.Seed = seed;
genDest.Generator = uid;
// Enclose the area
var boundaryUid = Spawn(null, originCoords);
var boundaryPhysics = AddComp<PhysicsComponent>(boundaryUid);
var cShape = new ChainShape();
// Don't need it to be a perfect circle, just need it to be loosely accurate.
cShape.CreateLoop(Vector2.Zero, restriction.Range + 1f, false, count: 4);
_fixtures.TryCreateFixture(
boundaryUid,
cShape,
"boundary",
collisionLayer: (int) (CollisionGroup.HighImpassable | CollisionGroup.Impassable | CollisionGroup.LowImpassable),
body: boundaryPhysics);
_physics.WakeBody(boundaryUid, body: boundaryPhysics);
AddComp<BoundaryComponent>(boundaryUid);
// Create the gateway.
var gatewayUid = SpawnAtPosition(generator.Proto, originCoords);
var gatewayComp = Comp<GatewayComponent>(gatewayUid);
_gateway.SetDestinationName(gatewayUid, FormattedMessage.FromMarkup($"[color=#D381C996]{gatewayName}[/color]"), gatewayComp);
_gateway.SetEnabled(gatewayUid, true, gatewayComp);
generator.Generated.Add(mapUid);
}
private void OnGeneratorAttemptOpen(Entity<GatewayGeneratorDestinationComponent> ent, ref AttemptGatewayOpenEvent args)
{
if (ent.Comp.Loaded || args.Cancelled)
return;
if (!TryComp(ent.Comp.Generator, out GatewayGeneratorComponent? generatorComp))
return;
if (generatorComp.NextUnlock + _metadata.GetPauseTime(ent.Owner) <= _timing.CurTime)
return;
args.Cancelled = true;
}
private void OnGeneratorOpen(Entity<GatewayGeneratorDestinationComponent> ent, ref GatewayOpenEvent args)
{
if (ent.Comp.Loaded)
return;
if (TryComp(ent.Comp.Generator, out GatewayGeneratorComponent? generatorComp))
{
generatorComp.NextUnlock = _timing.CurTime + generatorComp.UnlockCooldown;
_gateway.UpdateAllGateways();
// Generate another destination to keep them going.
GenerateDestination(ent.Comp.Generator);
}
if (!TryComp(args.MapUid, out MapGridComponent? grid))
return;
ent.Comp.Locked = false;
ent.Comp.Loaded = true;
// Do dungeon
var seed = ent.Comp.Seed;
var origin = ent.Comp.Origin;
var random = new Random(seed);
var dungeonDistance = random.Next(3, 6);
var dungeonRotation = _dungeon.GetDungeonRotation(seed);
var dungeonPosition = (origin + dungeonRotation.RotateVec(new Vector2i(0, dungeonDistance))).Floored();
_dungeon.GenerateDungeon(_protoManager.Index<DungeonConfigPrototype>("Experiment"), args.MapUid, grid, dungeonPosition, seed);
// TODO: Dungeon mobs + loot.
// Do markers on the map.
if (TryComp(ent.Owner, out BiomeComponent? biomeComp) && generatorComp != null)
{
// - Loot
var lootLayers = generatorComp.LootLayers.ToList();
for (var i = 0; i < generatorComp.LootLayerCount; i++)
{
var layerIdx = random.Next(lootLayers.Count);
var layer = lootLayers[layerIdx];
lootLayers.RemoveSwap(layerIdx);
_biome.AddMarkerLayer(biomeComp, layer.Id);
}
// - Mobs
var mobLayers = generatorComp.MobLayers.ToList();
for (var i = 0; i < generatorComp.MobLayerCount; i++)
{
var layerIdx = random.Next(mobLayers.Count);
var layer = mobLayers[layerIdx];
mobLayers.RemoveSwap(layerIdx);
_biome.AddMarkerLayer(biomeComp, layer.Id);
}
}
}
}