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 @@ + + + + = 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 + ". "; + endMessage += "The task was unsuccessful - the has submarine reached its destination."; + 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 + ", 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 (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/Items/CharacterInventory.cs b/Subsurface/Source/Items/CharacterInventory.cs index cab256dc1..25db5d641 100644 --- a/Subsurface/Source/Items/CharacterInventory.cs +++ b/Subsurface/Source/Items/CharacterInventory.cs @@ -144,11 +144,11 @@ namespace Subsurface //PutItem(item, i, false, false); combined = true; } - else if (items[i].Combine(item)) - { - //PutItem(items[i], i, false, false); - combined = true; - } + //else if (items[i].Combine(item)) + //{ + // //PutItem(items[i], i, false, false); + // combined = true; + //} if (!combined) return false; diff --git a/Subsurface/Source/Items/Components/Projectile.cs b/Subsurface/Source/Items/Components/Projectile.cs index 0e44f3468..122574f22 100644 --- a/Subsurface/Source/Items/Components/Projectile.cs +++ b/Subsurface/Source/Items/Components/Projectile.cs @@ -179,7 +179,7 @@ namespace Subsurface.Items.Components foreach (Item contained in item.ContainedItems) { contained.Condition = 0.0f; - if (contained.body!=null) + if (contained.body != null) { contained.body.SetTransform(item.SimPosition, contained.body.Rotation); } diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index 608b7fc8d..a6b4e95be 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -178,7 +178,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); } } diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 42d4cf342..57a8dbd23 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; } } @@ -85,6 +84,7 @@ namespace Subsurface.Networking 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); diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index d856f7694..a1d961eb4 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -22,17 +22,23 @@ 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="") { 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; @@ -62,7 +68,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 +88,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 +109,7 @@ namespace Subsurface.Networking refreshMasterTimer = DateTime.Now + refreshMasterInterval; } - private void RefreshMaster() + private IEnumerable RefreshMaster() { var client = new RestClient(NetworkMember.MasterServerUrl); @@ -112,17 +123,49 @@ 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(); - System.Diagnostics.Debug.WriteLine("took "+sw.ElapsedMilliseconds+" ms"); - - if (response.StatusCode != System.Net.HttpStatusCode.OK) + DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10); + while (!masterServerResponded) { - DebugConsole.ThrowError("Error while connecting to master server (" +response.StatusCode+": "+response.StatusDescription+")"); + 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 + ")"); + registeredToMaster = false; + return; + } } public override void Update(float deltaTime) @@ -159,7 +202,7 @@ namespace Subsurface.Networking if (registeredToMaster && refreshMasterTimer < DateTime.Now) { - RefreshMaster(); + CoroutineManager.StartCoroutine(RefreshMaster()); refreshMasterTimer = DateTime.Now + refreshMasterInterval; } @@ -204,9 +247,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(); @@ -218,7 +262,12 @@ namespace Subsurface.Networking 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 + ")"); break; diff --git a/Subsurface/Source/Screens/MainMenu.cs b/Subsurface/Source/Screens/MainMenu.cs index c9f9ae9d5..781fcfea7 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; + private GUITickBox isPublicBox; 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,21 @@ 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]); + serverNameBox = new GUITextBox(new Rectangle(0, 60, 200, 30), null, null, Alignment.CenterX, Alignment.CenterX, 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]); + portBox = new GUITextBox(new Rectangle(0, 130, 200, 30), null, null, Alignment.CenterX, Alignment.CenterX, GUI.style, menuTabs[(int)Tabs.HostServer]); portBox.Text = NetworkMember.DefaultPort.ToString(); portBox.ToolTip = "Server port"; + isPublicBox = new GUITickBox(new Rectangle(portBox.Rect.X - menuTabs[(int)Tabs.HostServer].Rect.X, 200, 20, 20), "Public server", Alignment.TopLeft, menuTabs[(int)Tabs.HostServer]); + + new GUITextBlock(new Rectangle(0, 240, 0, 30), "Password (optional):", GUI.style, Alignment.CenterX, Alignment.CenterX, menuTabs[(int)Tabs.HostServer]); + passwordBox = new GUITextBox(new Rectangle(0, 270, 200, 30), null, null, Alignment.CenterX, Alignment.CenterX, GUI.style, menuTabs[(int)Tabs.HostServer]); + GUIButton hostButton = new GUIButton(new Rectangle(0, 0, 200, 30), "Start", Alignment.BottomCenter, GUI.style, menuTabs[(int)Tabs.HostServer]); hostButton.OnClicked = HostServerClicked; @@ -177,7 +181,7 @@ namespace Subsurface return false; } - Game1.NetworkMember = new GameServer(name, port); + Game1.NetworkMember = new GameServer(name, port, isPublicBox.Selected, passwordBox.Text); Game1.NetLobbyScreen.IsServer = true; Game1.NetLobbyScreen.Select(); @@ -194,7 +198,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 +380,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/ServerListScreen.cs b/Subsurface/Source/Screens/ServerListScreen.cs index a68e096ad..6534975bd 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,56 @@ 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; + + + refreshDisableTimer = DateTime.Now; } public override void Select() { base.Select(); - UpdateServerList(); + + //RefreshServers(null, null); + //UpdateServerList(); } private bool SelectServer(object obj) @@ -75,16 +106,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 +150,7 @@ namespace Subsurface if (masterServerData.Substring(0,5).ToLower()=="error") { DebugConsole.ThrowError("Error while connecting to master server ("+masterServerData+")!"); + return; } @@ -112,23 +167,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 +202,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 +220,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 +276,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.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 +330,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/Subsurface.csproj b/Subsurface/Subsurface.csproj index 58023277f..ff3e2615a 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -38,7 +38,7 @@ 4 - x64 + x86 pdbonly true bin\Windows\Release\ diff --git a/Subsurface/changelog.txt b/Subsurface/changelog.txt index 61b893645..49db66232 100644 --- a/Subsurface/changelog.txt +++ b/Subsurface/changelog.txt @@ -1,3 +1,19 @@ +--------------------------------------------------------------------------------------------------------- +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_Solution.v12.suo b/Subsurface_Solution.v12.suo index 2c60509ce..fd62b5402 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ 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 + + + + _ + + + + + + ~ + + + + À + ə + + + +