while (mapComps.MoveNext(out var mapComp, out var mapXform, out var mapMetadata))
{
- if (!_shuttles.CanFTLTo(_shuttleEntity.Value, mapComp.MapId))
- continue;
-
+ if (_console != null && !_shuttles.CanFTLTo(_shuttleEntity.Value, mapComp.MapId, _console.Value))
+ {
+ continue;
+ }
var mapName = mapMetadata.EntityName;
if (string.IsNullOrEmpty(mapName))
};
_mapHeadings.Add(mapComp.MapId, gridContents);
-
foreach (var grid in _mapManager.GetAllMapGrids(mapComp.MapId))
{
_entManager.TryGetComponent(grid.Owner, out IFFComponent? iffComp);
{
AddMapObject(mapComp.MapId, gridObj);
}
- else if (iffComp == null ||
- (iffComp.Flags & IFFFlags.Hide) == 0x0)
+ else if (!_shuttles.IsBeaconMap(_mapManager.GetMapEntityId(mapComp.MapId)) && (iffComp == null ||
+ (iffComp.Flags & IFFFlags.Hide) == 0x0))
{
_pendingMapObjects.Add((mapComp.MapId, gridObj));
}
+using Content.Shared.Shuttles.Components;
using Content.Shared.Procedural;
using Content.Shared.Salvage.Expeditions;
+using Content.Shared.Dataset;
+using Robust.Shared.Prototypes;
namespace Content.Server.Salvage;
public sealed partial class SalvageSystem
{
+ [ValidatePrototypeId<EntityPrototype>]
+ public const string CoordinatesDisk = "CoordinatesDisk";
+
private void OnSalvageClaimMessage(EntityUid uid, SalvageExpeditionConsoleComponent component, ClaimSalvageMessage args)
{
var station = _station.GetOwningStation(uid);
if (!data.Missions.TryGetValue(args.Index, out var missionparams))
return;
- SpawnMission(missionparams, station.Value);
+ var cdUid = Spawn(CoordinatesDisk, Transform(uid).Coordinates);
+ SpawnMission(missionparams, station.Value, cdUid);
data.ActiveMission = args.Index;
var mission = GetMission(_prototypeManager.Index<SalvageDifficultyPrototype>(missionparams.Difficulty), missionparams.Seed);
data.NextOffer = _timing.CurTime + mission.Duration + TimeSpan.FromSeconds(1);
+
+ _labelSystem.Label(cdUid, GetFTLName(_prototypeManager.Index<DatasetPrototype>("names_borer"), missionparams.Seed));
+ _audio.PlayPvs(component.PrintSound, uid);
+
UpdateConsoles((station.Value, data));
}
using Robust.Shared.CPUJob.JobQueues;
using Robust.Shared.CPUJob.JobQueues.Queues;
using Robust.Shared.GameStates;
+using Robust.Shared.Map;
namespace Content.Server.Salvage;
return new SalvageExpeditionConsoleState(component.NextOffer, component.Claimed, component.Cooldown, component.ActiveMission, missions);
}
- private void SpawnMission(SalvageMissionParams missionParams, EntityUid station)
+ private void SpawnMission(SalvageMissionParams missionParams, EntityUid station, EntityUid? coordinatesDisk)
{
var cancelToken = new CancellationTokenSource();
var job = new SpawnSalvageMissionJob(
_biome,
_dungeon,
_metaData,
+ _transform,
station,
+ coordinatesDisk,
missionParams,
cancelToken.Token);
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
+using Content.Server.Labels;
namespace Content.Server.Salvage
{
{
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
+ [Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly BiomeSystem _biome = default!;
[Dependency] private readonly DungeonSystem _dungeon = default!;
[Dependency] private readonly GravitySystem _gravity = default!;
+ [Dependency] private readonly LabelSystem _labelSystem = default!;
[Dependency] private readonly MapLoaderSystem _map = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly RadioSystem _radioSystem = default!;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
+using Content.Server.Shuttles.Components;
+using Content.Shared.Coordinates;
+using Content.Shared.Shuttles.Components;
namespace Content.Server.Salvage;
private readonly BiomeSystem _biome;
private readonly DungeonSystem _dungeon;
private readonly MetaDataSystem _metaData;
+ private readonly SharedTransformSystem _xforms;
public readonly EntityUid Station;
+ public readonly EntityUid? CoordinatesDisk;
private readonly SalvageMissionParams _missionParams;
private readonly ISawmill _sawmill;
BiomeSystem biome,
DungeonSystem dungeon,
MetaDataSystem metaData,
+ SharedTransformSystem xform,
EntityUid station,
+ EntityUid? coordinatesDisk,
SalvageMissionParams missionParams,
CancellationToken cancellation = default) : base(maxTime, cancellation)
{
_biome = biome;
_dungeon = dungeon;
_metaData = metaData;
+ _xforms = xform;
Station = station;
+ CoordinatesDisk = coordinatesDisk;
_missionParams = missionParams;
_sawmill = logManager.GetSawmill("salvage_job");
#if !DEBUG
var random = new Random(_missionParams.Seed);
var destComp = _entManager.AddComponent<FTLDestinationComponent>(mapUid);
destComp.BeaconsOnly = true;
+ destComp.RequireCoordinateDisk = true;
+ destComp.Enabled = true;
+ _metaData.SetEntityName(mapUid, SharedSalvageSystem.GetFTLName(_prototypeManager.Index<DatasetPrototype>("names_borer"), _missionParams.Seed));
+ _entManager.AddComponent<FTLBeaconComponent>(mapUid);
+
+ // Saving the mission mapUid to a CD is made optional, in case one is somehow made in a process without a CD entity
+ if (CoordinatesDisk.HasValue)
+ {
+ var cd = _entManager.EnsureComponent<ShuttleDestinationCoordinatesComponent>(CoordinatesDisk.Value);
+ cd.Destination = mapUid;
+ _entManager.Dirty(CoordinatesDisk.Value, cd);
+ }
// Setup mission configs
// As we go through the config the rating will deplete so we'll go for most important to least important.
expedition.EndTime = _timing.CurTime + mission.Duration;
expedition.MissionParams = _missionParams;
- // Don't want consoles to have the incorrect name until refreshed.
- var ftlUid = _entManager.CreateEntityUninitialized("FTLPoint", new EntityCoordinates(mapUid, grid.TileSizeHalfVector));
- _metaData.SetEntityName(ftlUid, SharedSalvageSystem.GetFTLName(_prototypeManager.Index<DatasetPrototype>("names_borer"), _missionParams.Seed));
- _entManager.InitializeAndStartEntity(ftlUid);
-
var landingPadRadius = 24;
var minDungeonOffset = landingPadRadius + 4;
[RegisterComponent, Access(typeof(EmergencyShuttleSystem)), AutoGenerateComponentPause]
public sealed partial class EscapePodComponent : Component
{
- [DataField("launchTime", customTypeSerializer:typeof(TimeOffsetSerializer))]
+ [DataField(customTypeSerializer:typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan? LaunchTime;
}
/// </summary>
[DataField("zoom")]
public Vector2 Zoom = new(1.5f, 1.5f);
+
+ /// <summary>
+ /// Should this console have access to restricted FTL destinations?
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite), DataField("whitelistSpecific")]
+ public List<EntityUid> FTLWhitelist = new List<EntityUid>();
}
}
}
var mapId = _mapManager.CreateMap();
- var grid = _map.LoadGrid(mapId, component.Map.ToString(), new MapLoadOptions()
+ var grid = _map.LoadGrid(mapId, component.Map.ToString(), new MapLoadOptions()
{
LoadMap = false,
});
}
var nCoordinates = new NetCoordinates(GetNetEntity(targetXform.ParentUid), targetXform.LocalPosition);
+ if (targetXform.ParentUid == EntityUid.Invalid)
+ {
+ nCoordinates = new NetCoordinates(GetNetEntity(beaconEnt), targetXform.LocalPosition);
+ }
// Check target exists
if (!_shuttle.CanFTLBeacon(nCoordinates))
}
// Check shuttle can FTL to this target.
- if (!_shuttle.CanFTLTo(shuttleUid.Value, targetMap))
+ if (!_shuttle.CanFTLTo(shuttleUid.Value, targetMap, ent))
{
return;
}
using Content.Shared.Salvage.Expeditions.Modifiers;
+using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
[RegisterComponent, NetworkedComponent]
public sealed partial class SalvageExpeditionConsoleComponent : Component
{
-
+ /// <summary>
+ /// The sound made when spawning a coordinates disk
+ /// </summary>
+ [DataField]
+ public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/terminal_insert_disc.ogg");
}
[Serializable, NetSerializable]
/// </summary>
[DataField, AutoNetworkedField]
public bool BeaconsOnly;
+
+ /// <summary>
+ /// Shuttles must use a corresponding CD to travel to this location.
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
+ public bool RequireCoordinateDisk = false;
}
[NetworkedComponent]
public abstract partial class SharedShuttleConsoleComponent : Component
{
-
+ public static string DiskSlotName = "disk_slot";
}
[Serializable, NetSerializable]
--- /dev/null
+namespace Content.Shared.Shuttles.Components;
+using Robust.Shared.GameStates;
+
+/// <summary>
+/// Enables a shuttle to travel to a destination with an item inserted into its console
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class ShuttleDestinationCoordinatesComponent : Component
+{
+ /// <summary>
+ /// Uid for entity containing the FTLDestination component
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
+ public EntityUid? Destination;
+}
+using Content.Shared.Containers.ItemSlots;
using Content.Shared.Shuttles.BUIStates;
using Content.Shared.Shuttles.Components;
using Content.Shared.Shuttles.UI.MapObjects;
public abstract partial class SharedShuttleSystem : EntitySystem
{
- [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
[Dependency] protected readonly SharedMapSystem Maps = default!;
[Dependency] protected readonly SharedTransformSystem XformSystem = default!;
/// <summary>
/// Returns whether an entity can FTL to the specified map.
/// </summary>
- public bool CanFTLTo(EntityUid shuttleUid, MapId targetMap)
+ public bool CanFTLTo(EntityUid shuttleUid, MapId targetMap, EntityUid consoleUid)
{
var mapUid = _mapManager.GetMapEntityId(targetMap);
var shuttleMap = _xformQuery.GetComponent(shuttleUid).MapID;
if (shuttleMap == targetMap)
return true;
- if (!TryComp<FTLDestinationComponent>(mapUid, out var destination) ||
- !destination.Enabled)
- {
+ if (!TryComp<FTLDestinationComponent>(mapUid, out var destination) || !destination.Enabled)
return false;
+
+ if (destination.RequireCoordinateDisk)
+ {
+ if (!TryComp<ItemSlotsComponent>(consoleUid, out var slot))
+ {
+ return false;
+ }
+
+ if (!_itemSlots.TryGetSlot(consoleUid, SharedShuttleConsoleComponent.DiskSlotName, out var itemSlot, component: slot) || !itemSlot.HasItem)
+ {
+ return false;
+ }
+
+ if (itemSlot.Item is { Valid: true } disk)
+ {
+ ShuttleDestinationCoordinatesComponent? diskCoordinates = null;
+ if (!Resolve(disk, ref diskCoordinates))
+ {
+ return false;
+ }
+
+ var diskCoords = diskCoordinates.Destination;
+
+ if (diskCoords == null || !TryComp<FTLDestinationComponent>(diskCoords.Value, out var diskDestination) || diskDestination != destination)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
}
if (HasComp<FTLMapComponent>(mapUid))
--- /dev/null
+- type: entity
+ name: coordinates disk
+ parent: BaseItem
+ id: CoordinatesDisk
+ description: A disk containing the coordinates to a location in space. Necessary for any FTL-traversing vessel to reach their destination. Fits inside shuttle consoles.
+ components:
+ - type: Sprite
+ sprite: Objects/Misc/cd.rsi
+ state: icon
+ - type: StaticPrice
+ price: 100
+ - type: Tag
+ tags:
+ - CoordinatesDisk
+ - type: DamageOtherOnHit
+ damage:
+ types:
+ Slash: 1
+ - type: ShuttleDestinationCoordinates
--- /dev/null
+- type: entity
+ name: diskcase
+ parent: BaseStorageItem
+ id: DiskCase
+ description: Case for storing a coordinates disk.
+ components:
+ - type: Sprite
+ sprite: Objects/Misc/diskcases.rsi
+ state: icon_base
+ - type: Storage
+ grid:
+ - 0,0,0,1
+ maxItemSize: Normal
+ whitelist:
+ tags:
+ - Document
+ - CoordinatesDisk
+ storageOpenSound: /Audio/Machines/screwdriveropen.ogg
+ storageCloseSound: /Audio/Machines/screwdriverclose.ogg
+ storageInsertSound: /Audio/Items/crowbar.ogg
+ storageRemoveSound: /Audio/Items/crowbar.ogg
color: "#43ccb5"
- type: Rotatable
rotateWhileAnchored: true
+ - type: ItemSlots
+ slots:
+ disk_slot:
+ name: Disk
+ insertSound:
+ path: /Audio/Machines/terminal_insert_disc.ogg
+ ejectSound:
+ path: /Audio/Machines/terminal_insert_disc.ogg
+ whitelist:
+ components:
+ - ShuttleDestinationCoordinates
+ - type: ContainerContainer
+ containers:
+ board: !type:Container
+ ents: []
+ disk_slot: !type:ContainerSlot {}
- type: entity
parent: BaseComputerShuttle
- type: Tag
id: ConveyorAssembly
+- type: Tag
+ id: CoordinatesDisk
+
- type: Tag #Ohioans die happy
id: Corn
--- /dev/null
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Made by SlamBamActionman",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ }
+ ]
+}
--- /dev/null
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Made by SlamBamActionman",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon_base"
+ },
+ {
+ "name": "icon_cc"
+ },
+ {
+ "name": "icon_cargo"
+ }
+ ]
+}