diff --git a/Barotrauma/BarotraumaClient/ClientCode.projitems b/Barotrauma/BarotraumaClient/ClientCode.projitems index 1b79fd2eb..8360a00c7 100644 --- a/Barotrauma/BarotraumaClient/ClientCode.projitems +++ b/Barotrauma/BarotraumaClient/ClientCode.projitems @@ -43,8 +43,13 @@ + + + + + diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index dff098df6..f9fdba9c8 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -243,6 +243,7 @@ PreserveNewest + diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index 864fd5996..667d29d62 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -440,14 +440,15 @@ namespace Barotrauma return; } - //foreach (Limb limb in Limbs) - //{ - // limb.Draw(spriteBatch, cam); - //} + Color? color = null; + if (character.ExternalHighlight) + { + color = Color.Lerp(Color.White, Color.OrangeRed, (float)Math.Sin(Timing.TotalTime * 3.5f)); + } for (int i = 0; i < limbs.Length; i++) { - inversedLimbDrawOrder[i].Draw(spriteBatch, cam); + inversedLimbDrawOrder[i].Draw(spriteBatch, cam, color); } LimbJoints.ForEach(j => j.Draw(spriteBatch)); } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs index 11f6f191c..603769a8e 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs @@ -111,6 +111,33 @@ namespace Barotrauma get { return gibEmitters; } } + public class ObjectiveEntity + { + public Entity Entity; + public Sprite Sprite; + public Color Color; + + public ObjectiveEntity(Entity entity, Sprite sprite, Color? color = null) + { + Entity = entity; + Sprite = sprite; + if (color.HasValue) + { + Color = color.Value; + } + else + { + Color = Color.White; + } + } + } + + private List activeObjectiveEntities = new List(); + public IEnumerable ActiveObjectiveEntities + { + get { return activeObjectiveEntities; } + } + partial void InitProjSpecific(XDocument doc) { soundInterval = doc.Root.GetAttributeFloat("soundinterval", 10.0f); @@ -140,9 +167,6 @@ namespace Barotrauma } } - hudProgressBars = new Dictionary(); - } - partial void UpdateLimbLightSource(Limb limb) { if (limb.LightSource != null) @@ -735,6 +759,20 @@ namespace Barotrauma soundTimer = soundInterval; } + public void AddActiveObjectiveEntity(Entity entity, Sprite sprite, Color? color = null) + { + if (activeObjectiveEntities.Any(aoe => aoe.Entity == entity)) return; + ObjectiveEntity objectiveEntity = new ObjectiveEntity(entity, sprite, color); + activeObjectiveEntities.Add(objectiveEntity); + } + + public void RemoveActiveObjectiveEntity(Entity entity) + { + ObjectiveEntity found = activeObjectiveEntities.Find(aoe => aoe.Entity == entity); + if (found == null) return; + activeObjectiveEntities.Remove(found); + } + partial void ImplodeFX() { Vector2 centerOfMass = AnimController.GetCenterOfMass(); diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs index a2137e660..441ae6a6e 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs @@ -168,7 +168,12 @@ namespace Barotrauma DrawOrderIndicator(spriteBatch, cam, character, character.CurrentOrder, 1.0f); } } - + + foreach (Character.ObjectiveEntity objectiveEntity in character.ActiveObjectiveEntities) + { + DrawObjectiveIndicator(spriteBatch, cam, character, objectiveEntity, 1.0f); + } + foreach (Item brokenItem in brokenItems) { float dist = Vector2.Distance(character.WorldPosition, brokenItem.WorldPosition); @@ -371,5 +376,13 @@ namespace Barotrauma orderIndicatorCount[target] = orderIndicatorCount[target] + 1; } + + private static void DrawObjectiveIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Character.ObjectiveEntity objectiveEntity, float iconAlpha = 1.0f) + { + if (objectiveEntity == null) return; + + Vector2 drawPos = objectiveEntity.Entity.WorldPosition;// + Vector2.UnitX * objectiveEntity.Sprite.size.X * 1.5f; + GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, objectiveEntity.Sprite, objectiveEntity.Color * iconAlpha); + } } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs index 3799e1756..34ebcb336 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Health/CharacterHealth.cs @@ -136,6 +136,17 @@ namespace Barotrauma } } + public GUIButton CPRButton + { + get { return cprButton; } + } + + public float HealthBarPulsateTimer + { + get { return healthBarPulsateTimer; } + set { healthBarPulsateTimer = MathHelper.Clamp(value, 0.0f, 10.0f); } + } + static CharacterHealth() { damageOverlay = new Sprite("Content/UI/damageOverlay.png", Vector2.Zero); diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs index dddd37a0f..90d96a1dd 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs @@ -129,6 +129,8 @@ namespace Barotrauma get { return pauseMenuOpen; } } + public static bool PreventPauseMenuToggle = false; + public static Color ScreenOverlayColor { get; @@ -1413,6 +1415,7 @@ namespace Barotrauma public static void TogglePauseMenu() { if (Screen.Selected == GameMain.MainMenuScreen) return; + if (PreventPauseMenuToggle) return; settingsMenuOpen = false; @@ -1546,9 +1549,16 @@ namespace Barotrauma if (GameMain.GameSession != null) { - if (ContextualTutorial.Initialized && GameMain.GameSession.GameMode is SinglePlayerCampaign) + if (Tutorial.Initialized) { - ((SinglePlayerCampaign)GameMain.GameSession.GameMode).ContextualTutorial.Stop(); + if (GameMain.GameSession.GameMode is SinglePlayerCampaign) + { + ((SinglePlayerCampaign)GameMain.GameSession.GameMode).ContextualTutorial.Stop(); + } + else + { + ((TutorialMode)GameMain.GameSession.GameMode).Tutorial.Stop(); + } } if (GameSettings.SendUserStatistics) diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIButton.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIButton.cs index e9046010b..05e991ab8 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIButton.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIButton.cs @@ -174,6 +174,11 @@ namespace Barotrauma if (frame != null) frame.ApplyStyle(style); } + public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectInflate = null) + { + Frame.Flash(color, flashDuration, useRectangleFlash, flashRectInflate); + } + protected override void Draw(SpriteBatch spriteBatch) { //do nothing diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs index ddea12a60..1c546467b 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIComponent.cs @@ -121,77 +121,22 @@ namespace Barotrauma protected Color selectedColor; protected Color pressedColor; + private CoroutineHandle pulsateCoroutine; + protected ComponentState state; protected Color flashColor; protected float flashDuration = 1.5f; + private bool useRectangleFlash; + public float FlashTimer + { + get { return flashTimer; } + } protected float flashTimer; private Vector2 flashRectInflate; public bool IgnoreLayoutGroups; - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - - public bool IgnoreLayoutGroups; - public virtual ScalableFont Font { get; @@ -324,6 +269,8 @@ namespace Barotrauma set { pressedColor = value; } } + public bool ExternalHighlight = false; + private RectTransform rectTransform; public RectTransform RectTransform { @@ -496,11 +443,21 @@ namespace Barotrauma int flashCycleCount = (int)Math.Max(flashDuration, 1); float flashCycleDuration = flashDuration / flashCycleCount; + Rectangle flashRect = Rect; + flashRect.Inflate(flashRectInflate.X, flashRectInflate.Y); + //MathHelper.Pi * 0.8f -> the curve goes from 144 deg to 0, //i.e. quickly bumps up from almost full brightness to full and then fades out - GUI.UIGlow.Draw(spriteBatch, - rect, - flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f)); + if (!useRectangleFlash) + { + GUI.UIGlow.Draw(spriteBatch, + flashRect, + flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f)); + } + else + { + GUI.DrawRectangle(spriteBatch, flashRect, flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), true); + } } } @@ -525,6 +482,7 @@ namespace Barotrauma toolTipBlock.WrappedText.Split('\n').Length * 18 + 7); toolTipBlock.userData = toolTip; } + toolTipBlock.SetTextPos(); toolTipBlock.RectTransform.AbsoluteOffset = new Point(targetElement.Center.X, targetElement.Bottom); if (toolTipBlock.Rect.Right > GameMain.GraphicsWidth - 10) @@ -548,9 +506,11 @@ namespace Barotrauma color = new Color(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, a); } - public virtual void Flash(Color? color = null, float flashDuration = 1.5f) + public virtual void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectInflate = null) { flashTimer = flashDuration; + this.flashRectInflate = flashRectInflate ?? Vector2.Zero; + this.useRectangleFlash = useRectangleFlash; this.flashDuration = flashDuration; flashColor = (color == null) ? Color.Red : (Color)color; } @@ -568,12 +528,9 @@ namespace Barotrauma while (t < duration) { t += CoroutineManager.DeltaTime; - SetAlpha(MathHelper.Lerp(startA, to, t / duration)); - yield return CoroutineStatus.Running; } - toolTipBlock.SetTextPos(); SetAlpha(to); @@ -584,9 +541,31 @@ namespace Barotrauma yield return CoroutineStatus.Success; } + + public void Pulsate(Vector2 startScale, Vector2 endScale, float duration) + { + if (CoroutineManager.IsCoroutineRunning(pulsateCoroutine)) + { + return; + } + pulsateCoroutine = CoroutineManager.StartCoroutine(DoPulsate(startScale, endScale, duration), "Pulsate" + ToString()); + } + + private IEnumerable DoPulsate(Vector2 startScale, Vector2 endScale, float duration) + { + float t = 0.0f; + while (t < duration) + { + t += CoroutineManager.DeltaTime; + RectTransform.LocalScale = Vector2.Lerp(startScale, endScale, (float)Math.Sin(t / duration * MathHelper.Pi)); + yield return CoroutineStatus.Running; + } + RectTransform.LocalScale = startScale; + yield return CoroutineStatus.Success; + } #endregion - protected virtual void SetAlpha(float a) + public virtual void ApplyStyle(GUIComponentStyle style) { if (style == null) return; @@ -599,11 +578,7 @@ namespace Barotrauma OutlineColor = style.OutlineColor; - public virtual void Flash(Color? color = null, float flashDuration = 1.5f) - { - flashTimer = flashDuration; - this.flashDuration = flashDuration; - flashColor = (color == null) ? Color.Red : (Color)color; + this.style = style; } } } diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIMessageBox.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIMessageBox.cs index 4c3dcaf2a..e98b78b2e 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIMessageBox.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIMessageBox.cs @@ -227,6 +227,12 @@ namespace Barotrauma Content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), InnerFrame.RectTransform, Anchor.Center)) { AbsoluteSpacing = 5 }; Tag = tag; + InnerFrame = new GUIFrame(new RectTransform(new Point(width, height), RectTransform, Anchor.Center) { IsFixedSize = false }, style: null); + GUI.Style.Apply(InnerFrame, "", this); + + Content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), InnerFrame.RectTransform, Anchor.Center)) { AbsoluteSpacing = 5 }; + Tag = tag; + if (height == 0) { string wrappedText = ToolBox.WrapText(text, Content.Rect.Width, GUI.Font); diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs index 73fcd1b3a..886e5aa2c 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUITextBox.cs @@ -365,9 +365,9 @@ namespace Barotrauma OnDeselected?.Invoke(this, Keys.None); } - public override void Flash(Color? color = null, float flashDuration = 1.5f) + public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, Vector2? flashRectOffset = null) { - textBlock.Flash(color, flashDuration); + textBlock.Flash(color, flashDuration, useRectangleFlash, flashRectOffset); } protected override void Update(float deltaTime) diff --git a/Barotrauma/BarotraumaClient/Source/GUI/VideoPlayer.cs b/Barotrauma/BarotraumaClient/Source/GUI/VideoPlayer.cs index bb327ac69..ea9adc6f3 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/VideoPlayer.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/VideoPlayer.cs @@ -10,9 +10,10 @@ namespace Barotrauma { class VideoPlayer { + public bool IsPlaying; + private Video currentVideo; private string filePath; - private bool isPlaying; private GUIFrame background, videoFrame, textFrame; private GUITextBlock title, textContent, objectiveTitle, objectiveText; @@ -24,12 +25,14 @@ namespace Barotrauma private Point scaledVideoResolution; private readonly int borderSize = 20; - private readonly Point buttonSize = new Point(160, 50); + private readonly Point buttonSize = new Point(120, 30); private readonly int titleHeight = 30; private readonly int objectiveFrameHeight = 60; private readonly int textHeight = 25; - public struct TextSettings + private bool useTextOnRightSide = false; + + public class TextSettings { public string Text; public int Width; @@ -41,7 +44,7 @@ namespace Barotrauma } } - public struct VideoSettings + public class VideoSettings { public string File; @@ -62,7 +65,14 @@ namespace Barotrauma background = new GUIFrame(new RectTransform(Point.Zero, GUI.Canvas, Anchor.Center), "InnerFrame", backgroundColor); videoFrame = new GUIFrame(new RectTransform(Point.Zero, background.RectTransform, Anchor.Center, Pivot.Center), "SonarFrame"); - textFrame = new GUIFrame(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), "TextFrame"); + if (useTextOnRightSide) + { + textFrame = new GUIFrame(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), "TextFrame"); + } + else + { + textFrame = new GUIFrame(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), "TextFrame"); + } videoView = new GUICustomComponent(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.Center), (spriteBatch, guiCustomComponent) => { DrawVideo(spriteBatch, guiCustomComponent.Rect); }); title = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft), string.Empty, font: GUI.VideoTitleFont, textColor: new Color(253, 174, 0), textAlignment: Alignment.Left); @@ -70,7 +80,7 @@ namespace Barotrauma textContent = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft), string.Empty, font: GUI.Font, textAlignment: Alignment.TopLeft); objectiveTitle = new GUITextBlock(new RectTransform(new Vector2(1f, 0f), textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight, textColor: Color.White); - objectiveTitle.Text = TextManager.Get("NewObjective"); + objectiveTitle.Text = TextManager.Get("Tutorial.NewObjective"); objectiveText = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveNameFont, textColor: new Color(4, 180, 108), textAlignment: Alignment.CenterRight); objectiveTitle.Visible = objectiveText.Visible = false; @@ -78,12 +88,12 @@ namespace Barotrauma public void Play() { - isPlaying = true; + IsPlaying = true; } public void Stop() { - isPlaying = false; + IsPlaying = false; if (currentVideo == null) return; currentVideo.Dispose(); currentVideo = null; @@ -99,13 +109,6 @@ namespace Barotrauma public void Update() { if (currentVideo == null) return; - - if (PlayerInput.KeyHit(Keys.Enter) || PlayerInput.KeyHit(Keys.Escape)) - { - DisposeVideo(null, null); - return; - } - if (currentVideo.IsPlaying) return; currentVideo.Dispose(); @@ -115,7 +118,7 @@ namespace Barotrauma public void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0) { - if (!isPlaying) return; + if (!IsPlaying) return; background.AddToGUIUpdateList(ignoreChildren, order); } @@ -139,7 +142,7 @@ namespace Barotrauma currentVideo = CreateVideo(scaledVideoResolution); title.Text = TextManager.Get(contentId); - textContent.Text = textSettings.Text; + textContent.Text = textSettings != null ? textSettings.Text : string.Empty; objectiveText.Text = objective; AdjustFrames(videoSettings, textSettings); @@ -165,7 +168,8 @@ namespace Barotrauma title.TextScale = textContent.TextScale = objectiveText.TextScale = objectiveTitle.TextScale = GUI.Scale; int scaledBorderSize = (int)(borderSize * GUI.Scale); - int scaledTextWidth = (int)(textSettings.Width * GUI.Scale); + int scaledTextWidth = 0; + if (textSettings != null) scaledTextWidth = useTextOnRightSide ? (int)(textSettings.Width * GUI.Scale) : scaledVideoResolution.X / 2; int scaledTitleHeight = (int)(titleHeight * GUI.Scale); int scaledTextHeight = (int)(textHeight * GUI.Scale); int scaledObjectiveFrameHeight = (int)(objectiveFrameHeight * GUI.Scale); @@ -180,13 +184,21 @@ namespace Barotrauma title.RectTransform.NonScaledSize += new Point(scaledTextWidth, scaledTitleHeight); title.RectTransform.AbsoluteOffset = new Point((int)(5 * GUI.Scale), (int)(10 * GUI.Scale)); - if (!string.IsNullOrEmpty(textSettings.Text)) + if (textSettings != null && !string.IsNullOrEmpty(textSettings.Text)) { textSettings.Text = ToolBox.WrapText(textSettings.Text, scaledTextWidth, GUI.Font); int wrappedHeight = textSettings.Text.Split('\n').Length * scaledTextHeight; textFrame.RectTransform.NonScaledSize += new Point(scaledTextWidth + scaledBorderSize, wrappedHeight + scaledBorderSize + scaledButtonSize.Y + scaledTitleHeight); - textFrame.RectTransform.AbsoluteOffset = new Point(scaledVideoResolution.X + scaledBorderSize * 2, 0); + + if (useTextOnRightSide) + { + textFrame.RectTransform.AbsoluteOffset = new Point(scaledVideoResolution.X + scaledBorderSize * 2, 0); + } + else + { + textFrame.RectTransform.AbsoluteOffset = new Point(0, scaledVideoResolution.Y + scaledBorderSize * 2); + } textContent.RectTransform.NonScaledSize += new Point(scaledTextWidth, wrappedHeight); textContent.RectTransform.AbsoluteOffset = new Point(0, scaledBorderSize + scaledTitleHeight); @@ -209,22 +221,41 @@ namespace Barotrauma objectiveTitle.Visible = objectiveText.Visible = false; } - int totalFrameWidth = videoFrame.Rect.Width + textFrame.Rect.Width + scaledBorderSize * 2; - int xOffset = videoFrame.Rect.Width / 2 + scaledBorderSize - (videoFrame.Rect.Width / 2 - textFrame.Rect.Width / 2); - - - videoFrame.RectTransform.AbsoluteOffset = new Point(-xOffset, (int)(50 * GUI.Scale)); - if (okButton != null) { textFrame.RemoveChild(okButton); okButton = null; } - okButton = new GUIButton(new RectTransform(scaledButtonSize, textFrame.RectTransform, Anchor.BottomRight, Pivot.BottomRight) { AbsoluteOffset = new Point(scaledBorderSize, scaledBorderSize) }, TextManager.Get("OK")) + if (textSettings != null) { - OnClicked = DisposeVideo - }; + if (useTextOnRightSide) + { + int totalFrameWidth = videoFrame.Rect.Width + textFrame.Rect.Width + scaledBorderSize * 2; + int xOffset = videoFrame.Rect.Width / 2 + scaledBorderSize - (videoFrame.Rect.Width / 2 - textFrame.Rect.Width / 2); + videoFrame.RectTransform.AbsoluteOffset = new Point(-xOffset, (int)(50 * GUI.Scale)); + } + else + { + int totalFrameHeight = videoFrame.Rect.Height + textFrame.Rect.Height + scaledBorderSize * 2; + int yOffset = videoFrame.Rect.Height / 2 + scaledBorderSize - (videoFrame.Rect.Height / 2 - textFrame.Rect.Height / 2); + videoFrame.RectTransform.AbsoluteOffset = new Point(0, -yOffset); + } + + okButton = new GUIButton(new RectTransform(scaledButtonSize, textFrame.RectTransform, Anchor.BottomRight, Pivot.BottomRight) { AbsoluteOffset = new Point(scaledBorderSize, scaledBorderSize) }, TextManager.Get("OK")) + { + OnClicked = DisposeVideo + }; + } + else + { + videoFrame.RectTransform.AbsoluteOffset = new Point(0, (int)(100 * GUI.Scale)); + + okButton = new GUIButton(new RectTransform(scaledButtonSize, videoFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(scaledBorderSize, scaledBorderSize) }, TextManager.Get("Back")) + { + OnClicked = DisposeVideo + }; + } } private Video CreateVideo(Point resolution) @@ -245,7 +276,7 @@ namespace Barotrauma private void DrawVideo(SpriteBatch spriteBatch, Rectangle rect) { - if (!isPlaying) return; + if (!IsPlaying) return; spriteBatch.Draw(currentVideo.GetTexture(), rect, Color.White); } diff --git a/Barotrauma/BarotraumaClient/Source/GameMain.cs b/Barotrauma/BarotraumaClient/Source/GameMain.cs index 5ab2690c5..542ee3cf1 100644 --- a/Barotrauma/BarotraumaClient/Source/GameMain.cs +++ b/Barotrauma/BarotraumaClient/Source/GameMain.cs @@ -623,8 +623,12 @@ namespace Barotrauma { ((GUIMessageBox)GUIMessageBox.VisibleBox).Close(); } + else if (Tutorial.Initialized && Tutorial.ContentRunning) + { + (GameMain.GameSession.GameMode as TutorialMode).Tutorial.CloseActiveContentGUI(); + } else if ((Character.Controlled?.SelectedConstruction == null || !Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null)) - && Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null) + && Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null) { // Otherwise toggle pausing, unless another window/interface is open. GUI.TogglePauseMenu(); @@ -632,7 +636,7 @@ namespace Barotrauma } GUI.ClearUpdateList(); - paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || ContextualTutorial.ContentRunning) && + paused = (DebugConsole.IsOpen || GUI.PauseMenuOpen || GUI.SettingsMenuOpen || Tutorial.ContentRunning) && (NetworkMember == null || !NetworkMember.GameStarted); Screen.Selected.AddToGUIUpdateList(); @@ -651,9 +655,9 @@ namespace Barotrauma { Screen.Selected.Update(Timing.Step); } - else if (ContextualTutorial.Initialized && ContextualTutorial.ContentRunning && GameSession.GameMode is SinglePlayerCampaign) + else if (Tutorial.Initialized && Tutorial.ContentRunning) { - (GameSession.GameMode as SinglePlayerCampaign).ContextualTutorial.Update((float)Timing.Step); + (GameSession.GameMode as TutorialMode).Update((float)Timing.Step); } if (NetworkMember != null) diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs index ddad8bfd9..0c0696af7 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs @@ -49,6 +49,8 @@ namespace Barotrauma private GUIComponent orderTargetFrame, orderTargetFrameShadow; + public bool AllowCharacterSwitch = true; + public bool ToggleCrewAreaOpen { get { return toggleCrewAreaOpen; } @@ -63,6 +65,8 @@ namespace Barotrauma } } + public List OrderOptionButtons = new List(); + #endregion #region Constructors @@ -98,6 +102,20 @@ namespace Barotrauma CanBeFocused = false }; + scrollButtonUp = new GUIButton(new RectTransform(scrollButtonSize, crewArea.RectTransform, Anchor.TopLeft, Pivot.TopLeft), "", Alignment.Center, "GUIButtonVerticalArrow") + { + Visible = false, + UserData = -1, + OnClicked = ScrollCharacterList + }; + scrollButtonDown = new GUIButton(new RectTransform(scrollButtonSize, crewArea.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft), "", Alignment.Center, "GUIButtonVerticalArrow") + { + Visible = false, + UserData = 1, + OnClicked = ScrollCharacterList + }; + scrollButtonDown.Children.ForEach(c => c.SpriteEffects = SpriteEffects.FlipVertically); + var characterInfo = new CharacterInfo(subElement); characterInfos.Add(characterInfo); foreach (XElement invElement in subElement.Elements()) @@ -159,6 +177,16 @@ namespace Barotrauma ToggleCrewAreaOpen = GameMain.Config.CrewMenuOpen; } + + #endregion + + #region Character list management + + public Rectangle GetCharacterListArea() + { + return characterListBox.Rect; + } + partial void InitProjectSpecific() { guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent) @@ -547,7 +575,10 @@ namespace Barotrauma orderButtonFrame.RectTransform; var btn = new GUIButton(new RectTransform(new Point(iconSize, iconSize), btnParent, Anchor.CenterLeft), - style: null); + style: null) + { + UserData = order + }; new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "OuterGlow") { @@ -639,6 +670,7 @@ namespace Barotrauma /// public bool CharacterClicked(GUIComponent component, object selection) { + if (!AllowCharacterSwitch) { return false; } Character character = selection as Character; if (character == null || character.IsDead || character.IsUnconscious) return false; SelectCharacter(character); @@ -679,8 +711,33 @@ namespace Barotrauma { characterListBox.BarScroll = roundedPos; } + } - return false; + public void AddCharacterInfo(CharacterInfo characterInfo) + { + if (characterInfos.Contains(characterInfo)) + { + DebugConsole.ThrowError("Tried to add the same character info to CrewManager twice.\n" + Environment.StackTrace); + return; + } + + characterInfos.Add(characterInfo); + } + + /// + /// Remove the character from the crew (and crew menus). + /// + /// The character to remove + /// If the character info is also removed, the character will not be visible in the round summary. + public void RemoveCharacter(Character character, bool removeInfo = false) + { + if (character == null) + { + DebugConsole.ThrowError("Tried to remove a null character from CrewManager.\n" + Environment.StackTrace); + return; + } + characters.Remove(character); + if (removeInfo) characterInfos.Remove(character.Info); } private IEnumerable KillCharacterAnim(GUIComponent component) @@ -881,6 +938,22 @@ namespace Barotrauma } } } + + character.SetOrder(order, option, orderGiver, speak: orderGiver != character); + if (IsSinglePlayer) + { + orderGiver?.Speak( + order.GetChatMessage(character.Name, orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option), null); + } + else if (orderGiver != null) + { + OrderChatMessage msg = new OrderChatMessage(order, option, order.TargetItemComponent?.Item, character, orderGiver); + if (GameMain.Client != null) + { + GameMain.Client.SendChatMessage(msg); + } + } + DisplayCharacterOrder(character, order); } /// @@ -982,9 +1055,12 @@ namespace Barotrauma if (Character.Controlled == null) return false; SetCharacterOrder(character, userData as Order, option, Character.Controlled); orderTargetFrame = null; + OrderOptionButtons.Clear(); return true; } }; + + OrderOptionButtons.Add(optionButton); } } @@ -1017,9 +1093,13 @@ namespace Barotrauma if (Character.Controlled == null) return false; SetCharacterOrder(character, userData as Order, option, Character.Controlled); orderTargetFrame = null; + OrderOptionButtons.Clear(); return true; } }; + + OrderOptionButtons.Add(optionButton); + //lines between the order buttons if (i < order.Options.Length - 1) { @@ -1035,6 +1115,24 @@ namespace Barotrauma color: matchingItems.Count > 1 ? Color.Black * 0.9f : Color.Black * 0.7f); } + public void HighlightOrderButton(Character character, string orderAiTag, Color color, Vector2? flashRectInflate = null) + { + var order = Order.PrefabList.Find(o => o.AITag == orderAiTag); + if (order == null) + { + DebugConsole.ThrowError("Could not find an order with the AI tag \"" + orderAiTag + "\".\n" + Environment.StackTrace); + return; + } + var characterElement = characterListBox.Content.FindChild(character); + GUIButton orderBtn = characterElement.FindChild(order, recursive: true) as GUIButton; + if (orderBtn.Frame.FlashTimer <= 0) + { + orderBtn.Flash(color, 1.5f, false, flashRectInflate); + } + + //orderBtn.Pulsate(Vector2.One, Vector2.One * 2.0f, 1.5f); + } + #region Updating and drawing the UI private void DrawMiniMapOverlay(SpriteBatch spriteBatch, GUICustomComponent container) @@ -1092,6 +1190,7 @@ namespace Barotrauma public void SelectNextCharacter() { + if (!AllowCharacterSwitch) { return; } if (GameMain.IsMultiplayer) { return; } if (characters.None()) { return; } SelectCharacter(characters[TryAdjustIndex(1)]); @@ -1099,6 +1198,7 @@ namespace Barotrauma public void SelectPreviousCharacter() { + if (!AllowCharacterSwitch) { return; } if (GameMain.IsMultiplayer) { return; } if (characters.None()) { return; } SelectCharacter(characters[TryAdjustIndex(-1)]); @@ -1106,6 +1206,7 @@ namespace Barotrauma private void SelectCharacter(Character character) { + if (!AllowCharacterSwitch) { return; } //make the previously selected character wait in place for some time //(so they don't immediately start idling and walking away from their station) if (Character.Controlled?.AIController?.ObjectiveManager != null) diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs index 95f619e22..0a0677484 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs @@ -303,7 +303,7 @@ namespace Barotrauma.Tutorials yield return new WaitForSeconds(1.0f); - infoBox = CreateInfoFrame("Uh-oh... Something enormous just appeared on the sonar."); + infoBox = CreateInfoFrame("", "Uh-oh... Something enormous just appeared on the sonar."); List windows = new List(); foreach (Structure s in Structure.WallList) diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs index d8ac5bc80..b883c43ed 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ContextualTutorial.cs @@ -4,22 +4,12 @@ using System; using Microsoft.Xna.Framework; using Barotrauma.Items.Components; using System.Linq; -using Microsoft.Xna.Framework.Input; namespace Barotrauma.Tutorials { class ContextualTutorial : Tutorial { public static bool Selected = false; - public static bool ContentRunning = false; - public static bool Initialized = false; - - private enum ContentTypes { None = 0, Video = 1, TextOnly = 2 }; - - private TutorialSegment activeSegment; - private List segments; - - private VideoPlayer videoPlayer; private Steering navConsole; private Reactor reactor; @@ -33,83 +23,29 @@ namespace Barotrauma.Tutorials private List> characterTimeOnSonar; private float requiredTimeOnSonar = 5f; - private bool started = false; - private string playableContentPath; - private float tutorialTimer; private bool disableTutorialOnDeficiencyFound = true; - private GUIFrame holderFrame, objectiveFrame; - private List activeObjectives = new List(); - private string objectiveTranslated; - private float floodTutorialTimer = 0.0f; private const float floodTutorialDelay = 2.0f; private float medicalTutorialTimer = 0.0f; private const float medicalTutorialDelay = 2.0f; - private Point screenResolution; - private float prevUIScale; - - private class TutorialSegment - { - public string Id; - public string Objective; - public ContentTypes ContentType; - public XElement TextContent; - public XElement VideoContent; - public bool IsTriggered; - public GUIButton ReplayButton; - public GUITextBlock LinkedTitle, LinkedText; - - public TutorialSegment(XElement config) - { - Id = config.GetAttributeString("id", "Missing ID"); - Objective = TextManager.Get(config.GetAttributeString("objective", string.Empty), true); - Enum.TryParse(config.GetAttributeString("contenttype", "None"), true, out ContentType); - IsTriggered = config.GetAttributeBool("istriggered", false); - - switch (ContentType) - { - case ContentTypes.None: - break; - case ContentTypes.Video: - VideoContent = config.Element("Video"); - TextContent = config.Element("Text"); - break; - case ContentTypes.TextOnly: - TextContent = config.Element("Text"); - break; - } - } - } - public ContextualTutorial(XElement element) : base(element) { - playableContentPath = element.GetAttributeString("playablecontentpath", ""); - segments = new List(); - - foreach (var segment in element.Elements("Segment")) - { - segments.Add(new TutorialSegment(segment)); - } - Name = "ContextualTutorial"; } public override void Initialize() { + base.Initialize(); + for (int i = 0; i < segments.Count; i++) { segments[i].IsTriggered = false; } - if (Initialized) return; - Initialized = true; - - base.Initialize(); - videoPlayer = new VideoPlayer(); characterTimeOnSonar = new List>(); } @@ -167,10 +103,7 @@ namespace Barotrauma.Tutorials base.Start(); injuredMember = null; - activeObjectives.Clear(); - objectiveTranslated = TextManager.Get("Objective"); - CreateObjectiveFrame(); - activeSegment = null; + activeContentSegment = null; tutorialTimer = floodTutorialTimer = medicalTutorialTimer = 0.0f; subStartingPosition = Vector2.Zero; characterTimeOnSonar.Clear(); @@ -183,10 +116,10 @@ namespace Barotrauma.Tutorials #if DEBUG if (reactor == null || navConsole == null || sonar == null) { - infoBox = CreateInfoFrame("Submarine not compatible with the tutorial:" + infoBox = CreateInfoFrame("Error", "Submarine not compatible with the tutorial:" + "\nReactor - " + (reactor != null ? "OK" : "Tag 'reactor' not found") + "\nNavigation Console - " + (navConsole != null ? "OK" : "Tag 'command' not found") - + "\nSonar - " + (sonar != null ? "OK" : "Not found under Navigation Console"), true); + + "\nSonar - " + (sonar != null ? "OK" : "Not found under Navigation Console"), hasButton: true); CoroutineManager.StartCoroutine(WaitForErrorClosed()); return; } @@ -222,62 +155,15 @@ namespace Barotrauma.Tutorials } #endif - public void Stop() + public override void Stop() { - started = ContentRunning = Initialized = false; - videoPlayer.Remove(); - videoPlayer = null; + base.Stop(); characterTimeOnSonar = null; } - private void CreateObjectiveFrame() - { - holderFrame = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center)); - objectiveFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ObjectiveAnchor, holderFrame.RectTransform), style: null); - - for (int i = 0; i < activeObjectives.Count; i++) - { - CreateObjectiveGUI(activeObjectives[i], i); - } - - screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight); - prevUIScale = GUI.Scale; - } - - public override void AddToGUIUpdateList() - { - if (videoPlayer != null) - { - videoPlayer.AddToGUIUpdateList(order: 100); - } - - if (GUI.DisableHUD) return; - if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale) - { - CreateObjectiveFrame(); - } - - if (objectiveFrame != null && activeObjectives.Count > 0) - { - objectiveFrame.AddToGUIUpdateList(order: -1); - } - base.AddToGUIUpdateList(); - } - public override void Update(float deltaTime) { - if (videoPlayer != null) - { - videoPlayer.Update(); - } - - if (infoBox != null) - { - if (PlayerInput.KeyHit(Keys.Enter) || PlayerInput.KeyHit(Keys.Escape)) - { - CloseInfoFrame(null, null); - } - } + base.Update(deltaTime); if (!started || ContentRunning) return; @@ -285,93 +171,12 @@ namespace Barotrauma.Tutorials for (int i = 0; i < segments.Count; i++) { - if (segments[i].IsTriggered || activeObjectives.Contains(segments[i])) continue; + if (segments[i].IsTriggered || HasObjective(segments[i])) continue; if (CheckContextualTutorials(i, deltaTime)) // Found a relevant tutorial, halt finding new ones { break; } } - - for (int i = 0; i < activeObjectives.Count; i++) - { - CheckActiveObjectives(activeObjectives[i], deltaTime); - } - } - - private void ClosePreTextAndTriggerVideoCallback() - { - videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(activeSegment.VideoContent), new VideoPlayer.TextSettings(activeSegment.VideoContent), activeSegment.Id, true, activeSegment.Objective, CurrentSegmentStopCallback); - } - - private void CurrentSegmentStopCallback() - { - if (!string.IsNullOrEmpty(activeSegment.Objective)) - { - AddNewObjective(activeSegment); - } - - activeSegment = null; - ContentRunning = false; - } - - private void AddNewObjective(TutorialSegment segment) - { - activeObjectives.Add(segment); - CreateObjectiveGUI(segment, activeObjectives.Count - 1); - } - - private void CreateObjectiveGUI(TutorialSegment segment, int index) - { - Point replayButtonSize = new Point((int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).X * GUI.Scale), (int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).Y * 1.45f * GUI.Scale)); - - segment.ReplayButton = new GUIButton(new RectTransform(replayButtonSize, objectiveFrame.RectTransform, Anchor.TopRight, Pivot.TopRight) { AbsoluteOffset = new Point(0, (replayButtonSize.Y + (int)(20f * GUI.Scale)) * index) }, style: null); - segment.ReplayButton.OnClicked += (GUIButton btn, object userdata) => - { - ReplaySegmentVideo(segment); - return true; - }; - - int yOffset = (int)((GUI.ObjectiveNameFont.MeasureString(objectiveTranslated).Y / 2f + 5) * GUI.Scale); - segment.LinkedTitle = new GUITextBlock(new RectTransform(new Point(replayButtonSize.X, yOffset), segment.ReplayButton.RectTransform, Anchor.Center, Pivot.BottomCenter) { AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }, objectiveTranslated, textColor: Color.White, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight); - segment.LinkedText = new GUITextBlock(new RectTransform(new Point(replayButtonSize.X, yOffset), segment.ReplayButton.RectTransform, Anchor.Center, Pivot.TopCenter) { AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }, segment.Objective, textColor: new Color(4, 180, 108), font: GUI.ObjectiveNameFont, textAlignment: Alignment.CenterRight); - - segment.LinkedTitle.TextScale = segment.LinkedText.TextScale = GUI.Scale; - - segment.LinkedTitle.Color = segment.LinkedTitle.HoverColor = segment.LinkedTitle.PressedColor = segment.LinkedTitle.SelectedColor = Color.Transparent; - segment.LinkedText.Color = segment.LinkedText.HoverColor = segment.LinkedText.PressedColor = segment.LinkedText.SelectedColor = Color.Transparent; - segment.ReplayButton.Color = segment.ReplayButton.HoverColor = segment.ReplayButton.PressedColor = segment.ReplayButton.SelectedColor = Color.Transparent; - } - - private void RemoveCompletedObjective(TutorialSegment objective) - { - objective.IsTriggered = true; - - int checkMarkHeight = (int)(objective.ReplayButton.Rect.Height * 1.2f); - int checkMarkWidth = (int)(checkMarkHeight * 0.93f); - - Color color = new Color(4, 180, 108); - RectTransform rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), objective.ReplayButton.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft); - rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - 5, 0); - GUIImage checkmark = new GUIImage(rectTA, "CheckMark"); - checkmark.Color = color; - - RectTransform rectTB = new RectTransform(new Vector2(1.1f, .8f), objective.LinkedText.RectTransform, Anchor.Center, Pivot.Center); - GUIImage stroke = new GUIImage(rectTB, "Stroke"); - stroke.Color = color; - - CoroutineManager.StartCoroutine(WaitForObjectiveEnd(objective)); - } - - private IEnumerable WaitForObjectiveEnd(TutorialSegment objective) - { - yield return new WaitForSeconds(2.0f); - objectiveFrame.RemoveChild(objective.ReplayButton); - activeObjectives.Remove(objective); - - for (int i = 0; i < activeObjectives.Count; i++) - { - activeObjectives[i].ReplayButton.RectTransform.AbsoluteOffset = new Point(0, (activeObjectives[i].ReplayButton.Rect.Height + 20) * i); - } } private bool CheckContextualTutorials(int index, float deltaTime) @@ -526,17 +331,7 @@ namespace Barotrauma.Tutorials return true; } - private bool HasObjective(string objectiveName) - { - for (int i = 0; i < activeObjectives.Count; i++) - { - if (activeObjectives[i].Id == objectiveName) return true; - } - - return false; - } - - private void CheckActiveObjectives(TutorialSegment objective, float deltaTime) + protected override void CheckActiveObjectives(TutorialSegment objective, float deltaTime) { switch(objective.Id) { @@ -704,50 +499,9 @@ namespace Barotrauma.Tutorials return characterTimeOnSonar.Find(ct => ct.Second >= requiredTimeOnSonar && !ct.First.IsDead) != null; } - private void TriggerTutorialSegment(int index, params object[] args) + protected override void TriggerTutorialSegment(int index, params object[] args) { - Inventory.draggingItem = null; - ContentRunning = true; - activeSegment = segments[index]; - - string tutorialText = TextManager.GetFormatted(activeSegment.TextContent.GetAttributeString("tag", ""), true, args); - string objectiveText = string.Empty; - - if (!string.IsNullOrEmpty(activeSegment.Objective)) - { - if (args.Length == 0) - { - objectiveText = activeSegment.Objective; - } - else - { - objectiveText = string.Format(activeSegment.Objective, args); - } - - activeSegment.Objective = objectiveText; - } - else - { - activeSegment.IsTriggered = true; // Complete at this stage only if no related objective - } - - switch (activeSegment.ContentType) - { - case ContentTypes.None: - break; - case ContentTypes.Video: - infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Id), tutorialText, - activeSegment.TextContent.GetAttributeInt("width", 300), - activeSegment.TextContent.GetAttributeInt("height", 80), - activeSegment.TextContent.GetAttributeString("anchor", "Center"), true, ClosePreTextAndTriggerVideoCallback); - break; - case ContentTypes.TextOnly: - infoBox = CreateInfoFrame(TextManager.Get(activeSegment.Id), tutorialText, - activeSegment.TextContent.GetAttributeInt("width", 300), - activeSegment.TextContent.GetAttributeInt("height", 80), - activeSegment.TextContent.GetAttributeString("anchor", "Center"), true, CurrentSegmentStopCallback); - break; - } + base.TriggerTutorialSegment(index, args); for (int i = 0; i < segments.Count; i++) { @@ -757,13 +511,6 @@ namespace Barotrauma.Tutorials CoroutineManager.StartCoroutine(WaitToStop()); // Completed } - private void ReplaySegmentVideo(TutorialSegment segment) - { - if (ContentRunning) return; - ContentRunning = true; - videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, callback: () => ContentRunning = false); - } - private IEnumerable WaitToStop() { while (ContentRunning) yield return null; diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs index b372f675b..8ad220618 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/DoctorTutorial.cs @@ -170,7 +170,7 @@ namespace Barotrauma.Tutorials yield return new WaitForSeconds(2.0f); }*/ - TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Select), GameMain.Config.KeyBind(InputType.Deselect)); // Medical supplies objective + TriggerTutorialSegment(0, GameMain.Config.KeyBind(InputType.Use), GameMain.Config.KeyBind(InputType.Deselect)); // Medical supplies objective do { diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/MechanicTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/MechanicTutorial.cs index 6cc78431d..ec272ba98 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/MechanicTutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/MechanicTutorial.cs @@ -508,7 +508,7 @@ namespace Barotrauma.Tutorials mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_2, mechanic_repairIcon, mechanic_repairIconColor); do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_2)); mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_2); - TriggerTutorialSegment(9, GameMain.Config.KeyBind(InputType.Use)); // Repairing machinery (pump) + TriggerTutorialSegment(9, GameMain.Config.KeyBind(InputType.Select)); // Repairing machinery (pump) SetHighlight(mechanic_brokenPump.Item, true); Repairable repairablePumpComponent = mechanic_brokenPump.Item.GetComponent(); do diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ScenarioTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ScenarioTutorial.cs index 025ae979e..cbff14dca 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ScenarioTutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/ScenarioTutorial.cs @@ -1,44 +1,118 @@ -using System; +using Barotrauma.Items.Components; +using Microsoft.Xna.Framework; +using System; using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Xml.Linq; namespace Barotrauma.Tutorials { class ScenarioTutorial : Tutorial { + private CoroutineHandle tutorialCoroutine; + private Character character; + private string spawnSub; private SpawnType spawnPointType; private string submarinePath; + private string startOutpostPath; + private string endOutpostPath; private string levelSeed; + private string levelParams; + + private Submarine startOutpost = null; + private Submarine endOutpost = null; + private bool currentTutorialCompleted = false; + private float fadeOutTime = 3f; + protected float waitBeforeFade = 4f; + + // Colors + protected Color highlightColor = Color.OrangeRed; + protected Color uiHighlightColor = new Color(150, 50, 0); + protected Color buttonHighlightColor = new Color(255, 100, 0); + protected Color inaccessibleColor = Color.Red; + protected Color accessibleColor = Color.Green; public ScenarioTutorial(XElement element) : base(element) { submarinePath = element.GetAttributeString("submarinepath", ""); + startOutpostPath = element.GetAttributeString("startoutpostpath", ""); + endOutpostPath = element.GetAttributeString("endoutpostpath", ""); + levelSeed = element.GetAttributeString("levelseed", "tuto"); - Enum.TryParse(element.GetAttributeString("spawnpointtype", "Human"), true, out spawnPointType); + levelParams = element.GetAttributeString("levelparams", ""); + + spawnSub = element.GetAttributeString("spawnsub", ""); + Enum.TryParse(element.GetAttributeString("spawnpointtype", "Human"), true, out spawnPointType); } public override void Initialize() { base.Initialize(); + currentTutorialCompleted = false; GameMain.Instance.ShowLoading(Loading()); } + private IEnumerable Loading() + { + Submarine.MainSub = Submarine.Load(submarinePath, "", true); + + LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Name == levelParams); + + yield return CoroutineStatus.Running; + + GameMain.GameSession = new GameSession(Submarine.MainSub, "", + GameModePreset.List.Find(g => g.Identifier == "tutorial")); + (GameMain.GameSession.GameMode as TutorialMode).Tutorial = this; + + if (generationParams != null) + { + Biome biome = LevelGenerationParams.GetBiomes().Find(b => generationParams.AllowedBiomes.Contains(b)); + + if (startOutpostPath != string.Empty) + { + startOutpost = Submarine.Load(startOutpostPath, "", false); + } + + if (endOutpostPath != string.Empty) + { + endOutpost = Submarine.Load(endOutpostPath, "", false); + } + + Level tutorialLevel = new Level(levelSeed, 0, 0, generationParams, biome, startOutpost, endOutpost); + GameMain.GameSession.StartRound(tutorialLevel); + } + else + { + GameMain.GameSession.StartRound(levelSeed); + } + + GameMain.GameSession.EventManager.Events.Clear(); + GameMain.GameSession.EventManager.Enabled = false; + GameMain.GameScreen.Select(); + + yield return CoroutineStatus.Success; + } + public override void Start() { base.Start(); - WayPoint wayPoint = WayPoint.GetRandom(spawnPointType, null); + Submarine.MainSub.GodMode = true; + + CharacterInfo charInfo = configElement.Element("Character") == null ? + new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "engineer")) : + new CharacterInfo(configElement.Element("Character")); + + WayPoint wayPoint = GetSpawnPoint(charInfo); + if (wayPoint == null) { DebugConsole.ThrowError("A waypoint with the spawntype \"" + spawnPointType + "\" is required for the tutorial event"); return; } - CharacterInfo charInfo = configElement.Element("Character") == null ? - new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "engineer")) : - new CharacterInfo(configElement.Element("Character")); - character = Character.Create(charInfo, wayPoint.WorldPosition, "", false, false); Character.Controlled = character; character.GiveJobItems(null); @@ -52,22 +126,82 @@ namespace Barotrauma.Tutorials idCard.AddTag("com"); idCard.AddTag("eng"); - CoroutineManager.StartCoroutine(UpdateState()); + tutorialCoroutine = CoroutineManager.StartCoroutine(UpdateState()); } - private IEnumerable Loading() + public override void AddToGUIUpdateList() { - Submarine.MainSub = Submarine.Load(submarinePath, "", true); - yield return CoroutineStatus.Running; + if (!currentTutorialCompleted) + { + base.AddToGUIUpdateList(); + } + } - GameMain.GameSession = new GameSession(Submarine.MainSub, "", - GameModePreset.List.Find(g => g.Identifier == "tutorial")); - (GameMain.GameSession.GameMode as TutorialMode).tutorial = this; - GameMain.GameSession.StartRound(levelSeed); - GameMain.GameSession.EventManager.Events.Clear(); - GameMain.GameScreen.Select(); + private WayPoint GetSpawnPoint(CharacterInfo charInfo) + { + Submarine spawnSub = null; - yield return CoroutineStatus.Success; + if (this.spawnSub != string.Empty) + { + switch (this.spawnSub) + { + case "startoutpost": + spawnSub = startOutpost; + break; + + case "endoutpost": + spawnSub = endOutpost; + break; + + default: + spawnSub = Submarine.MainSub; + break; + } + } + + return WayPoint.GetRandom(spawnPointType, charInfo.Job, spawnSub); + } + + protected bool HasOrder(Character character, string aiTag, string option = null) + { + if (character.CurrentOrder?.AITag == aiTag) + { + if (option == null) + { + return true; + } + else + { + HumanAIController humanAI = character.AIController as HumanAIController; + return humanAI.CurrentOrderOption == option; + } + } + + return false; + } + + protected void SetHighlight(Item item, bool state) + { + if (item.ExternalHighlight == state) return; + item.SpriteColor = (state) ? highlightColor : Color.White; + item.ExternalHighlight = state; + } + + protected void SetHighlight(Structure structure, bool state) + { + structure.SpriteColor = (state) ? highlightColor : Color.White; + structure.ExternalHighlight = state; + } + + protected void SetHighlight(Character character, bool state) + { + character.ExternalHighlight = state; + } + + protected void SetDoorAccess(Door door, LightComponent light, bool state) + { + if (state && door != null) door.requiredItems.Clear(); + if (light != null) light.LightColor = (state) ? accessibleColor : inaccessibleColor; } public override void Update(float deltaTime) @@ -75,27 +209,47 @@ namespace Barotrauma.Tutorials base.Update(deltaTime); if (character != null) { - if (Character.Controlled == null) + if (character.Oxygen < 1) { - CoroutineManager.StopCoroutines("TutorialMode.UpdateState"); + character.Oxygen = 1; + } + if (character.IsDead) + { + CoroutineManager.StartCoroutine(Dead()); + } + else if (Character.Controlled == null) + { + if (tutorialCoroutine != null) + { + CoroutineManager.StopCoroutines(tutorialCoroutine); + } infoBox = null; } else if (Character.Controlled.IsDead) { - Character.Controlled = null; - - CoroutineManager.StopCoroutines("TutorialMode.UpdateState"); - infoBox = null; CoroutineManager.StartCoroutine(Dead()); } } } + public override void Stop() + { + if (tutorialCoroutine != null) + { + CoroutineManager.StopCoroutines(tutorialCoroutine); + } + base.Stop(); + } + private IEnumerable Dead() { + GUI.PreventPauseMenuToggle = true; + Character.Controlled = character = null; + Stop(); + yield return new WaitForSeconds(3.0f); - var messageBox = new GUIMessageBox("You have died", "Do you want to try again?", new string[] { "Yes", "No" }); + var messageBox = new GUIMessageBox(TextManager.Get("Tutorial.TryAgainHeader"), TextManager.Get("Tutorial.TryAgain"), new string[] { TextManager.Get("Yes"), TextManager.Get("No") }); messageBox.Buttons[0].OnClicked += Restart; messageBox.Buttons[0].OnClicked += messageBox.Close; @@ -106,5 +260,29 @@ namespace Barotrauma.Tutorials yield return CoroutineStatus.Success; } + + protected IEnumerable TutorialCompleted() + { + GUI.PreventPauseMenuToggle = true; + + Character.Controlled.ClearInputs(); + Character.Controlled = null; + + yield return new WaitForSeconds(waitBeforeFade); + + var endCinematic = new RoundEndCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, fadeOutTime); + currentTutorialCompleted = Completed = true; + while (endCinematic.Running) yield return null; + Stop(); + GameMain.MainMenuScreen.ReturnToMainMenu(null, null); + } + + protected void Heal(Character character) + { + character.SetAllDamage(0.0f, 0.0f, 0.0f); + character.Oxygen = 100.0f; + character.Bloodloss = 0.0f; + character.SetStun(0.0f, true); + } } } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/Tutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/Tutorial.cs index 69a5e98c9..b4f3af7a9 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/Tutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/Tutorial.cs @@ -1,15 +1,23 @@ using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; using System; using System.Collections.Generic; using System.Reflection; +using System.Linq; using System.Xml.Linq; +using Barotrauma.Items.Components; +using Barotrauma.Extensions; namespace Barotrauma.Tutorials { abstract class Tutorial { + #region Tutorial variables + public static bool Initialized = false; + public static bool ContentRunning = false; public static List Tutorials; + protected bool started = false; protected GUIComponent infoBox; private Action infoBoxClosedCallback; protected XElement configElement; @@ -17,6 +25,54 @@ namespace Barotrauma.Tutorials private enum TutorialType { None, Scenario, Contextual }; private TutorialType tutorialType = TutorialType.None; + protected VideoPlayer videoPlayer; + protected enum TutorialContentTypes { None = 0, Video = 1, ManualVideo = 2, TextOnly = 3 }; + protected string playableContentPath; + protected Point screenResolution; + protected float prevUIScale; + + private GUIFrame holderFrame, objectiveFrame; + private List activeObjectives = new List(); + private string objectiveTranslated; + + protected TutorialSegment activeContentSegment; + protected List segments; + + protected class TutorialSegment + { + public string Id; + public string Objective; + public TutorialContentTypes ContentType; + public XElement TextContent; + public XElement VideoContent; + public bool IsTriggered; + public GUIButton ReplayButton; + public GUITextBlock LinkedTitle, LinkedText; + public object[] Args; + + public TutorialSegment(XElement config) + { + Id = config.GetAttributeString("id", "Missing ID"); + Objective = TextManager.Get(config.GetAttributeString("objective", string.Empty), true); + Enum.TryParse(config.GetAttributeString("contenttype", "None"), true, out ContentType); + IsTriggered = config.GetAttributeBool("istriggered", false); + + switch (ContentType) + { + case TutorialContentTypes.None: + break; + case TutorialContentTypes.Video: + case TutorialContentTypes.ManualVideo: + VideoContent = config.Element("Video"); + TextContent = config.Element("Text"); + break; + case TutorialContentTypes.TextOnly: + TextContent = config.Element("Text"); + break; + } + } + } + public string Name { get; @@ -34,7 +90,9 @@ namespace Barotrauma.Tutorials GameMain.Config.SaveNewPlayerConfig(); } } + #endregion + #region Tutorial Controls public static void Init() { Tutorials = new List(); @@ -107,26 +165,85 @@ namespace Barotrauma.Tutorials Name = element.GetAttributeString("name", "Unnamed"); completed = GameMain.Config.CompletedTutorialNames.Contains(Name); Enum.TryParse(element.GetAttributeString("tutorialtype", "Scenario"), true, out tutorialType); + playableContentPath = element.GetAttributeString("playablecontentpath", ""); + + segments = new List(); + + foreach (var segment in element.Elements("Segment")) + { + segments.Add(new TutorialSegment(segment)); + } } public virtual void Initialize() { - + if (Initialized) return; + Initialized = true; + videoPlayer = new VideoPlayer(); } public virtual void Start() { - + activeObjectives.Clear(); + objectiveTranslated = TextManager.Get("Tutorial.Objective"); + CreateObjectiveFrame(); + + // Setup doors: Clear all requirements, unless the door is setup as locked. + foreach (var item in Item.ItemList) + { + var door = item.GetComponent(); + if (door != null) + { + if (door.requiredItems.Values.None(ris => ris.None(ri => ri.Identifiers.None(i => i == "locked")))) + { + door.requiredItems.Clear(); + } + } + } } public virtual void AddToGUIUpdateList() { + if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale) + { + CreateObjectiveFrame(); + } + + if (objectiveFrame != null && activeObjectives.Count > 0) + { + objectiveFrame.AddToGUIUpdateList(order: -1); + } + if (infoBox != null) infoBox.AddToGUIUpdateList(order: 100); + if (videoPlayer != null) videoPlayer.AddToGUIUpdateList(order: 100); } public virtual void Update(float deltaTime) { - + if (videoPlayer != null) + { + videoPlayer.Update(); + } + + if (activeObjectives != null) + { + for (int i = 0; i < activeObjectives.Count; i++) + { + CheckActiveObjectives(activeObjectives[i], deltaTime); + } + } + } + + public void CloseActiveContentGUI() + { + if (videoPlayer.IsPlaying) + { + videoPlayer.Stop(); + } + else if (infoBox != null) + { + CloseInfoFrame(null, null); + } } public virtual IEnumerable UpdateState() @@ -134,6 +251,233 @@ namespace Barotrauma.Tutorials yield return CoroutineStatus.Success; } + protected bool Restart(GUIButton button, object obj) + { + GUI.PreventPauseMenuToggle = false; + TutorialMode.StartTutorial(this); + return true; + } + + protected virtual void TriggerTutorialSegment(int index, params object[] args) + { + Inventory.draggingItem = null; + ContentRunning = true; + activeContentSegment = segments[index]; + segments[index].Args = args; + + string tutorialText = TextManager.GetFormatted(activeContentSegment.TextContent.GetAttributeString("tag", ""), true, args); + tutorialText = TextManager.ParseInputTypes(tutorialText); + string objectiveText = string.Empty; + + if (!string.IsNullOrEmpty(activeContentSegment.Objective)) + { + if (args.Length == 0) + { + objectiveText = activeContentSegment.Objective; + } + else + { + objectiveText = string.Format(activeContentSegment.Objective, args); + } + objectiveText = TextManager.ParseInputTypes(objectiveText); + activeContentSegment.Objective = objectiveText; + } + else + { + activeContentSegment.IsTriggered = true; // Complete at this stage only if no related objective + } + + + switch (activeContentSegment.ContentType) + { + case TutorialContentTypes.None: + break; + case TutorialContentTypes.Video: + infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText, + activeContentSegment.TextContent.GetAttributeInt("width", 300), + activeContentSegment.TextContent.GetAttributeInt("height", 80), + activeContentSegment.TextContent.GetAttributeString("anchor", "Center"), true, () => LoadVideo(activeContentSegment)); + break; + case TutorialContentTypes.ManualVideo: + infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText, + activeContentSegment.TextContent.GetAttributeInt("width", 300), + activeContentSegment.TextContent.GetAttributeInt("height", 80), + activeContentSegment.TextContent.GetAttributeString("anchor", "Center"), true, StopCurrentContentSegment, () => LoadVideo(activeContentSegment, false)); + break; + case TutorialContentTypes.TextOnly: + infoBox = CreateInfoFrame(TextManager.Get(activeContentSegment.Id), tutorialText, + activeContentSegment.TextContent.GetAttributeInt("width", 300), + activeContentSegment.TextContent.GetAttributeInt("height", 80), + activeContentSegment.TextContent.GetAttributeString("anchor", "Center"), true, StopCurrentContentSegment); + break; + } + } + + public virtual void Stop() + { + started = ContentRunning = Initialized = false; + infoBox = null; + if (videoPlayer != null) + { + videoPlayer.Remove(); + videoPlayer = null; + } + } + #endregion + + #region Objectives + private void CreateObjectiveFrame() + { + holderFrame = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center)); + objectiveFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ObjectiveAnchor, holderFrame.RectTransform), style: null); + + for (int i = 0; i < activeObjectives.Count; i++) + { + CreateObjectiveGUI(activeObjectives[i], i, activeObjectives[i].ContentType); + } + + screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight); + prevUIScale = GUI.Scale; + } + + protected void StopCurrentContentSegment() + { + if (!string.IsNullOrEmpty(activeContentSegment.Objective)) + { + AddNewObjective(activeContentSegment, activeContentSegment.ContentType); + } + + activeContentSegment = null; + ContentRunning = false; + } + + protected virtual void CheckActiveObjectives(TutorialSegment objective, float deltaTime) + { + + } + + protected bool HasObjective(TutorialSegment segment) + { + return activeObjectives.Contains(segment); + } + + protected void AddNewObjective(TutorialSegment segment, TutorialContentTypes type) + { + activeObjectives.Add(segment); + CreateObjectiveGUI(segment, activeObjectives.Count - 1, type); + } + + private void CreateObjectiveGUI(TutorialSegment segment, int index, TutorialContentTypes type) + { + Point replayButtonSize = new Point((int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).X * GUI.Scale), (int)(GUI.ObjectiveNameFont.MeasureString(segment.Objective).Y * 1.45f * GUI.Scale)); + + segment.ReplayButton = new GUIButton(new RectTransform(replayButtonSize, objectiveFrame.RectTransform, Anchor.TopRight, Pivot.TopRight) { AbsoluteOffset = new Point(0, (replayButtonSize.Y + (int)(20f * GUI.Scale)) * index) }, style: null); + segment.ReplayButton.OnClicked += (GUIButton btn, object userdata) => + { + if (type == TutorialContentTypes.Video) + { + ReplaySegmentVideo(segment); + } + else + { + ShowSegmentText(segment); + } + return true; + }; + + string objectiveText = TextManager.ParseInputTypes(objectiveTranslated); + int yOffset = (int)((GUI.ObjectiveNameFont.MeasureString(objectiveText).Y / 2f + 5) * GUI.Scale); + segment.LinkedTitle = new GUITextBlock(new RectTransform(new Point((int)GUI.ObjectiveNameFont.MeasureString(objectiveText).X, yOffset), segment.ReplayButton.RectTransform, Anchor.CenterRight, Pivot.BottomRight) { AbsoluteOffset = new Point((int)(-10 * GUI.Scale), 0) }, + objectiveText, textColor: Color.White, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight); + segment.LinkedText = new GUITextBlock(new RectTransform(new Point(replayButtonSize.X, yOffset), segment.ReplayButton.RectTransform, Anchor.Center, Pivot.TopCenter) { AbsoluteOffset = new Point((int)(10 * GUI.Scale), 0) }, + TextManager.ParseInputTypes(segment.Objective), textColor: new Color(4, 180, 108), font: GUI.ObjectiveNameFont, textAlignment: Alignment.CenterRight); + + segment.LinkedTitle.TextScale = segment.LinkedText.TextScale = GUI.Scale; + + segment.LinkedTitle.Color = segment.LinkedTitle.HoverColor = segment.LinkedTitle.PressedColor = segment.LinkedTitle.SelectedColor = Color.Transparent; + segment.LinkedText.Color = segment.LinkedText.HoverColor = segment.LinkedText.PressedColor = segment.LinkedText.SelectedColor = Color.Transparent; + segment.ReplayButton.Color = segment.ReplayButton.HoverColor = segment.ReplayButton.PressedColor = segment.ReplayButton.SelectedColor = Color.Transparent; + } + + private void ReplaySegmentVideo(TutorialSegment segment) + { + if (ContentRunning) return; + ContentRunning = true; + videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, callback: () => ContentRunning = false); + } + + private void ShowSegmentText(TutorialSegment segment) + { + if (ContentRunning) return; + Inventory.draggingItem = null; + ContentRunning = true; + + string tutorialText = TextManager.GetFormatted(segment.TextContent.GetAttributeString("tag", ""), true, segment.Args); + + Action videoAction = null; + + if (segment.ContentType != TutorialContentTypes.TextOnly) + { + videoAction = () => LoadVideo(segment, false); + } + + infoBox = CreateInfoFrame(TextManager.Get(segment.Id), tutorialText, + segment.TextContent.GetAttributeInt("width", 300), + segment.TextContent.GetAttributeInt("height", 80), + segment.TextContent.GetAttributeString("anchor", "Center"), true, () => ContentRunning = false, videoAction); + } + + protected void RemoveCompletedObjective(TutorialSegment segment) + { + if (!HasObjective(segment)) return; + segment.IsTriggered = true; + segment.ReplayButton.OnClicked = null; + + int checkMarkHeight = (int)(segment.ReplayButton.Rect.Height * 1.2f); + int checkMarkWidth = (int)(checkMarkHeight * 0.93f); + + Color color = new Color(4, 180, 108); + + int objectiveTextWidth = segment.LinkedText.Rect.Width; + int objectiveTitleWidth = segment.LinkedTitle.Rect.Width; + + RectTransform rectTA; + if (objectiveTextWidth > objectiveTitleWidth) + { + rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft); + rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - 5, 0); + } + else + { + rectTA = new RectTransform(new Point(checkMarkWidth, checkMarkHeight), segment.ReplayButton.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft); + rectTA.AbsoluteOffset = new Point(-rectTA.Rect.Width - 5 - (objectiveTitleWidth), 0); + } + + GUIImage checkmark = new GUIImage(rectTA, "CheckMark"); + checkmark.Color = checkmark.SelectedColor = checkmark.HoverColor = checkmark.PressedColor = color; + + RectTransform rectTB = new RectTransform(new Vector2(1.1f, .8f), segment.LinkedText.RectTransform, Anchor.Center, Pivot.Center); + GUIImage stroke = new GUIImage(rectTB, "Stroke"); + stroke.Color = stroke.SelectedColor = stroke.HoverColor = stroke.PressedColor = color; + + CoroutineManager.StartCoroutine(WaitForObjectiveEnd(segment)); + } + + private IEnumerable WaitForObjectiveEnd(TutorialSegment objective) + { + yield return new WaitForSeconds(2.0f); + objectiveFrame.RemoveChild(objective.ReplayButton); + activeObjectives.Remove(objective); + + for (int i = 0; i < activeObjectives.Count; i++) + { + activeObjectives[i].ReplayButton.RectTransform.AbsoluteOffset = new Point(0, (activeObjectives[i].ReplayButton.Rect.Height + 20) * i); + } + } + + #endregion + + #region InfoFrame protected bool CloseInfoFrame(GUIButton button, object userData) { infoBox = null; @@ -141,73 +485,71 @@ namespace Barotrauma.Tutorials return true; } - protected GUIComponent CreateInfoFrame(string text, bool hasButton = false, Action callback = null) + protected GUIComponent CreateInfoFrame(string title, string text, int width = 300, int height = 80, string anchorStr = "", bool hasButton = false, Action callback = null, Action showVideo = null) { - int width = 300; - int height = hasButton ? 110 : 80; + if (hasButton) height += 60; - string wrappedText = ToolBox.WrapText(text, width, GUI.Font); - - height += wrappedText.Split('\n').Length * 25; - - var infoBlock = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas, Anchor.TopRight) { AbsoluteOffset = new Point(20) }); - infoBlock.Flash(Color.Green); - - var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 0.7f), infoBlock.RectTransform, Anchor.Center), - text, wrap: true); - - infoBoxClosedCallback = callback; - - if (hasButton) - { - var okButton = new GUIButton(new RectTransform(new Point(160, 50), infoBlock.RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, -10) }, - TextManager.Get("OK")) - { - OnClicked = CloseInfoFrame - }; - } - - GUI.PlayUISound(GUISoundType.UIMessage); - - return infoBlock; - } - - protected GUIComponent CreateInfoFrame(string title, string text, int width, int height, string anchorStr, bool hasButton = false, Action callback = null) - { - if (hasButton) height += 30; - - string wrappedText = ToolBox.WrapText(text, width, GUI.Font); - - height += wrappedText.Split('\n').Length * 25; + float textScale = GUI.Scale; + string wrappedText = ToolBox.WrapText(text, width, GUI.Font, textScale); + height += (int)(GUI.Font.MeasureString(wrappedText).Y * textScale + 50); if (title.Length > 0) { height += 35; } Anchor anchor = Anchor.TopRight; - Enum.TryParse(anchorStr, out anchor); - var infoBlock = new GUIFrame(new RectTransform(new Point((int)(width * GUI.Scale), (int)(height * GUI.Scale)), GUI.Canvas, anchor) { AbsoluteOffset = new Point(20) }); + if (anchorStr != string.Empty) + { + Enum.TryParse(anchorStr, out anchor); + } + + var background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), "InnerFrame", new Color(0, 0, 0, 1f)); + + var infoBlock = new GUIFrame(new RectTransform(new Point((int)(width * GUI.Scale), (int)(height * GUI.Scale)), background.RectTransform, anchor) { AbsoluteOffset = new Point(20) }); infoBlock.Flash(Color.Green); + var infoContent = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), infoBlock.RectTransform, Anchor.Center)) + { + Stretch = true, + RelativeSpacing = 0.02f + }; + if (title.Length > 0) { - var titleBlock = new GUITextBlock(new RectTransform(new Vector2(1f, .35f), infoBlock.RectTransform, Anchor.TopCenter, - Pivot.TopCenter), title, font: GUI.VideoTitleFont, textAlignment: Alignment.Center, textColor: new Color(253, 174, 0)); - titleBlock.TextScale = GUI.Scale; + var titleBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), infoContent.RectTransform), + title, font: GUI.VideoTitleFont, textAlignment: Alignment.Center, textColor: new Color(253, 174, 0)); + titleBlock.TextScale = textScale; } - var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 1f), infoBlock.RectTransform, Anchor.BottomCenter), - text, wrap: true); - textBlock.TextScale = GUI.Scale; + var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), infoContent.RectTransform), text, wrap: true); infoBoxClosedCallback = callback; if (hasButton) { - var okButton = new GUIButton(new RectTransform(new Point(160, 50), infoBlock.RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, -10) }, - TextManager.Get("OK")) + var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), infoContent.RectTransform) { MinSize = new Point(0, 30), MaxSize = new Point((int) infoContent.Rect.X, 60) }, isHorizontal: true) + { + Stretch = true, + RelativeSpacing = 0.1f + }; + + if (showVideo != null) + { + var videoButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonContainer.RectTransform), + TextManager.Get("Video"), style: "GUIButtonLarge") + { + OnClicked = (GUIButton button, object obj) => + { + showVideo(); + return true; + } + }; + } + + var okButton = new GUIButton(new RectTransform(new Vector2(0.6f, 1.0f), buttonContainer.RectTransform), + TextManager.Get("OK"), style: "GUIButtonLarge") { OnClicked = CloseInfoFrame }; @@ -215,13 +557,55 @@ namespace Barotrauma.Tutorials GUI.PlayUISound(GUISoundType.UIMessage); - return infoBlock; + return background; + } + #endregion + + #region Video + protected void LoadVideo(TutorialSegment segment, bool showText = true) + { + if (videoPlayer == null) videoPlayer = new VideoPlayer(); + if (showText) + { + videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, segment.Objective, StopCurrentContentSegment); + } + else + { + videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), null, segment.Id, true, segment.Objective, null); + } + } + #endregion + + #region Highlights + protected void HighlightInventorySlot(Inventory inventory, string identifier, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount) + { + if (inventory.slots == null) { return; } + for (int i = 0; i < inventory.Items.Length; i++) + { + if (inventory.Items[i] != null && inventory.Items[i].Prefab.Identifier == identifier) + { + HighlightInventorySlot(inventory, i, color, fadeInDuration, fadeOutDuration, scaleUpAmount); + } + } } - protected bool Restart(GUIButton button, object obj) + protected void HighlightInventorySlotWithTag(Inventory inventory, string tag, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount) { - TutorialMode.StartTutorial(this); - return true; + if (inventory.slots == null) { return; } + for (int i = 0; i < inventory.Items.Length; i++) + { + if (inventory.Items[i] != null && inventory.Items[i].HasTag(tag)) + { + HighlightInventorySlot(inventory, i, color, fadeInDuration, fadeOutDuration, scaleUpAmount); + } + } } + + protected void HighlightInventorySlot(Inventory inventory, int index, Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount) + { + if (inventory.slots == null || index < 0 || inventory.slots[index].HighlightTimer > 0) return; + inventory.slots[index].ShowBorderHighlight(color, fadeInDuration, fadeOutDuration, scaleUpAmount); + } + #endregion } } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/TutorialMode.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/TutorialMode.cs index 942168cfb..407f742e9 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/TutorialMode.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/TutorialMode.cs @@ -4,7 +4,7 @@ namespace Barotrauma { class TutorialMode : GameMode { - public Tutorial tutorial; + public Tutorial Tutorial; public static void StartTutorial(Tutorial tutorial) { @@ -19,18 +19,20 @@ namespace Barotrauma public override void Start() { base.Start(); - tutorial.Start(); + GameMain.GameSession.CrewManager = new CrewManager(true); + Tutorial.Start(); } public override void AddToGUIUpdateList() { - tutorial.AddToGUIUpdateList(); + base.AddToGUIUpdateList(); + Tutorial.AddToGUIUpdateList(); } public override void Update(float deltaTime) { base.Update(deltaTime); - tutorial.Update(deltaTime); + Tutorial.Update(deltaTime); } } } diff --git a/Barotrauma/BarotraumaClient/Source/Items/CharacterInventory.cs b/Barotrauma/BarotraumaClient/Source/Items/CharacterInventory.cs index 532e98df2..3e479aa80 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/CharacterInventory.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/CharacterInventory.cs @@ -100,6 +100,7 @@ namespace Barotrauma limbSlotIcons.Add(InvSlotType.Head, new Sprite("Content/UI/IconAtlas.png", new Rectangle(896 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2))); limbSlotIcons.Add(InvSlotType.LeftHand, new Sprite("Content/UI/IconAtlas.png", new Rectangle(640 + margin, 383 + margin, 128 - margin * 2, 128 - margin * 2))); limbSlotIcons.Add(InvSlotType.RightHand, new Sprite("Content/UI/IconAtlas.png", new Rectangle(768 + margin, 383 + margin, 128 - margin * 2, 128 - margin * 2))); + limbSlotIcons.Add(InvSlotType.OuterClothes, new Sprite("Content/UI/IconAtlas.png", new Rectangle(768 + margin, 896 + margin, 128 - margin * 2, 128 - margin * 2))); } SlotPositions = new Vector2[SlotTypes.Length]; CurrentLayout = Layout.Default; diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/LightComponent.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/LightComponent.cs index 141433f4e..7f676175e 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/LightComponent.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/LightComponent.cs @@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components { 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.SpriteDepth - 0.0001f); + light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, item.Scale, SpriteEffects.None, item.SpriteDepth - 0.0001f); } } diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Deconstructor.cs index 85150941e..cb8889292 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Deconstructor.cs @@ -9,6 +9,10 @@ namespace Barotrauma.Items.Components { partial class Deconstructor : Powered, IServerSerializable, IClientSerializable { + public GUIButton ActivateButton + { + get { return activateButton; } + } private GUIButton activateButton; private GUIComponent inputInventoryHolder, outputInventoryHolder; private GUICustomComponent inputInventoryOverlay; @@ -44,7 +48,6 @@ namespace Barotrauma.Items.Components Visible = false, CanBeFocused = false }; - outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.3f), paddedFrame.RectTransform), style: null); } @@ -71,7 +74,7 @@ namespace Barotrauma.Items.Components public override void UpdateHUD(Character character, float deltaTime, Camera cam) { inSufficientPowerWarning.Visible = powerConsumption > 0 && voltage < minVoltage; - activateButton.Enabled = !inSufficientPowerWarning.Visible; + //activateButton.Enabled = !inSufficientPowerWarning.Visible; } private bool ToggleActive(GUIButton button, object obj) diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs index 4dc0b89a1..f01906f3d 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs @@ -15,6 +15,10 @@ namespace Barotrauma.Items.Components private GUIFrame selectedItemFrame; + public GUIButton ActivateButton + { + get { return activateButton; } + } private GUIButton activateButton; private GUITextBox itemFilterBox; @@ -22,6 +26,10 @@ namespace Barotrauma.Items.Components private GUIComponent inputInventoryHolder, outputInventoryHolder; private GUICustomComponent inputInventoryOverlay, outputInventoryOverlay; + public FabricationRecipe SelectedItem + { + get { return selectedItem; } + } private FabricationRecipe selectedItem; private GUIComponent inSufficientPowerWarning; @@ -73,7 +81,31 @@ namespace Barotrauma.Items.Components { CanBeFocused = false }; - + + CreateRecipes(); + + activateButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.07f), paddedFrame.RectTransform), + TextManager.Get("FabricatorCreate"), style: "GUIButtonLarge") + { + 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 CreateRecipes() + { + itemList.Content.RectTransform.ClearChildren(); + foreach (FabricationRecipe fi in fabricationRecipes) { GUIFrame frame = new GUIFrame(new RectTransform(new Point(itemList.Rect.Width, 30), itemList.Content.RectTransform), style: null) @@ -101,23 +133,6 @@ namespace Barotrauma.Items.Components }; } } - - activateButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.07f), paddedFrame.RectTransform), - TextManager.Get("FabricatorCreate"), style: "GUIButtonLarge") - { - 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() @@ -241,6 +256,7 @@ namespace Barotrauma.Items.Components } } } + private void DrawOutputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent) { overlayComponent.RectTransform.SetAsLastChild(); @@ -363,6 +379,29 @@ namespace Barotrauma.Items.Components return true; } + public void HighlightRecipe(string identifier, Color color) + { + foreach (GUIComponent child in itemList.Content.Children) + { + FabricationRecipe recipe = child.UserData as FabricationRecipe; + if (recipe?.DisplayName == null) { continue; } + if (recipe.TargetItem.Identifier == identifier) + { + if (child.FlashTimer > 0.0f) return; + child.Flash(color, 1.5f, false); + + for (int i = 0; i < child.CountChildren; i++) + { + var grandChild = child.GetChild(i); + if (grandChild is GUITextBlock) continue; + grandChild.Flash(color, 1.5f, false); + } + + return; + } + } + } + private bool StartButtonClicked(GUIButton button, object obj) { if (selectedItem == null) { return false; } diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Pump.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Pump.cs index b13727818..5ef0e010c 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Pump.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Pump.cs @@ -10,6 +10,10 @@ namespace Barotrauma.Items.Components { partial class Pump : Powered, IServerSerializable, IClientSerializable { + public GUIScrollBar IsActiveSlider + { + get { return isActiveSlider; } + } private GUIScrollBar isActiveSlider; private GUIScrollBar pumpSpeedSlider; private GUITickBox powerIndicator; @@ -49,7 +53,6 @@ namespace Barotrauma.Items.Components }; var sliderHandle = isActiveSlider.GetChild(); sliderHandle.RectTransform.NonScaledSize = new Point(84, sliderHandle.Rect.Height); - isActiveSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) => { bool active = scrollBar.BarScroll < 0.5f; diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Reactor.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Reactor.cs index 893943a62..b4d53d0e0 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Reactor.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Reactor.cs @@ -11,7 +11,16 @@ namespace Barotrauma.Items.Components { partial class Reactor : Powered, IServerSerializable, IClientSerializable { + public GUIScrollBar AutoTempSlider + { + get { return autoTempSlider; } + } private GUIScrollBar autoTempSlider; + + public GUIScrollBar OnOffSwitch + { + get { return onOffSwitch; } + } private GUIScrollBar onOffSwitch; private const int GraphSize = 25; @@ -27,7 +36,16 @@ namespace Barotrauma.Items.Components private Sprite graphLine; + public GUIScrollBar FissionRateScrollBar + { + get { return fissionRateScrollBar; } + } private GUIScrollBar fissionRateScrollBar; + + public GUIScrollBar TurbineOutputScrollBar + { + get { return turbineOutputScrollBar; } + } private GUIScrollBar turbineOutputScrollBar; private float[] outputGraph = new float[GraphSize]; diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs index 3c20dbb30..0c7c9c058 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs @@ -20,6 +20,10 @@ namespace Barotrauma.Items.Components private bool unsentChanges; private float networkUpdateTimer; + public GUITickBox ActiveTickBox + { + get { return activeTickBox; } + } private GUITickBox activeTickBox, passiveTickBox; private GUITextBlock signalWarningText; diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Repairable.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Repairable.cs index ddd2ffb29..5cde6d3ec 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Repairable.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Repairable.cs @@ -10,6 +10,10 @@ namespace Barotrauma.Items.Components { partial class Repairable : ItemComponent, IDrawableComponent { + public GUIButton RepairButton + { + get { return repairButton; } + } private GUIButton repairButton; private GUIProgressBar progressBar; diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs index 53c247abe..f5a3c8999 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/Connection.cs @@ -18,6 +18,14 @@ namespace Barotrauma.Items.Components private static Wire draggingConnected; + private Color flashColor; + private float flashDuration = 1.5f; + public float FlashTimer + { + get { return flashTimer; } + } + private float flashTimer; + public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character) { Rectangle panelRect = panel.GuiFrame.Rect; @@ -174,14 +182,38 @@ namespace Barotrauma.Items.Components } } } - + + if (flashTimer > 0.0f) + { + //the number of flashes depends on the duration, 1 flash per 1 full second + int flashCycleCount = (int)Math.Max(flashDuration, 1); + float flashCycleDuration = flashDuration / flashCycleCount; + + //MathHelper.Pi * 0.8f -> the curve goes from 144 deg to 0, + //i.e. quickly bumps up from almost full brightness to full and then fades out + connectionSpriteHighlight.Draw(spriteBatch, position, flashColor * (float)Math.Sin(flashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f)); + } + if (Wires.Any(w => w != null && w != draggingConnected)) { int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count; screwSprites[screwIndex].Draw(spriteBatch, position); } } - + + public void Flash(Color? color = null, float flashDuration = 1.5f) + { + flashTimer = flashDuration; + this.flashDuration = flashDuration; + flashColor = (color == null) ? Color.Red : (Color)color; + } + + public void UpdateFlashTimer(float deltaTime) + { + if (flashTimer <= 0) return; + flashTimer -= deltaTime; + } + 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) diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs index fe1fbc065..124992e2c 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Signal/CustomInterface.cs @@ -92,6 +92,25 @@ namespace Barotrauma.Items.Components } } + public void HighlightElement(int index, Color color, float duration, float pulsateAmount = 0.0f) + { + if (index < 0 || index >= uiElements.Count) { return; } + uiElements[index].Flash(color, duration); + + if (pulsateAmount > 0.0f) + { + if (uiElements[index] is GUIButton button) + { + button.Frame.Pulsate(Vector2.One, Vector2.One * (1.0f + pulsateAmount), duration); + button.Frame.RectTransform.SetPosition(Anchor.Center); + } + else + { + uiElements[index].Pulsate(Vector2.One, Vector2.One * (1.0f + pulsateAmount), duration); + } + } + } + partial void UpdateLabelsProjSpecific() { for (int i = 0; i < labels.Length && i < uiElements.Count; i++) diff --git a/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs b/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs index 30eaf8155..8fb30030a 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs @@ -26,6 +26,7 @@ namespace Barotrauma public Color Color; public Color HighlightColor; + public float HighlightScaleUpAmount; private CoroutineHandle highlightCoroutine; public float HighlightTimer; @@ -80,7 +81,7 @@ namespace Barotrauma return rect.Contains(PlayerInput.MousePosition); } - public void ShowBorderHighlight(Color color, float fadeInDuration, float fadeOutDuration) + public void ShowBorderHighlight(Color color, float fadeInDuration, float fadeOutDuration, float scaleUpAmount = 0.5f) { if (highlightCoroutine != null) { @@ -88,6 +89,7 @@ namespace Barotrauma highlightCoroutine = null; } + HighlightScaleUpAmount = scaleUpAmount; highlightCoroutine = CoroutineManager.StartCoroutine(UpdateBorderHighlight(color, fadeInDuration, fadeOutDuration)); } @@ -800,8 +802,7 @@ namespace Barotrauma if (slot.HighlightColor.A > 0) { - float scaleUpAmount = 0.5f; - float inflateAmount = (slot.HighlightColor.A / 255.0f) * scaleUpAmount * 0.5f; + float inflateAmount = (slot.HighlightColor.A / 255.0f) * slot.HighlightScaleUpAmount * 0.5f; rect.Inflate(rect.Width * inflateAmount, rect.Height * inflateAmount); } diff --git a/Barotrauma/BarotraumaClient/Source/Items/Item.cs b/Barotrauma/BarotraumaClient/Source/Items/Item.cs index 501f023e5..2c5e3b5cc 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Item.cs @@ -184,7 +184,7 @@ namespace Barotrauma if (!Visible || (!editing && hiddenInGame)) return; if (editing && !ShowItems) return; - Color color = isHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? Color.Orange : GetSpriteColor(); + Color color = IsHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? Color.Orange : GetSpriteColor(); //if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f); BrokenItemSprite fadeInBrokenSprite = null; diff --git a/Barotrauma/BarotraumaClient/Source/Map/Hull.cs b/Barotrauma/BarotraumaClient/Source/Map/Hull.cs index e32f31ea7..252662461 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Hull.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Hull.cs @@ -326,843 +326,6 @@ namespace Barotrauma Color.Green, width: 2); } } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } - - foreach (MapEntity e in linkedTo) - { - if (e is Hull) - { - Hull linkedHull = (Hull)e; - Rectangle connectedHullRect = e.Submarine == null ? - linkedHull.rect : - new Rectangle( - (int)(Submarine.DrawPosition.X + linkedHull.WorldPosition.X), - (int)(Submarine.DrawPosition.Y + linkedHull.WorldPosition.Y), - linkedHull.WorldRect.Width, linkedHull.WorldRect.Height); - - //center of the hull - Rectangle currentHullRect = Submarine == null ? - WorldRect : - new Rectangle( - (int)(Submarine.DrawPosition.X + WorldPosition.X), - (int)(Submarine.DrawPosition.Y + WorldPosition.Y), - WorldRect.Width, WorldRect.Height); - - GUI.DrawLine(spriteBatch, - new Vector2(currentHullRect.X, -currentHullRect.Y), - new Vector2(connectedHullRect.X, -connectedHullRect.Y), - Color.Green, width: 2); - } - } } public static void UpdateVertices(GraphicsDevice graphicsDevice, Camera cam, WaterRenderer renderer) diff --git a/Barotrauma/BarotraumaClient/Source/Map/Structure.cs b/Barotrauma/BarotraumaClient/Source/Map/Structure.cs index 8d893af08..08a9b5ae0 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Structure.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Structure.cs @@ -42,7 +42,21 @@ namespace Barotrauma MathHelper.Clamp(value.Y, 0.01f, 10)); } } - + + private string specialTag; + [Editable, Serialize("", true)] + public string SpecialTag + { + get { return specialTag; } + set { specialTag = value; } + } + + // Only for testing in the debug build. Not saved. +#if DEBUG + [Editable, Serialize(true, false)] +#endif + public bool DrawTiled { get; protected set; } = true; + protected Vector2 textureOffset = Vector2.Zero; [Editable(MinValueFloat = -1000f, MaxValueFloat = 1000f, ValueStep = 10f), Serialize("0.0, 0.0", true)] public Vector2 TextureOffset @@ -187,7 +201,7 @@ namespace Barotrauma if (HasBody && !ShowWalls) return; } - Color color = isHighlighted ? Color.Orange : spriteColor; + Color color = IsHighlighted ? Color.Orange : spriteColor; if (IsSelected && editing) { //color = Color.Lerp(color, Color.Gold, 0.5f); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs index c387484f4..835d09937 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -20,6 +20,8 @@ namespace Barotrauma private GUILayoutGroup subPreviewContainer; + private GUILayoutGroup subPreviewContainer; + private GUIButton loadGameButton; public Action StartNewGame; @@ -68,25 +70,20 @@ namespace Barotrauma new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed") + ":"); seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8)); - if (!isMultiplayer) - { - contextualTutorialBox = new GUITickBox(new RectTransform(new Point(32, 32), leftColumn.RectTransform), TextManager.Get("TutorialActive")); - UpdateTutorialSelection(); - } - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SelectedSub") + ":"); + var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), isHorizontal: true) + { + Stretch = true + }; subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform)) { ScrollBarVisible = true }; - var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), leftColumn.RectTransform), isHorizontal: true) - { - Stretch = true, - RelativeSpacing = 0.02f - }; - new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font); - var searchBox = new GUITextBox(new RectTransform(new Vector2(0.9f, 1.0f), filterContainer.RectTransform), font: GUI.Font); + var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font); + var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font); + searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; }; + searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; }; searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; }; - var clearButton = new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), filterContainer.RectTransform), "x") + var clearButton = new GUIButton(new RectTransform(new Vector2(0.075f, 1.0f), filterContainer.RectTransform), "x") { OnClicked = (btn, userdata) => { searchBox.Text = ""; FilterSubs(subList, ""); searchBox.Flash(Color.White); return true; } }; @@ -399,14 +396,7 @@ namespace Barotrauma }, Enabled = false }; - } - - public void UpdateTutorialSelection() - { - if (isMultiplayer) return; - Tutorial contextualTutorial = Tutorial.Tutorials.Find(t => t is ContextualTutorial); - contextualTutorialBox.Selected = (contextualTutorial != null) ? !GameMain.Config.CompletedTutorialNames.Contains(contextualTutorial.Name) : true; - } + } private bool SelectSaveFile(GUIComponent component, object obj) { diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs index 46c54674e..44859a667 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs @@ -182,23 +182,24 @@ namespace Barotrauma { TextGetter = GetMoney }; - var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.5f), storeContentTop.RectTransform), isHorizontal: true) + var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.4f), storeContentTop.RectTransform), isHorizontal: true) { - Stretch = true, - RelativeSpacing = 0.02f + Stretch = true }; - new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterRight, font: GUI.Font); - searchBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1.0f), filterContainer.RectTransform), font: GUI.Font); + var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font); + searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform), font: GUI.Font); + searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; }; + searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; }; + searchBox.OnTextChanged += (textBox, text) => { FilterStoreItems(null, text); return true; }; - var clearButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), filterContainer.RectTransform), "x") + var clearButton = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), filterContainer.RectTransform), "x") { OnClicked = (btn, userdata) => { searchBox.Text = ""; FilterStoreItems(selectedItemCategory, ""); searchBox.Flash(Color.White); return true; } }; var storeItemLists = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.8f), storeContent.RectTransform), isHorizontal: true) { - Stretch = true, - RelativeSpacing = 0.02f + Stretch = true }; myItemList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), storeItemLists.RectTransform)); storeItemList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), storeItemLists.RectTransform)) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs index 614b50e9c..2b85d4777 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs @@ -59,10 +59,10 @@ namespace Barotrauma Stretch = true, RelativeSpacing = 0.02f }; - + // === CAMPAIGN var campaignHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.1f, 0.0f) }, isHorizontal: true); - + new GUIImage(new RectTransform(new Vector2(0.2f, 0.7f), campaignHolder.RectTransform), "MainMenuCampaignIcon") { CanBeFocused = false @@ -84,6 +84,17 @@ namespace Barotrauma RelativeSpacing = 0.035f }; + new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), campaignList.RectTransform), "Tutorial", textAlignment: Alignment.Left, style: "MainMenuGUIButton") + { + ForceUpperCase = true, + UserData = Tab.Tutorials, + OnClicked = (tb, userdata) => + { + SelectTab(tb, userdata); + return true; + } + }; + new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), campaignList.RectTransform), TextManager.Get("LoadGameButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton") { ForceUpperCase = true, @@ -184,6 +195,10 @@ namespace Barotrauma UserData = Tab.SteamWorkshop, OnClicked = SelectTab }; + +#if OSX && !DEBUG + steamWorkshopButton.Text += " (Not yet available on MacOS)"; +#endif } new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), customizeList.RectTransform), TextManager.Get("SubEditorButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton") @@ -309,6 +324,7 @@ namespace Barotrauma false, null, ""); foreach (Tutorial tutorial in Tutorial.Tutorials) { + if (tutorial is ContextualTutorial) continue; var tutorialText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), tutorialList.Content.RectTransform), tutorial.Name, textAlignment: Alignment.Center, font: GUI.LargeFont) { UserData = tutorial @@ -320,8 +336,6 @@ namespace Barotrauma return true; }; - UpdateTutorialList(); - this.game = game; menuTabs[(int)Tab.Credits] = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null, color: Color.Black * 0.5f) @@ -331,9 +345,9 @@ namespace Barotrauma var creditsContainer = new GUIFrame(new RectTransform(new Vector2(0.75f, 1.5f), menuTabs[(int)Tab.Credits].RectTransform, Anchor.CenterRight), style: "OuterGlow", color: Color.Black * 0.8f); creditsPlayer = new CreditsPlayer(new RectTransform(Vector2.One, creditsContainer.RectTransform), "Content/Texts/Credits.xml"); } - #endregion +#endregion - #region Selection +#region Selection public override void Select() { base.Select(); @@ -348,10 +362,6 @@ namespace Barotrauma ResetButtonStates(null); - UpdateTutorialList(); - - ResetButtonStates(null); - GameAnalyticsManager.SetCustomDimension01(""); } @@ -397,7 +407,6 @@ namespace Barotrauma case Tab.NewGame: campaignSetupUI.CreateDefaultSaveName(); campaignSetupUI.RandomizeSeed(); - campaignSetupUI.UpdateTutorialSelection(); campaignSetupUI.UpdateSubList(Submarine.SavedSubmarines); break; case Tab.LoadGame: @@ -414,6 +423,7 @@ namespace Barotrauma case Tab.HostServer: break; case Tab.Tutorials: + UpdateTutorialList(); break; case Tab.CharacterEditor: Submarine.MainSub = null; @@ -444,6 +454,8 @@ namespace Barotrauma public bool ReturnToMainMenu(GUIButton button, object obj) { + GUI.PreventPauseMenuToggle = false; + if (Selected != this) { Select(); @@ -468,7 +480,7 @@ namespace Barotrauma otherButton.Selected = false; } } - #endregion +#endregion private void QuickStart() { @@ -646,6 +658,7 @@ namespace Barotrauma FileName = filename, Arguments = arguments #if !DEBUG + , WindowStyle = ProcessWindowStyle.Hidden #endif }; @@ -685,6 +698,7 @@ namespace Barotrauma GameMain.TitleScreen.TitleSize.Y / 2.0f * GameMain.TitleScreen.Scale + 30.0f), 0.1f); #if !DEBUG +#if !OSX if (Steam.SteamManager.USE_STEAM) { if (GameMain.Config.UseSteamMatchmaking) @@ -694,6 +708,16 @@ namespace Barotrauma } steamWorkshopButton.Enabled = Steam.SteamManager.IsInitialized; } +#else + if (Steam.SteamManager.USE_STEAM) + { + if (GameMain.Config.UseSteamMatchmaking) + { + joinServerButton.Enabled = Steam.SteamManager.IsInitialized; + hostServerButton.Enabled = Steam.SteamManager.IsInitialized; + } + } +#endif #else joinServerButton.Enabled = true; hostServerButton.Enabled = true; @@ -804,8 +828,7 @@ namespace Barotrauma } selectedSub = new Submarine(Path.Combine(SaveUtil.TempPath, selectedSub.Name + ".sub"), ""); - - ContextualTutorial.Selected = campaignSetupUI.TutorialSelected; + GameMain.GameSession = new GameSession(selectedSub, saveName, GameModePreset.List.Find(g => g.Identifier == "singleplayercampaign")); (GameMain.GameSession.GameMode as CampaignMode).GenerateMap(mapSeed); @@ -832,7 +855,7 @@ namespace Barotrauma GameMain.LobbyScreen.Select(); } - #region UI Methods +#region UI Methods private void CreateHostServerFields() { Vector2 textLabelSize = new Vector2(1.0f, 0.1f); @@ -913,7 +936,7 @@ namespace Barotrauma OnClicked = HostServerClicked }; } - #endregion +#endregion } } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs index 88890c05e..2ab09e2ee 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs @@ -1301,6 +1301,12 @@ namespace Barotrauma var paddedLoadFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), innerFrame.RectTransform, Anchor.Center)) { Stretch = true, RelativeSpacing = 0.02f }; var deleteButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedLoadFrame.RectTransform, Anchor.Center)); + + var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedLoadFrame.RectTransform), isHorizontal: true) + { + Stretch = true + }; + var subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), paddedLoadFrame.RectTransform)) { ScrollBarVisible = true, @@ -1311,15 +1317,13 @@ namespace Barotrauma } }; - var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedLoadFrame.RectTransform), isHorizontal: true) - { - Stretch = true, - RelativeSpacing = 0.02f - }; - new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font); - var searchBox = new GUITextBox(new RectTransform(new Vector2(0.9f, 1.0f), filterContainer.RectTransform), font: GUI.Font); + var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font); + var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform), font: GUI.Font); + searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; }; + searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; }; + searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; }; - var clearButton = new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), filterContainer.RectTransform), "x") + var clearButton = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), filterContainer.RectTransform), "x") { OnClicked = (btn, userdata) => { searchBox.Text = ""; FilterSubs(subList, ""); searchBox.Flash(Color.White); return true; } }; diff --git a/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml b/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml index 5d1bf37a2..c5985f21c 100644 --- a/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml +++ b/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml @@ -12,6 +12,7 @@ + diff --git a/Barotrauma/BarotraumaShared/SharedCode.projitems b/Barotrauma/BarotraumaShared/SharedCode.projitems index f15f9dbd1..05589e12a 100644 --- a/Barotrauma/BarotraumaShared/SharedCode.projitems +++ b/Barotrauma/BarotraumaShared/SharedCode.projitems @@ -181,6 +181,7 @@ + diff --git a/Barotrauma/BarotraumaShared/SharedContent.projitems b/Barotrauma/BarotraumaShared/SharedContent.projitems index dfe87235b..2b4cacac6 100644 --- a/Barotrauma/BarotraumaShared/SharedContent.projitems +++ b/Barotrauma/BarotraumaShared/SharedContent.projitems @@ -379,6 +379,18 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -409,6 +421,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -445,9 +463,24 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -475,6 +508,54 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -1144,6 +1225,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -1635,15 +1719,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - PreserveNewest @@ -2109,9 +2184,19 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest + + Never + + diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs index 7f2daf1d0..06af37860 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs @@ -1110,6 +1110,8 @@ namespace Barotrauma private bool IsProperlyLatchedOnSub => LatchOntoAI != null && LatchOntoAI.IsAttachedToSub && SelectedAiTarget?.Entity == wallTarget?.Structure; + private bool IsProperlyLatchedOnSub => LatchOntoAI != null && LatchOntoAI.IsAttachedToSub && SelectedAiTarget?.Entity == wallTarget?.Structure; + //goes through all the AItargets, evaluates how preferable it is to attack the target, //whether the Character can see/hear the target and chooses the most preferable target within //sight/hearing range diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index 11e41e70a..cd82280ff 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -426,7 +426,7 @@ namespace Barotrauma } } - private bool canSpeak; + public bool CanSpeak; private bool speechImpedimentSet; @@ -436,7 +436,7 @@ namespace Barotrauma { get { - if (!canSpeak || IsUnconscious || Stun > 0.0f || IsDead) return 100.0f; + if (!CanSpeak || IsUnconscious || Stun > 0.0f || IsDead) return 100.0f; return speechImpediment; } set @@ -710,7 +710,7 @@ namespace Barotrauma displayName = TextManager.Get($"Character.{Path.GetFileName(Path.GetDirectoryName(file))}", true); IsHumanoid = doc.Root.GetAttributeBool("humanoid", false); - canSpeak = doc.Root.GetAttributeBool("canspeak", false); + CanSpeak = doc.Root.GetAttributeBool("canspeak", false); needsAir = doc.Root.GetAttributeBool("needsair", false); Noise = doc.Root.GetAttributeFloat("noise", 100f); @@ -1588,9 +1588,8 @@ namespace Barotrauma } } } - - - if (item.InteractDistance == 0.0f && !item.Prefab.Triggers.Any()) return false; + + if (item.InteractDistance == 0.0f && !item.Prefab.Triggers.Any()) { return false; } Pickable pickableComponent = item.GetComponent(); if (pickableComponent != null && (pickableComponent.Picker != null && !pickableComponent.Picker.IsDead)) { return false; } @@ -2718,6 +2717,10 @@ namespace Barotrauma GameMain.GameSession?.CrewManager?.RemoveCharacter(this); #endif +#if CLIENT + GameMain.GameSession?.CrewManager?.RemoveCharacter(this); +#endif + #if CLIENT GameMain.GameSession?.CrewManager?.RemoveCharacter(this); #endif diff --git a/Barotrauma/BarotraumaShared/Source/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaShared/Source/Characters/CharacterInfo.cs index 8dcf98fce..cb7df70ec 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/CharacterInfo.cs @@ -399,7 +399,7 @@ namespace Barotrauma { ID = idCounter; idCounter++; - Name = element.GetAttributeString("name", "unnamed"); + Name = element.GetAttributeString("name", ""); string genderStr = element.GetAttributeString("gender", "male").ToLowerInvariant(); File = element.GetAttributeString("file", ""); SourceElement = GetConfig(File).Root; @@ -423,6 +423,29 @@ namespace Barotrauma element.GetAttributeInt("beardindex", -1), element.GetAttributeInt("moustacheindex", -1), element.GetAttributeInt("faceattachmentindex", -1)); + + if (string.IsNullOrEmpty(Name)) + { + if (SourceElement.Element("name") != null) + { + string firstNamePath = SourceElement.Element("name").GetAttributeString("firstname", ""); + if (firstNamePath != "") + { + firstNamePath = firstNamePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male"); + Name = ToolBox.GetRandomLine(firstNamePath); + } + + string lastNamePath = SourceElement.Element("name").GetAttributeString("lastname", ""); + if (lastNamePath != "") + { + lastNamePath = lastNamePath.Replace("[GENDER]", (Head.gender == Gender.Female) ? "female" : "male"); + if (Name != "") Name += " "; + Name += ToolBox.GetRandomLine(lastNamePath); + } + } + } + + StartItemsGiven = element.GetAttributeBool("startitemsgiven", false); string personalityName = element.GetAttributeString("personality", ""); ragdollFileName = element.GetAttributeString("ragdoll", string.Empty); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs index 831c07c39..fa9ff9e17 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs @@ -801,10 +801,7 @@ namespace Barotrauma.Items.Components string msg = TextManager.Get(Msg, true); if (msg != null) { - foreach (InputType inputType in Enum.GetValues(typeof(InputType))) - { - msg = msg.Replace("[" + inputType.ToString().ToLowerInvariant() + "]", GameMain.Config.KeyBind(inputType).ToString()); - } + msg = TextManager.ParseInputTypes(msg); DisplayMsg = msg; } else diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs index 777ecb668..de2718682 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Deconstructor.cs @@ -13,6 +13,11 @@ namespace Barotrauma.Items.Components private ItemContainer inputContainer, outputContainer; + public ItemContainer InputContainer + { + get { return inputContainer; } + } + public ItemContainer OutputContainer { get { return outputContainer; } @@ -102,6 +107,25 @@ namespace Barotrauma.Items.Components } } + if (targetItem.Prefab.DeconstructItems.Any()) + { + inputContainer.Inventory.RemoveItem(targetItem); + Entity.Spawner.AddToRemoveQueue(targetItem); + MoveInputQueue(); + PutItemsToLinkedContainer(); + } + else + { + if (outputContainer.Inventory.Items.All(i => i != null)) + { + targetItem.Drop(dropper: null); + } + else + { + outputContainer.Inventory.TryPutItem(targetItem, user: null, createNetworkEvent: true); + } + } + if (targetItem.Prefab.DeconstructItems.Any()) { inputContainer.Inventory.RemoveItem(targetItem); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs index 7ade916d4..cd1b0e081 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs @@ -23,6 +23,16 @@ namespace Barotrauma.Items.Components private ItemContainer inputContainer, outputContainer; + public ItemContainer InputContainer + { + get { return inputContainer; } + } + + public ItemContainer OutputContainer + { + get { return outputContainer; } + } + private float progressState; public Fabricator(Item item, XElement element) @@ -98,7 +108,23 @@ namespace Barotrauma.Items.Components { return (picker != null); } - + + public void RemoveFabricationRecipes(List allowedIdentifiers) + { + for (int i = 0; i < fabricationRecipes.Count; i++) + { + if (!allowedIdentifiers.Contains(fabricationRecipes[i].TargetItem.Identifier)) + { + fabricationRecipes.RemoveAt(i); + i--; + } + } + + CreateRecipes(); + } + + partial void CreateRecipes(); + private void StartFabricating(FabricationRecipe selectedItem, Character user) { if (selectedItem == null) return; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs index 40e97dfe5..144d8da1a 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Sonar.cs @@ -259,7 +259,7 @@ namespace Barotrauma.Items.Components int clockDir = (int)Math.Round((angle / MathHelper.TwoPi) * 12); if (clockDir == 0) clockDir = 12; - return TextManager.Get("SubDirOClock").Replace("[dir]", clockDir.ToString()); + return TextManager.Get("roomname.subdiroclock").Replace("[dir]", clockDir.ToString()); } private Vector2 GetTransducerCenter() diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs index 15be6c324..da381c89e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Steering.cs @@ -575,6 +575,19 @@ namespace Barotrauma.Items.Components return true; } + public override void OnItemLoaded() + { + sonar = item.GetComponent(); + } + + public override bool Select(Character character) + { + if (!CanBeSelected) return false; + + user = character; + return true; + } + public override void Update(float deltaTime, Camera cam) { networkUpdateTimer -= deltaTime; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs b/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs index e6e6a9541..85d352153 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs @@ -206,6 +206,16 @@ namespace Barotrauma return true; } + public bool IsFull() + { + for (int i = 0; i < capacity; i++) + { + if (Items[i] == null) return false; + } + + return true; + } + protected bool TrySwapping(int index, Item item, Character user, bool createNetworkEvent) { if (item?.ParentInventory == null || Items[index] == null) return false; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 3be49bf9d..53d8d3914 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -1200,6 +1200,10 @@ namespace Barotrauma { ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); } + if (!broken) + { + ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); + } ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime); if (body == null || !body.Enabled || !inWater || ParentInventory != null || Removed) { return; } diff --git a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs index 0c5ee8062..f3f077ac5 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs @@ -132,14 +132,16 @@ namespace Barotrauma //default size protected Vector2 size; - private float impactTolerance; + private List fabricationRecipeElements = new List(); private bool canSpriteFlipX, canSpriteFlipY; private Dictionary prices; - //an area next to the construction - //the construction can be Activated() by a Character inside the area + /// + /// Defines areas where the item can be interacted with. If RequireBodyInsideTrigger is set to true, the character + /// has to be within the trigger to interact. If it's set to false, having the cursor within the trigger is enough. + /// public List Triggers; private List fabricationRecipeElements = new List(); diff --git a/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs b/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs index a73ac8907..40f2acd92 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs @@ -40,7 +40,7 @@ namespace Barotrauma flames = true; underwaterBubble = true; } - + public Explosion(XElement element, string parentDebugName) { attack = new Attack(element, parentDebugName + ", Explosion"); @@ -62,6 +62,16 @@ namespace Barotrauma CameraShake = element.GetAttributeFloat("camerashake", attack.Range * 0.1f); } + public void DisableParticles() + { + sparks = false; + shockwave = false; + smoke = false; + flash = false; + flames = false; + underwaterBubble = false; + } + public List> GetRecentExplosions(float maxSecondsAgo) { return prevExplosions.FindAll(e => e.Third >= Timing.TotalTime - maxSecondsAgo); diff --git a/Barotrauma/BarotraumaShared/Source/Map/FireSource.cs b/Barotrauma/BarotraumaShared/Source/Map/FireSource.cs index 11bf41f6c..e75ec8749 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/FireSource.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/FireSource.cs @@ -15,14 +15,15 @@ namespace Barotrauma { const float OxygenConsumption = 50.0f; const float GrowSpeed = 5.0f; - - private Hull hull; + + protected Hull hull; + + protected Vector2 position; + protected Vector2 size; private bool removed; - private bool removed; - - private bool removed; + protected bool removed; #if CLIENT private List burnDecals = new List(); @@ -184,6 +185,16 @@ namespace Barotrauma } } + protected virtual void ReduceOxygen(float deltaTime) + { + hull.Oxygen -= size.X * deltaTime * OxygenConsumption; + } + + protected virtual void AdjustXPos(float growModifier, float deltaTime) + { + position.X -= GrowSpeed * growModifier * 0.5f * deltaTime; + } + partial void UpdateProjSpecific(float growModifier); private void OnChangeHull(Vector2 pos, Hull particleHull) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs index 6a5d96f45..32d49292c 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs @@ -660,6 +660,25 @@ namespace Barotrauma } } + public string DisplayName + { + get; + private set; + } + + private string roomName; + [Editable, Serialize("", true, translationTextTag: "RoomName.")] + public string RoomName + { + get { return roomName; } + set + { + if (roomName == value) { return; } + roomName = value; + DisplayName = TextManager.Get(roomName, returnNull: true) ?? roomName; + } + } + public override Rectangle Rect { get diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs index 5bace8352..695b56df0 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs @@ -138,6 +138,9 @@ namespace Barotrauma public Submarine StartOutpost { get; private set; } public Submarine EndOutpost { get; private set; } + private Submarine preSelectedStartOutpost; + private Submarine preSelectedEndOutpost; + public string Seed { get { return seed; } @@ -209,7 +212,7 @@ namespace Barotrauma /// /// A scalar between 0-100 /// A scalar between 0-1 (0 = the minimum width defined in the generation params is used, 1 = the max width is used) - public Level(string seed, float difficulty, float sizeFactor, LevelGenerationParams generationParams, Biome biome) + public Level(string seed, float difficulty, float sizeFactor, LevelGenerationParams generationParams, Biome biome, Submarine startOutpost = null, Submarine endOutPost = null) : base(null) { @@ -225,6 +228,9 @@ namespace Barotrauma (width / GridCellSize) * GridCellSize, (generationParams.Height / GridCellSize) * GridCellSize); + preSelectedStartOutpost = startOutpost; + preSelectedEndOutpost = endOutPost; + //remove from entity dictionary base.Remove(); } @@ -1510,14 +1516,24 @@ namespace Barotrauma continue; } - //only create a starting outpost in campaign mode - if (GameMain.GameSession?.GameMode as CampaignMode == null && ((i == 0) == !Mirrored)) + //only create a starting outpost in campaign and tutorial modes + if (!IsModeStartOutpostCompatible() && ((i == 0) == !Mirrored)) { continue; } - - string outpostFile = outpostFiles.GetRandom(Rand.RandSync.Server); - var outpost = new Submarine(outpostFile, tryLoad: false); + + Submarine outpost = null; + + if (i == 0 && preSelectedStartOutpost == null || i == 1 && preSelectedEndOutpost == null) + { + string outpostFile = outpostFiles.GetRandom(Rand.RandSync.Server); + outpost = new Submarine(outpostFile, tryLoad: false); + } + else + { + outpost = (i == 0) ? preSelectedStartOutpost : preSelectedEndOutpost; + } + outpost.Load(unloadPrevious: false); outpost.MakeOutpost(); @@ -1569,6 +1585,15 @@ namespace Barotrauma } } + private bool IsModeStartOutpostCompatible() + { +#if CLIENT + return GameMain.GameSession?.GameMode as CampaignMode != null || GameMain.GameSession?.GameMode as TutorialMode != null; +#else + return GameMain.GameSession?.GameMode as CampaignMode != null; +#endif + } + public override void Remove() { base.Remove(); diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index ab486666c..b686f5dac 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -431,6 +431,12 @@ namespace Barotrauma else if (ic is Pickable pickable) { //prevent picking up (or deattaching) items +#if CLIENT + if (GameMain.GameSession.GameMode is TutorialMode) + { + continue; + } +#endif pickable.CanBePicked = false; pickable.CanBeSelected = false; } @@ -1426,7 +1432,7 @@ namespace Barotrauma doc.Root.Add(new XAttribute("md5hash", hash.Hash)); if (previewImage != null) { - doc.Root.Add(new XAttribute("previewimage", Convert.ToBase64String(previewImage.ToArray()))); + //doc.Root.Add(new XAttribute("previewimage", Convert.ToBase64String(previewImage.ToArray()))); } try diff --git a/Barotrauma/BarotraumaShared/Source/PlayerInput.cs b/Barotrauma/BarotraumaShared/Source/PlayerInput.cs index 8ad826eea..e13028523 100644 --- a/Barotrauma/BarotraumaShared/Source/PlayerInput.cs +++ b/Barotrauma/BarotraumaShared/Source/PlayerInput.cs @@ -162,21 +162,6 @@ namespace Barotrauma get { return binding; } } - public void SetState() - { - hit = binding.IsHit(); - if (hit) hitQueue = true; - - held = binding.IsDown(); - if (held) heldQueue = true; - } -#endif - - public KeyOrMouse State - { - get { return binding; } - } - public void SetState() { hit = binding.IsHit(); diff --git a/Barotrauma/BarotraumaShared/Source/Serialization/XMLExtensions.cs b/Barotrauma/BarotraumaShared/Source/Serialization/XMLExtensions.cs index 8f9090ae9..10b3691c6 100644 --- a/Barotrauma/BarotraumaShared/Source/Serialization/XMLExtensions.cs +++ b/Barotrauma/BarotraumaShared/Source/Serialization/XMLExtensions.cs @@ -46,7 +46,15 @@ namespace Barotrauma if (File.Exists(filePath)) { - doc = XDocument.Load(filePath, LoadOptions.SetBaseUri); + try + { + doc = XDocument.Load(filePath, LoadOptions.SetBaseUri); + } + catch + { + return null; + } + if (doc.Root == null) return null; } diff --git a/Barotrauma/BarotraumaShared/Source/TextManager.cs b/Barotrauma/BarotraumaShared/Source/TextManager.cs index 52df9ac7b..9a0e023c7 100644 --- a/Barotrauma/BarotraumaShared/Source/TextManager.cs +++ b/Barotrauma/BarotraumaShared/Source/TextManager.cs @@ -79,6 +79,40 @@ namespace Barotrauma } public static string Get(string textTag, bool returnNull = false) + { + if (!textPacks.ContainsKey(Language)) + { + DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English..."); + Language = "English"; + if (!textPacks.ContainsKey(Language)) + { + throw new Exception("No text packs available in English!"); + } + } + } + + public static string GetFormatted(string textTag, bool returnNull = false, params object[] args) + { + string text = Get(textTag, returnNull); + + if (text == null || text.Length == 0) + { + if (returnNull) + { + return null; + } + else + { + DebugConsole.ThrowError("Text \"" + textTag + "\" not found."); + return textTag; + } + } + + return string.Format(text, args); + } + + // Format: ServerMessage.Identifier1/ServerMessage.Indentifier2~[variable1]=value~[variable2]=value + public static string GetServerMessage(string serverMessage) { if (!textPacks.ContainsKey(Language)) { @@ -118,6 +152,16 @@ namespace Barotrauma } } + public static string ParseInputTypes(string text) + { + foreach (InputType inputType in Enum.GetValues(typeof(InputType))) + { + text = text.Replace("[" + inputType.ToString().ToLowerInvariant() + "]", GameMain.Config.KeyBind(inputType).ToString()); + text = text.Replace("[InputType." + inputType.ToString() + "]", GameMain.Config.KeyBind(inputType).ToString()); + } + return text; + } + public static string GetFormatted(string textTag, bool returnNull = false, params object[] args) { string text = Get(textTag, returnNull); diff --git a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub index 1875ad5b0..cd2d2b7eb 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Dugong.sub and b/Barotrauma/BarotraumaShared/Submarines/Dugong.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Orca.sub b/Barotrauma/BarotraumaShared/Submarines/Orca.sub index bc01cbce0..1884e59b0 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Orca.sub and b/Barotrauma/BarotraumaShared/Submarines/Orca.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/TutorialOutpost.sub b/Barotrauma/BarotraumaShared/Submarines/TutorialOutpost.sub index 3e5085c2e..79e598573 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/TutorialOutpost.sub and b/Barotrauma/BarotraumaShared/Submarines/TutorialOutpost.sub differ diff --git a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub index 102edb6f8..b43126315 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Typhon.sub and b/Barotrauma/BarotraumaShared/Submarines/Typhon.sub differ