From 89406896cadbec5e4f71de39084274e14005f70c Mon Sep 17 00:00:00 2001 From: Regalis Date: Tue, 2 Feb 2016 19:04:15 +0200 Subject: [PATCH] Editor usable without console, HiddenSubPosition divisible with grid size --- Subsurface/Source/GUI/GUI.cs | 8 +- Subsurface/Source/GUI/GUIComponent.cs | 2 +- Subsurface/Source/GUI/GUITextBox.cs | 5 + Subsurface/Source/Map/Submarine.cs | 9 +- Subsurface/Source/Screens/EditMapScreen.cs | 212 ++++++++++++++++---- Subsurface/Source/Screens/MainMenuScreen.cs | 33 ++- Subsurface_Solution.v12.suo | Bin 922112 -> 908800 bytes 7 files changed, 208 insertions(+), 61 deletions(-) diff --git a/Subsurface/Source/GUI/GUI.cs b/Subsurface/Source/GUI/GUI.cs index d63eda23f..a227e2f9f 100644 --- a/Subsurface/Source/GUI/GUI.cs +++ b/Subsurface/Source/GUI/GUI.cs @@ -324,12 +324,12 @@ namespace Barotrauma ScreenOverlayColor, true); } - spriteBatch.DrawString(Font, - "FPS: " + (int)GameMain.FrameCounter.AverageFramesPerSecond, - new Vector2(10, 10), Color.White); - if (GameMain.DebugDraw) { + spriteBatch.DrawString(Font, + "FPS: " + (int)GameMain.FrameCounter.AverageFramesPerSecond, + new Vector2(10, 10), Color.White); + spriteBatch.DrawString(Font, "Physics: " + GameMain.World.UpdateTime, new Vector2(10, 30), Color.White); diff --git a/Subsurface/Source/GUI/GUIComponent.cs b/Subsurface/Source/GUI/GUIComponent.cs index 81e43e3b5..c2de9d40b 100644 --- a/Subsurface/Source/GUI/GUIComponent.cs +++ b/Subsurface/Source/GUI/GUIComponent.cs @@ -203,7 +203,7 @@ namespace Barotrauma return false; } - public void Flash(Color? color = null) + public virtual void Flash(Color? color = null) { flashTimer = FlashDuration; flashColor = (color == null) ? Color.Red * 0.8f : (Color)color; diff --git a/Subsurface/Source/GUI/GUITextBox.cs b/Subsurface/Source/GUI/GUITextBox.cs index 897f680e4..47d29dc84 100644 --- a/Subsurface/Source/GUI/GUITextBox.cs +++ b/Subsurface/Source/GUI/GUITextBox.cs @@ -171,6 +171,11 @@ namespace Barotrauma if (keyboardDispatcher.Subscriber == this) keyboardDispatcher.Subscriber = null; } + public override void Flash(Color? color = null) + { + textBlock.Flash(color); + } + //MouseState previousMouse; public override void Update(float deltaTime) { diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 6ef3443e1..5f46b32fb 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -1,18 +1,15 @@ using FarseerPhysics; -using FarseerPhysics.Collision; using FarseerPhysics.Common; using FarseerPhysics.Dynamics; using Lidgren.Network; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using Barotrauma.Items.Components; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Xml.Linq; -using Barotrauma.Lights; namespace Barotrauma { @@ -27,7 +24,7 @@ namespace Barotrauma //position of the "actual submarine" which is rendered wherever the SubmarineBody is //should be in an unreachable place - public static readonly Vector2 HiddenSubPosition = new Vector2(0.0f, 50000.0f); + public static readonly Vector2 HiddenSubPosition = new Vector2(0.0f, 50032.0f); public static List SavedSubmarines = new List(); @@ -517,6 +514,8 @@ namespace Barotrauma // return; } + loaded.filePath = SavePath + System.IO.Path.DirectorySeparatorChar + fileName; + return loaded.SaveAs(SavePath+System.IO.Path.DirectorySeparatorChar+fileName); } @@ -524,7 +523,7 @@ namespace Barotrauma { //string[] mapFilePaths; - Unload(); + //Unload(); SavedSubmarines.Clear(); if (!Directory.Exists(SavePath)) diff --git a/Subsurface/Source/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs index b0b02e5a1..999f3ac4e 100644 --- a/Subsurface/Source/Screens/EditMapScreen.cs +++ b/Subsurface/Source/Screens/EditMapScreen.cs @@ -10,11 +10,13 @@ namespace Barotrauma { private Camera cam; - public GUIComponent GUIpanel; + public GUIComponent topPanel, leftPanel; private GUIComponent[] GUItabs; private int selectedTab; + private GUIFrame loadFrame; + private GUITextBox nameBox; const int PreviouslyUsedCount = 10; @@ -70,26 +72,35 @@ namespace Barotrauma selectedTab = -1; - GUIpanel = new GUIFrame(new Rectangle(0, 0, 150, GameMain.GraphicsHeight), GUI.Style); - GUIpanel.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f); + topPanel = new GUIFrame(new Rectangle(0, 0, 0, 31), GUI.Style); + topPanel.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f); + + var button = new GUIButton(new Rectangle(0, 0, 70, 20), "Open...", GUI.Style, topPanel); + button.OnClicked = CreateLoadScreen; + + // var nameBlock =new GUITextBlock(new Rectangle(0, 20, 0, 20), "Submarine:", GUI.Style, leftPanel); + nameBox = new GUITextBox(new Rectangle(150, 0, 150, 20), GUI.Style, topPanel); + nameBox.OnEnterPressed = ChangeSubName; + + button = new GUIButton(new Rectangle(310,0,70,20), "Save", GUI.Style, topPanel); + button.OnClicked = SaveSub; + + leftPanel = new GUIFrame(new Rectangle(0, 30, 150, GameMain.GraphicsHeight-30), GUI.Style); + leftPanel.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f); //GUIListBox constructionList = new GUIListBox(new Rectangle(0, 0, 0, 300), Color.White * 0.7f, GUIpanel); //constructionList.OnSelected = MapEntityPrefab.SelectPrefab; //constructionList.CheckSelected = MapEntityPrefab.GetSelected; - var nameBlock =new GUITextBlock(new Rectangle(0, 20, 0, 20), "Submarine:", GUI.Style, GUIpanel); - //nameBox = new GUITextBox(new Rectangle(0, 40, 0, 20), GUI.Style, GUIpanel); - //nameBox.OnEnterPressed = ChangeSubName; - nameBlock.TextGetter = GetSubName; //GUIButton button = new GUIButton(new Rectangle(0,70,0,20), "Save", GUI.Style, GUIpanel); //button.OnClicked = SaveSub; - GUITextBlock itemCount = new GUITextBlock(new Rectangle(0, 100, 0, 20), "", GUI.Style, GUIpanel); + GUITextBlock itemCount = new GUITextBlock(new Rectangle(0, 30, 0, 20), "", GUI.Style, leftPanel); itemCount.TextGetter = GetItemCount; - GUITextBlock structureCount = new GUITextBlock(new Rectangle(0, 120, 0, 20), "", GUI.Style, GUIpanel); + GUITextBlock structureCount = new GUITextBlock(new Rectangle(0, 50, 0, 20), "", GUI.Style, leftPanel); structureCount.TextGetter = GetStructureCount; //GUITextBlock physicsBodyCount = new GUITextBlock(new Rectangle(0, 120, 0, 20), "", GUI.Style, GUIpanel); @@ -105,11 +116,11 @@ namespace Barotrauma int width = 400, height = 400; - int y = 160; + int y = 90; int i = 0; foreach (MapEntityCategory category in Enum.GetValues(typeof(MapEntityCategory))) { - var catButton = new GUIButton(new Rectangle(0, y, 0, 20), category.ToString(), Alignment.Left, GUI.Style, GUIpanel); + var catButton = new GUIButton(new Rectangle(0, y, 0, 20), category.ToString(), Alignment.Left, GUI.Style, leftPanel); catButton.UserData = i; catButton.OnClicked = SelectTab; y+=25; @@ -161,31 +172,32 @@ namespace Barotrauma } y+=50; - var button = new GUIButton(new Rectangle(0, y, 0, 20), "Character mode", Alignment.Left, GUI.Style, GUIpanel); + button = new GUIButton(new Rectangle(0, y, 0, 20), "Character mode", Alignment.Left, GUI.Style, leftPanel); button.ToolTip = "Allows you to pick up and use items. Useful for things such as placing items inside closets, turning devices on/off and doing the wiring."; button.OnClicked = ToggleCharacterMode; y+=50; - button = new GUIButton(new Rectangle(0, y, 0, 20), "Generate waypoints", Alignment.Left, GUI.Style, GUIpanel); + button = new GUIButton(new Rectangle(0, y, 0, 20), "Generate waypoints", Alignment.Left, GUI.Style, leftPanel); + button.ToolTip = "AI controlled crew members require waypoints to navigate around the sub."; button.OnClicked = GenerateWaypoints; y+=50; - new GUITextBlock(new Rectangle(0, y, 0, 20), "Show:", GUI.Style, GUIpanel); + new GUITextBlock(new Rectangle(0, y, 0, 20), "Show:", GUI.Style, leftPanel); - var tickBox = new GUITickBox(new Rectangle(0,y+20,20,20), "Waypoints", Alignment.TopLeft, GUIpanel); + var tickBox = new GUITickBox(new Rectangle(0,y+20,20,20), "Waypoints", Alignment.TopLeft, leftPanel); tickBox.OnSelected = (GUITickBox obj) => { WayPoint.ShowWayPoints = !WayPoint.ShowWayPoints; return true; }; tickBox.Selected = true; - tickBox = new GUITickBox(new Rectangle(0, y + 45, 20, 20), "Spawnpoints", Alignment.TopLeft, GUIpanel); + tickBox = new GUITickBox(new Rectangle(0, y + 45, 20, 20), "Spawnpoints", Alignment.TopLeft, leftPanel); tickBox.OnSelected = (GUITickBox obj) => { WayPoint.ShowSpawnPoints = !WayPoint.ShowSpawnPoints; return true; }; tickBox.Selected = true; - tickBox = new GUITickBox(new Rectangle(0, y + 70, 20, 20), "Links", Alignment.TopLeft, GUIpanel); + tickBox = new GUITickBox(new Rectangle(0, y + 70, 20, 20), "Links", Alignment.TopLeft, leftPanel); tickBox.OnSelected = (GUITickBox obj) => { Item.ShowLinks = !Item.ShowLinks; return true; }; tickBox.Selected = true; - tickBox = new GUITickBox(new Rectangle(0, y + 95, 20, 20), "Hulls", Alignment.TopLeft, GUIpanel); + tickBox = new GUITickBox(new Rectangle(0, y + 95, 20, 20), "Hulls", Alignment.TopLeft, leftPanel); tickBox.OnSelected = (GUITickBox obj) => { Hull.ShowHulls = !Hull.ShowHulls; return true; }; tickBox.Selected = true; - tickBox = new GUITickBox(new Rectangle(0, y + 120, 20, 20), "Gaps", Alignment.TopLeft, GUIpanel); + tickBox = new GUITickBox(new Rectangle(0, y + 120, 20, 20), "Gaps", Alignment.TopLeft, leftPanel); tickBox.OnSelected = (GUITickBox obj) => { Gap.ShowGaps = !Gap.ShowGaps; return true; }; tickBox.Selected = true; @@ -193,9 +205,9 @@ namespace Barotrauma if (y < GameMain.GraphicsHeight - 100) { - new GUITextBlock(new Rectangle(0, y, 0, 15), "Previously used:", GUI.Style, GUIpanel); + new GUITextBlock(new Rectangle(0, y, 0, 15), "Previously used:", GUI.Style, leftPanel); - previouslyUsedList = new GUIListBox(new Rectangle(0, y + 15, 0, Math.Min(GameMain.GraphicsHeight - y - 40, 150)), GUI.Style, GUIpanel); + previouslyUsedList = new GUIListBox(new Rectangle(0, y + 15, 0, Math.Min(GameMain.GraphicsHeight - y - 40, 150)), GUI.Style, leftPanel); previouslyUsedList.OnSelected = SelectPrefab; } @@ -218,13 +230,16 @@ namespace Barotrauma if (Submarine.Loaded != null) { cam.Position = Submarine.Loaded.Position + Submarine.HiddenSubPosition; - //nameBox.Text = Submarine.Loaded.Name; + nameBox.Text = Submarine.Loaded.Name; } else { cam.Position = Submarine.HiddenSubPosition; + nameBox.Text = ""; } + nameBox.Deselect(); + cam.UpdateTransform(); } @@ -252,7 +267,7 @@ namespace Barotrauma for (int i = 0; i + { + var deleteBtn = loadFrame.FindChild("delete") as GUIButton; + if (deleteBtn != null) deleteBtn.Enabled = true; + + return true; + }; + + foreach (Submarine sub in Submarine.SavedSubmarines) + { + GUITextBlock textBlock = new GUITextBlock( + new Rectangle(0, 0, 0, 25), + sub.Name, + GUI.Style, + Alignment.Left, Alignment.Left, subList); + textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); + textBlock.UserData = sub; + textBlock.ToolTip = sub.FilePath; + } + + var deleteButton = new GUIButton(new Rectangle(0, 0, 70, 20), "Delete", Alignment.BottomLeft, GUI.Style, loadFrame); + deleteButton.Enabled = false; + deleteButton.UserData = "delete"; + deleteButton.OnClicked = (GUIButton btn, object userdata) => + { + var subListBox = loadFrame.GetChild(); + + if (subList.Selected!=null) + { + Submarine sub = subList.Selected.UserData as Submarine; + try + { + System.IO.File.Delete(sub.FilePath); + } + catch (Exception e) + { + DebugConsole.ThrowError("Couldn't delete file ''"+sub.FilePath+"''!", e); + } + } + + deleteButton.Enabled = false; + + CreateLoadScreen(null, null); + + return true; + }; + + var loadButton = new GUIButton(new Rectangle(-90, 0, 80, 20), "Load", Alignment.Right | Alignment.Bottom, GUI.Style, loadFrame); + loadButton.OnClicked = LoadSub; + + var cancelButton = new GUIButton(new Rectangle(0, 0, 80, 20), "Cancel", Alignment.Right | Alignment.Bottom, GUI.Style, loadFrame); + cancelButton.OnClicked = (GUIButton btn, object userdata) => + { + loadFrame = null; + return true; + }; + + return true; + } + + private bool LoadSub(GUIButton button, object obj) + { + GUIListBox subList = loadFrame.GetChild(); + + if (subList.Selected == null) return false; + + Submarine selectedSub = subList.Selected.UserData as Submarine; + + if (selectedSub == null) return false; + + selectedSub.Load(); + + nameBox.Text = selectedSub.Name; + + loadFrame = null; + + return true; + } + private bool SelectTab(GUIButton button, object obj) { selectedTab = (int)obj; @@ -332,15 +431,23 @@ namespace Barotrauma return true; } - //private bool ChangeSubName(GUITextBox textBox, string text) - //{ - // if (Submarine.Loaded != null) Submarine.Loaded.Name = text; - // textBox.Deselect(); + private bool ChangeSubName(GUITextBox textBox, string text) + { + if (string.IsNullOrWhiteSpace(text)) + { + textBox.Flash(Color.Red); + return false; + } - // textBox.Text = text; + if (Submarine.Loaded != null) Submarine.Loaded.Name = text; + textBox.Deselect(); - // return true; - //} + textBox.Text = text; + + textBox.Flash(Color.Green); + + return true; + } private bool SelectPrefab(GUIComponent component, object obj) { @@ -393,10 +500,15 @@ namespace Barotrauma /// Provides a snapshot of timing values. public override void Update(double deltaTime) { - if (tutorial!=null) tutorial.Update((float)deltaTime); + if (tutorial != null) tutorial.Update((float)deltaTime); if (GUIComponent.MouseOn == null) { + if (nameBox.Selected && PlayerInput.LeftButtonClicked()) + { + ChangeSubName(nameBox, nameBox.Text); + } + cam.MoveCamera((float)deltaTime); //cam.Zoom = MathHelper.Clamp(cam.Zoom + (PlayerInput.ScrollWheelSpeed / 1000.0f)*cam.Zoom, 0.1f, 2.0f); } @@ -435,8 +547,16 @@ namespace Barotrauma } GUIComponent.MouseOn = null; - GUIpanel.Update((float)deltaTime); - if (selectedTab > -1) + + leftPanel.Update((float)deltaTime); + topPanel.Update((float)deltaTime); + + if (loadFrame!=null) + { + loadFrame.Update((float)deltaTime); + if (PlayerInput.RightButtonClicked()) loadFrame = null; + } + else if (selectedTab > -1) { GUItabs[selectedTab].Update((float)deltaTime); if (PlayerInput.RightButtonClicked()) selectedTab = -1; @@ -473,7 +593,8 @@ namespace Barotrauma spriteBatch.Begin(); - GUIpanel.Draw(spriteBatch); + leftPanel.Draw(spriteBatch); + topPanel.Draw(spriteBatch); //EntityPrefab.DrawList(spriteBatch, new Vector2(20,50)); @@ -512,7 +633,14 @@ namespace Barotrauma } else { - if (selectedTab > -1) GUItabs[selectedTab].Draw(spriteBatch); + if (loadFrame!=null) + { + loadFrame.Draw(spriteBatch); + } + else if (selectedTab > -1) + { + GUItabs[selectedTab].Draw(spriteBatch); + } MapEntity.Edit(spriteBatch, cam); } diff --git a/Subsurface/Source/Screens/MainMenuScreen.cs b/Subsurface/Source/Screens/MainMenuScreen.cs index 49e649c3f..f870fb958 100644 --- a/Subsurface/Source/Screens/MainMenuScreen.cs +++ b/Subsurface/Source/Screens/MainMenuScreen.cs @@ -33,37 +33,52 @@ namespace Barotrauma - buttonsTab = new GUIFrame(new Rectangle(50, 0, 200, 360), Color.Transparent, Alignment.Left | Alignment.CenterY); + buttonsTab = new GUIFrame(new Rectangle(0,0,0,0), Color.Transparent, Alignment.Left | Alignment.CenterY); + buttonsTab.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); //menuTabs[(int)Tabs.Main].Padding = GUI.style.smallPadding; + + int y = 170; + Rectangle panelRect = new Rectangle( - 290, buttonsTab.Rect.Y, + 290, y, 500, 360); - GUIButton button = new GUIButton(new Rectangle(0, 0, 0, 30), "Tutorial", Alignment.CenterX, GUI.Style, buttonsTab); + GUIButton button = new GUIButton(new Rectangle(50, y, 200, 30), "Tutorial", null, Alignment.TopLeft, Alignment.Left, GUI.Style, buttonsTab); + button.Color = button.Color * 0.8f; button.OnClicked = TutorialButtonClicked; - button = new GUIButton(new Rectangle(0, 60, 0, 30), "New Game", Alignment.CenterX, GUI.Style, buttonsTab); + button = new GUIButton(new Rectangle(50, y + 60, 200, 30), "New Game", null, Alignment.TopLeft, Alignment.Left, GUI.Style, buttonsTab); + button.Color = button.Color * 0.8f; button.UserData = Tab.NewGame; button.OnClicked = SelectTab; - button = new GUIButton(new Rectangle(0, 100, 0, 30), "Load Game", Alignment.CenterX, GUI.Style, buttonsTab); + button = new GUIButton(new Rectangle(50, y + 100, 200, 30), "Load Game", null, Alignment.TopLeft, Alignment.Left, GUI.Style, buttonsTab); + button.Color = button.Color * 0.8f; button.UserData = Tab.LoadGame; button.OnClicked = SelectTab; - button = new GUIButton(new Rectangle(0, 160, 0, 30), "Join Server", Alignment.CenterX, GUI.Style, buttonsTab); + button = new GUIButton(new Rectangle(50, y + 160, 200, 30), "Join Server", null, Alignment.TopLeft, Alignment.Left, GUI.Style, buttonsTab); + button.Color = button.Color * 0.8f; //button.UserData = (int)Tabs.JoinServer; button.OnClicked = JoinServerClicked; - button = new GUIButton(new Rectangle(0, 200, 0, 30), "Host Server", Alignment.CenterX, GUI.Style, buttonsTab); + button = new GUIButton(new Rectangle(50, y + 200, 200, 30), "Host Server", null, Alignment.TopLeft, Alignment.Left, GUI.Style, buttonsTab); + button.Color = button.Color * 0.8f; button.UserData = Tab.HostServer; button.OnClicked = SelectTab; - button = new GUIButton(new Rectangle(0, 260, 0, 30), "Settings", Alignment.CenterX, GUI.Style, buttonsTab); + button = new GUIButton(new Rectangle(50, y + 260, 200, 30), "Submarine Editor", null, Alignment.TopLeft, Alignment.Left, GUI.Style, buttonsTab); + button.Color = button.Color * 0.8f; + button.OnClicked = (GUIButton btn, object userdata) => { GameMain.EditMapScreen.Select(); return true; }; + + button = new GUIButton(new Rectangle(50, y + 320, 200, 30), "Settings", null, Alignment.TopLeft, Alignment.Left, GUI.Style, buttonsTab); + button.Color = button.Color * 0.8f; button.UserData = Tab.Settings; button.OnClicked = SelectTab; - button = new GUIButton(new Rectangle(0, 320, 0, 30), "Quit", Alignment.CenterX, GUI.Style, buttonsTab); + button = new GUIButton(new Rectangle(0, 0, 150, 30), "Quit", Alignment.BottomRight, GUI.Style, buttonsTab); + button.Color = button.Color * 0.8f; button.OnClicked = QuitClicked; //---------------------------------------------------------------------- diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 75965e6de37897662f7c5f52493015c609ae3ab0..64899467dfc7d3ef21606bd49a574508f37b8b35 100644 GIT binary patch delta 9332 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 QI-1GU+!5OU$A1$33x^V_pa1{> delta 11408 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 I|LF<-H^1t`X#fBK