diff --git a/Content.Server/Administration/WarpCommand.cs b/Content.Server/Administration/WarpCommand.cs new file mode 100644 index 0000000000..6152f4ee64 --- /dev/null +++ b/Content.Server/Administration/WarpCommand.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using System.Linq; +using Content.Server.GameObjects.Components.Markers; +using Robust.Server.Interfaces.Console; +using Robust.Server.Interfaces.Player; +using Robust.Shared.Enums; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.IoC; +using Robust.Shared.Map; + +namespace Content.Server.Administration +{ + public class WarpCommand : IClientCommand + { + public string Command => "warp"; + public string Description => "Teleports you to predefined areas on the map."; + + public string Help => + "warp \nLocations you can teleport to are predefined by the map. " + + "You can specify '?' as location to get a list of valid locations."; + + public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + { + if (player == null) + { + shell.SendText((IPlayerSession) null, "Only players can use this command"); + return; + } + + if (args.Length != 1) + { + shell.SendText(player, "Expected a single argument."); + return; + } + + var comp = IoCManager.Resolve(); + var location = args[0]; + if (location == "?") + { + var locations = string.Join(", ", + comp.GetAllComponents() + .Select(p => p.Location) + .Where(p => p != null) + .OrderBy(p => p) + .Distinct()); + + shell.SendText(player, locations); + } + else + { + if (player.Status != SessionStatus.InGame || player.AttachedEntity == null) + { + shell.SendText(player, "You are not in-game!"); + return; + } + + var mapManager = IoCManager.Resolve(); + var currentMap = player.AttachedEntity.Transform.MapID; + var currentGrid = player.AttachedEntity.Transform.GridID; + + var found = comp.GetAllComponents() + .Where(p => p.Location == location) + .Select(p => p.Owner.Transform.GridPosition) + .OrderBy(p => p, Comparer.Create((a, b) => + { + // Sort so that warp points on the same grid/map are first. + // So if you have two maps loaded with the same warp points, + // it will prefer the warp points on the map you're currently on. + if (a.GridID == b.GridID) + { + return 0; + } + + if (a.GridID == currentGrid) + { + return -1; + } + + if (b.GridID == currentGrid) + { + return 1; + } + + var mapA = mapManager.GetGrid(a.GridID).ParentMapId; + var mapB = mapManager.GetGrid(b.GridID).ParentMapId; + + if (mapA == mapB) + { + return 0; + } + + if (mapA == currentMap) + { + return -1; + } + + if (mapB == currentMap) + { + return 1; + } + + return 0; + })) + .FirstOrDefault(); + + if (found.GridID != GridId.Invalid) + { + player.AttachedEntity.Transform.GridPosition = found; + } + else + { + shell.SendText(player, "That location does not exist!"); + } + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Markers/WarpPointComponent.cs b/Content.Server/GameObjects/Components/Markers/WarpPointComponent.cs new file mode 100644 index 0000000000..62cafa7799 --- /dev/null +++ b/Content.Server/GameObjects/Components/Markers/WarpPointComponent.cs @@ -0,0 +1,30 @@ +using Content.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Markers +{ + [RegisterComponent] + public sealed class WarpPointComponent : Component, IExamine + { + public override string Name => "WarpPoint"; + + [ViewVariables(VVAccess.ReadWrite)] public string Location { get; set; } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(this, x => x.Location, "location", null); + } + + public void Examine(FormattedMessage message) + { + var loc = Location == null ? "" : $"'{Location}'"; + message.AddText(Loc.GetString("This one's location ID is {0}", loc)); + } + } +} diff --git a/Resources/Groups/groups.yml b/Resources/Groups/groups.yml index 7e3688ef71..5900002638 100644 --- a/Resources/Groups/groups.yml +++ b/Resources/Groups/groups.yml @@ -70,6 +70,7 @@ - showtime - group - addai + - warp CanViewVar: true CanAdminPlace: true @@ -132,6 +133,7 @@ - saveconfig - gc - gc_mode + - warp CanViewVar: true CanAdminPlace: true CanScript: true diff --git a/Resources/Prototypes/Entities/Markers/marker_base.yml b/Resources/Prototypes/Entities/Markers/marker_base.yml new file mode 100644 index 0000000000..51baba0381 --- /dev/null +++ b/Resources/Prototypes/Entities/Markers/marker_base.yml @@ -0,0 +1,18 @@ +- type: entity + id: MarkerBase + abstract: true + components: + - type: Marker + - type: Clickable + - type: InteractionOutline + - type: Collidable + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: cross_blue + + - type: Icon + sprite: Objects/markers.rsi + state: cross_blue + diff --git a/Resources/Prototypes/Entities/Markers/warp_point.yml b/Resources/Prototypes/Entities/Markers/warp_point.yml new file mode 100644 index 0000000000..7d3c75b19e --- /dev/null +++ b/Resources/Prototypes/Entities/Markers/warp_point.yml @@ -0,0 +1,13 @@ +- type: entity + id: WarpPoint + parent: MarkerBase + name: Warp Point + components: + - type: WarpPoint + - type: Sprite + state: cross_pink + + - type: Icon + state: cross_pink + +