38f1ddb...178a853: v0.8.9.1, removed content folder

This commit is contained in:
Joonas Rikkonen
2019-03-18 19:46:58 +02:00
parent 38f1ddb6fe
commit 6c0679c297
1054 changed files with 151673 additions and 144931 deletions
@@ -15,10 +15,10 @@ namespace Barotrauma.Items.Components
private Vector2[] GetConvexHullCorners(Rectangle rect)
{
Vector2[] corners = new Vector2[4];
corners[0] = new Vector2(rect.X, rect.Y - rect.Height);
corners[1] = new Vector2(rect.X, rect.Y);
corners[2] = new Vector2(rect.Right, rect.Y);
corners[3] = new Vector2(rect.Right, rect.Y - rect.Height);
corners[0] = new Vector2(rect.X - 1, rect.Y - rect.Height - 1);
corners[1] = new Vector2(rect.X - 1, rect.Y + 1);
corners[2] = new Vector2(rect.Right + 1, rect.Y + 1);
corners[3] = new Vector2(rect.Right + 1, rect.Y - rect.Height - 1);
return corners;
}
@@ -26,10 +26,10 @@ namespace Barotrauma.Items.Components
private void UpdateConvexHulls()
{
doorRect = new Rectangle(
item.Rect.Center.X - (int)(doorSprite.size.X / 2),
item.Rect.Y - item.Rect.Height / 2 + (int)(doorSprite.size.Y / 2.0f),
(int)doorSprite.size.X,
(int)doorSprite.size.Y);
item.Rect.Center.X - (int)(doorSprite.size.X / 2 * item.Scale),
item.Rect.Y - item.Rect.Height / 2 + (int)(doorSprite.size.Y / 2.0f * item.Scale),
(int)(doorSprite.size.X * item.Scale),
(int)(doorSprite.size.Y * item.Scale));
Rectangle rect = doorRect;
if (isHorizontal)
@@ -43,7 +43,7 @@ namespace Barotrauma.Items.Components
if (window.Height > 0 && window.Width > 0)
{
rect.Height = -window.Y;
rect.Height = -(int)(window.Y * item.Scale);
rect.Y += (int)(doorRect.Height * openState);
rect.Height = Math.Max(rect.Height - (rect.Y - doorRect.Y), 0);
@@ -52,12 +52,11 @@ namespace Barotrauma.Items.Components
if (convexHull2 != null)
{
Rectangle rect2 = doorRect;
rect2.Y = rect2.Y + window.Y - window.Height;
rect2.Y = rect2.Y + (int)((window.Y * item.Scale - window.Height * item.Scale));
rect2.Y += (int)(doorRect.Height * openState);
rect2.Y = Math.Min(doorRect.Y, rect2.Y);
rect2.Height = rect2.Y - (doorRect.Y - (int)(doorRect.Height * (1.0f - openState)));
//convexHull2.SetVertices(GetConvexHullCorners(rect2));
if (rect2.Height == 0)
{
@@ -86,7 +85,7 @@ namespace Barotrauma.Items.Components
public void Draw(SpriteBatch spriteBatch, bool editing)
{
Color color = (item.IsSelected) ? Color.Green : Color.White;
Color color = Color.White;
if (brokenSprite == null)
{
//broken doors turn black if no broken sprite has been configured
@@ -101,7 +100,7 @@ namespace Barotrauma.Items.Components
weldSpritePos.Y = -weldSpritePos.Y;
weldedSprite.Draw(spriteBatch,
weldSpritePos, Color.White * (stuck / 100.0f), 0.0f, 1.0f);
weldSpritePos, Color.White * (stuck / 100.0f), scale: item.Scale);
}
if (openState == 1.0f)
@@ -122,7 +121,7 @@ namespace Barotrauma.Items.Components
new Rectangle((int) (doorSprite.SourceRect.X + doorSprite.size.X * openState),
(int) doorSprite.SourceRect.Y,
(int) (doorSprite.size.X * (1.0f - openState)), (int) doorSprite.size.Y),
color, 0.0f, doorSprite.Origin, 1.0f, SpriteEffects.None, doorSprite.Depth);
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
}
if (brokenSprite != null && item.Health < item.Prefab.Health)
@@ -132,7 +131,7 @@ namespace Barotrauma.Items.Components
spriteBatch.Draw(brokenSprite.Texture, pos,
new Rectangle((int)(brokenSprite.SourceRect.X + brokenSprite.size.X * openState), brokenSprite.SourceRect.Y,
(int)(brokenSprite.size.X * (1.0f - openState)), (int)brokenSprite.size.Y),
color * alpha, 0.0f, brokenSprite.Origin, scale, SpriteEffects.None,
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, SpriteEffects.None,
brokenSprite.Depth);
}
}
@@ -148,7 +147,7 @@ namespace Barotrauma.Items.Components
new Rectangle(doorSprite.SourceRect.X,
(int) (doorSprite.SourceRect.Y + doorSprite.size.Y * openState),
(int) doorSprite.size.X, (int) (doorSprite.size.Y * (1.0f - openState))),
color, 0.0f, doorSprite.Origin, 1.0f, SpriteEffects.None, doorSprite.Depth);
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
}
if (brokenSprite != null && item.Health < item.Prefab.Health)
@@ -158,7 +157,7 @@ namespace Barotrauma.Items.Components
spriteBatch.Draw(brokenSprite.Texture, pos,
new Rectangle(brokenSprite.SourceRect.X, (int)(brokenSprite.SourceRect.Y + brokenSprite.size.Y * openState),
(int)brokenSprite.size.X, (int)(brokenSprite.size.Y * (1.0f - openState))),
color * alpha, 0.0f, brokenSprite.Origin, scale, SpriteEffects.None, brokenSprite.Depth);
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, SpriteEffects.None, brokenSprite.Depth);
}
}
@@ -0,0 +1,56 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
namespace Barotrauma.Items.Components
{
partial class ElectricalDischarger : Powered
{
private static SpriteSheet electricitySprite;
private int frameOffset;
partial void InitProjSpecific()
{
if (electricitySprite == null)
{
electricitySprite = new SpriteSheet("Content/Lights/Electricity.png", 4, 4, new Vector2(0.5f, 0.0f));
}
}
partial void DischargeProjSpecific()
{
PlaySound(ActionType.OnUse, item.WorldPosition);
foreach (Node node in nodes)
{
GameMain.ParticleManager.CreateParticle("swirlysmoke", node.WorldPosition, Vector2.Zero);
}
}
public void DrawElectricity(SpriteBatch spriteBatch)
{
for (int i = 0; i < nodes.Count; i++)
{
if (nodes[i].Length <= 1.0f) continue;
var node = nodes[i];
electricitySprite.Draw(spriteBatch,
(i + frameOffset) % electricitySprite.FrameCount,
new Vector2(node.WorldPosition.X, -node.WorldPosition.Y),
Color.Lerp(Color.LightBlue, Color.White, Rand.Range(0.0f, 1.0f)),
electricitySprite.Origin, -node.Angle - MathHelper.PiOver2,
new Vector2(
Math.Min(node.Length / electricitySprite.FrameSize.X, 1.0f) * Rand.Range(0.5f, 2.0f),
node.Length / electricitySprite.FrameSize.Y) * Rand.Range(1.0f, 1.2f));
}
if (GameMain.DebugDraw)
{
for (int i = 0; i < nodes.Count; i++)
{
if (nodes[i].Length <= 1.0f) continue;
GUI.DrawRectangle(spriteBatch, new Vector2(nodes[i].WorldPosition.X, -nodes[i].WorldPosition.Y), Vector2.One * 5, Color.LightCyan, isFilled: true);
}
}
}
}
}
@@ -1,4 +1,5 @@
using Barotrauma.Networking;
using Barotrauma.Sounds;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -10,25 +11,38 @@ using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
enum SoundSelectionMode
{
Random,
CharacterSpecific,
ItemSpecific,
All
}
class ItemSound
{
public readonly Sound Sound;
public readonly RoundSound RoundSound;
public readonly ActionType Type;
public string VolumeProperty;
public float VolumeMultiplier
{
get { return RoundSound.Volume; }
}
public float Range
{
get { return RoundSound.Range; }
}
public float VolumeMultiplier;
public readonly float Range;
public readonly bool Loop;
public ItemSound(Sound sound, ActionType type, float range, bool loop = false)
public ItemSound(RoundSound sound, ActionType type, bool loop = false)
{
this.Sound = sound;
this.RoundSound = sound;
this.Type = type;
this.Range = range;
this.Loop = loop;
}
}
@@ -36,71 +50,260 @@ namespace Barotrauma.Items.Components
partial class ItemComponent : ISerializableEntity
{
private Dictionary<ActionType, List<ItemSound>> sounds;
private Dictionary<ActionType, SoundSelectionMode> soundSelectionModes;
private GUIFrame guiFrame;
public GUILayoutSettings DefaultLayout { get; protected set; }
public GUILayoutSettings AlternativeLayout { get; protected set; }
protected GUIFrame GuiFrame
public class GUILayoutSettings
{
get
public Vector2? RelativeSize { get; private set; }
public Point? AbsoluteSize { get; private set; }
public Vector2? RelativeOffset { get; private set; }
public Point? AbsoluteOffset { get; private set; }
public Anchor? Anchor { get; private set; }
public Pivot? Pivot { get; private set; }
public static GUILayoutSettings Load(XElement element)
{
if (guiFrame == null)
var layout = new GUILayoutSettings();
var relativeSize = XMLExtensions.GetAttributeVector2(element, "relativesize", Vector2.Zero);
var absoluteSize = XMLExtensions.GetAttributePoint(element, "absolutesize", new Point(-1000, -1000));
var relativeOffset = XMLExtensions.GetAttributeVector2(element, "relativeoffset", Vector2.Zero);
var absoluteOffset = XMLExtensions.GetAttributePoint(element, "absoluteoffset", new Point(-1000, -1000));
if (relativeSize.Length() > 0)
{
DebugConsole.ThrowError("Error: the component " + name + " in " + item.Name + " doesn't have a GuiFrame component");
guiFrame = new GUIFrame(new Rectangle(0, 0, 100, 100), Color.Black);
layout.RelativeSize = relativeSize;
}
return guiFrame;
if (absoluteSize.X > 0 && absoluteSize.Y > 0)
{
layout.AbsoluteSize = absoluteSize;
}
if (relativeOffset.Length() > 0)
{
layout.RelativeOffset = relativeOffset;
}
if (absoluteOffset.X > -1000 && absoluteOffset.Y > -1000)
{
layout.AbsoluteOffset = absoluteOffset;
}
if (Enum.TryParse(XMLExtensions.GetAttributeString(element, "anchor", ""), out Anchor a))
{
layout.Anchor = a;
}
if (Enum.TryParse(XMLExtensions.GetAttributeString(element, "pivot", ""), out Pivot p))
{
layout.Pivot = p;
}
return layout;
}
public void ApplyTo(RectTransform target)
{
if (RelativeOffset.HasValue)
{
target.RelativeOffset = RelativeOffset.Value;
}
else if (AbsoluteOffset.HasValue)
{
target.AbsoluteOffset = AbsoluteOffset.Value;
}
if (RelativeSize.HasValue)
{
target.RelativeSize = RelativeSize.Value;
}
else if (AbsoluteSize.HasValue)
{
target.NonScaledSize = AbsoluteSize.Value;
}
if (Anchor.HasValue)
{
target.Anchor = Anchor.Value;
}
if (Pivot.HasValue)
{
target.Pivot = Pivot.Value;
}
else
{
target.Pivot = RectTransform.MatchPivotToAnchor(target.Anchor);
}
target.RecalculateChildren(true, true);
}
}
public GUIFrame GuiFrame { get; protected set; }
[Serialize(false, false)]
public bool AllowUIOverlap
{
get;
set;
}
private ItemComponent linkToUIComponent;
[Serialize("", false)]
public string LinkUIToComponent
{
get;
set;
}
[Serialize(0, false)]
public int HudPriority
{
get;
private set;
}
private bool useAlternativeLayout;
public bool UseAlternativeLayout
{
get { return useAlternativeLayout; }
set
{
if (AlternativeLayout != null)
{
if (value == useAlternativeLayout) { return; }
useAlternativeLayout = value;
if (useAlternativeLayout)
{
AlternativeLayout?.ApplyTo(GuiFrame.RectTransform);
}
else
{
DefaultLayout?.ApplyTo(GuiFrame.RectTransform);
}
}
}
}
private bool shouldMuffleLooping;
private float lastMuffleCheckTime;
private ItemSound loopingSound;
private int loopingSoundIndex;
public void PlaySound(ActionType type, Vector2 position)
private SoundChannel loopingSoundChannel;
public void PlaySound(ActionType type, Vector2 position, Character user = null)
{
if (loopingSound != null)
{
loopingSoundIndex = loopingSound.Sound.Loop(loopingSoundIndex, GetSoundVolume(loopingSound), position, loopingSound.Range);
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > loopingSound.Range * loopingSound.Range)
{
if (loopingSoundChannel != null)
{
loopingSoundChannel.Dispose(); loopingSoundChannel = null;
}
return;
}
if (loopingSoundChannel != null && loopingSoundChannel.Sound != loopingSound.RoundSound.Sound)
{
loopingSoundChannel.Dispose(); loopingSoundChannel = null;
}
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
{
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
new Vector3(position.X, position.Y, 0.0f),
GetSoundVolume(loopingSound),
SoundPlayer.ShouldMuffleSound(Character.Controlled, position, loopingSound.Range, Character.Controlled?.CurrentHull));
loopingSoundChannel.Looping = true;
//TODO: tweak
loopingSoundChannel.Near = loopingSound.Range * 0.4f;
loopingSoundChannel.Far = loopingSound.Range;
}
if (loopingSoundChannel != null)
{
if (Timing.TotalTime > lastMuffleCheckTime + 0.2f)
{
shouldMuffleLooping = SoundPlayer.ShouldMuffleSound(Character.Controlled, position, loopingSound.Range, Character.Controlled?.CurrentHull);
lastMuffleCheckTime = (float)Timing.TotalTime;
}
loopingSoundChannel.Muffled = shouldMuffleLooping;
loopingSoundChannel.Gain = GetSoundVolume(loopingSound);
loopingSoundChannel.Position = new Vector3(position.X, position.Y, 0.0f);
}
return;
}
List<ItemSound> matchingSounds;
if (!sounds.TryGetValue(type, out matchingSounds)) return;
if (!sounds.TryGetValue(type, out List<ItemSound> matchingSounds)) return;
ItemSound itemSound = null;
if (!Sounds.SoundManager.IsPlaying(loopingSoundIndex))
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
{
int index = Rand.Int(matchingSounds.Count);
SoundSelectionMode soundSelectionMode = soundSelectionModes[type];
int index;
if (soundSelectionMode == SoundSelectionMode.CharacterSpecific && user != null)
{
index = user.ID % matchingSounds.Count;
}
else if (soundSelectionMode == SoundSelectionMode.ItemSpecific)
{
index = item.ID % matchingSounds.Count;
}
else if (soundSelectionMode == SoundSelectionMode.All)
{
foreach (ItemSound sound in matchingSounds)
{
PlaySound(sound, position, user);
}
return;
}
else
{
index = Rand.Int(matchingSounds.Count);
}
itemSound = matchingSounds[index];
PlaySound(matchingSounds[index], position, user);
}
if (itemSound == null) return;
}
private void PlaySound(ItemSound itemSound, Vector2 position, Character user = null)
{
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > itemSound.Range * itemSound.Range)
{
return;
}
if (itemSound.Loop)
{
loopingSound = itemSound;
loopingSoundIndex = loopingSound.Sound.Loop(loopingSoundIndex, GetSoundVolume(loopingSound), position, loopingSound.Range);
if (loopingSoundChannel != null && loopingSoundChannel.Sound != loopingSound.RoundSound.Sound)
{
loopingSoundChannel.Dispose(); loopingSoundChannel = null;
}
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
{
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
new Vector3(position.X, position.Y, 0.0f),
GetSoundVolume(loopingSound),
muffle: SoundPlayer.ShouldMuffleSound(Character.Controlled, position, loopingSound.Range, Character.Controlled?.CurrentHull));
loopingSoundChannel.Looping = true;
//TODO: tweak
loopingSoundChannel.Near = loopingSound.Range * 0.4f;
loopingSoundChannel.Far = loopingSound.Range;
}
}
else
{
float volume = GetSoundVolume(itemSound);
if (volume == 0.0f) return;
itemSound.Sound.Play(volume, itemSound.Range, position);
if (volume <= 0.0f) return;
SoundPlayer.PlaySound(itemSound.RoundSound.Sound, volume, itemSound.Range, position, item.CurrentHull);
}
}
public void StopSounds(ActionType type)
{
if (loopingSoundIndex <= 0) return;
if (loopingSound == null) return;
if (loopingSound.Type != type) return;
if (Sounds.SoundManager.IsPlaying(loopingSoundIndex))
if (loopingSoundChannel != null)
{
Sounds.SoundManager.Stop(loopingSoundIndex);
loopingSoundChannel.Dispose();
loopingSoundChannel = null;
loopingSound = null;
loopingSoundIndex = -1;
}
}
@@ -109,8 +312,7 @@ namespace Barotrauma.Items.Components
if (sound == null) return 0.0f;
if (sound.VolumeProperty == "") return 1.0f;
SerializableProperty property = null;
if (properties.TryGetValue(sound.VolumeProperty.ToLowerInvariant(), out property))
if (properties.TryGetValue(sound.VolumeProperty.ToLowerInvariant(), out SerializableProperty property))
{
float newVolume = 0.0f;
try
@@ -123,55 +325,80 @@ namespace Barotrauma.Items.Components
}
newVolume *= sound.VolumeMultiplier;
if (!MathUtils.IsValid(newVolume))
{
DebugConsole.Log("Invalid sound volume (item " + item.Name + ", " + GetType().ToString() + "): " + newVolume);
GameAnalyticsManager.AddErrorEventOnce(
"ItemComponent.PlaySound:" + item.Name + GetType().ToString(),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Invalid sound volume (item " + item.Name + ", " + GetType().ToString() + "): " + newVolume);
return 0.0f;
}
return MathHelper.Clamp(newVolume, 0.0f, 1.0f);
}
return 0.0f;
}
public virtual bool ShouldDrawHUD(Character character)
{
return true;
}
public ItemComponent GetLinkUIToComponent()
{
if (string.IsNullOrEmpty(LinkUIToComponent))
{
return null;
}
foreach (ItemComponent component in item.components)
{
if (component.name.ToLower() == LinkUIToComponent.ToLower())
{
linkToUIComponent = component;
}
}
if (linkToUIComponent == null)
{
DebugConsole.ThrowError("Failed to link the component \"" + Name + "\" to \"" + LinkUIToComponent + "\" in the item \"" + item.Name + "\" - component with a matching name not found.");
}
return linkToUIComponent;
}
public virtual void DrawHUD(SpriteBatch spriteBatch, Character character) { }
public virtual void AddToGUIUpdateList() { }
public virtual void AddToGUIUpdateList()
{
GuiFrame?.AddToGUIUpdateList();
}
public virtual void UpdateHUD(Character character) { }
public virtual void UpdateHUD(Character character, float deltaTime, Camera cam) { }
private bool LoadElemProjSpecific(XElement subElement)
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "guiframe":
string rectStr = subElement.GetAttributeString("rect", "0.0,0.0,0.5,0.5");
string[] components = rectStr.Split(',');
if (components.Length < 4) break;
Vector4 rect = subElement.GetAttributeVector4("rect", Vector4.One);
if (components[0].Contains(".")) rect.X *= GameMain.GraphicsWidth;
if (components[1].Contains(".")) rect.Y *= GameMain.GraphicsHeight;
if (components[2].Contains(".")) rect.Z *= GameMain.GraphicsWidth;
if (components[3].Contains(".")) rect.W *= GameMain.GraphicsHeight;
string style = subElement.GetAttributeString("style", "");
Vector4 color = subElement.GetAttributeVector4("color", Vector4.One);
Alignment alignment = Alignment.Center;
try
if (subElement.Attribute("rect") != null)
{
alignment = (Alignment)Enum.Parse(typeof(Alignment),
subElement.GetAttributeString("alignment", "Center"), true);
}
catch
{
DebugConsole.ThrowError("Error in " + subElement.Parent + "! \"" + subElement.Parent.Attribute("type").Value + "\" is not a valid alignment");
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFile + "\" - GUIFrame defined as rect, use RectTransform instead.");
break;
}
guiFrame = new GUIFrame(
new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Z, (int)rect.W),
new Color(color.X, color.Y, color.Z) * color.W,
alignment, style);
Color? color = null;
if (subElement.Attribute("color") != null) color = subElement.GetAttributeColor("color", Color.White);
string style = subElement.Attribute("style") == null ?
null : subElement.GetAttributeString("style", "");
GuiFrame = new GUIFrame(RectTransform.Load(subElement, GUI.Canvas), style, color);
DefaultLayout = GUILayoutSettings.Load(subElement);
break;
case "alternativelayout":
AlternativeLayout = GUILayoutSettings.Load(subElement);
break;
case "itemsound":
case "sound":
string filePath = subElement.GetAttributeString("file", "");
@@ -189,7 +416,6 @@ namespace Barotrauma.Items.Components
}
ActionType type;
try
{
type = (ActionType)Enum.Parse(typeof(ActionType), subElement.GetAttributeString("type", ""), true);
@@ -199,14 +425,20 @@ namespace Barotrauma.Items.Components
DebugConsole.ThrowError("Invalid sound type in " + subElement + "!", e);
break;
}
RoundSound sound = Submarine.LoadRoundSound(subElement);
ItemSound itemSound = new ItemSound(sound, type, subElement.GetAttributeBool("loop", false))
{
VolumeProperty = subElement.GetAttributeString("volumeproperty", "")
};
Sound sound = Sound.Load(filePath);
float range = subElement.GetAttributeFloat("range", 800.0f);
bool loop = subElement.GetAttributeBool("loop", false);
ItemSound itemSound = new ItemSound(sound, type, range, loop);
itemSound.VolumeProperty = subElement.GetAttributeString("volume", "");
itemSound.VolumeMultiplier = subElement.GetAttributeFloat("volumemultiplier", 1.0f);
if (soundSelectionModes == null) soundSelectionModes = new Dictionary<ActionType, SoundSelectionMode>();
if (!soundSelectionModes.ContainsKey(type) || soundSelectionModes[type] == SoundSelectionMode.Random)
{
SoundSelectionMode selectionMode = SoundSelectionMode.Random;
Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out selectionMode);
soundSelectionModes[type] = selectionMode;
}
List<ItemSound> soundList = null;
if (!sounds.TryGetValue(itemSound.Type, out soundList))
@@ -1,29 +1,146 @@
using Microsoft.Xna.Framework;
using System;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma.Items.Components
{
partial class ItemContainer : ItemComponent, IDrawableComponent
{
//TODO: shouldn't this be overriding the base method?
private Sprite inventoryTopSprite;
private Sprite inventoryBackSprite;
private Sprite inventoryBottomSprite;
private GUICustomComponent guiCustomComponent;
public Sprite InventoryTopSprite
{
get { return inventoryTopSprite; }
}
public Sprite InventoryBackSprite
{
get { return inventoryBackSprite; }
}
public Sprite InventoryBottomSprite
{
get { return inventoryBottomSprite; }
}
public Sprite ContainedStateIndicator
{
get;
private set;
}
#if DEBUG
[Serialize("0.0,0.0", false), Editable]
#else
[Serialize("0.0,0.0", false)]
#endif
public Vector2 ItemPos { get; set; }
#if DEBUG
[Serialize("0.0,0.0", false), Editable]
#else
[Serialize("0.0,0.0", false)]
#endif
public Vector2 ItemInterval { get; set; }
[Serialize(100, false)]
public int ItemsPerRow { get; set; }
/// <summary>
/// Depth at which the contained sprites are drawn. If not set, the original depth of the item sprites is used.
/// </summary>
[Serialize(-1.0f, false)]
public float ContainedSpriteDepth { get; set; }
private float itemRotation;
[Serialize(0.0f, false)]
public float ItemRotation
{
get { return MathHelper.ToDegrees(itemRotation); }
set { itemRotation = MathHelper.ToRadians(value); }
}
[Serialize(null, false)]
public string UILabel { get; set; }
[Serialize(false, false)]
public bool ShowConditionInContainedStateIndicator
{
get;
set;
}
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "topsprite":
inventoryTopSprite = new Sprite(subElement);
break;
case "backsprite":
inventoryBackSprite = new Sprite(subElement);
break;
case "bottomsprite":
inventoryBottomSprite = new Sprite(subElement);
break;
case "containedstateindicator":
ContainedStateIndicator = new Sprite(subElement);
break;
}
}
if (GuiFrame == null)
{
//if a GUIFrame is not defined in the xml,
//we create a full-screen frame and let the inventory position itself on it
GuiFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
{
CanBeFocused = false
};
guiCustomComponent = new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform),
onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
onUpdate: null)
{
CanBeFocused = false
};
}
else
{
//if a GUIFrame has been defined, draw the inventory inside it
guiCustomComponent = new GUICustomComponent(new RectTransform(new Vector2(0.9f), GuiFrame.RectTransform, Anchor.Center),
onDraw: (SpriteBatch spriteBatch, GUICustomComponent component) => { Inventory.Draw(spriteBatch); },
onUpdate: null)
{
CanBeFocused = false
};
Inventory.RectTransform = guiCustomComponent.RectTransform;
}
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
{
if (hideItems || (item.body != null && !item.body.Enabled)) return;
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
DrawContainedItems(spriteBatch);
}
Vector2 transformedItemPos = itemPos;
Vector2 transformedItemInterval = itemInterval;
public void DrawContainedItems(SpriteBatch spriteBatch)
{
Vector2 transformedItemPos = ItemPos * item.Scale;
Vector2 transformedItemInterval = ItemInterval * item.Scale;
float currentRotation = itemRotation;
if (item.body == null)
{
transformedItemPos = new Vector2(item.Rect.X, item.Rect.Y);
if (item.Submarine != null) transformedItemPos += item.Submarine.DrawPosition;
transformedItemPos = transformedItemPos + itemPos;
transformedItemPos = transformedItemPos + ItemPos * item.Scale;
}
else
{
//item.body.Enabled = true;
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
if (item.body.Dir == -1.0f)
@@ -39,30 +156,80 @@ namespace Barotrauma.Items.Components
currentRotation += item.body.Rotation;
}
Vector2 currentItemPos = transformedItemPos;
int i = 0;
foreach (Item containedItem in Inventory.Items)
{
if (containedItem == null) continue;
if (AutoInteractWithContained)
{
containedItem.IsHighlighted = item.IsHighlighted;
item.IsHighlighted = false;
}
if (containedItem.body != null)
{
containedItem.body.FarseerBody.Rotation = currentRotation;
}
containedItem.Sprite.Draw(
spriteBatch,
new Vector2(transformedItemPos.X, -transformedItemPos.Y),
new Vector2(currentItemPos.X, -currentItemPos.Y),
containedItem.GetSpriteColor(),
-currentRotation,
1.0f,
(item.body != null && item.body.Dir == -1) ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
containedItem.Scale,
(item.body != null && item.body.Dir == -1) ? SpriteEffects.FlipHorizontally : SpriteEffects.None,
depth: ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth);
transformedItemPos += transformedItemInterval;
foreach (ItemContainer ic in containedItem.GetComponents<ItemContainer>())
{
if (ic.hideItems) continue;
ic.DrawContainedItems(spriteBatch);
}
i++;
if (Math.Abs(transformedItemInterval.X) > 0.001f && Math.Abs(transformedItemInterval.Y) > 0.001f)
{
//interval set on both axes -> use a grid layout
currentItemPos.X += transformedItemInterval.X;
if (i % ItemsPerRow == 0)
{
currentItemPos.X = transformedItemPos.X;
currentItemPos.Y += transformedItemInterval.Y;
}
}
else
{
currentItemPos += transformedItemInterval;
}
}
}
public override void UpdateHUD(Character character)
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
Inventory.Update((float)Timing.Step);
if (Inventory.RectTransform != null)
{
guiCustomComponent.RectTransform.Parent = Inventory.RectTransform;
}
//if the item is in the character's inventory, no need to update the item's inventory
//because the player can see it by hovering the cursor over the item
guiCustomComponent.Visible = item.ParentInventory?.Owner != character && DrawInventory;
if (!guiCustomComponent.Visible) return;
Inventory.Update(deltaTime, cam);
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
/*public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
Inventory.Draw(spriteBatch);
}
//if the item is in the character's inventory, no need to draw the item's inventory
//because the player can see it by hovering the cursor over the item
if (item.ParentInventory?.Owner == character || !DrawInventory) return;
Inventory.Draw(spriteBatch);
}*/
}
}
@@ -1,5 +1,7 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Text;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
@@ -10,20 +12,38 @@ namespace Barotrauma.Items.Components
private Color textColor;
private float scrollAmount;
private string scrollingText;
private float scrollPadding;
private int scrollIndex;
private bool needsScrolling;
private float[] charWidths;
[Serialize("0,0,0,0", true)]
public Vector4 Padding
{
get { return TextBlock.Padding; }
set { TextBlock.Padding = value; }
}
private string text;
[Serialize("", true), Editable(100)]
public string Text
{
get { return textBlock.Text.Replace("\n", ""); }
get { return text; }
set
{
if (value == TextBlock.Text || item.Rect.Width < 5) return;
if (value == text || item.Rect.Width < 5) return;
if (textBlock.Rect.Width != item.Rect.Width || textBlock.Rect.Height != item.Rect.Height)
if (TextBlock.Rect.Width != item.Rect.Width || textBlock.Rect.Height != item.Rect.Height)
{
textBlock = null;
}
text = value;
TextBlock.Text = value;
SetScrollingText();
}
}
@@ -48,42 +68,149 @@ namespace Barotrauma.Items.Components
}
}
private bool scrollable;
[Serialize(false, true)]
public bool Scrollable
{
get { return scrollable; }
set
{
scrollable = value;
IsActive = value;
TextBlock.Wrap = !scrollable;
TextBlock.TextAlignment = scrollable ? Alignment.CenterLeft : Alignment.Center;
}
}
[Serialize(20.0f, true)]
public float ScrollSpeed
{
get;
set;
}
private GUITextBlock TextBlock
{
get
{
if (textBlock == null)
{
textBlock = new GUITextBlock(new Rectangle(item.Rect.X, -item.Rect.Y, item.Rect.Width, item.Rect.Height), "",
Color.Transparent, textColor,
Alignment.TopLeft, Alignment.Center,
null, null, true);
textBlock.Font = GUI.SmallFont;
textBlock.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
textBlock.TextDepth = item.Sprite.Depth - 0.0001f;
textBlock.TextScale = TextScale;
textBlock = new GUITextBlock(new RectTransform(item.Rect.Size), "",
textColor: textColor, font: GUI.SmallFont, textAlignment: Alignment.Center, wrap: true, style: null)
{
TextDepth = item.SpriteDepth - 0.0001f,
TextScale = TextScale
};
}
return textBlock;
}
}
public override void Move(Vector2 amount)
{
textBlock.Rect = new Rectangle(item.Rect.X, -item.Rect.Y, item.Rect.Width, item.Rect.Height);
}
public ItemLabel(Item item, XElement element)
: base(item, element)
{
{
}
private void SetScrollingText()
{
if (!scrollable) return;
float totalWidth = textBlock.Font.MeasureString(text).X;
float textAreaWidth = Math.Max(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z, 0);
if (totalWidth >= textAreaWidth)
{
//add enough spaces to fill the rect
//(so the text can scroll entirely out of view before we reset it back to start)
needsScrolling = true;
float spaceWidth = textBlock.Font.MeasureChar(' ').X;
scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + text;
}
else
{
//whole text can fit in the textblock, no need to scroll
needsScrolling = false;
scrollingText = text;
scrollAmount = 0.0f;
scrollIndex = 0;
return;
}
//calculate character widths
scrollPadding = 0;
charWidths = new float[scrollingText.Length];
for (int i = 0; i < scrollingText.Length; i++)
{
float charWidth = TextBlock.Font.MeasureChar(scrollingText[i]).X;
scrollPadding = Math.Max(charWidth, scrollPadding);
charWidths[i] = charWidth;
}
scrollIndex = MathHelper.Clamp(scrollIndex, 0, text.Length);
}
public override void Update(float deltaTime, Camera cam)
{
if (!scrollable) return;
if (scrollingText == null)
{
SetScrollingText();
}
if (!needsScrolling) return;
scrollAmount -= deltaTime * ScrollSpeed;
float currLength = 0;
StringBuilder sb = new StringBuilder();
float textAreaWidth = textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z;
for (int i = scrollIndex; i < scrollingText.Length; i++)
{
//first character is out of view -> skip to next character
if (i == scrollIndex && scrollAmount < -charWidths[i])
{
scrollIndex++;
scrollAmount = 0;
if (scrollIndex >= scrollingText.Length) //reached the last character, reset
{
scrollIndex = 0;
break;
}
continue;
}
//reached the right edge, stop adding more character
if (scrollAmount + (currLength + charWidths[i] + scrollPadding) >= textAreaWidth)
{
break;
}
else
{
currLength += charWidths[i];
sb.Append(scrollingText[i]);
}
}
TextBlock.Text = sb.ToString();
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
{
var drawPos = new Vector2(
item.DrawPosition.X - item.Rect.Width / 2.0f,
-(item.DrawPosition.Y + item.Rect.Height / 2.0f));
Rectangle worldRect = item.WorldRect;
if (worldRect.X > Screen.Selected.Cam.WorldView.Right ||
worldRect.Right < Screen.Selected.Cam.WorldView.X ||
worldRect.Y < Screen.Selected.Cam.WorldView.Y - Screen.Selected.Cam.WorldView.Height ||
worldRect.Y - worldRect.Height > Screen.Selected.Cam.WorldView.Y)
{
return;
}
textBlock.Draw(spriteBatch, drawPos - textBlock.Rect.Location.ToVector2());
textBlock.TextOffset = drawPos - textBlock.Rect.Location.ToVector2() + new Vector2(scrollAmount + scrollPadding, 0.0f);
textBlock.DrawManually(spriteBatch);
}
}
}
@@ -0,0 +1,17 @@
using Barotrauma.Networking;
using Lidgren.Network;
namespace Barotrauma.Items.Components
{
partial class LevelResource : ItemComponent, IServerSerializable
{
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
DeattachTimer = msg.ReadSingle();
if (deattachTimer >= DeattachDuration)
{
holdable.DeattachFromWall();
}
}
}
}
@@ -9,16 +9,20 @@ namespace Barotrauma.Items.Components
partial class LightComponent : Powered, IServerSerializable, IDrawableComponent
{
private LightSource light;
public LightSource Light
{
get { return light; }
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
{
if (light.LightSprite != null && (item.body == null || item.body.Enabled))
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f)
{
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, 1.0f, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, item.Sprite.Depth - 0.0001f);
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, 1.0f, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, item.SpriteDepth - 0.0001f);
}
}
public override void FlipX()
public override void FlipX(bool relativeToSub)
{
if (light?.LightSprite != null)
{
@@ -1,27 +1,77 @@
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Deconstructor : Powered, IServerSerializable, IClientSerializable
{
GUIProgressBar progressBar;
GUIButton activateButton;
private GUIButton activateButton;
private GUIComponent inputInventoryHolder, outputInventoryHolder;
private GUICustomComponent inputInventoryOverlay;
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
private GUIComponent inSufficientPowerWarning;
partial void InitProjSpecific(XElement element)
{
GuiFrame.Draw(spriteBatch);
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
Stretch = true,
RelativeSpacing = 0.02f
};
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.2f, 0.7f), paddedFrame.RectTransform), style: null);
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null)
{
CanBeFocused = false
};
activateButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.1f), paddedFrame.RectTransform),
TextManager.Get("DeconstructorDeconstruct"))
{
OnClicked = ToggleActive
};
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform), TextManager.Get("DeconstructorNoPower"),
textColor: Color.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
{
HoverColor = Color.Black,
IgnoreLayoutGroups = true,
Visible = false,
CanBeFocused = false
};
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.3f), paddedFrame.RectTransform), style: null);
}
public override void AddToGUIUpdateList()
partial void OnItemLoadedProjSpecific()
{
GuiFrame.AddToGUIUpdateList();
inputContainer.AllowUIOverlap = true;
inputContainer.Inventory.RectTransform = inputInventoryHolder.RectTransform;
outputContainer.AllowUIOverlap = true;
outputContainer.Inventory.RectTransform = outputInventoryHolder.RectTransform;
}
public override void UpdateHUD(Character character)
private void DrawOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
{
GuiFrame.Update((float)Timing.Step);
overlayComponent.RectTransform.SetAsLastChild();
var lastSlot = inputContainer.Inventory.slots.Last();
GUI.DrawRectangle(spriteBatch,
new Rectangle(
lastSlot.Rect.X, lastSlot.Rect.Y + (int)(lastSlot.Rect.Height * (1.0f - progressState)),
lastSlot.Rect.Width, (int)(lastSlot.Rect.Height * progressState)),
Color.Green * 0.5f, isFilled: true);
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
inSufficientPowerWarning.Visible = powerConsumption > 0 && voltage < minVoltage;
activateButton.Enabled = !inSufficientPowerWarning.Visible;
}
private bool ToggleActive(GUIButton button, object obj)
@@ -1,25 +1,142 @@
using Microsoft.Xna.Framework;
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Engine : Powered
partial class Engine : Powered, IDrawableComponent
{
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
GuiFrame.Draw(spriteBatch);
private float spriteIndex;
GUI.Font.DrawString(spriteBatch, TextManager.Get("Force") + ": " + (int)(targetForce) + " %", new Vector2(GuiFrame.Rect.X + 30, GuiFrame.Rect.Y + 30), Color.White);
private SpriteSheet propellerSprite;
private GUITickBox powerIndicator;
private GUIScrollBar forceSlider;
public float AnimSpeed
{
get;
private set;
}
public override void AddToGUIUpdateList()
partial void InitProjSpecific(XElement element)
{
GuiFrame.AddToGUIUpdateList();
powerIndicator = new GUITickBox(new RectTransform(new Point(30, 30), GuiFrame.RectTransform) { RelativeOffset = new Vector2(0.05f, 0.15f) },
TextManager.Get("EnginePowered"), style: "IndicatorLightGreen")
{
CanBeFocused = false
};
string powerLabel = TextManager.Get("EngineForce");
new GUITextBlock(new RectTransform(new Vector2(0.9f, 0.3f), GuiFrame.RectTransform, Anchor.BottomCenter)
{ RelativeOffset = new Vector2(0.0f, 0.4f) }, "", textAlignment: Alignment.Center)
{
TextGetter = () => { return powerLabel + ": " + (int)(targetForce) + " %"; }
};
var sliderArea = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.25f), GuiFrame.RectTransform, Anchor.BottomCenter)
{ RelativeOffset = new Vector2(0.0f, 0.2f) }, isHorizontal: true);
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), sliderArea.RectTransform), TextManager.Get("EngineBackwards"),
font: GUI.SmallFont, textAlignment: Alignment.Center);
forceSlider = new GUIScrollBar(new RectTransform(new Vector2(0.6f, 1.0f), sliderArea.RectTransform), barSize: 0.25f, style: "GUISlider")
{
Step = 0.05f,
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
float newTargetForce = barScroll * 200.0f - 100.0f;
if (Math.Abs(newTargetForce - targetForce) < 0.01) return false;
targetForce = newTargetForce;
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(Character.Controlled.LogName + " set the force speed of " + item.Name + " to " + (int)(targetForce) + " %", ServerLog.MessageType.ItemInteraction);
}
else if (GameMain.Client != null)
{
correctionTimer = CorrectionDelay;
item.CreateClientEvent(this);
}
return true;
}
};
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), sliderArea.RectTransform), TextManager.Get("EngineForwards"),
font: GUI.SmallFont, textAlignment: Alignment.Center);
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "propellersprite":
propellerSprite = new SpriteSheet(subElement);
AnimSpeed = subElement.GetAttributeFloat("animspeed", 1.0f);
break;
}
}
}
public override void UpdateHUD(Character character)
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
GuiFrame.Update(1.0f / 60.0f);
powerIndicator.Selected = hasPower && IsActive;
if (!PlayerInput.LeftButtonHeld())
{
float newScroll = (targetForce + 100.0f) / 200.0f;
if (Math.Abs(newScroll - forceSlider.BarScroll) > 0.01f)
{
forceSlider.BarScroll = newScroll;
}
}
}
partial void UpdateAnimation(float deltaTime)
{
if (propellerSprite == null) return;
spriteIndex += (force / 100.0f) * AnimSpeed * deltaTime;
if (spriteIndex < 0) spriteIndex = propellerSprite.FrameCount;
if (spriteIndex >= propellerSprite.FrameCount) spriteIndex = 0.0f;
}
public void Draw(SpriteBatch spriteBatch, bool editing)
{
if (propellerSprite != null)
{
Vector2 drawPos = item.DrawPosition;
drawPos += PropellerPos;
drawPos.Y = -drawPos.Y;
propellerSprite.Draw(spriteBatch, (int)Math.Floor(spriteIndex), drawPos, Color.White, propellerSprite.Origin, 0.0f, Vector2.One);
}
if (editing)
{
Vector2 drawPos = item.DrawPosition;
drawPos += PropellerPos;
drawPos.Y = -drawPos.Y;
GUI.DrawRectangle(spriteBatch, drawPos - Vector2.One * 10, Vector2.One * 20, Color.Red);
}
}
public void ClientWrite(NetBuffer msg, object[] extraData = null)
{
//targetForce can only be adjusted at 10% intervals -> no need for more accuracy than this
msg.WriteRangedInteger(-10, 10, (int)(targetForce / 10.0f));
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
if (correctionTimer > 0.0f)
{
StartDelayedCorrection(type, msg.ExtractBits(5), sendingTime);
return;
}
targetForce = msg.ReadRangedInteger(-10, 10) * 10.0f;
}
}
}
@@ -1,4 +1,5 @@
using Barotrauma.Networking;
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -13,148 +14,309 @@ namespace Barotrauma.Items.Components
private GUIListBox itemList;
private GUIFrame selectedItemFrame;
private GUIProgressBar progressBar;
private GUIButton activateButton;
private GUIComponent inputInventoryHolder, outputInventoryHolder;
private GUICustomComponent inputInventoryOverlay, outputInventoryOverlay;
private FabricableItem selectedItem;
private GUIComponent inSufficientPowerWarning;
private Pair<Rectangle, string> tooltip;
partial void InitProjSpecific()
{
GuiFrame.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f);
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
Stretch = true,
RelativeSpacing = 0.02f
};
itemList = new GUIListBox(new Rectangle(0, 0, GuiFrame.Rect.Width / 2 - 20, 0), "", GuiFrame);
itemList.OnSelected = SelectItem;
itemList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), paddedFrame.RectTransform))
{
OnSelected = SelectItem
};
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 0.15f), paddedFrame.RectTransform), style: null);
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay, null)
{
CanBeFocused = false
};
var outputArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.3f), paddedFrame.RectTransform), isHorizontal: true);
selectedItemFrame = new GUIFrame(new RectTransform(new Vector2(0.75f, 1.0f), outputArea.RectTransform), style: "InnerFrame");
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), outputArea.RectTransform), style: null);
outputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, outputArea.RectTransform), DrawOutputOverLay, null)
{
CanBeFocused = false
};
foreach (FabricableItem fi in fabricableItems)
{
GUIFrame frame = new GUIFrame(new Rectangle(0, 0, 0, 50), Color.Transparent, null, itemList)
GUIFrame frame = new GUIFrame(new RectTransform(new Point(itemList.Rect.Width, 50), itemList.Content.RectTransform), style: null)
{
UserData = fi,
Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f),
HoverColor = Color.Gold * 0.2f,
SelectedColor = Color.Gold * 0.5f,
ToolTip = fi.TargetItem.Description
};
GUITextBlock textBlock = new GUITextBlock(
new Rectangle(40, 0, 0, 25),
fi.TargetItem.Name,
Color.Transparent, Color.White,
Alignment.Left, Alignment.Left,
null, frame);
textBlock.ToolTip = fi.TargetItem.Description;
textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
if (fi.TargetItem.sprite != null)
GUITextBlock textBlock = new GUITextBlock(new RectTransform(Vector2.Zero, frame.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(50, 0) },
fi.DisplayName)
{
GUIImage img = new GUIImage(new Rectangle(0, 0, 40, 40), fi.TargetItem.sprite, Alignment.Left, frame);
img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f);
img.Color = fi.TargetItem.SpriteColor;
img.ToolTip = fi.TargetItem.Description;
ToolTip = fi.TargetItem.Description
};
var itemIcon = fi.TargetItem.InventoryIcon ?? fi.TargetItem.sprite;
if (itemIcon != null)
{
GUIImage img = new GUIImage(new RectTransform(new Point(40, 40), frame.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(3, 0) },
itemIcon, scaleToFit: true)
{
Color = fi.TargetItem.InventoryIconColor,
ToolTip = fi.TargetItem.Description
};
}
}
activateButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.07f), paddedFrame.RectTransform),
TextManager.Get("FabricatorCreate"))
{
OnClicked = StartButtonClicked,
UserData = selectedItem,
Enabled = false
};
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform), TextManager.Get("FabricatorNoPower"),
textColor: Color.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
{
HoverColor = Color.Black,
IgnoreLayoutGroups = true,
Visible = false,
CanBeFocused = false
};
}
partial void OnItemLoadedProjSpecific()
{
inputContainer.AllowUIOverlap = true;
inputContainer.Inventory.RectTransform = inputInventoryHolder.RectTransform;
outputContainer.AllowUIOverlap = true;
outputContainer.Inventory.RectTransform = outputInventoryHolder.RectTransform;
}
partial void SelectProjSpecific(Character character)
{
var nonItems = itemList.Content.Children.Where(c => !(c.UserData is FabricableItem)).ToList();
nonItems.ForEach(i => itemList.Content.RemoveChild(i));
itemList.Content.RectTransform.SortChildren((c1, c2) =>
{
var item1 = c1.GUIComponent.UserData as FabricableItem;
var item2 = c2.GUIComponent.UserData as FabricableItem;
bool hasSkills1 = DegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f;
bool hasSkills2 = DegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f;
if (hasSkills1 != hasSkills2)
{
return hasSkills1 ? -1 : 1;
}
return string.Compare(item1.DisplayName, item2.DisplayName);
});
var sufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform), "Sufficient skills to fabricate:", textColor: Color.LightGreen)
{
CanBeFocused = false
};
sufficientSkillsText.RectTransform.SetAsFirstChild();
var insufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform), "Insufficient skills to fabricate:", textColor: Color.Orange)
{
CanBeFocused = false
};
var firstinSufficient = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricableItem fabricableItem && DegreeOfSuccess(character, fabricableItem.RequiredSkills) < 0.5f);
if (firstinSufficient != null)
{
insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform));
}
}
private void DrawInputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
{
overlayComponent.RectTransform.SetAsLastChild();
FabricableItem targetItem = fabricatedItem ?? selectedItem;
if (targetItem != null)
{
int slotIndex = 0;
var missingItems = new List<FabricableItem.RequiredItem>();
foreach (FabricableItem.RequiredItem requiredItem in targetItem.RequiredItems)
{
for (int i = 0; i < requiredItem.Amount; i++)
{
missingItems.Add(requiredItem);
}
}
foreach (Item item in inputContainer.Inventory.Items)
{
if (item == null) { continue; }
missingItems.Remove(missingItems.FirstOrDefault(mi => mi.ItemPrefab == item.prefab));
}
var availableIngredients = GetAvailableIngredients();
foreach (FabricableItem.RequiredItem requiredItem in missingItems)
{
//highlight suitable ingredients in linked inventories
foreach (Item item in availableIngredients)
{
if (item.ParentInventory != inputContainer.Inventory && IsItemValidIngredient(item, requiredItem))
{
int availableSlotIndex = Array.IndexOf(item.ParentInventory.Items, item);
if (item.ParentInventory.slots[availableSlotIndex].HighlightTimer <= 0.0f)
{
item.ParentInventory.slots[availableSlotIndex].ShowBorderHighlight(Color.LightGreen * 0.5f, 0.5f, 0.5f);
}
}
}
while (slotIndex < inputContainer.Capacity && inputContainer.Inventory.Items[slotIndex] != null)
{
slotIndex++;
}
if (slotIndex >= inputContainer.Capacity) { break; }
var itemIcon = requiredItem.ItemPrefab.InventoryIcon ?? requiredItem.ItemPrefab.sprite;
Rectangle slotRect = inputContainer.Inventory.slots[slotIndex].Rect;
itemIcon.Draw(
spriteBatch,
slotRect.Center.ToVector2(),
color: requiredItem.ItemPrefab.InventoryIconColor * 0.3f,
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y));
if (slotRect.Contains(PlayerInput.MousePosition))
{
string toolTipText = requiredItem.ItemPrefab.Name;
if (!string.IsNullOrEmpty(requiredItem.ItemPrefab.Description))
{
toolTipText += '\n' + requiredItem.ItemPrefab.Description;
}
tooltip = new Pair<Rectangle, string>(slotRect, toolTipText);
}
slotIndex++;
}
}
}
private void DrawOutputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
{
overlayComponent.RectTransform.SetAsLastChild();
FabricableItem targetItem = fabricatedItem ?? selectedItem;
if (targetItem != null)
{
var itemIcon = targetItem.TargetItem.InventoryIcon ?? targetItem.TargetItem.sprite;
Rectangle slotRect = outputContainer.Inventory.slots[0].Rect;
GUI.DrawRectangle(spriteBatch,
new Rectangle(
slotRect.X, slotRect.Y + (int)(slotRect.Height * (1.0f - progressState)),
slotRect.Width, (int)(slotRect.Height * progressState)),
Color.Green * 0.5f, isFilled: true);
itemIcon.Draw(
spriteBatch,
slotRect.Center.ToVector2(),
color: targetItem.TargetItem.InventoryIconColor * 0.4f,
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y) * 0.9f);
}
if (tooltip != null)
{
GUIComponent.DrawToolTip(spriteBatch, tooltip.Second, tooltip.First);
tooltip = null;
}
}
private bool SelectItem(GUIComponent component, object obj)
{
FabricableItem targetItem = obj as FabricableItem;
if (targetItem == null) return false;
selectedItem = obj as FabricableItem;
if (selectedItem == null) return false;
if (selectedItemFrame != null) GuiFrame.RemoveChild(selectedItemFrame);
selectedItemFrame.ClearChildren();
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), selectedItemFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f, Stretch = true };
//int width = 200, height = 150;
selectedItemFrame = new GUIFrame(new Rectangle(0, 0, (int)(GuiFrame.Rect.Width * 0.4f), 350), Color.Black * 0.8f, Alignment.CenterY | Alignment.Right, null, GuiFrame);
selectedItemFrame.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f);
progressBar = new GUIProgressBar(new Rectangle(0, 0, 0, 20), Color.Green, "", 0.0f, Alignment.BottomCenter, selectedItemFrame);
progressBar.IsHorizontal = true;
if (targetItem.TargetItem.sprite != null)
/*var itemIcon = selectedItem.TargetItem.InventoryIcon ?? selectedItem.TargetItem.sprite;
if (itemIcon != null)
{
int y = 0;
GUIImage img = new GUIImage(new Rectangle(10, 0, 40, 40), targetItem.TargetItem.sprite, Alignment.TopLeft, selectedItemFrame);
img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f);
img.Color = targetItem.TargetItem.SpriteColor;
new GUITextBlock(
new Rectangle(60, 0, 0, 25),
targetItem.TargetItem.Name,
Color.Transparent, Color.White,
Alignment.TopLeft,
Alignment.TopLeft, null,
selectedItemFrame, true);
y += 40;
if (!string.IsNullOrWhiteSpace(targetItem.TargetItem.Description))
GUIImage img = new GUIImage(new RectTransform(new Point(40, 40), paddedFrame.RectTransform),
itemIcon, scaleToFit: true)
{
var description = new GUITextBlock(
new Rectangle(0, y, 0, 0),
targetItem.TargetItem.Description,
"", Alignment.TopLeft, Alignment.TopLeft,
selectedItemFrame, true, GUI.SmallFont);
Color = selectedItem.TargetItem.InventoryIconColor
};
}*/
var nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
selectedItem.TargetItem.Name, textAlignment: Alignment.CenterLeft);
y += description.Rect.Height + 10;
}
List<Skill> inadequateSkills = new List<Skill>();
if (Character.Controlled != null)
if (!string.IsNullOrWhiteSpace(selectedItem.TargetItem.Description))
{
var description = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
selectedItem.TargetItem.Description,
font: GUI.SmallFont, wrap: true);
if (description.Rect.Height > paddedFrame.Rect.Height * 0.4f)
{
inadequateSkills = targetItem.RequiredSkills.FindAll(skill => Character.Controlled.GetSkillLevel(skill.Name) < skill.Level);
description.Wrap = false;
description.Text = description.WrappedText.Split('\n').First()+"...";
nameBlock.ToolTip = description.ToolTip = selectedItem.TargetItem.Description;
description.RectTransform.MaxSize = new Point(int.MaxValue, (int)description.Font.MeasureString(description.Text).Y);
}
string text = TextManager.Get("FabricatorRequiredItems")+ ":\n";
foreach (Tuple<ItemPrefab, int, float, bool> ip in targetItem.RequiredItems)
}
List<Skill> inadequateSkills = new List<Skill>();
if (Character.Controlled != null)
{
inadequateSkills = selectedItem.RequiredSkills.FindAll(skill => Character.Controlled.GetSkillLevel(skill.Identifier) < skill.Level);
}
if (selectedItem.RequiredSkills.Any())
{
string text = TextManager.Get("FabricatorRequiredSkills") + ":\n";
foreach (Skill skill in selectedItem.RequiredSkills)
{
text += " - " + ip.Item1.Name + " x" + ip.Item2 + (ip.Item3 < 1.0f ? ", " + ip.Item3 * 100 + "% " + TextManager.Get("FabricatorRequiredCondition") + "\n" : "\n");
text += " - " + TextManager.Get("SkillName." + skill.Identifier) + " " + TextManager.Get("Lvl").ToLower() + " " + skill.Level;
if (skill != selectedItem.RequiredSkills.Last()) { text += "\n"; }
}
text += TextManager.Get("FabricatorRequiredTime") + ": " + targetItem.RequiredTime + " s\n";
var requiredItemsText = new GUITextBlock(
new Rectangle(0, y, 0, 0),
text,
Color.Transparent, Color.White,
Alignment.TopLeft,
Alignment.TopLeft, null,
selectedItemFrame,
font: GUI.SmallFont);
if (targetItem.RequiredSkills.Any())
{
text = TextManager.Get("FabricatorRequiredSkills") + ":\n";
foreach (Skill skill in inadequateSkills)
{
text += " - " + skill.Name + " " + TextManager.Get("Lvl").ToLower() + " " + skill.Level + "\n";
}
new GUITextBlock(
new Rectangle(0, y + requiredItemsText.Rect.Height, 0, 0),
text,
Color.Transparent, inadequateSkills.Any() ? Color.Red : Color.White,
Alignment.TopLeft,
Alignment.TopLeft, null,
selectedItemFrame,
font: GUI.SmallFont);
}
activateButton = new GUIButton(new Rectangle(0, -30, 100, 20), TextManager.Get("FabricatorCreate"), Color.White, Alignment.CenterX | Alignment.Bottom, "", selectedItemFrame);
activateButton.OnClicked = StartButtonClicked;
activateButton.UserData = targetItem;
activateButton.Enabled = false;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), text,
textColor: inadequateSkills.Any() ? Color.Red : Color.LightGreen, font: GUI.SmallFont);
}
float degreeOfSuccess = DegreeOfSuccess(Character.Controlled, selectedItem.RequiredSkills);
if (degreeOfSuccess > 0.5f) { degreeOfSuccess = 1.0f; }
float requiredTime = GetRequiredTime(selectedItem, Character.Controlled);
string requiredTimeText = TextManager.Get("FabricatorRequiredTime") + ": " + ToolBox.SecondsToReadableTime(requiredTime);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
requiredTimeText, textColor: ToolBox.GradientLerp(degreeOfSuccess, Color.Red, Color.Yellow, Color.LightGreen), font: GUI.SmallFont);
return true;
}
private bool StartButtonClicked(GUIButton button, object obj)
{
if (selectedItem == null) { return false; }
if (fabricatedItem == null)
{
StartFabricating(obj as FabricableItem, Character.Controlled);
StartFabricating(selectedItem, Character.Controlled);
}
else
{
@@ -173,49 +335,29 @@ namespace Barotrauma.Items.Components
return true;
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
GuiFrame.Draw(spriteBatch);
}
public override void AddToGUIUpdateList()
{
GuiFrame.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character)
{
FabricableItem targetItem = itemList.SelectedData as FabricableItem;
if (targetItem != null)
{
activateButton.Enabled = CanBeFabricated(targetItem, character);
}
activateButton.Enabled = false;
inSufficientPowerWarning.Visible = powerConsumption > 0 && voltage < minVoltage;
var availableIngredients = GetAvailableIngredients();
if (character != null)
{
bool itemsChanged = false;
if (prevContainedItems == null)
foreach (GUIComponent child in itemList.Content.Children)
{
itemsChanged = true;
}
else
{
var itemContainer = item.GetComponent<ItemContainer>();
for (int i = 0; i < itemContainer.Inventory.Items.Length; i++)
var itemPrefab = child.UserData as FabricableItem;
if (itemPrefab == null) continue;
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients);
if (itemPrefab == selectedItem)
{
if (prevContainedItems[i] != itemContainer.Inventory.Items[i])
{
itemsChanged = true;
break;
}
activateButton.Enabled = canBeFabricated;
}
child.GetChild<GUITextBlock>().TextColor = Color.White * (canBeFabricated ? 1.0f : 0.5f);
child.GetChild<GUIImage>().Color = itemPrefab.TargetItem.InventoryIconColor * (canBeFabricated ? 1.0f : 0.5f);
}
if (itemsChanged) CheckFabricableItems(character);
}
GuiFrame.Update((float)Timing.Step);
}
public void ClientWrite(NetBuffer msg, object[] extraData = null)
@@ -227,8 +369,10 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
int itemIndex = msg.ReadRangedInteger(-1, fabricableItems.Count - 1);
UInt16 userID = msg.ReadUInt16();
Character user = Entity.FindEntityByID(userID) as Character;
if (itemIndex == -1)
if (itemIndex == -1 || user == null)
{
CancelFabricating();
}
@@ -239,7 +383,7 @@ namespace Barotrauma.Items.Components
if (itemIndex < 0 || itemIndex >= fabricableItems.Count) return;
SelectItem(null, fabricableItems[itemIndex]);
StartFabricating(fabricableItems[itemIndex]);
StartFabricating(fabricableItems[itemIndex], user);
}
}
}
@@ -1,126 +1,225 @@
using Microsoft.Xna.Framework;
using Barotrauma.Extensions;
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 MiniMap : Powered
{
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
private GUIFrame submarineContainer;
private GUIFrame hullInfoFrame;
private GUITextBlock hullNameText, hullBreachText, hullAirQualityText, hullWaterText;
private List<Submarine> displayedSubs = new List<Submarine>();
partial void InitProjSpecific(XElement element)
{
new GUICustomComponent(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center),
DrawHUDBack, null);
submarineContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center), style: null);
hullInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.13f), GUI.Canvas, minSize: new Point(250, 150)),
style: "InnerFrame")
{
CanBeFocused = false
};
var hullInfoContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), hullInfoFrame.RectTransform, Anchor.Center))
{
Stretch = true,
RelativeSpacing = 0.05f
};
hullNameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), hullInfoContainer.RectTransform), "");
hullBreachText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), hullInfoContainer.RectTransform), "");
hullAirQualityText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), hullInfoContainer.RectTransform), "");
hullWaterText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), hullInfoContainer.RectTransform), "");
hullInfoFrame.Children.ForEach(c => { c.CanBeFocused = false; c.Children.ForEach(c2 => c2.CanBeFocused = false); });
}
public override void AddToGUIUpdateList()
{
base.AddToGUIUpdateList();
if (hasPower) hullInfoFrame.AddToGUIUpdateList();
}
public override void OnMapLoaded()
{
base.OnMapLoaded();
CreateHUD();
}
private void CreateHUD()
{
submarineContainer.ClearChildren();
if (item.Submarine == null) return;
int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
item.Submarine.CreateMiniMap(submarineContainer);
displayedSubs.Clear();
displayedSubs.Add(item.Submarine);
displayedSubs.AddRange(item.Submarine.DockedTo);
}
GuiFrame.Draw(spriteBatch);
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
//recreate HUD if the subs we should display have changed
if ((item.Submarine == null && displayedSubs.Count > 0) || //item not inside a sub anymore, but display is still showing subs
!displayedSubs.Contains(item.Submarine) || //current sub not displayer
item.Submarine.DockedTo.Any(s => !displayedSubs.Contains(s)) || //some of the docked subs not diplayed
displayedSubs.Any(s => s != item.Submarine && !item.Submarine.DockedTo.Contains(s))) //displaying a sub that shouldn't be displayed
{
CreateHUD();
}
if (!hasPower) return;
float distort = 1.0f - item.Condition / 100.0f;
foreach (HullData hullData in hullDatas.Values)
{
hullData.DistortionTimer -= deltaTime;
if (hullData.DistortionTimer <= 0.0f)
{
hullData.Distort = Rand.Range(0.0f, 1.0f) < distort * distort;
if (hullData.Distort)
{
hullData.Oxygen = Rand.Range(0.0f, 100.0f);
hullData.Water = Rand.Range(0.0f, 1.0f);
}
hullData.DistortionTimer = Rand.Range(1.0f, 10.0f);
}
}
}
Rectangle miniMap = new Rectangle(x + 20, y + 40, width - 40, height - 60);
private void DrawHUDBack(SpriteBatch spriteBatch, GUICustomComponent container)
{
hullInfoFrame.Visible = false;
if (item.Submarine == null || !hasPower)
{
foreach (Hull hull in Hull.hullList)
{
var hullFrame = submarineContainer.Children.First().FindChild(hull);
if (hullFrame == null) continue;
float size = Math.Min((float)miniMap.Width / (float)item.Submarine.Borders.Width, (float)miniMap.Height / (float)item.Submarine.Borders.Height);
hullFrame.Color = Color.DarkCyan * 0.3f;
hullFrame.Children.First().Color = Color.DarkCyan * 0.3f;
}
}
float scale = 1.0f;
HashSet<Submarine> subs = new HashSet<Submarine>();
foreach (Hull hull in Hull.hullList)
{
Point topLeft = new Point(
miniMap.X + (int)((hull.Rect.X - item.Submarine.HiddenSubPosition.X - item.Submarine.Borders.X) * size),
miniMap.Y - (int)((hull.Rect.Y - item.Submarine.HiddenSubPosition.Y - item.Submarine.Borders.Y) * size));
if (hull.Submarine == null) continue;
var hullFrame = submarineContainer.Children.First().FindChild(hull);
if (hullFrame == null) continue;
Point bottomRight = new Point(
topLeft.X + (int)(hull.Rect.Width * size),
topLeft.Y + (int)(hull.Rect.Height * size));
topLeft.X = (int)MathUtils.RoundTowardsClosest(topLeft.X, 4);
topLeft.Y = (int)MathUtils.RoundTowardsClosest(topLeft.Y, 4);
bottomRight.X = (int)MathUtils.RoundTowardsClosest(bottomRight.X, 4);
bottomRight.Y = (int)MathUtils.RoundTowardsClosest(bottomRight.Y, 4);
Rectangle hullRect = new Rectangle(
topLeft, bottomRight - topLeft);
HullData hullData;
hullDatas.TryGetValue(hull, out hullData);
Color borderColor = Color.Green;
//hull integrity -----------------------------------
hullDatas.TryGetValue(hull, out HullData hullData);
if (hullData == null)
{
hullData = new HullData();
hullDatas.Add(hull, hullData);
}
if (hullData.Distort)
{
hullFrame.Children.First().Color = Color.Lerp(Color.Black, Color.DarkGray * 0.5f, Rand.Range(0.0f, 1.0f));
hullFrame.Color = Color.DarkGray * 0.5f;
continue;
}
subs.Add(hull.Submarine);
scale = Math.Min(
hullFrame.Parent.Rect.Width / (float)hull.Submarine.Borders.Width,
hullFrame.Parent.Rect.Height / (float)hull.Submarine.Borders.Height);
Color borderColor = Color.DarkCyan;
float? gapOpenSum = 0.0f;
if (ShowHullIntegrity)
{
gapOpenSum = hull.ConnectedGaps.Where(g => !g.IsRoomToRoom).Sum(g => g.Open);
borderColor = Color.Lerp(borderColor, Color.Red, Math.Min((float)gapOpenSum, 1.0f));
borderColor = Color.Lerp(Color.DarkCyan, Color.Red, Math.Min((float)gapOpenSum, 1.0f));
}
//oxygen -----------------------------------
float? oxygenAmount = null;
if (RequireOxygenDetectors && (hullData == null || hullData.Oxygen == null))
if (!RequireOxygenDetectors || hullData?.Oxygen != null)
{
borderColor *= 0.5f;
oxygenAmount = RequireOxygenDetectors ? hullData.Oxygen : hull.OxygenPercentage;
GUI.DrawRectangle(spriteBatch, hullFrame.Rect, Color.Lerp(Color.Red * 0.5f, Color.Green * 0.3f, (float)oxygenAmount / 100.0f), true);
}
else
{
oxygenAmount = hullData != null && hullData.Oxygen != null ? (float)hullData.Oxygen : hull.OxygenPercentage;
GUI.DrawRectangle(spriteBatch, hullRect, Color.Lerp(Color.Red * 0.5f, Color.Green * 0.3f, (float)oxygenAmount / 100.0f), true);
}
//water -----------------------------------
float? waterAmount = null;
if (RequireWaterDetectors && (hullData == null || hullData.Water == null))
if (!RequireWaterDetectors || hullData.Water != null)
{
borderColor *= 0.5f;
}
else
{
waterAmount = hullData != null && hullData.Water != null ?
(float)hullData.Water :
Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
if (hullRect.Height * waterAmount > 3.0f)
waterAmount = RequireWaterDetectors ? hullData.Water : Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
if (hullFrame.Rect.Height * waterAmount > 3.0f)
{
Rectangle waterRect = new Rectangle(
hullRect.X,
(int)(hullRect.Y + hullRect.Height * (1.0f - waterAmount)),
hullRect.Width,
(int)(hullRect.Height * waterAmount));
hullFrame.Rect.X, (int)(hullFrame.Rect.Y + hullFrame.Rect.Height * (1.0f - waterAmount)),
hullFrame.Rect.Width, (int)(hullFrame.Rect.Height * waterAmount));
waterRect.Inflate(-3, -3);
GUI.DrawRectangle(spriteBatch, waterRect, Color.DarkBlue, true);
GUI.DrawRectangle(spriteBatch, waterRect, new Color(85, 136, 147), true);
GUI.DrawLine(spriteBatch, new Vector2(waterRect.X, waterRect.Y), new Vector2(waterRect.Right, waterRect.Y), Color.LightBlue);
}
}
if (hullRect.Contains(PlayerInput.MousePosition))
if (GUI.MouseOn == hullFrame || hullFrame.IsParentOf(GUI.MouseOn))
{
borderColor = Color.White;
hullInfoFrame.RectTransform.ScreenSpaceOffset = hullFrame.Rect.Center;
if (gapOpenSum > 0.1f)
{
GUI.DrawString(spriteBatch,
new Vector2(x + 10, y + height - 60),
TextManager.Get("MiniMapHullBreach"), Color.Red, Color.Black * 0.5f, 2, GUI.SmallFont);
}
hullInfoFrame.Visible = true;
hullNameText.Text = hull.RoomName;
GUI.DrawString(spriteBatch,
new Vector2(x + 10, y + height - 60),
oxygenAmount == null ? TextManager.Get("MiniMapAirQualityUnavailable") : TextManager.Get("MiniMapAirQuality") + ": " + (int)oxygenAmount + " %",
oxygenAmount == null ? Color.Red : Color.Lerp(Color.Red, Color.LightGreen, (float)oxygenAmount / 100.0f),
Color.Black * 0.5f, 2, GUI.SmallFont);
hullBreachText.Text = gapOpenSum > 0.1f ? TextManager.Get("MiniMapHullBreach") : "";
hullBreachText.TextColor = Color.Red;
GUI.DrawString(spriteBatch,
new Vector2(x + 10, y + height - 40),
waterAmount == null ? TextManager.Get("MiniMapWaterLevelUnavailable") : TextManager.Get("MiniMapWaterLevel") + ": " + (int)(waterAmount * 100.0f) + " %",
waterAmount == null ? Color.Red : Color.Lerp(Color.LightGreen, Color.Red, (float)waterAmount),
Color.Black * 0.5f, 2, GUI.SmallFont);
hullAirQualityText.Text = oxygenAmount == null ? TextManager.Get("MiniMapAirQualityUnavailable") : TextManager.Get("MiniMapAirQuality") + ": " + (int)oxygenAmount + " %";
hullAirQualityText.TextColor = oxygenAmount == null ? Color.Red : Color.Lerp(Color.Red, Color.LightGreen, (float)oxygenAmount / 100.0f);
hullWaterText.Text = waterAmount == null ? TextManager.Get("MiniMapWaterLevelUnavailable") : TextManager.Get("MiniMapWaterLevel") + ": " + (int)(waterAmount * 100.0f) + " %";
hullWaterText.TextColor = waterAmount == null ? Color.Red : Color.Lerp(Color.LightGreen, Color.Red, (float)waterAmount);
borderColor = Color.Lerp(borderColor, Color.White, 0.5f);
hullFrame.Children.First().Color = Color.White;
}
else
{
hullFrame.Children.First().Color = Color.DarkCyan * 0.8f;
}
hullFrame.Color = borderColor;
}
GUI.DrawRectangle(spriteBatch, hullRect, borderColor, false, 0.0f, 2);
foreach (Submarine sub in subs)
{
if (sub.HullVertices == null) { continue; }
Rectangle worldBorders = sub.GetDockedBorders();
worldBorders.Location += sub.WorldPosition.ToPoint();
scale = Math.Min(
submarineContainer.Rect.Width / (float)worldBorders.Width,
submarineContainer.Rect.Height / (float)worldBorders.Height) * 0.9f;
float displayScale = ConvertUnits.ToDisplayUnits(scale);
Vector2 offset = ConvertUnits.ToSimUnits(sub.WorldPosition - new Vector2(worldBorders.Center.X, worldBorders.Y - worldBorders.Height / 2));
Vector2 center = container.Rect.Center.ToVector2();
for (int i = 0; i < sub.HullVertices.Count; i++)
{
Vector2 start = (sub.HullVertices[i] + offset) * displayScale;
start.Y = -start.Y;
Vector2 end = (sub.HullVertices[(i + 1) % sub.HullVertices.Count] + offset) * displayScale;
end.Y = -end.Y;
GUI.DrawLine(spriteBatch, center + start, center + end, Color.DarkCyan * Rand.Range(0.3f, 0.35f), width: 10);
}
}
}
}
@@ -1,20 +1,62 @@
using Barotrauma.Networking;
using Barotrauma.Particles;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Pump : Powered, IServerSerializable, IClientSerializable
{
private GUITickBox isActiveTickBox;
private GUIScrollBar isActiveSlider;
private GUIScrollBar pumpSpeedSlider;
private GUITickBox powerIndicator;
partial void InitProjSpecific()
private List<Pair<Vector2, ParticleEmitter>> pumpOutEmitters = new List<Pair<Vector2, ParticleEmitter>>();
private List<Pair<Vector2, ParticleEmitter>> pumpInEmitters = new List<Pair<Vector2, ParticleEmitter>>();
partial void InitProjSpecific(XElement element)
{
isActiveTickBox = new GUITickBox(new Rectangle(0, 0, 20, 20), TextManager.Get("PumpRunning"), Alignment.TopLeft, GuiFrame);
isActiveTickBox.OnSelected = (GUITickBox box) =>
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "pumpoutemitter":
pumpOutEmitters.Add(new Pair<Vector2, ParticleEmitter>(
subElement.GetAttributeVector2("position", Vector2.Zero),
new ParticleEmitter(subElement)));
break;
case "pumpinemitter":
pumpInEmitters.Add(new Pair<Vector2, ParticleEmitter>(
subElement.GetAttributeVector2("position", Vector2.Zero),
new ParticleEmitter(subElement)));
break;
}
}
if (GuiFrame == null) { return; }
GUIFrame paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.8f), GuiFrame.RectTransform, Anchor.Center), style: null);
isActiveSlider = new GUIScrollBar(new RectTransform(new Point(50, 100), paddedFrame.RectTransform, Anchor.CenterLeft),
barSize: 0.2f, style: "OnOffLever")
{
IsBooleanSwitch = true,
MinValue = 0.25f,
MaxValue = 0.75f
};
var sliderHandle = isActiveSlider.GetChild<GUIButton>();
sliderHandle.RectTransform.NonScaledSize = new Point(84, sliderHandle.Rect.Height);
isActiveSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
bool active = scrollBar.BarScroll < 0.5f;
if (active == IsActive) return false;
targetLevel = null;
IsActive = !IsActive;
IsActive = active;
if (!IsActive) currPowerConsumption = 0.0f;
if (GameMain.Server != null)
@@ -31,66 +73,102 @@ namespace Barotrauma.Items.Components
return true;
};
var button = new GUIButton(new Rectangle(160, 40, 35, 30), TextManager.Get("PumpOut"), "", GuiFrame);
button.OnClicked = (GUIButton btn, object obj) =>
var rightArea = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 1.0f), paddedFrame.RectTransform, Anchor.CenterRight)) { RelativeSpacing = 0.1f };
powerIndicator = new GUITickBox(new RectTransform(new Point(30, 30), rightArea.RectTransform), TextManager.Get("PumpPowered"), style: "IndicatorLightGreen")
{
FlowPercentage -= 10.0f;
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(Character.Controlled.LogName + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
}
else if (GameMain.Client != null)
{
correctionTimer = CorrectionDelay;
item.CreateClientEvent(this);
}
return true;
CanBeFocused = false
};
button = new GUIButton(new Rectangle(210, 40, 35, 30), TextManager.Get("PumpIn"), "", GuiFrame);
button.OnClicked = (GUIButton btn, object obj) =>
var pumpSpeedText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), rightArea.RectTransform) { RelativeOffset = new Vector2(0.25f, 0.0f) },
"", textAlignment: Alignment.BottomLeft);
string pumpSpeedStr = TextManager.Get("PumpSpeed");
pumpSpeedText.TextGetter = () => { return pumpSpeedStr + ": " + (int)flowPercentage + " %"; };
var sliderArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), rightArea.RectTransform, Anchor.CenterLeft), isHorizontal: true)
{
FlowPercentage += 10.0f;
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(Character.Controlled.LogName + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
}
else if (GameMain.Client != null)
{
correctionTimer = CorrectionDelay;
item.CreateClientEvent(this);
}
return true;
Stretch = true,
RelativeSpacing = 0.05f
};
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sliderArea.RectTransform),
TextManager.Get("PumpOut"), textAlignment: Alignment.Center);
pumpSpeedSlider = new GUIScrollBar(new RectTransform(new Vector2(0.8f, 1.0f), sliderArea.RectTransform), barSize: 0.25f, style: "GUISlider")
{
Step = 0.05f,
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
float newValue = barScroll * 200.0f - 100.0f;
if (Math.Abs(newValue - FlowPercentage) < 0.1f) return false;
FlowPercentage = newValue;
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(Character.Controlled.LogName + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
}
else if (GameMain.Client != null)
{
correctionTimer = CorrectionDelay;
item.CreateClientEvent(this);
}
return true;
}
};
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sliderArea.RectTransform),
TextManager.Get("PumpIn"), textAlignment: Alignment.Center);
}
public override void OnItemLoaded()
{
if (pumpSpeedSlider != null)
{
pumpSpeedSlider.BarScroll = (flowPercentage + 100.0f) / 200.0f;
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
partial void UpdateProjSpecific(float deltaTime)
{
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
GUI.Font.DrawString(spriteBatch, TextManager.Get("PumpSpeed") + ": " + (int)flowPercentage + " %", new Vector2(x + 40, y + 85), Color.White);
if (FlowPercentage < 0.0f)
{
foreach (Pair<Vector2, ParticleEmitter> pumpOutEmitter in pumpOutEmitters)
{
//only emit "pump out" particles when underwater
Vector2 particlePos = item.Rect.Location.ToVector2() + pumpOutEmitter.First;
if (item.CurrentHull != null && item.CurrentHull.Surface < particlePos.Y) continue;
pumpOutEmitter.Second.Emit(deltaTime, item.WorldRect.Location.ToVector2() + pumpOutEmitter.First * item.Scale, item.CurrentHull,
velocityMultiplier: MathHelper.Lerp(0.5f, 1.0f, -FlowPercentage / 100.0f));
}
}
else if (FlowPercentage > 0.0f)
{
foreach (Pair<Vector2, ParticleEmitter> pumpInEmitter in pumpInEmitters)
{
pumpInEmitter.Second.Emit(deltaTime, item.WorldRect.Location.ToVector2() + pumpInEmitter.First * item.Scale, item.CurrentHull,
velocityMultiplier: MathHelper.Lerp(0.5f, 1.0f, FlowPercentage / 100.0f));
}
}
}
public override void AddToGUIUpdateList()
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
GuiFrame.AddToGUIUpdateList();
}
powerIndicator.Selected = hasPower && IsActive;
public override void UpdateHUD(Character character)
{
GuiFrame.Update(1.0f / 60.0f);
}
if (!PlayerInput.LeftButtonHeld())
{
isActiveSlider.BarScroll += (IsActive ? -10.0f : 10.0f) * deltaTime;
float pumpSpeedScroll = (FlowPercentage + 100.0f) / 200.0f;
if (Math.Abs(pumpSpeedScroll - pumpSpeedSlider.BarScroll) > 0.01f)
{
pumpSpeedSlider.BarScroll = pumpSpeedScroll;
}
}
}
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
{
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
@@ -1,468 +0,0 @@
using Barotrauma.Networking;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using Voronoi2;
namespace Barotrauma.Items.Components
{
partial class Radar : Powered, IServerSerializable, IClientSerializable
{
private GUITickBox isActiveTickBox;
private List<RadarBlip> radarBlips;
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 override void AddToGUIUpdateList()
{
GuiFrame.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character)
{
GuiFrame.Update((float)Timing.Step);
for (int i = radarBlips.Count - 1; i >= 0; i--)
{
radarBlips[i].FadeTimer -= (float)Timing.Step * 0.5f;
if (radarBlips[i].FadeTimer <= 0.0f) radarBlips.RemoveAt(i);
}
if (IsActive)
{
float pingRadius = displayRadius * pingState;
Ping(item.WorldPosition, pingRadius, prevPingRadius, displayScale, range, 2.0f);
prevPingRadius = pingRadius;
return;
}
float passivePingRadius = (float)Math.Sin(Timing.TotalTime * 10);
if (passivePingRadius > 0.0f)
{
foreach (AITarget t in AITarget.List)
{
if (t.SoundRange <= 0.0f) continue;
if (Vector2.Distance(t.WorldPosition, item.WorldPosition) < t.SoundRange)
{
Ping(t.WorldPosition, t.SoundRange * passivePingRadius * 0.2f, t.SoundRange * prevPassivePingRadius * 0.2f, displayScale, t.SoundRange, 0.5f);
radarBlips.Add(new RadarBlip(t.WorldPosition, 1.0f, 1.0f));
}
}
}
prevPassivePingRadius = passivePingRadius;
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
GuiFrame.Draw(spriteBatch);
int radius = GuiFrame.Rect.Height / 2 - 10;
DrawRadar(spriteBatch, new Rectangle((int)GuiFrame.Center.X - radius, (int)GuiFrame.Center.Y - radius, radius * 2, radius * 2));
}
private void DrawRadar(SpriteBatch spriteBatch, Rectangle rect)
{
center = new Vector2(rect.X + rect.Width * 0.5f, rect.Center.Y);
displayRadius = (rect.Width / 2.0f) * (1.0f - displayBorderSize);
displayScale = displayRadius / range;
if (IsActive)
{
pingCircle.Draw(spriteBatch, center, Color.White * (1.0f - pingState), 0.0f, (displayRadius * 2 / pingCircle.size.X) * pingState);
}
if (item.Submarine != null && !DetectSubmarineWalls)
{
float simScale = displayScale * Physics.DisplayToSimRation;
foreach (Submarine submarine in Submarine.Loaded)
{
if (submarine != item.Submarine && !submarine.DockedTo.Contains(item.Submarine)) continue;
if (submarine.HullVertices == null) continue;
Vector2 offset = ConvertUnits.ToSimUnits(submarine.WorldPosition - item.WorldPosition);
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;
GUI.DrawLine(spriteBatch, center + start, center + end, Color.LightBlue);
}
}
}
if (radarBlips.Count > 0)
{
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
foreach (RadarBlip radarBlip in radarBlips)
{
DrawBlip(spriteBatch, radarBlip, center, radarBlip.FadeTimer / 2.0f);
}
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, GameMain.ScissorTestEnable);
}
if (GameMain.DebugDraw)
{
GUI.DrawString(spriteBatch, rect.Location.ToVector2(), radarBlips.Count.ToString(), Color.White);
}
if (screenOverlay != null)
{
screenOverlay.Draw(spriteBatch, center, 0.0f, rect.Width / screenOverlay.size.X);
}
if (GameMain.GameSession == null) return;
DrawMarker(spriteBatch,
GameMain.GameSession.StartLocation.Name,
(Level.Loaded.StartPosition - item.WorldPosition), displayScale, center, (rect.Width * 0.5f));
DrawMarker(spriteBatch,
GameMain.GameSession.EndLocation.Name,
(Level.Loaded.EndPosition - item.WorldPosition), displayScale, center, (rect.Width * 0.5f));
if (GameMain.GameSession.Mission != null)
{
var mission = GameMain.GameSession.Mission;
if (!string.IsNullOrWhiteSpace(mission.RadarLabel) && mission.RadarPosition != Vector2.Zero)
{
DrawMarker(spriteBatch,
mission.RadarLabel,
mission.RadarPosition - item.WorldPosition, displayScale, center, (rect.Width * 0.55f));
}
}
foreach (Submarine sub in Submarine.Loaded)
{
if (!sub.OnRadar) continue;
if (item.Submarine == sub || sub.DockedTo.Contains(item.Submarine)) continue;
if (sub.WorldPosition.Y > Level.Loaded.Size.Y) continue;
DrawMarker(spriteBatch, sub.Name, sub.WorldPosition - item.WorldPosition, displayScale, center, (rect.Width * 0.45f));
}
if (!GameMain.DebugDraw) return;
var steering = item.GetComponent<Steering>();
if (steering == null || steering.SteeringPath == null) return;
Vector2 prevPos = Vector2.Zero;
foreach (WayPoint wp in steering.SteeringPath.Nodes)
{
Vector2 pos = (wp.Position - item.WorldPosition) * 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), (steering.SteeringPath.CurrentNode == wp) ? Color.LightGreen : Color.Green, false);
if (prevPos != Vector2.Zero)
{
GUI.DrawLine(spriteBatch, pos, prevPos, Color.Green);
}
prevPos = pos;
}
}
private void Ping(Vector2 pingSource, float pingRadius, float prevPingRadius, float displayScale, float range, float pingStrength = 1.0f)
{
//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),
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f);
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),
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f);
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),
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f);
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),
pingRadius, prevPingRadius, 50.0f, 5.0f, range, 2.0f);
return;
}
foreach (Submarine submarine in Submarine.Loaded)
{
if (item.Submarine == submarine && !DetectSubmarineWalls) continue;
if (item.Submarine != null && item.Submarine.DockedTo.Contains(submarine)) continue;
if (submarine.HullVertices == null) 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,
pingRadius, prevPingRadius,
200.0f, 2.0f, range, 1.0f);
}
}
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),
pingRadius, prevPingRadius,
250.0f, 150.0f, range, pingStrength);
}
List<VoronoiCell> cells = Level.Loaded.GetCells(pingSource, 7);
foreach (VoronoiCell cell in cells)
{
foreach (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,
pingRadius, prevPingRadius,
350.0f, 3.0f * (Math.Abs(facingDot) + 1.0f), range, pingStrength);
}
}
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,
pingRadius, prevPingRadius,
100.0f, 1000.0f, range, pingStrength);
}
}
}
}
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).Length() * displayScale;
if (limb.SimPosition == Vector2.Zero || pointDist > displayRadius) continue;
if (pointDist > prevPingRadius && pointDist < pingRadius)
{
var blip = new RadarBlip(
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));
radarBlips.Add(blip);
}
}
}
}
private void CreateBlipsForLine(Vector2 point1, Vector2 point2, float pingRadius, float prevPingRadius,
float lineStep, float zStep, float range, float pingStrength)
{
float length = (point1 - point2).Length();
Vector2 lineDir = (point2 - point1) / length;
range *= displayScale;
for (float x = 0; x < length; x += lineStep * Rand.Range(0.8f, 1.2f))
{
Vector2 point = point1 + lineDir * x;
//point += cell.Translation;
float pointDist = Vector2.Distance(item.WorldPosition, point) * displayScale;
if (pointDist > displayRadius) continue;
if (pointDist < prevPingRadius || pointDist > pingRadius) continue;
float alpha = pingStrength * Rand.Range(1.5f, 2.0f);
for (float z = 0; z < displayRadius - pointDist * displayScale; z += zStep)
{
Vector2 pos = point + Rand.Vector(150.0f) + Vector2.Normalize(point - item.WorldPosition) * z / displayScale;
float fadeTimer = alpha * (1.0f - pointDist / range);
int minDist = 200;
radarBlips.RemoveAll(b => b.FadeTimer < fadeTimer && Math.Abs(pos.X - b.Position.X) < minDist && Math.Abs(pos.Y - b.Position.Y) < minDist);
var blip = new RadarBlip(pos, fadeTimer, 1.0f + ((pointDist+z) / displayRadius));
radarBlips.Add(blip);
zStep += 0.5f;
if (z == 0)
{
alpha = Math.Min(alpha - 0.5f, 1.5f);
}
else
{
alpha -= 0.1f;
}
if (alpha < 0) break;
}
}
}
private void DrawBlip(SpriteBatch spriteBatch, RadarBlip blip, Vector2 center, float strength)
{
strength = MathHelper.Clamp(strength, 0.0f, 1.0f);
float scaledT = strength * (blipColorGradient.Length - 1);
Color color = Color.Lerp(blipColorGradient[(int)scaledT], blipColorGradient[(int)Math.Min(scaledT + 1, blipColorGradient.Length - 1)], (scaledT - (int)scaledT));
Vector2 pos = (blip.Position - item.WorldPosition) * displayScale;
pos.Y = -pos.Y;
float posDist = pos.Length();
if (posDist > displayRadius)
{
blip.FadeTimer = 0.0f;
return;
}
if (radarBlip == null)
{
GUI.DrawRectangle(spriteBatch, center + pos, Vector2.One * 4, Color.Magenta, true);
return;
}
Vector2 dir = pos / posDist;
Vector2 normal = new Vector2(dir.Y, -dir.X);
float scale = (strength + 3.0f) * blip.Scale;
radarBlip.Draw(spriteBatch, center + pos, color, radarBlip.Origin, MathUtils.VectorToAngle(pos),
new Vector2(scale * 0.5f, scale) * 0.04f, SpriteEffects.None, 0);
pos += Rand.Range(0.0f, 1.0f) * dir + Rand.Range(-scale, scale) * normal;
radarBlip.Draw(spriteBatch, center + pos, color * 0.5f, radarBlip.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 *= 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 * scale > radius) ? dir * radius : position;
markerPos += center;
markerPos.X = (int)markerPos.X;
markerPos.Y = (int)markerPos.Y;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)markerPos.X, (int)markerPos.Y, 5, 5), Color.LightBlue);
if (dir.X < 0.0f) markerPos.X -= GUI.SmallFont.MeasureString(label).X + 10;
string wrappedLabel = ToolBox.WrapText(label, 150, GUI.SmallFont);
wrappedLabel += "\n" + ((int)(dist * Physics.DisplayToRealWorldRatio) + " m");
GUI.DrawString(spriteBatch,
new Vector2(markerPos.X + 10, markerPos.Y),
wrappedLabel,
Color.LightBlue * textAlpha, Color.Black * textAlpha * 0.5f,
2, GUI.SmallFont);
}
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
{
msg.Write(IsActive);
}
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
{
if (correctionTimer > 0.0f)
{
StartDelayedCorrection(type, msg.ExtractBits(1), sendingTime);
return;
}
IsActive = msg.ReadBoolean();
isActiveTickBox.Selected = IsActive;
}
}
class RadarBlip
{
public float FadeTimer;
public Vector2 Position;
public float Scale;
public RadarBlip(Vector2 pos, float fadeTimer, float scale)
{
Position = pos;
FadeTimer = Math.Max(fadeTimer, 0.0f);
Scale = scale;
}
}
}
@@ -4,200 +4,458 @@ 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 Reactor : Powered, IDrawableComponent, IServerSerializable, IClientSerializable
partial class Reactor : Powered, IServerSerializable, IClientSerializable
{
private GUITickBox autoTempTickBox;
private GUIScrollBar autoTempSlider;
private GUIScrollBar onOffSwitch;
private const int GraphSize = 25;
private float graphTimer;
private int updateGraphInterval = 500;
private Sprite fissionRateMeter, turbineOutputMeter;
private Sprite meterPointer;
private Sprite sectorSprite;
private float[] fissionRateGraph = new float[GraphSize];
private float[] coolingRateGraph = new float[GraphSize];
private float[] tempGraph = new float[GraphSize];
private Sprite tempMeterFrame, tempMeterBar;
private Sprite tempRangeIndicator;
private Sprite graphLine;
private GUIScrollBar fissionRateScrollBar;
private GUIScrollBar turbineOutputScrollBar;
private float[] outputGraph = new float[GraphSize];
private float[] loadGraph = new float[GraphSize];
private GUITickBox criticalHeatWarning;
private GUITickBox lowTemperatureWarning;
private GUITickBox criticalOutputWarning;
partial void InitProjSpecific()
private GUIFrame inventoryContainer;
private GUIComponent leftHUDColumn;
private Dictionary<string, GUIButton> warningButtons = new Dictionary<string, GUIButton>();
private static string[] warningTexts = new string[]
{
var button = new GUIButton(new Rectangle(410, 70, 40, 40), "-", "", GuiFrame);
button.OnPressed = () =>
{
lastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
ShutDownTemp -= 100.0f;
"ReactorWarningLowTemp","ReactorWarningOverheating",
"ReactorWarningLowOutput", "ReactorWarningHighOutput",
"ReactorWarningLowFuel", "ReactorWarningFuelOut",
"ReactorWarningMeltdown","ReactorWarningSCRAM"
};
return false;
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "fissionratemeter":
fissionRateMeter = new Sprite(subElement);
break;
case "turbineoutputmeter":
turbineOutputMeter = new Sprite(subElement);
break;
case "meterpointer":
meterPointer = new Sprite(subElement);
break;
case "sectorsprite":
sectorSprite = new Sprite(subElement);
break;
case "tempmeterframe":
tempMeterFrame = new Sprite(subElement);
break;
case "tempmeterbar":
tempMeterBar = new Sprite(subElement);
break;
case "temprangeindicator":
tempRangeIndicator = new Sprite(subElement);
break;
case "graphline":
graphLine = new Sprite(subElement);
break;
}
}
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.85f), GuiFrame.RectTransform, Anchor.Center), isHorizontal: true)
{
RelativeSpacing = 0.015f,
Stretch = true
};
GUIFrame columnLeft = new GUIFrame(new RectTransform(new Vector2(0.2f, 1.0f), paddedFrame.RectTransform), style: null);
leftHUDColumn = columnLeft;
GUIFrame columnMid = new GUIFrame(new RectTransform(new Vector2(0.45f, 1.0f), paddedFrame.RectTransform), style: null);
GUIFrame columnRight = new GUIFrame(new RectTransform(new Vector2(0.35f, 1.0f), paddedFrame.RectTransform), style: null);
//----------------------------------------------------------
//left column
//----------------------------------------------------------
int buttonsPerRow = 2;
int spacing = 5;
int buttonWidth = columnLeft.Rect.Width / buttonsPerRow - (spacing * (buttonsPerRow - 1));
int buttonHeight = (int)(columnLeft.Rect.Height * 0.5f) / 4;
for (int i = 0; i < warningTexts.Length; i++)
{
var warningBtn = new GUIButton(new RectTransform(new Point(buttonWidth, buttonHeight), columnLeft.RectTransform)
{ AbsoluteOffset = new Point((i % buttonsPerRow) * (buttonWidth + spacing), (int)Math.Floor(i / (float)buttonsPerRow) * (buttonHeight + spacing)) },
TextManager.Get(warningTexts[i]), style: "IndicatorButton");
var btnText = warningBtn.GetChild<GUITextBlock>();
btnText.Font = GUI.SmallFont;
btnText.Wrap = true;
btnText.SetTextPos();
warningButtons.Add(warningTexts[i], warningBtn);
}
inventoryContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.45f), columnLeft.RectTransform, Anchor.BottomLeft), style: null);
//----------------------------------------------------------
//mid column
//----------------------------------------------------------
criticalHeatWarning = new GUITickBox(new RectTransform(new Point(30, 30), columnMid.RectTransform),
TextManager.Get("ReactorWarningCriticalTemp"), font: GUI.SmallFont, style: "IndicatorLightRed")
{
CanBeFocused = false
};
lowTemperatureWarning = new GUITickBox(new RectTransform(new Point(30, 30), columnMid.RectTransform) { RelativeOffset = new Vector2(0.3f, 0.0f) },
TextManager.Get("ReactorWarningCriticalLowTemp"), font: GUI.SmallFont, style: "IndicatorLightRed")
{
CanBeFocused = false
};
criticalOutputWarning = new GUITickBox(new RectTransform(new Point(30, 30), columnMid.RectTransform) { RelativeOffset = new Vector2(0.75f, 0.0f) },
TextManager.Get("ReactorWarningCriticalOutput"), font: GUI.SmallFont, style: "IndicatorLightRed")
{
CanBeFocused = false
};
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.05f), columnMid.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.25f) },
TextManager.Get("ReactorFissionRate"));
new GUICustomComponent(new RectTransform(new Vector2(0.5f, 0.5f), columnMid.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.3f) },
DrawFissionRateMeter, null)
{
ToolTip = TextManager.Get("ReactorTipFissionRate")
};
button = new GUIButton(new Rectangle(460, 70, 40, 40), "+", "", GuiFrame);
button.OnPressed = () =>
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.05f), columnMid.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(0.0f, 0.25f) },
TextManager.Get("ReactorTurbineOutput"));
new GUICustomComponent(new RectTransform(new Vector2(0.5f, 0.5f), columnMid.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(0.0f, 0.3f) },
DrawTurbineOutputMeter, null)
{
lastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
ShutDownTemp += 100.0f;
return false;
ToolTip = TextManager.Get("ReactorTipTurbineOutput")
};
autoTempTickBox = new GUITickBox(new Rectangle(410, 170, 20, 20), TextManager.Get("ReactorAutoTemp"), Alignment.TopLeft, GuiFrame);
autoTempTickBox.OnSelected = ToggleAutoTemp;
button = new GUIButton(new Rectangle(210, 290, 40, 40), "+", "", GuiFrame);
button.OnPressed = () =>
new GUITextBlock(new RectTransform(new Point(0, 20), columnMid.RectTransform, Anchor.BottomLeft) { AbsoluteOffset = new Point(0, 90) },
TextManager.Get("ReactorFissionRate"));
fissionRateScrollBar = new GUIScrollBar(new RectTransform(new Point(columnMid.Rect.Width, 30), columnMid.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, 60) },
style: "GUISlider", barSize: 0.1f)
{
lastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
OnMoved = (GUIScrollBar bar, float scrollAmount) =>
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
FissionRate += 1.0f;
LastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
targetFissionRate = scrollAmount * 100.0f;
return false;
return false;
}
};
button = new GUIButton(new Rectangle(210, 340, 40, 40), "-", "", GuiFrame);
button.OnPressed = () =>
new GUITextBlock(new RectTransform(new Point(0, 20), columnMid.RectTransform, Anchor.BottomLeft) { AbsoluteOffset = new Point(0, 30) },
TextManager.Get("ReactorTurbineOutput"));
turbineOutputScrollBar = new GUIScrollBar(new RectTransform(new Point(columnMid.Rect.Width, 30), columnMid.RectTransform, Anchor.BottomCenter),
style: "GUISlider", barSize: 0.1f, isHorizontal: true)
{
lastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
OnMoved = (GUIScrollBar bar, float scrollAmount) =>
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
FissionRate -= 1.0f;
LastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
targetTurbineOutput = scrollAmount * 100.0f;
return false;
return false;
}
};
button = new GUIButton(new Rectangle(500, 290, 40, 40), "+", "", GuiFrame);
button.OnPressed = () =>
//----------------------------------------------------------
//right column
//----------------------------------------------------------
new GUITextBlock(new RectTransform(new Point(100, 20), columnRight.RectTransform), TextManager.Get("ReactorAutoTemp"))
{
lastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
CoolingRate += 1.0f;
return false;
ToolTip = TextManager.Get("ReactorTipAutoTemp")
};
button = new GUIButton(new Rectangle(500, 340, 40, 40), "-", "", GuiFrame);
button.OnPressed = () =>
autoTempSlider = new GUIScrollBar(new RectTransform(new Point(100, 30), columnRight.RectTransform) { AbsoluteOffset = new Point(0, 30) },
barSize: 0.5f, style: "OnOffSlider")
{
lastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
ToolTip = TextManager.Get("ReactorTipAutoTemp"),
IsBooleanSwitch = true,
BarScroll = 1.0f,
OnMoved = (scrollBar, scrollAmount) =>
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
LastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
return true;
}
unsentChanges = true;
CoolingRate -= 1.0f;
return false;
};
onOffSwitch = new GUIScrollBar(new RectTransform(new Point(50, 80), columnRight.RectTransform, Anchor.TopRight),
barSize: 0.2f, style: "OnOffLever")
{
IsBooleanSwitch = true,
MinValue = 0.25f,
MaxValue = 0.75f,
OnMoved = (scrollBar, scrollAmount) =>
{
LastUser = Character.Controlled;
if (nextServerLogWriteTime == null)
{
nextServerLogWriteTime = Math.Max(lastServerLogWriteTime + 1.0f, (float)Timing.TotalTime);
}
unsentChanges = true;
return true;
}
};
var lever = onOffSwitch.GetChild<GUIButton>();
lever.RectTransform.NonScaledSize = new Point(lever.Rect.Width + 30, lever.Rect.Height);
var graphArea = new GUICustomComponent(new RectTransform(new Vector2(1.0f, 0.5f), columnRight.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, 30) },
DrawGraph, null);
var loadText = new GUITextBlock(new RectTransform(new Point(100, 30), graphArea.RectTransform, Anchor.TopLeft, Pivot.BottomLeft),
"Load", textColor: Color.LightBlue, textAlignment: Alignment.CenterLeft)
{
ToolTip = TextManager.Get("ReactorTipLoad")
};
string loadStr = TextManager.Get("ReactorLoad");
loadText.TextGetter += () => { return loadStr.Replace("[kw]", ((int)load).ToString()); };
var outputText = new GUITextBlock(new RectTransform(new Point(100, 30), graphArea.RectTransform, Anchor.BottomLeft, Pivot.TopLeft),
"Output", textColor: Color.LightGreen, textAlignment: Alignment.CenterLeft)
{
ToolTip = TextManager.Get("ReactorTipPower")
};
string outputStr = TextManager.Get("ReactorOutput");
outputText.TextGetter += () => { return outputStr.Replace("[kw]", ((int)-currPowerConsumption).ToString()); };
}
public override void OnItemLoaded()
{
turbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
fissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
var itemContainer = item.GetComponent<ItemContainer>();
if (itemContainer != null)
{
itemContainer.AllowUIOverlap = true;
itemContainer.Inventory.RectTransform = inventoryContainer.RectTransform;
}
}
private void DrawGraph(SpriteBatch spriteBatch, GUICustomComponent container)
{
Rectangle graphArea = new Rectangle(container.Rect.X + 30, container.Rect.Y, container.Rect.Width - 30, container.Rect.Height);
float maxLoad = loadGraph.Max();
float xOffset = graphTimer / updateGraphInterval;
DrawGraph(outputGraph, spriteBatch,
graphArea, Math.Max(10000.0f, maxLoad), xOffset, Color.LightGreen);
DrawGraph(loadGraph, spriteBatch,
graphArea, Math.Max(10000.0f, maxLoad), xOffset, Color.LightBlue);
tempMeterFrame.Draw(spriteBatch, new Vector2(graphArea.X - 30, graphArea.Y), Color.White, Vector2.Zero, 0.0f, new Vector2(1.0f, graphArea.Height / tempMeterFrame.size.Y));
float tempFill = temperature / 100.0f;
int barPadding = 5;
Vector2 meterBarPos = new Vector2(graphArea.X - 30 + tempMeterFrame.size.X / 2, graphArea.Bottom - tempMeterBar.size.Y);
while (meterBarPos.Y > graphArea.Bottom - graphArea.Height * tempFill)
{
float tempRatio = 1.0f - ((meterBarPos.Y - graphArea.Y) / graphArea.Height);
Color color = tempRatio < 0.5f ?
Color.Lerp(Color.Green, Color.Orange, tempRatio * 2.0f) :
Color.Lerp(Color.Orange, Color.Red, (tempRatio - 0.5f) * 2.0f);
tempMeterBar.Draw(spriteBatch, meterBarPos, color);
meterBarPos.Y -= (tempMeterBar.size.Y + barPadding);
}
if (temperature > optimalTemperature.Y)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(graphArea.X - 30, graphArea.Y),
new Vector2(tempMeterFrame.SourceRect.Width, (graphArea.Bottom - graphArea.Height * optimalTemperature.Y / 100.0f) - graphArea.Y),
Color.Red * (float)Math.Sin(Timing.TotalTime * 5.0f) * 0.7f, isFilled: true);
}
if (temperature < optimalTemperature.X)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(graphArea.X - 30, graphArea.Bottom - graphArea.Height * optimalTemperature.X / 100.0f),
new Vector2(tempMeterFrame.SourceRect.Width, graphArea.Bottom - (graphArea.Bottom - graphArea.Height * optimalTemperature.X / 100.0f)),
Color.Red * (float)Math.Sin(Timing.TotalTime * 5.0f) * 0.7f, isFilled: true);
}
tempRangeIndicator.Draw(spriteBatch, new Vector2(meterBarPos.X, graphArea.Bottom - graphArea.Height * optimalTemperature.X / 100.0f));
tempRangeIndicator.Draw(spriteBatch, new Vector2(meterBarPos.X, graphArea.Bottom - graphArea.Height * optimalTemperature.Y / 100.0f));
}
private void UpdateGraph(float deltaTime)
{
graphTimer += deltaTime * 1000.0f;
if (graphTimer > updateGraphInterval)
{
UpdateGraph(fissionRateGraph, fissionRate);
UpdateGraph(coolingRateGraph, coolingRate);
UpdateGraph(tempGraph, temperature);
UpdateGraph(outputGraph, -currPowerConsumption);
UpdateGraph(loadGraph, load);
graphTimer = 0.0f;
}
if (autoTemp)
{
fissionRateScrollBar.BarScroll = FissionRate / 100.0f;
turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
}
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
private void DrawFissionRateMeter(SpriteBatch spriteBatch, GUICustomComponent container)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(item.Rect.X + item.Rect.Width / 2 - 6, -item.Rect.Y + 29),
new Vector2(12, 42), Color.Black);
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = container.Rect;
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
if (temperature > 0)
GUI.DrawRectangle(spriteBatch,
new Vector2(item.Rect.X + item.Rect.Width / 2 - 5, -item.Rect.Y + 30 + (40.0f * (1.0f - temperature / 10000.0f))),
new Vector2(10, 40 * (temperature / 10000.0f)), new Color(temperature / 10000.0f, 1.0f - (temperature / 10000.0f), 0.0f, 1.0f), true);
DrawMeter(spriteBatch, container.Rect,
fissionRateMeter, FissionRate, new Vector2(0.0f, 100.0f), optimalFissionRate, allowedFissionRate);
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
spriteBatch.Begin(SpriteSortMode.Deferred);
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
private void DrawTurbineOutputMeter(SpriteBatch spriteBatch, GUICustomComponent container)
{
DrawMeter(spriteBatch, container.Rect,
turbineOutputMeter, TurbineOutput, new Vector2(0.0f, 100.0f), optimalTurbineOutput, allowedTurbineOutput);
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
IsActive = true;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
float xOffset = graphTimer / updateGraphInterval;
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorOutput") + ": " + (int)temperature + " kW",
new Vector2(x + 450, y + 30), Color.Red);
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorGridLoad") + ": " + (int)load + " kW",
new Vector2(x + 600, y + 30), Color.Yellow);
bool lightOn = Timing.TotalTime % 0.5f < 0.25f && onOffSwitch.BarScroll < 0.5f;
float maxLoad = 0.0f;
foreach (float loadVal in loadGraph)
fissionRateScrollBar.Enabled = !autoTemp;
turbineOutputScrollBar.Enabled = !autoTemp;
criticalHeatWarning.Selected = temperature > allowedTemperature.Y && lightOn;
lowTemperatureWarning.Selected = temperature < allowedTemperature.X && lightOn;
criticalOutputWarning.Selected = -currPowerConsumption > load * 1.5f && lightOn;
warningButtons["ReactorWarningOverheating"].Selected = temperature > optimalTemperature.Y && lightOn;
warningButtons["ReactorWarningHighOutput"].Selected = -currPowerConsumption > load * 1.1f && lightOn;
warningButtons["ReactorWarningLowTemp"].Selected = temperature < optimalTemperature.X && lightOn;
warningButtons["ReactorWarningLowOutput"].Selected = -currPowerConsumption < load * 0.9f && lightOn;
warningButtons["ReactorWarningFuelOut"].Selected = prevAvailableFuel < fissionRate * 0.01f && lightOn;
warningButtons["ReactorWarningLowFuel"].Selected = prevAvailableFuel < fissionRate && lightOn;
warningButtons["ReactorWarningMeltdown"].Selected = meltDownTimer > MeltdownDelay * 0.5f || item.Condition == 0.0f && lightOn;
warningButtons["ReactorWarningSCRAM"].Selected = temperature > 0.1f && onOffSwitch.BarScroll > 0.5f;
AutoTemp = autoTempSlider.BarScroll < 0.5f;
shutDown = onOffSwitch.BarScroll > 0.5f;
if (shutDown)
{
maxLoad = Math.Max(maxLoad, loadVal);
}
DrawGraph(tempGraph, spriteBatch,
new Rectangle(x + 30, y + 30, 400, 250), Math.Max(10000.0f, maxLoad), xOffset, Color.Red);
DrawGraph(loadGraph, spriteBatch,
new Rectangle(x + 30, y + 30, 400, 250), Math.Max(10000.0f, maxLoad), xOffset, Color.Yellow);
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorShutdownTemp") + ": " + (int)shutDownTemp, new Vector2(x + 450, y + 80), Color.White);
y += 300;
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorFissionRate") + ": " + (int)fissionRate + " %", new Vector2(x + 30, y), Color.White);
DrawGraph(fissionRateGraph, spriteBatch,
new Rectangle(x + 30, y + 30, 200, 100), 100.0f, xOffset, Color.Orange);
GUI.Font.DrawString(spriteBatch, TextManager.Get("ReactorCoolingRate") + ": " + (int)coolingRate + " %", new Vector2(x + 320, y), Color.White);
DrawGraph(coolingRateGraph, spriteBatch,
new Rectangle(x + 320, y + 30, 200, 100), 100.0f, xOffset, Color.LightBlue);
}
public override void AddToGUIUpdateList()
{
GuiFrame.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character)
{
GuiFrame.Update(1.0f / 60.0f);
fissionRateScrollBar.BarScroll = FissionRate / 100.0f;
turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
}
}
private bool ToggleAutoTemp(GUITickBox tickBox)
{
unsentChanges = true;
autoTemp = tickBox.Selected;
LastUser = Character.Controlled;
return true;
}
private void DrawMeter(SpriteBatch spriteBatch, Rectangle rect, Sprite meterSprite, float value, Vector2 range, Vector2 optimalRange, Vector2 allowedRange)
{
float scale = Math.Min(rect.Width / meterSprite.size.X, rect.Height / meterSprite.size.Y);
Vector2 pos = new Vector2(rect.Center.X, rect.Y + meterSprite.Origin.Y * scale);
Vector2 optimalRangeNormalized = new Vector2(
(optimalRange.X - range.X) / (range.Y - range.X),
(optimalRange.Y - range.X) / (range.Y - range.X));
Vector2 allowedRangeNormalized = new Vector2(
(allowedRange.X - range.X) / (range.Y - range.X),
(allowedRange.Y - range.X) / (range.Y - range.X));
Vector2 sectorRad = new Vector2(-1.57f, 1.57f);
Vector2 optimalSectorRad = new Vector2(
MathHelper.Lerp(sectorRad.X, sectorRad.Y, optimalRangeNormalized.X),
MathHelper.Lerp(sectorRad.X, sectorRad.Y, optimalRangeNormalized.Y));
Vector2 allowedSectorRad = new Vector2(
MathHelper.Lerp(sectorRad.X, sectorRad.Y, allowedRangeNormalized.X),
MathHelper.Lerp(sectorRad.X, sectorRad.Y, allowedRangeNormalized.Y));
if (optimalRangeNormalized.X == optimalRangeNormalized.Y)
{
sectorSprite.Draw(spriteBatch, pos, Color.Red, MathHelper.PiOver2, scale);
}
else
{
spriteBatch.End();
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0,0,GameMain.GraphicsWidth, (int)(pos.Y + (meterSprite.size.Y - meterSprite.Origin.Y) * scale));
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
sectorSprite.Draw(spriteBatch, pos, Color.LightGreen, MathHelper.PiOver2, scale);
sectorSprite.Draw(spriteBatch, pos, Color.Orange, optimalSectorRad.X, scale);
sectorSprite.Draw(spriteBatch, pos, Color.Red, allowedSectorRad.X, scale);
sectorSprite.Draw(spriteBatch, pos, Color.Orange, MathHelper.Pi + optimalSectorRad.Y, scale);
sectorSprite.Draw(spriteBatch, pos, Color.Red, MathHelper.Pi + allowedSectorRad.Y, scale);
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
spriteBatch.Begin(SpriteSortMode.Deferred);
}
meterSprite.Draw(spriteBatch, pos, 0, scale);
float normalizedValue = (value - range.X) / (range.Y - range.X);
float valueRad = MathHelper.Lerp(sectorRad.X, sectorRad.Y, normalizedValue);
meterPointer.Draw(spriteBatch, pos, valueRad, scale);
}
static void UpdateGraph<T>(IList<T> graph, T newValue)
{
for (int i = graph.Count - 1; i > 0; i--)
@@ -207,8 +465,13 @@ namespace Barotrauma.Items.Components
graph[0] = newValue;
}
static void DrawGraph(IList<float> graph, SpriteBatch spriteBatch, Rectangle rect, float maxVal, float xOffset, Color color)
private void DrawGraph(IList<float> graph, SpriteBatch spriteBatch, Rectangle rect, float maxVal, float xOffset, Color color)
{
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = rect;
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
float lineWidth = (float)rect.Width / (float)(graph.Count - 2);
float yScale = (float)rect.Height / maxVal;
@@ -223,8 +486,16 @@ namespace Barotrauma.Items.Components
currX -= lineWidth;
Vector2 newPoint = new Vector2(currX, rect.Bottom - graph[i] * yScale);
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color);
if (graphLine == null)
{
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color);
}
else
{
Vector2 dir = Vector2.Normalize(newPoint - prevPoint);
GUI.DrawLine(spriteBatch, graphLine.Texture, prevPoint - dir, newPoint + dir, color, 0, 5);
}
prevPoint = newPoint;
}
@@ -232,16 +503,38 @@ namespace Barotrauma.Items.Components
Vector2 lastPoint = new Vector2(rect.X,
rect.Bottom - (graph[graph.Count - 1] + (graph[graph.Count - 2] - graph[graph.Count - 1]) * xOffset) * yScale);
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color);
if (graphLine == null)
{
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color);
}
else
{
GUI.DrawLine(spriteBatch, graphLine.Texture, prevPoint, lastPoint + (lastPoint - prevPoint), color, 0, 5);
}
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
spriteBatch.Begin(SpriteSortMode.Deferred);
}
protected override void RemoveComponentSpecific()
{
graphLine.Remove();
fissionRateMeter.Remove();
turbineOutputMeter.Remove();
meterPointer.Remove();
sectorSprite.Remove();
tempMeterFrame.Remove();
tempMeterBar.Remove();
tempRangeIndicator.Remove();
}
public void ClientWrite(NetBuffer msg, object[] extraData = null)
{
msg.Write(autoTemp);
msg.WriteRangedSingle(shutDownTemp, 0.0f, 10000.0f, 15);
msg.WriteRangedSingle(coolingRate, 0.0f, 100.0f, 8);
msg.WriteRangedSingle(fissionRate, 0.0f, 100.0f, 8);
msg.Write(shutDown);
msg.WriteRangedSingle(targetFissionRate, 0.0f, 100.0f, 8);
msg.WriteRangedSingle(targetTurbineOutput, 0.0f, 100.0f, 8);
correctionTimer = CorrectionDelay;
}
@@ -250,17 +543,20 @@ namespace Barotrauma.Items.Components
{
if (correctionTimer > 0.0f)
{
StartDelayedCorrection(type, msg.ExtractBits(16 + 1 + 15 + 8 + 8), sendingTime);
StartDelayedCorrection(type, msg.ExtractBits(1 + 1 + 8 + 8 + 8 + 8), sendingTime);
return;
}
Temperature = msg.ReadRangedSingle(0.0f, 10000.0f, 16);
AutoTemp = msg.ReadBoolean();
ShutDownTemp = msg.ReadRangedSingle(0.0f, 10000.0f, 15);
shutDown = msg.ReadBoolean();
Temperature = msg.ReadRangedSingle(0.0f, 100.0f, 8);
targetFissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
targetTurbineOutput = msg.ReadRangedSingle(0.0f, 100.0f, 8);
degreeOfSuccess = msg.ReadRangedSingle(0.0f, 1.0f, 8);
CoolingRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
FissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
fissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
turbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
onOffSwitch.BarScroll = shutDown ? Math.Max(onOffSwitch.BarScroll, 0.55f) : Math.Min(onOffSwitch.BarScroll, 0.45f);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,176 +1,565 @@
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
{
private GUITickBox autopilotTickBox, maintainPosTickBox;
private GUITickBox levelEndTickBox, levelStartTickBox;
private GUITickBox autopilotTickBox, manualTickBox;
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()
{
autopilotTickBox = new GUITickBox(new Rectangle(0, 25, 20, 20), TextManager.Get("SteeringAutoPilot"), Alignment.TopLeft, GuiFrame);
autopilotTickBox.OnSelected = (GUITickBox box) =>
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))
{
AutoPilot = box.Selected;
unsentChanges = true;
return true;
RelativeSpacing = 0.03f,
Stretch = true
};
maintainPosTickBox = new GUITickBox(new Rectangle(5, 50, 15, 15), TextManager.Get("SteeringMaintainPos"), Alignment.TopLeft, GUI.SmallFont, GuiFrame);
maintainPosTickBox.Enabled = false;
maintainPosTickBox.OnSelected = ToggleMaintainPosition;
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
};
levelStartTickBox = new GUITickBox(
new Rectangle(5, 70, 15, 15),
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;
}
};
GUITickBox.CreateRadioButtonGroup(new List<GUITickBox> { manualTickBox, autopilotTickBox });
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),
Alignment.TopLeft, GUI.SmallFont, GuiFrame);
levelStartTickBox.Enabled = false;
levelStartTickBox.OnSelected = SelectDestination;
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 Rectangle(5, 90, 15, 15),
levelEndTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), paddedAutoPilotControls.RectTransform),
GameMain.GameSession?.EndLocation == null ? "" : ToolBox.LimitString(GameMain.GameSession.EndLocation.Name, 20),
Alignment.TopLeft, GUI.SmallFont, GuiFrame);
levelEndTickBox.Enabled = false;
levelEndTickBox.OnSelected = SelectDestination;
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");
GUITickBox.CreateRadioButtonGroup(new List<GUITickBox> { maintainPosTickBox, levelStartTickBox, levelEndTickBox });
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);
}
private bool ToggleMaintainPosition(GUITickBox tickBox)
/// <summary>
/// Makes the sonar view CustomComponent render the steering HUD, preventing it from being drawn behing the sonar
/// </summary>
public void AttachToSonarHUD(GUICustomComponent sonarView)
{
unsentChanges = true;
levelStartTickBox.Selected = false;
levelEndTickBox.Selected = false;
if (item.Submarine == null)
{
posToMaintain = null;
}
else
{
posToMaintain = item.Submarine.WorldPosition;
}
tickBox.Selected = true;
return true;
steerArea.Visible = false;
sonarView.OnDraw += (spriteBatch, guiCustomComponent) => { DrawHUD(spriteBatch, guiCustomComponent.Rect); };
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
public void DrawHUD(SpriteBatch spriteBatch, Rectangle rect)
{
//if (voltage < minVoltage) return;
int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
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.DrawRectangle(spriteBatch, velRect, Color.White, false);
if (item.Submarine != null && Level.Loaded != null)
{
Vector2 realWorldVelocity = ConvertUnits.ToDisplayUnits(item.Submarine.Velocity * Physics.DisplayToRealWorldRatio) * 3.6f;
float realWorldDepth = Math.Abs(item.Submarine.Position.Y - Level.Loaded.Size.Y) * Physics.DisplayToRealWorldRatio;
GUI.DrawString(spriteBatch, new Vector2(x + 20, y + height - 65),
TextManager.Get("SteeringVelocityX").Replace("[kph]", ((int)realWorldVelocity.X).ToString()), Color.LightGreen, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x + 20, y + height - 50),
TextManager.Get("SteeringVelocityY").Replace("[kph]", ((int)-realWorldVelocity.Y).ToString()), Color.LightGreen, null, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(x + 20, y + height - 30),
TextManager.Get("SteeringDepth").Replace("[m]", ((int)realWorldDepth).ToString()), Color.LightGreen, null, 0, GUI.SmallFont);
}
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);
Vector2 targetVelPos = new Vector2(velRect.Center.X + targetVelocity.X, velRect.Center.Y - targetVelocity.Y);
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),
targetVelPos,
Color.LightGray);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)targetVelPos.X - 5, (int)targetVelPos.Y - 5, 10, 10), Color.White);
if (Vector2.Distance(PlayerInput.MousePosition, new Vector2(velRect.Center.X, velRect.Center.Y)) < 200.0f)
{
GUI.DrawRectangle(spriteBatch, new Rectangle((int)targetVelPos.X - 10, (int)targetVelPos.Y - 10, 20, 20), Color.Red);
}
steeringPos,
Color.CadetBlue, 0, 2);
}
public override void AddToGUIUpdateList()
public void DebugDrawHUD(SpriteBatch spriteBatch, Vector2 transducerCenter, float displayScale, float displayRadius, Vector2 center)
{
GuiFrame.AddToGUIUpdateList();
}
if (SteeringPath == null) return;
public override void UpdateHUD(Character character)
{
GuiFrame.Update(1.0f / 60.0f);
if (voltage < minVoltage && currPowerConsumption > 0.0f) return;
if (Vector2.Distance(PlayerInput.MousePosition, new Vector2(GuiFrame.Rect.Center.X, GuiFrame.Rect.Center.Y)) < 200.0f)
Vector2 prevPos = Vector2.Zero;
foreach (WayPoint wp in SteeringPath.Nodes)
{
if (PlayerInput.LeftButtonHeld())
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)
{
TargetVelocity = PlayerInput.MousePosition - new Vector2(GuiFrame.Rect.Center.X, GuiFrame.Rect.Center.Y);
targetVelocity.Y = -targetVelocity.Y;
GUI.DrawLine(spriteBatch, pos, prevPos, Color.Green);
}
unsentChanges = true;
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);
}
}
}
private bool SelectDestination(GUITickBox tickBox)
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
unsentChanges = true;
if (tickBox == levelStartTickBox)
if (steerArea.Rect.Contains(PlayerInput.MousePosition))
{
levelEndTickBox.Selected = false;
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)
{
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
{
levelStartTickBox.Selected = false;
inputCumulation = 0;
keyboardInput = Vector2.Zero;
}
maintainPosTickBox.Selected = false;
posToMaintain = null;
tickBox.Selected = true;
UpdatePath();
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; }
return true;
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)
@@ -180,8 +569,8 @@ namespace Barotrauma.Items.Components
if (!autoPilot)
{
//no need to write steering info if autopilot is controlling
msg.Write(targetVelocity.X);
msg.Write(targetVelocity.Y);
msg.Write(steeringInput.X);
msg.Write(steeringInput.Y);
}
else
{
@@ -202,11 +591,13 @@ namespace Barotrauma.Items.Components
{
long msgStartPos = msg.Position;
bool autoPilot = msg.ReadBoolean();
Vector2 newTargetVelocity = targetVelocity;
bool maintainPos = false;
Vector2? newPosToMaintain = null;
bool headingToStart = false;
bool autoPilot = msg.ReadBoolean();
Vector2 newSteeringInput = steeringInput;
Vector2 newTargetVelocity = targetVelocity;
float newSteeringAdjustSpeed = steeringAdjustSpeed;
bool maintainPos = false;
Vector2? newPosToMaintain = null;
bool headingToStart = false;
if (autoPilot)
{
@@ -224,7 +615,9 @@ namespace Barotrauma.Items.Components
}
else
{
newSteeringInput = new Vector2(msg.ReadFloat(), msg.ReadFloat());
newTargetVelocity = new Vector2(msg.ReadFloat(), msg.ReadFloat());
newSteeringAdjustSpeed = msg.ReadFloat();
}
if (correctionTimer > 0.0f)
@@ -239,11 +632,12 @@ namespace Barotrauma.Items.Components
if (!AutoPilot)
{
targetVelocity = newTargetVelocity;
SteeringInput = newSteeringInput;
TargetVelocity = newTargetVelocity;
steeringAdjustSpeed = newSteeringAdjustSpeed;
}
else
{
MaintainPos = newPosToMaintain != null;
posToMaintain = newPosToMaintain;
@@ -2,20 +2,48 @@
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
namespace Barotrauma.Items.Components
{
partial class PowerContainer : Powered, IDrawableComponent, IServerSerializable, IClientSerializable
{
private GUIProgressBar chargeIndicator;
private GUIScrollBar rechargeSpeedSlider;
partial void InitProjSpecific()
{
if (canBeSelected)
if (GuiFrame == null) return;
GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.7f), GuiFrame.RectTransform, Anchor.Center))
{ RelativeSpacing = 0.1f, Stretch = true };
string rechargeStr = TextManager.Get("PowerContainerRechargeRate");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform), "RechargeRate", textAlignment: Alignment.Center)
{
var button = new GUIButton(new Rectangle(160, 50, 30, 30), "-", "", GuiFrame);
button.OnClicked = (GUIButton btn, object obj) =>
TextGetter = () =>
{
RechargeSpeed = rechargeSpeed - maxRechargeSpeed * 0.1f;
return rechargeStr.Replace("[rate]", ((int)((rechargeSpeed / maxRechargeSpeed) * 100.0f)).ToString());
}
};
var sliderArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform, Anchor.BottomCenter), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
};
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sliderArea.RectTransform),
"0 %", textAlignment: Alignment.Center);
rechargeSpeedSlider = new GUIScrollBar(new RectTransform(new Vector2(0.8f, 1.0f), sliderArea.RectTransform), barSize: 0.25f, style: "GUISlider")
{
Step = 0.1f,
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
float newRechargeSpeed = maxRechargeSpeed * barScroll;
if (Math.Abs(newRechargeSpeed - rechargeSpeed) < 0.1f) return false;
RechargeSpeed = newRechargeSpeed;
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
@@ -26,68 +54,79 @@ namespace Barotrauma.Items.Components
item.CreateClientEvent(this);
correctionTimer = CorrectionDelay;
}
return true;
};
}
};
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sliderArea.RectTransform),
"100 %", textAlignment: Alignment.Center);
button = new GUIButton(new Rectangle(200, 50, 30, 30), "+", "", GuiFrame);
button.OnClicked = (GUIButton btn, object obj) =>
string chargeStr = TextManager.Get("PowerContainerCharge");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform), "Charge", textAlignment: Alignment.Center)
{
TextGetter = () =>
{
RechargeSpeed = rechargeSpeed + maxRechargeSpeed * 0.1f;
return chargeStr.Replace("[charge]", (int)charge + "/" + (int)capacity).Replace("[percentage]", ((int)((charge / capacity) * 100.0f)).ToString());
}
};
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(Character.Controlled.LogName + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
}
else if (GameMain.Client != null)
{
item.CreateClientEvent(this);
correctionTimer = CorrectionDelay;
}
chargeIndicator = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), barSize: 0.0f)
{
ProgressGetter = () =>
{
return charge / capacity;
}
};
}
return true;
};
public override void OnItemLoaded()
{
if (rechargeSpeedSlider != null)
{
rechargeSpeedSlider.BarScroll = rechargeSpeed / MaxRechargeSpeed;
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
float chargeRatio = charge / capacity;
chargeIndicator.Color = ToolBox.GradientLerp(chargeRatio, Color.Red, Color.Orange, Color.Green);
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
{
if (indicatorSize.X <= 1.0f || indicatorSize.Y <= 1.0f) return;
GUI.DrawRectangle(spriteBatch,
new Vector2(item.DrawPosition.X - 4, -item.DrawPosition.Y),
new Vector2(8, 22), Color.Black);
new Vector2(
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale,
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale),
indicatorSize * item.Scale, Color.Black, depth: item.SpriteDepth - 0.00001f);
if (charge > 0)
GUI.DrawRectangle(spriteBatch,
new Vector2(item.DrawPosition.X - 3, -item.DrawPosition.Y + 1 + (20.0f * (1.0f - charge / capacity))),
new Vector2(6, 20 * (charge / capacity)), Color.Green, true);
{
Color indicatorColor = ToolBox.GradientLerp(charge / capacity, Color.Red, Color.Orange, Color.Green);
if (!isHorizontal)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale + 1,
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale + 1 + ((indicatorSize.Y * item.Scale) * (1.0f - charge / capacity))),
new Vector2(indicatorSize.X * item.Scale - 2, (indicatorSize.Y * item.Scale - 2) * (charge / capacity)), indicatorColor, true,
depth: item.SpriteDepth - 0.00001f);
}
else
{
GUI.DrawRectangle(spriteBatch,
new Vector2(
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale + 1 ,
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale + 1),
new Vector2((indicatorSize.X * item.Scale - 2) * (charge / capacity), indicatorSize.Y * item.Scale - 2), indicatorColor, true,
depth: item.SpriteDepth - 0.00001f);
}
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
GuiFrame.Draw(spriteBatch);
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
//GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
GUI.Font.DrawString(spriteBatch,
TextManager.Get("PowerContainerCharge").Replace("[charge]", (int)charge + "/" + (int)capacity).Replace("[percentage]", ((int)((charge / capacity) * 100.0f)).ToString()),
new Vector2(x + 30, y + 30), Color.White);
GUI.Font.DrawString(spriteBatch, TextManager.Get("PowerContainerRechargeRate") + ": " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", new Vector2(x + 30, y + 95), Color.White);
}
public override void AddToGUIUpdateList()
{
GuiFrame.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character)
{
GuiFrame.Update(1.0f / 60.0f);
}
public void ClientWrite(NetBuffer msg, object[] extraData)
{
msg.WriteRangedInteger(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
@@ -1,36 +1,73 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class PowerTransfer : Powered
{
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
private GUITickBox powerIndicator;
private GUITickBox highVoltageIndicator;
private GUITickBox lowVoltageIndicator;
partial void InitProjectSpecific(XElement element)
{
if (!canBeSelected) return;
if (GuiFrame == null) return;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.7f), GuiFrame.RectTransform, Anchor.Center), style: null);
powerIndicator = new GUITickBox(new RectTransform(new Point(30, 30), paddedFrame.RectTransform),
TextManager.Get("PowerTransferPowered"), style: "IndicatorLightGreen")
{
Enabled = false
};
highVoltageIndicator = new GUITickBox(new RectTransform(new Point(30, 30), paddedFrame.RectTransform) { AbsoluteOffset = new Point(0, 40) },
TextManager.Get("PowerTransferHighVoltage"), style: "IndicatorLightRed")
{
ToolTip = TextManager.Get("PowerTransferTipOvervoltage"),
Enabled = false
};
lowVoltageIndicator = new GUITickBox(new RectTransform(new Point(30, 30), paddedFrame.RectTransform) { AbsoluteOffset = new Point(0, 80) },
TextManager.Get("PowerTransferLowVoltage"), style: "IndicatorLightRed")
{
ToolTip = TextManager.Get("PowerTransferTipLowvoltage"),
Enabled = false
};
GuiFrame.Draw(spriteBatch);
var textContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), paddedFrame.RectTransform, Anchor.TopRight));
GUI.Font.DrawString(spriteBatch,
TextManager.Get("PowerTransferPower").Replace("[power]", ((int)(-currPowerConsumption)).ToString()),
new Vector2(x + 30, y + 30), Color.White);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContainer.RectTransform),
TextManager.Get("PowerTransferPowerLabel"), font: GUI.LargeFont)
{
ToolTip = TextManager.Get("PowerTransferTipPower")
};
string powerStr = TextManager.Get("PowerTransferPower");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), textContainer.RectTransform), "", textColor: Color.LightGreen)
{
ToolTip = TextManager.Get("PowerTransferTipPower"),
TextGetter = () => { return powerStr.Replace("[power]", ((int)(-currPowerConsumption)).ToString()); }
};
GUI.Font.DrawString(spriteBatch,
TextManager.Get("PowerTransferLoad").Replace("[load]", ((int)powerLoad).ToString()),
new Vector2(x + 30, y + 100), Color.White);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContainer.RectTransform),
TextManager.Get("PowerTransferLoadLabel"), font: GUI.LargeFont)
{
ToolTip = TextManager.Get("PowerTransferTipLoad")
};
string loadStr = TextManager.Get("PowerTransferLoad");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), textContainer.RectTransform), "", textColor: Color.LightBlue)
{
ToolTip = TextManager.Get("PowerTransferTipLoad"),
TextGetter = () => { return loadStr.Replace("[load]", ((int)(powerLoad)).ToString()); }
};
}
public override void AddToGUIUpdateList()
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
GuiFrame.AddToGUIUpdateList();
}
if (GuiFrame == null) return;
public override void UpdateHUD(Character character)
{
GuiFrame.Update(1.0f / 60.0f);
float voltage = powerLoad <= 0.0f ? 1.0f : -currPowerConsumption / powerLoad;
powerIndicator.Selected = IsActive && currPowerConsumption < -0.1f;
highVoltageIndicator.Selected = Timing.TotalTime % 0.5f < 0.25f && powerIndicator.Selected && voltage > 1.2f;
lowVoltageIndicator.Selected = Timing.TotalTime % 0.5f < 0.25f && powerIndicator.Selected && voltage < 0.8f;
}
}
}
@@ -1,11 +1,31 @@
namespace Barotrauma.Items.Components
using System.Collections.Generic;
using System.Xml.Linq;
using Barotrauma.Sounds;
namespace Barotrauma.Items.Components
{
partial class Powered : ItemComponent
{
protected static Sound[] sparkSounds;
protected List<RoundSound> sparkSounds;
private RoundSound powerOnSound;
private bool powerOnSoundPlayed;
private static Sound powerOnSound;
partial void InitProjectSpecific(XElement element)
{
sparkSounds = new List<RoundSound>();
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "poweronsound":
powerOnSound = Submarine.LoadRoundSound(subElement, false);
break;
case "sparksound":
sparkSounds.Add(Submarine.LoadRoundSound(subElement, false));
break;
}
}
}
}
}
@@ -0,0 +1,126 @@
using Barotrauma.Particles;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class RepairTool
{
public ParticleEmitter ParticleEmitter
{
get;
private set;
}
private List<ParticleEmitter> ParticleEmitterHitStructure = new List<ParticleEmitter>();
private List<ParticleEmitter> ParticleEmitterHitCharacter = new List<ParticleEmitter>();
private List<Pair<RelatedItem, ParticleEmitter>> ParticleEmitterHitItem = new List<Pair<RelatedItem, ParticleEmitter>>();
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "particleemitter":
ParticleEmitter = new ParticleEmitter(subElement);
break;
case "particleemitterhititem":
string[] identifiers = subElement.GetAttributeStringArray("identifiers", new string[0]);
if (identifiers.Length == 0) identifiers = subElement.GetAttributeStringArray("identifier", new string[0]);
string[] excludedIdentifiers = subElement.GetAttributeStringArray("excludedidentifiers", new string[0]);
if (excludedIdentifiers.Length == 0) excludedIdentifiers = subElement.GetAttributeStringArray("excludedidentifier", new string[0]);
ParticleEmitterHitItem.Add(
new Pair<RelatedItem, ParticleEmitter>(
new RelatedItem(identifiers, excludedIdentifiers),
new ParticleEmitter(subElement)));
break;
case "particleemitterhitstructure":
ParticleEmitterHitStructure.Add(new ParticleEmitter(subElement));
break;
case "particleemitterhitcharacter":
ParticleEmitterHitCharacter.Add(new ParticleEmitter(subElement));
break;
}
}
}
partial void UseProjSpecific(float deltaTime)
{
if (ParticleEmitter != null)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
ParticleEmitter.Emit(
deltaTime, item.WorldPosition + TransformedBarrelPos,
item.CurrentHull, particleAngle, -particleAngle);
}
}
partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex)
{
Vector2 progressBarPos = targetStructure.SectionPosition(sectionIndex);
if (targetStructure.Submarine != null)
{
progressBarPos += targetStructure.Submarine.DrawPosition;
}
var progressBar = user.UpdateHUDProgressBar(
targetStructure,
progressBarPos,
1.0f - targetStructure.SectionDamage(sectionIndex) / targetStructure.Health,
Color.Red, Color.Green);
if (progressBar != null) progressBar.Size = new Vector2(60.0f, 20.0f);
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetStructure.Submarine != null) particlePos += targetStructure.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitStructure)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
}
}
partial void FixCharacterProjSpecific(Character user, float deltaTime, Character targetCharacter)
{
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetCharacter.Submarine != null) particlePos += targetCharacter.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitCharacter)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
}
}
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, float prevCondition)
{
if (prevCondition != targetItem.Condition)
{
Vector2 progressBarPos = targetItem.DrawPosition;
var progressBar = user.UpdateHUDProgressBar(
targetItem,
progressBarPos,
targetItem.Condition / 100.0f,
Color.Red, Color.Green);
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
}
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitItem)
{
if (!emitter.First.MatchesItem(targetItem)) continue;
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Second.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
}
}
}
}
@@ -0,0 +1,130 @@
using Barotrauma.Particles;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Repairable : ItemComponent
{
private GUIButton repairButton;
private GUIProgressBar progressBar;
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
//the corresponding particle emitter is active when the condition is within this range
private List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
private string repairButtonText, repairingText;
[Serialize("", false)]
public string Description
{
get;
set;
}
public override bool ShouldDrawHUD(Character character)
{
if (!HasRequiredItems(character, false)) return false;
return (item.Condition < ShowRepairUIThreshold || (currentFixer == character && item.Condition < item.Prefab.Health));
}
partial void InitProjSpecific(XElement element)
{
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
Stretch = true,
RelativeSpacing = 0.05f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
header, textAlignment: Alignment.TopCenter, font: GUI.LargeFont);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
Description, font: GUI.SmallFont, wrap: true);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
TextManager.Get("RequiredRepairSkills"));
for (int i = 0; i < requiredSkills.Count; i++)
{
var skillText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
" - " + TextManager.Get("SkillName." + requiredSkills[i].Identifier) + ": " + ((int)requiredSkills[i].Level), font: GUI.SmallFont)
{
UserData = requiredSkills[i]
};
}
progressBar = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
color: Color.Green, barSize: 0.0f);
repairButtonText = TextManager.Get("RepairButton");
repairingText = TextManager.Get("Repairing");
repairButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.TopCenter),
repairButtonText)
{
OnClicked = (btn, obj) =>
{
currentFixer = Character.Controlled;
item.CreateClientEvent(this);
return true;
}
};
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "emitter":
case "particleemitter":
particleEmitters.Add(new ParticleEmitter(subElement));
particleEmitterConditionRanges.Add(new Vector2(
subElement.GetAttributeFloat("mincondition", 0.0f),
subElement.GetAttributeFloat("maxcondition", 100.0f)));
break;
}
}
}
partial void UpdateProjSpecific(float deltaTime)
{
for (int i = 0; i < particleEmitters.Count; i++)
{
if (item.Condition >= particleEmitterConditionRanges[i].X && item.Condition <= particleEmitterConditionRanges[i].Y)
{
particleEmitters[i].Emit(deltaTime, item.WorldPosition, item.CurrentHull);
}
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
IsActive = true;
progressBar.BarSize = item.Condition / item.Prefab.Health;
progressBar.Color = ToolBox.GradientLerp(item.Condition / item.Prefab.Health, Color.Red, Color.Orange, Color.Green);
repairButton.Enabled = currentFixer == null;
repairButton.Text = currentFixer == null ?
repairButtonText :
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
{
Skill skill = c.UserData as Skill;
if (skill == null) continue;
GUITextBlock textBlock = (GUITextBlock)c;
if (character.GetSkillLevel(skill.Identifier) < skill.Level)
{
textBlock.TextColor = Color.Red;
}
else
{
textBlock.TextColor = Color.White;
}
}
}
}
}
@@ -2,27 +2,27 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma.Items.Components
{
partial class Connection
{
private static Texture2D panelTexture;
//private static Texture2D panelTexture;
private static Sprite connector;
private static Sprite wireVertical;
private static Sprite connectionSprite;
private static Sprite connectionSpriteHighlight;
private static List<Sprite> screwSprites;
private static Wire draggingConnected;
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
{
int width = 400, height = 200;
int x = GameMain.GraphicsWidth / 2 - width / 2, y = GameMain.GraphicsHeight - height;
Rectangle panelRect = new Rectangle(x, y, width, height);
spriteBatch.Draw(panelTexture, panelRect, new Rectangle(0, 512 - height, width, height), Color.White);
//GUI.DrawRectangle(spriteBatch, panelRect, Color.Black, true);
Rectangle panelRect = panel.GuiFrame.Rect;
int x = panelRect.X, y = panelRect.Y;
int width = panelRect.Width, height = panelRect.Height;
bool mouseInRect = panelRect.Contains(PlayerInput.MousePosition);
@@ -49,14 +49,15 @@ namespace Barotrauma.Items.Components
}
}
Vector2 rightPos = new Vector2(x + width - 130, y + 50);
Vector2 leftPos = new Vector2(x + 130, y + 50);
Vector2 rightPos = new Vector2(x + width - 130, y + 80);
Vector2 leftPos = new Vector2(x + 130, y + 80);
Vector2 rightWirePos = new Vector2(x + width - 5, y + 30);
Vector2 leftWirePos = new Vector2(x + 5, y + 30);
int wireInterval = (height - 20) / Math.Max(totalWireCount, 1);
int connectorIntervalLeft = (height - 100) / Math.Max(panel.Connections.Count(c => c.IsOutput), 1);
int connectorIntervalRight = (height - 100) / Math.Max(panel.Connections.Count(c => !c.IsOutput), 1);
foreach (Connection c in panel.Connections)
{
@@ -67,7 +68,7 @@ namespace Barotrauma.Items.Components
int linkIndex = c.FindWireIndex(draggingConnected.Item);
if (linkIndex > -1)
{
Inventory.draggingItem = c.Wires[linkIndex].Item;
Inventory.draggingItem = c.wires[linkIndex].Item;
}
}
@@ -80,7 +81,7 @@ namespace Barotrauma.Items.Components
mouseInRect, equippedWire,
wireInterval);
rightPos.Y += 30;
rightPos.Y += connectorIntervalLeft;
rightWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
}
else
@@ -91,7 +92,7 @@ namespace Barotrauma.Items.Components
mouseInRect, equippedWire,
wireInterval);
leftPos.Y += 30;
leftPos.Y += connectorIntervalRight;
leftWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
//leftWireX -= wireInterval;
}
@@ -99,7 +100,7 @@ namespace Barotrauma.Items.Components
if (draggingConnected != null)
{
DrawWire(spriteBatch, draggingConnected, draggingConnected.Item, PlayerInput.MousePosition, new Vector2(x + width / 2, y + height), mouseInRect, null, panel);
DrawWire(spriteBatch, draggingConnected, draggingConnected.Item, PlayerInput.MousePosition, new Vector2(x + width / 2, y + height - 10), mouseInRect, null, panel, "");
if (!PlayerInput.LeftButtonHeld())
{
@@ -124,48 +125,45 @@ namespace Barotrauma.Items.Components
{
DrawWire(spriteBatch, equippedWire, equippedWire.Item,
new Vector2(x + width / 2, y + height - 100),
new Vector2(x + width / 2, y + height), mouseInRect, null, panel);
new Vector2(x + width / 2, y + height), mouseInRect, null, panel, "");
if (draggingConnected == equippedWire) Inventory.draggingItem = equippedWire.Item;
}
}
//stop dragging a wire item if cursor is outside the panel
if (mouseInRect) Inventory.draggingItem = null;
spriteBatch.Draw(panelTexture, panelRect, new Rectangle(0, 0, width, height), Color.White);
//stop dragging a wire item if the cursor is within any connection panel
//(so we don't drop the item when dropping the wire on a connection)
if (mouseInRect || GUI.MouseOn?.UserData is ConnectionPanel) Inventory.draggingItem = null;
}
private void Draw(SpriteBatch spriteBatch, ConnectionPanel panel, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn, Wire equippedWire, float wireInterval)
{
//spriteBatch.DrawString(GUI.SmallFont, Name, new Vector2(labelPos.X, labelPos.Y-10), Color.White);
GUI.DrawString(spriteBatch, labelPos, Name, IsPower ? Color.Red : Color.White, Color.Black, 0, GUI.SmallFont);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)position.X - 10, (int)position.Y - 10, 20, 20), Color.White);
spriteBatch.Draw(panelTexture, position - new Vector2(16.0f, 16.0f), new Rectangle(64, 256, 32, 32), Color.White);
connectionSprite.Draw(spriteBatch, position);
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null || Wires[i].Hidden || draggingConnected == Wires[i]) continue;
if (wires[i] == null || wires[i].Hidden || draggingConnected == wires[i]) continue;
Connection recipient = Wires[i].OtherConnection(this);
DrawWire(spriteBatch, Wires[i], (recipient == null) ? Wires[i].Item : recipient.item, position, wirePosition, mouseIn, equippedWire, panel);
Connection recipient = wires[i].OtherConnection(this);
string label = recipient == null ? "" :
wires[i].Locked ? recipient.item.Name + "\n" + TextManager.Get("ConnectionLocked") : recipient.item.Name;
DrawWire(spriteBatch, wires[i], (recipient == null) ? wires[i].Item : recipient.item, position, wirePosition, mouseIn, equippedWire, panel, label);
wirePosition.Y += wireInterval;
}
if (draggingConnected != null && Vector2.Distance(position, PlayerInput.MousePosition) < 13.0f)
{
spriteBatch.Draw(panelTexture, position - new Vector2(21.5f, 21.5f), new Rectangle(106, 250, 43, 43), Color.White);
connectionSpriteHighlight.Draw(spriteBatch, position);
if (!PlayerInput.LeftButtonHeld())
{
//find an empty cell for the new connection
int index = FindWireIndex(null);
int index = FindEmptyIndex();
if (index > -1 && !Wires.Contains(draggingConnected))
{
bool alreadyConnected = draggingConnected.IsConnectedTo(panel.Item);
@@ -186,22 +184,20 @@ namespace Barotrauma.Items.Components
Item.Name + " (" + Name + ") to " + otherConnection.item.Name + " (" + otherConnection.Name + ")", ServerLog.MessageType.ItemInteraction);
}
AddLink(index, draggingConnected);
SetWire(index, draggingConnected);
}
}
}
}
int screwIndex = (position.Y % 60 < 30) ? 0 : 1;
if (Wires.Any(w => w != null && w != draggingConnected))
{
spriteBatch.Draw(panelTexture, position - new Vector2(16.0f, 16.0f), new Rectangle(screwIndex * 32, 256, 32, 32), Color.White);
int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count;
screwSprites[screwIndex].Draw(spriteBatch, position);
}
}
private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Item item, Vector2 end, Vector2 start, bool mouseIn, Wire equippedWire, ConnectionPanel panel)
private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Item item, Vector2 end, Vector2 start, bool mouseIn, Wire equippedWire, ConnectionPanel panel, string label)
{
if (draggingConnected == wire)
{
@@ -228,13 +224,14 @@ namespace Barotrauma.Items.Components
Vector2.Distance(end, PlayerInput.MousePosition) < 20.0f ||
new Rectangle((start.X < end.X) ? textX - 100 : textX, (int)start.Y - 5, 100, 14).Contains(PlayerInput.MousePosition));
string label = wire.Locked || panel.Locked ? item.Name + "\n" + TextManager.Get("ConnectionLocked") : item.Name;
GUI.DrawString(spriteBatch,
new Vector2(start.X < end.X ? textX - GUI.SmallFont.MeasureString(label).X : textX, start.Y - 5.0f),
label,
(mouseOn ? Color.Gold : Color.White) * (wire.Locked ? 0.6f : 1.0f), Color.Black * 0.8f,
3, GUI.SmallFont);
if (!string.IsNullOrEmpty(label))
{
GUI.DrawString(spriteBatch,
new Vector2(start.X < end.X ? textX - GUI.SmallFont.MeasureString(label).X : textX, start.Y - 5.0f),
label,
(mouseOn ? Color.Gold : Color.White) * (wire.Locked ? 0.6f : 1.0f), Color.Black * 0.8f,
3, GUI.SmallFont);
}
var wireEnd = end + Vector2.Normalize(start - end) * 30.0f;
@@ -1,15 +1,44 @@
using Barotrauma.Networking;
using Lidgren.Network;
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 ConnectionPanel : ItemComponent, IServerSerializable, IClientSerializable
{
public override void UpdateHUD(Character character)
public static Wire HighlightedWire;
partial void InitProjSpecific(XElement element)
{
if (GuiFrame == null) return;
new GUICustomComponent(new RectTransform(Vector2.One, GuiFrame.RectTransform), DrawConnections, null)
{
UserData = this
};
}
public override void Move(Vector2 amount)
{
if (item.Submarine == null || item.Submarine.Loading || Screen.Selected != GameMain.SubEditorScreen) return;
MoveConnectedWires(amount);
}
public override bool ShouldDrawHUD(Character character)
{
return character == Character.Controlled && character == user;
}
public override void AddToGUIUpdateList()
{
GuiFrame?.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
if (character != Character.Controlled || character != user) return;
@@ -21,12 +50,17 @@ namespace Barotrauma.Items.Components
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
private void DrawConnections(SpriteBatch spriteBatch, GUICustomComponent container)
{
if (character != Character.Controlled || character != user) return;
if (user != Character.Controlled || user == null) return;
HighlightedWire = null;
Connection.DrawConnections(spriteBatch, this, character);
Connection.DrawConnections(spriteBatch, this, user);
foreach (UISprite sprite in GUI.Style.GetComponentStyle("ConnectionPanelFront").Sprites[GUIComponent.ComponentState.None])
{
sprite.Draw(spriteBatch, GuiFrame.Rect, Color.White, SpriteEffects.None);
}
}
@@ -47,7 +81,7 @@ namespace Barotrauma.Items.Components
private void ApplyRemoteState(NetBuffer msg)
{
List<Wire> prevWires = Connections.SelectMany(c => Array.FindAll(c.Wires, w => w != null)).ToList();
List<Wire> prevWires = Connections.SelectMany(c => c.Wires.Where(w => w != null)).ToList();
List<Wire> newWires = new List<Wire>();
foreach (Connection connection in Connections)
@@ -69,7 +103,7 @@ namespace Barotrauma.Items.Components
newWires.Add(wireComponent);
connection.Wires[i] = wireComponent;
connection.SetWire(i, wireComponent);
wireComponent.Connect(connection, false);
}
}
@@ -0,0 +1,114 @@
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class CustomInterface
{
private List<GUIComponent> uiElements = new List<GUIComponent>();
partial void InitProjSpecific(XElement element)
{
uiElements.Clear();
GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), GuiFrame.RectTransform, Anchor.Center))
{ RelativeSpacing = 0.05f, Stretch = true };
foreach (CustomInterfaceElement ciElement in customInterfaceElementList)
{
if (ciElement.ContinuousSignal)
{
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), ciElement.Label)
{
UserData = ciElement
};
tickBox.OnSelected += (tBox) =>
{
if (GameMain.Client == null)
{
TickBoxToggled(tBox.UserData as CustomInterfaceElement, tBox.Selected);
}
else
{
item.CreateClientEvent(this);
}
return true;
};
uiElements.Add(tickBox);
}
else
{
var btn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), ciElement.Label)
{
UserData = ciElement
};
btn.OnClicked += (_, userdata) =>
{
if (GameMain.Client == null)
{
ButtonClicked(userdata as CustomInterfaceElement);
}
else
{
GameMain.Client.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.components.IndexOf(this), userdata as CustomInterfaceElement });
}
return true;
};
uiElements.Add(btn);
}
}
}
partial void UpdateLabelsProjSpecific()
{
for (int i = 0; i < labels.Length && i < uiElements.Count; i++)
{
if (uiElements[i] is GUIButton button)
{
button.Text = labels[i];
}
else if (uiElements[i] is GUITickBox tickBox)
{
tickBox.Text = labels[i];
}
}
}
public void ClientWrite(NetBuffer msg, object[] extraData = null)
{
//extradata contains an array of buttons clicked by the player (or nothing if the player didn't click anything)
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
if (customInterfaceElementList[i].ContinuousSignal)
{
msg.Write(((GUITickBox)uiElements[i]).Selected);
}
else
{
msg.Write(extraData != null && extraData.Any(d => d as CustomInterfaceElement == customInterfaceElementList[i]));
}
}
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
bool elementState = msg.ReadBoolean();
if (customInterfaceElementList[i].ContinuousSignal)
{
((GUITickBox)uiElements[i]).Selected = elementState;
TickBoxToggled(customInterfaceElementList[i], elementState);
}
else if (elementState)
{
ButtonClicked(customInterfaceElementList[i]);
}
}
}
}
}
@@ -0,0 +1,18 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma.Items.Components
{
partial class MotionSensor : IDrawableComponent
{
public void Draw(SpriteBatch spriteBatch, bool editing)
{
if (!editing || !MapEntity.SelectedList.Contains(item)) return;
Vector2 pos = item.WorldPosition + detectOffset;
pos.Y = -pos.Y;
GUI.DrawRectangle(spriteBatch, pos - new Vector2(rangeX, rangeY), new Vector2(rangeX, rangeY) * 2.0f, Color.Cyan * 0.5f, isFilled: false, thickness: 2);
}
}
}
@@ -0,0 +1,18 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma.Items.Components
{
partial class WifiComponent : IDrawableComponent
{
public void Draw(SpriteBatch spriteBatch, bool editing)
{
if (!editing || !MapEntity.SelectedList.Contains(item)) return;
Vector2 pos = new Vector2(item.DrawPosition.X, -item.DrawPosition.Y);
ShapeExtensions.DrawLine(spriteBatch, pos + Vector2.UnitY * range, pos - Vector2.UnitY * range, Color.Cyan * 0.5f, 2);
ShapeExtensions.DrawLine(spriteBatch, pos + Vector2.UnitX * range, pos - Vector2.UnitX * range, Color.Cyan * 0.5f, 2);
ShapeExtensions.DrawCircle(spriteBatch, pos, range, 32, Color.Cyan * 0.5f, 3);
}
}
}
@@ -35,8 +35,7 @@ namespace Barotrauma.Items.Components
SpriteEffects.None,
depth);
}
}
}
private static Sprite wireSprite;
private static Wire draggingWire;
@@ -45,7 +44,7 @@ namespace Barotrauma.Items.Components
public void Draw(SpriteBatch spriteBatch, bool editing)
{
if (sections.Count == 0 && !IsActive)
if (sections.Count == 0 && !IsActive || Hidden)
{
Drawable = false;
return;
@@ -187,8 +186,7 @@ namespace Barotrauma.Items.Components
else
{
//check if close enough to a node
float temp = 0.0f;
int closestIndex = selectedWire.GetClosestNodeIndex(mousePos, nodeSelectDist, out temp);
int closestIndex = selectedWire.GetClosestNodeIndex(mousePos, nodeSelectDist, out _);
if (closestIndex > -1)
{
highlightedNodeIndex = closestIndex;
@@ -209,37 +207,40 @@ namespace Barotrauma.Items.Components
}
}
//check which wire is highlighted with the cursor
Wire highlighted = null;
float closestDist = float.PositiveInfinity;
foreach (Wire w in wires)
//check which wire is highlighted with the cursor
if (GUI.MouseOn == null)
{
Vector2 mousePos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
if (w.item.Submarine != null) mousePos -= (w.item.Submarine.Position + w.item.Submarine.HiddenSubPosition);
float dist = 0.0f;
int highlightedNode = w.GetClosestNodeIndex(mousePos, highlighted == null ? nodeSelectDist : closestDist, out dist);
if (highlightedNode > -1)
float closestDist = float.PositiveInfinity;
foreach (Wire w in wires)
{
if (dist < closestDist)
Vector2 mousePos = GameMain.SubEditorScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
if (w.item.Submarine != null) mousePos -= (w.item.Submarine.Position + w.item.Submarine.HiddenSubPosition);
int highlightedNode = w.GetClosestNodeIndex(mousePos, highlighted == null ? nodeSelectDist : closestDist, out float dist);
if (highlightedNode > -1)
{
highlightedNodeIndex = highlightedNode;
highlighted = w;
closestDist = dist;
if (dist < closestDist)
{
highlightedNodeIndex = highlightedNode;
highlighted = w;
closestDist = dist;
}
}
if (w.GetClosestSectionIndex(mousePos, highlighted == null ? sectionSelectDist : closestDist, out dist) > -1)
{
//prefer nodes over sections
if (dist + nodeSelectDist * 0.5f < closestDist)
{
highlightedNodeIndex = null;
highlighted = w;
closestDist = dist + nodeSelectDist * 0.5f;
}
}
}
if (w.GetClosestSectionIndex(mousePos, highlighted == null ? sectionSelectDist : closestDist, out dist) > -1)
{
//prefer nodes over sections
if (dist + nodeSelectDist * 0.5f < closestDist)
{
highlightedNodeIndex = null;
highlighted = w;
closestDist = dist + nodeSelectDist * 0.5f;
}
}
}
}
if (highlighted != null)
{
@@ -137,53 +137,77 @@ namespace Barotrauma.Items.Components
hudPos += Vector2.UnitX * 50.0f;
List<string> texts = new List<string>();
List<Color> textColors = new List<Color>();
if (target.Info != null)
{
texts.Add(target.Name);
textColors.Add(Color.White);
}
if (target.IsDead)
{
texts.Add(TextManager.Get("Deceased"));
texts.Add(TextManager.Get("CauseOfDeath") + ": " + TextManager.Get("CauseOfDeath." + target.CauseOfDeath.ToString()));
textColors.Add(Color.Red);
texts.Add(
target.CauseOfDeath.Affliction?.CauseOfDeathDescription ??
TextManager.Get("CauseOfDeath") + ": " +TextManager.Get("CauseOfDeath." + target.CauseOfDeath.Type.ToString()));
textColors.Add(Color.Red);
}
else
{
if (target.IsUnconscious) texts.Add(TextManager.Get("Unconscious"));
if (target.Stun > 0.01f) texts.Add(TextManager.Get("Stunned"));
int healthTextIndex = target.Health > 95.0f ? 0 :
MathHelper.Clamp((int)Math.Ceiling((1.0f - (target.Health / 200.0f + 0.5f)) * HealthTexts.Length), 0, HealthTexts.Length - 1);
texts.Add(HealthTexts[healthTextIndex]);
if (target.IsUnconscious)
{
texts.Add(TextManager.Get("Unconscious"));
textColors.Add(Color.Orange);
}
if (target.Stun > 0.01f)
{
texts.Add(TextManager.Get("Stunned"));
textColors.Add(Color.Orange);
}
int oxygenTextIndex = MathHelper.Clamp((int)Math.Floor((1.0f - (target.Oxygen / 100.0f)) * OxygenTexts.Length), 0, OxygenTexts.Length - 1);
texts.Add(OxygenTexts[oxygenTextIndex]);
textColors.Add(Color.Lerp(Color.Red, Color.Green, target.Oxygen / 100.0f));
if (target.Bleeding > 0.0f)
{
int bleedingTextIndex = MathHelper.Clamp((int)Math.Floor(target.Bleeding / 4.0f) * BleedingTexts.Length, 0, BleedingTexts.Length - 1);
int bleedingTextIndex = MathHelper.Clamp((int)Math.Floor(target.Bleeding / 100.0f) * BleedingTexts.Length, 0, BleedingTexts.Length - 1);
texts.Add(BleedingTexts[bleedingTextIndex]);
textColors.Add(Color.Lerp(Color.Red, Color.Green, target.Bleeding / 100.0f));
}
if (target.huskInfection != null)
var allAfflictions = target.CharacterHealth.GetAllAfflictions();
Dictionary<AfflictionPrefab, float> combinedAfflictionStrengths = new Dictionary<AfflictionPrefab, float>();
foreach (Affliction affliction in allAfflictions)
{
if (target.huskInfection.State == HuskInfection.InfectionState.Transition)
if (affliction.Strength < affliction.Prefab.ActivationThreshold || affliction.Strength < affliction.Prefab.ShowIconThreshold) continue;
if (combinedAfflictionStrengths.ContainsKey(affliction.Prefab))
{
texts.Add(TextManager.Get("HuskInfectionTransition"));
combinedAfflictionStrengths[affliction.Prefab] += affliction.Strength;
}
else if (target.huskInfection.State == HuskInfection.InfectionState.Active)
else
{
texts.Add(TextManager.Get("HuskInfectionActive"));
combinedAfflictionStrengths[affliction.Prefab] = affliction.Strength;
}
}
foreach (AfflictionPrefab affliction in combinedAfflictionStrengths.Keys)
{
texts.Add(affliction.Name + ": " + ((int)combinedAfflictionStrengths[affliction]).ToString() + " %");
textColors.Add(Color.Lerp(Color.Red, Color.Green, combinedAfflictionStrengths[affliction] / affliction.MaxStrength));
}
}
foreach (string text in texts)
GUI.DrawString(spriteBatch, hudPos, texts[0], textColors[0] * alpha, Color.Black * 0.7f * alpha, 2);
hudPos.X += 5.0f;
hudPos.Y += 24.0f;
for (int i = 1; i < texts.Count; i++)
{
GUI.DrawString(spriteBatch, hudPos, text, Color.LightGreen * alpha, Color.Black * 0.7f * alpha, 2);
hudPos.Y += 24.0f;
GUI.DrawString(spriteBatch, hudPos, texts[i], textColors[i] * alpha, Color.Black * 0.7f * alpha, 2, GUI.SmallFont);
hudPos.Y += 18.0f;
}
}
}
@@ -1,4 +1,6 @@
using Barotrauma.Networking;
using Barotrauma.Particles;
using Barotrauma.Sounds;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -12,10 +14,25 @@ namespace Barotrauma.Items.Components
{
partial class Turret : Powered, IDrawableComponent, IServerSerializable
{
private Sprite crosshairSprite, disabledCrossHairSprite;
private Sprite crosshairSprite, crosshairPointerSprite;
private GUIProgressBar powerIndicator;
private float recoilTimer;
private RoundSound startMoveSound, endMoveSound, moveSound;
private SoundChannel moveSoundChannel;
private Vector2 crosshairPos, crosshairPointerPos;
private bool flashLowPower;
private bool flashNoAmmo;
private float flashTimer;
private float flashLength = 1;
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
[Editable, Serialize("0.0,0.0,0.0,0.0", true)]
public Color HudTint
{
@@ -37,6 +54,13 @@ namespace Barotrauma.Items.Components
private set;
}
[Serialize(0.0f, false)]
public float RecoilDistance
{
get;
private set;
}
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
@@ -47,77 +71,220 @@ namespace Barotrauma.Items.Components
case "crosshair":
crosshairSprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.ConfigFile));
break;
case "disabledcrosshair":
disabledCrossHairSprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.ConfigFile));
case "crosshairpointer":
crosshairPointerSprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.ConfigFile));
break;
case "startmovesound":
startMoveSound = Submarine.LoadRoundSound(subElement, false);
break;
case "endmovesound":
endMoveSound = Submarine.LoadRoundSound(subElement, false);
break;
case "movesound":
moveSound = Submarine.LoadRoundSound(subElement, false);
break;
case "particleemitter":
particleEmitters.Add(new ParticleEmitter(subElement));
break;
}
}
int barWidth = 200;
powerIndicator = new GUIProgressBar(new Rectangle(GameMain.GraphicsWidth / 2 - barWidth / 2, 20, barWidth, 30), Color.White, 0.0f);
powerIndicator = new GUIProgressBar(new RectTransform(new Vector2(0.18f, 0.03f), GUI.Canvas, Anchor.TopCenter)
{
MinSize = new Point(100,20),
RelativeOffset = new Vector2(0.0f, 0.01f)
},
barSize: 0.0f);
}
partial void LaunchProjSpecific()
{
recoilTimer = Math.Max(Reload, 0.1f);
PlaySound(ActionType.OnUse, item.WorldPosition);
Vector2 particlePos = new Vector2(item.WorldRect.X + transformedBarrelPos.X, item.WorldRect.Y - transformedBarrelPos.Y);
foreach (ParticleEmitter emitter in particleEmitters)
{
emitter.Emit(1.0f, particlePos, hullGuess: null, angle: rotation, particleRotation: rotation);
}
}
partial void UpdateProjSpecific(float deltaTime)
{
recoilTimer -= deltaTime;
if (crosshairSprite != null)
{
Vector2 itemPos = cam.WorldToScreen(new Vector2(item.WorldRect.X + transformedBarrelPos.X, item.WorldRect.Y - transformedBarrelPos.Y));
Vector2 turretDir = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation));
Vector2 mouseDiff = itemPos - PlayerInput.MousePosition;
crosshairPos = new Vector2(
MathHelper.Clamp(itemPos.X + turretDir.X * mouseDiff.Length(), 0, GameMain.GraphicsWidth),
MathHelper.Clamp(itemPos.Y + turretDir.Y * mouseDiff.Length(), 0, GameMain.GraphicsHeight));
}
crosshairPointerPos = PlayerInput.MousePosition;
if (Math.Abs(angularVelocity) > 0.1f)
{
if (moveSoundChannel == null && startMoveSound != null)
{
moveSoundChannel = SoundPlayer.PlaySound(startMoveSound.Sound, startMoveSound.Volume, startMoveSound.Range, item.WorldPosition);
}
else if (moveSoundChannel == null || !moveSoundChannel.IsPlaying)
{
if (moveSound != null)
{
moveSoundChannel.Dispose();
moveSoundChannel = SoundPlayer.PlaySound(moveSound.Sound, moveSound.Volume, moveSound.Range, item.WorldPosition);
if (moveSoundChannel != null) moveSoundChannel.Looping = true;
}
}
}
else if (Math.Abs(angularVelocity) < 0.05f)
{
if (moveSoundChannel != null)
{
if (endMoveSound != null && moveSoundChannel.Sound != endMoveSound.Sound)
{
moveSoundChannel.Dispose();
moveSoundChannel = SoundPlayer.PlaySound(endMoveSound.Sound, endMoveSound.Volume, endMoveSound.Range, item.WorldPosition);
if (moveSoundChannel != null) moveSoundChannel.Looping = false;
}
else if (!moveSoundChannel.IsPlaying)
{
moveSoundChannel.Dispose();
moveSoundChannel = null;
}
}
}
if (moveSoundChannel != null && moveSoundChannel.IsPlaying)
{
moveSoundChannel.Gain = MathHelper.Clamp(Math.Abs(angularVelocity), 0.5f, 1.0f);
}
if (flashLowPower || flashNoAmmo)
{
flashTimer += deltaTime;
if (flashTimer >= flashLength)
{
flashTimer = 0;
flashLowPower = false;
flashNoAmmo = false;
}
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
if (crosshairSprite != null)
{
Vector2 itemPos = cam.WorldToScreen(item.WorldPosition);
Vector2 turretDir = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation));
Vector2 mouseDiff = itemPos - PlayerInput.MousePosition;
crosshairPos = new Vector2(
MathHelper.Clamp(itemPos.X + turretDir.X * mouseDiff.Length(), 0, GameMain.GraphicsWidth),
MathHelper.Clamp(itemPos.Y + turretDir.Y * mouseDiff.Length(), 0, GameMain.GraphicsHeight));
}
crosshairPointerPos = PlayerInput.MousePosition;
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
{
Vector2 drawPos = new Vector2(item.Rect.X, item.Rect.Y);
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
if (item.Submarine != null) drawPos += item.Submarine.DrawPosition;
drawPos.Y = -drawPos.Y;
if (barrelSprite != null)
float recoilOffset = 0.0f;
if (RecoilDistance > 0.0f && recoilTimer > 0.0f)
{
barrelSprite.Draw(spriteBatch,
drawPos + barrelPos, Color.White,
rotation + MathHelper.PiOver2, 1.0f,
SpriteEffects.None, item.Sprite.Depth + 0.01f);
//move the barrel backwards 0.1 seconds after launching
if (recoilTimer >= Math.Max(Reload, 0.1f) - 0.1f)
{
recoilOffset = RecoilDistance * (1.0f - (recoilTimer - (Math.Max(Reload, 0.1f) - 0.1f)) / 0.1f);
}
//move back to normal position while reloading
else
{
recoilOffset = RecoilDistance * recoilTimer / (Math.Max(Reload, 0.1f) - 0.1f);
}
}
railSprite?.Draw(spriteBatch,
drawPos,
Color.White,
rotation + MathHelper.PiOver2, item.Scale,
SpriteEffects.None, item.SpriteDepth + (railSprite.Depth - item.Sprite.Depth));
barrelSprite?.Draw(spriteBatch,
drawPos - new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * recoilOffset * item.Scale,
Color.White,
rotation + MathHelper.PiOver2, item.Scale,
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
if (!editing) return;
GUI.DrawLine(spriteBatch,
drawPos + barrelPos,
drawPos + barrelPos + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * 60.0f,
drawPos,
drawPos + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * 60.0f,
Color.Green);
GUI.DrawLine(spriteBatch,
drawPos + barrelPos,
drawPos + barrelPos + new Vector2((float)Math.Cos(maxRotation), (float)Math.Sin(maxRotation)) * 60.0f,
drawPos,
drawPos + new Vector2((float)Math.Cos(maxRotation), (float)Math.Sin(maxRotation)) * 60.0f,
Color.Green);
GUI.DrawLine(spriteBatch,
drawPos + barrelPos,
drawPos + barrelPos + new Vector2((float)Math.Cos((maxRotation + minRotation) / 2), (float)Math.Sin((maxRotation + minRotation) / 2)) * 60.0f,
drawPos,
drawPos + new Vector2((float)Math.Cos((maxRotation + minRotation) / 2), (float)Math.Sin((maxRotation + minRotation) / 2)) * 60.0f,
Color.LightGreen);
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
if (HudTint.A > 0)
{
GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight),
new Color(HudTint.R, HudTint.G, HudTint.B) * (HudTint.A/255.0f), true);
GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight),
new Color(HudTint.R, HudTint.G, HudTint.B) * (HudTint.A / 255.0f), true);
}
GetAvailablePower(out float batteryCharge, out float batteryCapacity);
float batteryCharge;
float batteryCapacity;
GetAvailablePower(out batteryCharge, out batteryCapacity);
List<Projectile> projectiles = GetLoadedProjectiles(false, true);
List<Item> availableAmmo = new List<Item>();
foreach (MapEntity e in item.linkedTo)
{
var linkedItem = e as Item;
if (linkedItem == null) continue;
var itemContainer = linkedItem.GetComponent<ItemContainer>();
if (itemContainer?.Inventory?.Items == null) continue;
availableAmmo.AddRange(itemContainer.Inventory.Items);
}
float chargeRate = powerConsumption <= 0.0f ? 1.0f : batteryCharge / batteryCapacity;
bool charged = batteryCharge * 3600.0f > powerConsumption;
bool readyToFire = reload <= 0.0f && charged && projectiles.Any(p => p != null);
bool readyToFire = reload <= 0.0f && charged && availableAmmo.Any(p => p != null);
if (ShowChargeIndicator && PowerConsumption > 0.0f)
{
powerIndicator.BarSize = chargeRate;
powerIndicator.Color = charged ? Color.Green : Color.Red;
powerIndicator.Draw(spriteBatch);
if (flashLowPower)
{
powerIndicator.BarSize = 1;
powerIndicator.Color *= (float)Math.Sin(flashTimer * 12);
powerIndicator.RectTransform.ChangeScale(Vector2.Lerp(Vector2.One, Vector2.One * 1.01f, 2 * (float)Math.Sin(flashTimer * 15)));
}
else
{
powerIndicator.BarSize = chargeRate;
}
powerIndicator.DrawManually(spriteBatch, true);
int requiredChargeIndicatorPos = (int)((powerConsumption / (batteryCapacity * 3600.0f)) * powerIndicator.Rect.Width);
GUI.DrawRectangle(spriteBatch,
@@ -129,27 +296,33 @@ namespace Barotrauma.Items.Components
{
Point slotSize = new Point(60, 30);
int spacing = 5;
int slotsPerRow = Math.Min(projectiles.Count, 6);
int slotsPerRow = Math.Min(availableAmmo.Count, 6);
int totalWidth = slotSize.X * slotsPerRow + spacing * (slotsPerRow - 1);
Point invSlotPos = new Point(GameMain.GraphicsWidth / 2 - totalWidth / 2, 60);
for (int i = 0; i < projectiles.Count; i++)
for (int i = 0; i < availableAmmo.Count; i++)
{
Inventory.DrawSlot(spriteBatch,
// TODO: Optimize? Creates multiple new classes per frame?
Inventory.DrawSlot(spriteBatch, null,
new InventorySlot(new Rectangle(invSlotPos + new Point((i % slotsPerRow) * (slotSize.X + spacing), (int)Math.Floor(i / (float)slotsPerRow) * (slotSize.Y + spacing)), slotSize)),
projectiles[i] == null ? null : projectiles[i].Item, true);
availableAmmo[i], true);
}
if (flashNoAmmo)
{
Rectangle rect = new Rectangle(invSlotPos.X, invSlotPos.Y, totalWidth, slotSize.Y);
float inflate = MathHelper.Lerp(3, 8, (float)Math.Abs(1 * Math.Sin(flashTimer * 5)));
rect.Inflate(inflate, inflate);
Color color = Color.Red * MathHelper.Max(0.5f, (float)Math.Sin(flashTimer * 12));
GUI.DrawRectangle(spriteBatch, rect, color, thickness: 3);
}
}
if (readyToFire)
if (crosshairSprite != null)
{
if (crosshairSprite != null) crosshairSprite.Draw(spriteBatch, PlayerInput.MousePosition);
}
else
{
if (disabledCrossHairSprite != null) disabledCrossHairSprite.Draw(spriteBatch, PlayerInput.MousePosition);
crosshairSprite.Draw(spriteBatch, crosshairPos, readyToFire ? Color.White : Color.White * 0.2f, 0, (float)Math.Sqrt(cam.Zoom));
}
if (crosshairPointerSprite != null) crosshairPointerSprite.Draw(spriteBatch, crosshairPointerPos, 0, (float)Math.Sqrt(cam.Zoom));
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
UInt16 projectileID = msg.ReadUInt16();