4 using Microsoft.Xna.Framework;
5 using Microsoft.Xna.Framework.Graphics;
7 using System.Collections.Generic;
14 private GUIButton steeringModeSwitch;
15 private GUITickBox autopilotIndicator, manualPilotIndicator;
24 private GUITickBox maintainPosTickBox, levelEndTickBox, levelStartTickBox;
26 private GUIComponent statusContainer, dockingContainer;
30 private bool dockingNetworkMessagePending;
37 private GUITextBlock pressureWarningText, iceSpireWarningText;
41 private LocalizedString noPowerTip, autoPilotMaintainPosTip, autoPilotLevelStartTip, autoPilotLevelEndTip;
43 private Sprite maintainPosIndicator, maintainPosOriginIndicator;
44 private Sprite steeringIndicator;
46 private List<DockingPort> connectedPorts =
new List<DockingPort>();
47 private float checkConnectedPortsTimer;
48 private const float CheckConnectedPortsInterval = 1.0f;
52 private Vector2 keyboardInput = Vector2.Zero;
53 private float inputCumulation;
55 private bool? swapDestinationOrder;
59 private bool levelStartSelected;
62 get {
return levelStartTickBox.Selected; }
63 set { levelStartTickBox.Selected = value; }
66 private bool levelEndSelected;
69 get {
return levelEndTickBox.Selected; }
70 set { levelEndTickBox.Selected = value; }
73 private bool maintainPos;
76 get {
return maintainPosTickBox.Selected; }
77 set { maintainPosTickBox.Selected = value; }
80 private float steerRadius;
89 steerRadius = value ?? (steerArea.
Rect.Width / 2);
93 private bool disableControls;
99 get {
return disableControls; }
102 if (disableControls == value) {
return; }
103 disableControls = value;
113 foreach (var subElement
in element.Elements())
115 switch (subElement.Name.ToString().ToLowerInvariant())
117 case "steeringindicator":
118 steeringIndicator =
new Sprite(subElement);
120 case "maintainposindicator":
121 maintainPosIndicator =
new Sprite(subElement);
123 case "maintainposoriginindicator":
124 maintainPosOriginIndicator =
new Sprite(subElement);
136 AbsoluteOffset = GUIStyle.ItemFrameOffset
139 var steeringModeArea =
new GUIFrame(
new RectTransform(
new Vector2(1, 0.4f), paddedControlContainer.RectTransform,
Anchor.TopLeft), style:
null);
140 steeringModeSwitch =
new GUIButton(
new RectTransform(
new Vector2(0.2f, 1), steeringModeArea.RectTransform),
string.Empty, style:
"SwitchVertical")
146 OnClicked = (button, data) =>
148 button.Selected = !button.Selected;
152 unsentChanges =
true;
158 var steeringModeRightSide =
new GUIFrame(
new RectTransform(
new Vector2(1.0f - steeringModeSwitch.RectTransform.RelativeSize.X, 0.8f), steeringModeArea.RectTransform,
Anchor.CenterLeft)
160 RelativeOffset = new Vector2(steeringModeSwitch.RectTransform.RelativeSize.X, 0)
163 TextManager.Get(
"SteeringManual"), font: GUIStyle.SubHeadingFont, style:
"IndicatorLightRedSmall")
169 TextManager.Get(
"SteeringAutoPilot"), font: GUIStyle.SubHeadingFont, style:
"IndicatorLightRedSmall")
174 manualPilotIndicator.TextBlock.OverrideTextColor(GUIStyle.TextColorNormal);
175 autopilotIndicator.TextBlock.OverrideTextColor(GUIStyle.TextColorNormal);
178 var autoPilotControls =
new GUIFrame(
new RectTransform(
new Vector2(0.75f, 0.62f), paddedControlContainer.RectTransform,
Anchor.BottomCenter),
"OutlineFrame");
179 var paddedAutoPilotControls =
new GUIFrame(
new RectTransform(
new Vector2(0.92f, 0.88f), autoPilotControls.RectTransform,
Anchor.Center), style:
null);
181 int textLimit = (int)(paddedAutoPilotControls.Rect.Width * 0.75f);
183 ToolBox.LimitString(TextManager.Get(
"SteeringMaintainPos"), GUIStyle.SmallFont, textLimit), font: GUIStyle.SmallFont, style:
"GUIRadioButton")
188 OnSelected = tickBox =>
190 if (maintainPos != tickBox.Selected)
192 unsentChanges =
true;
194 maintainPos = tickBox.Selected;
197 if (controlledSub ==
null)
199 posToMaintain =
null;
212 posToMaintain =
null;
220 font: GUIStyle.SmallFont, style:
"GUIRadioButton")
224 OnSelected = tickBox =>
226 if (levelStartSelected != tickBox.Selected)
228 unsentChanges =
true;
230 levelStartSelected = tickBox.Selected;
231 levelEndSelected = !levelStartSelected;
232 if (levelStartSelected)
247 font: GUIStyle.SmallFont, style:
"GUIRadioButton")
252 OnSelected = tickBox =>
254 if (levelEndSelected != tickBox.Selected)
256 unsentChanges =
true;
258 levelEndSelected = tickBox.Selected;
259 levelStartSelected = !levelEndSelected;
260 if (levelEndSelected)
272 maintainPosTickBox.RectTransform.IsFixedSize = levelStartTickBox.RectTransform.IsFixedSize = levelEndTickBox.RectTransform.IsFixedSize =
false;
273 maintainPosTickBox.RectTransform.MaxSize = levelStartTickBox.RectTransform.MaxSize = levelEndTickBox.RectTransform.MaxSize =
274 new Point(
int.MaxValue, paddedAutoPilotControls.Rect.Height / 3);
275 maintainPosTickBox.RectTransform.MinSize = levelStartTickBox.RectTransform.MinSize = levelEndTickBox.RectTransform.MinSize =
278 GUITextBlock.
AutoScaleAndNormalize(scaleHorizontal:
false, scaleVertical:
true, maintainPosTickBox.TextBlock, levelStartTickBox.TextBlock, levelEndTickBox.TextBlock);
281 destinations.
AddRadioButton((
int)Destination.MaintainPos, maintainPosTickBox);
282 destinations.
AddRadioButton((
int)Destination.LevelStart, levelStartTickBox);
283 destinations.
AddRadioButton((
int)Destination.LevelEnd, levelEndTickBox);
284 destinations.
Selected = (int)(maintainPos ? Destination.MaintainPos :
285 levelStartSelected ? Destination.LevelStart : Destination.LevelEnd);
290 RelativeOffset = Sonar.controlBoxOffset
292 var paddedStatusContainer =
new GUIFrame(
new RectTransform(statusContainer.Rect.Size - GUIStyle.ItemFrameMargin, statusContainer.RectTransform,
Anchor.Center, isFixedSize:
false)
294 AbsoluteOffset = GUIStyle.ItemFrameOffset
297 var elements = GUI.CreateElements(3,
new Vector2(1f, 0.333f), paddedStatusContainer.RectTransform, rt =>
new GUIFrame(rt, style:
null),
Anchor.TopCenter, relativeSpacing: 0.01f);
298 List<GUIComponent> leftElements =
new List<GUIComponent>(), centerElements =
new List<GUIComponent>(), rightElements =
new List<GUIComponent>();
299 for (
int i = 0; i < elements.Count; i++)
304 RelativeSpacing = 0.01f,
308 var center =
new GUIFrame(
new RectTransform(
new Vector2(0.15f, 1), group.RectTransform), style:
null);
309 var right =
new GUIFrame(
new RectTransform(
new Vector2(0.4f, 0.8f), group.RectTransform), style:
null);
310 leftElements.Add(left);
311 centerElements.Add(center);
312 rightElements.Add(right);
318 leftText = TextManager.Get(
"DescentVelocity");
319 centerText = TextManager.Get(
"KilometersPerHour");
320 rightTextGetter = () =>
322 Vector2 vel = controlledSub ==
null ? Vector2.Zero : controlledSub.
Velocity;
323 var realWorldVel = ConvertUnits.ToDisplayUnits(vel.Y * Physics.DisplayToRealWorldRatio) * 3.6f;
324 return (-realWorldVel).ToString(
"0.0");
328 leftText = TextManager.Get(
"Velocity");
329 centerText = TextManager.Get(
"KilometersPerHour");
330 rightTextGetter = () =>
332 Vector2 vel = controlledSub ==
null ? Vector2.Zero : controlledSub.
Velocity;
333 var realWorldVel = ConvertUnits.ToDisplayUnits(vel.X * Physics.DisplayToRealWorldRatio) * 3.6f;
334 if (controlledSub !=
null && controlledSub.
FlippedX) { realWorldVel *= -1; }
335 return realWorldVel.ToString(
"0.0");
339 leftText = TextManager.Get(
"Depth");
340 centerText = TextManager.Get(
"Meter");
341 rightTextGetter = () =>
345 return Timing.TotalTime % 5.0f < 0.5f ? Rand.Range(-9000, 9000).
ToString() :
"ERROR";
347 float realWorldDepth = controlledSub ==
null ? -1000.0f : controlledSub.
RealWorldDepth;
348 return ((
int)realWorldDepth).ToString();
352 new GUITextBlock(
new RectTransform(Vector2.One, left.RectTransform), leftText, font: GUIStyle.SubHeadingFont, wrap: leftText.Contains(
" "), textAlignment: Alignment.CenterRight);
353 new GUITextBlock(
new RectTransform(Vector2.One, center.RectTransform), centerText, font: GUIStyle.Font, textAlignment: Alignment.Center) { Padding = Vector4.Zero };
354 var digitalFrame =
new GUIFrame(
new RectTransform(Vector2.One, right.RectTransform), style:
"DigitalFrameDark");
355 new GUITextBlock(
new RectTransform(Vector2.One * 0.85f, digitalFrame.RectTransform,
Anchor.Center),
"12345", GUIStyle.TextColorDark, GUIStyle.DigitalFont, Alignment.CenterRight)
357 TextGetter = rightTextGetter
365 float dockingButtonSize = 1.1f;
366 float elementScale = 0.6f;
369 RelativeOffset = new Vector2(Sonar.controlBoxOffset.X + 0.05f, -0.05f)
372 dockText = TextManager.Get(
"label.navterminaldock",
"captain.dock");
373 undockText = TextManager.Get(
"label.navterminalundock",
"captain.undock");
374 dockingButton =
new GUIButton(
new RectTransform(
new Vector2(elementScale), dockingContainer.RectTransform,
Anchor.Center), dockText, style:
"PowerButton")
376 OnClicked = (btn, userdata) =>
380 new GUIMessageBox(
"", TextManager.Get(
"undockingdisabledbymission"));
386 DockingSources.Any(d => d.Docked && (d.DockingTarget?.Item.Submarine?.Info?.IsOutpost ??
false)))
389 if (!ObjectiveManager.AllActiveObjectivesCompleted())
392 TextManager.GetWithVariable(
"CampaignExitTutorialOutpostPrompt",
"[locationname]", campaign.Map.CurrentLocation.DisplayName),
393 new LocalizedString[] { TextManager.Get(
"yes"), TextManager.Get(
"no") });
394 exitOutpostPrompt.
Buttons[0].OnClicked += (_, _) =>
396 exitOutpostPrompt.
Close();
397 return OpenMap(campaign);
399 exitOutpostPrompt.
Buttons[1].OnClicked += exitOutpostPrompt.
Close;
402 return OpenMap(campaign);
405 !
ActiveDockingSource.
Docked && DockingTarget?.Item?.Submarine == Level.Loaded.StartOutpost && (DockingTarget?.Item?.Submarine?.Info.IsOutpost ??
false))
408 var subsToLeaveBehind = CampaignMode.GetSubsToLeaveBehind(
Item.
Submarine);
409 if (subsToLeaveBehind.Any())
411 enterOutpostPrompt =
new GUIMessageBox(
412 TextManager.GetWithVariable(
"enterlocation",
"[locationname]", DockingTarget.
Item.
Submarine.
Info.
Name),
413 TextManager.Get(subsToLeaveBehind.Count == 1 ?
"LeaveSubBehind" :
"LeaveSubsBehind"),
414 new LocalizedString[] { TextManager.Get(
"yes"), TextManager.Get(
"no") });
418 enterOutpostPrompt =
new GUIMessageBox(
"",
419 TextManager.GetWithVariable(
"campaignenteroutpostprompt",
"[locationname]", DockingTarget.
Item.
Submarine.
Info.
Name),
420 new LocalizedString[] { TextManager.Get(
"yes"), TextManager.Get(
"no") });
422 enterOutpostPrompt.
Buttons[0].OnClicked += (btn, userdata) =>
425 enterOutpostPrompt.
Close();
428 enterOutpostPrompt.
Buttons[1].OnClicked += enterOutpostPrompt.
Close;
438 bool OpenMap(CampaignMode campaign)
440 campaign.ShowCampaignUI =
true;
441 campaign.CampaignUI.SelectTab(CampaignMode.InteractionType.Map);
445 void SendDockingSignal()
447 if (GameMain.Client ==
null)
453 dockingNetworkMessagePending =
true;
454 item.CreateClientEvent(
this);
458 dockingButton.
Font = GUIStyle.SubHeadingFont;
462 var style = GUIStyle.GetComponentStyle(
"DockingButtonUp");
463 Sprite buttonSprite = style.Sprites.FirstOrDefault().Value.FirstOrDefault()?.Sprite;
464 Point buttonSize = buttonSprite !=
null ? buttonSprite.size.ToPoint() :
new Point(149, 52);
465 Point horizontalButtonSize = buttonSize.Multiply(elementScale * GUI.Scale * dockingButtonSize);
466 Point verticalButtonSize = horizontalButtonSize.Flip();
467 var leftButton =
new GUIButton(
new RectTransform(verticalButtonSize, dockingContainer.RectTransform,
Anchor.CenterLeft),
"", style:
"DockingButtonLeft")
469 OnClicked = NudgeButtonClicked,
470 UserData = -Vector2.UnitX
472 var rightButton =
new GUIButton(
new RectTransform(verticalButtonSize, dockingContainer.RectTransform,
Anchor.CenterRight),
"", style:
"DockingButtonRight")
474 OnClicked = NudgeButtonClicked,
475 UserData = Vector2.UnitX
477 var upButton =
new GUIButton(
new RectTransform(horizontalButtonSize, dockingContainer.RectTransform,
Anchor.TopCenter),
"", style:
"DockingButtonUp")
479 OnClicked = NudgeButtonClicked,
480 UserData = Vector2.UnitY
482 var downButton =
new GUIButton(
new RectTransform(horizontalButtonSize, dockingContainer.RectTransform,
Anchor.BottomCenter),
"", style:
"DockingButtonDown")
484 OnClicked = NudgeButtonClicked,
485 UserData = -Vector2.UnitY
490 (spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); },
null);
491 steerRadius = steerArea.
Rect.Width / 2;
493 iceSpireWarningText =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 0.25f), steerArea.
RectTransform,
Anchor.Center,
Pivot.TopCenter),
494 TextManager.Get(
"NavTerminalIceSpireWarning"), GUIStyle.Red, GUIStyle.SubHeadingFont, Alignment.Center, color: Color.Black * 0.8f, wrap:
true)
498 pressureWarningText =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 0.25f), steerArea.
RectTransform,
Anchor.Center,
Pivot.TopCenter),
499 TextManager.Get(
"SteeringDepthWarning"), GUIStyle.Red, GUIStyle.SubHeadingFont, Alignment.Center, color: Color.Black * 0.8f)
504 tipContainer =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 0.1f), steerArea.
RectTransform,
Anchor.BottomCenter,
Pivot.TopCenter)
505 ,
"", font: GUIStyle.Font, wrap:
true, style:
"GUIToolTip", textAlignment: Alignment.Center)
507 AutoScaleHorizontal =
true
509 noPowerTip = TextManager.Get(
"SteeringNoPowerTip");
510 autoPilotMaintainPosTip = TextManager.Get(
"SteeringAutoPilotMaintainPosTip");
511 autoPilotLevelStartTip = TextManager.GetWithVariable(
"SteeringAutoPilotLocationTip",
"[locationname]",
512 GameMain.GameSession?.StartLocation ==
null ?
"Start" : GameMain.GameSession.StartLocation.DisplayName);
513 autoPilotLevelEndTip = TextManager.GetWithVariable(
"SteeringAutoPilotLocationTip",
"[locationname]",
514 GameMain.GameSession?.EndLocation ==
null ?
"End" : GameMain.GameSession.EndLocation.DisplayName);
528 sonarView.
OnDraw += (spriteBatch, guiCustomComponent) =>
530 DrawHUD(spriteBatch, guiCustomComponent.Rect);
538 private static Vector2 MapSquareToCircle(Vector2 steeringVector)
540 float xSqr = steeringVector.X * steeringVector.X;
541 float ySqr = steeringVector.Y * steeringVector.Y;
542 float length = MathF.Sqrt(ySqr + xSqr);
543 if (MathUtils.NearlyEqual(length, 0.0f)) {
return Vector2.Zero; }
546 float x = steeringVector.X * MathF.Sqrt(xSqr + ySqr - xSqr * ySqr) / length;
547 float y = steeringVector.Y * MathF.Sqrt(xSqr + ySqr - xSqr * ySqr) / length;
548 return new Vector2(x, y);
551 public void DrawHUD(SpriteBatch spriteBatch, Rectangle rect)
553 int width = rect.Width, height = rect.Height;
557 if (Voltage < MinVoltage) {
return; }
560 Vector2 steeringOrigin = steerArea.
Rect.Center.ToVector2();
565 Vector2 steeringInputPos = MapSquareToCircle(steeringInput / 100f) * 100.0f;
566 steeringInputPos.Y = -steeringInputPos.Y;
567 steeringInputPos += steeringOrigin;
569 if (steeringIndicator !=
null)
571 Vector2 dir = steeringInputPos - steeringOrigin;
572 float angle = (float)Math.Atan2(dir.Y, dir.X);
573 steeringIndicator.
Draw(spriteBatch, steeringOrigin, Color.White, origin: steeringIndicator.
Origin, rotate: angle,
574 scale:
new Vector2(dir.Length() / steeringIndicator.
size.X, 1.0f));
578 GUI.DrawLine(spriteBatch, steeringOrigin, steeringInputPos, Color.LightGray);
579 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)steeringInputPos.X - 5, (
int)steeringInputPos.Y - 5, 10, 10), Color.White);
584 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)steeringInputPos.X - 4, (
int)steeringInputPos.Y - 4, 8, 8), GUIStyle.Red, thickness: 2);
587 else if (posToMaintain.HasValue && !LevelStartSelected && !LevelEndSelected)
590 if (sonar !=
null && controlledSub !=
null)
592 Vector2 displayPosToMaintain = ((posToMaintain.Value - controlledSub.WorldPosition)) * sonar.
DisplayScale;
594 displayPosToMaintain.Y = -displayPosToMaintain.Y;
595 displayPosToMaintain = displayPosToMaintain.ClampLength(velRect.Width / 2);
596 displayPosToMaintain = steerArea.
Rect.Center.ToVector2() + displayPosToMaintain;
598 Color crosshairColor = GUIStyle.Orange * (0.5f + ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) / 4.0f);
599 if (maintainPosIndicator !=
null)
601 maintainPosIndicator.
Draw(spriteBatch, displayPosToMaintain, crosshairColor, scale: 0.5f * sonar.
Zoom);
605 float crossHairSize = 8.0f;
606 GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitY * crossHairSize, displayPosToMaintain - Vector2.UnitY * crossHairSize, crosshairColor, width: 3);
607 GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitX * crossHairSize, displayPosToMaintain - Vector2.UnitX * crossHairSize, crosshairColor, width: 3);
610 if (maintainPosOriginIndicator !=
null)
612 maintainPosOriginIndicator.
Draw(spriteBatch, steeringOrigin, GUIStyle.Orange, scale: 0.5f * sonar.
Zoom);
616 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)steeringOrigin.X - 5, (int)steeringOrigin.Y - 5, 10, 10), GUIStyle.Orange);
622 Vector2 steeringPos = MapSquareToCircle(targetVelocity / 100f) * 90.0f;
623 steeringPos.Y = -steeringPos.Y;
624 steeringPos += steeringOrigin;
626 if (steeringIndicator !=
null)
628 Vector2 dir = steeringPos - steeringOrigin;
629 float angle = (float)Math.Atan2(dir.Y, dir.X);
630 steeringIndicator.
Draw(spriteBatch, steeringOrigin, Color.Gray, origin: steeringIndicator.
Origin, rotate: angle,
631 scale:
new Vector2(dir.Length() / steeringIndicator.
size.X, 0.7f));
635 GUI.DrawLine(spriteBatch,
638 Color.CadetBlue, 0, 2);
642 public void DebugDrawHUD(SpriteBatch spriteBatch, Vector2 transducerCenter,
float displayScale,
float displayRadius, Vector2 center)
646 Vector2 prevPos = Vector2.Zero;
649 Vector2 pos = (wp.
Position - transducerCenter) * displayScale;
650 if (pos.Length() > displayRadius)
continue;
655 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)pos.X - 3 / 2, (
int)pos.Y - 3, 6, 6), (
SteeringPath.
CurrentNode == wp) ? Color.LightGreen : GUIStyle.Green,
false);
657 if (prevPos != Vector2.Zero)
659 GUI.DrawLine(spriteBatch, pos, prevPos, GUIStyle.Green);
665 foreach (ObstacleDebugInfo obstacle
in debugDrawObstacles)
667 Vector2 pos1 = (obstacle.Point1 - transducerCenter) * displayScale;
670 Vector2 pos2 = (obstacle.Point2 - transducerCenter) * displayScale;
674 GUI.DrawLine(spriteBatch,
677 GUIStyle.Red * 0.6f, width: 3);
679 if (obstacle.Intersection.HasValue)
681 Vector2 intersectionPos = (obstacle.Intersection.Value - transducerCenter) * displayScale;
682 intersectionPos.Y = -intersectionPos.Y;
683 intersectionPos += center;
684 GUI.DrawRectangle(spriteBatch, intersectionPos - Vector2.One * 2, Vector2.One * 4, GUIStyle.Red);
687 Vector2 obstacleCenter = (pos1 + pos2) / 2;
688 if (obstacle.AvoidStrength.LengthSquared() > 0.01f)
690 GUI.DrawLine(spriteBatch,
692 obstacleCenter +
new Vector2(obstacle.AvoidStrength.X, -obstacle.AvoidStrength.Y) * 100,
693 Color.Lerp(GUIStyle.Green, GUIStyle.Orange, obstacle.Dot), width: 2);
700 if (swapDestinationOrder ==
null)
702 swapDestinationOrder = item.Submarine !=
null && item.Submarine.FlippedX;
703 if (swapDestinationOrder.Value)
705 levelStartTickBox.RectTransform.SetAsLastChild();
719 dockingModeEnabled =
false;
722 dockingContainer.Visible = DockingModeEnabled;
723 statusContainer.Visible = !DockingModeEnabled;
724 if (!DockingModeEnabled)
726 enterOutpostPrompt?.
Close();
729 if (DockingModeEnabled && ActiveDockingSource !=
null)
734 dockingButton.
Text = dockText;
737 dockingButton.
Flash(GUIStyle.Blue, 0.5f, useCircularFlash:
true);
738 dockingButton.
Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.
FlashTimer);
743 enterOutpostPrompt?.
Close();
746 else if (connectedPorts.Any(d => d.Docked))
748 dockingButton.
Text = undockText;
749 dockingContainer.Visible =
true;
750 statusContainer.Visible =
false;
753 dockingButton.
Flash(GUIStyle.Orange, useCircularFlash:
true);
754 dockingButton.
Pulsate(Vector2.One, Vector2.One * 1.2f, dockingButton.
FlashTimer);
759 dockingButton.
Text = dockText;
762 if (Voltage < MinVoltage)
765 tipContainer.
Text = noPowerTip;
769 tipContainer.
Visible = AutoPilot;
774 tipContainer.
Text = autoPilotMaintainPosTip;
776 else if (LevelStartSelected)
778 tipContainer.
Text = autoPilotLevelStartTip;
780 else if (LevelEndSelected)
782 tipContainer.
Text = autoPilotLevelEndTip;
785 if (DockingModeEnabled && DockingTarget !=
null)
791 pressureWarningText.
Visible = item.Submarine !=
null && Timing.TotalTime % 1.0f < 0.8f;
794 item.Submarine.RealWorldDepth > item.Submarine.RealWorldCrushDepth - PressureWarningThreshold)
796 pressureWarningText.
Visible =
true;
797 pressureWarningText.
Text =
798 item.Submarine.AtDamageDepth ?
799 TextManager.Get(
"SteeringDepthWarning") :
800 TextManager.GetWithVariable(
"SteeringDepthWarningLow",
"[crushdepth]", ((
int)item.Submarine.RealWorldCrushDepth).ToString());
804 pressureWarningText.
Visible =
false;
807 iceSpireWarningText.
Visible = item.Submarine !=
null && !pressureWarningText.
Visible && showIceSpireWarning && Timing.TotalTime % 1.0f < 0.8f;
809 if (!disableControls && Vector2.DistanceSquared(
PlayerInput.
MousePosition, steerArea.
Rect.Center.ToVector2()) < steerRadius * steerRadius)
815 inputPos.Y = -inputPos.Y;
816 if (AutoPilot && !LevelStartSelected && !LevelEndSelected)
818 posToMaintain = controlledSub !=
null ?
819 controlledSub.WorldPosition + inputPos / sonar.DisplayRadius * sonar.Range / sonar.Zoom :
820 item.Submarine ==
null ? item.WorldPosition : item.Submarine.WorldPosition;
824 SteeringInput = inputPos;
826 unsentChanges =
true;
832 steeringAdjustSpeed = character ==
null ? DefaultSteeringAdjustSpeed : MathHelper.Lerp(0.2f, 1.0f, character.
GetSkillLevel(
"helm") / 100.0f);
833 Vector2 input = Vector2.Zero;
840 SteeringInput += input * deltaTime * 200;
842 keyboardInput = Vector2.Zero;
843 unsentChanges =
true;
847 float step = deltaTime * 5;
848 if (input.Length() > 0)
850 inputCumulation += step;
854 inputCumulation -= step;
856 float maxCumulation = 1;
857 inputCumulation = MathHelper.Clamp(inputCumulation, 0, maxCumulation);
858 float length = MathHelper.Lerp(0, 0.2f, MathUtils.InverseLerp(0, maxCumulation, inputCumulation));
859 var normalizedInput = Vector2.Normalize(input);
860 if (MathUtils.IsValid(normalizedInput))
862 keyboardInput += normalizedInput * length;
864 if (keyboardInput.LengthSquared() > 0.01f)
866 SteeringInput += keyboardInput;
867 unsentChanges =
true;
869 keyboardInput *= MathHelper.Clamp(1 - step, 0, 1);
876 keyboardInput = Vector2.Zero;
879 if (!UseAutoDocking || DisableControls) {
return; }
881 if (checkConnectedPortsTimer <= 0.0f)
883 Connection dockingConnection = item.Connections?.FirstOrDefault(c => c.Name ==
"toggle_docking");
884 if (dockingConnection !=
null)
886 connectedPorts = item.GetConnectedComponentsRecursive<
DockingPort>(dockingConnection, ignoreInactiveRelays:
true, allowTraversingBackwards:
false);
888 checkConnectedPortsTimer = CheckConnectedPortsInterval;
892 checkConnectedPortsTimer -= deltaTime;
895 DockingModeEnabled =
false;
897 if (connectedPorts.None()) {
return; }
899 float closestDist = DockingAssistThreshold * DockingAssistThreshold;
903 if (sourcePort.
Item.
Submarine != controlledSub) {
continue; }
905 int sourceDir = sourcePort.
GetDir();
913 if (sourceDir == targetPort.
GetDir()) {
continue; }
916 if (dist < closestDist)
919 DockingModeEnabled =
true;
920 ActiveDockingSource = sourcePort;
921 DockingTarget = targetPort;
927 private bool NudgeButtonClicked(
GUIButton btn,
object userdata)
929 if (!MaintainPos || !AutoPilot)
932 posToMaintain = item.Submarine.WorldPosition;
935 if (userdata is Vector2 nudgeAmount)
937 if (item.GetComponent<Sonar>() is Sonar sonar)
939 nudgeAmount *= 500.0f / sonar.Zoom;
941 PosToMaintain += nudgeAmount;
948 base.RemoveComponentSpecific();
949 maintainPosIndicator?.
Remove();
950 maintainPosOriginIndicator?.
Remove();
951 steeringIndicator?.
Remove();
952 enterOutpostPrompt?.
Close();
953 exitOutpostPrompt?.
Close();
961 dockingNetworkMessagePending =
false;
972 if (posToMaintain !=
null)
992 Vector2 newSteeringInput = steeringInput;
993 Vector2 newTargetVelocity = targetVelocity;
994 float newSteeringAdjustSpeed = steeringAdjustSpeed;
995 Vector2? newPosToMaintain =
null;
996 bool headingToStart =
false;
998 if (dockingButtonClicked)
1007 newPosToMaintain =
new Vector2(
1023 if (correctionTimer > 0.0f)
1025 int msgLength = (int)(msg.
BitPosition - msgStartPos);
1027 StartDelayedCorrection(msg.ExtractBits(msgLength), sendingTime);
1031 AutoPilot = autoPilot;
1035 SteeringInput = newSteeringInput;
1036 TargetVelocity = newTargetVelocity;
1037 steeringAdjustSpeed = newSteeringAdjustSpeed;
1041 MaintainPos = newPosToMaintain !=
null;
1042 posToMaintain = newPosToMaintain;
1044 if (posToMaintain ==
null)
1046 LevelStartSelected = headingToStart;
1047 LevelEndSelected = !headingToStart;
1052 LevelStartSelected =
false;
1053 LevelEndSelected =
false;
1058 private void UpdateGUIElements()
1060 steeringModeSwitch.Selected = AutoPilot;
1061 autopilotIndicator.Selected = AutoPilot;
1062 manualPilotIndicator.Selected = !AutoPilot;
1063 if (DisableControls)
1065 steeringModeSwitch.Enabled =
false;
1066 maintainPosTickBox.Enabled =
false;
1067 levelEndTickBox.Enabled =
false;
1068 levelStartTickBox.Enabled =
false;
1072 steeringModeSwitch.Enabled =
true;
1073 maintainPosTickBox.Enabled = AutoPilot;
1074 levelEndTickBox.Enabled = AutoPilot;
1075 levelStartTickBox.Enabled = AutoPilot;
bool??????? ShowCampaignUI
float GetSkillLevel(string skillIdentifier)
static bool DisableControls
static Character? Controlled
Responsible for keeping track of the characters in the player crew, saving and loading their orders,...
static bool? IsCommandInterfaceOpen
static Entity FindEntityByID(ushort ID)
Find an entity based on the ID
void Pulsate(Vector2 startScale, Vector2 endScale, float duration)
virtual void DrawChildren(SpriteBatch spriteBatch, bool recursive)
Draws all the children manually.
RectTransform RectTransform
GUIComponent that can be used to render custom content on the UI
Action< SpriteBatch, GUICustomComponent > OnDraw
static readonly List< GUIComponent > MessageBoxes
List< GUIButton > Buttons
bool AutoScaleHorizontal
When enabled, the text is automatically scaled down to fit the textblock horizontally.
static void AutoScaleAndNormalize(params GUITextBlock[] textBlocks)
Set the text scale of the GUITextBlocks so that they all use the same scale and can fit the text with...
delegate LocalizedString TextGetterHandler()
static GameSession?? GameSession
IEnumerable< Mission > Missions
static bool IsTabMenuOpen
void SendSignal(string signal, string connectionName)
static IEnumerable< DockingPort > List
int GetDir(DockingPort dockingTarget=null)
Vector2 DistanceTolerance
float DisplayScale
Current scale of the display, taking zoom into account. In other words, the scaling factor of world c...
static readonly Vector2 controlBoxSize
GUIComponent ControlContainer
override void RemoveComponentSpecific()
List< DockingPort > DockingSources
override void CreateGUI()
Overload this method and implement. The method is automatically called when the resolution changes.
void ClientEventRead(IReadMessage msg, float sendingTime)
bool DisableControls
Can be used by status effects to disable all the UI controls
override void OnResolutionChanged()
void DebugDrawHUD(SpriteBatch spriteBatch, Vector2 transducerCenter, float displayScale, float displayRadius, Vector2 center)
void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData=null)
void AttachToSonarHUD(GUICustomComponent sonarView)
Makes the sonar view CustomComponent render the steering HUD, preventing it from being drawn behing t...
override bool RecreateGUIOnResolutionChange
override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
void DrawHUD(SpriteBatch spriteBatch, Rectangle rect)
DockingPort ActiveDockingSource
float RealWorldCrushDepth
The crush depth of a non-upgraded submarine in "real world units" (meters from the surface of Europa)...
static bool IsLoadedOutpost
Is there a loaded level set and is it an outpost?
override string ToString()
LocalizedString DisplayName
override Vector2 Position
void Draw(ISpriteBatch spriteBatch, Vector2 pos, float rotate=0.0f, float scale=1.0f, SpriteEffects spriteEffect=SpriteEffects.None)
override Vector2? WorldPosition
IEnumerable< Submarine > DockedTo
float? RealWorldDepth
How deep down the sub is from the surface of Europa in meters (affected by level type,...
Highlights an UI element of some kind. Generally used in tutorials.
Interface for entities that the clients can send events to the server
Interface for entities that the server can send events to the clients
void WriteBoolean(bool val)
void WriteSingle(Single val)