74086415fc
commit e08c5e722fdff38d408428d138919bb8ea90321b Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Tue Feb 5 11:13:25 2019 +0200 Changed default radio chat keybind to T. OemTilde works as an apostrophe on some keyboard layouts, making it difficult to type in chat messages without deselecting the chatbox. Closes #1044 commit e0ca9ffebe06b3f711b28a3ccfd486d84c47f9b0 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Tue Feb 5 11:03:14 2019 +0200 Fixed content package compatibility check. Closes #1059 commit f54bc180e8aef383cf9c893cd44c103840c066ac Author: itchyOwl <lauri.harkanen@gmail.com> Date: Tue Feb 5 10:48:03 2019 +0200 Remove the spacing from the crew selection listbox and disable focusing from the background. An alternative fix for #1039. commit d037815054ecc8269b0af3297700d2b98e1e5bc5 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Tue Feb 5 10:40:52 2019 +0200 Enforce vsync during the splash screen. Should fix the crashes due to insufficient memory mentioned in #1060. Does not fix the issue on releasing the used video resources. commit 90f1d8fe168356ba3c797c0c58fadea2aff57458 Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 23:05:54 2019 +0200 small updates to subs commit 56dbdf6ea6e8e14035f943eb232eed7aa250f8f6 Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 23:05:26 2019 +0200 adjusted default deterioration values on prefabs commit eaa4818cb63d52e1af519c8ca5c4f01f20143cb2 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 21:59:03 2019 +0200 Fixed servers occasionally starting the round multiple times when automatically starting the game via autorestart or clients being ready. Happened because "initiatedStartGame" (which prevents starting the round again) was not set until the InitiateStartGame coroutine is run for the first time, causing the automatic restart logic to run one extra time. Closes #1056 commit afd83b6ef40333a95e5eeec400d5f981cbdb1889 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 21:36:35 2019 +0200 Fixed some typos in affliction & mission descriptions. Closes #1057 commit feb97628582a9a22f0660a8ab2798f8e03fe8fc9 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 18:29:40 2019 +0200 Fixes to Level.TryGetInterestingPosition. Should fix monsters spawning very close to the sub in some levels (see #1054). - Ignore outposts when determining which positions are far enough from the sub. - If no position far enough from the sub is found, use the furthest one instead of choosing randomly. commit 62e5d7b229f334a5cf15cedf22e6795f18d637b9 Merge: 6ffc90da6 73f3dd060 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 18:03:44 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 6ffc90da69d9a5db146435054fdbb2cb18d855be Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 18:03:26 2019 +0200 Allow to focus on the crew selection listbox to enable scrolling when the mouse cursor is not over a content element, but is inside the listbox. Another option would be to remove the spacing from the listbox. Fixes #1039. commit 73f3dd060ef208199941cb74a72dcda6a7c15f41 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 18:00:57 2019 +0200 Fixed compiler error in GameServer.ClientWriteIngame commit 131263490c7093dd526a84757f4edd096a213a74 Merge: 637668488 9753e46a5 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 17:55:39 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 637668488b27954afa0a8485eeaa3b23cf9461c5 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 17:55:01 2019 +0200 Changed character culling logic a bit. The characters need to be 22,000 units away from the players to be disabled, and won't be re-enabled until they're within 20,000 units. Using 20,000 as the threshold for both caused characters to be constantly toggled on/off when they're around the maximum distance, which caused ContactManager to constantly have to update contacts. commit 9753e46a5694b7b3c2bd0c4c006e2c1856c6eddb Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 17:54:35 2019 +0200 Add a debug command for adding more money in the compaign mode. commit f8a7179d6f8cb7c834b91b942722b1ae05417316 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 17:53:03 2019 +0200 Always disallow zooming when the cursor is over a gui element. commit eefd956c50650be906acbd10662e24507e48cb83 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 17:47:18 2019 +0200 Don't display outpost markers on the sonar (the ending and starting positions of the level are displayed, no need to show an additional marker on the "outpost submarine"). commit c7883bafc634e0ac2603bc96a87433da0c3481df Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 17:21:50 2019 +0200 removed references to medical syringes
1077 lines
47 KiB
C#
1077 lines
47 KiB
C#
using Barotrauma.Networking;
|
|
using FarseerPhysics;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Barotrauma.Items.Components
|
|
{
|
|
partial class Sonar : Powered, IServerSerializable, IClientSerializable
|
|
{
|
|
private bool unsentChanges;
|
|
private float networkUpdateTimer;
|
|
|
|
private GUITickBox activeTickBox, passiveTickBox;
|
|
private GUITextBlock signalWarningText;
|
|
|
|
private GUIScrollBar zoomSlider;
|
|
|
|
private GUITickBox directionalTickBox;
|
|
private GUIScrollBar directionalSlider;
|
|
|
|
private GUIComponent activeControlsContainer;
|
|
|
|
private GUICustomComponent sonarView;
|
|
|
|
private float displayBorderSize;
|
|
|
|
private List<SonarBlip> sonarBlips;
|
|
|
|
private float prevPingRadius;
|
|
|
|
private float prevPassivePingRadius;
|
|
|
|
private Vector2 center;
|
|
private float displayScale;
|
|
|
|
private float zoomSqrt;
|
|
|
|
//Vector2 = vector from the ping source to the position of the disruption
|
|
//float = strength of the disruption, between 0-1
|
|
List<Pair<Vector2, float>> disruptedDirections = new List<Pair<Vector2, float>>();
|
|
|
|
private static Color[] blipColorGradient =
|
|
{
|
|
Color.TransparentBlack,
|
|
new Color(0, 50, 160),
|
|
new Color(0, 133, 166),
|
|
new Color(2, 159, 30),
|
|
new Color(255, 255, 255)
|
|
};
|
|
|
|
public Vector2 DisplayOffset { get; private set; }
|
|
|
|
public float DisplayRadius { get; private set; }
|
|
|
|
partial void InitProjSpecific(XElement element)
|
|
{
|
|
sonarBlips = new List<SonarBlip>();
|
|
|
|
int viewSize = (int)Math.Min(GuiFrame.Rect.Width - 150, GuiFrame.Rect.Height * 0.9f);
|
|
sonarView = new GUICustomComponent(new RectTransform(new Point(viewSize), GuiFrame.RectTransform, Anchor.CenterLeft),
|
|
(spriteBatch, guiCustomComponent) => { DrawSonar(spriteBatch, guiCustomComponent.Rect); }, null);
|
|
|
|
var controlContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.35f), GuiFrame.RectTransform, Anchor.TopLeft)
|
|
{ MinSize = new Point(150, 0), AbsoluteOffset = new Point((int)(viewSize * 0.9f), 0) }, "SonarFrame");
|
|
|
|
controlContainer.RectTransform.SetAsFirstChild();
|
|
|
|
var paddedControlContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), controlContainer.RectTransform, Anchor.Center))
|
|
{
|
|
RelativeSpacing = 0.03f,
|
|
Stretch = true
|
|
};
|
|
|
|
passiveTickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.2f), paddedControlContainer.RectTransform), TextManager.Get("SonarPassive"), style: "GUIRadioButton")
|
|
{
|
|
ToolTip = TextManager.Get("SonarTipPassive"),
|
|
Selected = true
|
|
};
|
|
|
|
activeTickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.2f), paddedControlContainer.RectTransform), TextManager.Get("SonarActive"), style: "GUIRadioButton")
|
|
{
|
|
ToolTip = TextManager.Get("SonarTipActive"),
|
|
OnSelected = (GUITickBox box) =>
|
|
{
|
|
if (GameMain.Server != null)
|
|
{
|
|
unsentChanges = true;
|
|
}
|
|
else if (GameMain.Client != null)
|
|
{
|
|
unsentChanges = true;
|
|
correctionTimer = CorrectionDelay;
|
|
}
|
|
IsActive = box.Selected;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
var zoomContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), paddedControlContainer.RectTransform), isHorizontal: true);
|
|
new GUITextBlock(new RectTransform(new Vector2(0.35f, 1.0f), zoomContainer.RectTransform), TextManager.Get("SonarZoom"), font: GUI.SmallFont)
|
|
{
|
|
Padding = Vector4.Zero
|
|
};
|
|
zoomSlider = new GUIScrollBar(new RectTransform(new Vector2(0.65f, 1.0f), zoomContainer.RectTransform), barSize: 0.1f, isHorizontal: true)
|
|
{
|
|
OnMoved = (scrollbar, scroll) =>
|
|
{
|
|
zoom = MathHelper.Lerp(MinZoom, MaxZoom, scroll);
|
|
if (GameMain.Server != null)
|
|
{
|
|
unsentChanges = true;
|
|
}
|
|
else if (GameMain.Client != null)
|
|
{
|
|
unsentChanges = true;
|
|
correctionTimer = CorrectionDelay;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
var activeControls = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.6f), paddedControlContainer.RectTransform) { RelativeOffset = new Vector2(0.1f, 0.0f) }, "InnerFrame");
|
|
activeControlsContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), activeControls.RectTransform, Anchor.Center))
|
|
{
|
|
RelativeSpacing = 0.03f,
|
|
Stretch = true
|
|
};
|
|
|
|
directionalTickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.3f), activeControlsContainer.RectTransform), TextManager.Get("SonarDirectionalPing"))
|
|
{
|
|
OnSelected = (tickBox) =>
|
|
{
|
|
useDirectionalPing = tickBox.Selected;
|
|
if (GameMain.Server != null)
|
|
{
|
|
unsentChanges = true;
|
|
}
|
|
else if (GameMain.Client != null)
|
|
{
|
|
unsentChanges = true;
|
|
correctionTimer = CorrectionDelay;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
directionalSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.3f), activeControlsContainer.RectTransform), barSize: 0.1f, isHorizontal: true)
|
|
{
|
|
OnMoved = (scrollbar, scroll) =>
|
|
{
|
|
float pingAngle = MathHelper.Lerp(0.0f, MathHelper.TwoPi, scroll);
|
|
pingDirection = new Vector2((float)Math.Cos(pingAngle), (float)Math.Sin(pingAngle));
|
|
if (GameMain.Server != null)
|
|
{
|
|
unsentChanges = true;
|
|
}
|
|
else if (GameMain.Client != null)
|
|
{
|
|
unsentChanges = true;
|
|
correctionTimer = CorrectionDelay;
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
signalWarningText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedControlContainer.RectTransform), "", Color.Orange, textAlignment: Alignment.Center);
|
|
|
|
GUITickBox.CreateRadioButtonGroup(new List<GUITickBox>() { activeTickBox, passiveTickBox });
|
|
|
|
GuiFrame.CanBeFocused = false;
|
|
}
|
|
|
|
public override void OnItemLoaded()
|
|
{
|
|
zoomSlider.BarScroll = MathUtils.InverseLerp(MinZoom, MaxZoom, zoom);
|
|
//make the sonarView customcomponent render the steering view so it gets drawn in front of the sonar
|
|
item.GetComponent<Steering>()?.AttachToSonarHUD(sonarView);
|
|
}
|
|
|
|
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
|
{
|
|
if (unsentChanges)
|
|
{
|
|
if (networkUpdateTimer <= 0.0f)
|
|
{
|
|
#if CLIENT
|
|
if (GameMain.Client != null)
|
|
{
|
|
item.CreateClientEvent(this);
|
|
correctionTimer = CorrectionDelay;
|
|
}
|
|
#endif
|
|
if (GameMain.Server != null)
|
|
{
|
|
item.CreateServerEvent(this);
|
|
}
|
|
|
|
networkUpdateTimer = 0.1f;
|
|
unsentChanges = false;
|
|
}
|
|
}
|
|
networkUpdateTimer -= deltaTime;
|
|
|
|
if (sonarView.Rect.Contains(PlayerInput.MousePosition))
|
|
{
|
|
float scrollSpeed = PlayerInput.ScrollWheelSpeed / 1000.0f;
|
|
if (Math.Abs(scrollSpeed) > 0.0001f)
|
|
{
|
|
zoomSlider.BarScroll += PlayerInput.ScrollWheelSpeed / 1000.0f;
|
|
zoomSlider.OnMoved(zoomSlider, zoomSlider.BarScroll);
|
|
}
|
|
}
|
|
|
|
float distort = 1.0f - item.Condition / 100.0f;
|
|
for (int i = sonarBlips.Count - 1; i >= 0; i--)
|
|
{
|
|
sonarBlips[i].FadeTimer -= deltaTime * MathHelper.Lerp(0.5f, 2.0f, distort);
|
|
sonarBlips[i].Position += sonarBlips[i].Velocity * deltaTime;
|
|
|
|
if (sonarBlips[i].FadeTimer <= 0.0f) sonarBlips.RemoveAt(i);
|
|
}
|
|
|
|
foreach (GUIComponent component in activeControlsContainer.Parent.GetAllChildren())
|
|
{
|
|
if (component is GUITextBlock textBlock)
|
|
{
|
|
textBlock.TextColor = IsActive ? textBlock.Style.textColor : textBlock.Style.textColor * 0.5f;
|
|
}
|
|
}
|
|
|
|
//sonar view can only get focus when the cursor is inside the circle
|
|
sonarView.CanBeFocused =
|
|
Vector2.DistanceSquared(sonarView.Rect.Center.ToVector2(), PlayerInput.MousePosition) <
|
|
(sonarView.Rect.Width / 2 * sonarView.Rect.Width / 2);
|
|
|
|
if (UseTransducers && connectedTransducers.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vector2 transducerCenter = UseTransducers ? GetTransducerCenter() : item.WorldPosition;
|
|
transducerCenter += DisplayOffset;
|
|
|
|
if (Level.Loaded != null)
|
|
{
|
|
Dictionary<LevelTrigger, Vector2> levelTriggerFlows = new Dictionary<LevelTrigger, Vector2>();
|
|
foreach (LevelObject levelObject in Level.Loaded.LevelObjectManager.GetAllObjects(transducerCenter, range * pingState / zoom))
|
|
{
|
|
//gather all nearby triggers that are causing the water to flow into the dictionary
|
|
foreach (LevelTrigger trigger in levelObject.Triggers)
|
|
{
|
|
Vector2 flow = trigger.GetWaterFlowVelocity();
|
|
//ignore ones that are barely doing anything (flow^2 < 1)
|
|
if (flow.LengthSquared() > 1.0f) levelTriggerFlows.Add(trigger, flow);
|
|
}
|
|
}
|
|
|
|
foreach (KeyValuePair<LevelTrigger, Vector2> triggerFlow in levelTriggerFlows)
|
|
{
|
|
LevelTrigger trigger = triggerFlow.Key;
|
|
Vector2 flow = triggerFlow.Value;
|
|
|
|
float flowMagnitude = flow.Length();
|
|
if (Rand.Range(0.0f, 1.0f) < flowMagnitude / 1000.0f)
|
|
{
|
|
float edgeDist = Rand.Range(0.0f, 1.0f);
|
|
Vector2 blipPos = trigger.WorldPosition + Rand.Vector(trigger.ColliderRadius * edgeDist);
|
|
Vector2 blipVel = flow;
|
|
if (trigger.ForceFalloff) flow *= (1.0f - edgeDist);
|
|
|
|
//go through other triggers in range and add the flows of the ones that the blip is inside
|
|
foreach (KeyValuePair<LevelTrigger, Vector2> triggerFlow2 in levelTriggerFlows)
|
|
{
|
|
LevelTrigger trigger2 = triggerFlow2.Key;
|
|
if (trigger2 != trigger && Vector2.DistanceSquared(blipPos, trigger2.WorldPosition) < trigger2.ColliderRadius * trigger2.ColliderRadius)
|
|
{
|
|
Vector2 trigger2flow = triggerFlow2.Value;
|
|
if (trigger2.ForceFalloff) trigger2flow *= (1.0f - Vector2.Distance(blipPos, trigger2.WorldPosition) / trigger2.ColliderRadius);
|
|
blipVel += trigger2flow;
|
|
}
|
|
}
|
|
var flowBlip = new SonarBlip(blipPos, Rand.Range(0.5f, 1.0f), 1.0f)
|
|
{
|
|
Velocity = blipVel * Rand.Range(1.0f, 5.0f),
|
|
Size = new Vector2(MathHelper.Lerp(0.4f, 5f, flowMagnitude / 500.0f), 0.2f),
|
|
Rotation = (float)Math.Atan2(-blipVel.Y, blipVel.X)
|
|
};
|
|
sonarBlips.Add(flowBlip);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsActive)
|
|
{
|
|
float pingRadius = DisplayRadius * pingState / zoom;
|
|
UpdateDisruptions(transducerCenter, pingRadius / displayScale, prevPingRadius / displayScale);
|
|
Ping(transducerCenter, transducerCenter,
|
|
pingRadius, prevPingRadius, displayScale, range / zoom, passive: false, pingStrength: 2.0f);
|
|
prevPingRadius = pingRadius;
|
|
return;
|
|
}
|
|
|
|
float passivePingRadius = (float)Math.Sin(Timing.TotalTime * 10);
|
|
if (passivePingRadius > 0.0f)
|
|
{
|
|
disruptedDirections.Clear();
|
|
foreach (AITarget t in AITarget.List)
|
|
{
|
|
if (t.SoundRange <= 0.0f || !t.Enabled) continue;
|
|
|
|
if (Vector2.DistanceSquared(t.WorldPosition, transducerCenter) < t.SoundRange * t.SoundRange)
|
|
{
|
|
Ping(t.WorldPosition, transducerCenter,
|
|
t.SoundRange * passivePingRadius * 0.2f, t.SoundRange * prevPassivePingRadius * 0.2f, displayScale, t.SoundRange,
|
|
passive: true, pingStrength: 0.5f);
|
|
sonarBlips.Add(new SonarBlip(t.WorldPosition, 1.0f, 1.0f));
|
|
}
|
|
}
|
|
}
|
|
prevPassivePingRadius = passivePingRadius;
|
|
}
|
|
|
|
private void DrawSonar(SpriteBatch spriteBatch, Rectangle rect)
|
|
{
|
|
displayBorderSize = 0.2f;
|
|
center = rect.Center.ToVector2();
|
|
DisplayRadius = (rect.Width / 2.0f) * (1.0f - displayBorderSize);
|
|
displayScale = DisplayRadius / range * zoom;
|
|
|
|
if (screenBackground != null)
|
|
{
|
|
screenBackground.Draw(spriteBatch, center, 0.0f, rect.Width / screenBackground.size.X);
|
|
}
|
|
|
|
if (IsActive)
|
|
{
|
|
if (isLastPingDirectional && directionalPingCircle != null)
|
|
{
|
|
directionalPingCircle.Draw(spriteBatch, center, Color.White * (1.0f - pingState),
|
|
rotate: MathUtils.VectorToAngle(lastPingDirection),
|
|
scale: (DisplayRadius / directionalPingCircle.size.X) * pingState);
|
|
}
|
|
else
|
|
{
|
|
pingCircle.Draw(spriteBatch, center, Color.White * (1.0f - pingState), 0.0f, (DisplayRadius * 2 / pingCircle.size.X) * pingState);
|
|
}
|
|
}
|
|
|
|
float signalStrength = 1.0f;
|
|
if (UseTransducers)
|
|
{
|
|
signalStrength = 0.0f;
|
|
foreach (ConnectedTransducer connectedTransducer in connectedTransducers)
|
|
{
|
|
signalStrength = Math.Max(signalStrength, connectedTransducer.SignalStrength);
|
|
}
|
|
}
|
|
|
|
Vector2 transducerCenter = UseTransducers && connectedTransducers.Count > 0 ? GetTransducerCenter() : item.WorldPosition;
|
|
|
|
if (item.Submarine != null && !DetectSubmarineWalls)
|
|
{
|
|
DrawDockingPorts(spriteBatch, transducerCenter, signalStrength);
|
|
transducerCenter += DisplayOffset;
|
|
DrawOwnSubmarineBorders(spriteBatch, transducerCenter, signalStrength);
|
|
}
|
|
else
|
|
{
|
|
DisplayOffset = Vector2.Zero;
|
|
}
|
|
|
|
|
|
if (sonarBlips.Count > 0)
|
|
{
|
|
zoomSqrt = (float)Math.Sqrt(zoom);
|
|
spriteBatch.End();
|
|
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
|
|
|
|
foreach (SonarBlip sonarBlip in sonarBlips)
|
|
{
|
|
DrawBlip(spriteBatch, sonarBlip, transducerCenter, center, sonarBlip.FadeTimer / 2.0f * signalStrength);
|
|
}
|
|
|
|
spriteBatch.End();
|
|
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
|
|
}
|
|
|
|
if (useDirectionalPing && IsActive)
|
|
{
|
|
Vector2 sector1 = MathUtils.RotatePointAroundTarget(pingDirection * DisplayRadius, Vector2.Zero, DirectionalPingSector * 0.5f);
|
|
Vector2 sector2 = MathUtils.RotatePointAroundTarget(pingDirection * DisplayRadius, Vector2.Zero, -DirectionalPingSector * 0.5f);
|
|
GUI.DrawLine(spriteBatch, center, center + sector1, Color.LightCyan * 0.2f, width: 3);
|
|
GUI.DrawLine(spriteBatch, center, center + sector2, Color.LightCyan * 0.2f, width: 3);
|
|
}
|
|
|
|
if (GameMain.DebugDraw)
|
|
{
|
|
GUI.DrawString(spriteBatch, rect.Location.ToVector2(), sonarBlips.Count.ToString(), Color.White);
|
|
}
|
|
|
|
if (screenOverlay != null)
|
|
{
|
|
screenOverlay.Draw(spriteBatch, center, 0.0f, rect.Width / screenOverlay.size.X);
|
|
}
|
|
|
|
if (signalStrength <= 0.5f)
|
|
{
|
|
signalWarningText.Text = TextManager.Get(signalStrength <= 0.0f ? "SonarNoSignal" : "SonarSignalWeak");
|
|
signalWarningText.Color = signalStrength <= 0.0f ? Color.Red : Color.Orange;
|
|
signalWarningText.Visible = true;
|
|
}
|
|
else
|
|
{
|
|
signalWarningText.Visible = false;
|
|
}
|
|
|
|
if (GameMain.GameSession == null) return;
|
|
|
|
DrawMarker(spriteBatch,
|
|
GameMain.GameSession.StartLocation.Name,
|
|
(Level.Loaded.StartPosition - transducerCenter), displayScale, center, (rect.Width * 0.5f));
|
|
|
|
DrawMarker(spriteBatch,
|
|
GameMain.GameSession.EndLocation.Name,
|
|
(Level.Loaded.EndPosition - transducerCenter), displayScale, center, (rect.Width * 0.5f));
|
|
|
|
foreach (AITarget aiTarget in AITarget.List)
|
|
{
|
|
if (!aiTarget.Enabled) continue;
|
|
if (string.IsNullOrEmpty(aiTarget.SonarLabel) || aiTarget.SoundRange <= 0.0f) continue;
|
|
|
|
if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < aiTarget.SoundRange * aiTarget.SoundRange)
|
|
{
|
|
DrawMarker(spriteBatch,
|
|
aiTarget.SonarLabel,
|
|
aiTarget.WorldPosition - transducerCenter, displayScale, center, (rect.Width * 0.47f));
|
|
}
|
|
}
|
|
|
|
if (GameMain.GameSession.Mission != null)
|
|
{
|
|
var mission = GameMain.GameSession.Mission;
|
|
|
|
if (!string.IsNullOrWhiteSpace(mission.SonarLabel) && mission.SonarPosition != Vector2.Zero)
|
|
{
|
|
DrawMarker(spriteBatch,
|
|
mission.SonarLabel,
|
|
mission.SonarPosition - transducerCenter, displayScale, center, (rect.Width * 0.47f));
|
|
}
|
|
}
|
|
|
|
foreach (Submarine sub in Submarine.Loaded)
|
|
{
|
|
if (!sub.ShowSonarMarker) { continue; }
|
|
if (UseTransducers ?
|
|
connectedTransducers.Any(t => sub == t.Transducer.Item.Submarine || sub.DockedTo.Contains(t.Transducer.Item.Submarine)) :
|
|
(sub == item.Submarine || sub.DockedTo.Contains(item.Submarine)))
|
|
{
|
|
continue;
|
|
}
|
|
if (sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
|
|
|
DrawMarker(spriteBatch, sub.Name, sub.WorldPosition - transducerCenter, displayScale, center, (rect.Width * 0.45f));
|
|
}
|
|
|
|
if (GameMain.DebugDraw)
|
|
{
|
|
var steering = item.GetComponent<Steering>();
|
|
steering?.DebugDrawHUD(spriteBatch, transducerCenter, displayScale, DisplayRadius, center);
|
|
}
|
|
}
|
|
|
|
private void DrawOwnSubmarineBorders(SpriteBatch spriteBatch, Vector2 transducerCenter, float signalStrength)
|
|
{
|
|
float simScale = displayScale * Physics.DisplayToSimRation * zoom;
|
|
|
|
foreach (Submarine submarine in Submarine.Loaded)
|
|
{
|
|
if (UseTransducers ?
|
|
!connectedTransducers.Any(t => submarine == t.Transducer.Item.Submarine || submarine.DockedTo.Contains(t.Transducer.Item.Submarine)) :
|
|
submarine != item.Submarine && !submarine.DockedTo.Contains(item.Submarine)) continue;
|
|
if (submarine.HullVertices == null) continue;
|
|
|
|
Vector2 offset = ConvertUnits.ToSimUnits(submarine.WorldPosition - transducerCenter);
|
|
|
|
for (int i = 0; i < submarine.HullVertices.Count; i++)
|
|
{
|
|
Vector2 start = (submarine.HullVertices[i] + offset) * simScale;
|
|
start.Y = -start.Y;
|
|
Vector2 end = (submarine.HullVertices[(i + 1) % submarine.HullVertices.Count] + offset) * simScale;
|
|
end.Y = -end.Y;
|
|
|
|
DrawLine(spriteBatch, start, end, Color.LightBlue * signalStrength * 0.5f, width: 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawLine(SpriteBatch spriteBatch, Vector2 start, Vector2 end, Color color, int width)
|
|
{
|
|
bool startOutside = start.LengthSquared() > DisplayRadius * DisplayRadius;
|
|
bool endOutside = end.LengthSquared() > DisplayRadius * DisplayRadius;
|
|
if (startOutside && endOutside)
|
|
{
|
|
return;
|
|
}
|
|
else if (startOutside)
|
|
{
|
|
if (MathUtils.GetLineCircleIntersections(Vector2.Zero, DisplayRadius, end, start, true, out Vector2? intersection1, out Vector2? intersection2) == 1)
|
|
{
|
|
GUI.DrawLine(spriteBatch, center + intersection1.Value, center + end, color, width: width);
|
|
}
|
|
}
|
|
else if (endOutside)
|
|
{
|
|
if (MathUtils.GetLineCircleIntersections(Vector2.Zero, DisplayRadius, start, end, true, out Vector2? intersection1, out Vector2? intersection2) == 1)
|
|
{
|
|
GUI.DrawLine(spriteBatch, center + start, center + intersection1.Value, color, width: width);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GUI.DrawLine(spriteBatch, center + start, center + end, color, width: width);
|
|
}
|
|
}
|
|
|
|
private void DrawDockingPorts(SpriteBatch spriteBatch, Vector2 transducerCenter, float signalStrength)
|
|
{
|
|
float scale = displayScale * zoom;
|
|
|
|
Steering steering = item.GetComponent<Steering>();
|
|
if (steering != null && steering.DockingModeEnabled)
|
|
{
|
|
DisplayOffset =
|
|
Vector2.Lerp(DisplayOffset,
|
|
(steering.DockingSource.Item.WorldPosition + steering.DockingTarget.Item.WorldPosition) / 2.0f - transducerCenter,
|
|
0.1f);
|
|
transducerCenter += DisplayOffset;
|
|
|
|
Vector2 sourcePortDiff = (steering.DockingSource.Item.WorldPosition - transducerCenter) * scale;
|
|
Vector2 sourcePortPos = new Vector2(sourcePortDiff.X, -sourcePortDiff.Y);
|
|
Vector2 targetPortDiff = (steering.DockingTarget.Item.WorldPosition - transducerCenter) * scale;
|
|
Vector2 targetPortPos = new Vector2(targetPortDiff.X, -targetPortDiff.Y);
|
|
|
|
Vector2 midPos = (sourcePortPos + targetPortPos) / 2.0f;
|
|
|
|
System.Diagnostics.Debug.Assert(steering.DockingSource.IsHorizontal == steering.DockingTarget.IsHorizontal);
|
|
|
|
float xDist = Math.Abs(steering.DockingSource.Item.WorldPosition.X - steering.DockingTarget.Item.WorldPosition.X);
|
|
float normalizedXDist = xDist / steering.DockingSource.DistanceTolerance.X;
|
|
float yDist = Math.Abs(steering.DockingSource.Item.WorldPosition.Y - steering.DockingTarget.Item.WorldPosition.Y);
|
|
float normalizedYDist = yDist / steering.DockingSource.DistanceTolerance.Y;
|
|
|
|
Color xColor = normalizedXDist <= 1.0f ? Color.Lime : Color.Lerp(Color.Orange, Color.Red, normalizedXDist - 1.0f);
|
|
Color yColor = normalizedYDist <= 1.0f ? Color.Lime : Color.Lerp(Color.Orange, Color.Red, normalizedYDist - 1.0f);
|
|
|
|
if (steering.DockingSource.IsHorizontal)
|
|
{
|
|
if (yDist < steering.DockingSource.DistanceTolerance.Y)
|
|
{
|
|
DrawLine(spriteBatch, sourcePortPos, new Vector2(targetPortPos.X, sourcePortPos.Y), xColor, width: 3);
|
|
}
|
|
else
|
|
{
|
|
DrawLine(spriteBatch, sourcePortPos, new Vector2(midPos.X, sourcePortPos.Y), xColor, width: 3);
|
|
DrawLine(spriteBatch, targetPortPos, new Vector2(midPos.X, targetPortPos.Y), xColor, width: 3);
|
|
DrawLine(spriteBatch, new Vector2(midPos.X, sourcePortPos.Y), new Vector2(midPos.X, targetPortPos.Y), yColor, width: 3);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xDist < steering.DockingSource.DistanceTolerance.X)
|
|
{
|
|
DrawLine(spriteBatch, sourcePortPos, new Vector2(sourcePortPos.X, targetPortPos.Y), yColor, width: 3);
|
|
}
|
|
else
|
|
{
|
|
DrawLine(spriteBatch, sourcePortPos, new Vector2(sourcePortPos.X, midPos.Y), yColor, width: 3);
|
|
DrawLine(spriteBatch, targetPortPos, new Vector2(targetPortPos.X, midPos.Y), yColor, width: 3);
|
|
DrawLine(spriteBatch, new Vector2(sourcePortPos.X, midPos.Y), new Vector2(targetPortPos.X, midPos.Y), xColor, width: 3);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DisplayOffset = Vector2.Lerp(DisplayOffset, Vector2.Zero, 0.1f);
|
|
}
|
|
|
|
|
|
foreach (DockingPort dockingPort in DockingPort.List)
|
|
{
|
|
if (Level.Loaded != null && dockingPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
|
|
|
Vector2 offset = (dockingPort.Item.WorldPosition - transducerCenter) * scale;
|
|
offset.Y = -offset.Y;
|
|
if (offset.LengthSquared() > DisplayRadius * DisplayRadius) { continue; }
|
|
Vector2 size = dockingPort.Item.Rect.Size.ToVector2() * scale;
|
|
|
|
if (dockingPort.IsHorizontal)
|
|
{
|
|
size.X = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
size.Y = 0.0f;
|
|
}
|
|
GUI.DrawLine(spriteBatch, center + offset - size / 2, center + offset + size / 2, Color.LightGreen, width: (int)(zoom));
|
|
}
|
|
|
|
}
|
|
|
|
private void UpdateDisruptions(Vector2 pingSource, float worldPingRadius, float worldPrevPingRadius)
|
|
{
|
|
float worldPingRadiusSqr = worldPingRadius * worldPingRadius;
|
|
float worldPrevPingRadiusSqr = worldPrevPingRadius * worldPrevPingRadius;
|
|
|
|
disruptedDirections.Clear();
|
|
if (Level.Loaded == null) { return; }
|
|
|
|
foreach (LevelObject levelObject in Level.Loaded.LevelObjectManager.GetAllObjects(pingSource, range * pingState))
|
|
{
|
|
if (levelObject.ActivePrefab?.SonarDisruption <= 0.0f) { continue; }
|
|
|
|
float disruptionStrength = levelObject.ActivePrefab.SonarDisruption;
|
|
Vector2 disruptionPos = new Vector2(levelObject.Position.X, levelObject.Position.Y);
|
|
|
|
float disruptionDist = Vector2.Distance(pingSource, disruptionPos);
|
|
disruptedDirections.Add(new Pair<Vector2, float>((disruptionPos - pingSource) / disruptionDist, disruptionStrength));
|
|
|
|
if (disruptionDist > worldPrevPingRadius && disruptionDist <= worldPingRadius)
|
|
{
|
|
for (int i = 0; i < disruptionStrength * Level.GridCellSize * 0.02f; i++)
|
|
{
|
|
var blip = new SonarBlip(disruptionPos + Rand.Vector(Rand.Range(0.0f, Level.GridCellSize * 4 * disruptionStrength)), MathHelper.Lerp(1.0f, 1.5f, disruptionStrength), Rand.Range(1.0f, 2.0f + disruptionStrength));
|
|
sonarBlips.Add(blip);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Ping(Vector2 pingSource, Vector2 transducerPos, float pingRadius, float prevPingRadius, float displayScale, float range, bool passive,
|
|
float pingStrength = 1.0f)
|
|
{
|
|
float prevPingRadiusSqr = prevPingRadius * prevPingRadius;
|
|
float pingRadiusSqr = pingRadius * pingRadius;
|
|
|
|
//inside a hull -> only show the edges of the hull
|
|
if (item.CurrentHull != null && DetectSubmarineWalls)
|
|
{
|
|
CreateBlipsForLine(
|
|
new Vector2(item.CurrentHull.WorldRect.X, item.CurrentHull.WorldRect.Y),
|
|
new Vector2(item.CurrentHull.WorldRect.Right, item.CurrentHull.WorldRect.Y),
|
|
transducerPos,
|
|
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f, passive);
|
|
|
|
CreateBlipsForLine(
|
|
new Vector2(item.CurrentHull.WorldRect.X, item.CurrentHull.WorldRect.Y - item.CurrentHull.Rect.Height),
|
|
new Vector2(item.CurrentHull.WorldRect.Right, item.CurrentHull.WorldRect.Y - item.CurrentHull.Rect.Height),
|
|
transducerPos,
|
|
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f, passive);
|
|
|
|
CreateBlipsForLine(
|
|
new Vector2(item.CurrentHull.WorldRect.X, item.CurrentHull.WorldRect.Y),
|
|
new Vector2(item.CurrentHull.WorldRect.X, item.CurrentHull.WorldRect.Y - item.CurrentHull.Rect.Height),
|
|
transducerPos,
|
|
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f, passive);
|
|
|
|
CreateBlipsForLine(
|
|
new Vector2(item.CurrentHull.WorldRect.Right, item.CurrentHull.WorldRect.Y),
|
|
new Vector2(item.CurrentHull.WorldRect.Right, item.CurrentHull.WorldRect.Y - item.CurrentHull.Rect.Height),
|
|
transducerPos,
|
|
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f, passive);
|
|
|
|
return;
|
|
}
|
|
|
|
foreach (Submarine submarine in Submarine.Loaded)
|
|
{
|
|
if (submarine.HullVertices == null) continue;
|
|
if (!DetectSubmarineWalls)
|
|
{
|
|
if (UseTransducers)
|
|
{
|
|
if (connectedTransducers.Any(t => submarine == t.Transducer.Item.Submarine ||
|
|
submarine.DockedTo.Contains(t.Transducer.Item.Submarine))) continue;
|
|
}
|
|
else
|
|
{
|
|
if (item.Submarine == submarine) continue;
|
|
if (item.Submarine != null && item.Submarine.DockedTo.Contains(submarine)) continue;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < submarine.HullVertices.Count; i++)
|
|
{
|
|
Vector2 start = ConvertUnits.ToDisplayUnits(submarine.HullVertices[i]);
|
|
Vector2 end = ConvertUnits.ToDisplayUnits(submarine.HullVertices[(i + 1) % submarine.HullVertices.Count]);
|
|
|
|
if (item.Submarine == submarine)
|
|
{
|
|
start += Rand.Vector(500.0f);
|
|
end += Rand.Vector(500.0f);
|
|
}
|
|
|
|
CreateBlipsForLine(
|
|
start + submarine.WorldPosition,
|
|
end + submarine.WorldPosition,
|
|
transducerPos,
|
|
pingRadius, prevPingRadius,
|
|
200.0f, 2.0f, range, 1.0f, passive);
|
|
}
|
|
}
|
|
|
|
if (Level.Loaded != null && (item.CurrentHull == null || !DetectSubmarineWalls))
|
|
{
|
|
if (Level.Loaded.Size.Y - pingSource.Y < range)
|
|
{
|
|
CreateBlipsForLine(
|
|
new Vector2(pingSource.X - range, Level.Loaded.Size.Y),
|
|
new Vector2(pingSource.X + range, Level.Loaded.Size.Y),
|
|
transducerPos,
|
|
pingRadius, prevPingRadius,
|
|
250.0f, 150.0f, range, pingStrength, passive);
|
|
}
|
|
|
|
List<Voronoi2.VoronoiCell> cells = Level.Loaded.GetCells(pingSource, 7);
|
|
foreach (Voronoi2.VoronoiCell cell in cells)
|
|
{
|
|
foreach (Voronoi2.GraphEdge edge in cell.Edges)
|
|
{
|
|
if (!edge.IsSolid) continue;
|
|
float cellDot = Vector2.Dot(cell.Center - pingSource, (edge.Center + cell.Translation) - cell.Center);
|
|
if (cellDot > 0) continue;
|
|
|
|
float facingDot = Vector2.Dot(
|
|
Vector2.Normalize(edge.Point1 - edge.Point2),
|
|
Vector2.Normalize(cell.Center - pingSource));
|
|
|
|
CreateBlipsForLine(
|
|
edge.Point1 + cell.Translation,
|
|
edge.Point2 + cell.Translation,
|
|
transducerPos,
|
|
pingRadius, prevPingRadius,
|
|
350.0f, 3.0f * (Math.Abs(facingDot) + 1.0f), range, pingStrength, passive);
|
|
}
|
|
}
|
|
|
|
foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
|
|
{
|
|
if (!MathUtils.CircleIntersectsRectangle(pingSource, range, ruin.Area)) continue;
|
|
|
|
foreach (var ruinShape in ruin.RuinShapes)
|
|
{
|
|
foreach (RuinGeneration.Line wall in ruinShape.Walls)
|
|
{
|
|
float cellDot = Vector2.Dot(
|
|
Vector2.Normalize(ruinShape.Center - pingSource),
|
|
Vector2.Normalize((wall.A + wall.B) / 2.0f - ruinShape.Center));
|
|
if (cellDot > 0) continue;
|
|
|
|
CreateBlipsForLine(
|
|
wall.A, wall.B,
|
|
transducerPos,
|
|
pingRadius, prevPingRadius,
|
|
100.0f, 1000.0f, range, pingStrength, passive);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (Item item in Item.ItemList)
|
|
{
|
|
if (item.CurrentHull == null && item.Prefab.SonarSize > 0.0f)
|
|
{
|
|
float pointDist = ((item.WorldPosition - pingSource) * displayScale).LengthSquared();
|
|
|
|
if (pointDist > prevPingRadiusSqr && pointDist < pingRadiusSqr)
|
|
{
|
|
var blip = new SonarBlip(
|
|
item.WorldPosition + Rand.Vector(item.Prefab.SonarSize),
|
|
MathHelper.Clamp(item.Prefab.SonarSize, 0.1f, pingStrength),
|
|
MathHelper.Clamp(item.Prefab.SonarSize * 0.1f, 0.1f, 10.0f));
|
|
if (!passive && !CheckBlipVisibility(blip, transducerPos)) continue;
|
|
sonarBlips.Add(blip);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (Character c in Character.CharacterList)
|
|
{
|
|
if (c.AnimController.CurrentHull != null || !c.Enabled) continue;
|
|
if (DetectSubmarineWalls && c.AnimController.CurrentHull == null && item.CurrentHull != null) continue;
|
|
|
|
foreach (Limb limb in c.AnimController.Limbs)
|
|
{
|
|
float pointDist = ((limb.WorldPosition - pingSource) * displayScale).LengthSquared();
|
|
|
|
if (limb.SimPosition == Vector2.Zero || pointDist > DisplayRadius * DisplayRadius) continue;
|
|
|
|
if (pointDist > prevPingRadiusSqr && pointDist < pingRadiusSqr)
|
|
{
|
|
var blip = new SonarBlip(
|
|
limb.WorldPosition + Rand.Vector(limb.Mass / 10.0f),
|
|
MathHelper.Clamp(limb.Mass, 0.1f, pingStrength),
|
|
MathHelper.Clamp(limb.Mass * 0.1f, 0.1f, 2.0f));
|
|
if (!passive && !CheckBlipVisibility(blip, transducerPos)) continue;
|
|
sonarBlips.Add(blip);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreateBlipsForLine(Vector2 point1, Vector2 point2, Vector2 transducerPos, float pingRadius, float prevPingRadius,
|
|
float lineStep, float zStep, float range, float pingStrength, bool passive)
|
|
{
|
|
lineStep /= zoom;
|
|
zStep /= zoom;
|
|
range *= displayScale;
|
|
float length = (point1 - point2).Length();
|
|
Vector2 lineDir = (point2 - point1) / length;
|
|
for (float x = 0; x < length; x += lineStep * Rand.Range(0.8f, 1.2f))
|
|
{
|
|
Vector2 point = point1 + lineDir * x;
|
|
//point += cell.Translation;
|
|
|
|
Vector2 pointDiff = point - transducerPos;
|
|
float pointDist = pointDiff.Length();
|
|
float displayPointDist = pointDist * displayScale;
|
|
|
|
if (displayPointDist > DisplayRadius) continue;
|
|
if (displayPointDist < prevPingRadius || displayPointDist > pingRadius) continue;
|
|
|
|
bool disrupted = false;
|
|
foreach (Pair<Vector2, float> disruptDir in disruptedDirections)
|
|
{
|
|
float dot = Vector2.Dot(pointDiff / pointDist, disruptDir.First);
|
|
if (dot > 1.0f - disruptDir.Second)
|
|
{
|
|
disrupted = true;
|
|
break;
|
|
}
|
|
}
|
|
if (disrupted) continue;
|
|
|
|
float alpha = pingStrength * Rand.Range(1.5f, 2.0f);
|
|
for (float z = 0; z < DisplayRadius - displayPointDist; z += zStep)
|
|
{
|
|
Vector2 pos = point + Rand.Vector(150.0f / zoom) + Vector2.Normalize(point - item.WorldPosition) * z / displayScale;
|
|
float fadeTimer = alpha * (1.0f - displayPointDist / range);
|
|
|
|
int minDist = (int)(200 / zoom);
|
|
sonarBlips.RemoveAll(b => b.FadeTimer < fadeTimer && Math.Abs(pos.X - b.Position.X) < minDist && Math.Abs(pos.Y - b.Position.Y) < minDist);
|
|
|
|
var blip = new SonarBlip(pos, fadeTimer, 1.0f + ((displayPointDist + z) / DisplayRadius));
|
|
if (!passive && !CheckBlipVisibility(blip, transducerPos)) continue;
|
|
|
|
sonarBlips.Add(blip);
|
|
zStep += 0.5f / zoom;
|
|
|
|
if (z == 0)
|
|
{
|
|
alpha = Math.Min(alpha - 0.5f, 1.5f);
|
|
}
|
|
else
|
|
{
|
|
alpha -= 0.1f;
|
|
}
|
|
|
|
if (alpha < 0) break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool CheckBlipVisibility(SonarBlip blip, Vector2 transducerPos)
|
|
{
|
|
Vector2 pos = (blip.Position - transducerPos) * displayScale * zoom;
|
|
pos.Y = -pos.Y;
|
|
|
|
float posDistSqr = pos.LengthSquared();
|
|
if (posDistSqr > DisplayRadius * DisplayRadius)
|
|
{
|
|
blip.FadeTimer = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
Vector2 dir = pos / (float)Math.Sqrt(posDistSqr);
|
|
if (isLastPingDirectional)
|
|
{
|
|
if (Vector2.Dot(lastPingDirection, dir) < DirectionalPingDotProduct)
|
|
{
|
|
blip.FadeTimer = 0.0f;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void DrawBlip(SpriteBatch spriteBatch, SonarBlip blip, Vector2 transducerPos, Vector2 center, float strength)
|
|
{
|
|
strength = MathHelper.Clamp(strength, 0.0f, 1.0f);
|
|
|
|
float distort = 1.0f - item.Condition / 100.0f;
|
|
|
|
Vector2 pos = (blip.Position - transducerPos) * displayScale * zoom;
|
|
pos.Y = -pos.Y;
|
|
|
|
if (Rand.Range(0.5f, 2.0f) < distort) pos.X = -pos.X;
|
|
if (Rand.Range(0.5f, 2.0f) < distort) pos.Y = -pos.Y;
|
|
|
|
float posDistSqr = pos.LengthSquared();
|
|
if (posDistSqr > DisplayRadius * DisplayRadius)
|
|
{
|
|
blip.FadeTimer = 0.0f;
|
|
return;
|
|
}
|
|
|
|
if (sonarBlip == null)
|
|
{
|
|
GUI.DrawRectangle(spriteBatch, center + pos, Vector2.One * 4, Color.Magenta, true);
|
|
return;
|
|
}
|
|
|
|
Vector2 dir = pos / (float)Math.Sqrt(posDistSqr);
|
|
Vector2 normal = new Vector2(dir.Y, -dir.X);
|
|
float scale = (strength + 3.0f) * blip.Scale * zoomSqrt;
|
|
Color color = ToolBox.GradientLerp(strength, blipColorGradient);
|
|
|
|
sonarBlip.Draw(spriteBatch, center + pos, color, sonarBlip.Origin, blip.Rotation ?? MathUtils.VectorToAngle(pos),
|
|
blip.Size * scale * 0.04f, SpriteEffects.None, 0);
|
|
|
|
pos += Rand.Range(0.0f, 1.0f) * dir + Rand.Range(-scale, scale) * normal;
|
|
|
|
sonarBlip.Draw(spriteBatch, center + pos, color * 0.5f, sonarBlip.Origin, 0, scale * 0.08f, SpriteEffects.None, 0);
|
|
}
|
|
|
|
private void DrawMarker(SpriteBatch spriteBatch, string label, Vector2 position, float scale, Vector2 center, float radius)
|
|
{
|
|
float dist = position.Length();
|
|
|
|
position *= zoom;
|
|
position *= scale;
|
|
position.Y = -position.Y;
|
|
|
|
float textAlpha = MathHelper.Clamp(1.5f - dist / 50000.0f, 0.5f, 1.0f);
|
|
|
|
Vector2 dir = Vector2.Normalize(position);
|
|
Vector2 markerPos = (dist * zoom * scale > radius) ? dir * radius : position;
|
|
markerPos += center;
|
|
|
|
markerPos.X = (int)markerPos.X;
|
|
markerPos.Y = (int)markerPos.Y;
|
|
|
|
float alpha = 1.0f;
|
|
if (dist * scale < radius)
|
|
{
|
|
float normalizedDist = dist * scale / radius;
|
|
alpha = Math.Max(normalizedDist - 0.4f, 0.0f);
|
|
|
|
float mouseDist = Vector2.Distance(PlayerInput.MousePosition, markerPos);
|
|
float hoverThreshold = 150.0f;
|
|
if (mouseDist < hoverThreshold)
|
|
{
|
|
alpha += (hoverThreshold - mouseDist) / hoverThreshold;
|
|
}
|
|
}
|
|
|
|
if (!GuiFrame.Children.First().Rect.Contains(markerPos))
|
|
{
|
|
if (MathUtils.GetLineRectangleIntersection(center, markerPos, GuiFrame.Children.First().Rect, out Vector2 intersection))
|
|
{
|
|
markerPos = intersection;
|
|
}
|
|
}
|
|
|
|
GUI.DrawRectangle(spriteBatch, new Rectangle((int)markerPos.X - 3, (int)markerPos.Y - 3, 6, 6), Color.Red, thickness: 2);
|
|
|
|
if (alpha <= 0.0f) { return; }
|
|
|
|
string wrappedLabel = ToolBox.WrapText(label, 150, GUI.SmallFont);
|
|
wrappedLabel += "\n" + ((int)(dist * Physics.DisplayToRealWorldRatio) + " m");
|
|
|
|
Vector2 labelPos = markerPos;
|
|
Vector2 textSize = GUI.SmallFont.MeasureString(wrappedLabel);
|
|
|
|
//flip the text to left side when the marker is on the left side or goes outside the right edge of the interface
|
|
if (dir.X < 0.0f || labelPos.X + textSize.X + 10 > GuiFrame.Rect.X) labelPos.X -= textSize.X + 10;
|
|
|
|
GUI.DrawString(spriteBatch,
|
|
new Vector2(labelPos.X + 10, labelPos.Y),
|
|
wrappedLabel,
|
|
Color.LightBlue * textAlpha * alpha, Color.Black * textAlpha * 0.8f * alpha,
|
|
2, GUI.SmallFont);
|
|
}
|
|
|
|
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
|
{
|
|
msg.Write(IsActive);
|
|
if (IsActive)
|
|
{
|
|
msg.WriteRangedSingle(zoom, MinZoom, MaxZoom, 8);
|
|
msg.Write(useDirectionalPing);
|
|
if (useDirectionalPing)
|
|
{
|
|
msg.WriteRangedSingle(directionalSlider.BarScroll, 0.0f, 1.0f, 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
|
|
{
|
|
long msgStartPos = msg.Position;
|
|
|
|
bool isActive = msg.ReadBoolean();
|
|
float zoomT = 1.0f;
|
|
bool directionalPing = useDirectionalPing;
|
|
float directionT = 0.0f;
|
|
if (isActive)
|
|
{
|
|
zoomT = msg.ReadRangedSingle(0.0f, 1.0f, 8);
|
|
directionalPing = msg.ReadBoolean();
|
|
if (directionalPing)
|
|
{
|
|
directionT = msg.ReadRangedSingle(0.0f, 1.0f, 8);
|
|
}
|
|
}
|
|
|
|
if (correctionTimer > 0.0f)
|
|
{
|
|
int msgLength = (int)(msg.Position - msgStartPos);
|
|
msg.Position = msgStartPos;
|
|
StartDelayedCorrection(type, msg.ExtractBits(msgLength), sendingTime);
|
|
return;
|
|
}
|
|
|
|
IsActive = isActive;
|
|
if (isActive)
|
|
{
|
|
activeTickBox.Selected = true;
|
|
zoomSlider.BarScroll = zoomT;
|
|
zoom = MathHelper.Lerp(MinZoom, MaxZoom, zoomT);
|
|
if (directionalPing)
|
|
{
|
|
directionalSlider.BarScroll = directionT;
|
|
float pingAngle = MathHelper.Lerp(0.0f, MathHelper.TwoPi, directionalSlider.BarScroll);
|
|
pingDirection = new Vector2((float)Math.Cos(pingAngle), (float)Math.Sin(pingAngle));
|
|
}
|
|
useDirectionalPing = directionalTickBox.Selected = directionalPing;
|
|
}
|
|
else
|
|
{
|
|
passiveTickBox.Selected = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
class SonarBlip
|
|
{
|
|
public float FadeTimer;
|
|
public Vector2 Position;
|
|
public float Scale;
|
|
public Vector2 Velocity;
|
|
public float? Rotation;
|
|
public Vector2 Size;
|
|
|
|
public SonarBlip(Vector2 pos, float fadeTimer, float scale)
|
|
{
|
|
Position = pos;
|
|
FadeTimer = Math.Max(fadeTimer, 0.0f);
|
|
Scale = scale;
|
|
Size = new Vector2(0.5f, 1.0f);
|
|
}
|
|
}
|
|
}
|