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
This commit is contained in:
234
Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs
Normal file
234
Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using Content.Server.Gateway.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Gateway;
|
||||
using Content.Shared.Popups;
|
||||
@@ -6,9 +8,8 @@ using Content.Shared.Teleportation.Components;
|
||||
using Content.Shared.Teleportation.Systems;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Gateway.Systems;
|
||||
|
||||
@@ -19,6 +20,8 @@ public sealed class GatewaySystem : EntitySystem
|
||||
[Dependency] private readonly LinkedEntitySystem _linkedEntity = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly StationSystem _stations = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
|
||||
@@ -26,62 +29,109 @@ public sealed class GatewaySystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GatewayComponent, EntityUnpausedEvent>(OnGatewayUnpaused);
|
||||
SubscribeLocalEvent<GatewayComponent, ComponentStartup>(OnStartup);
|
||||
SubscribeLocalEvent<GatewayComponent, ActivatableUIOpenAttemptEvent>(OnGatewayOpenAttempt);
|
||||
SubscribeLocalEvent<GatewayComponent, BoundUIOpenedEvent>(UpdateUserInterface);
|
||||
SubscribeLocalEvent<GatewayComponent, GatewayOpenPortalMessage>(OnOpenPortal);
|
||||
|
||||
SubscribeLocalEvent<GatewayDestinationComponent, ComponentStartup>(OnDestinationStartup);
|
||||
SubscribeLocalEvent<GatewayDestinationComponent, ComponentShutdown>(OnDestinationShutdown);
|
||||
SubscribeLocalEvent<GatewayDestinationComponent, GetVerbsEvent<AlternativeVerb>>(OnDestinationGetVerbs);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
public void SetEnabled(EntityUid uid, bool value, GatewayComponent? component = null)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
if (!Resolve(uid, ref component) || component.Enabled == value)
|
||||
return;
|
||||
|
||||
// close portals after theyve been open long enough
|
||||
var query = EntityQueryEnumerator<GatewayComponent, PortalComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp, out var _))
|
||||
{
|
||||
if (_timing.CurTime < comp.NextClose)
|
||||
continue;
|
||||
component.Enabled = value;
|
||||
UpdateAllGateways();
|
||||
}
|
||||
|
||||
ClosePortal(uid, comp);
|
||||
}
|
||||
private void OnGatewayUnpaused(EntityUid uid, GatewayComponent component, ref EntityUnpausedEvent args)
|
||||
{
|
||||
component.NextReady += args.PausedTime;
|
||||
}
|
||||
|
||||
private void OnStartup(EntityUid uid, GatewayComponent comp, ComponentStartup args)
|
||||
{
|
||||
// add existing destinations
|
||||
var query = EntityQueryEnumerator<GatewayDestinationComponent>();
|
||||
while (query.MoveNext(out var dest, out _))
|
||||
{
|
||||
comp.Destinations.Add(dest);
|
||||
}
|
||||
|
||||
// no need to update ui since its just been created, just do portal
|
||||
UpdateAppearance(uid);
|
||||
}
|
||||
|
||||
private void OnGatewayOpenAttempt(EntityUid uid, GatewayComponent component, ref ActivatableUIOpenAttemptEvent args)
|
||||
{
|
||||
if (!component.Enabled || !component.Interactable)
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void UpdateUserInterface<T>(EntityUid uid, GatewayComponent comp, T args)
|
||||
{
|
||||
UpdateUserInterface(uid, comp);
|
||||
}
|
||||
|
||||
private void UpdateUserInterface(EntityUid uid, GatewayComponent comp)
|
||||
public void UpdateAllGateways()
|
||||
{
|
||||
var destinations = new List<(NetEntity, string, TimeSpan, bool)>();
|
||||
foreach (var destUid in comp.Destinations)
|
||||
var query = AllEntityQuery<GatewayComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp, out var xform))
|
||||
{
|
||||
var dest = Comp<GatewayDestinationComponent>(destUid);
|
||||
if (!dest.Enabled)
|
||||
UpdateUserInterface(uid, comp, xform);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateUserInterface(EntityUid uid, GatewayComponent comp, TransformComponent? xform = null)
|
||||
{
|
||||
if (!Resolve(uid, ref xform))
|
||||
return;
|
||||
|
||||
var destinations = new List<GatewayDestinationData>();
|
||||
var query = AllEntityQuery<GatewayComponent, TransformComponent>();
|
||||
|
||||
var nextUnlock = TimeSpan.Zero;
|
||||
var unlockTime = TimeSpan.Zero;
|
||||
|
||||
// Next unlock is based off of:
|
||||
// - Our station's unlock timer (if we have a station)
|
||||
// - If our map is a generated destination then use the generator that made it
|
||||
|
||||
if (TryComp(_stations.GetOwningStation(uid), out GatewayGeneratorComponent? generatorComp) ||
|
||||
(TryComp(xform.MapUid, out GatewayGeneratorDestinationComponent? generatorDestination) &&
|
||||
TryComp(generatorDestination.Generator, out generatorComp)))
|
||||
{
|
||||
nextUnlock = generatorComp.NextUnlock;
|
||||
unlockTime = generatorComp.UnlockCooldown;
|
||||
}
|
||||
|
||||
while (query.MoveNext(out var destUid, out var dest, out var destXform))
|
||||
{
|
||||
if (!dest.Enabled || destUid == uid)
|
||||
continue;
|
||||
|
||||
destinations.Add((GetNetEntity(destUid), dest.Name, dest.NextReady, HasComp<PortalComponent>(destUid)));
|
||||
// Show destination if either no destination comp on the map or it's ours.
|
||||
TryComp<GatewayGeneratorDestinationComponent>(destXform.MapUid, out var gatewayDestination);
|
||||
|
||||
destinations.Add(new GatewayDestinationData()
|
||||
{
|
||||
Entity = GetNetEntity(destUid),
|
||||
// Fallback to grid's ID if applicable.
|
||||
Name = dest.Name.IsEmpty && destXform.GridUid != null ? FormattedMessage.FromUnformatted(MetaData(destXform.GridUid.Value).EntityName) : dest.Name ,
|
||||
Portal = HasComp<PortalComponent>(destUid),
|
||||
// If NextUnlock < CurTime it's unlocked, however
|
||||
// we'll always send the client if it's locked
|
||||
// It can just infer unlock times locally and not have to worry about it here.
|
||||
Locked = gatewayDestination != null && gatewayDestination.Locked
|
||||
});
|
||||
}
|
||||
|
||||
_linkedEntity.GetLink(uid, out var current);
|
||||
var state = new GatewayBoundUserInterfaceState(destinations, GetNetEntity(current), comp.NextClose, comp.LastOpen);
|
||||
|
||||
var state = new GatewayBoundUserInterfaceState(
|
||||
destinations,
|
||||
GetNetEntity(current),
|
||||
comp.NextReady,
|
||||
comp.Cooldown,
|
||||
nextUnlock,
|
||||
unlockTime
|
||||
);
|
||||
|
||||
_ui.TrySetUiState(uid, GatewayUiKey.Key, state);
|
||||
}
|
||||
|
||||
@@ -92,38 +142,58 @@ public sealed class GatewaySystem : EntitySystem
|
||||
|
||||
private void OnOpenPortal(EntityUid uid, GatewayComponent comp, GatewayOpenPortalMessage args)
|
||||
{
|
||||
if (args.Session.AttachedEntity == null)
|
||||
if (args.Session.AttachedEntity == null || GetNetEntity(uid) == args.Destination ||
|
||||
!comp.Enabled || !comp.Interactable)
|
||||
return;
|
||||
|
||||
// if the gateway has an access reader check it before allowing opening
|
||||
var user = args.Session.AttachedEntity.Value;
|
||||
if (CheckAccess(user, uid))
|
||||
if (CheckAccess(user, uid, comp))
|
||||
return;
|
||||
|
||||
// can't link if portal is already open on either side, the destination is invalid or on cooldown
|
||||
var desto = GetEntity(args.Destination);
|
||||
|
||||
if (HasComp<PortalComponent>(uid) ||
|
||||
HasComp<PortalComponent>(desto) ||
|
||||
!TryComp<GatewayDestinationComponent>(desto, out var dest) ||
|
||||
// If it's already open / not enabled / we're not ready DENY.
|
||||
if (!TryComp<GatewayComponent>(desto, out var dest) ||
|
||||
!dest.Enabled ||
|
||||
_timing.CurTime < dest.NextReady)
|
||||
_timing.CurTime < _metadata.GetPauseTime(uid) + comp.NextReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: admin log???
|
||||
ClosePortal(uid, comp, false);
|
||||
OpenPortal(uid, comp, desto, dest);
|
||||
}
|
||||
|
||||
private void OpenPortal(EntityUid uid, GatewayComponent comp, EntityUid dest, GatewayDestinationComponent destComp)
|
||||
private void OpenPortal(EntityUid uid, GatewayComponent comp, EntityUid dest, GatewayComponent destComp, TransformComponent? destXform = null)
|
||||
{
|
||||
_linkedEntity.TryLink(uid, dest);
|
||||
EnsureComp<PortalComponent>(uid).CanTeleportToOtherMaps = true;
|
||||
EnsureComp<PortalComponent>(dest).CanTeleportToOtherMaps = true;
|
||||
if (!Resolve(dest, ref destXform) || destXform.MapUid == null)
|
||||
return;
|
||||
|
||||
var ev = new AttemptGatewayOpenEvent(destXform.MapUid.Value, dest);
|
||||
RaiseLocalEvent(destXform.MapUid.Value, ref ev);
|
||||
|
||||
if (ev.Cancelled)
|
||||
return;
|
||||
|
||||
_linkedEntity.OneWayLink(uid, dest);
|
||||
|
||||
var sourcePortal = EnsureComp<PortalComponent>(uid);
|
||||
var targetPortal = EnsureComp<PortalComponent>(dest);
|
||||
|
||||
sourcePortal.CanTeleportToOtherMaps = true;
|
||||
targetPortal.CanTeleportToOtherMaps = true;
|
||||
|
||||
sourcePortal.RandomTeleport = false;
|
||||
targetPortal.RandomTeleport = false;
|
||||
|
||||
var openEv = new GatewayOpenEvent(destXform.MapUid.Value, dest);
|
||||
RaiseLocalEvent(destXform.MapUid.Value, ref openEv);
|
||||
|
||||
// for ui
|
||||
comp.LastOpen = _timing.CurTime;
|
||||
// close automatically after time is up
|
||||
comp.NextClose = comp.LastOpen + destComp.OpenTime;
|
||||
comp.NextReady = _timing.CurTime + comp.Cooldown;
|
||||
|
||||
_audio.PlayPvs(comp.OpenSound, uid);
|
||||
_audio.PlayPvs(comp.OpenSound, dest);
|
||||
@@ -133,7 +203,7 @@ public sealed class GatewaySystem : EntitySystem
|
||||
UpdateAppearance(dest);
|
||||
}
|
||||
|
||||
private void ClosePortal(EntityUid uid, GatewayComponent? comp = null)
|
||||
private void ClosePortal(EntityUid uid, GatewayComponent? comp = null, bool update = true)
|
||||
{
|
||||
if (!Resolve(uid, ref comp))
|
||||
return;
|
||||
@@ -142,7 +212,7 @@ public sealed class GatewaySystem : EntitySystem
|
||||
if (!_linkedEntity.GetLink(uid, out var dest))
|
||||
return;
|
||||
|
||||
if (TryComp<GatewayDestinationComponent>(dest, out var destComp))
|
||||
if (TryComp<GatewayComponent>(dest, out var destComp))
|
||||
{
|
||||
// portals closed, put it on cooldown and let it eventually be opened again
|
||||
destComp.NextReady = _timing.CurTime + destComp.Cooldown;
|
||||
@@ -153,46 +223,35 @@ public sealed class GatewaySystem : EntitySystem
|
||||
|
||||
_linkedEntity.TryUnlink(uid, dest.Value);
|
||||
RemComp<PortalComponent>(dest.Value);
|
||||
UpdateUserInterface(uid, comp);
|
||||
UpdateAppearance(uid);
|
||||
UpdateAppearance(dest.Value);
|
||||
|
||||
if (update)
|
||||
{
|
||||
UpdateUserInterface(uid, comp);
|
||||
UpdateAppearance(uid);
|
||||
UpdateAppearance(dest.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestinationStartup(EntityUid uid, GatewayDestinationComponent comp, ComponentStartup args)
|
||||
private void OnDestinationStartup(EntityUid uid, GatewayComponent comp, ComponentStartup args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<GatewayComponent>();
|
||||
var query = AllEntityQuery<GatewayComponent>();
|
||||
while (query.MoveNext(out var gatewayUid, out var gateway))
|
||||
{
|
||||
gateway.Destinations.Add(uid);
|
||||
UpdateUserInterface(gatewayUid, gateway);
|
||||
}
|
||||
|
||||
UpdateAppearance(uid);
|
||||
}
|
||||
|
||||
private void OnDestinationShutdown(EntityUid uid, GatewayDestinationComponent comp, ComponentShutdown args)
|
||||
private void OnDestinationShutdown(EntityUid uid, GatewayComponent comp, ComponentShutdown args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<GatewayComponent>();
|
||||
var query = AllEntityQuery<GatewayComponent>();
|
||||
while (query.MoveNext(out var gatewayUid, out var gateway))
|
||||
{
|
||||
gateway.Destinations.Remove(uid);
|
||||
UpdateUserInterface(gatewayUid, gateway);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestinationGetVerbs(EntityUid uid, GatewayDestinationComponent comp, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!comp.Closeable || !args.CanInteract || !args.CanAccess)
|
||||
return;
|
||||
|
||||
// a portal is open so add verb to close it
|
||||
args.Verbs.Add(new AlternativeVerb()
|
||||
{
|
||||
Act = () => TryClose(uid, args.User),
|
||||
Text = Loc.GetString("gateway-close-portal")
|
||||
});
|
||||
}
|
||||
|
||||
private void TryClose(EntityUid uid, EntityUid user)
|
||||
{
|
||||
// portal already closed so cant close it
|
||||
@@ -222,4 +281,31 @@ public sealed class GatewaySystem : EntitySystem
|
||||
_audio.PlayPvs(comp.AccessDeniedSound, uid);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetDestinationName(EntityUid gatewayUid, FormattedMessage gatewayName, GatewayComponent? gatewayComp = null)
|
||||
{
|
||||
if (!Resolve(gatewayUid, ref gatewayComp))
|
||||
return;
|
||||
|
||||
gatewayComp.Name = gatewayName;
|
||||
Dirty(gatewayUid, gatewayComp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed on the target map when a GatewayDestination is attempted to be opened.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct AttemptGatewayOpenEvent(EntityUid MapUid, EntityUid GatewayDestinationUid)
|
||||
{
|
||||
public readonly EntityUid MapUid = MapUid;
|
||||
public readonly EntityUid GatewayDestinationUid = GatewayDestinationUid;
|
||||
|
||||
public bool Cancelled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed on the target map when a gateway is opened.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public readonly record struct GatewayOpenEvent(EntityUid MapUid, EntityUid GatewayDestinationUid);
|
||||
|
||||
Reference in New Issue
Block a user