diff --git a/Farseer Physics Engine 3.5/Farseer Physics Engine.v12.suo b/Farseer Physics Engine 3.5/Farseer Physics Engine.v12.suo new file mode 100644 index 000000000..7d0e3e068 Binary files /dev/null and b/Farseer Physics Engine 3.5/Farseer Physics Engine.v12.suo differ diff --git a/Launcher/Form1.cs b/Launcher/Form1.cs index d80ed81b5..9a92d6ccc 100644 --- a/Launcher/Form1.cs +++ b/Launcher/Form1.cs @@ -17,7 +17,6 @@ namespace Launcher { public partial class LauncherMain : Form { - public static string ContentPackageFolder = "Data/ContentPackages/"; private const string configPath = "config.xml"; private Subsurface.GameSettings settings; @@ -42,7 +41,7 @@ namespace Launcher { InitializeComponent(); - ContentPackage.LoadAll(LauncherMain.ContentPackageFolder); + ContentPackage.LoadAll(ContentPackage.Folder); contentPackageBox.DataSource = ContentPackage.list; supportedModes = new List(); diff --git a/Launcher/PackageManager.Designer.cs b/Launcher/PackageManager.Designer.cs index 9cfc78428..7584ed37e 100644 --- a/Launcher/PackageManager.Designer.cs +++ b/Launcher/PackageManager.Designer.cs @@ -102,6 +102,7 @@ this.itemList.Name = "itemList"; this.itemList.Size = new System.Drawing.Size(255, 134); this.itemList.TabIndex = 8; + this.itemList.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.fileList_KeyPress); // // itemButton // @@ -161,6 +162,7 @@ this.structureList.Name = "structureList"; this.structureList.Size = new System.Drawing.Size(255, 121); this.structureList.TabIndex = 8; + this.structureList.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.fileList_KeyPress); // // structureButton // @@ -189,6 +191,7 @@ this.jobList.Name = "jobList"; this.jobList.Size = new System.Drawing.Size(255, 134); this.jobList.TabIndex = 11; + this.jobList.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.fileList_KeyPress); // // label4 // diff --git a/Launcher/PackageManager.cs b/Launcher/PackageManager.cs index 61e9b7e2e..420b1fdd6 100644 --- a/Launcher/PackageManager.cs +++ b/Launcher/PackageManager.cs @@ -96,28 +96,25 @@ namespace Launcher fileButton.Enabled = (selectedPackage != null); } - if (selectedPackage == null) + + foreach (ListBox fileBox in fileBoxes) { - foreach (ListBox fileBox in fileBoxes) + fileBox.Items.Clear(); + } + + + foreach (ListBox fileBox in fileBoxes) + { + ContentType type = (fileBox.Tag is ContentType) ? (ContentType)fileBox.Tag : ContentType.None; + + foreach (ContentFile file in selectedPackage.files) { - fileBox.Items.Clear(); - } - } - else - { - - foreach (ListBox fileBox in fileBoxes) - { - ContentType type = (fileBox.Tag is ContentType) ? (ContentType)fileBox.Tag : ContentType.None; - - foreach (ContentFile file in selectedPackage.files) - { - if (file.type != type) continue; - - fileBox.Items.Add(file); - } + if (file.type != type) continue; + + fileBox.Items.Add(file); } } + } private void newPackage_Click(object sender, EventArgs e) @@ -145,7 +142,7 @@ namespace Launcher OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "XML files (*.xml)|*.xml;*.XML"; - //ofd.RestoreDirectory? + ofd.RestoreDirectory = true; if (ofd.ShowDialog() == DialogResult.OK) { @@ -256,7 +253,7 @@ namespace Launcher private void okButton_Click(object sender, EventArgs e) { - if (selectedPackage!=null) selectedPackage.Save(LauncherMain.ContentPackageFolder); + if (selectedPackage!=null) selectedPackage.Save(ContentPackage.Folder); this.Close(); } diff --git a/Subsurface/Content/Items/Electricity/poweritems.xml b/Subsurface/Content/Items/Electricity/poweritems.xml index a57442421..fb0260648 100644 --- a/Subsurface/Content/Items/Electricity/poweritems.xml +++ b/Subsurface/Content/Items/Electricity/poweritems.xml @@ -41,7 +41,27 @@ - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Subsurface/Content/Items/Electricity/regex.png b/Subsurface/Content/Items/Electricity/regex.png new file mode 100644 index 000000000..52a4c0295 Binary files /dev/null and b/Subsurface/Content/Items/Electricity/regex.png differ diff --git a/Subsurface/Content/Items/Electricity/signalitems.xml b/Subsurface/Content/Items/Electricity/signalitems.xml index 7bcb2e020..c42fd6b19 100644 --- a/Subsurface/Content/Items/Electricity/signalitems.xml +++ b/Subsurface/Content/Items/Electricity/signalitems.xml @@ -185,7 +185,7 @@ linkable="true" price="10"> - + @@ -203,5 +203,30 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Subsurface/Content/Items/Electricity/supercapacitor.png b/Subsurface/Content/Items/Electricity/supercapacitor.png new file mode 100644 index 000000000..46eab4595 Binary files /dev/null and b/Subsurface/Content/Items/Electricity/supercapacitor.png differ diff --git a/Subsurface/Content/Items/Electricity/wifi.png b/Subsurface/Content/Items/Electricity/wifi.png new file mode 100644 index 000000000..bb63ff272 Binary files /dev/null and b/Subsurface/Content/Items/Electricity/wifi.png differ diff --git a/Subsurface/Content/Items/Ladder/item.xml b/Subsurface/Content/Items/Ladder/ladder.xml similarity index 100% rename from Subsurface/Content/Items/Ladder/item.xml rename to Subsurface/Content/Items/Ladder/ladder.xml diff --git a/Subsurface/Content/Items/Reactor/reactor.xml b/Subsurface/Content/Items/Reactor/reactor.xml index 758928870..306b9b1f0 100644 --- a/Subsurface/Content/Items/Reactor/reactor.xml +++ b/Subsurface/Content/Items/Reactor/reactor.xml @@ -34,6 +34,8 @@ + + diff --git a/Subsurface/Content/Items/blank.png b/Subsurface/Content/Items/blank.png new file mode 100644 index 000000000..9a1af9801 Binary files /dev/null and b/Subsurface/Content/Items/blank.png differ diff --git a/Subsurface/Content/Items/idcard.xml b/Subsurface/Content/Items/idcard.xml index 045bd351d..8e75e69f1 100644 --- a/Subsurface/Content/Items/idcard.xml +++ b/Subsurface/Content/Items/idcard.xml @@ -5,9 +5,9 @@ Tags="smallitem" pickdistance="150"> - + - + diff --git a/Subsurface/Content/Items/itemlabel.xml b/Subsurface/Content/Items/itemlabel.xml new file mode 100644 index 000000000..56e4fcc9f --- /dev/null +++ b/Subsurface/Content/Items/itemlabel.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/Subsurface/Content/Jobs.xml b/Subsurface/Content/Jobs.xml index a9fc829e4..8316e2e55 100644 --- a/Subsurface/Content/Jobs.xml +++ b/Subsurface/Content/Jobs.xml @@ -13,7 +13,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/Subsurface/Content/UI/style.xml b/Subsurface/Content/UI/style.xml index 73b0c7357..5fb091a28 100644 --- a/Subsurface/Content/UI/style.xml +++ b/Subsurface/Content/UI/style.xml @@ -54,6 +54,13 @@ + + + + 0) { charElement.Add(new XAttribute("items", string.Join(",", pickedItems))); diff --git a/Subsurface/Source/Characters/HumanoidAnimController.cs b/Subsurface/Source/Characters/HumanoidAnimController.cs index a887f35e3..553a13752 100644 --- a/Subsurface/Source/Characters/HumanoidAnimController.cs +++ b/Subsurface/Source/Characters/HumanoidAnimController.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Xml.Linq; using FarseerPhysics; using Microsoft.Xna.Framework; +using Subsurface.Items.Components; namespace Subsurface { @@ -542,7 +543,7 @@ namespace Subsurface void UpdateClimbing() { - if (character.SelectedConstruction == null) + if (character.SelectedConstruction == null || character.SelectedConstruction.GetComponent()==null) { Anim = Animation.None; return; @@ -623,7 +624,12 @@ namespace Subsurface torso.body.ApplyForce(climbForce * 40.0f * torso.Mass); head.body.SmoothRotate(0.0f); - Rectangle trigger = character.SelectedConstruction.Prefab.Triggers.First(); + Rectangle trigger = character.SelectedConstruction.Prefab.Triggers.FirstOrDefault(); + if (trigger == null) + { + character.SelectedConstruction = null; + return; + } trigger = character.SelectedConstruction.TransformTrigger(trigger); //stop climbing if: @@ -673,10 +679,10 @@ namespace Subsurface Limb rightHand = GetLimb(LimbType.RightHand); Limb rightArm = GetLimb(LimbType.RightArm); - Vector2 itemPos = character.SecondaryKeyDown.State ? aimPos : holdPos; + Vector2 itemPos = character.GetInputState(InputType.SecondaryHeld) ? aimPos : holdPos; float itemAngle; - if (character.SecondaryKeyDown.State && itemPos != Vector2.Zero) + if (character.GetInputState(InputType.SecondaryHeld) && itemPos != Vector2.Zero) { Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition); diff --git a/Subsurface/Source/Characters/Ragdoll.cs b/Subsurface/Source/Characters/Ragdoll.cs index 0efc2b6b3..3187ed605 100644 --- a/Subsurface/Source/Characters/Ragdoll.cs +++ b/Subsurface/Source/Characters/Ragdoll.cs @@ -472,7 +472,7 @@ namespace Subsurface inWater = false; headInWater = false; - if (currentHull.Volume>currentHull.FullVolume*0.95f || ConvertUnits.ToSimUnits(currentHull.Surface)-floorY> HeadPosition*0.95f) + if (currentHull.Volume > currentHull.FullVolume * 0.95f || ConvertUnits.ToSimUnits(currentHull.Surface) - floorY > HeadPosition * 0.95f) inWater = true; } @@ -562,7 +562,7 @@ namespace Subsurface private void UpdateNetplayerPosition() { Limb refLimb = GetLimb(LimbType.Torso); - if (refLimb== null) refLimb = GetLimb(LimbType.Head); + if (refLimb == null) refLimb = GetLimb(LimbType.Head); if (refLimb.body.TargetPosition == Vector2.Zero) return; @@ -603,7 +603,7 @@ namespace Subsurface if (resetAll) { - System.Diagnostics.Debug.WriteLine("resetall"); + System.Diagnostics.Debug.WriteLine("reset ragdoll limb positions"); foreach (Limb limb in limbs) { diff --git a/Subsurface/Source/ContentPackage.cs b/Subsurface/Source/ContentPackage.cs index 98501441d..2a263b4cc 100644 --- a/Subsurface/Source/ContentPackage.cs +++ b/Subsurface/Source/ContentPackage.cs @@ -15,6 +15,9 @@ namespace Subsurface public class ContentPackage { + + public static string Folder = "Data/ContentPackages/"; + public static List list = new List(); @@ -81,6 +84,7 @@ namespace Subsurface { ContentPackage newPackage = new ContentPackage("Content/Data/"+name); newPackage.name = name; + newPackage.Path = Folder + name; list.Add(newPackage); return newPackage; diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs index 93b8f8047..edf99ab91 100644 --- a/Subsurface/Source/DebugConsole.cs +++ b/Subsurface/Source/DebugConsole.cs @@ -136,11 +136,13 @@ namespace Subsurface public static void ExecuteCommand(string command, Game1 game) { +#if !DEBUG if (Game1.Client!=null) { ThrowError("Console commands are disabled in multiplayer mode"); return; } +#endif if (command == "") return; string[] commands = command.Split(' '); @@ -246,6 +248,9 @@ namespace Subsurface hull.OxygenPercentage = 100.0f; } break; + case "tutorial": + TutorialMode.Start(); + break; case "lobbyscreen": case "lobby": Game1.LobbyScreen.Select(); diff --git a/Subsurface/Source/EventInput/KeyboardDispatcher.cs b/Subsurface/Source/EventInput/KeyboardDispatcher.cs index 9427af6d5..3026824bc 100644 --- a/Subsurface/Source/EventInput/KeyboardDispatcher.cs +++ b/Subsurface/Source/EventInput/KeyboardDispatcher.cs @@ -1,6 +1,8 @@ using System; using System.Threading; +#if WINDOWS using System.Windows; +#endif using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; @@ -42,12 +44,14 @@ namespace EventInput //ctrl-v if (e.Character == 0x16) { +#if WINDOWS //XNA runs in Multiple Thread Apartment state, which cannot recieve clipboard Thread thread = new Thread(PasteThread); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); _subscriber.ReceiveTextInput(_pasteResult); +#endif } else { @@ -74,6 +78,7 @@ namespace EventInput } } +#if WINDOWS //Thread has to be in Single Thread Apartment state in order to receive clipboard string _pasteResult = ""; [STAThread] @@ -81,5 +86,7 @@ namespace EventInput { _pasteResult = Clipboard.ContainsText() ? Clipboard.GetText() : ""; } +#endif + } } diff --git a/Subsurface/Source/GUI/GUI.cs b/Subsurface/Source/GUI/GUI.cs index 51f20f963..70b667c2d 100644 --- a/Subsurface/Source/GUI/GUI.cs +++ b/Subsurface/Source/GUI/GUI.cs @@ -20,7 +20,7 @@ namespace Subsurface public static GUIStyle style; static Texture2D t; - public static SpriteFont Font, SmallFont; + public static SpriteFont Font, SmallFont, LargeFont; private static GraphicsDevice graphicsDevice; @@ -274,7 +274,7 @@ namespace Subsurface bool clicked = false; - if (rect.Contains(PlayerInput.GetMouseState.Position)) + if (rect.Contains(PlayerInput.MousePosition)) { clicked = (PlayerInput.GetMouseState.LeftButton == ButtonState.Pressed); @@ -301,8 +301,16 @@ namespace Subsurface spriteBatch.DrawString(Font, "Physics: " + Game1.World.UpdateTime + " - bodies: " + Game1.World.BodyList.Count - + "Camera pos: " + Game1.GameScreen.Cam.Position, + + " Camera pos: " + Game1.GameScreen.Cam.Position, new Vector2(10, 30), Color.White); + + if (Submarine.Loaded!=null) + { + spriteBatch.DrawString(Font, + "Sub pos: " + Submarine.Loaded.Position, + new Vector2(10, 50), Color.White); + } + } diff --git a/Subsurface/Source/GUI/GUIButton.cs b/Subsurface/Source/GUI/GUIButton.cs index 0eacc727d..bb238ba04 100644 --- a/Subsurface/Source/GUI/GUIButton.cs +++ b/Subsurface/Source/GUI/GUIButton.cs @@ -60,7 +60,7 @@ namespace Subsurface public override void Draw(SpriteBatch spriteBatch) { - if (rect.Contains(PlayerInput.GetMouseState.Position) && Enabled && (MouseOn == null || MouseOn == this || IsParentOf(MouseOn))) + if (rect.Contains(PlayerInput.MousePosition) && Enabled && (MouseOn == null || MouseOn == this || IsParentOf(MouseOn))) { state = ComponentState.Hover; if (PlayerInput.GetMouseState.LeftButton == ButtonState.Pressed) diff --git a/Subsurface/Source/GUI/GUIListBox.cs b/Subsurface/Source/GUI/GUIListBox.cs index b8074a1c9..56e882201 100644 --- a/Subsurface/Source/GUI/GUIListBox.cs +++ b/Subsurface/Source/GUI/GUIListBox.cs @@ -27,6 +27,14 @@ namespace Subsurface private bool enabled; + public GUIComponent Selected + { + get + { + return selected; + } + } + public object SelectedData { get @@ -276,7 +284,7 @@ namespace Subsurface if (CheckSelected() != selected.UserData) selected = null; } } - else if (enabled && (MouseOn == this || (MouseOn != null && this.IsParentOf(MouseOn))) && child.Rect.Contains(PlayerInput.GetMouseState.Position)) + else if (enabled && (MouseOn == this || (MouseOn != null && this.IsParentOf(MouseOn))) && child.Rect.Contains(PlayerInput.MousePosition)) { child.State = ComponentState.Hover; if (PlayerInput.LeftButtonClicked()) diff --git a/Subsurface/Source/GUI/GUIMessageBox.cs b/Subsurface/Source/GUI/GUIMessageBox.cs index f5cfccb00..c56cda83f 100644 --- a/Subsurface/Source/GUI/GUIMessageBox.cs +++ b/Subsurface/Source/GUI/GUIMessageBox.cs @@ -15,6 +15,12 @@ namespace Subsurface //GUIFrame frame; public GUIButton[] Buttons; + public string Text + { + get { return (children[1] as GUITextBlock).Text; } + set { (children[1] as GUITextBlock).Text = value; } + } + public GUIMessageBox(string header, string text) : this(header, text, new string[] {"OK"}) { diff --git a/Subsurface/Source/GUI/GUIScrollBar.cs b/Subsurface/Source/GUI/GUIScrollBar.cs index 0ab9663d7..b654948c5 100644 --- a/Subsurface/Source/GUI/GUIScrollBar.cs +++ b/Subsurface/Source/GUI/GUIScrollBar.cs @@ -155,14 +155,14 @@ namespace Subsurface int moveAmount; if (isHorizontal) { - moveAmount = PlayerInput.GetMouseState.Position.X - PlayerInput.GetOldMouseState.Position.X; + moveAmount = (int)PlayerInput.MouseSpeed.X; newX = Math.Min(Math.Max(newX + moveAmount, 0), frame.Rect.Width - bar.Rect.Width); barScroll = (float)newX / ((float)frame.Rect.Width - (float)bar.Rect.Width); } else { - moveAmount = PlayerInput.GetMouseState.Position.Y - PlayerInput.GetOldMouseState.Position.Y; + moveAmount = (int)PlayerInput.MouseSpeed.Y; newY = Math.Min(Math.Max(newY+moveAmount, 0), frame.Rect.Height - bar.Rect.Height); barScroll = (float)newY / ((float)frame.Rect.Height - (float)bar.Rect.Height); diff --git a/Subsurface/Source/GUI/GUITextBlock.cs b/Subsurface/Source/GUI/GUITextBlock.cs index f699cada0..8842689c3 100644 --- a/Subsurface/Source/GUI/GUITextBlock.cs +++ b/Subsurface/Source/GUI/GUITextBlock.cs @@ -76,9 +76,12 @@ namespace Subsurface } - public GUITextBlock(Rectangle rect, string text, GUIStyle style, Alignment alignment = Alignment.TopLeft, Alignment textAlignment = Alignment.TopLeft, GUIComponent parent = null, bool wrap = false) + public GUITextBlock(Rectangle rect, string text, GUIStyle style, Alignment alignment = Alignment.TopLeft, Alignment textAlignment = Alignment.TopLeft, GUIComponent parent = null, bool wrap = false, SpriteFont font =null) : this (rect, text, null, null, alignment, textAlignment, style, parent, wrap) { + this.Font = font == null ? GUI.Font : font; + + SetTextPos(); } public GUITextBlock(Rectangle rect, string text, Color? color, Color? textColor, Alignment textAlignment = Alignment.Left, GUIStyle style = null, GUIComponent parent = null, bool wrap = false) @@ -117,11 +120,7 @@ namespace Subsurface if (parent != null) parent.AddChild(this); - //if (wrap) - //{ - this.Wrap = wrap; - // this.text = ToolBox.WrapText(this.text, rect.Width); - //} + this.Wrap = wrap; SetTextPos(); } @@ -135,7 +134,7 @@ namespace Subsurface if (Wrap && rect.Width>0) { //text = text.Replace("\n"," "); - text = ToolBox.WrapText(text, rect.Width, Font); + text = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font); Vector2 newSize = MeasureText(text); diff --git a/Subsurface/Source/GUI/GUITextBox.cs b/Subsurface/Source/GUI/GUITextBox.cs index fcebd9b22..4401d2cd0 100644 --- a/Subsurface/Source/GUI/GUITextBox.cs +++ b/Subsurface/Source/GUI/GUITextBox.cs @@ -146,6 +146,7 @@ namespace Subsurface public void Deselect() { + Selected = false; if (keyboardDispatcher.Subscriber == this) keyboardDispatcher.Subscriber = null; } @@ -158,7 +159,7 @@ namespace Subsurface caretTimer += deltaTime; caretVisible = ((caretTimer*1000.0f) % 1000) < 500; - if (rect.Contains(PlayerInput.GetMouseState.Position)) + if (rect.Contains(PlayerInput.MousePosition)) { state = ComponentState.Hover; if (PlayerInput.LeftButtonClicked()) Select(); diff --git a/Subsurface/Source/GUI/GUITickBox.cs b/Subsurface/Source/GUI/GUITickBox.cs index ffa74fb80..0564b2bb5 100644 --- a/Subsurface/Source/GUI/GUITickBox.cs +++ b/Subsurface/Source/GUI/GUITickBox.cs @@ -25,6 +25,12 @@ namespace Subsurface } } + public bool Enabled + { + get; + set; + } + public GUITickBox(Rectangle rect, string label, Alignment alignment, GUIComponent parent) : base(null) { @@ -35,15 +41,26 @@ namespace Subsurface box.HoverColor = Color.Gray; box.SelectedColor = Color.DarkGray; - text = new GUITextBlock(new Rectangle(rect.X + 40, rect.Y, 200, 30), label, Color.Transparent, Color.White, Alignment.TopLeft, null, this); + text = new GUITextBlock(new Rectangle(rect.X + 40, rect.Y, 200, rect.Height), label, Color.Transparent, Color.White, Alignment.TopLeft, null, this); + + Enabled = true; } public override void Update(float deltaTime) { - base.Update(deltaTime); + if (rect.Width ==420) + { + int asd = 1; + } + //base.Update(deltaTime); - if (box.Rect.Contains(PlayerInput.GetMouseState.Position)) + if (!Enabled) return; + + if (box.Rect.Contains(PlayerInput.MousePosition)) { + + + box.State = ComponentState.Hover; if (PlayerInput.GetMouseState.LeftButton == ButtonState.Pressed) @@ -67,12 +84,16 @@ namespace Subsurface public override void Draw(SpriteBatch spriteBatch) { + if (rect.Width == 420) + { + int asd = 1; + } + DrawChildren(spriteBatch); - if (Selected) - { - GUI.DrawRectangle(spriteBatch, new Rectangle(box.Rect.X + 2, box.Rect.Y + 2, box.Rect.Width - 4, box.Rect.Height - 4), Color.Green * 0.8f, true); - } + GUI.DrawRectangle(spriteBatch, new Rectangle(box.Rect.X + 2, box.Rect.Y + 2, box.Rect.Width - 4, box.Rect.Height - 4), + selected ? Color.Green * 0.8f : Color.Black, true); + } } } diff --git a/Subsurface/Source/Game1.cs b/Subsurface/Source/Game1.cs index 91d528f0d..e6562c43a 100644 --- a/Subsurface/Source/Game1.cs +++ b/Subsurface/Source/Game1.cs @@ -10,6 +10,7 @@ using Subsurface.Particles; using System.Collections; using System.Collections.Generic; using Microsoft.Xna.Framework.Input; +using System.Xml; namespace Subsurface { @@ -119,8 +120,8 @@ namespace Subsurface //TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 55); World = new World(new Vector2(0, -9.82f)); - Settings.VelocityIterations = 2; - Settings.PositionIterations = 1; + FarseerPhysics.Settings.VelocityIterations = 2; + FarseerPhysics.Settings.PositionIterations = 1; } /// @@ -165,6 +166,7 @@ namespace Subsurface { GUI.Font = ToolBox.TryLoadFont("SpriteFont1", Content); GUI.SmallFont = ToolBox.TryLoadFont("SmallFont", Content); + GUI.LargeFont = ToolBox.TryLoadFont("LargeFont", Content); sw = new Stopwatch(); @@ -263,7 +265,7 @@ namespace Subsurface DebugConsole.Update(this, (float)deltaTime); - if ((!DebugConsole.IsOpen && !GUI.PauseMenuOpen) || NetworkMember != null) Screen.Selected.Update(deltaTime); + if ((!DebugConsole.IsOpen && !GUI.PauseMenuOpen) || (NetworkMember != null && NetworkMember.GameStarted)) Screen.Selected.Update(deltaTime); GUI.Update((float)deltaTime); @@ -323,4 +325,4 @@ namespace Subsurface } } -} +} \ No newline at end of file diff --git a/Subsurface/Source/GameSession/GameModes/TraitorMode.cs b/Subsurface/Source/GameSession/GameModes/TraitorMode.cs index e81751bff..76d3bffb6 100644 --- a/Subsurface/Source/GameSession/GameModes/TraitorMode.cs +++ b/Subsurface/Source/GameSession/GameModes/TraitorMode.cs @@ -30,16 +30,7 @@ namespace Subsurface base.Update(deltaTime); if (!isRunning) return; - - if (DateTime.Now >= endTime) - { - string endMessage = traitor.character.Info.Name + " was a traitor! "; - endMessage += (traitor.character.Info.Gender == Gender.Male) ? "His" : "Her"; - endMessage += " task was to assassinate " + target.character.Info.Name + ". The task was unsuccesful."; - End(endMessage); - return; - } - + if (traitor==null || target ==null) { @@ -68,6 +59,35 @@ namespace Subsurface endMessage += " task was to assassinate " + target.character.Info.Name + ". The task was succesful."; End(endMessage); } + else if (traitor.character.IsDead) + { + string endMessage = traitor.character.Info.Name + " was a traitor! "; + endMessage += (traitor.character.Info.Gender == Gender.Male) ? "His" : "Her"; + endMessage += " task was to assassinate " + target.character.Info.Name + ", but "; + endMessage += (traitor.character.Info.Gender == Gender.Male) ? "he" : "she"; + endMessage += " got " + ((traitor.character.Info.Gender == Gender.Male) ? "himself" : "herself"); + endMessage += " killed before completing it."; + End(endMessage); + return; + } + else if (Level.Loaded.AtEndPosition) + { + string endMessage = traitor.character.Info.Name + " was a traitor! "; + endMessage += (traitor.character.Info.Gender == Gender.Male) ? "His" : "Her"; + endMessage += " task was to assassinate " + target.character.Info.Name + ". "; + endMessage += "The task was unsuccessful - the has submarine reached its destination."; + End(endMessage); + return; + } + else if (DateTime.Now >= endTime) + { + string endMessage = traitor.character.Info.Name + " was a traitor! "; + endMessage += (traitor.character.Info.Gender == Gender.Male) ? "His" : "Her"; + endMessage += " task was to assassinate " + target.character.Info.Name + ". The task was unsuccesful."; + End(endMessage); + return; + } + } } } diff --git a/Subsurface/Source/GameSession/GameModes/TutorialMode.cs b/Subsurface/Source/GameSession/GameModes/TutorialMode.cs index 7a83faa6f..dd82ff8d9 100644 --- a/Subsurface/Source/GameSession/GameModes/TutorialMode.cs +++ b/Subsurface/Source/GameSession/GameModes/TutorialMode.cs @@ -22,6 +22,8 @@ namespace Subsurface Game1.GameSession.StartShift(TimeSpan.Zero, "tutorial"); + Game1.GameSession.taskManager.Tasks.Clear(); + Game1.GameScreen.Select(); } @@ -184,7 +186,7 @@ namespace Subsurface + " going into the to the power connection - that's why the monitor isn't working." + " You should find a piece of wire to connect it. Try searching some of the cabinets scattered around the sub."); - while (Character.Controlled.Inventory.items.FirstOrDefault(i => i!=null && i.GetComponent()!=null)==null) + while (!HasItem("Wire")) { yield return Status.Running; } @@ -280,32 +282,159 @@ namespace Subsurface var moloch = new Character("Content/Characters/Moloch/moloch.xml", steering.Item.SimPosition + Vector2.UnitX * 15.0f); moloch.PlaySound(AIController.AiState.Attack); - //moloch.AIController. - infoBox = CreateInfoFrame("Uh-oh... Something enormous just appeared on the radar."); - Structure window = null; + List windows = new List(); foreach (Structure s in Structure.wallList) { - if (s.CastShadow) continue; + if (s.CastShadow || !s.HasBody) continue; - if (window == null || s.Rect.Right > window.Rect.Right) window = s; + if (s.Rect.Right > steering.Item.Position.X) windows.Add(s); } bool broken = false; do { - moloch.AIController.SelectTarget(steering.Item); - for (int i = 0; i < window.SectionCount; i++) + moloch.AIController.SelectTarget(steering.Item.CurrentHull.AiTarget); + Vector2 steeringDir = windows[0].Position - moloch.Position; + if (steeringDir != Vector2.Zero) steeringDir = Vector2.Normalize(steeringDir); + + foreach (Limb limb in moloch.AnimController.limbs) { - if (!window.SectionHasHole(i)) continue; - broken = true; - break; + limb.body.LinearVelocity = new Vector2(limb.LinearVelocity.X, limb.LinearVelocity.Y + steeringDir.Y*0.01f); } + moloch.AIController.Steering = steeringDir; + + foreach (Structure window in windows) + { + for (int i = 0; i < window.SectionCount; i++) + { + if (!window.SectionHasHole(i)) continue; + broken = true; + break; + } + if (broken) break; + } + + yield return new WaitForSeconds(1.0f); } while (!broken); + yield return new WaitForSeconds(1.0f); + + + var capacitor1 = Item.itemList.Find(i => i.HasTag("capacitor1")).GetComponent(); + var capacitor2 = Item.itemList.Find(i => i.HasTag("capacitor1")).GetComponent(); + CoroutineManager.StartCoroutine(KeepEnemyAway(moloch, new PowerContainer[] { capacitor1, capacitor2 })); + + + infoBox = CreateInfoFrame("The hull has been breached! Close all the doors to the command room to stop the water from flooding the entire sub!"); + + + Door commandDoor1 = Item.itemList.Find(i => i.HasTag("commanddoor1")).GetComponent(); + Door commandDoor2 = Item.itemList.Find(i => i.HasTag("commanddoor2")).GetComponent(); + Door commandDoor3 = Item.itemList.Find(i => i.HasTag("commanddoor3")).GetComponent(); + + while (commandDoor1.IsOpen && (commandDoor2.IsOpen || commandDoor3.IsOpen)) + { + yield return Status.Running; + } + + infoBox = CreateInfoFrame("Great! You should find yourself an diving mask or a diving suit, in case the creature causes more damage. "+ + "There are some in the room next to the airlock."); + + while (!HasItem("Diving Mask") && !HasItem("Diving Suit")) + { + yield return Status.Running; + } + + if (HasItem("Diving Mask")) + { + infoBox = CreateInfoFrame("The diving mask will let you breathe underwater, but it won't protect from the water pressure outside the sub. "+ + "It should be fine for the situation at hand, but you still need to find an oxygen tank and drag it into the same slot as the mask." + + "You should grab one or two."); + } + else if (HasItem("Diving Suit")) + { + infoBox = CreateInfoFrame("In addition to letting you breathe underwater, the suit will protect you from the water pressure outside the sub " + + "(unlike the diving mask). However, you still need to drag an oxygen tank into the same slot as the suit to supply oxygen. "+ + "You should grab one or two."); + } + + while (!HasItem("Oxygen Tank")) + { + yield return Status.Running; + } + + yield return new WaitForSeconds(5.0f); + + infoBox = CreateInfoFrame("Now it's time to stop the creature attacking the submarine. Head to the railgun room at the upper right corner of the sub."); + + var railGun = Item.itemList.Find(i => i.GetComponent()!=null); + + while (Vector2.Distance(Character.Controlled.Position, railGun.Position)>500) + { + yield return new WaitForSeconds(1.0f); + } + + infoBox = CreateInfoFrame("The railgun requires a large power surge to fire. The reactor can't provide a surge large enough, so we need to use the " + +" supercapacitors in the railgun room. The capacitors need to be charged first; select them and crank up the recharge rate."); + + while (capacitor1.RechargeSpeed<0.5f && capacitor2.RechargeSpeed<0.5f) + { + yield return new WaitForSeconds(1.0f); + } + + infoBox = CreateInfoFrame("The capacitors consume large amounts of power when they're being charged at a high rate. "+ + "Be cautious to overload the electrical grid or the reactor. They also take some time to recharge, so now is a good "+ + "time to head to the room below to load some shells into the railgun."); + + + var loader = Item.itemList.Find(i => i.Name == "Railgun Loader").GetComponent(); + + while (Math.Abs(Character.Controlled.Position.Y - loader.Item.Position.Y)>50) + { + yield return Status.Running; + } + + infoBox = CreateInfoFrame("Grab one of the shells. You can load it by selecting the railgun loader and dragging the shell to. " + +"one of the free slots."); + + while (loader.Item.ContainedItems.FirstOrDefault(i => i != null) != null) + { + capacitor1.Charge += 1.0f; + capacitor2.Charge += 1.0f; + yield return Status.Running; + } + + + yield return Status.Success; + } + + private bool HasItem(string itemName) + { + if (Character.Controlled == null) return false; + return Character.Controlled.Inventory.items.FirstOrDefault(i => i != null && i.Name == itemName)!=null; + } + + /// + /// keeps the enemy away from the sub until the capacitors are loaded + /// + private IEnumerable KeepEnemyAway(Character enemy, PowerContainer[] capacitors) + { + do + { + Vector2 targetPos = Character.Controlled.Position + new Vector2(0.0f, 3000.0f); + + Vector2 steering = targetPos - enemy.Position; + if (steering != Vector2.Zero) steering = Vector2.Normalize(steering); + + enemy.AIController.Steering = steering*2.0f; + + yield return Status.Running; + } while (capacitors.FirstOrDefault(c => c.Charge > 0.4f) == null); + yield return Status.Success; } diff --git a/Subsurface/Source/GameSession/GameSession.cs b/Subsurface/Source/GameSession/GameSession.cs index 6ea2a2f8d..8ac5a91a9 100644 --- a/Subsurface/Source/GameSession/GameSession.cs +++ b/Subsurface/Source/GameSession/GameSession.cs @@ -132,7 +132,7 @@ namespace Subsurface if (Game1.Server!=null) { - Game1.Server.EndGame(endMessage); + CoroutineManager.StartCoroutine(Game1.Server.EndGame(endMessage)); } else if (Game1.Client==null) diff --git a/Subsurface/Source/Items/CharacterInventory.cs b/Subsurface/Source/Items/CharacterInventory.cs index cab256dc1..d705153bb 100644 --- a/Subsurface/Source/Items/CharacterInventory.cs +++ b/Subsurface/Source/Items/CharacterInventory.cs @@ -139,12 +139,13 @@ namespace Subsurface if (items[i] != null) { bool combined = false; - if (item.Combine(items[i])) - { - //PutItem(item, i, false, false); - combined = true; - } - else if (items[i].Combine(item)) + //if (item.Combine(items[i])) + //{ + // //PutItem(item, i, false, false); + // combined = true; + //} + //else + if (items[i].Combine(item)) { //PutItem(items[i], i, false, false); combined = true; diff --git a/Subsurface/Source/Items/Components/Door.cs b/Subsurface/Source/Items/Components/Door.cs index 3558efb76..1a7ee9cd7 100644 --- a/Subsurface/Source/Items/Components/Door.cs +++ b/Subsurface/Source/Items/Components/Door.cs @@ -119,7 +119,6 @@ namespace Subsurface.Items.Components (int)doorSprite.size.X, (int)doorSprite.size.Y); - body = new PhysicsBody(BodyFactory.CreateRectangle(Game1.World, ConvertUnits.ToSimUnits(Math.Max(doorRect.Width, 1)), ConvertUnits.ToSimUnits(Math.Max(doorRect.Height, 1)), diff --git a/Subsurface/Source/Items/Components/Holdable/Holdable.cs b/Subsurface/Source/Items/Components/Holdable/Holdable.cs index fb285428d..33711de9e 100644 --- a/Subsurface/Source/Items/Components/Holdable/Holdable.cs +++ b/Subsurface/Source/Items/Components/Holdable/Holdable.cs @@ -101,7 +101,7 @@ namespace Subsurface.Items.Components Msg = ""; } - if (attachedByDefault) Use(1.0f); + if (attachedByDefault || Screen.Selected == Game1.EditMapScreen) Use(1.0f); //holdAngle = ToolBox.GetAttributeFloat(element, "holdangle", 0.0f); diff --git a/Subsurface/Source/Items/Components/Holdable/RangedWeapon.cs b/Subsurface/Source/Items/Components/Holdable/RangedWeapon.cs index 05cbb0559..7055f4f63 100644 --- a/Subsurface/Source/Items/Components/Holdable/RangedWeapon.cs +++ b/Subsurface/Source/Items/Components/Holdable/RangedWeapon.cs @@ -53,7 +53,7 @@ namespace Subsurface.Items.Components public override bool Use(float deltaTime, Character character = null) { if (character == null) return false; - if (!character.SecondaryKeyDown.State || reload > 0.0f) return false; + if (!character.GetInputState(InputType.SecondaryHeld) || reload > 0.0f) return false; isActive = true; reload = 1.0f; diff --git a/Subsurface/Source/Items/Components/Holdable/RepairTool.cs b/Subsurface/Source/Items/Components/Holdable/RepairTool.cs index 7063d955e..9d7a7dc21 100644 --- a/Subsurface/Source/Items/Components/Holdable/RepairTool.cs +++ b/Subsurface/Source/Items/Components/Holdable/RepairTool.cs @@ -102,7 +102,7 @@ namespace Subsurface.Items.Components public override bool Use(float deltaTime, Character character = null) { if (character == null) return false; - if (!character.SecondaryKeyDown.State) return false; + if (!character.GetInputState(InputType.SecondaryHeld)) return false; if (DoesUseFail(character)) return false; @@ -146,7 +146,7 @@ namespace Subsurface.Items.Components } else if ((targetLimb = (targetBody.UserData as Limb)) != null) { - if (character.SecondaryKeyDown.State) + if (character.GetInputState(InputType.SecondaryHeld)) { targetLimb.character.Health += limbFixAmount; //isActive = true; diff --git a/Subsurface/Source/Items/Components/Holdable/Throwable.cs b/Subsurface/Source/Items/Components/Holdable/Throwable.cs index e2e08be40..62a817c7b 100644 --- a/Subsurface/Source/Items/Components/Holdable/Throwable.cs +++ b/Subsurface/Source/Items/Components/Holdable/Throwable.cs @@ -28,7 +28,7 @@ namespace Subsurface.Items.Components public override bool Use(float deltaTime, Character character = null) { if (character == null) return false; - if (!character.SecondaryKeyDown.State || throwing) return false; + if (!character.GetInputState(InputType.SecondaryHeld) || throwing) return false; throwing = true; @@ -60,7 +60,7 @@ namespace Subsurface.Items.Components if (!item.body.Enabled) return; if (!picker.HasSelectedItem(item)) isActive = false; - if (!picker.SecondaryKeyDown.State && !throwing) throwPos = 0.0f; + if (!picker.GetInputState(InputType.SecondaryHeld) && !throwing) throwPos = 0.0f; ApplyStatusEffects(ActionType.OnActive, deltaTime, picker); diff --git a/Subsurface/Source/Items/Components/ItemLabel.cs b/Subsurface/Source/Items/Components/ItemLabel.cs new file mode 100644 index 000000000..0b9ff1323 --- /dev/null +++ b/Subsurface/Source/Items/Components/ItemLabel.cs @@ -0,0 +1,66 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System.Xml.Linq; +namespace Subsurface.Items.Components +{ + class ItemLabel : ItemComponent + { + private GUITextBlock textBlock; + + [HasDefaultValue("", true), Editable(100)] + public string Text + { + get { return textBlock.Text; } + set + { + if (value == TextBlock.Text || item.Rect.Width < 5) return; + TextBlock.Text = value; + } + } + + private Color textColor; + [Editable, HasDefaultValue("0.0,0.0,0.0,1.0", true)] + public string TextColor + { + get { return ToolBox.Vector4ToString(textColor.ToVector4()); } + set + { + textColor = new Color(ToolBox.ParseToVector4(value)); + } + } + + private GUITextBlock TextBlock + { + get + { + if (textBlock==null) + { + textBlock = new GUITextBlock(new Rectangle(item.Rect.X,-item.Rect.Y,item.Rect.Width, item.Rect.Height), "", + Color.Transparent, Color.Black, + Alignment.TopLeft, Alignment.Center, + null, null, true); + textBlock.Font = GUI.SmallFont; + textBlock.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f); + } + return textBlock; + } + } + + public override void Move(Vector2 amount) + { + textBlock.Rect = new Rectangle(item.Rect.X, -item.Rect.Y, item.Rect.Width, item.Rect.Height); + } + + public ItemLabel(Item item, XElement element) + : base(item, element) + { + } + + public override void Draw(SpriteBatch spriteBatch, bool editing = false) + { + base.Draw(spriteBatch, editing); + + textBlock.Draw(spriteBatch); + } + } +} \ No newline at end of file diff --git a/Subsurface/Source/Items/Components/Label.cs b/Subsurface/Source/Items/Components/Label.cs index 411fbdeee..dbc63f08b 100644 --- a/Subsurface/Source/Items/Components/Label.cs +++ b/Subsurface/Source/Items/Components/Label.cs @@ -92,8 +92,11 @@ namespace Subsurface.Items.Components newText = message.ReadString(); } - catch + catch (Exception e) { +#if DEBUG + DebugConsole.ThrowError("invalid network message", e); +#endif return; } diff --git a/Subsurface/Source/Items/Components/Machines/Controller.cs b/Subsurface/Source/Items/Components/Machines/Controller.cs index a968e8ed9..9bd231f5a 100644 --- a/Subsurface/Source/Items/Components/Machines/Controller.cs +++ b/Subsurface/Source/Items/Components/Machines/Controller.cs @@ -66,7 +66,9 @@ namespace Subsurface.Items.Components { this.cam = cam; - if (character == null || character.SelectedConstruction != item) + if (character == null + || character.SelectedConstruction != item + || Vector2.Distance(character.SimPosition, item.SimPosition) > item.PickDistance * 1.5f) { if (character != null) { diff --git a/Subsurface/Source/Items/Components/Machines/Pump.cs b/Subsurface/Source/Items/Components/Machines/Pump.cs index d162e1e42..c320f0944 100644 --- a/Subsurface/Source/Items/Components/Machines/Pump.cs +++ b/Subsurface/Source/Items/Components/Machines/Pump.cs @@ -22,8 +22,9 @@ namespace Subsurface.Items.Components get { return flowPercentage; } set { - if (float.IsNaN(flowPercentage)) return; - flowPercentage = MathHelper.Clamp(value,-100.0f,100.0f); + if (!MathUtils.IsValid(flowPercentage)) return; + flowPercentage = MathHelper.Clamp(value,-100.0f,100.0f); + flowPercentage = MathUtils.Round(flowPercentage, 1.0f); } } @@ -117,14 +118,14 @@ namespace Subsurface.Items.Components spriteBatch.DrawString(GUI.Font, "Flow percentage: " + (int)flowPercentage + " %", new Vector2(x + 20, y + 80), Color.White); - if (GUI.DrawButton(spriteBatch, new Rectangle(x + 200, y + 70, 40, 40), "+", true)) + if (GUI.DrawButton(spriteBatch, new Rectangle(x + 200, y + 70, 40, 40), "+", false)) { - FlowPercentage += 1.0f; + FlowPercentage += 10.0f; item.NewComponentEvent(this, true); } - if (GUI.DrawButton(spriteBatch, new Rectangle(x + 250, y + 70, 40, 40), "-", true)) + if (GUI.DrawButton(spriteBatch, new Rectangle(x + 250, y + 70, 40, 40), "-", false)) { - FlowPercentage -= 1.0f; + FlowPercentage -= 10.0f; item.NewComponentEvent(this, true); } @@ -166,7 +167,7 @@ namespace Subsurface.Items.Components public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message) { - message.Write(flowPercentage); + message.Write(Convert.ToByte(flowPercentage+100)); message.Write(isActive); } @@ -177,11 +178,17 @@ namespace Subsurface.Items.Components try { - newFlow = message.ReadFloat(); + newFlow = (float)(message.ReadByte()-100); newActive = message.ReadBoolean(); } - catch { return; } + catch (Exception e) + { +#if DEBUG + DebugConsole.ThrowError("invalid network message", e); +#endif + return; + } FlowPercentage = newFlow; isActive = newActive; diff --git a/Subsurface/Source/Items/Components/Machines/Reactor.cs b/Subsurface/Source/Items/Components/Machines/Reactor.cs index afe8c36d5..960667c9c 100644 --- a/Subsurface/Source/Items/Components/Machines/Reactor.cs +++ b/Subsurface/Source/Items/Components/Machines/Reactor.cs @@ -68,19 +68,31 @@ namespace Subsurface.Items.Components public float FissionRate { get { return fissionRate; } - set { fissionRate = MathHelper.Clamp(value, 0.0f, 100.0f); } + set + { + if (!MathUtils.IsValid(value)) return; + fissionRate = MathHelper.Clamp(value, 0.0f, 100.0f); + } } public float CoolingRate { get { return coolingRate; } - set { coolingRate = MathHelper.Clamp(value, 0.0f, 100.0f); } + set + { + if (!MathUtils.IsValid(value)) return; + coolingRate = MathHelper.Clamp(value, 0.0f, 100.0f); + } } public float Temperature { get { return temperature; } - set { temperature = MathHelper.Clamp(value, 0.0f, 10000.0f); } + set + { + if (!MathUtils.IsValid(value)) return; + temperature = MathHelper.Clamp(value, 0.0f, 10000.0f); + } } public bool IsRunning() @@ -100,6 +112,7 @@ namespace Subsurface.Items.Components public float ShutDownTemp { get { return shutDownTemp; } + private set { shutDownTemp = MathHelper.Clamp(value, 0.0f, 10000.0f); } } public Reactor(Item item, XElement element) @@ -127,7 +140,7 @@ namespace Subsurface.Items.Components float heat = 100 * fissionRate * (AvailableFuel/2000.0f); float heatDissipation = 50 * coolingRate + ExtraCooling; - float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 1000.0f; + float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 10000.0f; Temperature = temperature + deltaTemp; if (temperature > meltDownTemp) @@ -142,8 +155,7 @@ namespace Subsurface.Items.Components powerUpTask = new PropertyTask(item, IsRunning, 50.0f, "Power up the reactor"); } } - - + item.Condition -= temperature * deltaTime * 0.00005f; if (temperature > shutDownTemp) @@ -188,8 +200,7 @@ namespace Subsurface.Items.Components //fission rate can't be lowered below a certain amount if the core is too hot FissionRate = Math.Max(fissionRate, heat / 200.0f); - - + //the power generated by the reactor is equal to the temperature currPowerConsumption = -temperature*powerPerTemp; @@ -203,6 +214,8 @@ namespace Subsurface.Items.Components ExtraCooling = 0.0f; AvailableFuel = 0.0f; + + item.SendSignal(((int)temperature).ToString(), "temperature_out"); } public override void UpdateBroken(float deltaTime, Camera cam) @@ -239,24 +252,15 @@ namespace Subsurface.Items.Components new RepairTask(item, 60.0f, "Reactor meltdown!"); item.Condition = 0.0f; - //fissionRate = 0.0f; - //coolingRate = 0.0f; - //PlaySound(ActionType.OnFailure, item.Position); - //item.ApplyStatusEffects(ActionType.OnFailure, 1.0f, null); - - //new Explosion(item.SimPosition, 6.0f, 500.0f, 600.0f, 10.0f, 2.0f).Explode(); + var containedItems = item.ContainedItems; + if (containedItems == null) return; - if (item.ContainedItems!=null) + foreach (Item containedItem in item.ContainedItems) { - foreach (Item containedItem in item.ContainedItems) - { - if (containedItem == null) continue; - containedItem.Condition = 0.0f; - } + if (containedItem == null) continue; + containedItem.Condition = 0.0f; } - - } public override bool Pick(Character picker) @@ -343,12 +347,12 @@ namespace Subsurface.Items.Components if (GUI.DrawButton(spriteBatch, new Rectangle(x + 400, y + 180, 40, 40), "+", true)) { valueChanged = true; - shutDownTemp += 100.0f; + ShutDownTemp += 100.0f; } if (GUI.DrawButton(spriteBatch, new Rectangle(x + 450, y + 180, 40, 40), "-", true)) { valueChanged = true; - shutDownTemp -= 100.0f; + ShutDownTemp -= 100.0f; } if (valueChanged) @@ -398,14 +402,24 @@ namespace Subsurface.Items.Components GUI.DrawLine(spriteBatch, prevPoint, lastPoint, Color.White); } + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power) + { + switch (connection.Name) + { + case "shutdown": + shutDownTemp = 0.0f; + break; + } + } + public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message) { message.Write(autoTemp); - message.Write(temperature); - message.Write(shutDownTemp); + message.WriteRangedSingle(temperature, 0.0f, 10000.0f, 16); + message.WriteRangedSingle(shutDownTemp, 0.0f, 10000.0f, 16); - message.Write(coolingRate); - message.Write(fissionRate); + message.WriteRangedSingle(coolingRate, 0.0f, 100.0f, 8); + message.WriteRangedSingle(fissionRate, 0.0f, 100.0f, 8); } public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message) @@ -417,18 +431,24 @@ namespace Subsurface.Items.Components try { newAutoTemp = message.ReadBoolean(); - newTemperature = message.ReadFloat(); - newShutDownTemp = message.ReadFloat(); + newTemperature = message.ReadRangedSingle(0.0f, 10000.0f, 16); + newShutDownTemp = message.ReadRangedSingle(0.0f, 10000.0f, 16); - newCoolingRate = message.ReadFloat(); - newFissionRate = message.ReadFloat(); + newCoolingRate = message.ReadRangedSingle(0.0f, 100.0f, 8); + newFissionRate = message.ReadRangedSingle(0.0f, 100.0f, 8); } - catch { return; } + catch (Exception e) + { +#if DEBUG + DebugConsole.ThrowError("invalid network message", e); +#endif + return; + } autoTemp = newAutoTemp; Temperature = newTemperature; - shutDownTemp = newShutDownTemp; + ShutDownTemp = newShutDownTemp; CoolingRate = newCoolingRate; FissionRate = newFissionRate; diff --git a/Subsurface/Source/Items/Components/Machines/Steering.cs b/Subsurface/Source/Items/Components/Machines/Steering.cs index 0caf77329..5bb97e7c8 100644 --- a/Subsurface/Source/Items/Components/Machines/Steering.cs +++ b/Subsurface/Source/Items/Components/Machines/Steering.cs @@ -48,10 +48,7 @@ namespace Subsurface.Items.Components get { return targetVelocity;} set { - if (float.IsNaN(value.X) || float.IsNaN(value.Y)) - { - return; - } + if (!MathUtils.IsValid(value)) return; targetVelocity.X = MathHelper.Clamp(value.X, -100.0f, 100.0f); targetVelocity.Y = MathHelper.Clamp(value.Y, -100.0f, 100.0f); } diff --git a/Subsurface/Source/Items/Components/Projectile.cs b/Subsurface/Source/Items/Components/Projectile.cs index 0e44f3468..8deae4633 100644 --- a/Subsurface/Source/Items/Components/Projectile.cs +++ b/Subsurface/Source/Items/Components/Projectile.cs @@ -173,16 +173,19 @@ namespace Subsurface.Items.Components (float)Math.Cos(item.body.Rotation), (float)Math.Sin(item.body.Rotation)); - if (Vector2.Dot(f1.Body.LinearVelocity, normal)<0 ) return StickToTarget(f2.Body, dir); + if (Vector2.Dot(f1.Body.LinearVelocity, normal) < 0.0f) return StickToTarget(f2.Body, dir); } - foreach (Item contained in item.ContainedItems) + + var containedItems = item.ContainedItems; + if (containedItems == null) return true; + foreach (Item contained in containedItems) { - contained.Condition = 0.0f; - if (contained.body!=null) + if (contained.body != null) { - contained.body.SetTransform(item.SimPosition, contained.body.Rotation); + contained.SetTransform(item.SimPosition, contained.body.Rotation); } + contained.Condition = 0.0f; } return true; diff --git a/Subsurface/Source/Items/Components/Signal/Connection.cs b/Subsurface/Source/Items/Components/Signal/Connection.cs index 86ddc2556..258af00b1 100644 --- a/Subsurface/Source/Items/Components/Signal/Connection.cs +++ b/Subsurface/Source/Items/Components/Signal/Connection.cs @@ -319,14 +319,13 @@ namespace Subsurface.Items.Components if (index>-1) { Wires[index].RemoveConnection(this); - Wires[index].Item.SetTransform(item.SimPosition, 0.0f); - Wires[index].Item.Drop(); - Wires[index].Item.body.Enabled = true; + //Wires[index].Item.SetTransform(item.SimPosition, 0.0f); + //Wires[index].Item.Drop(); + //Wires[index].Item.body.Enabled = true; Wires[index] = null; } } - } - + } } diff --git a/Subsurface/Source/Items/Components/Signal/RegExFindComponent.cs b/Subsurface/Source/Items/Components/Signal/RegExFindComponent.cs index 28ea8b161..917c45ac8 100644 --- a/Subsurface/Source/Items/Components/Signal/RegExFindComponent.cs +++ b/Subsurface/Source/Items/Components/Signal/RegExFindComponent.cs @@ -9,6 +9,8 @@ namespace Subsurface.Items.Components private string expression; + private string receivedSignal; + [InGameEditable, HasDefaultValue("1", true)] public string Output { @@ -26,6 +28,27 @@ namespace Subsurface.Items.Components public RegExFindComponent(Item item, XElement element) : base(item, element) { + isActive = true; + } + + public override void Update(float deltaTime, Camera cam) + { + if (string.IsNullOrWhiteSpace(expression)) return; + + bool success = false; + try + { + Regex regex = new Regex(@expression); + Match match = regex.Match(receivedSignal); + success = match.Success; + } + catch + { + item.SendSignal("ERROR", "signal_out"); + return; + } + + item.SendSignal(success ? output : "0", "signal_out"); } public override void ReceiveSignal(string signal, Connection connection, Item sender, float power = 0.0f) @@ -33,22 +56,7 @@ namespace Subsurface.Items.Components switch (connection.Name) { case "signal_in": - if (string.IsNullOrWhiteSpace(expression)) return; - - bool success = false; - try - { - Regex regex = new Regex(@expression); - Match match = regex.Match(signal); - success = match.Success; - } - catch - { - item.SendSignal("ERROR", "signal_out"); - return; - } - - item.SendSignal(success ? output : "0", "signal_out"); + receivedSignal = signal; break; case "set_output": diff --git a/Subsurface/Source/Items/Components/Signal/WifiComponent.cs b/Subsurface/Source/Items/Components/Signal/WifiComponent.cs new file mode 100644 index 000000000..d1486eca7 --- /dev/null +++ b/Subsurface/Source/Items/Components/Signal/WifiComponent.cs @@ -0,0 +1,56 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Xml.Linq; + +namespace Subsurface.Items.Components +{ + class WifiComponent : ItemComponent + { + + private static List list = new List(); + + private int channel; + + [InGameEditable, HasDefaultValue(1, true)] + public int Channel + { + get { return channel; } + set + { + channel = MathHelper.Clamp(value, 0, 100); + } + } + + public WifiComponent(Item item, XElement element) + : base (item, element) + { + + list.Add(this); + } + + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f) + { + //prevent an ininite loop of wificomponents sending messages between each other + if (sender.GetComponent()!=null) return; + + switch (connection.Name) + { + case "signal_in": + foreach (WifiComponent wifiComp in list) + { + if (wifiComp == this || wifiComp.channel != channel) continue; + wifiComp.item.SendSignal(signal, "signal_out"); + } + break; + } + } + + public override void Remove() + { + base.Remove(); + + list.Remove(this); + } + } +} diff --git a/Subsurface/Source/Items/Components/Turret.cs b/Subsurface/Source/Items/Components/Turret.cs index 5f7a6fc76..118868959 100644 --- a/Subsurface/Source/Items/Components/Turret.cs +++ b/Subsurface/Source/Items/Components/Turret.cs @@ -106,8 +106,31 @@ namespace Subsurface.Items.Components if (reload > 0.0f) return false; Projectile projectileComponent = null; + //search for a projectile from linked containers + Item projectile = null; + foreach (MapEntity e in item.linkedTo) + { + Item container = e as Item; + if (container == null) continue; + + ItemContainer containerComponent = container.GetComponent(); + if (containerComponent == null) continue; + + for (int i = 0; i < containerComponent.inventory.items.Length; i++) + { + if (containerComponent.inventory.items[i] == null) continue; + if ((projectileComponent = containerComponent.inventory.items[i].GetComponent()) != null) + { + projectile = containerComponent.inventory.items[i]; + break; + } + } + + if (projectileComponent != null) break; + } + + if (projectile == null || projectileComponent == null) return false; - //currPowerConsumption = powerConsumption; float availablePower = 0.0f; //List batteries = new List(); @@ -132,31 +155,6 @@ namespace Subsurface.Items.Components if (availablePower < currPowerConsumption) return false; - //search for a projectile from linked containers - Item projectile = null; - foreach (MapEntity e in item.linkedTo) - { - Item container = e as Item; - if (container == null) continue; - - ItemContainer containerComponent = container.GetComponent(); - if (containerComponent == null) continue; - - for (int i = 0; i < containerComponent.inventory.items.Length; i++) - { - if (containerComponent.inventory.items[i] == null) continue; - if ((projectileComponent = containerComponent.inventory.items[i].GetComponent()) != null) - { - projectile = containerComponent.inventory.items[i]; - break; - } - } - - if (projectileComponent != null) break; - } - - if (projectile == null || projectileComponent==null) return false; - projectile.body.ResetDynamics(); projectile.body.Enabled = true; projectile.SetTransform(ConvertUnits.ToSimUnits(new Vector2(item.Rect.X + barrelPos.X, item.Rect.Y - barrelPos.Y)), -rotation); diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index 608b7fc8d..d8cbe19d6 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -61,6 +61,11 @@ namespace Subsurface get { return prefab.sprite; } } + public float PickDistance + { + get { return prefab.PickDistance; } + } + public float Condition { get { return condition; } @@ -178,7 +183,7 @@ namespace Subsurface get { ItemContainer c = GetComponent(); - return (c == null) ? null : c.inventory.items; + return (c == null) ? null : Array.FindAll(c.inventory.items, i=>i!=null); } } @@ -546,15 +551,19 @@ namespace Subsurface Color color = (isSelected && editing) ? color = Color.Red : spriteColor; if (isHighlighted) color = Color.Orange; - if (body==null) + if (prefab.sprite!=null) { - prefab.sprite.DrawTiled(spriteBatch, new Vector2(rect.X, -rect.Y), new Vector2(rect.Width, rect.Height), color); - } - else if (body.Enabled) - { - body.Draw(spriteBatch, prefab.sprite, color); + if (body==null) + { + prefab.sprite.DrawTiled(spriteBatch, new Vector2(rect.X, -rect.Y), new Vector2(rect.Width, rect.Height), color); + } + else if (body.Enabled) + { + body.Draw(spriteBatch, prefab.sprite, color); + } } + foreach (ItemComponent component in components) component.Draw(spriteBatch, editing); if (!editing || (body!=null && !body.Enabled)) @@ -665,7 +674,13 @@ namespace Subsurface foreach (var objectProperty in editableProperties) { new GUITextBlock(new Rectangle(0, y, 100, 20), objectProperty.Name, Color.Transparent, Color.White, Alignment.Left, null, editingHUD); - GUITextBox propertyBox = new GUITextBox(new Rectangle(100, y, 200, 20), GUI.style, editingHUD); + + int height = 20; + var editable = objectProperty.Attributes.OfType().FirstOrDefault(); + if (editable != null) height = (int)(Math.Ceiling(editable.MaxLength / 20.0f) * 20.0f); + + GUITextBox propertyBox = new GUITextBox(new Rectangle(100, y, 200, height), GUI.style, editingHUD); + if (height>20) propertyBox.Wrap = true; object value = objectProperty.GetValue(); if (value != null) @@ -676,7 +691,7 @@ namespace Subsurface propertyBox.UserData = objectProperty; propertyBox.OnEnter = EnterProperty; propertyBox.OnTextChanged = PropertyChanged; - y = y + 30; + y = y + height+10; } return editingHUD; } @@ -933,8 +948,8 @@ namespace Subsurface if (objectProperty == null) return false; object prevValue = objectProperty.GetValue(); - - textBox.Selected = false; + + textBox.Deselect(); if (objectProperty.TrySetValue(text)) { diff --git a/Subsurface/Source/Items/ItemPrefab.cs b/Subsurface/Source/Items/ItemPrefab.cs index e13b087be..504bd9016 100644 --- a/Subsurface/Source/Items/ItemPrefab.cs +++ b/Subsurface/Source/Items/ItemPrefab.cs @@ -106,7 +106,7 @@ namespace Subsurface position = placePosition; } - sprite.DrawTiled(spriteBatch, new Vector2(position.X, -position.Y), placeSize, Color.White); + if (sprite != null) sprite.DrawTiled(spriteBatch, new Vector2(position.X, -position.Y), placeSize, Color.White); } if (PlayerInput.GetMouseState.RightButton == ButtonState.Pressed) selected = null; diff --git a/Subsurface/Source/Map/Entity.cs b/Subsurface/Source/Map/Entity.cs index bd2dc940d..375f796fd 100644 --- a/Subsurface/Source/Map/Entity.cs +++ b/Subsurface/Source/Map/Entity.cs @@ -45,6 +45,11 @@ namespace Subsurface get { return Vector2.Zero; } } + public AITarget AiTarget + { + get { return aiTarget; } + } + public Entity() { //give an unique ID diff --git a/Subsurface/Source/Map/Hull.cs b/Subsurface/Source/Map/Hull.cs index 3c77ad2b6..f95c6a561 100644 --- a/Subsurface/Source/Map/Hull.cs +++ b/Subsurface/Source/Map/Hull.cs @@ -156,7 +156,7 @@ namespace Subsurface public int GetWaveIndex(Vector2 position) { int index = (int)(position.X - rect.X) / WaveWidth; - index = MathHelper.Clamp(index, 0, waveY.Length-1); + index = (int)MathHelper.Clamp(index, 0, waveY.Length-1); return index; } diff --git a/Subsurface/Source/Map/Lights/ConvexHull.cs b/Subsurface/Source/Map/Lights/ConvexHull.cs index 3de439e67..364b82ad3 100644 --- a/Subsurface/Source/Map/Lights/ConvexHull.cs +++ b/Subsurface/Source/Map/Lights/ConvexHull.cs @@ -245,7 +245,10 @@ namespace Subsurface.Lights * Matrix.CreateOrthographic(Game1.GraphicsWidth, Game1.GraphicsHeight, -1, 1) * 0.5f; shadowEffect.CurrentTechnique.Passes[0].Apply(); - graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVertices, 0, 2, VertexPositionTexture.VertexDeclaration); +#if WINDOWS + graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVertices, 0, 2, VertexPositionTexture.VertexDeclaration); + +#endif } } diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 260ee1d2f..3f02177da 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -50,7 +50,7 @@ namespace Subsurface private string name; - private double lastNetworkUpdate; + private float lastNetworkUpdate; //properties ---------------------------------------------------- @@ -505,7 +505,7 @@ namespace Subsurface private void Translate(Vector2 amount) { - if (amount == Vector2.Zero) return; + if (amount == Vector2.Zero || !amount.IsValid()) return; Level.Loaded.Move(-amount); } @@ -516,11 +516,6 @@ namespace Subsurface speed += force/mass; } - //public void Move(Vector2 amount) - //{ - // speed = Vector2.Lerp(speed, amount, 0.05f); - //} - VoronoiCell collidingCell; public bool OnCollision(Fixture f1, Fixture f2, Contact contact) { @@ -569,7 +564,7 @@ namespace Subsurface public override void FillNetworkData(Networking.NetworkEventType type, NetOutgoingMessage message, object data) { - message.Write(NetTime.Now); + message.Write((float)NetTime.Now); message.Write(Position.X); message.Write(Position.Y); @@ -580,11 +575,11 @@ namespace Subsurface public override void ReadNetworkData(Networking.NetworkEventType type, NetIncomingMessage message) { - double sendingTime; + float sendingTime; Vector2 newTargetPosition, newSpeed; try { - sendingTime = message.ReadDouble(); + sendingTime = message.ReadFloat(); if (sendingTime <= lastNetworkUpdate) return; @@ -592,11 +587,16 @@ namespace Subsurface newSpeed = new Vector2(message.ReadFloat(), message.ReadFloat()); } - catch + catch (Exception e) { +#if DEBUG + DebugConsole.ThrowError("invalid network message", e); +#endif return; } + if (!newSpeed.IsValid() || !newTargetPosition.IsValid()) return; + //newTargetPosition = newTargetPosition + newSpeed * (float)(NetTime.Now - sendingTime); targetPosition = newTargetPosition; diff --git a/Subsurface/Source/Map/WaterRenderer.cs b/Subsurface/Source/Map/WaterRenderer.cs index 46da2f6d5..37ca73c25 100644 --- a/Subsurface/Source/Map/WaterRenderer.cs +++ b/Subsurface/Source/Map/WaterRenderer.cs @@ -109,7 +109,12 @@ namespace Subsurface { pass.Apply(); - graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, verts.Length / 3, WaterVertex.VertexDeclaration); +#if WINDOWS + graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, verts.Length / 3, WaterVertex.VertexDeclaration); +#endif +#if LINUX + //graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, verts.Length / 3, WaterVertex.VertexDeclaration, ); +#endif } } @@ -130,7 +135,9 @@ namespace Subsurface { pass.Apply(); - graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3, WaterVertex.VertexDeclaration); +#if WINDOWS + graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3, WaterVertex.VertexDeclaration); +#endif } } diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 42d4cf342..1e66fe2f0 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -50,9 +50,8 @@ namespace Subsurface.Networking } - public void ConnectToServer(string hostIP) + public void ConnectToServer(string hostIP, string password = "") { - string[] address = hostIP.Split(':'); if (address.Length==1) { @@ -65,7 +64,7 @@ namespace Subsurface.Networking if (!int.TryParse(address[1], out Port)) { - DebugConsole.ThrowError("Invalid port: address[1]!"); + DebugConsole.ThrowError("Invalid port: "+address[1]+"!"); Port = DefaultPort; } } @@ -73,18 +72,24 @@ namespace Subsurface.Networking myCharacter = Character.Controlled; // Create new instance of configs. Parameter is "application Id". It has to be same on client and server. - NetPeerConfiguration Config = new NetPeerConfiguration("subsurface"); - - //Config.SimulatedLoss = 0.2f; - //Config.SimulatedMinimumLatency = 0.25f; + NetPeerConfiguration config = new NetPeerConfiguration("subsurface"); + +#if DEBUG + config.SimulatedLoss = 0.2f; + config.SimulatedMinimumLatency = 0.3f; +#endif + + config.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt + | NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error); // Create new client, with previously created configs - client = new NetClient(Config); + client = new NetClient(config); NetOutgoingMessage outmsg = client.CreateMessage(); client.Start(); outmsg.Write((byte)PacketTypes.Login); + outmsg.Write(password); outmsg.Write(Game1.Version.ToString()); outmsg.Write(Game1.SelectedPackage.Name); outmsg.Write(Game1.SelectedPackage.MD5hash.Hash); @@ -111,8 +116,11 @@ namespace Subsurface.Networking //update.Elapsed += new System.Timers.ElapsedEventHandler(Update); // Funtion that waits for connection approval info from server + if (reconnectBox==null) + { + reconnectBox = new GUIMessageBox("CONNECTING", "Connecting to " + serverIP, new string[0]); + } - reconnectBox = new GUIMessageBox("CONNECTING", "Connecting to " + serverIP, new string[0]); CoroutineManager.StartCoroutine(WaitForStartingInfo()); // Start the timer @@ -141,7 +149,7 @@ namespace Subsurface.Networking // When this is set to true, we are approved and ready to go bool CanStart = false; - DateTime timeOut = DateTime.Now + new TimeSpan(0,0,5); + DateTime timeOut = DateTime.Now + new TimeSpan(0,0,15); // Loop untill we are approved while (!CanStart) @@ -239,14 +247,19 @@ namespace Subsurface.Networking if (!connected || updateTimer > DateTime.Now) return; - if (client.ConnectionStatus == NetConnectionStatus.Disconnected && reconnectBox==null) + if (client.ConnectionStatus == NetConnectionStatus.Disconnected) { - reconnectBox = new GUIMessageBox("CONNECTION LOST", "You have been disconnected from the server. Reconnecting...", new string[0]); - connected = false; - ConnectToServer(serverIP); + if (reconnectBox==null) + { + reconnectBox = new GUIMessageBox("CONNECTION LOST", "You have been disconnected from the server. Reconnecting...", new string[0]); + connected = false; + ConnectToServer(serverIP); + } + return; } - else if (reconnectBox!=null) + + if (reconnectBox!=null) { reconnectBox.Close(null,null); reconnectBox = null; @@ -259,9 +272,20 @@ namespace Subsurface.Networking Character.Controlled = null; Game1.GameScreen.Cam.TargetPos = Vector2.Zero; } - else + else if (gameStarted) { - if (gameStarted) new NetworkEvent(myCharacter.ID, true); + Vector2 charMovement = myCharacter.AnimController.TargetMovement; + if ((charMovement == Vector2.Zero || charMovement.Length() < 0.001f) && + !myCharacter.GetInputState(InputType.ActionHeld) && + !myCharacter.GetInputState(InputType.SecondaryHeld)) + { + new NetworkEvent(NetworkEventType.NotMoving, myCharacter.ID, true); + + } + else + { + new NetworkEvent(myCharacter.ID, true); + } } } @@ -354,7 +378,7 @@ namespace Subsurface.Networking break; case (byte)PacketTypes.EndGame: string endMessage = inc.ReadString(); - EndGame(endMessage); + CoroutineManager.StartCoroutine(EndGame(endMessage)); break; case (byte)PacketTypes.PlayerJoined: @@ -406,19 +430,68 @@ namespace Subsurface.Networking } } - public void EndGame(string endMessage) + public IEnumerable EndGame(string endMessage) { + gameStarted = false; + + var messageBox = new GUIMessageBox("The round has ended", endMessage); + + Character.Controlled = null; + Game1.LightManager.LosEnabled = false; + + float endPreviewLength = 10.0f; + + DateTime endTime = DateTime.Now + new TimeSpan(0,0,0,0,(int)(1000.0f*endPreviewLength)); + float secondsLeft = endPreviewLength; + + do + { + secondsLeft = (float)(endTime - DateTime.Now).TotalSeconds; + + float camAngle = (float)((DateTime.Now - endTime).TotalSeconds / endPreviewLength) * MathHelper.TwoPi; + Vector2 offset = (new Vector2( + (float)Math.Cos(camAngle) * (Submarine.Borders.Width / 2.0f), + (float)Math.Sin(camAngle) * (Submarine.Borders.Height / 2.0f))); + + Game1.GameScreen.Cam.TargetPos = offset * 0.8f; + //Game1.GameScreen.Cam.MoveCamera((float)deltaTime); + + messageBox.Text = endMessage + "\nReturning to lobby in " + (int)secondsLeft + " s"; + yield return Status.Running; + } while (secondsLeft > 0.0f); + + messageBox.Text = endMessage; + Submarine.Unload(); Game1.NetLobbyScreen.Select(); if (Game1.GameSession!=null) Game1.GameSession.EndShift(""); - new GUIMessageBox("The round has ended", endMessage); - myCharacter = null; - gameStarted = false; + yield return Status.Success; + + } + + public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + + if (!Game1.DebugDraw) return; + + int width = 200, height = 300; + int x = Game1.GraphicsWidth - width, y = (int)(Game1.GraphicsHeight * 0.3f); + + GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black * 0.7f, true); + spriteBatch.DrawString(GUI.Font, "Network statistics:", new Vector2(x + 10, y + 10), Color.White); + + spriteBatch.DrawString(GUI.SmallFont, "Received bytes: " + client.Statistics.ReceivedBytes, new Vector2(x + 10, y + 45), Color.White); + spriteBatch.DrawString(GUI.SmallFont, "Received packets: " + client.Statistics.ReceivedPackets, new Vector2(x + 10, y + 60), Color.White); + + spriteBatch.DrawString(GUI.SmallFont, "Sent bytes: " + client.Statistics.SentBytes, new Vector2(x + 10, y + 75), Color.White); + spriteBatch.DrawString(GUI.SmallFont, "Sent packets: " + client.Statistics.SentPackets, new Vector2(x + 10, y + 90), Color.White); + } public override void Disconnect() @@ -514,7 +587,7 @@ namespace Subsurface.Networking msg.Write((byte)type); msg.Write(message); - client.SendMessage(msg, NetDeliveryMethod.Unreliable); + client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } /// diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index d856f7694..6b6d0b572 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -22,39 +22,54 @@ namespace Subsurface.Networking private TimeSpan refreshMasterInterval = new TimeSpan(0, 0, 40); private DateTime refreshMasterTimer; + private bool masterServerResponded; + private bool registeredToMaster; + private string password; + private Client myClient; - public GameServer(string name, int port) + public GameServer(string name, int port, bool isPublic = false, string password = "", bool attemptUPnP = false, int maxPlayers = 10) { var endRoundButton = new GUIButton(new Rectangle(Game1.GraphicsWidth - 290, 20, 150, 25), "End round", Alignment.TopLeft, GUI.style, inGameHUD); endRoundButton.OnClicked = EndButtonHit; this.name = name; + this.password = password; + config = new NetPeerConfiguration("subsurface"); - //config.SimulatedLoss = 0.2f; - //config.SimulatedMinimumLatency = 0.25f; - +#if DEBUG + config.SimulatedLoss = 0.2f; + config.SimulatedMinimumLatency = 0.3f; +#endif + config.Port = port; Port = port; - config.EnableUPnP = true; + if (attemptUPnP) + { + config.EnableUPnP = true; + } - config.MaximumConnections = 10; - + config.MaximumConnections = maxPlayers; + + config.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt + | NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error); + config.EnableMessageType(NetIncomingMessageType.ConnectionApproval); try { server = new NetServer(config); server.Start(); - - // attempt to forward port - server.UPnP.ForwardPort(port, "subsurface"); + if (attemptUPnP) + { + server.UPnP.ForwardPort(port, "subsurface"); + } } catch (Exception e) @@ -62,7 +77,11 @@ namespace Subsurface.Networking DebugConsole.ThrowError("Couldn't start the server", e); } - RegisterToMasterServer(); + if (isPublic) + { + RegisterToMasterServer(); + } + updateInterval = new TimeSpan(0, 0, 0, 0, 30); @@ -78,6 +97,7 @@ namespace Subsurface.Networking request.AddParameter("servername", name); request.AddParameter("serverport", Port); request.AddParameter("playercount", PlayerCountToByte(connectedClients.Count, config.MaximumConnections)); + request.AddParameter("password", string.IsNullOrWhiteSpace(password) ? 0 : 1); // execute the request RestResponse response = (RestResponse)client.Execute(request); @@ -98,7 +118,7 @@ namespace Subsurface.Networking refreshMasterTimer = DateTime.Now + refreshMasterInterval; } - private void RefreshMaster() + private IEnumerable RefreshMaster() { var client = new RestClient(NetworkMember.MasterServerUrl); @@ -112,17 +132,43 @@ namespace Subsurface.Networking var sw = new Stopwatch(); sw.Start(); - RestResponse response = (RestResponse)client.Execute(request); + masterServerResponded = false; + var restRequestHandle = client.ExecuteAsync(request, response => MasterServerCallBack(response)); - sw.Stop(); + DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 15); + while (!masterServerResponded) + { + if (DateTime.Now > timeOut) + { + restRequestHandle.Abort(); + DebugConsole.ThrowError("Couldn't connect to master server (request timed out)"); + registeredToMaster = false; + } System.Diagnostics.Debug.WriteLine("took "+sw.ElapsedMilliseconds+" ms"); + + yield return Status.Running; + } + + yield return Status.Success; + } + + private void MasterServerCallBack(IRestResponse response) + { + masterServerResponded = true; + + if (response.ErrorException != null) + { + DebugConsole.ThrowError("Error while connecting to master server", response.ErrorException); + registeredToMaster = false; + return; + } if (response.StatusCode != System.Net.HttpStatusCode.OK) { - DebugConsole.ThrowError("Error while connecting to master server (" +response.StatusCode+": "+response.StatusDescription+")"); + DebugConsole.ThrowError("Error while connecting to master server (" + response.StatusCode + ": " + response.StatusDescription + ")"); + registeredToMaster = false; + return; } - - } public override void Update(float deltaTime) @@ -159,7 +205,7 @@ namespace Subsurface.Networking if (registeredToMaster && refreshMasterTimer < DateTime.Now) { - RefreshMaster(); + CoroutineManager.StartCoroutine(RefreshMaster()); refreshMasterTimer = DateTime.Now + refreshMasterInterval; } @@ -177,9 +223,9 @@ namespace Subsurface.Networking break; } - if (!isClient) + if (!isClient && (c.SimPosition==Vector2.Zero || c.SimPosition.Length() < 300.0f)) { - c.LargeUpdateTimer = 0; + c.LargeUpdateTimer -= 2; new NetworkEvent(c.ID, false); } } @@ -204,9 +250,10 @@ namespace Subsurface.Networking Client existingClient = connectedClients.Find(c=> c.Connection == inc.SenderConnection); if (existingClient==null) { - string version = "", packageName="", packageHash="", name = ""; + string userPassword = "", version = "", packageName="", packageHash="", name = ""; try { + userPassword = inc.ReadString(); version = inc.ReadString(); packageName = inc.ReadString(); packageHash = inc.ReadString(); @@ -215,27 +262,38 @@ namespace Subsurface.Networking catch { inc.SenderConnection.Deny("Connection error - server failed to read your ConnectionApproval message"); + DebugConsole.NewMessage("Connection error - server failed to read the ConnectionApproval message", Color.Red); break; } - if (version != Game1.Version.ToString()) + if (userPassword != password) + { + inc.SenderConnection.Deny("Wrong password!"); + + break; + } + else if (version != Game1.Version.ToString()) { inc.SenderConnection.Deny("Subsurface version " + Game1.Version + " required to connect to the server (Your version: " + version + ")"); + DebugConsole.NewMessage("Connection error - wrong game version", Color.Red); break; } else if (packageName != Game1.SelectedPackage.Name) { inc.SenderConnection.Deny("Your content package ("+packageName+") doesn't match the server's version (" + Game1.SelectedPackage.Name + ")"); + DebugConsole.NewMessage("Connection error - wrong content package name", Color.Red); break; } else if (packageHash != Game1.SelectedPackage.MD5hash.Hash) { inc.SenderConnection.Deny("Your content package (MD5: " + packageHash + ") doesn't match the server's version (MD5: " + Game1.SelectedPackage.MD5hash.Hash + ")"); + DebugConsole.NewMessage("Connection error - wrong content package hash", Color.Red); break; } else if (connectedClients.Find(c => c.name.ToLower() == name.ToLower())!=null) { inc.SenderConnection.Deny("The name ''" + name + "'' is already in use. Please choose another name."); + DebugConsole.NewMessage("Connection error - name already in use", Color.Red); break; } @@ -348,7 +406,9 @@ namespace Subsurface.Networking } if (recipients.Count == 0) break; - server.SendMessage(outmsg, recipients, inc.DeliveryMethod, 0); + server.SendMessage(outmsg, recipients, inc.DeliveryMethod, 0); + + System.Diagnostics.Debug.WriteLine("Sending networkevent (" + outmsg.LengthBytes+" bytes)"); break; case (byte)PacketTypes.Chatmessage: @@ -396,15 +456,42 @@ namespace Subsurface.Networking { //System.Diagnostics.Debug.WriteLine("networkevent "+networkEvent.ID); + List recipients = new List(); + + if (!networkEvent.IsImportant) + { + Entity e = Entity.FindEntityByID(networkEvent.ID); + foreach (Client c in connectedClients) + { + if (c.character==null) continue; + if (Vector2.Distance(e.SimPosition, c.character.SimPosition) > 2000.0f) continue; + + recipients.Add(c.Connection); + } + } + else + { + foreach (Client c in connectedClients) + { + if (c.character == null) continue; + + recipients.Add(c.Connection); + } + } + + if (recipients.Count == 0) return; + NetOutgoingMessage message = server.CreateMessage(); message.Write((byte)PacketTypes.NetworkEvent); //if (!networkEvent.IsClient) continue; networkEvent.FillData(message); + System.Diagnostics.Debug.WriteLine("Sending networkevent " + Entity.FindEntityByID(networkEvent.ID).ToString() + " (" + message.LengthBytes + " bytes)"); + if (server.ConnectionsCount>0) { - server.SendMessage(message, server.Connections, + server.SendMessage(message, recipients, (networkEvent.IsImportant) ? NetDeliveryMethod.Unreliable : NetDeliveryMethod.ReliableUnordered, 0); } @@ -415,13 +502,19 @@ namespace Subsurface.Networking public bool StartGame(GUIButton button, object obj) { + Submarine selectedMap = Game1.NetLobbyScreen.SelectedMap as Submarine; + + if (selectedMap == null) + { + Game1.NetLobbyScreen.SubList.Flash(); + return false; + } + int seed = DateTime.Now.Millisecond; Rand.SetSyncedSeed(seed); - AssignJobs(); - - Submarine selectedMap = Game1.NetLobbyScreen.SelectedMap as Submarine; - + AssignJobs(); + //selectedMap.Load(); Game1.GameSession = new GameSession(selectedMap, "", Game1.NetLobbyScreen.SelectedMode); @@ -518,9 +611,10 @@ namespace Subsurface.Networking return true; } - public void EndGame(string endMessage) + public IEnumerable EndGame(string endMessage) { + gameStarted = false; if (connectedClients.Count > 0) { @@ -540,13 +634,34 @@ namespace Subsurface.Networking } } + float endPreviewLength = 10.0f; + + DateTime endTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, (int)(1000.0f * endPreviewLength)); + float secondsLeft = endPreviewLength; + + do + { + secondsLeft = (float)(endTime - DateTime.Now).TotalSeconds; + + float camAngle = (float)((DateTime.Now - endTime).TotalSeconds / endPreviewLength) * MathHelper.TwoPi; + Vector2 offset = (new Vector2( + (float)Math.Cos(camAngle) * (Submarine.Borders.Width / 2.0f), + (float)Math.Sin(camAngle) * (Submarine.Borders.Height / 2.0f))); + + Game1.GameScreen.Cam.TargetPos = offset * 0.8f; + //Game1.GameScreen.Cam.MoveCamera((float)deltaTime); + + yield return Status.Running; + } while (secondsLeft > 0.0f); + Submarine.Unload(); - - gameStarted = false; Game1.NetLobbyScreen.Select(); DebugConsole.ThrowError(endMessage); + + yield return Status.Success; + } private void DisconnectClient(NetConnection senderConnection) @@ -605,7 +720,7 @@ namespace Subsurface.Networking public void NewTraitor(Client traitor, Client target) { - new GUIMessageBox("New traitor", traitor.name + " is the traitor and the target is " + target+"."); + new GUIMessageBox("New traitor", traitor.name + " is the traitor and the target is " + target.name+"."); NetOutgoingMessage msg = server.CreateMessage(); msg.Write((byte)PacketTypes.Traitor); @@ -616,6 +731,36 @@ namespace Subsurface.Networking } } + public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + + if (!Game1.DebugDraw) return; + + int width = 200, height = 300; + int x = Game1.GraphicsWidth - width, y = (int)(Game1.GraphicsHeight*0.3f); + + GUI.DrawRectangle(spriteBatch, new Rectangle(x,y,width,height), Color.Black*0.7f, true); + spriteBatch.DrawString(GUI.Font, "Network statistics:", new Vector2(x+10, y+10), Color.White); + + spriteBatch.DrawString(GUI.SmallFont, "Connections: "+server.ConnectionsCount, new Vector2(x + 10, y + 30), Color.White); + spriteBatch.DrawString(GUI.SmallFont, "Received bytes: " + server.Statistics.ReceivedBytes, new Vector2(x + 10, y + 45), Color.White); + spriteBatch.DrawString(GUI.SmallFont, "Received packets: " + server.Statistics.ReceivedPackets, new Vector2(x + 10, y + 60), Color.White); + + spriteBatch.DrawString(GUI.SmallFont, "Sent bytes: " + server.Statistics.SentBytes, new Vector2(x + 10, y + 75), Color.White); + spriteBatch.DrawString(GUI.SmallFont, "Sent packets: " + server.Statistics.SentPackets, new Vector2(x + 10, y + 90), Color.White); + + y += 110; + foreach (Client c in connectedClients) + { + spriteBatch.DrawString(GUI.SmallFont, c.name + ":", new Vector2(x + 10, y), Color.White); + spriteBatch.DrawString(GUI.SmallFont, "- avg roundtrip " + c.Connection.AverageRoundtripTime+" s", new Vector2(x + 20, y + 15), Color.White); + y += 50; + + } + + } + public bool UpdateNetLobby(object obj) { NetOutgoingMessage msg = server.CreateMessage(); @@ -650,12 +795,12 @@ namespace Subsurface.Networking } if (recipients.Count>0) { - server.SendMessage(msg, recipients, NetDeliveryMethod.Unreliable, 0); + server.SendMessage(msg, recipients, NetDeliveryMethod.ReliableUnordered, 0); } } else { - server.SendMessage(msg, server.Connections, NetDeliveryMethod.Unreliable, 0); + server.SendMessage(msg, server.Connections, NetDeliveryMethod.ReliableUnordered, 0); } } diff --git a/Subsurface/Source/Networking/NetworkEvent.cs b/Subsurface/Source/Networking/NetworkEvent.cs index e2d699ffc..37e69e849 100644 --- a/Subsurface/Source/Networking/NetworkEvent.cs +++ b/Subsurface/Source/Networking/NetworkEvent.cs @@ -11,14 +11,15 @@ namespace Subsurface.Networking DropItem = 3, InventoryUpdate = 4, PickItem = 5, - UpdateProperty = 6 + UpdateProperty = 6, + NotMoving = 7 } class NetworkEvent { public static List events = new List(); - private static bool[] isImportant = { false, true, false, true, true, true }; + private static bool[] isImportant = { false, true, false, true, true, true, true, false }; private int id; @@ -113,6 +114,8 @@ namespace Subsurface.Networking return false; } + System.Diagnostics.Debug.WriteLine("Networkevent entity: "+e.ToString()); + //System.Diagnostics.Debug.WriteLine("new message: " + eventType +" - "+e); e.ReadNetworkData(eventType, message); diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index e28c54583..7e7f4c7b6 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -64,6 +64,11 @@ namespace Subsurface.Networking } } + public bool GameStarted + { + get { return gameStarted; } + } + public GUIFrame InGameHUD { get { return inGameHUD; } diff --git a/Subsurface/Source/Physics/PhysicsBody.cs b/Subsurface/Source/Physics/PhysicsBody.cs index 8af21e7f0..562397974 100644 --- a/Subsurface/Source/Physics/PhysicsBody.cs +++ b/Subsurface/Source/Physics/PhysicsBody.cs @@ -7,6 +7,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Subsurface.Networking; using System.Collections.Generic; +using System; namespace Subsurface { @@ -48,6 +49,7 @@ namespace Subsurface get { return targetPosition; } set { + if (float.IsNaN(value.X) || float.IsNaN(value.Y)) return; targetPosition.X = MathHelper.Clamp(value.X, -10000.0f, 10000.0f); targetPosition.Y = MathHelper.Clamp(value.Y, -10000.0f, 10000.0f); } @@ -57,7 +59,8 @@ namespace Subsurface { get { return targetVelocity; } set - { + { + if (float.IsNaN(value.X) || float.IsNaN(value.Y)) return; targetVelocity.X = MathHelper.Clamp(value.X, -100.0f, 100.0f); targetVelocity.Y = MathHelper.Clamp(value.Y, -100.0f, 100.0f); } @@ -68,7 +71,7 @@ namespace Subsurface get { return targetRotation; } set { - if (float.IsNaN(value) || float.IsInfinity(value) || float.IsNegativeInfinity(value)) return; + if (float.IsNaN(value) || float.IsInfinity(value)) return; targetRotation = value; } } @@ -76,7 +79,11 @@ namespace Subsurface public float TargetAngularVelocity { get { return targetAngularVelocity; } - set { targetAngularVelocity = value; } + set + { + if (float.IsNaN(value) || float.IsInfinity(value)) return; + targetAngularVelocity = value; + } } public Vector2 DrawPosition @@ -356,13 +363,37 @@ namespace Subsurface public void ReadNetworkData(NetworkEventType type, NetIncomingMessage message) { - targetPosition.X = message.ReadFloat(); - targetPosition.Y = message.ReadFloat(); - targetVelocity.X = message.ReadFloat(); - targetVelocity.Y = message.ReadFloat(); + Vector2 newTargetPos = Vector2.Zero; + Vector2 newTargetVel = Vector2.Zero; + + float newTargetRotation = 0.0f, newTargetAngularVel = 0.0f; + try + { + newTargetPos = new Vector2(message.ReadFloat(),message.ReadFloat()); + newTargetVel = new Vector2(message.ReadFloat(),message.ReadFloat()); + + newTargetRotation = message.ReadFloat(); + newTargetAngularVel = message.ReadFloat(); + } + + catch (Exception e) + { +#if DEBUG + DebugConsole.ThrowError("invalid network message", e); +#endif + return; + } + + if (!MathUtils.IsValid(newTargetPos) || !MathUtils.IsValid(newTargetVel) || + !MathUtils.IsValid(newTargetRotation) || !MathUtils.IsValid(newTargetAngularVel)) return; + + targetPosition = newTargetPos; + targetVelocity = newTargetVel; + + targetRotation = newTargetRotation; + targetAngularVelocity = newTargetAngularVel; + - targetRotation = message.ReadFloat(); - targetAngularVelocity = message.ReadFloat(); } } } diff --git a/Subsurface/Source/PlayerInput.cs b/Subsurface/Source/PlayerInput.cs index 642be272c..bb7a3e10a 100644 --- a/Subsurface/Source/PlayerInput.cs +++ b/Subsurface/Source/PlayerInput.cs @@ -3,157 +3,164 @@ using Microsoft.Xna.Framework.Input; namespace Subsurface { - class Key - { - private bool state, stateQueue; - private bool canBeHeld; - - public Key(bool canBeHeld) + + public enum InputType { Select, ActionHit, ActionHeld, SecondaryHit, SecondaryHeld } + + class Key + { + private bool state, stateQueue; + private bool canBeHeld; + + public bool CanBeHeld { - this.canBeHeld = canBeHeld; + get { return canBeHeld; } } + + public Key(bool canBeHeld) + { + this.canBeHeld = canBeHeld; + } - public bool State - { - get - { - return state; - } - set - { - //if (value == false) return; - state = value; - //if (value) stateQueue = value; - } - } + public bool State + { + get + { + return state; + } + set + { + //if (value == false) return; + state = value; + //if (value) stateQueue = value; + } + } - public void SetState(bool value) - { - state = value; - if (value) stateQueue = value; - } + public void SetState(bool value) + { + state = value; + if (value) stateQueue = value; + } - public bool Dequeue - { - get - { - bool value = stateQueue; - stateQueue = false; - return value; - } - //set - //{ - // stateQueue = value; - //} - } + public bool Dequeue + { + get + { + bool value = stateQueue; + stateQueue = false; + return value; + } + //set + //{ + // stateQueue = value; + //} + } - public void Reset() - { - if (!canBeHeld) state = false; - //stateQueue = false; - } - } + public void Reset() + { + if (!canBeHeld) state = false; + //stateQueue = false; + } + } - static class PlayerInput - { - static MouseState mouseState, oldMouseState; - static KeyboardState keyboardState, oldKeyboardState; + static class PlayerInput + { + static MouseState mouseState, oldMouseState; + static KeyboardState keyboardState, oldKeyboardState; - static double timeSinceClick; + static double timeSinceClick; - const double doubleClickDelay = 0.4; + const double doubleClickDelay = 0.4; - static bool doubleClicked; + static bool doubleClicked; - public static Keys selectKey = Keys.E; + public static Keys selectKey = Keys.E; - public static Vector2 MousePosition - { - get { return new Vector2(mouseState.Position.X, mouseState.Position.Y); } - } + public static Vector2 MousePosition + { + get { return new Vector2(mouseState.X, mouseState.Y); } + } - public static MouseState GetMouseState - { - get { return mouseState; } - } - public static MouseState GetOldMouseState - { - get { return oldMouseState; } - } + public static MouseState GetMouseState + { + get { return mouseState; } + } + public static MouseState GetOldMouseState + { + get { return oldMouseState; } + } - public static Vector2 MouseSpeed - { - get - { - Point speed = mouseState.Position - oldMouseState.Position; - return new Vector2(speed.X, speed.Y); - } - } + public static Vector2 MouseSpeed + { + get + { + return MousePosition - new Vector2(oldMouseState.X, oldMouseState.Y); + } + } - public static KeyboardState GetKeyboardState - { - get { return keyboardState; } - } + public static KeyboardState GetKeyboardState + { + get { return keyboardState; } + } - public static KeyboardState GetOldKeyboardState - { - get { return oldKeyboardState; } - } + public static KeyboardState GetOldKeyboardState + { + get { return oldKeyboardState; } + } - public static int ScrollWheelSpeed - { - get { return mouseState.ScrollWheelValue - oldMouseState.ScrollWheelValue; } - - } + public static int ScrollWheelSpeed + { + get { return mouseState.ScrollWheelValue - oldMouseState.ScrollWheelValue; } + + } - public static bool LeftButtonDown() - { - return mouseState.LeftButton == ButtonState.Pressed; - } + public static bool LeftButtonDown() + { + return mouseState.LeftButton == ButtonState.Pressed; + } - public static bool LeftButtonClicked() - { - return (oldMouseState.LeftButton == ButtonState.Pressed - && mouseState.LeftButton == ButtonState.Released); - } + public static bool LeftButtonClicked() + { + return (oldMouseState.LeftButton == ButtonState.Pressed + && mouseState.LeftButton == ButtonState.Released); + } - public static bool RightButtonClicked() - { - return (oldMouseState.RightButton == ButtonState.Pressed - && mouseState.RightButton == ButtonState.Released); - } + public static bool RightButtonClicked() + { + return (oldMouseState.RightButton == ButtonState.Pressed + && mouseState.RightButton == ButtonState.Released); + } - public static bool DoubleClicked() - { - return doubleClicked; - } + public static bool DoubleClicked() + { + return doubleClicked; + } - public static bool KeyHit(Keys button) - { - return (oldKeyboardState.IsKeyDown(button) && keyboardState.IsKeyUp(button)); - } + public static bool KeyHit(Keys button) + { + return (oldKeyboardState.IsKeyDown(button) && keyboardState.IsKeyUp(button)); + } - public static bool KeyDown(Keys button) - { - return (keyboardState.IsKeyDown(button)); - } + public static bool KeyDown(Keys button) + { + return (keyboardState.IsKeyDown(button)); + } - public static void Update(double deltaTime) - { - timeSinceClick += deltaTime; + public static void Update(double deltaTime) + { + timeSinceClick += deltaTime; - oldMouseState = mouseState; - mouseState = Mouse.GetState(); + oldMouseState = mouseState; + mouseState = Mouse.GetState(); - oldKeyboardState = keyboardState; - keyboardState = Keyboard.GetState(); + oldKeyboardState = keyboardState; + keyboardState = Keyboard.GetState(); - doubleClicked = false; - if (LeftButtonClicked()) - { - if (timeSinceClick < doubleClickDelay) doubleClicked = true; - timeSinceClick = 0.0; - } - } - } + doubleClicked = false; + if (LeftButtonClicked()) + { + if (timeSinceClick < doubleClickDelay) doubleClicked = true; + timeSinceClick = 0.0; + } + } + } } diff --git a/Subsurface/Source/Properties.cs b/Subsurface/Source/Properties.cs index 3b4d10fef..e27bdf52a 100644 --- a/Subsurface/Source/Properties.cs +++ b/Subsurface/Source/Properties.cs @@ -5,11 +5,18 @@ using System.Globalization; using System.Linq; using System.Xml.Linq; + namespace Subsurface { [AttributeUsage(AttributeTargets.Property)] public class Editable : System.Attribute { + public int MaxLength; + + public Editable(int maxLength = 20) + { + MaxLength = maxLength; + } } [AttributeUsage(AttributeTargets.Property)] diff --git a/Subsurface/Source/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs index 326d199ef..6bfc35afe 100644 --- a/Subsurface/Source/Screens/EditMapScreen.cs +++ b/Subsurface/Source/Screens/EditMapScreen.cs @@ -176,7 +176,7 @@ namespace Subsurface // CreateDummyCharacter(); //} - cam.MoveCamera((float)deltaTime); + if (GUIComponent.MouseOn==null) cam.MoveCamera((float)deltaTime); cam.Zoom = MathHelper.Clamp(cam.Zoom + PlayerInput.ScrollWheelSpeed/1000.0f,0.1f, 2.0f); if (characterMode) diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index 366965bb4..96a4d111a 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -75,11 +75,12 @@ namespace Subsurface StatusEffect.UpdateAll((float)deltaTime); - cam.MoveCamera((float)deltaTime); Physics.accumulator = Math.Min(Physics.accumulator, Physics.step * 4); while (Physics.accumulator >= Physics.step) { + cam.MoveCamera((float)Physics.step); + foreach (PhysicsBody pb in PhysicsBody.list) { pb.SetPrevTransform(pb.Position, pb.Rotation); @@ -146,7 +147,7 @@ namespace Subsurface graphics.Clear(new Color(11, 18, 26, 255)); - spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.LinearWrap); + spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.LinearWrap, DepthStencilState.Default, RasterizerState.CullNone); Vector2 backgroundPos = cam.Position; if (Level.Loaded != null) backgroundPos -= Level.Loaded.Position; diff --git a/Subsurface/Source/Screens/LobbyScreen.cs b/Subsurface/Source/Screens/LobbyScreen.cs index 04160fa25..266740951 100644 --- a/Subsurface/Source/Screens/LobbyScreen.cs +++ b/Subsurface/Source/Screens/LobbyScreen.cs @@ -428,7 +428,7 @@ namespace Subsurface private bool StartShift(GUIButton button, object selection) { - Game1.GameSession.StartShift(TimeSpan.Zero, selectedLevel); + Game1.GameSession.StartShift(TimeSpan.Zero, selectedLevel, false); Game1.GameScreen.Select(); return true; diff --git a/Subsurface/Source/Screens/MainMenu.cs b/Subsurface/Source/Screens/MainMenu.cs index c9f9ae9d5..107da690a 100644 --- a/Subsurface/Source/Screens/MainMenu.cs +++ b/Subsurface/Source/Screens/MainMenu.cs @@ -18,9 +18,8 @@ namespace Subsurface private GUITextBox saveNameBox, seedBox; - private GUITextBox clientNameBox, ipBox; - - private GUITextBox serverNameBox, portBox; + private GUITextBox serverNameBox, portBox, passwordBox, maxPlayersBox; + private GUITickBox isPublicBox, useUpnpBox; private Game1 game; @@ -38,10 +37,10 @@ namespace Subsurface menuTabs[(int)Tabs.Main] = new GUIFrame(panelRect, GUI.style); //menuTabs[(int)Tabs.Main].Padding = GUI.style.smallPadding; - GUIButton button = new GUIButton(new Rectangle(0, 0, 0, 30), "Tutorial", Alignment.CenterX, GUI.style, menuTabs[(int)Tabs.Main]); - button.OnClicked = TutorialButtonClicked; + //GUIButton button = new GUIButton(new Rectangle(0, 0, 0, 30), "Tutorial", Alignment.CenterX, GUI.style, menuTabs[(int)Tabs.Main]); + //button.OnClicked = TutorialButtonClicked; - button = new GUIButton(new Rectangle(0, 70, 0, 30), "New Game", Alignment.CenterX, GUI.style, menuTabs[(int)Tabs.Main]); + GUIButton button = new GUIButton(new Rectangle(0, 70, 0, 30), "New Game", Alignment.CenterX, GUI.style, menuTabs[(int)Tabs.Main]); button.UserData = (int)Tabs.NewGame; button.OnClicked = SelectTab; //button.Enabled = false; @@ -112,16 +111,44 @@ namespace Subsurface menuTabs[(int)Tabs.HostServer] = new GUIFrame(panelRect, GUI.style); //menuTabs[(int)Tabs.JoinServer].Padding = GUI.style.smallPadding; - new GUITextBlock(new Rectangle(0, 0, 0, 30), "Host Server", GUI.style, Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.HostServer]); + new GUITextBlock(new Rectangle(0, -25, 0, 30), "Host Server", GUI.style, Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.HostServer], false, GUI.LargeFont); - new GUITextBlock(new Rectangle(0, 30, 0, 30), "Server Name:", GUI.style, Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.HostServer]); - serverNameBox = new GUITextBox(new Rectangle(0, 60, 200, 30), Color.White, Color.Black, Alignment.CenterX, Alignment.CenterX, null, menuTabs[(int)Tabs.HostServer]); + new GUITextBlock(new Rectangle(0, 50, 0, 30), "Server Name:", GUI.style, Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tabs.HostServer]); + serverNameBox = new GUITextBox(new Rectangle(160, 50, 200, 30), null, null, Alignment.TopLeft, Alignment.Left, GUI.style, menuTabs[(int)Tabs.HostServer]); - new GUITextBlock(new Rectangle(0, 100, 0, 30), "Server port:", GUI.style, Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.HostServer]); - portBox = new GUITextBox(new Rectangle(0, 130, 200, 30), Color.White, Color.Black, Alignment.CenterX, Alignment.CenterX, null, menuTabs[(int)Tabs.HostServer]); + new GUITextBlock(new Rectangle(0, 100, 0, 30), "Server port:", GUI.style, Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tabs.HostServer]); + portBox = new GUITextBox(new Rectangle(160, 100, 200, 30), null, null, Alignment.TopLeft, Alignment.Left, GUI.style, menuTabs[(int)Tabs.HostServer]); portBox.Text = NetworkMember.DefaultPort.ToString(); portBox.ToolTip = "Server port"; + new GUITextBlock(new Rectangle(0, 150, 100, 30), "Max players:", GUI.style, Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tabs.HostServer]); + maxPlayersBox = new GUITextBox(new Rectangle(195, 150, 30, 30), null, null, Alignment.TopLeft, Alignment.Center, GUI.style, menuTabs[(int)Tabs.HostServer]); + maxPlayersBox.Text = "8"; + maxPlayersBox.Enabled = false; + + var plusPlayersBox = new GUIButton(new Rectangle(230, 150, 30, 30), "+", GUI.style, menuTabs[(int)Tabs.HostServer]); + plusPlayersBox.UserData = 1; + plusPlayersBox.OnClicked = ChangeMaxPlayers; + + var minusPlayersBox = new GUIButton(new Rectangle(160, 150, 30, 30), "-", GUI.style, menuTabs[(int)Tabs.HostServer]); + minusPlayersBox.UserData = -1; + minusPlayersBox.OnClicked = ChangeMaxPlayers; + + new GUITextBlock(new Rectangle(0, 200, 0, 30), "Password (optional):", GUI.style, Alignment.TopLeft, Alignment.Left, menuTabs[(int)Tabs.HostServer]); + passwordBox = new GUITextBox(new Rectangle(160, 200, 200, 30), null, null, Alignment.TopLeft, Alignment.Left, GUI.style, menuTabs[(int)Tabs.HostServer]); + + + isPublicBox = new GUITickBox(new Rectangle(10, 250, 20, 20), "Public server", Alignment.TopLeft, menuTabs[(int)Tabs.HostServer]); + + useUpnpBox = new GUITickBox(new Rectangle(10, 300, 20, 20), "Attempt UPnP port forwarding", Alignment.TopLeft, menuTabs[(int)Tabs.HostServer]); + new GUITextBlock(new Rectangle(0, 330, 0, 30), + "UPnP can be used for forwarding ports on your router to allow players join the server." + + " However, UPnP isn't supported by all routers, so you may need to setup port forwards manually" + +" if players are unable to join the server (see the readme for instructions).", + GUI.style, Alignment.TopLeft, Alignment.TopLeft, menuTabs[(int)Tabs.HostServer], true, GUI.SmallFont); + + + GUIButton hostButton = new GUIButton(new Rectangle(0, 0, 200, 30), "Start", Alignment.BottomCenter, GUI.style, menuTabs[(int)Tabs.HostServer]); hostButton.OnClicked = HostServerClicked; @@ -159,6 +186,18 @@ namespace Subsurface return true; } + private bool ChangeMaxPlayers(GUIButton button, object obj) + { + int currMaxPlayers = 10; + + int.TryParse(maxPlayersBox.Text, out currMaxPlayers); + currMaxPlayers = (int)MathHelper.Clamp(currMaxPlayers+(int)button.UserData, 1, 10); + + maxPlayersBox.Text = currMaxPlayers.ToString(); + + return true; + } + private bool HostServerClicked(GUIButton button, object obj) { string name = serverNameBox.Text; @@ -177,7 +216,7 @@ namespace Subsurface return false; } - Game1.NetworkMember = new GameServer(name, port); + Game1.NetworkMember = new GameServer(name, port, isPublicBox.Selected, passwordBox.Text, useUpnpBox.Selected, int.Parse(maxPlayersBox.Text)); Game1.NetLobbyScreen.IsServer = true; Game1.NetLobbyScreen.Select(); @@ -194,7 +233,7 @@ namespace Subsurface { menuTabs[(int)Tabs.LoadGame].ClearChildren(); - new GUITextBlock(new Rectangle(0, 0, 0, 30), "Load Game", GUI.style, Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.LoadGame]); + new GUITextBlock(new Rectangle(0, -25, 0, 30), "Load Game", GUI.style, Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.LoadGame], false, GUI.LargeFont); string[] saveFiles = SaveUtil.GetSaveFiles(); @@ -376,26 +415,5 @@ namespace Subsurface return true; } - - private bool JoinServer(GUIButton button, object obj) - { - if (string.IsNullOrEmpty(clientNameBox.Text)) return false; - if (string.IsNullOrEmpty(ipBox.Text)) return false; - - Game1.NetworkMember = new GameClient(clientNameBox.Text); - Game1.Client.ConnectToServer(ipBox.Text); - - return true; - //{ - // Game1.NetLobbyScreen.Select(); - // return true; - //} - //else - //{ - // Game1.NetworkMember = null; - // return false; - //} - } - } } diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index 993e285c7..dbcf83bde 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -23,8 +23,6 @@ namespace Subsurface private GUITextBox textBox, seedBox; - //GUIFrame previewPlayer; - private GUIScrollBar durationBar; private GUIFrame playerFrame; @@ -36,6 +34,11 @@ namespace Subsurface private GUITextBox serverMessage; + public GUIListBox SubList + { + get { return subList; } + } + public Submarine SelectedMap { get { return subList.SelectedData as Submarine; } @@ -275,7 +278,7 @@ namespace Subsurface modeList.OnSelected += Game1.Server.UpdateNetLobby; durationBar.OnMoved = Game1.Server.UpdateNetLobby; - if (subList.CountChildren > 0) subList.Select(0); + if (subList.CountChildren > 0) subList.Select(-1); if (GameModePreset.list.Count > 0) modeList.Select(0); } else if (playerFrame.children.Count==0) @@ -306,9 +309,11 @@ namespace Subsurface jobList = new GUIListBox(new Rectangle(0, 180, 180, 0), GUI.style, playerFrame); jobList.Enabled = false; + + int i = 1; foreach (JobPrefab job in JobPrefab.List) { - GUITextBlock jobText = new GUITextBlock(new Rectangle(0,0,0,20), job.Name, GUI.style, Alignment.Left, Alignment.Right, jobList); + GUITextBlock jobText = new GUITextBlock(new Rectangle(0,0,0,20), i+". "+job.Name, GUI.style, Alignment.Left, Alignment.Right, jobList); jobText.UserData = job; GUIButton upButton = new GUIButton(new Rectangle(0, 0, 15, 15), "u", GUI.style, jobText); @@ -443,6 +448,7 @@ namespace Subsurface ((chatBox.CountChildren % 2) == 0) ? Color.Transparent : Color.Black*0.1f, color, Alignment.Left, GUI.style, null, true); msg.Font = GUI.SmallFont; + msg.CanBeFocused = false; msg.Padding = new Vector4(20, 0, 0, 0); chatBox.AddChild(msg); @@ -556,13 +562,17 @@ namespace Subsurface private void UpdateJobPreferences(GUIListBox listBox) { listBox.Deselect(); - for (int i = 1; i < listBox.children.Count; i++) + for (int i = 0; i < listBox.children.Count; i++) { float a = (float)(i - 1) / 3.0f; a = Math.Min(a, 3); Color color = new Color(1.0f - a, (1.0f - a) * 0.6f, 0.0f, 0.3f); listBox.children[i].Color = color; + listBox.children[i].HoverColor = color; + listBox.children[i].SelectedColor = color; + + (listBox.children[i] as GUITextBlock).Text = (i+1) + ". " + (listBox.children[i].UserData as JobPrefab).Name; } Game1.Client.SendCharacterData(); @@ -658,57 +668,13 @@ namespace Subsurface return; } - TrySelectMap(mapName, md5Hash); + if (!string.IsNullOrWhiteSpace(mapName)) TrySelectMap(mapName, md5Hash); modeList.Select(modeIndex); durationBar.BarScroll = durationScroll; LevelSeed = levelSeed; - - //try - //{ - // int playerCount = msg.ReadInt32(); - - // for (int i = 0; i < playerCount; i++) - // { - // int clientID = msg.ReadInt32(); - // string jobName = msg.ReadString(); - - // Client client = null; - // GUITextBlock textBlock = null; - // foreach (GUIComponent child in playerList.children) - // { - // Client tempClient = child.UserData as Client; - // if (tempClient == null || tempClient.ID != clientID) continue; - - // client = tempClient; - // textBlock = child as GUITextBlock; - // break; - // } - // if (client == null) continue; - - // client.assignedJob = JobPrefab.List.Find(jp => jp.Name == jobName); - - // textBlock.Text = client.name + ((client.assignedJob==null) ? "" : " (" + client.assignedJob.Name + ")"); - - // if (client.assignedJob==null || jobName != client.assignedJob.Name) - // { - // if (clientID == Game1.Client.ID) - // { - // Game1.Client.CharacterInfo.Job = new Job(client.assignedJob); - // Game1.Client.CharacterInfo.Name = client.name; - // UpdatePreviewPlayer(Game1.Client.CharacterInfo); - // } - // } - // } - //} - - //catch - //{ - // return; - //} - } } diff --git a/Subsurface/Source/Screens/Screen.cs b/Subsurface/Source/Screens/Screen.cs index 36e95f6d3..e0a8268ab 100644 --- a/Subsurface/Source/Screens/Screen.cs +++ b/Subsurface/Source/Screens/Screen.cs @@ -5,7 +5,7 @@ namespace Subsurface class Screen { private static Screen selected; - + public static Screen Selected { get { return selected; } diff --git a/Subsurface/Source/Screens/ServerListScreen.cs b/Subsurface/Source/Screens/ServerListScreen.cs index a68e096ad..00dd70f84 100644 --- a/Subsurface/Source/Screens/ServerListScreen.cs +++ b/Subsurface/Source/Screens/ServerListScreen.cs @@ -14,6 +14,9 @@ namespace Subsurface { class ServerListScreen : Screen { + //how often the client is allowed to refresh servers + private TimeSpan AllowedRefreshInterval = new TimeSpan(0,0,3); + private GUIFrame menu; private GUIListBox serverList; @@ -22,6 +25,15 @@ namespace Subsurface private GUITextBox clientNameBox, ipBox; + //private RestRequestAsyncHandle restRequestHandle; + private bool masterServerResponded; + + private int[] columnX; + + //a timer for + private DateTime refreshDisableTimer; + private bool waitingForRefresh; + public ServerListScreen() { int width = Math.Min(Game1.GraphicsWidth - 160, 1000); @@ -30,37 +42,55 @@ namespace Subsurface Rectangle panelRect = new Rectangle(0, 0, width, height); menu = new GUIFrame(panelRect, null, Alignment.Center, GUI.style); - - new GUITextBlock(new Rectangle(0, 0, 0, 30), "Join Server", GUI.style, Alignment.CenterX, Alignment.CenterX, menu); + + new GUITextBlock(new Rectangle(0, -25, 0, 30), "Join Server", GUI.style, Alignment.CenterX, Alignment.CenterX, menu, false, GUI.LargeFont); new GUITextBlock(new Rectangle(0, 30, 0, 30), "Your Name:", GUI.style, menu); clientNameBox = new GUITextBox(new Rectangle(0, 60, 200, 30), GUI.style, menu); new GUITextBlock(new Rectangle(0, 100, 0, 30), "Server IP:", GUI.style, menu); ipBox = new GUITextBox(new Rectangle(0, 130, 200, 30), GUI.style, menu); - + int middleX = (int)(width * 0.4f); serverList = new GUIListBox(new Rectangle(middleX,60,0,(int)(height*0.7f)), GUI.style, menu); serverList.OnSelected = SelectServer; - new GUITextBlock(new Rectangle(middleX, 30, 0, 30), "Name", GUI.style, menu); - new GUITextBlock(new Rectangle(middleX, 30, 0, 30), "Players", GUI.style, Alignment.TopLeft, Alignment.TopCenter, menu); - new GUITextBlock(new Rectangle(middleX, 30, 0, 30), "Game running", GUI.style, Alignment.TopLeft, Alignment.TopRight, menu); + float[] columnRelativeX = new float[] { 0.15f, 0.55f, 0.15f, 0.15f }; + columnX = new int[columnRelativeX.Length]; + for (int n = 0; n < columnX.Length; n++) + { + columnX[n] = (int)(columnRelativeX[n] * serverList.Rect.Width); + if (n > 0) columnX[n] += columnX[n - 1]; + } + + new GUITextBlock(new Rectangle(middleX, 30, 0, 30), "Password", GUI.style, menu); + + new GUITextBlock(new Rectangle(middleX + columnX[0], 30, 0, 30), "Name", GUI.style, menu); + new GUITextBlock(new Rectangle(middleX + columnX[1], 30, 0, 30), "Players", GUI.style, menu); + new GUITextBlock(new Rectangle(middleX + columnX[2], 30, 0, 30), "Running", GUI.style, menu); joinButton = new GUIButton(new Rectangle(-170, 0, 150, 30), "Refresh", Alignment.BottomRight, GUI.style, menu); joinButton.OnClicked = RefreshServers; joinButton = new GUIButton(new Rectangle(0,0,150,30), "Join", Alignment.BottomRight, GUI.style, menu); joinButton.OnClicked = JoinServer; - //joinButton.Enabled = false; + + GUIButton button = new GUIButton(new Rectangle(-20, -20, 100, 30), "Back", Alignment.TopLeft, GUI.style, menu); + button.UserData = 0; + button.OnClicked = Game1.MainMenuScreen.SelectTab; + + + refreshDisableTimer = DateTime.Now; } public override void Select() { base.Select(); - UpdateServerList(); + + //RefreshServers(null, null); + //UpdateServerList(); } private bool SelectServer(object obj) @@ -75,16 +105,39 @@ namespace Subsurface private bool RefreshServers(GUIButton button, object obj) { - UpdateServerList(); + if (waitingForRefresh) return false; + serverList.ClearChildren(); + + new GUITextBlock(new Rectangle(0, 0, 0, 20), "Refreshing server list...", GUI.style, serverList); + + CoroutineManager.StartCoroutine(WaitForRefresh()); return true; } - private void UpdateServerList() + private IEnumerable WaitForRefresh() + { + waitingForRefresh = true; + if (refreshDisableTimer > DateTime.Now) + { + yield return new WaitForSeconds((float)(refreshDisableTimer - DateTime.Now).TotalSeconds); + } + + //CoroutineManager.StartCoroutine(UpdateServerList()); + CoroutineManager.StartCoroutine(SendMasterServerRequest()); + + waitingForRefresh = false; + + refreshDisableTimer = DateTime.Now + AllowedRefreshInterval; + + yield return Status.Success; + } + + private void UpdateServerList(string masterServerData) { serverList.ClearChildren(); - - string masterServerData = GetMasterServerData(); + + //string masterServerData = GetMasterServerData(); if (string.IsNullOrWhiteSpace(masterServerData)) { @@ -96,6 +149,7 @@ namespace Subsurface if (masterServerData.Substring(0,5).ToLower()=="error") { DebugConsole.ThrowError("Error while connecting to master server ("+masterServerData+")!"); + return; } @@ -112,23 +166,33 @@ namespace Subsurface string gameStarted = (arguments.Length > 3) ? arguments[3] : ""; string playerCountStr = (arguments.Length > 4) ? arguments[4] : ""; + string hasPassWordStr = (arguments.Length > 5) ? arguments[5] : ""; + var serverFrame = new GUIFrame(new Rectangle(0,0,0,20), (i%2 == 0) ? Color.Transparent : Color.White*0.2f, null, serverList); serverFrame.UserData = IP+":"+port; serverFrame.HoverColor = Color.Gold * 0.2f; serverFrame.SelectedColor = Color.Gold * 0.5f; - var nameText = new GUITextBlock(new Rectangle(0,0,0,0), serverName, GUI.style, serverFrame); + var passwordBox = new GUITickBox(new Rectangle(columnX[0]/2, 0, 20, 20), "", Alignment.TopLeft, serverFrame); + passwordBox.Selected = hasPassWordStr == "1"; + passwordBox.Enabled = false; + passwordBox.UserData = "password"; + + var nameText = new GUITextBlock(new Rectangle(columnX[0], 0, 0, 0), serverName, GUI.style, serverFrame); int playerCount, maxPlayers; playerCount = GameClient.ByteToPlayerCount((byte)int.Parse(playerCountStr), out maxPlayers); - var playerCountText = new GUITextBlock(new Rectangle(0, 0, 0, 0), playerCount+"/"+maxPlayers, GUI.style, Alignment.Left, Alignment.TopCenter, serverFrame); - var gameStartedText = new GUITextBlock(new Rectangle(0, 0, 0, 0), gameStarted=="1" ? "Yes" : "No", GUI.style, Alignment.Left, Alignment.TopRight, serverFrame); + var playerCountText = new GUITextBlock(new Rectangle(columnX[1], 0, 0, 0), playerCount + "/" + maxPlayers, GUI.style, serverFrame); + + var gameStartedBox = new GUITickBox(new Rectangle(columnX[2] + (columnX[3] - columnX[2])/ 2, 0, 20, 20), "", Alignment.TopLeft, serverFrame); + gameStartedBox.Selected = gameStarted == "1"; + gameStartedBox.Enabled = false; } } - private string GetMasterServerData() + private IEnumerable SendMasterServerRequest() { RestClient client = null; try @@ -137,10 +201,11 @@ namespace Subsurface } catch (Exception e) { - DebugConsole.ThrowError("Error while connecting to master server", e); - return ""; + DebugConsole.ThrowError("Error while connecting to master server", e); } + if (client == null) yield return Status.Success; + var request = new RestRequest("masterserver.php", Method.GET); request.AddParameter("gamename", "subsurface"); // adds to POST or URL querystring based on Method @@ -154,17 +219,44 @@ namespace Subsurface //request.AddFile(path); // execute the request - RestResponse response = (RestResponse)client.Execute(request); + masterServerResponded = false; + var restRequestHandle = client.ExecuteAsync(request, response => MasterServerCallBack(response)); + DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 8); + while (!masterServerResponded) + { + if (DateTime.Now > timeOut) + { + serverList.ClearChildren(); + restRequestHandle.Abort(); + DebugConsole.ThrowError("Couldn't connect to master server (request timed out)"); + } + yield return Status.Running; + } + + yield return Status.Success; + + } + + private void MasterServerCallBack(IRestResponse response) + { + masterServerResponded = true; + + if (response.ErrorException!=null) + { + serverList.ClearChildren(); + DebugConsole.ThrowError("Error while connecting to master server", response.ErrorException); + return; + } if (response.StatusCode!= System.Net.HttpStatusCode.OK) { + serverList.ClearChildren(); DebugConsole.ThrowError("Error while connecting to master server (" +response.StatusCode+": "+response.StatusDescription+")"); - return ""; + return; } - return response.Content; // raw content as string - + UpdateServerList(response.Content); } private bool JoinServer(GUIButton button, object obj) @@ -183,12 +275,41 @@ namespace Subsurface return false; } - Game1.NetworkMember = new GameClient(clientNameBox.Text); - Game1.Client.ConnectToServer(ip); + CoroutineManager.StartCoroutine(JoinServer(ip)); + return true; } + private IEnumerable JoinServer(string ip) + { + string selectedPassword = ""; + + if (serverList.Selected!=null && (serverList.Selected.GetChild("password") as GUITickBox).Selected) + { + var msgBox = new GUIMessageBox("Password required", ""); + var passwordBox = new GUITextBox(new Rectangle(0,0,150,20), Alignment.BottomCenter, GUI.style, msgBox); + passwordBox.UserData = "password"; + + var okButton = msgBox.GetChild(); + + while (GUIMessageBox.MessageBoxes.Contains(msgBox)) + { + okButton.Enabled = !string.IsNullOrWhiteSpace(passwordBox.Text); + yield return Status.Running; + } + + selectedPassword = passwordBox.Text; + } + + Game1.NetworkMember = new GameClient(clientNameBox.Text); + Game1.Client.ConnectToServer(ip, selectedPassword); + + Game1.NetLobbyScreen.Select(); + + yield return Status.Success; + } + public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) { graphics.Clear(Color.CornflowerBlue); @@ -208,6 +329,8 @@ namespace Subsurface public override void Update(double deltaTime) { + + menu.Update((float)deltaTime); GUI.Update((float)deltaTime); diff --git a/Subsurface/Source/Sounds/AmbientSoundManager.cs b/Subsurface/Source/Sounds/AmbientSoundManager.cs index a984733c5..72ef26434 100644 --- a/Subsurface/Source/Sounds/AmbientSoundManager.cs +++ b/Subsurface/Source/Sounds/AmbientSoundManager.cs @@ -155,7 +155,7 @@ namespace Subsurface if (startDrone!=null) { - if (!SoundManager.IsPlaying(startDrone.AlBufferId)) + if (!startDrone.IsPlaying) { startDrone.Remove(); startDrone = null; diff --git a/Subsurface/Source/Sounds/Sound.cs b/Subsurface/Source/Sounds/Sound.cs index 1244d6c1e..ac74d1272 100644 --- a/Subsurface/Source/Sounds/Sound.cs +++ b/Subsurface/Source/Sounds/Sound.cs @@ -19,6 +19,8 @@ namespace Subsurface private OggSound oggSound; string filePath; + + private int alSourceId; //public float Volume @@ -71,7 +73,8 @@ namespace Subsurface public int Play(float volume = 1.0f) { - return SoundManager.Play(this, volume); + alSourceId = SoundManager.Play(this, volume); + return alSourceId; } public int Play(float baseVolume, float range, Vector2 position) @@ -83,7 +86,9 @@ namespace Subsurface Vector2 relativePos = GetRelativePosition(position); float volume = GetVolume(relativePos, range, baseVolume); - return SoundManager.Play(this, relativePos, volume, volume); + alSourceId = SoundManager.Play(this, relativePos, volume, volume); + + return alSourceId; //if (newIndex == -1) return -1; @@ -96,7 +101,9 @@ namespace Subsurface //bodyPosition.Y = -bodyPosition.Y; - return Play(volume, range, ConvertUnits.ToDisplayUnits(body.Position)); + alSourceId = Play(volume, range, ConvertUnits.ToDisplayUnits(body.Position)); + + return alSourceId; } private float GetVolume(Vector2 relativePosition, float range, float baseVolume) @@ -178,6 +185,14 @@ namespace Subsurface } + public bool IsPlaying + { + get + { + return SoundManager.IsPlaying(alSourceId); + } + } + //public int Loop(float volume = 1.0f) //{ // return SoundManager.Loop(this, volume); diff --git a/Subsurface/Source/Sounds/SoundManager.cs b/Subsurface/Source/Sounds/SoundManager.cs index ef705ba62..345e7009d 100644 --- a/Subsurface/Source/Sounds/SoundManager.cs +++ b/Subsurface/Source/Sounds/SoundManager.cs @@ -1,8 +1,11 @@ using System.Collections.Generic; using System.Diagnostics; using Microsoft.Xna.Framework; -using OpenTK.Audio; +#if WINDOWS using OpenTK.Audio.OpenAL; +#endif +using OpenTK.Audio; + using System; namespace Subsurface.Sounds @@ -34,14 +37,14 @@ namespace Subsurface.Sounds for (int i = 0 ; i < DefaultSourceCount; i++) { - alSources.Add(AL.GenSource()); + alSources.Add(OpenTK.Audio.OpenAL.AL.GenSource()); } if (ALHelper.Efx.IsInitialized) { lowpassFilterId = ALHelper.Efx.GenFilter(); //alFilters.Add(alFilterId); - ALHelper.Efx.Filter(lowpassFilterId, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass); + ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilteri.FilterType, (int)OpenTK.Audio.OpenAL.EfxFilterType.Lowpass); //LowPassHFGain = 1; } @@ -129,29 +132,29 @@ namespace Subsurface.Sounds for (int i = 1; i < DefaultSourceCount; i++) { //find a source that's free to use (not playing or paused) - if (AL.GetSourceState(alSources[i]) == ALSourceState.Playing - || AL.GetSourceState(alSources[i]) == ALSourceState.Paused) continue; + if (OpenTK.Audio.OpenAL.AL.GetSourceState(alSources[i]) == OpenTK.Audio.OpenAL.ALSourceState.Playing + || OpenTK.Audio.OpenAL.AL.GetSourceState(alSources[i]) == OpenTK.Audio.OpenAL.ALSourceState.Paused) continue; //if (position!=Vector2.Zero) // position /= 1000.0f; alBuffers[i] = sound.AlBufferId; - AL.Source(alSources[i], ALSourceb.Looping, false); + OpenTK.Audio.OpenAL.AL.Source(alSources[i], OpenTK.Audio.OpenAL.ALSourceb.Looping, false); position /= 1000.0f; //System.Diagnostics.Debug.WriteLine("updatesoundpos: "+offset); - AL.Source(alSources[i], ALSourcef.Gain, volume); - AL.Source(alSources[i], ALSource3f.Position, position.X, position.Y, 0.0f); + OpenTK.Audio.OpenAL.AL.Source(alSources[i], OpenTK.Audio.OpenAL.ALSourcef.Gain, volume); + OpenTK.Audio.OpenAL.AL.Source(alSources[i], OpenTK.Audio.OpenAL.ALSource3f.Position, position.X, position.Y, 0.0f); - AL.Source(alSources[i], ALSourcei.Buffer, sound.AlBufferId); + OpenTK.Audio.OpenAL.AL.Source(alSources[i], OpenTK.Audio.OpenAL.ALSourcei.Buffer, sound.AlBufferId); - ALHelper.Efx.Filter(lowpassFilterId, EfxFilterf.LowpassGainHF, lowPassHfGain = Math.Min(lowPassGain, overrideLowPassGain)); + ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassHfGain = Math.Min(lowPassGain, overrideLowPassGain)); ALHelper.Efx.BindFilterToSource(alSources[i], lowpassFilterId); ALHelper.Check(); //AL.Source(alSources[i], ALSource3f.Position, position.X, position.Y, 0.0f); - AL.SourcePlay(alSources[i]); + OpenTK.Audio.OpenAL.AL.SourcePlay(alSources[i]); //sound.sourceIndex = i; @@ -261,10 +264,10 @@ namespace Subsurface.Sounds for (int i = 0; i < DefaultSourceCount; i++) { //find a source that's free to use (not playing or paused) - if (AL.GetSourceState(alSources[i]) != ALSourceState.Playing - && AL.GetSourceState(alSources[i])!= ALSourceState.Paused) continue; + if (OpenTK.Audio.OpenAL.AL.GetSourceState(alSources[i]) != OpenTK.Audio.OpenAL.ALSourceState.Playing + && OpenTK.Audio.OpenAL.AL.GetSourceState(alSources[i])!= OpenTK.Audio.OpenAL.ALSourceState.Paused) continue; - ALHelper.Efx.Filter(lowpassFilterId, EfxFilterf.LowpassGainHF, lowPassHfGain = value); + ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassHfGain = value); ALHelper.Efx.BindFilterToSource(alSources[i], lowpassFilterId); ALHelper.Check(); } @@ -293,10 +296,10 @@ namespace Subsurface.Sounds position/= 1000.0f; //System.Diagnostics.Debug.WriteLine("updatesoundpos: "+offset); - AL.Source(alSources[sourceIndex], ALSourcef.Gain, baseVolume); - AL.Source(alSources[sourceIndex], ALSource3f.Position, position.X, position.Y, 0.0f); + OpenTK.Audio.OpenAL.AL.Source(alSources[sourceIndex], OpenTK.Audio.OpenAL.ALSourcef.Gain, baseVolume); + OpenTK.Audio.OpenAL.AL.Source(alSources[sourceIndex], OpenTK.Audio.OpenAL.ALSource3f.Position, position.X, position.Y, 0.0f); - ALHelper.Efx.Filter(lowpassFilterId, EfxFilterf.LowpassGainHF, lowPassHfGain = Math.Min(lowPassGain, overrideLowPassGain)); + ALHelper.Efx.Filter(lowpassFilterId, OpenTK.Audio.OpenAL.EfxFilterf.LowpassGainHF, lowPassHfGain = Math.Min(lowPassGain, overrideLowPassGain)); ALHelper.Efx.BindFilterToSource(alSources[sourceIndex], lowpassFilterId); ALHelper.Check(); } @@ -328,7 +331,7 @@ namespace Subsurface.Sounds { if (alBuffers[i] == bufferId) { - AL.Source(alSources[i], ALSourcei.Buffer, 0); + OpenTK.Audio.OpenAL.AL.Source(alSources[i], OpenTK.Audio.OpenAL.ALSourcei.Buffer, 0); } } @@ -343,11 +346,11 @@ namespace Subsurface.Sounds for (int i = 0; i < DefaultSourceCount; i++) { - var state = AL.GetSourceState(alSources[i]); - if (state == ALSourceState.Playing || state == ALSourceState.Paused) + var state = OpenTK.Audio.OpenAL.AL.GetSourceState(alSources[i]); + if (state == OpenTK.Audio.OpenAL.ALSourceState.Playing || state == OpenTK.Audio.OpenAL.ALSourceState.Paused) Stop(i); - AL.DeleteSource(alSources[i]); + OpenTK.Audio.OpenAL.AL.DeleteSource(alSources[i]); ALHelper.Check(); } diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs index 02ae459b5..10b736eee 100644 --- a/Subsurface/Source/Utils/MathUtils.cs +++ b/Subsurface/Source/Utils/MathUtils.cs @@ -17,7 +17,9 @@ namespace Subsurface public static float Round(float value, float div) { - return (float)Math.Floor(value / div) * div; + return (value < 0.0f) ? + (float)Math.Ceiling(value / div) * div : + (float)Math.Floor(value / div) * div; } public static float VectorToAngle(Vector2 vector) @@ -25,6 +27,16 @@ namespace Subsurface return (float)Math.Atan2(vector.Y, vector.X); } + public static bool IsValid(float value) + { + return (!float.IsInfinity(value) && !float.IsNaN(value)); + } + + public static bool IsValid(Vector2 vector) + { + return (IsValid(vector.X) && IsValid(vector.Y)); + } + public static float CurveAngle(float from, float to, float step) { diff --git a/Subsurface/Source/Utils/SaveUtil.cs b/Subsurface/Source/Utils/SaveUtil.cs index b9111f1ad..5836779c1 100644 --- a/Subsurface/Source/Utils/SaveUtil.cs +++ b/Subsurface/Source/Utils/SaveUtil.cs @@ -55,11 +55,16 @@ namespace Subsurface { DebugConsole.ThrowError("Error saving gamesession", e); } - //Game1.GameSession.crewManager.Save(directory+"\\crew.xml"); + + try + { + CompressDirectory(tempPath, fileName+".save", null); + } - CompressDirectory(tempPath, fileName+".save", null); - - //Directory.Delete(tempPath, true); + catch (Exception e) + { + DebugConsole.ThrowError("Error compressing save file", e); + } } public static void LoadGame(string fileName) diff --git a/Subsurface/Source/Utils/TextureLoader.cs b/Subsurface/Source/Utils/TextureLoader.cs index a4853d54a..d224204e2 100644 --- a/Subsurface/Source/Utils/TextureLoader.cs +++ b/Subsurface/Source/Utils/TextureLoader.cs @@ -4,6 +4,7 @@ using System.IO; using Microsoft.Xna.Framework.Graphics; using Color = Microsoft.Xna.Framework.Color; using System; +using Microsoft.Xna.Framework; namespace Subsurface { @@ -44,8 +45,15 @@ namespace Subsurface { try { +#if WINDOWS using (Stream fileStream = File.OpenRead(path)) return FromStream(fileStream, preMultiplyAlpha); +#endif +#if LINUX + using (Stream fileStream = File.OpenRead(path)) + return Texture2D.FromFile(_graphicsDevice, fileStream);// .FromStream(fileStream, preMultiplyAlpha); +#endif + } catch (Exception e) { @@ -55,7 +63,8 @@ namespace Subsurface } - public Texture2D FromStream(Stream stream, bool preMultiplyAlpha = true) +#if WINDOWS + private Texture2D FromStream(Stream stream, bool preMultiplyAlpha = true) { Texture2D texture; @@ -114,6 +123,8 @@ namespace Subsurface return texture; } +#endif + private static readonly BlendState BlendColorBlendState; private static readonly BlendState BlendAlphaBlendState; diff --git a/Subsurface/Source/Utils/ToolBox.cs b/Subsurface/Source/Utils/ToolBox.cs index f64c02bdd..b37a172bc 100644 --- a/Subsurface/Source/Utils/ToolBox.cs +++ b/Subsurface/Source/Utils/ToolBox.cs @@ -36,9 +36,9 @@ namespace Subsurface { font = contentManager.Load(file); } - catch + catch (Exception e) { - DebugConsole.ThrowError("Loading font ''"+file+"'' failed"); + DebugConsole.ThrowError("Loading font ''"+file+"'' failed", e); } return font; diff --git a/Subsurface/StyleCop.Cache b/Subsurface/StyleCop.Cache index c2264d137..456c5e6fd 100644 --- a/Subsurface/StyleCop.Cache +++ b/Subsurface/StyleCop.Cache @@ -6336,9 +6336,6 @@ - - DEBUG;TRACE;WINDOWS - 2014.04.01 10:18:24.000 @@ -6464,4 +6461,30 @@ + + DEBUG;TRACE;WINDOWS + + + + 2014.04.01 10:18:24.000 + 2015.07.02 21:22:42.115 + 2015.08.21 17:49:13.627 + 2014.04.01 10:18:24.000 + 2014.04.01 10:18:24.000 + -1945363787 + 2014.04.01 10:18:24.000 + 0 + 2014.04.01 10:18:24.000 + 0 + 2014.04.01 10:18:24.000 + 0 + 2014.04.01 10:18:24.000 + 0 + 2014.04.01 10:18:24.000 + 0 + 2014.04.01 10:18:24.000 + 0 + + + \ No newline at end of file diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 58023277f..616b23517 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -38,7 +38,7 @@ 4 - x64 + x86 pdbonly true bin\Windows\Release\ @@ -76,7 +76,9 @@ + + @@ -301,6 +303,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -310,6 +315,15 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer PreserveNewest @@ -320,6 +334,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest Designer @@ -557,7 +574,7 @@ PreserveNewest - + PreserveNewest @@ -580,6 +597,7 @@ PreserveNewest + Designer PreserveNewest diff --git a/Subsurface/changelog.txt b/Subsurface/changelog.txt index 61b893645..28d44748c 100644 --- a/Subsurface/changelog.txt +++ b/Subsurface/changelog.txt @@ -1,4 +1,58 @@ +--------------------------------------------------------------------------------------------------------- +v0.1.3.2 +--------------------------------------------------------------------------------------------------------- + +Multiplayer: + - some major opimization to networked messages (less lag) + - option to disable UPnP port forwarding (which may have prevented some from hosting a server) + - a new round can't be started if a submarine hasn't been selected (which used to crash the game) + - maximum number of players can be changed + - fixed a bug in the net lobby screen that disabled the start button when the chat box was scrolled + to a specific position + - a window that displays some network statistics when hosting a server (can be activated by entering + "debugview" to the debug console) + +--------------------------------------------------------------------------------------------------------- +v0.1.3.1 +--------------------------------------------------------------------------------------------------------- + +Multiplayer: + - chat messages are sent reliably + +--------------------------------------------------------------------------------------------------------- +v0.1.3 +--------------------------------------------------------------------------------------------------------- + +Multiplayer: + - fixed master server connection errors in server list screen + - fixed a bug that caused other characters to get "stuck" to the railgun controller, causing them + to fly back to it as they try to move away + +Items: + - putting items inside other items works properly now (i.e. by pulling a spear to the same slot as + a harpoon, not the other way around) + - C4 blocks loaded inside a railgun shell won't explode inside the submarine when firing the railgun + - fixed another game-crashing railgun bug + - fixed a bug that caused characters to spawn with an incorrect number of items + +--------------------------------------------------------------------------------------------------------- +v0.1.2 +--------------------------------------------------------------------------------------------------------- + +Multiplayer: + - a "lobby screen" showing a list of servers that are currently running + - password protected servers + - traitor rounds end when the traitor dies/disconnects or if the submarine reaches the end of the level + +Items: + - fixed the crashing when firing the railgun or activating a detonator + +Other: + - optimized lightning and "line of sight" rendering + - an unfinished tutorial which can currently only be accessed by entering "tutorial" into the + debug console + --------------------------------------------------------------------------------------------------------- v0.1.1 --------------------------------------------------------------------------------------------------------- diff --git a/Subsurface/readme.txt b/Subsurface/readme.txt index 58e9c8186..d3d4f6d62 100644 --- a/Subsurface/readme.txt +++ b/Subsurface/readme.txt @@ -17,6 +17,31 @@ http://subsurface.gamepedia.com ------------------------------------------------------------------------ +Port forwarding: +You may try to forward ports on your router using UPnP (Universal Plug and +Play) port forwarding by selecting "Attempt UPnP port forwarding" in the +"Host Server" menu. + +However, UPnP isn't supported by all routers, so you may need to setup port +forwards manually. The exact steps for forwarding a port depend on your +router's model, but you may you may be able to find a port forwarding +guide for your particular router/application on portforward.com or by +practicing your google-fu skills. + +These are the values that you should use when forwarding a port to your +Subsurface server: + +Service/Application: subsurface +External Port: The port you have selected for your server (14242 by default) +Internal Port: The port you have selected for your server (14242 by default) +Protocol: UDP + + +------------------------------------------------------------------------ +------------------------------------------------------------------------ +Credits: +------------------------------------------------------------------------ + Programming, graphics, sounds, game design - Joonas Rikkonen ("Regalis") Graphics - James Bear ("Moonsaber99") diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 2c60509ce..f9c6f6d56 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ diff --git a/Subsurface_content/Subsurface_content/Subsurface_content.csproj.PSM.cachefile b/Subsurface_content/Subsurface_content/Subsurface_content.csproj.PSM.cachefile index 1c77f5a53..2a3436749 100644 --- a/Subsurface_content/Subsurface_content/Subsurface_content.csproj.PSM.cachefile +++ b/Subsurface_content/Subsurface_content/Subsurface_content.csproj.PSM.cachefile @@ -1,4 +1,6 @@ Content\SpriteFont1.xnb Content\SmallFont.xnb +Content\LargeFont.xnb Content\SpriteFont1.spritefont Content\SmallFont.spritefont +Content\LargeFont.spritefont diff --git a/Subsurface_content/Subsurface_content/Subsurface_content.csproj.Windows.cachefile b/Subsurface_content/Subsurface_content/Subsurface_content.csproj.Windows.cachefile new file mode 100644 index 000000000..2a3436749 --- /dev/null +++ b/Subsurface_content/Subsurface_content/Subsurface_content.csproj.Windows.cachefile @@ -0,0 +1,6 @@ +Content\SpriteFont1.xnb +Content\SmallFont.xnb +Content\LargeFont.xnb +Content\SpriteFont1.spritefont +Content\SmallFont.spritefont +Content\LargeFont.spritefont diff --git a/Subsurface_content/Subsurface_content/bin/Windows/Content/SpriteFont1.xnb b/Subsurface_content/Subsurface_content/bin/Windows/Content/SpriteFont1.xnb index 51c4abd74..37d6342fc 100644 Binary files a/Subsurface_content/Subsurface_content/bin/Windows/Content/SpriteFont1.xnb and b/Subsurface_content/Subsurface_content/bin/Windows/Content/SpriteFont1.xnb differ diff --git a/Subsurface_content/Subsurface_content/bin/Windows/IgnoreMe.dll b/Subsurface_content/Subsurface_content/bin/Windows/IgnoreMe.dll index 56f61cc36..5c634cfcf 100644 Binary files a/Subsurface_content/Subsurface_content/bin/Windows/IgnoreMe.dll and b/Subsurface_content/Subsurface_content/bin/Windows/IgnoreMe.dll differ diff --git a/Subsurface_content/Subsurface_content/obj/PSM/cachefile-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}-targetpath.txt b/Subsurface_content/Subsurface_content/obj/PSM/cachefile-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}-targetpath.txt index 1c77f5a53..2a3436749 100644 --- a/Subsurface_content/Subsurface_content/obj/PSM/cachefile-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}-targetpath.txt +++ b/Subsurface_content/Subsurface_content/obj/PSM/cachefile-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}-targetpath.txt @@ -1,4 +1,6 @@ Content\SpriteFont1.xnb Content\SmallFont.xnb +Content\LargeFont.xnb Content\SpriteFont1.spritefont Content\SmallFont.spritefont +Content\LargeFont.spritefont diff --git a/Subsurface_content/Subsurface_content/obj/Windows/ContentPipeline-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}.xml b/Subsurface_content/Subsurface_content/obj/Windows/ContentPipeline-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}.xml index f51a9df04..d4c649161 100644 --- a/Subsurface_content/Subsurface_content/obj/Windows/ContentPipeline-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}.xml +++ b/Subsurface_content/Subsurface_content/obj/Windows/ContentPipeline-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}.xml @@ -7,8 +7,26 @@ FontDescriptionImporter FontDescriptionProcessor None - C:\Users\Joonas\Desktop\SBMR_3011\Sbmr_content\Sbmr_content\bin\Windows\Content\SpriteFont1.xnb - + E:\Subsurface\Subsurface_content\Subsurface_content\bin\Windows\Content\SpriteFont1.xnb + + + + SmallFont.spritefont + SmallFont + FontDescriptionImporter + FontDescriptionProcessor + None + E:\Subsurface\Subsurface_content\Subsurface_content\bin\Windows\Content\SmallFont.xnb + + + + LargeFont.spritefont + LargeFont + FontDescriptionImporter + FontDescriptionProcessor + None + E:\Subsurface\Subsurface_content\Subsurface_content\bin\Windows\Content\LargeFont.xnb + true @@ -17,15 +35,15 @@ HiDef Windows false - C:\Users\Joonas\Desktop\SBMR_3011\Sbmr_content\Sbmr_contentContent\ - C:\Users\Joonas\Desktop\SBMR_3011\Sbmr_content\Sbmr_content\ - C:\Users\Joonas\Desktop\SBMR_3011\Sbmr_content\Sbmr_content\obj\Windows\ - C:\Users\Joonas\Desktop\SBMR_3011\Sbmr_content\Sbmr_content\bin\Windows\Content\ + E:\Subsurface\Subsurface_content\Subsurface_contentContent\ + E:\Subsurface\Subsurface_content\Subsurface_content\ + E:\Subsurface\Subsurface_content\Subsurface_content\obj\Windows\ + E:\Subsurface\Subsurface_content\Subsurface_content\bin\Windows\Content\ C:\Program Files (x86)\MSBuild\MonoGame\v3.0\MonoGameContentProcessors.dll - 2014-04-06T00:56:18+03:00 + 2015-02-12T06:10:24+02:00 C:\Program Files (x86)\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.Content.Pipeline.XImporter.dll diff --git a/Subsurface_content/Subsurface_content/obj/Windows/DesignTimeResolveAssemblyReferencesInput.cache b/Subsurface_content/Subsurface_content/obj/Windows/DesignTimeResolveAssemblyReferencesInput.cache index 8237fb523..c28b17377 100644 Binary files a/Subsurface_content/Subsurface_content/obj/Windows/DesignTimeResolveAssemblyReferencesInput.cache and b/Subsurface_content/Subsurface_content/obj/Windows/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/Subsurface_content/Subsurface_content/obj/Windows/IgnoreMe.dll b/Subsurface_content/Subsurface_content/obj/Windows/IgnoreMe.dll index 56f61cc36..5c634cfcf 100644 Binary files a/Subsurface_content/Subsurface_content/obj/Windows/IgnoreMe.dll and b/Subsurface_content/Subsurface_content/obj/Windows/IgnoreMe.dll differ diff --git a/Subsurface_content/Subsurface_content/obj/Windows/cachefile-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}-targetpath.txt b/Subsurface_content/Subsurface_content/obj/Windows/cachefile-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}-targetpath.txt index b1ac40206..2a3436749 100644 --- a/Subsurface_content/Subsurface_content/obj/Windows/cachefile-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}-targetpath.txt +++ b/Subsurface_content/Subsurface_content/obj/Windows/cachefile-{8C1D2051-F0F3-457B-AAAE-4E155FC7C75C}-targetpath.txt @@ -1 +1,6 @@ Content\SpriteFont1.xnb +Content\SmallFont.xnb +Content\LargeFont.xnb +Content\SpriteFont1.spritefont +Content\SmallFont.spritefont +Content\LargeFont.spritefont diff --git a/Subsurface_content/Subsurface_contentContent/LargeFont.spritefont b/Subsurface_content/Subsurface_contentContent/LargeFont.spritefont new file mode 100644 index 000000000..b3a30a69a --- /dev/null +++ b/Subsurface_content/Subsurface_contentContent/LargeFont.spritefont @@ -0,0 +1,42 @@ + + + + + + Verdana + + 16 + + 0 + + true + + + + _ + + + + + + ~ + + + + À + ə + + + + diff --git a/Subsurface_content/Subsurface_contentContent/Subsurface_contentContent.contentproj b/Subsurface_content/Subsurface_contentContent/Subsurface_contentContent.contentproj index 91d4cea64..14690175f 100644 --- a/Subsurface_content/Subsurface_contentContent/Subsurface_contentContent.contentproj +++ b/Subsurface_content/Subsurface_contentContent/Subsurface_contentContent.contentproj @@ -65,6 +65,15 @@ FontDescriptionProcessor + + + Designer + Always + LargeFont + FontDescriptionImporter + FontDescriptionProcessor + +