예제 #1
0
        protected override void CreateGUI()
        {
            controlContainer = new GUIFrame(new RectTransform(new Vector2(Sonar.controlBoxSize.X, 1 - Sonar.controlBoxSize.Y * 2), GuiFrame.RectTransform, Anchor.CenterRight), "ItemUI");
            var paddedControlContainer = new GUIFrame(new RectTransform(controlContainer.Rect.Size - GUIStyle.ItemFrameMargin, controlContainer.RectTransform, Anchor.Center)
            {
                AbsoluteOffset = GUIStyle.ItemFrameOffset
            }, style: null);

            var steeringModeArea = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), paddedControlContainer.RectTransform, Anchor.TopLeft), style: null);

            steeringModeSwitch = new GUIButton(new RectTransform(new Vector2(0.2f, 1), steeringModeArea.RectTransform), string.Empty, style: "SwitchVertical")
            {
                Selected   = autoPilot,
                Enabled    = true,
                ClickSound = GUISoundType.UISwitch,
                OnClicked  = (button, data) =>
                {
                    button.Selected = !button.Selected;
                    AutoPilot       = button.Selected;
                    if (GameMain.Client != null)
                    {
                        unsentChanges = true;
                        user          = Character.Controlled;
                    }
                    return(true);
                }
            };
            var steeringModeRightSide = new GUIFrame(new RectTransform(new Vector2(1.0f - steeringModeSwitch.RectTransform.RelativeSize.X, 0.8f), steeringModeArea.RectTransform, Anchor.CenterLeft)
            {
                RelativeOffset = new Vector2(steeringModeSwitch.RectTransform.RelativeSize.X, 0)
            }, style: null);

            manualPilotIndicator = new GUITickBox(new RectTransform(new Vector2(1, 0.45f), steeringModeRightSide.RectTransform, Anchor.TopLeft),
                                                  TextManager.Get("SteeringManual"), font: GUI.SubHeadingFont, style: "IndicatorLightRedSmall")
            {
                Selected = !autoPilot,
                Enabled  = false
            };
            autopilotIndicator = new GUITickBox(new RectTransform(new Vector2(1, 0.45f), steeringModeRightSide.RectTransform, Anchor.BottomLeft),
                                                TextManager.Get("SteeringAutoPilot"), font: GUI.SubHeadingFont, style: "IndicatorLightRedSmall")
            {
                Selected = autoPilot,
                Enabled  = false
            };
            manualPilotIndicator.TextBlock.OverrideTextColor(GUI.Style.TextColor);
            autopilotIndicator.TextBlock.OverrideTextColor(GUI.Style.TextColor);
            GUITextBlock.AutoScaleAndNormalize(manualPilotIndicator.TextBlock, autopilotIndicator.TextBlock);

            var autoPilotControls       = new GUIFrame(new RectTransform(new Vector2(0.75f, 0.62f), paddedControlContainer.RectTransform, Anchor.BottomCenter), "OutlineFrame");
            var paddedAutoPilotControls = new GUIFrame(new RectTransform(new Vector2(0.92f, 0.88f), autoPilotControls.RectTransform, Anchor.Center), style: null);

            maintainPosTickBox = new GUITickBox(new RectTransform(new Vector2(1, 0.333f), paddedAutoPilotControls.RectTransform, Anchor.TopCenter),
                                                TextManager.Get("SteeringMaintainPos"), font: GUI.SmallFont, style: "GUIRadioButton")
            {
                Enabled    = autoPilot,
                Selected   = maintainPos,
                OnSelected = tickBox =>
                {
                    if (maintainPos != tickBox.Selected)
                    {
                        unsentChanges = true;
                        user          = Character.Controlled;
                        maintainPos   = tickBox.Selected;
                        if (maintainPos)
                        {
                            if (controlledSub == null)
                            {
                                posToMaintain = null;
                            }
                            else
                            {
                                posToMaintain = controlledSub.WorldPosition;
                            }
                        }
                        else if (!LevelEndSelected && !LevelStartSelected)
                        {
                            AutoPilot = false;
                        }
                        if (!maintainPos)
                        {
                            posToMaintain = null;
                        }
                    }
                    return(true);
                }
            };
            int textLimit = (int)(MathHelper.Clamp(25 * GUI.xScale, 15, 35));

            levelStartTickBox = new GUITickBox(new RectTransform(new Vector2(1, 0.333f), paddedAutoPilotControls.RectTransform, Anchor.Center),
                                               GameMain.GameSession?.StartLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.StartLocation.Name, textLimit),
                                               font: GUI.SmallFont, style: "GUIRadioButton")
            {
                Enabled    = autoPilot,
                Selected   = levelStartSelected,
                OnSelected = tickBox =>
                {
                    if (levelStartSelected != tickBox.Selected)
                    {
                        unsentChanges      = true;
                        user               = Character.Controlled;
                        levelStartSelected = tickBox.Selected;
                        levelEndSelected   = !levelStartSelected;
                        if (levelStartSelected)
                        {
                            UpdatePath();
                        }
                        else if (!MaintainPos && !LevelEndSelected)
                        {
                            AutoPilot = false;
                        }
                    }
                    return(true);
                }
            };

            levelEndTickBox = new GUITickBox(new RectTransform(new Vector2(1, 0.333f), paddedAutoPilotControls.RectTransform, Anchor.BottomCenter),
                                             (GameMain.GameSession?.EndLocation == null || Level.IsLoadedOutpost) ? "" : ToolBox.LimitString(GameMain.GameSession.EndLocation.Name, textLimit),
                                             font: GUI.SmallFont, style: "GUIRadioButton")
            {
                Enabled    = autoPilot,
                Selected   = levelEndSelected,
                Visible    = GameMain.GameSession?.EndLocation != null,
                OnSelected = tickBox =>
                {
                    if (levelEndSelected != tickBox.Selected)
                    {
                        unsentChanges      = true;
                        user               = Character.Controlled;
                        levelEndSelected   = tickBox.Selected;
                        levelStartSelected = !levelEndSelected;
                        if (levelEndSelected)
                        {
                            UpdatePath();
                        }
                        else if (!MaintainPos && !LevelStartSelected)
                        {
                            AutoPilot = false;
                        }
                    }
                    return(true);
                }
            };
            maintainPosTickBox.RectTransform.IsFixedSize = levelStartTickBox.RectTransform.IsFixedSize = levelEndTickBox.RectTransform.IsFixedSize = false;
            maintainPosTickBox.RectTransform.MaxSize     = levelStartTickBox.RectTransform.MaxSize = levelEndTickBox.RectTransform.MaxSize =
                new Point(int.MaxValue, paddedAutoPilotControls.Rect.Height / 3);
            maintainPosTickBox.RectTransform.MinSize = levelStartTickBox.RectTransform.MinSize = levelEndTickBox.RectTransform.MinSize =
                Point.Zero;

            GUITextBlock.AutoScaleAndNormalize(scaleHorizontal: false, scaleVertical: true, maintainPosTickBox.TextBlock, levelStartTickBox.TextBlock, levelEndTickBox.TextBlock);

            GUIRadioButtonGroup destinations = new GUIRadioButtonGroup();

            destinations.AddRadioButton((int)Destination.MaintainPos, maintainPosTickBox);
            destinations.AddRadioButton((int)Destination.LevelStart, levelStartTickBox);
            destinations.AddRadioButton((int)Destination.LevelEnd, levelEndTickBox);
            destinations.Selected = (int)(maintainPos ? Destination.MaintainPos :
                                          levelStartSelected ? Destination.LevelStart : Destination.LevelEnd);

            // Status ->
            statusContainer = new GUIFrame(new RectTransform(Sonar.controlBoxSize, GuiFrame.RectTransform, Anchor.BottomRight)
            {
                RelativeOffset = Sonar.controlBoxOffset
            }, "ItemUI");
            var paddedStatusContainer = new GUIFrame(new RectTransform(statusContainer.Rect.Size - GUIStyle.ItemFrameMargin, statusContainer.RectTransform, Anchor.Center, isFixedSize: false)
            {
                AbsoluteOffset = GUIStyle.ItemFrameOffset
            }, style: null);

            var elements = GUI.CreateElements(3, new Vector2(1f, 0.333f), paddedStatusContainer.RectTransform, rt => new GUIFrame(rt, style: null), Anchor.TopCenter, relativeSpacing: 0.01f);
            List <GUIComponent> leftElements = new List <GUIComponent>(), centerElements = new List <GUIComponent>(), rightElements = new List <GUIComponent>();

            for (int i = 0; i < elements.Count; i++)
            {
                var e     = elements[i];
                var group = new GUILayoutGroup(new RectTransform(Vector2.One, e.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
                {
                    RelativeSpacing = 0.01f,
                    Stretch         = true
                };
                var left   = new GUIFrame(new RectTransform(new Vector2(0.45f, 1), group.RectTransform), style: null);
                var center = new GUIFrame(new RectTransform(new Vector2(0.15f, 1), group.RectTransform), style: null);
                var right  = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.8f), group.RectTransform), style: null);
                leftElements.Add(left);
                centerElements.Add(center);
                rightElements.Add(right);
                string leftText = string.Empty, centerText = string.Empty;
                GUITextBlock.TextGetterHandler rightTextGetter = null;
                switch (i)
                {
                case 0:
                    leftText        = TextManager.Get("DescentVelocity");
                    centerText      = $"({TextManager.Get("KilometersPerHour")})";
                    rightTextGetter = () =>
                    {
                        Vector2 vel          = controlledSub == null ? Vector2.Zero : controlledSub.Velocity;
                        var     realWorldVel = ConvertUnits.ToDisplayUnits(vel.Y * Physics.DisplayToRealWorldRatio) * 3.6f;
                        return(((int)(-realWorldVel)).ToString());
                    };
                    break;

                case 1:
                    leftText        = TextManager.Get("Velocity");
                    centerText      = $"({TextManager.Get("KilometersPerHour")})";
                    rightTextGetter = () =>
                    {
                        Vector2 vel          = controlledSub == null ? Vector2.Zero : controlledSub.Velocity;
                        var     realWorldVel = ConvertUnits.ToDisplayUnits(vel.X * Physics.DisplayToRealWorldRatio) * 3.6f;
                        return(((int)realWorldVel).ToString());
                    };
                    break;

                case 2:
                    leftText        = TextManager.Get("Depth");
                    centerText      = $"({TextManager.Get("Meter")})";
                    rightTextGetter = () =>
                    {
                        float realWorldDepth = controlledSub == null ? -1000.0f : controlledSub.RealWorldDepth;
                        return(((int)realWorldDepth).ToString());
                    };
                    break;
                }
                new GUITextBlock(new RectTransform(Vector2.One, left.RectTransform), leftText, font: GUI.SubHeadingFont, wrap: leftText.Contains(' '), textAlignment: Alignment.CenterRight);
                new GUITextBlock(new RectTransform(Vector2.One, center.RectTransform), centerText, font: GUI.Font, textAlignment: Alignment.Center)
                {
                    Padding = Vector4.Zero
                };
                var digitalFrame = new GUIFrame(new RectTransform(Vector2.One, right.RectTransform), style: "DigitalFrameDark");
                new GUITextBlock(new RectTransform(Vector2.One * 0.85f, digitalFrame.RectTransform, Anchor.Center), "12345", GUI.Style.TextColorDark, GUI.DigitalFont, Alignment.CenterRight)
                {
                    TextGetter = rightTextGetter
                };
            }
            GUITextBlock.AutoScaleAndNormalize(leftElements.SelectMany(e => e.GetAllChildren <GUITextBlock>()));
            GUITextBlock.AutoScaleAndNormalize(centerElements.SelectMany(e => e.GetAllChildren <GUITextBlock>()));
            GUITextBlock.AutoScaleAndNormalize(rightElements.SelectMany(e => e.GetAllChildren <GUITextBlock>()));

            //docking interface ----------------------------------------------------
            float dockingButtonSize = 1.1f;
            float elementScale      = 0.6f;

            dockingContainer = new GUIFrame(new RectTransform(Sonar.controlBoxSize, GuiFrame.RectTransform, Anchor.BottomRight, scaleBasis: ScaleBasis.Smallest)
            {
                RelativeOffset = new Vector2(Sonar.controlBoxOffset.X + 0.05f, -0.05f)
            }, style: null);

            dockText      = TextManager.Get("label.navterminaldock", fallBackTag: "captain.dock");
            undockText    = TextManager.Get("label.navterminalundock", fallBackTag: "captain.undock");
            dockingButton = new GUIButton(new RectTransform(new Vector2(elementScale), dockingContainer.RectTransform, Anchor.Center), dockText, style: "PowerButton")
            {
                OnClicked = (btn, userdata) =>
                {
                    if (GameMain.GameSession?.Campaign is CampaignMode campaign)
                    {
                        if (Level.IsLoadedOutpost &&
                            DockingSources.Any(d => d.Docked && (d.DockingTarget?.Item.Submarine?.Info?.IsOutpost ?? false)))
                        {
                            // Undocking from an outpost
                            campaign.CampaignUI.SelectTab(CampaignMode.InteractionType.Map);
                            campaign.ShowCampaignUI = true;
                            return(false);
                        }
                        else if (!Level.IsLoadedOutpost && DockingModeEnabled && ActiveDockingSource != null &&
                                 !ActiveDockingSource.Docked && DockingTarget?.Item?.Submarine == Level.Loaded.StartOutpost && (DockingTarget?.Item?.Submarine?.Info.IsOutpost ?? false))
                        {
                            // Docking to an outpost
                            var subsToLeaveBehind = campaign.GetSubsToLeaveBehind(Item.Submarine);
                            if (subsToLeaveBehind.Any())
                            {
                                enterOutpostPrompt = new GUIMessageBox(
                                    TextManager.GetWithVariable("enterlocation", "[locationname]", DockingTarget.Item.Submarine.Info.Name),
                                    TextManager.Get(subsToLeaveBehind.Count == 1 ? "LeaveSubBehind" : "LeaveSubsBehind"),
                                    new string[] { TextManager.Get("yes"), TextManager.Get("no") });
                            }
                            else
                            {
                                enterOutpostPrompt = new GUIMessageBox("",
                                                                       TextManager.GetWithVariable("campaignenteroutpostprompt", "[locationname]", DockingTarget.Item.Submarine.Info.Name),
                                                                       new string[] { TextManager.Get("yes"), TextManager.Get("no") });
                            }
                            enterOutpostPrompt.Buttons[0].OnClicked += (btn, userdata) =>
                            {
                                SendDockingSignal();
                                enterOutpostPrompt.Close();
                                return(true);
                            };
                            enterOutpostPrompt.Buttons[1].OnClicked += enterOutpostPrompt.Close;
                            return(false);
                        }
                    }
                    SendDockingSignal();

                    return(true);
                }
            };
            void SendDockingSignal()
            {
                if (GameMain.Client == null)
                {
                    item.SendSignal(0, "1", "toggle_docking", sender: null);
                }
                else
                {
                    dockingNetworkMessagePending = true;
                    item.CreateClientEvent(this);
                }
            }

            dockingButton.Font = GUI.SubHeadingFont;
            dockingButton.TextBlock.RectTransform.MaxSize = new Point((int)(dockingButton.Rect.Width * 0.7f), int.MaxValue);
            dockingButton.TextBlock.AutoScaleHorizontal   = true;

            var    style        = GUI.Style.GetComponentStyle("DockingButtonUp");
            Sprite buttonSprite = style.Sprites.FirstOrDefault().Value.FirstOrDefault()?.Sprite;
            Point  buttonSize   = buttonSprite != null?buttonSprite.size.ToPoint() : new Point(149, 52);

            Point horizontalButtonSize = buttonSize.Multiply(elementScale * GUI.Scale * dockingButtonSize);
            Point verticalButtonSize   = horizontalButtonSize.Flip();
            var   leftButton           = new GUIButton(new RectTransform(verticalButtonSize, dockingContainer.RectTransform, Anchor.CenterLeft), "", style: "DockingButtonLeft")
            {
                OnClicked = NudgeButtonClicked,
                UserData  = -Vector2.UnitX
            };
            var rightButton = new GUIButton(new RectTransform(verticalButtonSize, dockingContainer.RectTransform, Anchor.CenterRight), "", style: "DockingButtonRight")
            {
                OnClicked = NudgeButtonClicked,
                UserData  = Vector2.UnitX
            };
            var upButton = new GUIButton(new RectTransform(horizontalButtonSize, dockingContainer.RectTransform, Anchor.TopCenter), "", style: "DockingButtonUp")
            {
                OnClicked = NudgeButtonClicked,
                UserData  = Vector2.UnitY
            };
            var downButton = new GUIButton(new RectTransform(horizontalButtonSize, dockingContainer.RectTransform, Anchor.BottomCenter), "", style: "DockingButtonDown")
            {
                OnClicked = NudgeButtonClicked,
                UserData  = -Vector2.UnitY
            };

            // Sonar area
            steerArea = new GUICustomComponent(new RectTransform(Sonar.GUISizeCalculation, GuiFrame.RectTransform, Anchor.CenterLeft, scaleBasis: ScaleBasis.Smallest),
                                               (spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); }, null);
            steerRadius = steerArea.Rect.Width / 2;

            pressureWarningText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), steerArea.RectTransform, Anchor.Center, Pivot.TopCenter),
                                                   TextManager.Get("SteeringDepthWarning"), Color.Red, GUI.LargeFont, Alignment.Center)
            {
                Visible = false
            };
            // Tooltip/helper text
            tipContainer = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.1f), steerArea.RectTransform, Anchor.BottomCenter, Pivot.TopCenter)
                                            , "", font: GUI.Font, wrap: true, style: "GUIToolTip", textAlignment: Alignment.Center)
            {
                AutoScaleHorizontal = true
            };
            noPowerTip = TextManager.Get("SteeringNoPowerTip");
            autoPilotMaintainPosTip = TextManager.Get("SteeringAutoPilotMaintainPosTip");
            autoPilotLevelStartTip  = TextManager.GetWithVariable("SteeringAutoPilotLocationTip", "[locationname]",
                                                                  GameMain.GameSession?.StartLocation == null ? "Start" : GameMain.GameSession.StartLocation.Name);
            autoPilotLevelEndTip = TextManager.GetWithVariable("SteeringAutoPilotLocationTip", "[locationname]",
                                                               GameMain.GameSession?.EndLocation == null ? "End" : GameMain.GameSession.EndLocation.Name);
        }
예제 #2
0
        public override void UpdateHUD(Character character, float deltaTime, Camera cam)
        {
            if (swapDestinationOrder == null)
            {
                swapDestinationOrder = item.Submarine != null && item.Submarine.FlippedX;
                if (swapDestinationOrder.Value)
                {
                    levelStartTickBox.RectTransform.SetAsLastChild();
                }
            }

            if (steerArea.Rect.Contains(PlayerInput.MousePosition))
            {
                if (!PlayerInput.KeyDown(InputType.Deselect) && !PlayerInput.KeyHit(InputType.Deselect))
                {
                    Character.DisableControls = true;
                }
            }

            dockingContainer.Visible = DockingModeEnabled;
            statusContainer.Visible  = !DockingModeEnabled;
            if (!DockingModeEnabled)
            {
                enterOutpostPrompt?.Close();
            }

            if (DockingModeEnabled && ActiveDockingSource != null)
            {
                if (Math.Abs(ActiveDockingSource.Item.WorldPosition.X - DockingTarget.Item.WorldPosition.X) < ActiveDockingSource.DistanceTolerance.X &&
                    Math.Abs(ActiveDockingSource.Item.WorldPosition.Y - DockingTarget.Item.WorldPosition.Y) < ActiveDockingSource.DistanceTolerance.Y)
                {
                    dockingButton.Text = dockText;
                    if (dockingButton.FlashTimer <= 0.0f)
                    {
                        dockingButton.Flash(GUI.Style.Blue, 0.5f, useCircularFlash: true);
                        dockingButton.Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.FlashTimer);
                    }
                }
                else
                {
                    enterOutpostPrompt?.Close();
                }
            }
            else if (DockingSources.Any(d => d.Docked))
            {
                dockingButton.Text       = undockText;
                dockingContainer.Visible = true;
                statusContainer.Visible  = false;
                if (dockingButton.FlashTimer <= 0.0f)
                {
                    dockingButton.Flash(GUI.Style.Orange, useCircularFlash: true);
                    dockingButton.Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.FlashTimer);
                }
            }
            else
            {
                dockingButton.Text = dockText;
            }

            if (Voltage < MinVoltage)
            {
                tipContainer.Visible = true;
                tipContainer.Text    = noPowerTip;
                return;
            }

            tipContainer.Visible = AutoPilot;
            if (AutoPilot)
            {
                if (maintainPos)
                {
                    tipContainer.Text = autoPilotMaintainPosTip;
                }
                else if (LevelStartSelected)
                {
                    tipContainer.Text = autoPilotLevelStartTip;
                }
                else if (LevelEndSelected)
                {
                    tipContainer.Text = autoPilotLevelEndTip;
                }

                if (DockingModeEnabled && DockingTarget != null)
                {
                    posToMaintain += ConvertUnits.ToDisplayUnits(DockingTarget.Item.Submarine.Velocity) * deltaTime;
                }
            }

            pressureWarningText.Visible = item.Submarine != null && item.Submarine.AtDamageDepth && Timing.TotalTime % 1.0f < 0.5f;

            if (Vector2.DistanceSquared(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerRadius * steerRadius)
            {
                if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen && !GameSession.IsTabMenuOpen &&
                    (!GameMain.GameSession?.Campaign?.ShowCampaignUI ?? true) && !GUIMessageBox.MessageBoxes.Any())
                {
                    Vector2 inputPos = PlayerInput.MousePosition - steerArea.Rect.Center.ToVector2();
                    inputPos.Y = -inputPos.Y;
                    if (AutoPilot && !LevelStartSelected && !LevelEndSelected)
                    {
                        posToMaintain = controlledSub != null ?
                                        controlledSub.WorldPosition + inputPos / sonar.DisplayRadius * sonar.Range / sonar.Zoom :
                                        item.Submarine == null ? item.WorldPosition : item.Submarine.WorldPosition;
                    }
                    else
                    {
                        SteeringInput = inputPos;
                    }
                    unsentChanges = true;
                    user          = Character.Controlled;
                }
            }
            if (!AutoPilot && Character.DisableControls && GUI.KeyboardDispatcher.Subscriber == null)
            {
                steeringAdjustSpeed = character == null ? 0.2f : MathHelper.Lerp(0.2f, 1.0f, character.GetSkillLevel("helm") / 100.0f);
                Vector2 input = Vector2.Zero;
                if (PlayerInput.KeyDown(InputType.Left))
                {
                    input -= Vector2.UnitX;
                }
                if (PlayerInput.KeyDown(InputType.Right))
                {
                    input += Vector2.UnitX;
                }
                if (PlayerInput.KeyDown(InputType.Up))
                {
                    input += Vector2.UnitY;
                }
                if (PlayerInput.KeyDown(InputType.Down))
                {
                    input -= Vector2.UnitY;
                }
                if (PlayerInput.KeyDown(InputType.Run))
                {
                    SteeringInput  += input * deltaTime * 200;
                    inputCumulation = 0;
                    keyboardInput   = Vector2.Zero;
                    unsentChanges   = true;
                }
                else
                {
                    float step = deltaTime * 5;
                    if (input.Length() > 0)
                    {
                        inputCumulation += step;
                    }
                    else
                    {
                        inputCumulation -= step;
                    }
                    float maxCumulation = 1;
                    inputCumulation = MathHelper.Clamp(inputCumulation, 0, maxCumulation);
                    float length          = MathHelper.Lerp(0, 0.2f, MathUtils.InverseLerp(0, maxCumulation, inputCumulation));
                    var   normalizedInput = Vector2.Normalize(input);
                    if (MathUtils.IsValid(normalizedInput))
                    {
                        keyboardInput += normalizedInput * length;
                    }
                    if (keyboardInput.LengthSquared() > 0.01f)
                    {
                        SteeringInput += keyboardInput;
                        unsentChanges  = true;
                        user           = Character.Controlled;
                        keyboardInput *= MathHelper.Clamp(1 - step, 0, 1);
                    }
                }
            }
            else
            {
                inputCumulation = 0;
                keyboardInput   = Vector2.Zero;
            }

            if (!UseAutoDocking)
            {
                return;
            }

            if (checkConnectedPortsTimer <= 0.0f)
            {
                Connection dockingConnection = item.Connections?.FirstOrDefault(c => c.Name == "toggle_docking");
                if (dockingConnection != null)
                {
                    connectedPorts = item.GetConnectedComponentsRecursive <DockingPort>(dockingConnection);
                }
                checkConnectedPortsTimer = CheckConnectedPortsInterval;
            }
            else
            {
                checkConnectedPortsTimer -= deltaTime;
            }

            DockingModeEnabled = false;

            if (connectedPorts.None())
            {
                return;
            }

            float closestDist = DockingAssistThreshold * DockingAssistThreshold;

            foreach (DockingPort sourcePort in connectedPorts)
            {
                if (sourcePort.Docked || sourcePort.Item.Submarine == null)
                {
                    continue;
                }
                if (sourcePort.Item.Submarine != controlledSub)
                {
                    continue;
                }

                int sourceDir = sourcePort.GetDir();

                foreach (DockingPort targetPort in DockingPort.List)
                {
                    if (targetPort.Docked || targetPort.Item.Submarine == null)
                    {
                        continue;
                    }
                    if (targetPort.Item.Submarine == controlledSub || targetPort.IsHorizontal != sourcePort.IsHorizontal)
                    {
                        continue;
                    }
                    if (targetPort.Item.Submarine.DockedTo?.Contains(sourcePort.Item.Submarine) ?? false)
                    {
                        continue;
                    }
                    if (Level.Loaded != null && targetPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y)
                    {
                        continue;
                    }
                    if (sourceDir == targetPort.GetDir())
                    {
                        continue;
                    }

                    float dist = Vector2.DistanceSquared(sourcePort.Item.WorldPosition, targetPort.Item.WorldPosition);
                    if (dist < closestDist)
                    {
                        closestDist         = dist;
                        DockingModeEnabled  = true;
                        ActiveDockingSource = sourcePort;
                        DockingTarget       = targetPort;
                    }
                }
            }
        }
        public override void UpdateHUD(Character character, float deltaTime, Camera cam)
        {
            if (swapDestinationOrder == null)
            {
                swapDestinationOrder = item.Submarine != null && item.Submarine.FlippedX;
                if (swapDestinationOrder.Value)
                {
                    levelStartTickBox.RectTransform.SetAsLastChild();
                }
            }

            if (steerArea.Rect.Contains(PlayerInput.MousePosition))
            {
                if (!PlayerInput.KeyDown(InputType.Deselect) && !PlayerInput.KeyHit(InputType.Deselect))
                {
                    Character.DisableControls = true;
                }
            }

            dockingContainer.Visible = DockingModeEnabled;
            statusContainer.Visible  = !DockingModeEnabled;
            if (!DockingModeEnabled)
            {
                enterOutpostPrompt?.Close();
            }

            if (DockingModeEnabled && ActiveDockingSource != null)
            {
                if (Math.Abs(ActiveDockingSource.Item.WorldPosition.X - DockingTarget.Item.WorldPosition.X) < ActiveDockingSource.DistanceTolerance.X &&
                    Math.Abs(ActiveDockingSource.Item.WorldPosition.Y - DockingTarget.Item.WorldPosition.Y) < ActiveDockingSource.DistanceTolerance.Y)
                {
                    dockingButton.Text = dockText;
                    if (dockingButton.FlashTimer <= 0.0f)
                    {
                        dockingButton.Flash(GUI.Style.Blue, 0.5f, useCircularFlash: true);
                        dockingButton.Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.FlashTimer);
                    }
                }
                else
                {
                    enterOutpostPrompt?.Close();
                }
            }
            else if (DockingSources.Any(d => d.Docked))
            {
                dockingButton.Text       = undockText;
                dockingContainer.Visible = true;
                statusContainer.Visible  = false;
                if (dockingButton.FlashTimer <= 0.0f)
                {
                    dockingButton.Flash(GUI.Style.Orange, useCircularFlash: true);
                    dockingButton.Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.FlashTimer);
                }
            }
            else
            {
                dockingButton.Text = dockText;
            }

            if (Voltage < MinVoltage)
            {
                tipContainer.Visible = true;
                tipContainer.Text    = noPowerTip;
                return;
            }

            tipContainer.Visible = AutoPilot;
            if (AutoPilot)
            {
                if (maintainPos)
                {
                    tipContainer.Text = autoPilotMaintainPosTip;
                }
                else if (LevelStartSelected)
                {
                    tipContainer.Text = autoPilotLevelStartTip;
                }
                else if (LevelEndSelected)
                {
                    tipContainer.Text = autoPilotLevelEndTip;
                }

                if (DockingModeEnabled && DockingTarget != null)
                {
                    posToMaintain += ConvertUnits.ToDisplayUnits(DockingTarget.Item.Submarine.Velocity) * deltaTime;
                }
            }

            pressureWarningText.Visible = item.Submarine != null && item.Submarine.AtDamageDepth && Timing.TotalTime % 1.0f < 0.8f;
            iceSpireWarningText.Visible = item.Submarine != null && !pressureWarningText.Visible && showIceSpireWarning && Timing.TotalTime % 1.0f < 0.8f;

            if (Vector2.DistanceSquared(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerRadius * steerRadius)
            {
                if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen && !GameSession.IsTabMenuOpen &&
                    (!GameMain.GameSession?.Campaign?.ShowCampaignUI ?? true) && !GUIMessageBox.MessageBoxes.Any(msgBox => msgBox is GUIMessageBox {
                    MessageBoxType: GUIMessageBox.Type.Default
                }))