Add shortcut to flip for construction menu (#14152)

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
08A
2023-05-15 06:13:24 +02:00
committed by GitHub
parent 6aeda003a1
commit 3f93b11e4a
11 changed files with 282 additions and 65 deletions

View File

@@ -46,6 +46,8 @@ namespace Content.Client.Construction
new PointerInputCmdHandler(HandleOpenCraftingMenu)) new PointerInputCmdHandler(HandleOpenCraftingMenu))
.Bind(EngineKeyFunctions.Use, .Bind(EngineKeyFunctions.Use,
new PointerInputCmdHandler(HandleUse, outsidePrediction: true)) new PointerInputCmdHandler(HandleUse, outsidePrediction: true))
.Bind(ContentKeyFunctions.EditorFlipObject,
new PointerInputCmdHandler(HandleFlip))
.Register<ConstructionSystem>(); .Register<ConstructionSystem>();
SubscribeLocalEvent<ConstructionGhostComponent, ExaminedEvent>(HandleConstructionGhostExamined); SubscribeLocalEvent<ConstructionGhostComponent, ExaminedEvent>(HandleConstructionGhostExamined);
@@ -99,6 +101,7 @@ namespace Content.Client.Construction
public event EventHandler<CraftingAvailabilityChangedArgs>? CraftingAvailabilityChanged; public event EventHandler<CraftingAvailabilityChangedArgs>? CraftingAvailabilityChanged;
public event EventHandler<string>? ConstructionGuideAvailable; public event EventHandler<string>? ConstructionGuideAvailable;
public event EventHandler? ToggleCraftingWindow; public event EventHandler? ToggleCraftingWindow;
public event EventHandler? FlipConstructionPrototype;
private void HandleAckStructure(AckStructureConstructionMessage msg) private void HandleAckStructure(AckStructureConstructionMessage msg)
{ {
@@ -118,6 +121,13 @@ namespace Content.Client.Construction
return true; 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) private void UpdateCraftingAvailability(bool available)
{ {
if (CraftingEnabled == available) if (CraftingEnabled == available)

View File

@@ -148,6 +148,9 @@ namespace Content.Client.Construction.UI
foreach (var recipe in _prototypeManager.EnumeratePrototypes<ConstructionPrototype>()) foreach (var recipe in _prototypeManager.EnumeratePrototypes<ConstructionPrototype>())
{ {
if (recipe.Hide)
continue;
if (!string.IsNullOrEmpty(search)) if (!string.IsNullOrEmpty(search))
{ {
if (!recipe.Name.ToLowerInvariant().Contains(search.Trim().ToLowerInvariant())) if (!recipe.Name.ToLowerInvariant().Contains(search.Trim().ToLowerInvariant()))
@@ -342,6 +345,7 @@ namespace Content.Client.Construction.UI
{ {
_constructionSystem = system; _constructionSystem = system;
system.ToggleCraftingWindow += SystemOnToggleMenu; system.ToggleCraftingWindow += SystemOnToggleMenu;
system.FlipConstructionPrototype += SystemFlipConstructionPrototype;
system.CraftingAvailabilityChanged += SystemCraftingAvailabilityChanged; system.CraftingAvailabilityChanged += SystemCraftingAvailabilityChanged;
system.ConstructionGuideAvailable += SystemGuideAvailable; system.ConstructionGuideAvailable += SystemGuideAvailable;
if (_uiManager.GetActiveUIWidgetOrNull<GameTopMenuBar>() != null) if (_uiManager.GetActiveUIWidgetOrNull<GameTopMenuBar>() != null)
@@ -358,6 +362,7 @@ namespace Content.Client.Construction.UI
throw new InvalidOperationException(); throw new InvalidOperationException();
system.ToggleCraftingWindow -= SystemOnToggleMenu; system.ToggleCraftingWindow -= SystemOnToggleMenu;
system.FlipConstructionPrototype -= SystemFlipConstructionPrototype;
system.CraftingAvailabilityChanged -= SystemCraftingAvailabilityChanged; system.CraftingAvailabilityChanged -= SystemCraftingAvailabilityChanged;
system.ConstructionGuideAvailable -= SystemGuideAvailable; system.ConstructionGuideAvailable -= SystemGuideAvailable;
_constructionSystem = null; _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) private void SystemGuideAvailable(object? sender, string e)
{ {
if (!CraftingAvailable) if (!CraftingAvailable)

View File

@@ -37,6 +37,9 @@ namespace Content.Client.Input
// Not in engine, because engine cannot check for sanbox/admin status before starting placement. // Not in engine, because engine cannot check for sanbox/admin status before starting placement.
common.AddFunction(ContentKeyFunctions.EditorCopyObject); 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"); var human = contexts.GetContext("human");
human.AddFunction(EngineKeyFunctions.MoveUp); human.AddFunction(EngineKeyFunctions.MoveUp);
human.AddFunction(EngineKeyFunctions.MoveDown); human.AddFunction(EngineKeyFunctions.MoveDown);

View File

@@ -184,6 +184,7 @@ namespace Content.Client.Options.UI.Tabs
AddButton(EngineKeyFunctions.EditorGridPlace); AddButton(EngineKeyFunctions.EditorGridPlace);
AddButton(EngineKeyFunctions.EditorLinePlace); AddButton(EngineKeyFunctions.EditorLinePlace);
AddButton(EngineKeyFunctions.EditorRotateObject); AddButton(EngineKeyFunctions.EditorRotateObject);
AddButton(ContentKeyFunctions.EditorFlipObject);
AddButton(ContentKeyFunctions.EditorCopyObject); AddButton(ContentKeyFunctions.EditorCopyObject);
AddHeader("ui-options-header-dev"); AddHeader("ui-options-header-dev");

View File

@@ -3,86 +3,96 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Shared.Construction.Prototypes namespace Content.Shared.Construction.Prototypes;
[Prototype("construction")]
public sealed class ConstructionPrototype : IPrototype
{ {
[Prototype("construction")] [DataField("conditions")] private List<IConstructionCondition> _conditions = new();
public sealed class ConstructionPrototype : IPrototype
{
[DataField("conditions")] private List<IConstructionCondition> _conditions = new();
/// <summary> /// <summary>
/// Friendly name displayed in the construction GUI. /// Hide from the construction list
/// </summary> /// </summary>
[DataField("name")] [DataField("hide")]
public string Name { get; } = string.Empty; public bool Hide = false;
/// <summary> /// <summary>
/// "Useful" description displayed in the construction GUI. /// Friendly name displayed in the construction GUI.
/// </summary> /// </summary>
[DataField("description")] [DataField("name")]
public string Description { get; } = string.Empty; public string Name= string.Empty;
/// <summary> /// <summary>
/// The <see cref="ConstructionGraphPrototype"/> this construction will be using. /// "Useful" description displayed in the construction GUI.
/// </summary> /// </summary>
[DataField("graph", customTypeSerializer:typeof(PrototypeIdSerializer<ConstructionGraphPrototype>))] [DataField("description")]
public string Graph { get; } = string.Empty; public string Description = string.Empty;
/// <summary> /// <summary>
/// The target <see cref="ConstructionGraphNode"/> this construction will guide the user to. /// The <see cref="ConstructionGraphPrototype"/> this construction will be using.
/// </summary> /// </summary>
[DataField("targetNode")] [DataField("graph", customTypeSerializer:typeof(PrototypeIdSerializer<ConstructionGraphPrototype>))]
public string TargetNode { get; } = string.Empty; public string Graph = string.Empty;
/// <summary> /// <summary>
/// The starting <see cref="ConstructionGraphNode"/> this construction will start at. /// The target <see cref="ConstructionGraphNode"/> this construction will guide the user to.
/// </summary> /// </summary>
[DataField("startNode")] [DataField("targetNode")]
public string StartNode { get; } = string.Empty; public string TargetNode = string.Empty;
/// <summary> /// <summary>
/// Texture path inside the construction GUI. /// The starting <see cref="ConstructionGraphNode"/> this construction will start at.
/// </summary> /// </summary>
[DataField("icon")] [DataField("startNode")]
public SpriteSpecifier Icon { get; } = SpriteSpecifier.Invalid; public string StartNode = string.Empty;
/// <summary> /// <summary>
/// Texture paths used for the construction ghost. /// Texture path inside the construction GUI.
/// </summary> /// </summary>
[DataField("layers")] [DataField("icon")]
private List<SpriteSpecifier>? _layers; public SpriteSpecifier Icon = SpriteSpecifier.Invalid;
/// <summary> /// <summary>
/// If you can start building or complete steps on impassable terrain. /// Texture paths used for the construction ghost.
/// </summary> /// </summary>
[DataField("canBuildInImpassable")] [DataField("layers")]
public bool CanBuildInImpassable { get; private set; } 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] [DataField("objectType")] public ConstructionType Type { get; private set; } = ConstructionType.Structure;
[IdDataField]
public string ID { get; } = default!;
[DataField("placementMode")] [ViewVariables]
public string PlacementMode { get; } = "PlaceFree"; [IdDataField]
public string ID { get; } = default!;
/// <summary> [DataField("placementMode")]
/// Whether this construction can be constructed rotated or not. public string PlacementMode = "PlaceFree";
/// </summary>
[DataField("canRotate")]
public bool CanRotate { get; } = true;
public IReadOnlyList<IConstructionCondition> Conditions => _conditions; /// <summary>
public IReadOnlyList<SpriteSpecifier> Layers => _layers ?? new List<SpriteSpecifier>{Icon}; /// Whether this construction can be constructed rotated or not.
} /// </summary>
[DataField("canRotate")]
public bool CanRotate = true;
public enum ConstructionType /// <summary>
{ /// Construction to replace this construction with when the current one is 'flipped'
Structure, /// </summary>
Item, [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,
}

View File

@@ -111,5 +111,6 @@ namespace Content.Shared.Input
public static readonly BoundKeyFunction Vote8 = "Vote8"; public static readonly BoundKeyFunction Vote8 = "Vote8";
public static readonly BoundKeyFunction Vote9 = "Vote9"; public static readonly BoundKeyFunction Vote9 = "Vote9";
public static readonly BoundKeyFunction EditorCopyObject = "EditorCopyObject"; public static readonly BoundKeyFunction EditorCopyObject = "EditorCopyObject";
public static readonly BoundKeyFunction EditorFlipObject = "EditorFlipObject";
} }
} }

View File

@@ -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-grid-place = Place in grid
ui-options-function-editor-line-place = Place line ui-options-function-editor-line-place = Place line
ui-options-function-editor-rotate-object = Rotate ui-options-function-editor-rotate-object = Rotate
ui-options-function-editor-flip-object = Flip
ui-options-function-editor-copy-object = Copy ui-options-function-editor-copy-object = Copy
ui-options-function-open-abilities-menu = Open action menu ui-options-function-open-abilities-menu = Open action menu

View File

@@ -4,24 +4,39 @@
graph: graph:
- node: start - node: start
edges: edges:
# Filter
- to: filter - to: filter
steps: steps:
- material: Steel - material: Steel
amount: 2 amount: 2
doAfter: 1 doAfter: 1
- to: filterflipped
steps:
- material: Steel
amount: 2
doAfter: 1
# Mixer
- to: mixer - to: mixer
steps: steps:
- material: Steel - material: Steel
amount: 2 amount: 2
doAfter: 1 doAfter: 1
- to: mixerflipped
steps:
- material: Steel
amount: 2
doAfter: 1
- to: pneumaticvalve - to: pneumaticvalve
steps: steps:
- material: Steel - material: Steel
amount: 2 amount: 2
doAfter: 1 doAfter: 1
# Filter
- node: filter - node: filter
entity: GasFilter entity: GasFilter
edges: edges:
@@ -38,6 +53,23 @@
- tool: Welding - tool: Welding
doAfter: 1 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 - node: mixer
entity: GasMixer entity: GasMixer
edges: edges:
@@ -54,6 +86,22 @@
- tool: Welding - tool: Welding
doAfter: 1 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 - node: pneumaticvalve
entity: PressureControlledValve entity: PressureControlledValve
edges: edges:

View File

@@ -19,16 +19,28 @@
- material: Steel - material: Steel
amount: 2 amount: 2
doAfter: 1 doAfter: 1
# DisposalRouter
- to: router - to: router
steps: steps:
- material: Steel - material: Steel
amount: 2 amount: 2
doAfter: 1 doAfter: 1
- to: routerflipped
steps:
- material: Steel
amount: 2
doAfter: 1
# DisposalJunction
- to: junction - to: junction
steps: steps:
- material: Steel - material: Steel
amount: 2 amount: 2
doAfter: 1 doAfter: 1
- to: junctionflipped
steps:
- material: Steel
amount: 2
doAfter: 1
- to: yJunction - to: yJunction
steps: steps:
- material: Steel - material: Steel
@@ -86,6 +98,7 @@
steps: steps:
- tool: Welding - tool: Welding
doAfter: 1 doAfter: 1
# DisposalRouter
- node: router - node: router
entity: DisposalRouter entity: DisposalRouter
edges: edges:
@@ -98,6 +111,19 @@
steps: steps:
- tool: Welding - tool: Welding
doAfter: 1 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 - node: junction
entity: DisposalJunction entity: DisposalJunction
edges: edges:
@@ -114,6 +140,22 @@
steps: steps:
- tool: Screwing - tool: Screwing
doAfter: 1 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 - node: yJunction
entity: DisposalYJunction entity: DisposalYJunction
edges: edges:
@@ -130,6 +172,10 @@
steps: steps:
- tool: Screwing - tool: Screwing
doAfter: 1 doAfter: 1
- to: junctionflipped
steps:
- tool: Screwing
doAfter: 1
- node: bend - node: bend
entity: DisposalBend entity: DisposalBend
edges: edges:

View File

@@ -211,6 +211,23 @@
icon: icon:
sprite: Structures/Piping/disposal.rsi sprite: Structures/Piping/disposal.rsi
state: conpipe-j1s 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 - type: construction
name: disposal junction name: disposal junction
@@ -225,6 +242,23 @@
icon: icon:
sprite: Structures/Piping/disposal.rsi sprite: Structures/Piping/disposal.rsi
state: conpipe-j1 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 - type: construction
name: disposal Y junction name: disposal Y junction
@@ -624,6 +658,25 @@
icon: icon:
sprite: Structures/Piping/Atmospherics/gasfilter.rsi sprite: Structures/Piping/Atmospherics/gasfilter.rsi
state: gasFilter 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: conditions:
- !type:TileNotBlocked {} - !type:TileNotBlocked {}
@@ -640,6 +693,25 @@
icon: icon:
sprite: Structures/Piping/Atmospherics/gasmixer.rsi sprite: Structures/Piping/Atmospherics/gasmixer.rsi
state: gasMixer 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: conditions:
- !type:TileNotBlocked {} - !type:TileNotBlocked {}

View File

@@ -150,6 +150,10 @@ binds:
- function: EditorRotateObject - function: EditorRotateObject
type: State type: State
key: MouseMiddle key: MouseMiddle
- function: EditorFlipObject
type: State
key: MouseMiddle
mod1: Control
- function: EditorCopyObject - function: EditorCopyObject
type: State type: State
key: P key: P