Add shortcut to flip for construction menu (#14152)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -46,6 +46,8 @@ namespace Content.Client.Construction
|
||||
new PointerInputCmdHandler(HandleOpenCraftingMenu))
|
||||
.Bind(EngineKeyFunctions.Use,
|
||||
new PointerInputCmdHandler(HandleUse, outsidePrediction: true))
|
||||
.Bind(ContentKeyFunctions.EditorFlipObject,
|
||||
new PointerInputCmdHandler(HandleFlip))
|
||||
.Register<ConstructionSystem>();
|
||||
|
||||
SubscribeLocalEvent<ConstructionGhostComponent, ExaminedEvent>(HandleConstructionGhostExamined);
|
||||
@@ -99,6 +101,7 @@ namespace Content.Client.Construction
|
||||
public event EventHandler<CraftingAvailabilityChangedArgs>? CraftingAvailabilityChanged;
|
||||
public event EventHandler<string>? ConstructionGuideAvailable;
|
||||
public event EventHandler? ToggleCraftingWindow;
|
||||
public event EventHandler? FlipConstructionPrototype;
|
||||
|
||||
private void HandleAckStructure(AckStructureConstructionMessage msg)
|
||||
{
|
||||
@@ -118,6 +121,13 @@ namespace Content.Client.Construction
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleFlip(in PointerInputCmdHandler.PointerInputCmdArgs args)
|
||||
{
|
||||
if (args.State == BoundKeyState.Down)
|
||||
FlipConstructionPrototype?.Invoke(this, EventArgs.Empty);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateCraftingAvailability(bool available)
|
||||
{
|
||||
if (CraftingEnabled == available)
|
||||
|
||||
@@ -148,6 +148,9 @@ namespace Content.Client.Construction.UI
|
||||
|
||||
foreach (var recipe in _prototypeManager.EnumeratePrototypes<ConstructionPrototype>())
|
||||
{
|
||||
if (recipe.Hide)
|
||||
continue;
|
||||
|
||||
if (!string.IsNullOrEmpty(search))
|
||||
{
|
||||
if (!recipe.Name.ToLowerInvariant().Contains(search.Trim().ToLowerInvariant()))
|
||||
@@ -342,6 +345,7 @@ namespace Content.Client.Construction.UI
|
||||
{
|
||||
_constructionSystem = system;
|
||||
system.ToggleCraftingWindow += SystemOnToggleMenu;
|
||||
system.FlipConstructionPrototype += SystemFlipConstructionPrototype;
|
||||
system.CraftingAvailabilityChanged += SystemCraftingAvailabilityChanged;
|
||||
system.ConstructionGuideAvailable += SystemGuideAvailable;
|
||||
if (_uiManager.GetActiveUIWidgetOrNull<GameTopMenuBar>() != null)
|
||||
@@ -358,6 +362,7 @@ namespace Content.Client.Construction.UI
|
||||
throw new InvalidOperationException();
|
||||
|
||||
system.ToggleCraftingWindow -= SystemOnToggleMenu;
|
||||
system.FlipConstructionPrototype -= SystemFlipConstructionPrototype;
|
||||
system.CraftingAvailabilityChanged -= SystemCraftingAvailabilityChanged;
|
||||
system.ConstructionGuideAvailable -= SystemGuideAvailable;
|
||||
_constructionSystem = null;
|
||||
@@ -392,6 +397,22 @@ namespace Content.Client.Construction.UI
|
||||
}
|
||||
}
|
||||
|
||||
private void SystemFlipConstructionPrototype(object? sender, EventArgs eventArgs)
|
||||
{
|
||||
if (!_placementManager.IsActive || _placementManager.Eraser)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_selected == null || _selected.Mirror == String.Empty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_selected = _prototypeManager.Index<ConstructionPrototype>(_selected.Mirror);
|
||||
UpdateGhostPlacement();
|
||||
}
|
||||
|
||||
private void SystemGuideAvailable(object? sender, string e)
|
||||
{
|
||||
if (!CraftingAvailable)
|
||||
|
||||
@@ -37,6 +37,9 @@ namespace Content.Client.Input
|
||||
// Not in engine, because engine cannot check for sanbox/admin status before starting placement.
|
||||
common.AddFunction(ContentKeyFunctions.EditorCopyObject);
|
||||
|
||||
// Not in engine because the engine doesn't understand what a flipped object is
|
||||
common.AddFunction(ContentKeyFunctions.EditorFlipObject);
|
||||
|
||||
var human = contexts.GetContext("human");
|
||||
human.AddFunction(EngineKeyFunctions.MoveUp);
|
||||
human.AddFunction(EngineKeyFunctions.MoveDown);
|
||||
|
||||
@@ -184,6 +184,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
AddButton(EngineKeyFunctions.EditorGridPlace);
|
||||
AddButton(EngineKeyFunctions.EditorLinePlace);
|
||||
AddButton(EngineKeyFunctions.EditorRotateObject);
|
||||
AddButton(ContentKeyFunctions.EditorFlipObject);
|
||||
AddButton(ContentKeyFunctions.EditorCopyObject);
|
||||
|
||||
AddHeader("ui-options-header-dev");
|
||||
|
||||
@@ -3,86 +3,96 @@ using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Construction.Prototypes
|
||||
namespace Content.Shared.Construction.Prototypes;
|
||||
|
||||
[Prototype("construction")]
|
||||
public sealed class ConstructionPrototype : IPrototype
|
||||
{
|
||||
[Prototype("construction")]
|
||||
public sealed class ConstructionPrototype : IPrototype
|
||||
{
|
||||
[DataField("conditions")] private List<IConstructionCondition> _conditions = new();
|
||||
[DataField("conditions")] private List<IConstructionCondition> _conditions = new();
|
||||
|
||||
/// <summary>
|
||||
/// Friendly name displayed in the construction GUI.
|
||||
/// </summary>
|
||||
[DataField("name")]
|
||||
public string Name { get; } = string.Empty;
|
||||
/// <summary>
|
||||
/// Hide from the construction list
|
||||
/// </summary>
|
||||
[DataField("hide")]
|
||||
public bool Hide = false;
|
||||
|
||||
/// <summary>
|
||||
/// "Useful" description displayed in the construction GUI.
|
||||
/// </summary>
|
||||
[DataField("description")]
|
||||
public string Description { get; } = string.Empty;
|
||||
/// <summary>
|
||||
/// Friendly name displayed in the construction GUI.
|
||||
/// </summary>
|
||||
[DataField("name")]
|
||||
public string Name= string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ConstructionGraphPrototype"/> this construction will be using.
|
||||
/// </summary>
|
||||
[DataField("graph", customTypeSerializer:typeof(PrototypeIdSerializer<ConstructionGraphPrototype>))]
|
||||
public string Graph { get; } = string.Empty;
|
||||
/// <summary>
|
||||
/// "Useful" description displayed in the construction GUI.
|
||||
/// </summary>
|
||||
[DataField("description")]
|
||||
public string Description = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The target <see cref="ConstructionGraphNode"/> this construction will guide the user to.
|
||||
/// </summary>
|
||||
[DataField("targetNode")]
|
||||
public string TargetNode { get; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The <see cref="ConstructionGraphPrototype"/> this construction will be using.
|
||||
/// </summary>
|
||||
[DataField("graph", customTypeSerializer:typeof(PrototypeIdSerializer<ConstructionGraphPrototype>))]
|
||||
public string Graph = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The starting <see cref="ConstructionGraphNode"/> this construction will start at.
|
||||
/// </summary>
|
||||
[DataField("startNode")]
|
||||
public string StartNode { get; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The target <see cref="ConstructionGraphNode"/> this construction will guide the user to.
|
||||
/// </summary>
|
||||
[DataField("targetNode")]
|
||||
public string TargetNode = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Texture path inside the construction GUI.
|
||||
/// </summary>
|
||||
[DataField("icon")]
|
||||
public SpriteSpecifier Icon { get; } = SpriteSpecifier.Invalid;
|
||||
/// <summary>
|
||||
/// The starting <see cref="ConstructionGraphNode"/> this construction will start at.
|
||||
/// </summary>
|
||||
[DataField("startNode")]
|
||||
public string StartNode = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Texture paths used for the construction ghost.
|
||||
/// </summary>
|
||||
[DataField("layers")]
|
||||
private List<SpriteSpecifier>? _layers;
|
||||
/// <summary>
|
||||
/// Texture path inside the construction GUI.
|
||||
/// </summary>
|
||||
[DataField("icon")]
|
||||
public SpriteSpecifier Icon = SpriteSpecifier.Invalid;
|
||||
|
||||
/// <summary>
|
||||
/// If you can start building or complete steps on impassable terrain.
|
||||
/// </summary>
|
||||
[DataField("canBuildInImpassable")]
|
||||
public bool CanBuildInImpassable { get; private set; }
|
||||
/// <summary>
|
||||
/// Texture paths used for the construction ghost.
|
||||
/// </summary>
|
||||
[DataField("layers")]
|
||||
private List<SpriteSpecifier>? _layers;
|
||||
|
||||
[DataField("category")] public string Category { get; private set; } = "";
|
||||
/// <summary>
|
||||
/// If you can start building or complete steps on impassable terrain.
|
||||
/// </summary>
|
||||
[DataField("canBuildInImpassable")]
|
||||
public bool CanBuildInImpassable { get; private set; }
|
||||
|
||||
[DataField("objectType")] public ConstructionType Type { get; private set; } = ConstructionType.Structure;
|
||||
[DataField("category")] public string Category { get; private set; } = "";
|
||||
|
||||
[ViewVariables]
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
[DataField("objectType")] public ConstructionType Type { get; private set; } = ConstructionType.Structure;
|
||||
|
||||
[DataField("placementMode")]
|
||||
public string PlacementMode { get; } = "PlaceFree";
|
||||
[ViewVariables]
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this construction can be constructed rotated or not.
|
||||
/// </summary>
|
||||
[DataField("canRotate")]
|
||||
public bool CanRotate { get; } = true;
|
||||
[DataField("placementMode")]
|
||||
public string PlacementMode = "PlaceFree";
|
||||
|
||||
public IReadOnlyList<IConstructionCondition> Conditions => _conditions;
|
||||
public IReadOnlyList<SpriteSpecifier> Layers => _layers ?? new List<SpriteSpecifier>{Icon};
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether this construction can be constructed rotated or not.
|
||||
/// </summary>
|
||||
[DataField("canRotate")]
|
||||
public bool CanRotate = true;
|
||||
|
||||
public enum ConstructionType
|
||||
{
|
||||
Structure,
|
||||
Item,
|
||||
}
|
||||
/// <summary>
|
||||
/// Construction to replace this construction with when the current one is 'flipped'
|
||||
/// </summary>
|
||||
[DataField("mirror", customTypeSerializer:typeof(PrototypeIdSerializer<ConstructionPrototype>))]
|
||||
public string Mirror = string.Empty;
|
||||
|
||||
public IReadOnlyList<IConstructionCondition> Conditions => _conditions;
|
||||
public IReadOnlyList<SpriteSpecifier> Layers => _layers ?? new List<SpriteSpecifier>{Icon};
|
||||
}
|
||||
|
||||
public enum ConstructionType
|
||||
{
|
||||
Structure,
|
||||
Item,
|
||||
}
|
||||
|
||||
@@ -111,5 +111,6 @@ namespace Content.Shared.Input
|
||||
public static readonly BoundKeyFunction Vote8 = "Vote8";
|
||||
public static readonly BoundKeyFunction Vote9 = "Vote9";
|
||||
public static readonly BoundKeyFunction EditorCopyObject = "EditorCopyObject";
|
||||
public static readonly BoundKeyFunction EditorFlipObject = "EditorFlipObject";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ ui-options-function-editor-cancel-place = Cancel placement
|
||||
ui-options-function-editor-grid-place = Place in grid
|
||||
ui-options-function-editor-line-place = Place line
|
||||
ui-options-function-editor-rotate-object = Rotate
|
||||
ui-options-function-editor-flip-object = Flip
|
||||
ui-options-function-editor-copy-object = Copy
|
||||
|
||||
ui-options-function-open-abilities-menu = Open action menu
|
||||
|
||||
@@ -4,24 +4,39 @@
|
||||
graph:
|
||||
- node: start
|
||||
edges:
|
||||
# Filter
|
||||
- to: filter
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
|
||||
- to: filterflipped
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
|
||||
# Mixer
|
||||
- to: mixer
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
|
||||
- to: mixerflipped
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
|
||||
- to: pneumaticvalve
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
|
||||
# Filter
|
||||
- node: filter
|
||||
entity: GasFilter
|
||||
edges:
|
||||
@@ -38,6 +53,23 @@
|
||||
- tool: Welding
|
||||
doAfter: 1
|
||||
|
||||
- node: filterflipped
|
||||
entity: GasFilterFlipped
|
||||
edges:
|
||||
- to: start
|
||||
conditions:
|
||||
- !type:EntityAnchored
|
||||
anchored: false
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetSteel1
|
||||
amount: 2
|
||||
- !type:DeleteEntity
|
||||
steps:
|
||||
- tool: Welding
|
||||
doAfter: 1
|
||||
|
||||
# Mixer
|
||||
- node: mixer
|
||||
entity: GasMixer
|
||||
edges:
|
||||
@@ -54,6 +86,22 @@
|
||||
- tool: Welding
|
||||
doAfter: 1
|
||||
|
||||
- node: mixerflipped
|
||||
entity: GasMixerFlipped
|
||||
edges:
|
||||
- to: start
|
||||
conditions:
|
||||
- !type:EntityAnchored
|
||||
anchored: false
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetSteel1
|
||||
amount: 2
|
||||
- !type:DeleteEntity
|
||||
steps:
|
||||
- tool: Welding
|
||||
doAfter: 1
|
||||
|
||||
- node: pneumaticvalve
|
||||
entity: PressureControlledValve
|
||||
edges:
|
||||
|
||||
@@ -19,16 +19,28 @@
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
# DisposalRouter
|
||||
- to: router
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
- to: routerflipped
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
# DisposalJunction
|
||||
- to: junction
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
- to: junctionflipped
|
||||
steps:
|
||||
- material: Steel
|
||||
amount: 2
|
||||
doAfter: 1
|
||||
- to: yJunction
|
||||
steps:
|
||||
- material: Steel
|
||||
@@ -86,6 +98,7 @@
|
||||
steps:
|
||||
- tool: Welding
|
||||
doAfter: 1
|
||||
# DisposalRouter
|
||||
- node: router
|
||||
entity: DisposalRouter
|
||||
edges:
|
||||
@@ -98,6 +111,19 @@
|
||||
steps:
|
||||
- tool: Welding
|
||||
doAfter: 1
|
||||
- node: routerflipped
|
||||
entity: DisposalRouterFlipped
|
||||
edges:
|
||||
- to: start
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetSteel1
|
||||
amount: 2
|
||||
- !type:DeleteEntity
|
||||
steps:
|
||||
- tool: Welding
|
||||
doAfter: 1
|
||||
# DisposalJunction
|
||||
- node: junction
|
||||
entity: DisposalJunction
|
||||
edges:
|
||||
@@ -114,6 +140,22 @@
|
||||
steps:
|
||||
- tool: Screwing
|
||||
doAfter: 1
|
||||
- node: junctionflipped
|
||||
entity: DisposalJunctionFlipped
|
||||
edges:
|
||||
- to: start
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetSteel1
|
||||
amount: 2
|
||||
- !type:DeleteEntity
|
||||
steps:
|
||||
- tool: Welding
|
||||
doAfter: 1
|
||||
- to: yJunction
|
||||
steps:
|
||||
- tool: Screwing
|
||||
doAfter: 1
|
||||
- node: yJunction
|
||||
entity: DisposalYJunction
|
||||
edges:
|
||||
@@ -130,6 +172,10 @@
|
||||
steps:
|
||||
- tool: Screwing
|
||||
doAfter: 1
|
||||
- to: junctionflipped
|
||||
steps:
|
||||
- tool: Screwing
|
||||
doAfter: 1
|
||||
- node: bend
|
||||
entity: DisposalBend
|
||||
edges:
|
||||
|
||||
@@ -211,6 +211,23 @@
|
||||
icon:
|
||||
sprite: Structures/Piping/disposal.rsi
|
||||
state: conpipe-j1s
|
||||
mirror: DisposalRouterFlipped
|
||||
|
||||
- type: construction
|
||||
hide: true
|
||||
name: disposal router
|
||||
description: A three-way router. Entities with matching tags get routed to the side.
|
||||
id: DisposalRouterFlipped
|
||||
graph: DisposalPipe
|
||||
startNode: start
|
||||
targetNode: routerflipped
|
||||
category: construction-category-utilities
|
||||
placementMode: SnapgridCenter
|
||||
canBuildInImpassable: false
|
||||
icon:
|
||||
sprite: Structures/Piping/disposal.rsi
|
||||
state: conpipe-j2s
|
||||
mirror: DisposalRouter
|
||||
|
||||
- type: construction
|
||||
name: disposal junction
|
||||
@@ -225,6 +242,23 @@
|
||||
icon:
|
||||
sprite: Structures/Piping/disposal.rsi
|
||||
state: conpipe-j1
|
||||
mirror: DisposalJunctionFlipped
|
||||
|
||||
- type: construction
|
||||
hide: true
|
||||
name: disposal junction
|
||||
description: A three-way junction. The arrow indicates where items exit.
|
||||
id: DisposalJunctionFlipped
|
||||
graph: DisposalPipe
|
||||
startNode: start
|
||||
targetNode: junctionflipped
|
||||
category: construction-category-utilities
|
||||
placementMode: SnapgridCenter
|
||||
canBuildInImpassable: false
|
||||
icon:
|
||||
sprite: Structures/Piping/disposal.rsi
|
||||
state: conpipe-j2
|
||||
mirror: DisposalJunction
|
||||
|
||||
- type: construction
|
||||
name: disposal Y junction
|
||||
@@ -624,6 +658,25 @@
|
||||
icon:
|
||||
sprite: Structures/Piping/Atmospherics/gasfilter.rsi
|
||||
state: gasFilter
|
||||
mirror: GasFilterFlipped
|
||||
conditions:
|
||||
- !type:TileNotBlocked {}
|
||||
|
||||
- type: construction
|
||||
id: GasFilterFlipped
|
||||
hide: true
|
||||
name: gas filter
|
||||
description: Very useful for filtering gases.
|
||||
graph: GasTrinary
|
||||
startNode: start
|
||||
targetNode: filterflipped
|
||||
category: construction-category-utilities
|
||||
placementMode: SnapgridCenter
|
||||
canBuildInImpassable: false
|
||||
icon:
|
||||
sprite: Structures/Piping/Atmospherics/gasfilter.rsi
|
||||
state: gasFilterF
|
||||
mirror: GasFilter
|
||||
conditions:
|
||||
- !type:TileNotBlocked {}
|
||||
|
||||
@@ -640,6 +693,25 @@
|
||||
icon:
|
||||
sprite: Structures/Piping/Atmospherics/gasmixer.rsi
|
||||
state: gasMixer
|
||||
mirror: GasMixerFlipped
|
||||
conditions:
|
||||
- !type:TileNotBlocked {}
|
||||
|
||||
- type: construction
|
||||
id: GasMixerFlipped
|
||||
hide: true
|
||||
name: gas mixer
|
||||
description: Very useful for mixing gases.
|
||||
graph: GasTrinary
|
||||
startNode: start
|
||||
targetNode: mixerflipped
|
||||
category: construction-category-utilities
|
||||
placementMode: SnapgridCenter
|
||||
canBuildInImpassable: false
|
||||
icon:
|
||||
sprite: Structures/Piping/Atmospherics/gasmixer.rsi
|
||||
state: gasMixerF
|
||||
mirror: GasMixer
|
||||
conditions:
|
||||
- !type:TileNotBlocked {}
|
||||
|
||||
|
||||
@@ -150,6 +150,10 @@ binds:
|
||||
- function: EditorRotateObject
|
||||
type: State
|
||||
key: MouseMiddle
|
||||
- function: EditorFlipObject
|
||||
type: State
|
||||
key: MouseMiddle
|
||||
mod1: Control
|
||||
- function: EditorCopyObject
|
||||
type: State
|
||||
key: P
|
||||
|
||||
Reference in New Issue
Block a user