diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 48b0a5c18..c9d2e5a0b 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -104,7 +104,8 @@ - + + @@ -905,6 +906,21 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -932,6 +948,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Subsurface/Content/Map/dustparticles.png b/Subsurface/Content/Map/dustparticles.png index a68587406..0f8efffb1 100644 Binary files a/Subsurface/Content/Map/dustparticles.png and b/Subsurface/Content/Map/dustparticles.png differ diff --git a/Subsurface/Content/Sounds/Damage/creak1.ogg b/Subsurface/Content/Sounds/Damage/creak1.ogg new file mode 100644 index 000000000..1b407a531 Binary files /dev/null and b/Subsurface/Content/Sounds/Damage/creak1.ogg differ diff --git a/Subsurface/Content/Sounds/Damage/creak2.ogg b/Subsurface/Content/Sounds/Damage/creak2.ogg new file mode 100644 index 000000000..519077568 Binary files /dev/null and b/Subsurface/Content/Sounds/Damage/creak2.ogg differ diff --git a/Subsurface/Content/Sounds/Damage/creak3.ogg b/Subsurface/Content/Sounds/Damage/creak3.ogg new file mode 100644 index 000000000..4ffbc42e1 Binary files /dev/null and b/Subsurface/Content/Sounds/Damage/creak3.ogg differ diff --git a/Subsurface/Content/Sounds/Damage/creak4.ogg b/Subsurface/Content/Sounds/Damage/creak4.ogg new file mode 100644 index 000000000..22df1ea74 Binary files /dev/null and b/Subsurface/Content/Sounds/Damage/creak4.ogg differ diff --git a/Subsurface/Content/Sounds/Damage/creak5.ogg b/Subsurface/Content/Sounds/Damage/creak5.ogg new file mode 100644 index 000000000..5a5a55d1d Binary files /dev/null and b/Subsurface/Content/Sounds/Damage/creak5.ogg differ diff --git a/Subsurface/Content/Sounds/Music/amb_JD_drone_clattering_machine.ogg b/Subsurface/Content/Sounds/Music/amb_JD_drone_clattering_machine.ogg new file mode 100644 index 000000000..799bb38c4 Binary files /dev/null and b/Subsurface/Content/Sounds/Music/amb_JD_drone_clattering_machine.ogg differ diff --git a/Subsurface/Content/Sounds/sounds.xml b/Subsurface/Content/Sounds/sounds.xml index 95075bb76..4c6afb20b 100644 --- a/Subsurface/Content/Sounds/sounds.xml +++ b/Subsurface/Content/Sounds/sounds.xml @@ -28,7 +28,11 @@ - + + + + + @@ -36,4 +40,5 @@ + \ No newline at end of file diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 3040be6e6..fe7777f30 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -379,12 +379,15 @@ namespace Barotrauma if (Info.PickedItemIDs.Any()) { - foreach (ushort id in Info.PickedItemIDs) + for (ushort i = 0; i < Info.PickedItemIDs.Count; i++ ) { - Item item = FindEntityByID(id) as Item; + if (i == 0) continue; + + Item item = FindEntityByID(Info.PickedItemIDs[i]) as Item; if (item == null) continue; - item.Pick(this); + item.Pick(this, true, true, true); + inventory.TryPutItem(item, i, false); } } diff --git a/Subsurface/Source/Characters/CharacterInfo.cs b/Subsurface/Source/Characters/CharacterInfo.cs index edbd7df7e..1ee00a41e 100644 --- a/Subsurface/Source/Characters/CharacterInfo.cs +++ b/Subsurface/Source/Characters/CharacterInfo.cs @@ -1,4 +1,5 @@ using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Xml.Linq; @@ -186,25 +187,27 @@ namespace Barotrauma { GUIImage image = new GUIImage(new Rectangle(0,0,30,30), HeadSprite, Alignment.TopLeft, frame); + SpriteFont font = frame.Rect.Width<280 ? GUI.SmallFont : GUI.Font; + int x = 0, y = 0; - new GUITextBlock(new Rectangle(x+80, y, 200, 20), Name, GUI.Style, frame); + new GUITextBlock(new Rectangle(x+60, y, 200, 20), Name, GUI.Style, frame, font); y += 20; if (Job!=null) { - new GUITextBlock(new Rectangle(x+80, y, 200, 20), Job.Name, GUI.Style, frame); + new GUITextBlock(new Rectangle(x + 60, y, 200, 20), Job.Name, GUI.Style, frame, font); y += 30; var skills = Job.Skills; skills.Sort((s1, s2) => -s1.Level.CompareTo(s2.Level)); - new GUITextBlock(new Rectangle(x, y, 200, 20), "Skills:", GUI.Style, frame); + new GUITextBlock(new Rectangle(x, y, 200, 20), "Skills:", GUI.Style, frame, font); y += 20; foreach (Skill skill in skills) { Color textColor = Color.White * (0.5f + skill.Level/200.0f); - new GUITextBlock(new Rectangle(x+20, y, 200, 20), skill.Name, Color.Transparent, textColor, Alignment.Left, GUI.Style, frame); - new GUITextBlock(new Rectangle(x + 20, y, 200, 20), skill.Level.ToString(), Color.Transparent, textColor, Alignment.Right, GUI.Style, frame); + new GUITextBlock(new Rectangle(x, y, 200, 20), skill.Name, Color.Transparent, textColor, Alignment.Left, GUI.Style, frame).Font = font; + new GUITextBlock(new Rectangle(x, y, 200, 20), skill.Level.ToString(), Color.Transparent, textColor, Alignment.Right, GUI.Style, frame).Font = font; y += 20; } } @@ -218,8 +221,7 @@ namespace Barotrauma pickedItems.Clear(); foreach (Item item in Character.Inventory.items) { - if (item == null) continue; - pickedItems.Add(item.ID); + pickedItems.Add(item == null ? (ushort)0 : item.ID); } } diff --git a/Subsurface/Source/Events/Quests/SalvageQuest.cs b/Subsurface/Source/Events/Quests/SalvageQuest.cs index 82f01a3ed..d7a3ae9ba 100644 --- a/Subsurface/Source/Events/Quests/SalvageQuest.cs +++ b/Subsurface/Source/Events/Quests/SalvageQuest.cs @@ -37,10 +37,35 @@ namespace Barotrauma public override void Start(Level level) { - Vector2 position = level.PositionsOfInterest[Rand.Int(level.PositionsOfInterest.Count, false)]; + Vector2 position = Vector2.Zero; + + int tries = 0; + do + { + Vector2 tryPos = level.PositionsOfInterest[Rand.Int(level.PositionsOfInterest.Count, false)]; + + if (Submarine.PickBody( + tryPos + level.Position, + tryPos + level.Position - Vector2.UnitY*level.Size.Y, + null, Physics.CollisionLevel) != null) + { + position = tryPos; + break; + } + + tries++; + + if (tries==10) + { + position = level.EndPosition - Vector2.UnitY*300.0f; + } + + } while (tries < 10); + item = new Item(itemPrefab, position + level.Position); item.MoveWithLevel = true; + item.body.FarseerBody.GravityScale = 0.5f; //item.MoveWithLevel = true; } diff --git a/Subsurface/Source/GUI/GUIComponent.cs b/Subsurface/Source/GUI/GUIComponent.cs index 618f489ff..1bf6fe961 100644 --- a/Subsurface/Source/GUI/GUIComponent.cs +++ b/Subsurface/Source/GUI/GUIComponent.cs @@ -370,12 +370,12 @@ namespace Barotrauma public GUIComponent FindChild(object userData) { - foreach (GUIComponent child in children) - { - if (child.userData == userData) return child; - } + return children.FirstOrDefault(c => c.userData == userData); + } - return null; + public List FindChildren(object userData) + { + return children .FindAll(c => c.userData == userData); } public virtual void ClearChildren() diff --git a/Subsurface/Source/GUI/GUITextBlock.cs b/Subsurface/Source/GUI/GUITextBlock.cs index 24050692c..8d9b9d95b 100644 --- a/Subsurface/Source/GUI/GUITextBlock.cs +++ b/Subsurface/Source/GUI/GUITextBlock.cs @@ -76,7 +76,13 @@ namespace Barotrauma { get { return caretPos; } } - + + public GUITextBlock(Rectangle rect, string text, GUIStyle style, GUIComponent parent, SpriteFont font) + : this(rect, text, style, Alignment.TopLeft, Alignment.TopLeft, parent, false, font) + { + } + + public GUITextBlock(Rectangle rect, string text, GUIStyle style, GUIComponent parent = null, bool wrap = false) : this(rect, text, style, Alignment.TopLeft, Alignment.TopLeft, parent, wrap) { diff --git a/Subsurface/Source/GameSession/GameModes/TutorialMode.cs b/Subsurface/Source/GameSession/GameModes/TutorialMode.cs index d8b926c31..45618a090 100644 --- a/Subsurface/Source/GameSession/GameModes/TutorialMode.cs +++ b/Subsurface/Source/GameSession/GameModes/TutorialMode.cs @@ -160,7 +160,7 @@ namespace Barotrauma infoBox = CreateInfoFrame("The amount of power generated by the reactor should be kept close to the amount of power consumed by the devices in the submarine. " +"If there isn't enough power, devices won't function properly (or at all), and if there's too much power, some devices may be damaged." - +" Try to raise the temperature of the reactor close to 3000 degrees by adjusting the fission and cooling rates."); + +" Try to raise the temperature of the reactor close to 3000 degrees by adjusting the fission and cooling rates.", true); while (Math.Abs(reactor.Temperature-3000.0f) > 100.0f) { diff --git a/Subsurface/Source/Items/Components/Machines/Radar.cs b/Subsurface/Source/Items/Components/Machines/Radar.cs index 9560934b9..0b5311f0f 100644 --- a/Subsurface/Source/Items/Components/Machines/Radar.cs +++ b/Subsurface/Source/Items/Components/Machines/Radar.cs @@ -47,7 +47,7 @@ namespace Barotrauma.Items.Components { base.Update(deltaTime, cam); - if (voltage>=minVoltage) + if (voltage >= minVoltage) { pingState = (pingState + deltaTime * 0.5f); if (pingState>1.0f) diff --git a/Subsurface/Source/Map/Levels/Level.cs b/Subsurface/Source/Map/Levels/Level.cs index 7e8eaeab6..92ca9cdc4 100644 --- a/Subsurface/Source/Map/Levels/Level.cs +++ b/Subsurface/Source/Map/Levels/Level.cs @@ -65,6 +65,11 @@ namespace Barotrauma private set; } + public Vector2 Size + { + get { return new Vector2(borders.Width, borders.Height); } + } + public Vector2 EndPosition { get { return endPosition; } @@ -277,7 +282,7 @@ namespace Barotrauma var newPathCells = GeneratePath(new List { start, end }, cells, pathBorders, 0.0f, 0.8f, mirror); - for (int n = 0; n < newPathCells.Count-5; n += 3) + for (int n = 0; n < newPathCells.Count; n += 5) { positionsOfInterest.Add(newPathCells[n].Center); } @@ -297,9 +302,13 @@ namespace Barotrauma // GeneratePath(rand, tunnelStart, new Vector2(tunnelStart.X, borders.Height), cells, pathBorders, minWidth, 0.1f, mirror) // ); //} - - cells = CleanCells(pathCells); + cells = CleanCells(pathCells); + + pathCells.AddRange(CreateBottomHoles(1.0f, new Rectangle( + (int)(borders.Width * 0.2f), 0, + (int)(borders.Width * 0.6f), (int)(borders.Height * 0.3f)))); + foreach (VoronoiCell cell in pathCells) { cells.Remove(cell); @@ -344,6 +353,17 @@ namespace Barotrauma } } + + for (int i = 0; i < 2; i++) + { + Body shaftBody = BodyFactory.CreateRectangle(GameMain.World, 100.0f, 10.0f, 5.0f); + shaftBody.BodyType = BodyType.Kinematic; + shaftBody.CollisionCategories = Physics.CollisionLevel; + shaftBody.SetTransform(ConvertUnits.ToSimUnits((i == 0) ? startPosition : endPosition), 0.0f); + shaftBody.SleepingAllowed = false; + bodies.Add(shaftBody); + } + foreach (VoronoiCell cell in cells) { foreach (GraphEdge edge in cell.edges) @@ -381,6 +401,7 @@ namespace Barotrauma //lower values will cause the path to "wander" more, higher will make it head straight to the end wanderAmount = MathHelper.Clamp(wanderAmount, 0.0f, 1.0f); + List allowedEdges = new List(); List pathCells = new List(); VoronoiCell[] targetCells = new VoronoiCell[points.Count]; @@ -398,12 +419,21 @@ namespace Barotrauma { int edgeIndex = 0; + allowedEdges.Clear(); + foreach (GraphEdge edge in currentCell.edges) + { + if (!limits.Contains(edge.AdjacentCell(currentCell).Center)) continue; + + allowedEdges.Add(edge); + } + //steer towards target - if (Rand.Range(0.0f, 1.0f, false) > wanderAmount) + if (Rand.Range(0.0f, 1.0f, false) > wanderAmount || allowedEdges.Count == 0) { for (int i = 0; i < currentCell.edges.Count; i++) { - if (!MathUtils.LinesIntersect(currentCell.Center, targetCells[currentTargetIndex].Center, currentCell.edges[i].point1, currentCell.edges[i].point2)) continue; + if (!MathUtils.LinesIntersect(currentCell.Center, targetCells[currentTargetIndex].Center, + currentCell.edges[i].point1, currentCell.edges[i].point2)) continue; edgeIndex = i; break; } @@ -411,24 +441,18 @@ namespace Barotrauma //choose random edge (ignoring ones where the adjacent cell is outside limits) else { - List allowedEdges = new List(); - foreach (GraphEdge edge in currentCell.edges) - { - if (!limits.Contains(edge.AdjacentCell(currentCell).Center)) continue; - allowedEdges.Add(edge); - } - if (allowedEdges.Count==0) - { - edgeIndex = Rand.Int(currentCell.edges.Count, false); - } - else - { + //if (allowedEdges.Count==0) + //{ + // edgeIndex = Rand.Int(currentCell.edges.Count, false); + //} + //else + //{ edgeIndex = Rand.Int(allowedEdges.Count, false); if (mirror && edgeIndex > 0) edgeIndex = allowedEdges.Count - edgeIndex; edgeIndex = currentCell.edges.IndexOf(allowedEdges[edgeIndex]); - } + //} } currentCell = currentCell.edges[edgeIndex].AdjacentCell(currentCell); @@ -495,6 +519,26 @@ namespace Barotrauma return pathCells; } + private List CreateBottomHoles(float holeProbability, Rectangle limits) + { + List toBeRemoved = new List(); + foreach (VoronoiCell cell in cells) + { + if (Rand.Range(0.0f, 1.0f, false) > holeProbability) continue; + + if (!limits.Contains(cell.Center)) continue; + + toBeRemoved.Add(cell); + } + + return toBeRemoved; + + //foreach (VoronoiCell cell in toBeRemoved) + //{ + // cells.Remove(cell); + //} + } + private List GetTooCloseCells(List emptyCells, float minDistance) { List tooCloseCells = new List(); @@ -671,17 +715,7 @@ namespace Barotrauma bodies.Add(edgeBody); } - for (int i = 0; i < 2; i++ ) - { - Body shaftBody = BodyFactory.CreateRectangle(GameMain.World, 100.0f, 10.0f, 5.0f); - shaftBody.BodyType = BodyType.Kinematic; - shaftBody.CollisionCategories = Physics.CollisionLevel; - shaftBody.SetTransform(ConvertUnits.ToSimUnits((i==0) ? startPosition : endPosition), 0.0f); - shaftBody.SleepingAllowed = false; - bodies.Add(shaftBody); - } - - return verticeList.ToArray(); + return verticeList.ToArray(); } public void SetPosition(Vector2 pos) @@ -918,7 +952,7 @@ namespace Barotrauma for (int i = 0; i < 2; i++) { basicEffect.World = Matrix.CreateTranslation(new Vector3(Position + wrappingWalls[side, i].Offset, 0.0f)) * cam.ShaderTransform - * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f; + * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f; basicEffect.CurrentTechnique.Passes[0].Apply(); diff --git a/Subsurface/Source/Map/Levels/WrappingWall.cs b/Subsurface/Source/Map/Levels/WrappingWall.cs index d7050abc5..d58fb1af8 100644 --- a/Subsurface/Source/Map/Levels/WrappingWall.cs +++ b/Subsurface/Source/Map/Levels/WrappingWall.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework; +using FarseerPhysics; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; @@ -12,7 +13,7 @@ namespace Barotrauma class WrappingWall { - const float wallWidth = 10000.0f; + const float wallWidth = 20000.0f; public VertexPositionTexture[] Vertices; @@ -60,7 +61,7 @@ namespace Barotrauma } } - Vector2 wallSectionSize = new Vector2(2000.0f, 2000.0f); + Vector2 wallSectionSize = new Vector2(2300.0f, 2300.0f); Vector2 startPos = (dir < 0) ? edgeCell.Center + Vector2.UnitX * wallWidth * dir : edgeCell.Center + wallWidth * Vector2.UnitX * (dir - 1); @@ -77,7 +78,7 @@ namespace Barotrauma float normalizedDist = distFromEdge / (wallWidth / 2); float variance = 1000.0f * normalizedDist; - bottomVertices.Add(center + new Vector2(Rand.Range(-variance, variance, false), Rand.Range(-variance, variance, false)*5.0f)); + bottomVertices.Add(center + new Vector2(Rand.Range(-variance, variance, false), Rand.Range(-variance, variance, false)*2.0f)); } for (int i = 1; i < bottomVertices.Count; i++) @@ -127,6 +128,22 @@ namespace Barotrauma walls[0, 0] = walls[0, 1]; walls[0, 1] = temp; } + else if (pos.X > walls[1, 1].midPos.X && walls[1,0].midPos.X < pos.X) + { + walls[1, 0].Shift(2); + + var temp = walls[1, 0]; + walls[1, 0] = walls[1, 1]; + walls[1, 1] = temp; + } + else if (pos.X < walls[1, 0].midPos.X && walls[1, 1].midPos.X > pos.X && walls[1, 1].slot > 0) + { + walls[1, 1].Shift(-2); + + var temp = walls[0, 0]; + walls[1, 0] = walls[1, 1]; + walls[1, 1] = temp; + } } public void Shift(int amount) @@ -134,9 +151,11 @@ namespace Barotrauma slot += amount; Vector2 moveAmount = Vector2.UnitX * wallWidth * amount; + + Vector2 simMoveAmount = ConvertUnits.ToSimUnits(moveAmount); foreach (VoronoiCell cell in cells) { - cell.body.SetTransform(cell.body.Position + moveAmount, 0.0f); + cell.body.SetTransform(cell.body.Position + simMoveAmount, 0.0f); } midPos += moveAmount; diff --git a/Subsurface/Source/Map/SubmarineHull.cs b/Subsurface/Source/Map/SubmarineHull.cs index 5518b77ce..55d59e0c8 100644 --- a/Subsurface/Source/Map/SubmarineHull.cs +++ b/Subsurface/Source/Map/SubmarineHull.cs @@ -16,6 +16,9 @@ namespace Barotrauma { class SubmarineBody { + const float DamageDepth = 0.0f; + const float PressureDamageMultiplier = 0.001f; + //structure damage = impact * damageMultiplier const float DamageMultiplier = 50.0f; @@ -27,6 +30,8 @@ namespace Barotrauma private set; } + private float depthDamageTimer; + private Submarine sub; private Body body; @@ -207,6 +212,8 @@ namespace Barotrauma ApplyForce(totalForce); + UpdateDepthDamage(deltaTime); + //hullBodies[0].body.LinearVelocity = -hullBodies[0].body.Position; //hullBody.SetTransform(Vector2.Zero , 0.0f); @@ -240,6 +247,48 @@ namespace Barotrauma Speed += force / mass; } + private void UpdateDepthDamage(float deltaTime) + { + if (sub.Position.Y > DamageDepth) return; + + float depth = DamageDepth - sub.Position.Y; + depth = Math.Max(depth, -40000.0f); + + // float prevTimer = depthDamageTimer; + + depthDamageTimer -= deltaTime*depth*PressureDamageMultiplier; + + //if (prevTimer>5.0f && depthDamageTimer<=5.0f) + //{ + // SoundPlayer.PlayDamageSound(DamageSoundType.Pressure, 50.0f,); + //} + + if (depthDamageTimer > 0.0f) return; + + Vector2 damagePos = Vector2.Zero; + if (Rand.Int(2)==0) + { + damagePos = new Vector2( + (Rand.Int(2) == 0) ? Borders.X : Borders.X+Borders.Width, + Rand.Range(Borders.Y - Borders.Height, Borders.Y)); + } + else + { + damagePos = new Vector2( + Rand.Range(Borders.X, Borders.X + Borders.Width), + (Rand.Int(2) == 0) ? Borders.Y : Borders.Y - Borders.Height); + } + + SoundPlayer.PlayDamageSound(DamageSoundType.Pressure, 50.0f, damagePos, 5000.0f); + + GameMain.GameScreen.Cam.Shake = depth * PressureDamageMultiplier * 0.1f; + + Explosion.RangedStructureDamage(damagePos, depth * PressureDamageMultiplier * 50.0f, depth * PressureDamageMultiplier); + //SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, Rand.Range(0.0f, 100.0f), damagePos, 5000.0f); + + depthDamageTimer = 10.0f; + } + private void UpdateColliding() { if (body.Position.LengthSquared()<0.00001f) return; diff --git a/Subsurface/Source/Map/WayPoint.cs b/Subsurface/Source/Map/WayPoint.cs index 6ed255969..d86ad027b 100644 --- a/Subsurface/Source/Map/WayPoint.cs +++ b/Subsurface/Source/Map/WayPoint.cs @@ -226,7 +226,6 @@ namespace Barotrauma //try to give the crew member a spawnpoint that hasn't been assigned to anyone and matches their job for (int n = 0; n < unassignedWayPoints.Count; n++) { - if (crew[i].Job.Prefab != unassignedWayPoints[n].assignedJob) continue; assignedWayPoints[i] = unassignedWayPoints[n]; unassignedWayPoints.RemoveAt(n); diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 2830a071d..54c918929 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -438,7 +438,12 @@ namespace Barotrauma.Networking AddChatMessage(inc.ReadString(), ChatMessageType.Server); Client disconnectedClient = otherClients.Find(c => c.ID == leavingID); - if (disconnectedClient != null) GameMain.NetLobbyScreen.RemovePlayer(disconnectedClient.name); + + if (disconnectedClient != null) + { + otherClients.Remove(disconnectedClient); + GameMain.NetLobbyScreen.RemovePlayer(disconnectedClient.name); + } if (!gameStarted) return; @@ -487,6 +492,9 @@ namespace Barotrauma.Networking case (byte)PacketTypes.LatestMessageID: reliableChannel.HandleLatestMessageID(inc); break; + case (byte)PacketTypes.VoteStatus: + Voting.ReadData(inc); + break; } } } @@ -512,7 +520,7 @@ namespace Barotrauma.Networking yield return CoroutineStatus.Success; } - if (!GameMain.NetLobbyScreen.TrySelectMap(mapName, mapHash)) + if (!GameMain.NetLobbyScreen.TrySelectSub(mapName, mapHash)) { yield return CoroutineStatus.Success; } @@ -522,7 +530,7 @@ namespace Barotrauma.Networking Rand.SetSyncedSeed(seed); //int gameModeIndex = inc.ReadInt32(); - GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedMap, "", gameMode); + GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode); yield return CoroutineStatus.Running; @@ -637,6 +645,25 @@ namespace Barotrauma.Networking GameMain.NetworkMember = null; } + public void Vote(VoteType voteType, object userData) + { + NetOutgoingMessage msg = client.CreateMessage(); + msg.Write((byte)PacketTypes.Vote); + msg.Write((byte)voteType); + + switch (voteType) + { + 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; + } + } + public void SendCharacterData() { if (characterInfo == null) return; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 4f5918815..8fb56e9c9 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -223,7 +223,6 @@ namespace Barotrauma.Networking connectedClients.Find(c => c.character != null && !c.character.IsDead)==null && (myCharacter == null || myCharacter.IsDead)) { - AutoRestartTimer = 20.0f; EndButtonHit(null, null); UpdateNetLobby(null,null); return; @@ -484,6 +483,9 @@ namespace Barotrauma.Networking case (byte)PacketTypes.LatestMessageID: dataSender.ReliableChannel.HandleLatestMessageID(inc); break; + case (byte)PacketTypes.Vote: + Voting.RegisterVote(inc, connectedClients); + break; } break; case NetIncomingMessageType.WarningMessage: @@ -674,7 +676,8 @@ namespace Barotrauma.Networking public bool StartGameClicked(GUIButton button, object obj) { - Submarine selectedSub = GameMain.NetLobbyScreen.SelectedMap as Submarine; + Submarine selectedSub = Voting.AllowSubVoting ? + Voting.HighestVoted(VoteType.Sub, connectedClients) : GameMain.NetLobbyScreen.SelectedSub; if (selectedSub == null) { @@ -695,7 +698,11 @@ namespace Barotrauma.Networking int seed = DateTime.Now.Millisecond; Rand.SetSyncedSeed(seed); - GameMain.GameSession = new GameSession(selectedSub, "", GameMain.NetLobbyScreen.SelectedMode); + + GameModePreset selectedMode = Voting.HighestVoted(VoteType.Mode, connectedClients); + if (selectedMode==null) selectedMode=GameMain.NetLobbyScreen.SelectedMode; + + GameMain.GameSession = new GameSession(selectedSub, "", selectedMode); GameMain.GameSession.StartShift(GameMain.NetLobbyScreen.LevelSeed); yield return CoroutineStatus.Running; @@ -747,10 +754,10 @@ namespace Barotrauma.Networking msg.Write(GameMain.NetLobbyScreen.LevelSeed); - msg.Write(GameMain.NetLobbyScreen.SelectedMap.Name); - msg.Write(GameMain.NetLobbyScreen.SelectedMap.MD5Hash.Hash); + msg.Write(selectedSub.Name); + msg.Write(selectedSub.MD5Hash.Hash); - msg.Write(GameMain.NetLobbyScreen.SelectedMode.Name); + msg.Write(selectedMode.Name); //msg.Write(GameMain.NetLobbyScreen.GameDuration.TotalMinutes); @@ -788,6 +795,8 @@ namespace Barotrauma.Networking { GameMain.GameSession.gameMode.End("Server admin has ended the round"); + if (autoRestart) AutoRestartTimer = 20.0f; + return true; } @@ -1044,6 +1053,27 @@ namespace Barotrauma.Networking } + public void UpdateVoteStatus() + { + if (server.Connections.Count == 0) return; + + try + { + NetOutgoingMessage msg = server.CreateMessage(); + msg.Write((byte)PacketTypes.VoteStatus); + Voting.WriteData(msg, connectedClients); + + server.SendMessage(msg, server.Connections, NetDeliveryMethod.ReliableUnordered, 0); + } + catch (Exception e) + { +#if DEBUG + DebugConsole.ThrowError("Failed to update vote status", e); +#endif + } + + } + public bool UpdateNetLobby(object obj) { return UpdateNetLobby(null, obj); @@ -1051,14 +1081,13 @@ namespace Barotrauma.Networking public bool UpdateNetLobby(GUIComponent component, object obj) { + if (server.Connections.Count == 0) return true; + NetOutgoingMessage msg = server.CreateMessage(); msg.Write((byte)PacketTypes.UpdateNetLobby); GameMain.NetLobbyScreen.WriteData(msg); - if (server.Connections.Count > 0) - { - server.SendMessage(msg, server.Connections, NetDeliveryMethod.ReliableUnordered, 0); - } + server.SendMessage(msg, server.Connections, NetDeliveryMethod.ReliableUnordered, 0); return true; } @@ -1320,6 +1349,8 @@ namespace Barotrauma.Networking public string version; public bool inGame; + private object[] votes; + public List jobPreferences; public JobPrefab assignedJob; @@ -1337,8 +1368,20 @@ namespace Barotrauma.Networking { this.name = name; this.ID = ID; + + votes = new object[Enum.GetNames(typeof(VoteType)).Length]; jobPreferences = new List(JobPrefab.List.GetRange(0,3)); } + + public object GetVote(VoteType voteType) + { + return votes[(int)voteType]; + } + + public void SetVote(VoteType voteType, object value) + { + votes[(int)voteType] = value; + } } } diff --git a/Subsurface/Source/Screens/NetLobbySettings.cs b/Subsurface/Source/Networking/GameServerSettings.cs similarity index 88% rename from Subsurface/Source/Screens/NetLobbySettings.cs rename to Subsurface/Source/Networking/GameServerSettings.cs index 91b21bff6..bfc0e1f44 100644 --- a/Subsurface/Source/Screens/NetLobbySettings.cs +++ b/Subsurface/Source/Networking/GameServerSettings.cs @@ -20,7 +20,7 @@ namespace Barotrauma.Networking private SelectionMode subSelectionMode, modeSelectionMode; - private bool randomizeSeed; + private bool randomizeSeed = true; private bool registeredToMaster; @@ -108,6 +108,13 @@ namespace Barotrauma.Networking ((GUITickBox)otherTickBox).Selected = false; } + Voting.AllowSubVoting = subSelectionMode == SelectionMode.Vote; + + if (subSelectionMode==SelectionMode.Random) + { + GameMain.NetLobbyScreen.SubList.Select(Rand.Range(0, GameMain.NetLobbyScreen.SubList.CountChildren)); + } + return true; } @@ -121,6 +128,13 @@ namespace Barotrauma.Networking ((GUITickBox)otherTickBox).Selected = false; } + Voting.AllowModeVoting = modeSelectionMode == SelectionMode.Vote; + + if (modeSelectionMode == SelectionMode.Random) + { + GameMain.NetLobbyScreen.ModeList.Select(Rand.Range(0, GameMain.NetLobbyScreen.ModeList.CountChildren)); + } + return true; } diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index af75c2428..830c289f0 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -30,10 +30,20 @@ namespace Barotrauma.Networking Traitor, + Vote, + VoteStatus, + ResendRequest, ReliableMessage, - LatestMessageID - + LatestMessageID + } + + enum VoteType + { + Unknown, + Sub, + Mode, + EndRound } class NetworkMember @@ -61,6 +71,8 @@ namespace Barotrauma.Networking protected Character myCharacter; protected CharacterInfo characterInfo; + public Voting Voting; + public Character Character { get { return myCharacter; } @@ -113,6 +125,8 @@ namespace Barotrauma.Networking crewButton = new GUIButton(new Rectangle(chatBox.Rect.Right-80, chatBox.Rect.Y-30, 80, 20), "Crew", GUI.Style, inGameHUD); crewButton.OnClicked = ToggleCrewFrame; + + Voting = new Voting(); } protected void CreateCrewFrame(List crew) diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index fb6c3acf0..974e2bc18 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -78,7 +78,7 @@ namespace Barotrauma if (PlayerInput.KeyDown(Keys.J)) targetMovement.X -= 1.0f; if (PlayerInput.KeyDown(Keys.L)) targetMovement.X += 1.0f; - GameMain.GameSession.Submarine.ApplyForce(targetMovement * 100000.0f); + GameMain.GameSession.Submarine.ApplyForce(targetMovement * 1000000.0f); } #endif dustOffset -= Vector2.UnitY * 10.0f * (float)deltaTime; @@ -213,11 +213,11 @@ namespace Barotrauma viewRect.Y = -viewRect.Y; float multiplier = 0.8f; - for (int i = 1; i < 3; i++) + for (int i = 1; i < 4; i++) { spriteBatch.Draw(dustParticles, viewRect, new Rectangle((int)((backgroundPos.X * multiplier)), (int)((-backgroundPos.Y * multiplier)), cam.WorldView.Width, cam.WorldView.Height), - Color.LightGray * multiplier, 0.0f, Vector2.Zero, SpriteEffects.None, 1.0f-multiplier); + Color.White * multiplier, 0.0f, Vector2.Zero, SpriteEffects.None, 1.0f-multiplier); multiplier -= 0.15f; } diff --git a/Subsurface/Source/Screens/LobbyScreen.cs b/Subsurface/Source/Screens/LobbyScreen.cs index 947cf2b75..24d588624 100644 --- a/Subsurface/Source/Screens/LobbyScreen.cs +++ b/Subsurface/Source/Screens/LobbyScreen.cs @@ -58,14 +58,14 @@ namespace Barotrauma { Rectangle panelRect = new Rectangle( 40, 40, - 180, + GameMain.GraphicsWidth < 1000 ? 140 : 180, GameMain.GraphicsHeight - 80); leftPanel = new GUIFrame(panelRect, GUI.Style); - //leftPanel.Padding = GUI.style.smallPadding; + leftPanel.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); - new GUITextBlock(new Rectangle(0, 0, 200, 25), - "asdfdasfasdf", Color.Transparent, Color.White, Alignment.Left, GUI.Style, leftPanel); + //new GUITextBlock(new Rectangle(0, 0, 200, 25), + // save, Color.Transparent, Color.White, Alignment.Left, GUI.Style, leftPanel); GUITextBlock moneyText = new GUITextBlock(new Rectangle(0, 30, 200, 25), "", Color.Transparent, Color.White, Alignment.Left, GUI.Style, leftPanel); @@ -100,17 +100,18 @@ namespace Barotrauma rightPanel = new GUIFrame[4]; rightPanel[(int)PanelTab.Crew] = new GUIFrame(panelRect, GUI.Style); - //rightPanel[(int)PanelTab.Crew].Padding = GUI.style.smallPadding; + rightPanel[(int)PanelTab.Crew].Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); new GUITextBlock(new Rectangle(0, 0, 200, 25), "Crew:", Color.Transparent, Color.White, Alignment.Left, GUI.Style, rightPanel[(int)PanelTab.Crew]); - characterList = new GUIListBox(new Rectangle(0, 30, 300, 0), GUI.Style, rightPanel[(int)PanelTab.Crew]); + int crewColumnWidth = Math.Min(300, (panelRect.Width - 40) / 2); + characterList = new GUIListBox(new Rectangle(0, 30, crewColumnWidth, 0), GUI.Style, rightPanel[(int)PanelTab.Crew]); characterList.OnSelected = SelectCharacter; //--------------------------------------- rightPanel[(int)PanelTab.Map] = new GUIFrame(panelRect, GUI.Style); - //rightPanel[(int)PanelTab.Map].Padding = GUI.style.smallPadding; + rightPanel[(int)PanelTab.Map].Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); startButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.BottomRight, GUI.Style, rightPanel[(int)PanelTab.Map]); @@ -124,17 +125,20 @@ namespace Barotrauma //--------------------------------------- rightPanel[(int)PanelTab.Store] = new GUIFrame(panelRect, GUI.Style); + rightPanel[(int)PanelTab.Store].Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); - selectedItemList = new GUIListBox(new Rectangle(0, 0, 300, 400), Color.White * 0.7f, GUI.Style, rightPanel[(int)PanelTab.Store]); + int sellColumnWidth = (panelRect.Width - 40) / 2 - 20; + + selectedItemList = new GUIListBox(new Rectangle(0, 0, sellColumnWidth, 400), Color.White * 0.7f, GUI.Style, rightPanel[(int)PanelTab.Store]); selectedItemList.OnSelected = DeselectItem; - var costText = new GUITextBlock(new Rectangle(0, 0, 200, 25), "Cost: ", GUI.Style, Alignment.BottomLeft, Alignment.TopLeft, rightPanel[(int)PanelTab.Store]); + var costText = new GUITextBlock(new Rectangle(0, 0, 100, 25), "Cost: ", GUI.Style, Alignment.BottomLeft, Alignment.TopLeft, rightPanel[(int)PanelTab.Store]); costText.TextGetter = CostTextGetter; - buyButton = new GUIButton(new Rectangle(150, 0, 100, 25), "Buy", Alignment.Bottom, GUI.Style, rightPanel[(int)PanelTab.Store]); + buyButton = new GUIButton(new Rectangle(sellColumnWidth+20, 0, 100, 25), "Buy", Alignment.Bottom, GUI.Style, rightPanel[(int)PanelTab.Store]); buyButton.OnClicked = BuyItems; - itemList = new GUIListBox(new Rectangle(0, 0, 300, 400), Color.White * 0.7f, Alignment.TopRight, GUI.Style, rightPanel[(int)PanelTab.Store]); + itemList = new GUIListBox(new Rectangle(0, 0, sellColumnWidth, 400), Color.White * 0.7f, Alignment.TopRight, GUI.Style, rightPanel[(int)PanelTab.Store]); itemList.OnSelected = SelectItem; foreach (MapEntityPrefab ep in MapEntityPrefab.list) @@ -237,7 +241,7 @@ namespace Barotrauma c.Name + " (" + c.Job.Name + ")", GUI.Style, Alignment.Left, Alignment.Left, - characterList); + characterList, false, GameMain.GraphicsWidth<1000 ? GUI.SmallFont : GUI.Font); textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); textBlock.UserData = c; } @@ -254,12 +258,15 @@ namespace Barotrauma frame.HoverColor = Color.Gold * 0.2f; frame.SelectedColor = Color.Gold * 0.5f; + SpriteFont font = listBox.Rect.Width < 280 ? GUI.SmallFont : GUI.Font; + GUITextBlock textBlock = new GUITextBlock( new Rectangle(40, 0, 0, 25), ep.Name, Color.Transparent, Color.White, Alignment.Left, Alignment.Left, null, frame); + textBlock.Font = font; textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f); textBlock = new GUITextBlock( @@ -267,6 +274,7 @@ namespace Barotrauma ep.Price.ToString(), null, null, Alignment.TopRight, GUI.Style, textBlock); + textBlock.Font = font; if (ep.sprite != null) { @@ -410,7 +418,7 @@ namespace Barotrauma if (previewFrame == null || previewFrame.UserData != characterInfo) { - previewFrame = new GUIFrame(new Rectangle(350, 60, 300, 300), + previewFrame = new GUIFrame(new Rectangle(rightPanel[(int)PanelTab.Crew].Rect.Width/2, 60, Math.Min(300,rightPanel[(int)PanelTab.Crew].Rect.Width/2 - 40), 300), new Color(0.0f, 0.0f, 0.0f, 0.8f), Alignment.Top, GUI.Style, rightPanel[selectedRightPanel]); previewFrame.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index c20f4216b..471b5bdfc 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -11,7 +11,7 @@ using System.Collections.Generic; namespace Barotrauma { - class NetLobbyScreen : Screen + partial class NetLobbyScreen : Screen { private GUIFrame menu; private GUIFrame infoFrame; @@ -43,7 +43,17 @@ namespace Barotrauma get { return subList; } } - public Submarine SelectedMap + public GUIListBox ModeList + { + get { return modeList; } + } + + public GUIFrame InfoFrame + { + get { return infoFrame; } + } + + public Submarine SelectedSub { get { return subList.SelectedData as Submarine; } } @@ -105,7 +115,7 @@ namespace Barotrauma if (autoRestartTimer == 0.0f) return ""; return "Restarting in " + (int)autoRestartTimer; } - + public NetLobbyScreen() { int width = Math.Min(GameMain.GraphicsWidth - 80, 1500); @@ -156,12 +166,16 @@ namespace Barotrauma //submarine list ------------------------------------------------------------------ - int columnWidth = infoFrame.Rect.Width / 5 - 30; + int columnWidth = infoFrame.Rect.Width / 3 - 5; int columnX = 0; new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 30), "Submarine:", GUI.Style, infoFrame); subList = new GUIListBox(new Rectangle(columnX, 150, columnWidth, infoFrame.Rect.Height - 150 - 80), Color.White, GUI.Style, infoFrame); - subList.OnSelected = SelectMap; + subList.OnSelected = VotableClicked; + + var voteText = new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 30), "Votes: ", GUI.Style, Alignment.TopLeft, Alignment.TopRight, infoFrame); + voteText.UserData = "subvotes"; + voteText.Visible = false; if (Submarine.SavedSubmarines.Count > 0) { @@ -188,8 +202,13 @@ namespace Barotrauma new GUITextBlock(new Rectangle(columnX, 120, 0, 30), "Game mode: ", GUI.Style, infoFrame); modeList = new GUIListBox(new Rectangle(columnX, 150, columnWidth, infoFrame.Rect.Height - 150 - 80), GUI.Style, infoFrame); + modeList.OnSelected = VotableClicked; + voteText = new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 30), "Votes: ", GUI.Style, Alignment.TopLeft, Alignment.TopRight, infoFrame); + voteText.UserData = "modevotes"; + voteText.Visible = false; + foreach (GameModePreset mode in GameModePreset.list) { if (mode.IsSinglePlayer) continue; @@ -199,29 +218,31 @@ namespace Barotrauma mode.Name, GUI.Style, Alignment.Left, Alignment.Left, modeList); + textBlock.ToolTip = mode.Description; textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); textBlock.UserData = mode; } - columnX += columnWidth; + + columnX += columnWidth + 20; //gamemode description ------------------------------------------------------------------ - var modeDescription = new GUITextBlock( - new Rectangle(columnX, 150, (int)(columnWidth * 1.5f), infoFrame.Rect.Height - 150 - 80), - "", GUI.Style, Alignment.TopLeft, Alignment.TopLeft, infoFrame, true, GameMain.GraphicsWidth>1024 ? GUI.Font : GUI.SmallFont); - modeDescription.Color = Color.Black * 0.3f; + //var modeDescription = new GUITextBlock( + // new Rectangle(columnX, 150, (int)(columnWidth * 1.2f), infoFrame.Rect.Height - 150 - 80), + // "", GUI.Style, Alignment.TopLeft, Alignment.TopLeft, infoFrame, true, GUI.SmallFont); + //modeDescription.Color = Color.Black * 0.3f; - modeList.UserData = modeDescription; + //modeList.UserData = modeDescription; - columnX += modeDescription.Rect.Width + 40; + //columnX += modeDescription.Rect.Width + 20; //seed ------------------------------------------------------------------ - new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 20), + new GUITextBlock(new Rectangle(columnX, 120, 180, 20), "Level Seed: ", GUI.Style, Alignment.Left, Alignment.TopLeft, infoFrame); - seedBox = new GUITextBox(new Rectangle(columnX, 150, columnWidth, 20), + seedBox = new GUITextBox(new Rectangle(columnX, 150, columnWidth/2, 20), Alignment.TopLeft, GUI.Style, infoFrame); seedBox.OnTextChanged = SelectSeed; LevelSeed = ToolBox.RandomSeed(8); @@ -264,16 +285,16 @@ namespace Barotrauma Character.Controlled = null; GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; - - subList.Enabled = GameMain.Server != null; + + subList.Enabled = GameMain.Server != null || GameMain.NetworkMember.Voting.AllowSubVoting; playerList.Enabled = GameMain.Server != null; - modeList.Enabled = GameMain.Server != null; + modeList.Enabled = GameMain.Server != null || GameMain.NetworkMember.Voting.AllowModeVoting; seedBox.Enabled = GameMain.Server != null; serverMessage.Enabled = GameMain.Server != null; autoRestartBox.Enabled = GameMain.Server != null; ServerName = (GameMain.Server==null) ? "Server" : GameMain.Server.Name; - modeList.OnSelected += SelectMode; + infoFrame.RemoveChild(infoFrame.children.Find(c => c.UserData as string == "startButton")); @@ -281,6 +302,11 @@ namespace Barotrauma if (IsServer && GameMain.Server != null) { + modeList.OnSelected = VotableClicked; + modeList.OnSelected += SelectMode; + subList.OnSelected = VotableClicked; + subList.OnSelected += SelectMode; + GUIButton startButton = new GUIButton(new Rectangle(0, 0, 80, 30), "Start", Alignment.BottomRight, GUI.Style, infoFrame); startButton.OnClicked = GameMain.Server.StartGameClicked; startButton.UserData = "startButton"; @@ -294,7 +320,7 @@ namespace Barotrauma banListButton.UserData = "banListButton"; //mapList.OnSelected = new GUIListBox.OnSelectedHandler(Game1.server.UpdateNetLobby); - modeList.OnSelected += GameMain.Server.UpdateNetLobby; + //modeList.OnSelected += GameMain.Server.UpdateNetLobby; if (subList.CountChildren > 0 && subList.Selected == null) subList.Select(-1); if (GameModePreset.list.Count > 0 && modeList.Selected == null) modeList.Select(-1); @@ -339,21 +365,21 @@ namespace Barotrauma playerName.Text = characterInfo.Name; playerName.OnEnterPressed += ChangeCharacterName; - GUIButton toggleHead = new GUIButton(new Rectangle(0, 50, 20, 20), "<", GUI.Style, myPlayerFrame); + GUIButton toggleHead = new GUIButton(new Rectangle(0, 50, 15, 15), "<", GUI.Style, myPlayerFrame); toggleHead.UserData = -1; toggleHead.OnClicked = ToggleHead; - toggleHead = new GUIButton(new Rectangle(60, 50, 20, 20), ">", GUI.Style, myPlayerFrame); + toggleHead = new GUIButton(new Rectangle(60, 50, 15, 15), ">", GUI.Style, myPlayerFrame); toggleHead.UserData = 1; toggleHead.OnClicked = ToggleHead; - new GUITextBlock(new Rectangle(0, 100, 200, 30), "Gender: ", GUI.Style, myPlayerFrame); + new GUITextBlock(new Rectangle(0, 90, 200, 30), "Gender: ", GUI.Style, myPlayerFrame); - GUIButton maleButton = new GUIButton(new Rectangle(70, 100, 60, 20), "Male", + GUIButton maleButton = new GUIButton(new Rectangle(0, 110, 60, 20), "Male", Alignment.TopLeft, GUI.Style, myPlayerFrame); maleButton.UserData = Gender.Male; maleButton.OnClicked += SwitchGender; - GUIButton femaleButton = new GUIButton(new Rectangle(140, 100, 60, 20), "Female", + GUIButton femaleButton = new GUIButton(new Rectangle(70, 110, 60, 20), "Female", Alignment.TopLeft, GUI.Style, myPlayerFrame); femaleButton.UserData = Gender.Female; femaleButton.OnClicked += SwitchGender; @@ -367,7 +393,9 @@ namespace Barotrauma int i = 1; foreach (JobPrefab job in JobPrefab.List) { - GUITextBlock jobText = new GUITextBlock(new Rectangle(0, 0, 0, 20), i + ". " + 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, false, + GameMain.GraphicsWidth<1000 ? GUI.SmallFont : GUI.Font); jobText.UserData = job; GUIButton infoButton = new GUIButton(new Rectangle(0, 0, 15, 15), "?", GUI.Style, jobText); @@ -439,6 +467,31 @@ namespace Barotrauma return true; } + public bool VotableClicked(GUIComponent component, object userData) + { + if (GameMain.Client == null) return false; + + VoteType voteType = VoteType.Unknown; + if (component.Parent == GameMain.NetLobbyScreen.SubList) + { + if (!GameMain.Client.Voting.AllowSubVoting) return false; + voteType = VoteType.Sub; + } + else if (component.Parent == GameMain.NetLobbyScreen.ModeList) + { + if (!GameMain.Client.Voting.AllowModeVoting) return false; + voteType = VoteType.Mode; + } + else + { + return false; + } + + GameMain.Client.Vote(voteType, userData); + + return true; + } + public bool ChangeServerName(GUITextBox textBox, string text) { if (GameMain.Server == null) return false; @@ -581,7 +634,7 @@ namespace Barotrauma spriteBatch.Begin(); menu.Draw(spriteBatch); - + if (jobInfoFrame != null) jobInfoFrame.Draw(spriteBatch); //if (previewPlayer!=null) previewPlayer.Draw(spriteBatch); @@ -664,15 +717,16 @@ namespace Barotrauma private bool SelectMode(GUIComponent component, object obj) { + if (GameMain.NetworkMember == null) return false; + + //if (GameMain.Server==null) + //{ + // return VotableClicked(component, obj); + //} + GameModePreset modePreset = obj as GameModePreset; if (modePreset == null) return false; - GUITextBlock description = modeList.UserData as GUITextBlock; - - description.Text = modePreset.Description; - - //if (Game1.Server != null) Game1.Server.UpdateNetLobby(null); - return true; } @@ -767,34 +821,34 @@ namespace Barotrauma if (GameMain.Client!=null) GameMain.Client.SendCharacterData(); } - public bool TrySelectMap(string mapName, string md5Hash) + public bool TrySelectSub(string subName, string md5Hash) { - Submarine map = Submarine.SavedSubmarines.Find(m => m.Name == mapName); - if (map == null) + Submarine sub = Submarine.SavedSubmarines.Find(m => m.Name == subName); + if (sub == null) { - new GUIMessageBox("Submarine not found!","The submarine ''" + mapName + "'' has been selected by the server. Matching file not found in your map folder."); + new GUIMessageBox("Submarine not found!","The submarine ''" + subName + "'' has been selected by the server. Matching file not found in your map folder."); return false; } else { - if (map.MD5Hash.Hash != md5Hash) + if (sub.MD5Hash.Hash != md5Hash) { new GUIMessageBox("Submarine not found!", - "Your version of the map file ''" + map.Name + "'' doesn't match the server's version!" - +"\nYour file: " + map.Name + "(MD5 hash : " + map.MD5Hash.Hash + ")" - +"\nServer's file: " + mapName + "(MD5 hash : " + md5Hash + ")"); + "Your version of the map file ''" + sub.Name + "'' doesn't match the server's version!" + +"\nYour file: " + sub.Name + "(MD5 hash : " + sub.MD5Hash.Hash + ")" + +"\nServer's file: " + subName + "(MD5 hash : " + md5Hash + ")"); return false; } else { - subList.Select(map); + subList.Select(sub); //map.Load(); return true; } } } - + public void WriteData(NetOutgoingMessage msg) { Submarine selectedMap = subList.SelectedData as Submarine; @@ -813,6 +867,9 @@ namespace Barotrauma msg.Write(ServerName); msg.Write(ServerMessage); + //msg.Write(AllowSubVoting); + //msg.Write(AllowModeVoting); + msg.Write(modeList.SelectedIndex-1); //msg.Write(durationBar.BarScroll); msg.Write(LevelSeed); @@ -828,8 +885,6 @@ namespace Barotrauma } } - - public void ReadData(NetIncomingMessage msg) { string mapName="", md5Hash=""; @@ -844,20 +899,23 @@ namespace Barotrauma try { - mapName = msg.ReadString(); - md5Hash = msg.ReadString(); + mapName = msg.ReadString(); + md5Hash = msg.ReadString(); - ServerName = msg.ReadString(); - ServerMessage = msg.ReadString(); + ServerName = msg.ReadString(); + ServerMessage = msg.ReadString(); - modeIndex = msg.ReadInt32(); + //AllowSubVoting = msg.ReadBoolean(); + //AllowModeVoting = msg.ReadBoolean(); + + modeIndex = msg.ReadInt32(); //durationScroll = msg.ReadFloat(); - levelSeed = msg.ReadString(); + levelSeed = msg.ReadString(); - autoRestart = msg.ReadBoolean(); - restartTimer = msg.ReadFloat(); + autoRestart = msg.ReadBoolean(); + restartTimer = msg.ReadFloat(); int playerCount = msg.ReadByte(); @@ -873,9 +931,9 @@ namespace Barotrauma return; } - if (!string.IsNullOrWhiteSpace(mapName)) TrySelectMap(mapName, md5Hash); + if (!string.IsNullOrWhiteSpace(mapName) && !GameMain.NetworkMember.Voting.AllowSubVoting) TrySelectSub(mapName, md5Hash); - modeList.Select(modeIndex); + if (!GameMain.NetworkMember.Voting.AllowModeVoting) modeList.Select(modeIndex); autoRestartBox.Selected = autoRestart; autoRestartTimer = restartTimer; diff --git a/Subsurface/Source/Screens/NetLobbyVoting.cs b/Subsurface/Source/Screens/NetLobbyVoting.cs new file mode 100644 index 000000000..ee3a3029f --- /dev/null +++ b/Subsurface/Source/Screens/NetLobbyVoting.cs @@ -0,0 +1,234 @@ +using Barotrauma.Networking; +using Lidgren.Network; +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Barotrauma +{ + class Voting + { + private bool allowSubVoting, allowModeVoting; + + public bool AllowSubVoting + { + get { return allowSubVoting; } + set + { + if (value == allowSubVoting) return; + allowSubVoting = value; + GameMain.NetLobbyScreen.SubList.Enabled = value || GameMain.Server != null; + GameMain.NetLobbyScreen.InfoFrame.FindChild("subvotes").Visible = value; + + if (GameMain.Server != null) + { + UpdateVoteTexts(GameMain.Server.connectedClients, VoteType.Sub); + GameMain.Server.UpdateVoteStatus(); + } + else + { + GameMain.NetLobbyScreen.SubList.Deselect(); + } + } + } + public bool AllowModeVoting + { + get { return allowModeVoting; } + set + { + if (value == allowModeVoting) return; + allowModeVoting = value; + GameMain.NetLobbyScreen.ModeList.Enabled = value || GameMain.Server != null; + GameMain.NetLobbyScreen.InfoFrame.FindChild("modevotes").Visible = value; + if (GameMain.Server != null) + { + UpdateVoteTexts(GameMain.Server.connectedClients, VoteType.Mode); + GameMain.Server.UpdateVoteStatus(); + } + else + { + GameMain.NetLobbyScreen.ModeList.Deselect(); + } + } + } + + public void RegisterVote(NetIncomingMessage inc, List connectedClients) + { + byte voteTypeByte = inc.ReadByte(); + VoteType voteType = VoteType.Unknown; + try + { + voteType = (VoteType)voteTypeByte; + } + catch + { + return; + } + Client sender = connectedClients.Find(x => x.Connection == inc.SenderConnection); + switch (voteType) + { + case VoteType.Sub: + string subName = inc.ReadString(); + Submarine sub = Submarine.SavedSubmarines.Find(s => s.Name == subName); + sender.SetVote(voteType, sub); + UpdateVoteTexts(connectedClients, voteType); + break; + + case VoteType.Mode: + string modeName = inc.ReadString(); + GameModePreset mode = GameModePreset.list.Find(gm => gm.Name == modeName); + sender.SetVote(voteType, mode); + UpdateVoteTexts(connectedClients, voteType); + break; + case VoteType.EndRound: + sender.SetVote(voteType, inc.ReadBoolean()); + break; + } + + GameMain.Server.UpdateVoteStatus(); + } + + public void UpdateVoteTexts(List clients, VoteType voteType) + { + GUIListBox listBox = (voteType == VoteType.Sub) ? + GameMain.NetLobbyScreen.SubList : GameMain.NetLobbyScreen.ModeList; + + foreach (GUIComponent comp in listBox.children) + { + GUITextBlock voteText = comp.FindChild("votes") as GUITextBlock; + if (voteText != null) comp.RemoveChild(voteText); + } + + List> voteList = GetVoteList(voteType, clients); + foreach (Pair votable in voteList) + { + SetVoteText(listBox, votable.First, votable.Second); + } + } + + private void SetVoteText(GUIListBox listBox, object userData, int votes) + { + if (userData == null) return; + foreach (GUIComponent comp in listBox.children) + { + if (comp.UserData != userData) continue; + GUITextBlock voteText = comp.FindChild("votes") as GUITextBlock; + if (voteText == null) + { + voteText = new GUITextBlock(new Rectangle(0, 0, 30, 0), "", GUI.Style, Alignment.Right, Alignment.Right, comp); + voteText.UserData = "votes"; + } + + 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); + if (vote == null) continue; + + var existingVotable = voteList.Find(v => v.First == vote); + if (existingVotable == null) + { + voteList.Add(Pair.Create(vote, 1)); + } + else + { + existingVotable.Second++; + } + } + return voteList; + } + + public T HighestVoted(VoteType voteType, List voters) + { + if (voteType == VoteType.Sub && !AllowSubVoting) return default(T); + if (voteType == VoteType.Mode && !AllowModeVoting) return default(T); + + List> voteList = GetVoteList(voteType,voters); + + T selected = default(T); + int highestVotes = 0; + foreach (Pair votable in voteList) + { + if (selected == null || votable.Second > highestVotes) + { + highestVotes = votable.Second; + selected = (T)votable.First; + } + } + + return selected; + } + + public void WriteData(NetOutgoingMessage msg, List voters) + { + msg.Write(allowSubVoting); + + if (allowSubVoting) + { + List> voteList = GetVoteList(VoteType.Sub, voters); + msg.Write((byte)voteList.Count); + foreach (Pair vote in voteList) + { + if (vote.Second < 1 || vote.First==null) continue; + msg.Write((byte)vote.Second); + msg.Write(((Submarine)vote.First).Name); + } + } + + + msg.Write(AllowModeVoting); + if (allowModeVoting) + { + List> voteList = GetVoteList(VoteType.Mode, voters); + msg.Write((byte)voteList.Count); + foreach (Pair vote in voteList) + { + if (vote.Second < 1 || vote.First == null) continue; + msg.Write((byte)vote.Second); + msg.Write(((GameModePreset)vote.First).Name); + } + } + + + + } + + public void ReadData(NetIncomingMessage msg) + { + AllowSubVoting = msg.ReadBoolean(); + if (allowSubVoting) + { + int votableCount = msg.ReadByte(); + for (int i = 0; i sm.Name == subName); + SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes); + } + } + + AllowModeVoting = msg.ReadBoolean(); + if (allowModeVoting) + { + int votableCount = msg.ReadByte(); + for (int i = 0; i < votableCount; i++) + { + int votes = msg.ReadByte(); + string modeName = msg.ReadString(); + GameModePreset mode = GameModePreset.list.Find(m => m.Name == modeName); + SetVoteText(GameMain.NetLobbyScreen.SubList, mode, votes); + } + } + } + } +} diff --git a/Subsurface/Source/Screens/ServerListScreen.cs b/Subsurface/Source/Screens/ServerListScreen.cs index 379ffcfbb..20c7aa855 100644 --- a/Subsurface/Source/Screens/ServerListScreen.cs +++ b/Subsurface/Source/Screens/ServerListScreen.cs @@ -65,11 +65,13 @@ namespace Barotrauma if (n > 0) columnX[n] += columnX[n - 1]; } - new GUITextBlock(new Rectangle(middleX, 30, 0, 30), "Password", GUI.Style, menu); + SpriteFont font = serverList.Rect.Width < 400 ? GUI.SmallFont : GUI.Font; - 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), "Round started", GUI.Style, menu); + new GUITextBlock(new Rectangle(middleX, 30, 0, 30), "Password", GUI.Style, menu).Font = font; + + new GUITextBlock(new Rectangle(middleX + columnX[0], 30, 0, 30), "Name", GUI.Style, menu).Font = font; + new GUITextBlock(new Rectangle(middleX + columnX[1], 30, 0, 30), "Players", GUI.Style, menu).Font = font; + new GUITextBlock(new Rectangle(middleX + columnX[2], 30, 0, 30), "Round started", GUI.Style, menu).Font = font; joinButton = new GUIButton(new Rectangle(-170, 0, 150, 30), "Refresh", Alignment.BottomRight, GUI.Style, menu); joinButton.OnClicked = RefreshServers; diff --git a/Subsurface/Source/Screens/sygwkgy0.iv5 b/Subsurface/Source/Screens/sygwkgy0.iv5 new file mode 100644 index 000000000..20c7aa855 --- /dev/null +++ b/Subsurface/Source/Screens/sygwkgy0.iv5 @@ -0,0 +1,337 @@ +using System; +using Lidgren.Network; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Barotrauma.Networking; +using FarseerPhysics; +using FarseerPhysics.Factories; +using FarseerPhysics.Dynamics; +using System.IO; +using System.Collections.Generic; +using RestSharp; + +namespace Barotrauma +{ + 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; + + private GUIButton joinButton; + + 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(GameMain.GraphicsWidth - 160, 1000); + int height = Math.Min(GameMain.GraphicsHeight - 160, 700); + + Rectangle panelRect = new Rectangle(0, 0, width, height); + + menu = new GUIFrame(panelRect, null, Alignment.Center, GUI.Style); + menu.Padding = new Vector4(40.0f, 40.0f, 40.0f, 20.0f); + + 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,height-160), GUI.Style, menu); + serverList.OnSelected = SelectServer; + + 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]; + } + + SpriteFont font = serverList.Rect.Width < 400 ? GUI.SmallFont : GUI.Font; + + new GUITextBlock(new Rectangle(middleX, 30, 0, 30), "Password", GUI.Style, menu).Font = font; + + new GUITextBlock(new Rectangle(middleX + columnX[0], 30, 0, 30), "Name", GUI.Style, menu).Font = font; + new GUITextBlock(new Rectangle(middleX + columnX[1], 30, 0, 30), "Players", GUI.Style, menu).Font = font; + new GUITextBlock(new Rectangle(middleX + columnX[2], 30, 0, 30), "Round started", GUI.Style, menu).Font = font; + + 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; + + GUIButton button = new GUIButton(new Rectangle(-20, -20, 100, 30), "Back", Alignment.TopLeft, GUI.Style, menu); + button.OnClicked = GameMain.MainMenuScreen.SelectTab; + button.CanBeSelected = false; + button.SelectedColor = button.Color; + + refreshDisableTimer = DateTime.Now; + } + + public override void Select() + { + base.Select(); + + + RefreshServers(null, null); + } + + private bool SelectServer(GUIComponent component, object obj) + { + string ip = obj as string; + if (string.IsNullOrWhiteSpace(ip)) return false; + + ipBox.Text = ip; + + return true; + } + + private bool RefreshServers(GUIButton button, object obj) + { + 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 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 CoroutineStatus.Success; + } + + private void UpdateServerList(string masterServerData) + { + serverList.ClearChildren(); + + //string masterServerData = GetMasterServerData(); + + if (string.IsNullOrWhiteSpace(masterServerData)) + { + var nameText = new GUITextBlock(new Rectangle(0, 0, 0, 20), "Couldn't find any servers", GUI.Style, serverList); + + return; + } + + if (masterServerData.Substring(0,5).ToLower()=="error") + { + DebugConsole.ThrowError("Error while connecting to master server ("+masterServerData+")!"); + + return; + } + + string[] lines = masterServerData.Split('\n'); + + for (int i = 0; i 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 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(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 IEnumerable SendMasterServerRequest() + { + RestClient client = null; + try + { + client = new RestClient(NetConfig.MasterServerUrl); + } + catch (Exception e) + { + DebugConsole.ThrowError("Error while connecting to master server", e); + } + + if (client == null) yield return CoroutineStatus.Success; + + + var request = new RestRequest("masterserver.php", Method.GET); + request.AddParameter("gamename", "barotrauma"); // adds to POST or URL querystring based on Method + request.AddParameter("action", "listservers"); // adds to POST or URL querystring based on Method + + + // easily add HTTP Headers + //request.AddHeader("header", "value"); + + //// add files to upload (works with compatible verbs) + //request.AddFile(path); + + // execute the 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 CoroutineStatus.Running; + } + + yield return CoroutineStatus.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; + } + + UpdateServerList(response.Content); + } + + private bool JoinServer(GUIButton button, object obj) + { + if (string.IsNullOrWhiteSpace(clientNameBox.Text)) + { + clientNameBox.Flash(); + return false; + } + + string ip = ipBox.Text; + + if (string.IsNullOrWhiteSpace(ip)) + { + ipBox.Flash(); + return false; + } + + 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,40,150,25), Alignment.TopLeft, GUI.Style, msgBox); + passwordBox.UserData = "password"; + + var okButton = msgBox.GetChild(); + + while (GUIMessageBox.MessageBoxes.Contains(msgBox)) + { + okButton.Enabled = !string.IsNullOrWhiteSpace(passwordBox.Text); + yield return CoroutineStatus.Running; + } + + selectedPassword = passwordBox.Text; + } + + GameMain.NetworkMember = new GameClient(clientNameBox.Text); + GameMain.Client.ConnectToServer(ip, selectedPassword); + + yield return CoroutineStatus.Success; + } + + public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) + { + graphics.Clear(Color.CornflowerBlue); + + GameMain.GameScreen.DrawMap(graphics, spriteBatch); + + spriteBatch.Begin(); + + menu.Draw(spriteBatch); + + //if (previewPlayer!=null) previewPlayer.Draw(spriteBatch); + + GUI.Draw((float)deltaTime, spriteBatch, null); + + spriteBatch.End(); + } + + 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 bd538bd69..ddef81f8a 100644 --- a/Subsurface/Source/Sounds/AmbientSoundManager.cs +++ b/Subsurface/Source/Sounds/AmbientSoundManager.cs @@ -14,7 +14,7 @@ namespace Barotrauma None, StructureBlunt, StructureSlash, LimbBlunt, LimbSlash, LimbArmor, - Implode } + Implode, Pressure } public struct DamageSound { @@ -228,7 +228,11 @@ namespace Barotrauma } List suitableMusic = null; - if (criticalTask == null) + if (Submarine.Loaded!=null && Submarine.Loaded.Position.Y<0.0f) + { + suitableMusic = musicClips.Where(x => x != null && x.type == "deep").ToList(); + } + else if (criticalTask == null) { suitableMusic = musicClips.Where(x => x != null && x.type == "default").ToList(); } @@ -278,7 +282,7 @@ namespace Barotrauma PlayDamageSound(damageType, damage, bodyPosition); } - public static void PlayDamageSound(DamageSoundType damageType, float damage, Vector2 position) + public static void PlayDamageSound(DamageSoundType damageType, float damage, Vector2 position, float range = 2000.0f) { damage = MathHelper.Clamp(damage+Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f); var sounds = damageSounds.Where(x => damage >= x.damageRange.X && damage <= x.damageRange.Y && x.damageType == damageType).ToList(); @@ -291,7 +295,7 @@ namespace Barotrauma { if (i == selectedSound) { - s.sound.Play(1.0f, 2000.0f, position); + s.sound.Play(1.0f, range, position); Debug.WriteLine("playing: " + s.sound); return; } diff --git a/Subsurface/Source/Utils/ToolBox.cs b/Subsurface/Source/Utils/ToolBox.cs index ea76459eb..5afb9de85 100644 --- a/Subsurface/Source/Utils/ToolBox.cs +++ b/Subsurface/Source/Utils/ToolBox.cs @@ -10,6 +10,21 @@ using System.Xml.Linq; namespace Barotrauma { + public class Pair + { + public T1 First { get; set; } + public T2 Second { get; set; } + + public static Pair Create(T1 first, T2 second) + { + Pair pair = new Pair(); + pair.First = first; + pair.Second = second; + + return pair; + } + } + public static class ToolBox { public static XDocument TryLoadXml(string filePath) diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 90718df32..6a685082e 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ