diff --git a/Content.Client/Shuttles/UI/MapScreen.xaml.cs b/Content.Client/Shuttles/UI/MapScreen.xaml.cs index 225d1be14e..10800b8c5f 100644 --- a/Content.Client/Shuttles/UI/MapScreen.xaml.cs +++ b/Content.Client/Shuttles/UI/MapScreen.xaml.cs @@ -263,9 +263,10 @@ public sealed partial class MapScreen : BoxContainer 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)) @@ -310,7 +311,6 @@ public sealed partial class MapScreen : BoxContainer }; _mapHeadings.Add(mapComp.MapId, gridContents); - foreach (var grid in _mapManager.GetAllMapGrids(mapComp.MapId)) { _entManager.TryGetComponent(grid.Owner, out IFFComponent? iffComp); @@ -327,8 +327,8 @@ public sealed partial class MapScreen : BoxContainer { 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)); } diff --git a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs index f7f3718208..61636bea7c 100644 --- a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs +++ b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs @@ -1,10 +1,16 @@ +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] + public const string CoordinatesDisk = "CoordinatesDisk"; + private void OnSalvageClaimMessage(EntityUid uid, SalvageExpeditionConsoleComponent component, ClaimSalvageMessage args) { var station = _station.GetOwningStation(uid); @@ -15,11 +21,16 @@ public sealed partial class SalvageSystem 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(missionparams.Difficulty), missionparams.Seed); data.NextOffer = _timing.CurTime + mission.Duration + TimeSpan.FromSeconds(1); + + _labelSystem.Label(cdUid, GetFTLName(_prototypeManager.Index("names_borer"), missionparams.Seed)); + _audio.PlayPvs(component.PrintSound, uid); + UpdateConsoles((station.Value, data)); } diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 7e4a9c9310..839730ec87 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -8,6 +8,7 @@ using Content.Shared.Salvage.Expeditions; using Robust.Shared.CPUJob.JobQueues; using Robust.Shared.CPUJob.JobQueues.Queues; using Robust.Shared.GameStates; +using Robust.Shared.Map; namespace Content.Server.Salvage; @@ -148,7 +149,7 @@ public sealed partial class SalvageSystem 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( @@ -162,7 +163,9 @@ public sealed partial class SalvageSystem _biome, _dungeon, _metaData, + _transform, station, + coordinatesDisk, missionParams, cancelToken.Token); diff --git a/Content.Server/Salvage/SalvageSystem.cs b/Content.Server/Salvage/SalvageSystem.cs index a1a3b686b2..9af4736345 100644 --- a/Content.Server/Salvage/SalvageSystem.cs +++ b/Content.Server/Salvage/SalvageSystem.cs @@ -32,6 +32,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map.Components; using Robust.Shared.Timing; +using Content.Server.Labels; namespace Content.Server.Salvage { @@ -39,6 +40,7 @@ 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!; @@ -48,6 +50,7 @@ namespace Content.Server.Salvage [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!; diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index e2b17b5872..180c8d145c 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -33,6 +33,9 @@ using Robust.Shared.Prototypes; 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; @@ -46,8 +49,10 @@ public sealed class SpawnSalvageMissionJob : Job 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; @@ -63,7 +68,9 @@ public sealed class SpawnSalvageMissionJob : Job BiomeSystem biome, DungeonSystem dungeon, MetaDataSystem metaData, + SharedTransformSystem xform, EntityUid station, + EntityUid? coordinatesDisk, SalvageMissionParams missionParams, CancellationToken cancellation = default) : base(maxTime, cancellation) { @@ -75,7 +82,9 @@ public sealed class SpawnSalvageMissionJob : Job _biome = biome; _dungeon = dungeon; _metaData = metaData; + _xforms = xform; Station = station; + CoordinatesDisk = coordinatesDisk; _missionParams = missionParams; _sawmill = logManager.GetSawmill("salvage_job"); #if !DEBUG @@ -94,6 +103,18 @@ public sealed class SpawnSalvageMissionJob : Job var random = new Random(_missionParams.Seed); var destComp = _entManager.AddComponent(mapUid); destComp.BeaconsOnly = true; + destComp.RequireCoordinateDisk = true; + destComp.Enabled = true; + _metaData.SetEntityName(mapUid, SharedSalvageSystem.GetFTLName(_prototypeManager.Index("names_borer"), _missionParams.Seed)); + _entManager.AddComponent(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(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. @@ -144,11 +165,6 @@ public sealed class SpawnSalvageMissionJob : Job 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("names_borer"), _missionParams.Seed)); - _entManager.InitializeAndStartEntity(ftlUid); - var landingPadRadius = 24; var minDungeonOffset = landingPadRadius + 4; diff --git a/Content.Server/Shuttles/Components/EscapePodComponent.cs b/Content.Server/Shuttles/Components/EscapePodComponent.cs index 72c8024e12..d717e97441 100644 --- a/Content.Server/Shuttles/Components/EscapePodComponent.cs +++ b/Content.Server/Shuttles/Components/EscapePodComponent.cs @@ -9,7 +9,7 @@ namespace Content.Server.Shuttles.Components; [RegisterComponent, Access(typeof(EmergencyShuttleSystem)), AutoGenerateComponentPause] public sealed partial class EscapePodComponent : Component { - [DataField("launchTime", customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer:typeof(TimeOffsetSerializer))] [AutoPausedField] public TimeSpan? LaunchTime; } diff --git a/Content.Server/Shuttles/Components/ShuttleConsoleComponent.cs b/Content.Server/Shuttles/Components/ShuttleConsoleComponent.cs index 91cecde044..03e262cef5 100644 --- a/Content.Server/Shuttles/Components/ShuttleConsoleComponent.cs +++ b/Content.Server/Shuttles/Components/ShuttleConsoleComponent.cs @@ -14,5 +14,11 @@ namespace Content.Server.Shuttles.Components /// [DataField("zoom")] public Vector2 Zoom = new(1.5f, 1.5f); + + /// + /// Should this console have access to restricted FTL destinations? + /// + [ViewVariables(VVAccess.ReadWrite), DataField("whitelistSpecific")] + public List FTLWhitelist = new List(); } } diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index a7f83f2e15..c043861b37 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -418,7 +418,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem } 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, }); diff --git a/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.FTL.cs b/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.FTL.cs index 7606d190a4..c214bb015c 100644 --- a/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.FTL.cs +++ b/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.FTL.cs @@ -44,6 +44,10 @@ public sealed partial class ShuttleConsoleSystem } 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)) @@ -128,7 +132,7 @@ public sealed partial class ShuttleConsoleSystem } // Check shuttle can FTL to this target. - if (!_shuttle.CanFTLTo(shuttleUid.Value, targetMap)) + if (!_shuttle.CanFTLTo(shuttleUid.Value, targetMap, ent)) { return; } diff --git a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs index fe4d59b81a..4844a1f3fd 100644 --- a/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs @@ -1,4 +1,5 @@ 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; @@ -30,7 +31,11 @@ public sealed class SalvageExpeditionConsoleState : BoundUserInterfaceState [RegisterComponent, NetworkedComponent] public sealed partial class SalvageExpeditionConsoleComponent : Component { - + /// + /// The sound made when spawning a coordinates disk + /// + [DataField] + public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/terminal_insert_disc.ogg"); } [Serializable, NetSerializable] diff --git a/Content.Shared/Shuttles/Components/FTLDestinationComponent.cs b/Content.Shared/Shuttles/Components/FTLDestinationComponent.cs index 58cff96c2b..d4bc536a29 100644 --- a/Content.Shared/Shuttles/Components/FTLDestinationComponent.cs +++ b/Content.Shared/Shuttles/Components/FTLDestinationComponent.cs @@ -23,4 +23,10 @@ public sealed partial class FTLDestinationComponent : Component /// [DataField, AutoNetworkedField] public bool BeaconsOnly; + + /// + /// Shuttles must use a corresponding CD to travel to this location. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public bool RequireCoordinateDisk = false; } diff --git a/Content.Shared/Shuttles/Components/SharedShuttleConsoleComponent.cs b/Content.Shared/Shuttles/Components/SharedShuttleConsoleComponent.cs index 436c830d20..2ee03210ba 100644 --- a/Content.Shared/Shuttles/Components/SharedShuttleConsoleComponent.cs +++ b/Content.Shared/Shuttles/Components/SharedShuttleConsoleComponent.cs @@ -9,7 +9,7 @@ namespace Content.Shared.Shuttles.Components [NetworkedComponent] public abstract partial class SharedShuttleConsoleComponent : Component { - + public static string DiskSlotName = "disk_slot"; } [Serializable, NetSerializable] diff --git a/Content.Shared/Shuttles/Components/ShuttleDestinationCoordinatesComponent.cs b/Content.Shared/Shuttles/Components/ShuttleDestinationCoordinatesComponent.cs new file mode 100644 index 0000000000..009dee49d1 --- /dev/null +++ b/Content.Shared/Shuttles/Components/ShuttleDestinationCoordinatesComponent.cs @@ -0,0 +1,15 @@ +namespace Content.Shared.Shuttles.Components; +using Robust.Shared.GameStates; + +/// +/// Enables a shuttle to travel to a destination with an item inserted into its console +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ShuttleDestinationCoordinatesComponent : Component +{ + /// + /// Uid for entity containing the FTLDestination component + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public EntityUid? Destination; +} diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs index ca25a49b23..d859d9f485 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.Containers.ItemSlots; using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Components; using Content.Shared.Shuttles.UI.MapObjects; @@ -10,7 +11,8 @@ namespace Content.Shared.Shuttles.Systems; 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!; @@ -34,7 +36,7 @@ public abstract partial class SharedShuttleSystem : EntitySystem /// /// Returns whether an entity can FTL to the specified map. /// - 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; @@ -42,10 +44,40 @@ public abstract partial class SharedShuttleSystem : EntitySystem if (shuttleMap == targetMap) return true; - if (!TryComp(mapUid, out var destination) || - !destination.Enabled) - { + if (!TryComp(mapUid, out var destination) || !destination.Enabled) return false; + + if (destination.RequireCoordinateDisk) + { + if (!TryComp(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(diskCoords.Value, out var diskDestination) || diskDestination != destination) + { + return false; + } + } + else + { + return false; + } } if (HasComp(mapUid)) diff --git a/Resources/Prototypes/Entities/Objects/Misc/cds.yml b/Resources/Prototypes/Entities/Objects/Misc/cds.yml new file mode 100644 index 0000000000..a80a7d1d58 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Misc/cds.yml @@ -0,0 +1,19 @@ +- 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 diff --git a/Resources/Prototypes/Entities/Objects/Misc/diskcases.yml b/Resources/Prototypes/Entities/Objects/Misc/diskcases.yml new file mode 100644 index 0000000000..da86d7a00d --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Misc/diskcases.yml @@ -0,0 +1,21 @@ +- 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 diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 8f58464bd4..5a3dc37582 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -63,6 +63,22 @@ 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 diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 303a9b7c87..961912d609 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -418,6 +418,9 @@ - type: Tag id: ConveyorAssembly +- type: Tag + id: CoordinatesDisk + - type: Tag #Ohioans die happy id: Corn diff --git a/Resources/Textures/Objects/Misc/cd.rsi/icon.png b/Resources/Textures/Objects/Misc/cd.rsi/icon.png new file mode 100644 index 0000000000..346d8c162a Binary files /dev/null and b/Resources/Textures/Objects/Misc/cd.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Misc/cd.rsi/meta.json b/Resources/Textures/Objects/Misc/cd.rsi/meta.json new file mode 100644 index 0000000000..7f5e1ec864 --- /dev/null +++ b/Resources/Textures/Objects/Misc/cd.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by SlamBamActionman", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + } + ] +} diff --git a/Resources/Textures/Objects/Misc/diskcases.rsi/icon_base.png b/Resources/Textures/Objects/Misc/diskcases.rsi/icon_base.png new file mode 100644 index 0000000000..11fb7140ff Binary files /dev/null and b/Resources/Textures/Objects/Misc/diskcases.rsi/icon_base.png differ diff --git a/Resources/Textures/Objects/Misc/diskcases.rsi/icon_cargo.png b/Resources/Textures/Objects/Misc/diskcases.rsi/icon_cargo.png new file mode 100644 index 0000000000..4bee922d75 Binary files /dev/null and b/Resources/Textures/Objects/Misc/diskcases.rsi/icon_cargo.png differ diff --git a/Resources/Textures/Objects/Misc/diskcases.rsi/icon_cc.png b/Resources/Textures/Objects/Misc/diskcases.rsi/icon_cc.png new file mode 100644 index 0000000000..a0dd3a8793 Binary files /dev/null and b/Resources/Textures/Objects/Misc/diskcases.rsi/icon_cc.png differ diff --git a/Resources/Textures/Objects/Misc/diskcases.rsi/meta.json b/Resources/Textures/Objects/Misc/diskcases.rsi/meta.json new file mode 100644 index 0000000000..714b0b19a0 --- /dev/null +++ b/Resources/Textures/Objects/Misc/diskcases.rsi/meta.json @@ -0,0 +1,20 @@ +{ + "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" + } + ] +}