diff --git a/Subsurface/Content/Characters/Husk/husk.xml b/Subsurface/Content/Characters/Husk/husk.xml index 052271843..137bd0eeb 100644 --- a/Subsurface/Content/Characters/Husk/husk.xml +++ b/Subsurface/Content/Characters/Husk/husk.xml @@ -11,6 +11,7 @@ + diff --git a/Subsurface/Content/Items/Weapons/railgun.xml b/Subsurface/Content/Items/Weapons/railgun.xml index f77e5ead4..ad75a5009 100644 --- a/Subsurface/Content/Items/Weapons/railgun.xml +++ b/Subsurface/Content/Items/Weapons/railgun.xml @@ -110,7 +110,7 @@ - + diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index c32565245..1a7c16bac 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -915,7 +915,7 @@ namespace Barotrauma if (isDead) return; - if (!(AnimController is FishAnimController)) + if (needsAir) { bool protectedFromPressure = PressureProtection > 0.0f; @@ -1445,7 +1445,7 @@ namespace Barotrauma else { Character character = FindEntityByID(characterId) as Character; - if (character != null) SelectCharacter(character, false); + if (character != null && character.IsHumanoid) SelectCharacter(character, false); } return; case NetworkEventType.KillCharacter: diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs index 0e0ee524d..d16e443e1 100644 --- a/Subsurface/Source/DebugConsole.cs +++ b/Subsurface/Source/DebugConsole.cs @@ -382,16 +382,8 @@ namespace Barotrauma return; } if (Submarine.SaveCurrent(fileName +".sub")) NewMessage("map saved", Color.Green); + Submarine.Loaded.CheckForErrors(); - if (WayPoint.WayPointList.Find(wp => !wp.MoveWithLevel && wp.SpawnType == SpawnType.Path)==null) - { - DebugConsole.ThrowError("No waypoints found in the submarine. AI controlled crew members won't be able to navigate without waypoints."); - } - - if (WayPoint.WayPointList.Find(wp => wp.SpawnType == SpawnType.Cargo) == null) - { - DebugConsole.ThrowError("The submarine doesn't have a waypoint marked as ''Cargo'', which are used for determining where to place bought items."); - } break; case "loadmap": case "loadsub": diff --git a/Subsurface/Source/Events/Quests/MonsterQuest.cs b/Subsurface/Source/Events/Quests/MonsterQuest.cs index 13581fe82..6a7882541 100644 --- a/Subsurface/Source/Events/Quests/MonsterQuest.cs +++ b/Subsurface/Source/Events/Quests/MonsterQuest.cs @@ -27,7 +27,7 @@ namespace Barotrauma public override void Start(Level level) { - Vector2 position = level.GetRandomInterestingPosition(monster.Mass > 500.0f, true); + Vector2 position = level.GetRandomInterestingPosition(true, true); monster = Character.Create(monsterFile, position); monster.Enabled = false; diff --git a/Subsurface/Source/GUI/GUIScrollBar.cs b/Subsurface/Source/GUI/GUIScrollBar.cs index df635b1ca..b83047cbf 100644 --- a/Subsurface/Source/GUI/GUIScrollBar.cs +++ b/Subsurface/Source/GUI/GUIScrollBar.cs @@ -17,7 +17,7 @@ namespace Barotrauma private bool enabled; - public delegate bool OnMovedHandler(float barScroll); + public delegate bool OnMovedHandler(GUIScrollBar scrollBar, float barScroll); public OnMovedHandler OnMoved; public bool IsHorizontal @@ -174,7 +174,7 @@ namespace Barotrauma barScroll = (float)newY / ((float)frame.Rect.Height - (float)bar.Rect.Height); } - if (moveAmount != 0 && OnMoved != null) OnMoved(barScroll); + if (moveAmount != 0 && OnMoved != null) OnMoved(this, barScroll); bar.Rect = new Rectangle(newX + frame.Rect.X, newY + frame.Rect.Y, bar.Rect.Width, bar.Rect.Height); diff --git a/Subsurface/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs b/Subsurface/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs index 5caeb23fd..65fe392fb 100644 --- a/Subsurface/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs +++ b/Subsurface/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs @@ -17,7 +17,7 @@ namespace Barotrauma.Tutorials public override IEnumerable UpdateState() { - Submarine.Loaded.SetPosition(new Vector2(Submarine.Loaded.Position.X, 38500.0f)); + //Submarine.Loaded.SetPosition(new Vector2(Submarine.Loaded.Position.X, 38500.0f)); //spawn some fish next to the player GameMain.GameScreen.BackgroundCreatureManager.SpawnSprites(2, @@ -91,7 +91,7 @@ namespace Barotrauma.Tutorials { yield return CoroutineStatus.Running; } - + infoBox = CreateInfoFrame("The reactor is now fueled up. Try turning it on by increasing the fission rate."); while (reactor.FissionRate <= 0.0f) @@ -275,7 +275,7 @@ namespace Barotrauma.Tutorials infoBox = CreateInfoFrame("Steer the submarine downwards, heading further into the cavern."); - while (Submarine.Loaded.WorldPosition.Y > 31000.0f) + while (Submarine.Loaded.WorldPosition.Y > 39000.0f) { yield return CoroutineStatus.Running; } diff --git a/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialType.cs b/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialType.cs index 4914ddb00..4c1811280 100644 --- a/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialType.cs +++ b/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialType.cs @@ -42,7 +42,7 @@ namespace Barotrauma.Tutorials GameMain.GameSession = new GameSession(Submarine.Loaded, "", GameModePreset.list.Find(gm => gm.Name.ToLower() == "tutorial")); (GameMain.GameSession.gameMode as TutorialMode).tutorialType = this; - GameMain.GameSession.StartShift("tuto"); + GameMain.GameSession.StartShift("tutorial"); GameMain.GameSession.TaskManager.Tasks.Clear(); diff --git a/Subsurface/Source/GameSettings.cs b/Subsurface/Source/GameSettings.cs index a09070837..f15c828ac 100644 --- a/Subsurface/Source/GameSettings.cs +++ b/Subsurface/Source/GameSettings.cs @@ -248,7 +248,7 @@ namespace Barotrauma doc.Save(filePath); } - private bool ChangeSoundVolume(float barScroll) + private bool ChangeSoundVolume(GUIScrollBar scrollBar, float barScroll) { UnsavedSettings = true; SoundVolume = MathHelper.Clamp(barScroll, 0.0f, 1.0f); @@ -256,7 +256,7 @@ namespace Barotrauma return true; } - private bool ChangeMusicVolume(float barScroll) + private bool ChangeMusicVolume(GUIScrollBar scrollBar, float barScroll) { UnsavedSettings = true; MusicVolume = MathHelper.Clamp(barScroll, 0.0f, 1.0f); diff --git a/Subsurface/Source/Map/Levels/Level.cs b/Subsurface/Source/Map/Levels/Level.cs index 530003b63..70c495875 100644 --- a/Subsurface/Source/Map/Levels/Level.cs +++ b/Subsurface/Source/Map/Levels/Level.cs @@ -150,18 +150,21 @@ namespace Barotrauma float minWidth = Submarine.Loaded == null ? 3000.0f : Math.Max(Submarine.Borders.Width, Submarine.Borders.Height); - startPosition = new Vector2(minWidth * 2, borders.Height); - endPosition = new Vector2(borders.Width - minWidth * 2, borders.Height); + startPosition = new Vector2((int)minWidth * 2, Rand.Range((int)minWidth * 2, borders.Height - (int)minWidth * 2, false)); + endPosition = new Vector2(borders.Width - (int)minWidth * 2, Rand.Range((int)minWidth * 2, borders.Height - (int)minWidth * 2, false)); + List pathNodes = new List(); Rectangle pathBorders = borders;// new Rectangle((int)minWidth, (int)minWidth, borders.Width - (int)minWidth * 2, borders.Height - (int)minWidth); pathBorders.Inflate(-minWidth*2, -minWidth*2); - pathNodes.Add(startPosition); - //pathNodes.Add(new Vector2(minWidth * 3, Rand.Range(minWidth * 2, borders.Height - minWidth * 2, false))); - for (float x = startPosition.X; x < endPosition.X; x += Rand.Range(2000.0f, 10000.0f, false)) + pathNodes.Add(new Vector2(startPosition.X, borders.Height)); + pathNodes.Add(startPosition); + + + for (float x = startPosition.X; x < endPosition.X; x += Rand.Range(5000.0f, 10000.0f, false)) { pathNodes.Add(new Vector2(x, Rand.Range(pathBorders.Y, pathBorders.Bottom, false))); @@ -171,8 +174,8 @@ namespace Barotrauma //} } - //pathNodes.Add(new Vector2(borders.Width - minWidth * 3, borders.Height / 2)); pathNodes.Add(endPosition); + pathNodes.Add(new Vector2(endPosition.X, borders.Height)); int smallTunnelCount = 5; @@ -283,7 +286,8 @@ namespace Barotrauma // pathNodes.Reverse(); //} - List pathCells = GeneratePath(pathNodes, cells, pathBorders, minWidth, 0.3f, mirror, true); + List pathCells = GeneratePath(pathNodes, cells, + new Rectangle(pathBorders.X, pathBorders.Y, pathBorders.Width, borders.Height), minWidth, 0.3f, mirror, true); foreach (InterestingPosition positionOfInterest in positionsOfInterest) { @@ -291,8 +295,8 @@ namespace Barotrauma wayPoint.MoveWithLevel = true; } - startPosition = pathCells[0].Center; - endPosition = pathCells[pathCells.Count - 1].Center; + //startPosition = pathCells[0].Center; + //endPosition = pathCells[pathCells.Count - 1].Center; foreach (List tunnel in smallTunnels) { @@ -475,9 +479,7 @@ namespace Barotrauma pathCells.Add(currentCell); int currentTargetIndex = 1; - - wanderAmount = 0.0f; - + do { int edgeIndex = 0; @@ -617,30 +619,41 @@ namespace Barotrauma minDistance *= 0.5f; do { - var closeCells = GetCells(position, 2); + var closeCells = GetCells(position, 1); foreach (VoronoiCell cell in closeCells) { - if (!cell.edges.Any(e => Vector2.Distance(position, e.point1) < minDistance || Vector2.Distance(position, e.point2) < minDistance)) continue; + bool tooClose = false; + foreach (GraphEdge edge in cell.edges) + { + if (Math.Abs(position.X - edge.point1.X) < minDistance || + Math.Abs(position.Y - edge.point1.Y) < minDistance || + Math.Abs(position.X - edge.point2.X) < minDistance || + Math.Abs(position.Y - edge.point2.Y) < minDistance) + { + tooClose = true; + break; + } + } - if (!tooCloseCells.Contains(cell)) tooCloseCells.Add(cell); + if (tooClose && !tooCloseCells.Contains(cell)) tooCloseCells.Add(cell); } - //for (int x = -1; x <= 1; x++) - //{ - // for (int y = -1; y <= 1; y++) - // { - // if (x == 0 && y == 0) continue; - // Vector2 cornerPos = position + new Vector2(x * minDistance, y * minDistance); + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + if (x == 0 && y == 0) continue; + Vector2 cornerPos = position + new Vector2(x * minDistance, y * minDistance); - // int cellIndex = FindCellIndex(cornerPos); - // if (cellIndex == -1) continue; - // if (!tooCloseCells.Contains(cells[cellIndex])) - // { - // tooCloseCells.Add(cells[cellIndex]); - // } - // } - //} + int cellIndex = FindCellIndex(cornerPos); + if (cellIndex == -1) continue; + if (!tooCloseCells.Contains(cells[cellIndex])) + { + tooCloseCells.Add(cells[cellIndex]); + } + } + } position += Vector2.Normalize(emptyCells[targetCellIndex].Center - position) * step; @@ -664,7 +677,7 @@ namespace Barotrauma foreach (GraphEdge edge in cell.edges) { VoronoiCell adjacent = edge.AdjacentCell(cell); - if (!newCells.Contains(adjacent)) newCells.Add(adjacent); + if (adjacent!=null && !newCells.Contains(adjacent)) newCells.Add(adjacent); } } @@ -964,7 +977,7 @@ namespace Barotrauma int tries = 0; do { - Vector2 startPos = ConvertUnits.ToSimUnits(positionsOfInterest[Rand.Int(positionsOfInterest.Count, false)].Position); + Vector2 startPos = ConvertUnits.ToSimUnits(Level.Loaded.GetRandomInterestingPosition(true, false)); Vector2 endPos = startPos - ConvertUnits.ToSimUnits(Vector2.UnitY * Size.Y); @@ -989,20 +1002,21 @@ namespace Barotrauma return position; } - public Vector2 GetRandomInterestingPosition(bool requireSpace, bool useSyncedRand) + public Vector2 GetRandomInterestingPosition(bool useSyncedRand, bool? preferLarge) { if (!positionsOfInterest.Any()) return Size * 0.5f; - if (requireSpace) + if (preferLarge==null) { - var positionsWithSpace = positionsOfInterest.FindAll(p => p.IsLarge); - if (!positionsWithSpace.Any()) return Size * 0.5f; + return positionsOfInterest[Rand.Int(positionsOfInterest.Count, !useSyncedRand)].Position; - return positionsWithSpace[Rand.Int(positionsOfInterest.Count, !useSyncedRand)].Position; } else { - return positionsOfInterest[Rand.Int(positionsOfInterest.Count, !useSyncedRand)].Position; + var positionsWithSpace = positionsOfInterest.FindAll(p => (bool)preferLarge == p.IsLarge); + if (!positionsWithSpace.Any()) return Size * 0.5f; + + return positionsWithSpace[Rand.Int(positionsOfInterest.Count, !useSyncedRand)].Position; } } diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index d5ea1d62b..907764a7b 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -524,6 +524,34 @@ namespace Barotrauma return loaded.SaveAs(SavePath+System.IO.Path.DirectorySeparatorChar+fileName); } + public void CheckForErrors() + { + if (!Hull.hullList.Any()) + { + DebugConsole.ThrowError("No hulls found in the submarine. Hulls determine the ''borders'' of an individual room and are required for water and air distribution to work correctly."); + } + + foreach (Item item in Item.ItemList) + { + if (item.GetComponent() == null) continue; + + if (!item.linkedTo.Any()) + { + DebugConsole.ThrowError("The submarine contains vents which haven't been linked to an oxygen generator. Select a vent and click an oxygen generator while holding space to link them."); + } + } + + if (WayPoint.WayPointList.Find(wp => !wp.MoveWithLevel && wp.SpawnType == SpawnType.Path) == null) + { + DebugConsole.ThrowError("No waypoints found in the submarine. AI controlled crew members won't be able to navigate without waypoints."); + } + + if (WayPoint.WayPointList.Find(wp => wp.SpawnType == SpawnType.Cargo) == null) + { + DebugConsole.ThrowError("The submarine doesn't have a waypoint marked as ''Cargo'', which are used for determining where to place bought items."); + } + } + public static void Preload() { @@ -669,7 +697,6 @@ namespace Barotrauma { DebugConsole.ThrowError("Could not find the method ''Load'' in " + t + ".", e); } - } subBody = new SubmarineBody(this); diff --git a/Subsurface/Source/Map/SubmarineBody.cs b/Subsurface/Source/Map/SubmarineBody.cs index 3b6667486..381f08f59 100644 --- a/Subsurface/Source/Map/SubmarineBody.cs +++ b/Subsurface/Source/Map/SubmarineBody.cs @@ -87,57 +87,67 @@ namespace Barotrauma { this.submarine = sub; - - List convexHull = GenerateConvexHull(); - HullVertices = convexHull; - - for (int i = 0; i < convexHull.Count; i++) + if (!Hull.hullList.Any()) { - convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]); + + body = BodyFactory.CreateRectangle(GameMain.World, 1.0f, 1.0f, 1.0f); + DebugConsole.ThrowError("WARNING: no hulls found, generating a physics body for the submarine failed."); } - - convexHull.Reverse(); - - //get farseer 'vertices' from vectors - Vertices shapevertices = new Vertices(convexHull); - - AABB hullAABB = shapevertices.GetAABB(); - - Borders = new Rectangle( - (int)ConvertUnits.ToDisplayUnits(hullAABB.LowerBound.X), - (int)ConvertUnits.ToDisplayUnits(hullAABB.UpperBound.Y), - (int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.X * 2.0f), - (int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.Y * 2.0f)); - - //var triangulatedVertices = Triangulate.ConvexPartition(shapevertices, TriangulationAlgorithm.Bayazit); - - body = BodyFactory.CreateBody(GameMain.World, this); - - foreach (Hull hull in Hull.hullList) + else { - Rectangle rect = hull.Rect; - foreach (Structure wall in Structure.WallList) + List convexHull = GenerateConvexHull(); + HullVertices = convexHull; + + for (int i = 0; i < convexHull.Count; i++) { - if (!Submarine.RectsOverlap(wall.Rect, hull.Rect)) continue; - - Rectangle wallRect = wall.IsHorizontal ? - new Rectangle(hull.Rect.X, wall.Rect.Y, hull.Rect.Width, wall.Rect.Height) : - new Rectangle(wall.Rect.X, hull.Rect.Y, wall.Rect.Width, hull.Rect.Height); - - rect = Rectangle.Union( - new Rectangle(wallRect.X, wallRect.Y-wallRect.Height, wallRect.Width, wallRect.Height), - new Rectangle(rect.X, rect.Y - rect.Height, rect.Width, rect.Height)); - rect.Y = rect.Y + rect.Height; + convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]); } - FixtureFactory.AttachRectangle( - ConvertUnits.ToSimUnits(rect.Width), - ConvertUnits.ToSimUnits(rect.Height), - 5.0f, - ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width/2, rect.Y - rect.Height/2)), - body, this); + convexHull.Reverse(); + + //get farseer 'vertices' from vectors + Vertices shapevertices = new Vertices(convexHull); + + AABB hullAABB = shapevertices.GetAABB(); + + Borders = new Rectangle( + (int)ConvertUnits.ToDisplayUnits(hullAABB.LowerBound.X), + (int)ConvertUnits.ToDisplayUnits(hullAABB.UpperBound.Y), + (int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.X * 2.0f), + (int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.Y * 2.0f)); + + //var triangulatedVertices = Triangulate.ConvexPartition(shapevertices, TriangulationAlgorithm.Bayazit); + + body = BodyFactory.CreateBody(GameMain.World, this); + + foreach (Hull hull in Hull.hullList) + { + Rectangle rect = hull.Rect; + foreach (Structure wall in Structure.WallList) + { + if (!Submarine.RectsOverlap(wall.Rect, hull.Rect)) continue; + + Rectangle wallRect = wall.IsHorizontal ? + new Rectangle(hull.Rect.X, wall.Rect.Y, hull.Rect.Width, wall.Rect.Height) : + new Rectangle(wall.Rect.X, hull.Rect.Y, wall.Rect.Width, hull.Rect.Height); + + rect = Rectangle.Union( + new Rectangle(wallRect.X, wallRect.Y - wallRect.Height, wallRect.Width, wallRect.Height), + new Rectangle(rect.X, rect.Y - rect.Height, rect.Width, rect.Height)); + rect.Y = rect.Y + rect.Height; + } + + FixtureFactory.AttachRectangle( + ConvertUnits.ToSimUnits(rect.Width), + ConvertUnits.ToSimUnits(rect.Height), + 5.0f, + ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)), + body, this); + } } + + body.BodyType = BodyType.Dynamic; body.CollisionCategories = Physics.CollisionMisc | Physics.CollisionWall; body.CollidesWith = Physics.CollisionLevel | Physics.CollisionCharacter; @@ -275,7 +285,7 @@ namespace Barotrauma volume += hull.FullVolume; } - float waterPercentage = waterVolume / volume; + float waterPercentage = volume==0.0f ? 0.0f : waterVolume / volume; float neutralPercentage = 0.07f; diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index abfc37b62..ac5709976 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -15,6 +15,8 @@ namespace Barotrauma.Networking private ReliableChannel reliableChannel; + private GUIButton endRoundButton; + private bool connected; private int myID; @@ -28,8 +30,17 @@ namespace Barotrauma.Networking get { return myID; } } + public List OtherClients + { + get { return otherClients; } + } + public GameClient(string newName) { + endRoundButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 170, 20, 150, 25), "End round", Alignment.TopLeft, GUI.Style, inGameHUD); + endRoundButton.OnClicked = EndRoundClicked; + endRoundButton.Visible = false; + GameMain.DebugDraw = false; Hull.EditFire = false; Hull.EditWater = false; @@ -230,7 +241,6 @@ namespace Barotrauma.Networking new GUIMessageBox("Connection timed out", "You were disconnected for too long and your Character was deleted. Please wait for another round to start."); } - GameMain.NetLobbyScreen.ClearPlayers(); //add the names of other connected clients to the lobby screen @@ -590,6 +600,8 @@ namespace Barotrauma.Networking gameStarted = true; + endRoundButton.Visible = Voting.AllowEndVoting; + GameMain.GameScreen.Select(); AddChatMessage("Press TAB to chat", ChatMessageType.Server); @@ -659,7 +671,7 @@ namespace Barotrauma.Networking public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) { base.Draw(spriteBatch); - + if (!GameMain.DebugDraw) return; int width = 200, height = 300; @@ -696,13 +708,16 @@ namespace Barotrauma.Networking { case VoteType.Sub: msg.Write(((Submarine)userData).Name); - client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); break; case VoteType.Mode: msg.Write(((GameModePreset)userData).Name); - client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); + break; + case VoteType.EndRound: + msg.Write((bool)userData); break; } + + client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } public bool SpectateClicked(GUIButton button, object userData) @@ -717,6 +732,23 @@ namespace Barotrauma.Networking return false; } + public bool EndRoundClicked(GUIButton button, object userData) + { + if (!gameStarted) return false; + + if (!Voting.AllowEndVoting) + { + button.Visible = false; + return false; + } + + Vote(VoteType.EndRound, true); + + return false; + } + + + public void SendCharacterData() { if (characterInfo == null) return; @@ -794,7 +826,8 @@ namespace Barotrauma.Networking if (client.ServerConnection == null) return; - type = (gameStarted && myCharacter != null && myCharacter.IsDead) ? ChatMessageType.Dead : ChatMessageType.Default; + type = (Screen.Selected == GameMain.GameScreen && + (myCharacter == null || myCharacter.IsDead)) ? ChatMessageType.Dead : ChatMessageType.Default; ReliableMessage msg = reliableChannel.CreateMessage(); msg.InnerMessage.Write((byte)PacketTypes.Chatmessage); diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index a1ddbcf48..6bce006b0 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -473,6 +473,12 @@ namespace Barotrauma.Networking break; case (byte)PacketTypes.Vote: Voting.RegisterVote(inc, ConnectedClients); + + if (Voting.AllowEndVoting && + ((float)EndVoteCount / (float)EndVoteMax) >= EndVoteRequiredRatio) + { + EndButtonHit(null,null); + } break; case (byte)PacketTypes.RequestNetLobbyUpdate: UpdateNetLobby(null, null); @@ -860,9 +866,11 @@ namespace Barotrauma.Networking private bool EndButtonHit(GUIButton button, object obj) { + if (!gameStarted) return false; + string endMessage = "The round has ended." + '\n'; - if (TraitorManager!=null) + if (TraitorManager != null) { endMessage += TraitorManager.GetEndMessage(); } @@ -1092,7 +1100,7 @@ namespace Barotrauma.Networking base.Draw(spriteBatch); if (settingsFrame != null) settingsFrame.Draw(spriteBatch); - + if (!ShowNetStats) return; int width = 200, height = 300; @@ -1465,14 +1473,22 @@ namespace Barotrauma.Networking jobPreferences = new List(JobPrefab.List.GetRange(0,3)); } - public object GetVote(VoteType voteType) + public T GetVote(VoteType voteType) { - return votes[(int)voteType]; + return (votes[(int)voteType] is T) ? (T)votes[(int)voteType] : default(T); } public void SetVote(VoteType voteType, object value) { votes[(int)voteType] = value; } + + public void ResetVotes() + { + for (int i = 0; i { endRoundAtLevelEnd = GUITickBox.Selected; return true; }; + + var endVoteBox = new GUITickBox(new Rectangle(0, 90, 20, 20), "End round by voting", Alignment.Left, innerFrame); + endVoteBox.Selected = Voting.AllowEndVoting; + endVoteBox.OnSelected = (GUITickBox) => + { + Voting.AllowEndVoting = !Voting.AllowEndVoting; + GameMain.Server.UpdateVoteStatus(); + return true; + }; + + var votesRequiredText = new GUITextBlock(new Rectangle(20, 110, 20, 20), "Votes required: 50 %", GUI.Style, innerFrame, GUI.SmallFont); + + var votesRequiredSlider = new GUIScrollBar(new Rectangle(150,115, 100, 10), GUI.Style, 0.1f, innerFrame); + votesRequiredSlider.UserData = votesRequiredText; + votesRequiredSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) => + { + GUITextBlock voteText = scrollBar.UserData as GUITextBlock; + + scrollBar.BarScroll = MathUtils.Round(barScroll, 0.2f); + EndVoteRequiredRatio = barScroll/2.0f + 0.5f; + voteText.Text = "Votes required: " + (int)MathUtils.Round(EndVoteRequiredRatio * 100.0f, 10.0f) + " %"; + return true; + }; - new GUITextBlock(new Rectangle(0, 95, 100, 20), "Submarine selection:", GUI.Style, innerFrame); - var selectionFrame = new GUIFrame(new Rectangle(0, 120, 300, 20), null, innerFrame); + new GUITextBlock(new Rectangle(0, 95+50, 100, 20), "Submarine selection:", GUI.Style, innerFrame); + var selectionFrame = new GUIFrame(new Rectangle(0, 120 + 50, 300, 20), null, innerFrame); for (int i = 0; i<3; i++) { var selectionTick = new GUITickBox(new Rectangle(i * 100, 0, 20, 20), ((SelectionMode)i).ToString(), Alignment.Left, selectionFrame); @@ -110,9 +135,9 @@ namespace Barotrauma.Networking selectionTick.OnSelected = SwitchSubSelection; selectionTick.UserData = (SelectionMode)i; } - - new GUITextBlock(new Rectangle(0, 145, 100, 20), "Mode selection:", GUI.Style, innerFrame); - selectionFrame = new GUIFrame(new Rectangle(0, 170, 300, 20), null, innerFrame); + + new GUITextBlock(new Rectangle(0, 145 + 50, 100, 20), "Mode selection:", GUI.Style, innerFrame); + selectionFrame = new GUIFrame(new Rectangle(0, 170 + 50, 300, 20), null, innerFrame); for (int i = 0; i<3; i++) { var selectionTick = new GUITickBox(new Rectangle(i*100, 0, 20, 20), ((SelectionMode)i).ToString(), Alignment.Left, selectionFrame); @@ -120,8 +145,8 @@ namespace Barotrauma.Networking selectionTick.OnSelected = SwitchModeSelection; selectionTick.UserData = (SelectionMode)i; } - - var allowSpecBox = new GUITickBox(new Rectangle(0, 210, 20, 20), "Allow spectating", Alignment.Left, innerFrame); + + var allowSpecBox = new GUITickBox(new Rectangle(0, 210 + 50, 20, 20), "Allow spectating", Alignment.Left, innerFrame); allowSpecBox.Selected = true; allowSpecBox.OnSelected = ToggleAllowSpectating; diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index fb47c8bd2..767a9eaaa 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -47,7 +47,7 @@ namespace Barotrauma.Networking class NetworkMember { - protected static Color[] messageColor = { Color.White, Color.Red, Color.LightBlue, Color.LightGreen }; + protected static Color[] messageColor = { Color.White, Color.Red, new Color(63,72,204), Color.LightGreen }; protected NetPeer netPeer; @@ -60,6 +60,10 @@ namespace Barotrauma.Networking protected GUIListBox chatBox; protected GUITextBox chatMsgBox; + + public int EndVoteCount, EndVoteMax; + //private GUITextBlock endVoteText; + public int Port; protected bool gameStarted; @@ -122,7 +126,6 @@ namespace Barotrauma.Networking chatMsgBox.Padding = Vector4.Zero; chatMsgBox.OnEnterPressed = EnterChatMessage; - Voting = new Voting(); } @@ -247,6 +250,12 @@ namespace Barotrauma.Networking GameMain.GameSession.CrewManager.Draw(spriteBatch); inGameHUD.Draw(spriteBatch); + + if (EndVoteCount > 0) + { + GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 150.0f, 40), "Votes: " + EndVoteCount + "/" + EndVoteMax, Color.White); + } + } public virtual bool SelectCrewCharacter(GUIComponent component, object obj) diff --git a/Subsurface/Source/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs index 44f863ada..f5d9285ff 100644 --- a/Subsurface/Source/Screens/EditMapScreen.cs +++ b/Subsurface/Source/Screens/EditMapScreen.cs @@ -292,6 +292,7 @@ namespace Barotrauma } Submarine.SaveCurrent(nameBox.Text + ".sub"); + Submarine.Loaded.CheckForErrors(); GUI.AddMessage("Submarine saved to " + Submarine.Loaded.FilePath, Color.Green, 3.0f); diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index 8607b25df..133383100 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -355,6 +355,8 @@ namespace Barotrauma playYourself.UserData = "playyourself"; } + GameMain.Server.Voting.ResetVotes(GameMain.Server.ConnectedClients); + if (GameMain.Server.RandomizeSeed) LevelSeed = ToolBox.RandomSeed(8); if (GameMain.Server.SubSelectionMode == SelectionMode.Random) subList.Select(Rand.Range(0,subList.CountChildren)); if (GameMain.Server.ModeSelectionMode == SelectionMode.Random) modeList.Select(Rand.Range(0, modeList.CountChildren)); @@ -368,6 +370,8 @@ namespace Barotrauma spectateButton.UserData = "spectateButton"; } + GameMain.Client.Voting.ResetVotes(GameMain.Client.OtherClients); + UpdatePlayerFrame(GameMain.Client.CharacterInfo); } diff --git a/Subsurface/Source/Screens/NetLobbyVoting.cs b/Subsurface/Source/Screens/NetLobbyVoting.cs index 6f6bee116..c4b5a53f6 100644 --- a/Subsurface/Source/Screens/NetLobbyVoting.cs +++ b/Subsurface/Source/Screens/NetLobbyVoting.cs @@ -12,6 +12,8 @@ namespace Barotrauma { private bool allowSubVoting, allowModeVoting; + public bool AllowEndVoting = true; + public bool AllowSubVoting { get { return allowSubVoting; } @@ -83,7 +85,12 @@ namespace Barotrauma UpdateVoteTexts(connectedClients, voteType); break; case VoteType.EndRound: + if (sender.Character == null) return; sender.SetVote(voteType, inc.ReadBoolean()); + + GameMain.NetworkMember.EndVoteCount = connectedClients.Count(c => c.Character != null && c.GetVote(VoteType.EndRound)); + GameMain.NetworkMember.EndVoteMax = connectedClients.Count(c => c.Character != null); + break; } @@ -107,7 +114,7 @@ namespace Barotrauma SetVoteText(listBox, votable.First, votable.Second); } } - + private void SetVoteText(GUIListBox listBox, object userData, int votes) { if (userData == null) return; @@ -124,14 +131,14 @@ namespace Barotrauma voteText.Text = votes.ToString(); } } - + private List> GetVoteList(VoteType voteType, List voters) { List> voteList = new List>(); foreach (Client voter in voters) { - object vote = voter.GetVote(voteType); + object vote = voter.GetVote(voteType); if (vote == null) continue; var existingVotable = voteList.Find(v => v.First == vote); @@ -167,6 +174,20 @@ namespace Barotrauma return selected; } + + public void ResetVotes(List connectedClients) + { + foreach (Client client in connectedClients) + { + client.ResetVotes(); + } + + GameMain.NetworkMember.EndVoteCount = 0; + GameMain.NetworkMember.EndVoteMax = 0; + + UpdateVoteTexts(connectedClients, VoteType.Mode); + UpdateVoteTexts(connectedClients, VoteType.Sub); + } public void WriteData(NetOutgoingMessage msg, List voters) { @@ -198,17 +219,22 @@ namespace Barotrauma } } - + msg.Write(AllowEndVoting); + if (AllowEndVoting) + { + msg.Write((byte)voters.Count); + msg.Write((byte)voters.Count(v => v.GetVote(VoteType.EndRound))); + } } public void ReadData(NetIncomingMessage msg) { - AllowSubVoting = msg.ReadBoolean(); + AllowSubVoting = msg.ReadBoolean(); if (allowSubVoting) { int votableCount = msg.ReadByte(); - for (int i = 0; i