667 lines
29 KiB
C#
667 lines
29 KiB
C#
using Barotrauma.Networking;
|
|
using FarseerPhysics;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Input;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Barotrauma.Items.Components
|
|
{
|
|
partial class Steering : Powered, IServerSerializable, IClientSerializable
|
|
{
|
|
enum Mode
|
|
{
|
|
AutoPilot,
|
|
Manual
|
|
};
|
|
private GUITickBox autopilotTickBox, manualTickBox;
|
|
|
|
enum Destination
|
|
{
|
|
MaintainPos,
|
|
LevelEnd,
|
|
LevelStart
|
|
};
|
|
private GUITickBox maintainPosTickBox, levelEndTickBox, levelStartTickBox;
|
|
|
|
private GUIFrame autoPilotControlsDisabler;
|
|
|
|
private GUIComponent steerArea;
|
|
|
|
private GUITextBlock pressureWarningText;
|
|
|
|
private GUITextBlock tipContainer;
|
|
|
|
private string noPowerTip, autoPilotMaintainPosTip, autoPilotLevelStartTip, autoPilotLevelEndTip;
|
|
|
|
private Vector2 keyboardInput = Vector2.Zero;
|
|
private float inputCumulation;
|
|
|
|
private bool levelStartSelected;
|
|
public bool LevelStartSelected
|
|
{
|
|
get { return levelStartTickBox.Selected; }
|
|
set { levelStartTickBox.Selected = value; }
|
|
}
|
|
|
|
private bool levelEndSelected;
|
|
public bool LevelEndSelected
|
|
{
|
|
get { return levelEndTickBox.Selected; }
|
|
set { levelEndTickBox.Selected = value; }
|
|
}
|
|
|
|
private bool maintainPos;
|
|
public bool MaintainPos
|
|
{
|
|
get { return maintainPosTickBox.Selected; }
|
|
set { maintainPosTickBox.Selected = value; }
|
|
}
|
|
|
|
public bool DockingModeEnabled
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public DockingPort DockingSource, DockingTarget;
|
|
|
|
partial void InitProjSpecific()
|
|
{
|
|
int viewSize = (int)Math.Min(GuiFrame.Rect.Width - 150, GuiFrame.Rect.Height * 0.9f);
|
|
var controlContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.35f), GuiFrame.RectTransform, Anchor.CenterLeft)
|
|
{ MinSize = new Point(150, 0), AbsoluteOffset = new Point((int)(viewSize * 0.99f), (int)(viewSize * 0.05f)) }, "SonarFrame");
|
|
var paddedControlContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), controlContainer.RectTransform, Anchor.Center))
|
|
{
|
|
RelativeSpacing = 0.03f,
|
|
Stretch = true
|
|
};
|
|
|
|
var statusContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GuiFrame.RectTransform, Anchor.BottomLeft)
|
|
{ MinSize = new Point(150, 0), AbsoluteOffset = new Point((int)(viewSize * 0.9f), 0) }, "SonarFrame");
|
|
var paddedStatusContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), statusContainer.RectTransform, Anchor.Center))
|
|
{
|
|
RelativeSpacing = 0.03f,
|
|
Stretch = true
|
|
};
|
|
|
|
manualTickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.3f), paddedControlContainer.RectTransform),
|
|
TextManager.Get("SteeringManual"), style: "GUIRadioButton")
|
|
{
|
|
Selected = true,
|
|
OnSelected = (GUITickBox box) =>
|
|
{
|
|
AutoPilot = !box.Selected;
|
|
unsentChanges = true;
|
|
user = Character.Controlled;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
autopilotTickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.3f), paddedControlContainer.RectTransform),
|
|
TextManager.Get("SteeringAutoPilot"), style: "GUIRadioButton")
|
|
{
|
|
OnSelected = (GUITickBox box) =>
|
|
{
|
|
AutoPilot = box.Selected;
|
|
if (AutoPilot && MaintainPos)
|
|
{
|
|
posToMaintain = controlledSub == null ? item.WorldPosition : controlledSub.WorldPosition;
|
|
}
|
|
unsentChanges = true;
|
|
user = Character.Controlled;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
GUIRadioButtonGroup modes = new GUIRadioButtonGroup();
|
|
modes.AddRadioButton(Mode.AutoPilot, autopilotTickBox);
|
|
modes.AddRadioButton(Mode.Manual, manualTickBox);
|
|
modes.Selected = Mode.Manual;
|
|
|
|
var autoPilotControls = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f), paddedControlContainer.RectTransform), "InnerFrame");
|
|
var paddedAutoPilotControls = new GUILayoutGroup(new RectTransform(new Vector2(0.8f), autoPilotControls.RectTransform, Anchor.Center))
|
|
{
|
|
Stretch = true,
|
|
RelativeSpacing = 0.03f
|
|
};
|
|
|
|
maintainPosTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), paddedAutoPilotControls.RectTransform),
|
|
TextManager.Get("SteeringMaintainPos"), font: GUI.SmallFont)
|
|
{
|
|
Enabled = false,
|
|
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;
|
|
}
|
|
};
|
|
|
|
levelStartTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), paddedAutoPilotControls.RectTransform),
|
|
GameMain.GameSession?.StartLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.StartLocation.Name, 20),
|
|
font: GUI.SmallFont)
|
|
{
|
|
Enabled = false,
|
|
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(0.2f, 0.2f), paddedAutoPilotControls.RectTransform),
|
|
GameMain.GameSession?.EndLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.EndLocation.Name, 20),
|
|
font: GUI.SmallFont)
|
|
{
|
|
Enabled = false,
|
|
Selected = levelEndSelected,
|
|
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;
|
|
}
|
|
};
|
|
|
|
autoPilotControlsDisabler = new GUIFrame(new RectTransform(Vector2.One, autoPilotControls.RectTransform), "InnerFrame");
|
|
|
|
GUIRadioButtonGroup destinations = new GUIRadioButtonGroup();
|
|
destinations.AddRadioButton(Destination.MaintainPos, maintainPosTickBox);
|
|
destinations.AddRadioButton(Destination.LevelStart, levelStartTickBox);
|
|
destinations.AddRadioButton(Destination.LevelEnd, levelEndTickBox);
|
|
destinations.Selected = maintainPos ? Destination.MaintainPos :
|
|
levelStartSelected ? Destination.LevelStart : Destination.LevelEnd;
|
|
|
|
string steeringVelX = TextManager.Get("SteeringVelocityX");
|
|
string steeringVelY = TextManager.Get("SteeringVelocityY");
|
|
string steeringDepth = TextManager.Get("SteeringDepth");
|
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), paddedStatusContainer.RectTransform), "")
|
|
{
|
|
TextGetter = () =>
|
|
{
|
|
Vector2 vel = controlledSub == null ? Vector2.Zero : controlledSub.Velocity;
|
|
var realWorldVel = ConvertUnits.ToDisplayUnits(vel.Y * Physics.DisplayToRealWorldRatio) * 3.6f;
|
|
return steeringVelY.Replace("[kph]", ((int)-realWorldVel).ToString());
|
|
}
|
|
};
|
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), paddedStatusContainer.RectTransform), "")
|
|
{
|
|
TextGetter = () =>
|
|
{
|
|
Vector2 vel = controlledSub == null ? Vector2.Zero : controlledSub.Velocity;
|
|
var realWorldVel = ConvertUnits.ToDisplayUnits(vel.X * Physics.DisplayToRealWorldRatio) * 3.6f;
|
|
return steeringVelX.Replace("[kph]", ((int)realWorldVel).ToString());
|
|
}
|
|
};
|
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), paddedStatusContainer.RectTransform), "")
|
|
{
|
|
TextGetter = () =>
|
|
{
|
|
Vector2 pos = controlledSub == null ? Vector2.Zero : controlledSub.Position;
|
|
float realWorldDepth = Level.Loaded == null ? 0.0f : Math.Abs(pos.Y - Level.Loaded.Size.Y) * Physics.DisplayToRealWorldRatio;
|
|
return steeringDepth.Replace("[m]", ((int)realWorldDepth).ToString());
|
|
}
|
|
};
|
|
|
|
pressureWarningText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), paddedStatusContainer.RectTransform), TextManager.Get("SteeringDepthWarning"), Color.Red)
|
|
{
|
|
Visible = false
|
|
};
|
|
|
|
tipContainer = new GUITextBlock(new RectTransform(new Vector2(0.25f, 0.12f), GuiFrame.RectTransform, Anchor.BottomLeft)
|
|
{ MinSize = new Point(150, 0), RelativeOffset = new Vector2(0.0f, -0.05f) }, "", wrap: true, style: "GUIToolTip")
|
|
{
|
|
AutoScale = true
|
|
};
|
|
|
|
noPowerTip = TextManager.Get("SteeringNoPowerTip");
|
|
autoPilotMaintainPosTip = TextManager.Get("SteeringAutoPilotMaintainPosTip");
|
|
autoPilotLevelStartTip = TextManager.Get("SteeringAutoPilotLocationTip").Replace("[locationname]",
|
|
GameMain.GameSession?.StartLocation == null ? "Start" : GameMain.GameSession.StartLocation.Name);
|
|
autoPilotLevelEndTip = TextManager.Get("SteeringAutoPilotLocationTip").Replace("[locationname]",
|
|
GameMain.GameSession?.EndLocation == null ? "End" : GameMain.GameSession.EndLocation.Name);
|
|
|
|
steerArea = new GUICustomComponent(new RectTransform(new Point(viewSize), GuiFrame.RectTransform, Anchor.CenterLeft),
|
|
(spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); }, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the sonar view CustomComponent render the steering HUD, preventing it from being drawn behing the sonar
|
|
/// </summary>
|
|
public void AttachToSonarHUD(GUICustomComponent sonarView)
|
|
{
|
|
steerArea.Visible = false;
|
|
sonarView.OnDraw += (spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); };
|
|
}
|
|
|
|
public void DrawHUD(SpriteBatch spriteBatch, Rectangle rect)
|
|
{
|
|
int width = rect.Width, height = rect.Height;
|
|
int x = rect.X;
|
|
int y = rect.Y;
|
|
|
|
if (voltage < minVoltage && currPowerConsumption > 0.0f) return;
|
|
|
|
Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40);
|
|
GUI.DrawLine(spriteBatch,
|
|
new Vector2(velRect.Center.X, velRect.Center.Y),
|
|
new Vector2(velRect.Center.X + currVelocity.X, velRect.Center.Y - currVelocity.Y),
|
|
Color.Gray);
|
|
|
|
if (!AutoPilot)
|
|
{
|
|
Vector2 unitSteeringInput = steeringInput / 100.0f;
|
|
//map input from rectangle to circle
|
|
Vector2 steeringInputPos = new Vector2(
|
|
steeringInput.X * (float)Math.Sqrt(1.0f - 0.5f * unitSteeringInput.Y * unitSteeringInput.Y),
|
|
-steeringInput.Y * (float)Math.Sqrt(1.0f - 0.5f * unitSteeringInput.X * unitSteeringInput.X));
|
|
steeringInputPos.X += velRect.Center.X;
|
|
steeringInputPos.Y += velRect.Center.Y;
|
|
|
|
GUI.DrawLine(spriteBatch,
|
|
new Vector2(velRect.Center.X, velRect.Center.Y),
|
|
steeringInputPos,
|
|
Color.LightGray);
|
|
|
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)steeringInputPos.X - 5, (int)steeringInputPos.Y - 5, 10, 10), Color.White);
|
|
|
|
//if (keyboardInput.Length() > 0 || Vector2.Distance(PlayerInput.MousePosition, new Vector2(velRect.Center.X, velRect.Center.Y)) < 200.0f)
|
|
if (velRect.Contains(PlayerInput.MousePosition))
|
|
{
|
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)steeringInputPos.X - 10, (int)steeringInputPos.Y - 10, 20, 20), Color.Red);
|
|
}
|
|
}
|
|
else if (posToMaintain.HasValue && !LevelStartSelected && !LevelEndSelected)
|
|
{
|
|
Sonar sonar = item.GetComponent<Sonar>();
|
|
if (sonar != null && controlledSub != null)
|
|
{
|
|
Vector2 displayPosToMaintain = ((posToMaintain.Value - sonar.DisplayOffset * sonar.Zoom - controlledSub.WorldPosition)) / sonar.Range * sonar.DisplayRadius * sonar.Zoom;
|
|
displayPosToMaintain.Y = -displayPosToMaintain.Y;
|
|
displayPosToMaintain = displayPosToMaintain.ClampLength(velRect.Width / 2);
|
|
displayPosToMaintain = velRect.Center.ToVector2() + displayPosToMaintain;
|
|
|
|
float crossHairSize = 8.0f;
|
|
Color crosshairColor = Color.Orange * (0.5f + ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) / 4.0f);
|
|
|
|
GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitY * crossHairSize, displayPosToMaintain - Vector2.UnitY * crossHairSize, crosshairColor, width: 3);
|
|
GUI.DrawLine(spriteBatch, displayPosToMaintain + Vector2.UnitX * crossHairSize, displayPosToMaintain - Vector2.UnitX * crossHairSize, crosshairColor, width: 3);
|
|
|
|
Vector2 neutralPos = ((controlledSub.WorldPosition - sonar.DisplayOffset * sonar.Zoom - controlledSub.WorldPosition)) / sonar.Range * sonar.DisplayRadius * sonar.Zoom;
|
|
|
|
neutralPos.Y = -neutralPos.Y;
|
|
neutralPos = neutralPos.ClampLength(velRect.Width / 2);
|
|
neutralPos = velRect.Center.ToVector2() + neutralPos;
|
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)neutralPos.X - 5, (int)neutralPos.Y - 5, 10, 10), Color.Orange);
|
|
}
|
|
}
|
|
|
|
//map velocity from rectangle to circle
|
|
Vector2 unitTargetVel = targetVelocity / 100.0f;
|
|
Vector2 steeringPos = new Vector2(
|
|
targetVelocity.X * 0.9f * (float)Math.Sqrt(1.0f - 0.5f * unitTargetVel.Y * unitTargetVel.Y),
|
|
-targetVelocity.Y * 0.9f * (float)Math.Sqrt(1.0f - 0.5f * unitTargetVel.X * unitTargetVel.X));
|
|
steeringPos.X += velRect.Center.X;
|
|
steeringPos.Y += velRect.Center.Y;
|
|
|
|
GUI.DrawLine(spriteBatch,
|
|
new Vector2(velRect.Center.X, velRect.Center.Y),
|
|
steeringPos,
|
|
Color.CadetBlue, 0, 2);
|
|
}
|
|
|
|
public void DebugDrawHUD(SpriteBatch spriteBatch, Vector2 transducerCenter, float displayScale, float displayRadius, Vector2 center)
|
|
{
|
|
if (SteeringPath == null) return;
|
|
|
|
Vector2 prevPos = Vector2.Zero;
|
|
foreach (WayPoint wp in SteeringPath.Nodes)
|
|
{
|
|
Vector2 pos = (wp.Position - transducerCenter) * displayScale;
|
|
if (pos.Length() > displayRadius) continue;
|
|
|
|
pos.Y = -pos.Y;
|
|
pos += center;
|
|
|
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - 3 / 2, (int)pos.Y - 3, 6, 6), (SteeringPath.CurrentNode == wp) ? Color.LightGreen : Color.Green, false);
|
|
|
|
if (prevPos != Vector2.Zero)
|
|
{
|
|
GUI.DrawLine(spriteBatch, pos, prevPos, Color.Green);
|
|
}
|
|
|
|
prevPos = pos;
|
|
}
|
|
|
|
foreach (ObstacleDebugInfo obstacle in debugDrawObstacles)
|
|
{
|
|
Vector2 pos1 = (obstacle.Point1 - transducerCenter) * displayScale;
|
|
pos1.Y = -pos1.Y;
|
|
pos1 += center;
|
|
Vector2 pos2 = (obstacle.Point2 - transducerCenter) * displayScale;
|
|
pos2.Y = -pos2.Y;
|
|
pos2 += center;
|
|
|
|
GUI.DrawLine(spriteBatch,
|
|
pos1,
|
|
pos2,
|
|
Color.Red * 0.6f, width: 3);
|
|
|
|
if (obstacle.Intersection.HasValue)
|
|
{
|
|
Vector2 intersectionPos = (obstacle.Intersection.Value - transducerCenter) *displayScale;
|
|
intersectionPos.Y = -intersectionPos.Y;
|
|
intersectionPos += center;
|
|
GUI.DrawRectangle(spriteBatch, intersectionPos - Vector2.One * 2, Vector2.One * 4, Color.Red);
|
|
}
|
|
|
|
Vector2 obstacleCenter = (pos1 + pos2) / 2;
|
|
if (obstacle.AvoidStrength.LengthSquared() > 0.01f)
|
|
{
|
|
GUI.DrawLine(spriteBatch,
|
|
obstacleCenter,
|
|
obstacleCenter + new Vector2(obstacle.AvoidStrength.X, -obstacle.AvoidStrength.Y) * 100,
|
|
Color.Lerp(Color.Green, Color.Orange, obstacle.Dot), width: 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
|
{
|
|
if (steerArea.Rect.Contains(PlayerInput.MousePosition))
|
|
{
|
|
if (!PlayerInput.KeyDown(InputType.Select) && !PlayerInput.KeyHit(InputType.Select))
|
|
{
|
|
Character.DisableControls = true;
|
|
}
|
|
}
|
|
|
|
autoPilotControlsDisabler.Visible = !AutoPilot;
|
|
|
|
if (voltage < minVoltage && currPowerConsumption > 0.0f)
|
|
{
|
|
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.Distance(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerArea.Rect.Width / 2)
|
|
{
|
|
if (PlayerInput.LeftButtonHeld())
|
|
{
|
|
Vector2 inputPos = PlayerInput.MousePosition - steerArea.Rect.Center.ToVector2();
|
|
inputPos.Y = -inputPos.Y;
|
|
if (AutoPilot && !LevelStartSelected && !LevelEndSelected)
|
|
{
|
|
posToMaintain = controlledSub == null ?
|
|
item.WorldPosition :
|
|
controlledSub.WorldPosition + (sonar.DisplayOffset * sonar.Zoom) + inputPos / sonar.DisplayRadius * sonar.Range / sonar.Zoom;
|
|
}
|
|
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(Keys.LeftShift))
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
float closestDist = DockingAssistThreshold * DockingAssistThreshold;
|
|
DockingModeEnabled = false;
|
|
DockingSource = null;
|
|
DockingTarget = null;
|
|
foreach (DockingPort sourcePort in DockingPort.List)
|
|
{
|
|
if (sourcePort.Docked || sourcePort.Item.Submarine == null) { continue; }
|
|
if (sourcePort.Item.Submarine != controlledSub) { continue; }
|
|
|
|
int sourceDir = sourcePort.IsHorizontal ?
|
|
Math.Sign(sourcePort.Item.WorldPosition.X - sourcePort.Item.Submarine.WorldPosition.X) :
|
|
Math.Sign(sourcePort.Item.WorldPosition.Y - sourcePort.Item.Submarine.WorldPosition.Y);
|
|
|
|
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 (Level.Loaded != null && targetPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
|
|
|
int targetDir = targetPort.IsHorizontal ?
|
|
Math.Sign(targetPort.Item.WorldPosition.X - targetPort.Item.Submarine.WorldPosition.X) :
|
|
Math.Sign(targetPort.Item.WorldPosition.Y - targetPort.Item.Submarine.WorldPosition.Y);
|
|
|
|
if (sourceDir == targetDir) { continue; }
|
|
|
|
float dist = Vector2.DistanceSquared(sourcePort.Item.WorldPosition, targetPort.Item.WorldPosition);
|
|
if (dist < closestDist)
|
|
{
|
|
DockingModeEnabled = true;
|
|
DockingSource = sourcePort;
|
|
DockingTarget = targetPort;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
|
{
|
|
msg.Write(autoPilot);
|
|
|
|
if (!autoPilot)
|
|
{
|
|
//no need to write steering info if autopilot is controlling
|
|
msg.Write(steeringInput.X);
|
|
msg.Write(steeringInput.Y);
|
|
}
|
|
else
|
|
{
|
|
msg.Write(posToMaintain != null);
|
|
if (posToMaintain != null)
|
|
{
|
|
msg.Write(((Vector2)posToMaintain).X);
|
|
msg.Write(((Vector2)posToMaintain).Y);
|
|
}
|
|
else
|
|
{
|
|
msg.Write(LevelStartSelected);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
|
|
{
|
|
long msgStartPos = msg.Position;
|
|
|
|
bool autoPilot = msg.ReadBoolean();
|
|
Vector2 newSteeringInput = steeringInput;
|
|
Vector2 newTargetVelocity = targetVelocity;
|
|
float newSteeringAdjustSpeed = steeringAdjustSpeed;
|
|
bool maintainPos = false;
|
|
Vector2? newPosToMaintain = null;
|
|
bool headingToStart = false;
|
|
|
|
if (autoPilot)
|
|
{
|
|
maintainPos = msg.ReadBoolean();
|
|
if (maintainPos)
|
|
{
|
|
newPosToMaintain = new Vector2(
|
|
msg.ReadFloat(),
|
|
msg.ReadFloat());
|
|
}
|
|
else
|
|
{
|
|
headingToStart = msg.ReadBoolean();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newSteeringInput = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
|
newTargetVelocity = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
|
newSteeringAdjustSpeed = msg.ReadFloat();
|
|
}
|
|
|
|
if (correctionTimer > 0.0f)
|
|
{
|
|
int msgLength = (int)(msg.Position - msgStartPos);
|
|
msg.Position = msgStartPos;
|
|
StartDelayedCorrection(type, msg.ExtractBits(msgLength), sendingTime);
|
|
return;
|
|
}
|
|
|
|
AutoPilot = autoPilot;
|
|
|
|
if (!AutoPilot)
|
|
{
|
|
SteeringInput = newSteeringInput;
|
|
TargetVelocity = newTargetVelocity;
|
|
steeringAdjustSpeed = newSteeringAdjustSpeed;
|
|
}
|
|
else
|
|
{
|
|
MaintainPos = newPosToMaintain != null;
|
|
posToMaintain = newPosToMaintain;
|
|
|
|
if (posToMaintain == null)
|
|
{
|
|
LevelStartSelected = headingToStart;
|
|
LevelEndSelected = !headingToStart;
|
|
UpdatePath();
|
|
}
|
|
else
|
|
{
|
|
LevelStartSelected = false;
|
|
LevelEndSelected = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|