diff --git a/.gitignore b/.gitignore index ee3a6b563..caabdf211 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ bld/ [Oo]bj/ *.v12.suo +*.suo #performance reports & sessions *.vsp diff --git a/.vs/Subsurface_Solution/v14/.suo b/.vs/Subsurface_Solution/v14/.suo index 195ff13d2..188fc21d5 100644 Binary files a/.vs/Subsurface_Solution/v14/.suo and b/.vs/Subsurface_Solution/v14/.suo differ diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 68a2ac24e..44af133a5 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -118,6 +118,7 @@ + @@ -143,6 +144,7 @@ + @@ -152,6 +154,7 @@ + @@ -491,6 +494,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -1086,6 +1095,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/Subsurface/Content/Items/Door/dockingport.png b/Subsurface/Content/Items/Door/dockingport.png new file mode 100644 index 000000000..6538ddf08 Binary files /dev/null and b/Subsurface/Content/Items/Door/dockingport.png differ diff --git a/Subsurface/Content/Items/Door/dockingport1.ogg b/Subsurface/Content/Items/Door/dockingport1.ogg new file mode 100644 index 000000000..3d9aea42e Binary files /dev/null and b/Subsurface/Content/Items/Door/dockingport1.ogg differ diff --git a/Subsurface/Content/Items/Door/dockingport2.ogg b/Subsurface/Content/Items/Door/dockingport2.ogg new file mode 100644 index 000000000..8795bf1fb Binary files /dev/null and b/Subsurface/Content/Items/Door/dockingport2.ogg differ diff --git a/Subsurface/Content/Items/Door/dockingport2.png b/Subsurface/Content/Items/Door/dockingport2.png new file mode 100644 index 000000000..2862aaf62 Binary files /dev/null and b/Subsurface/Content/Items/Door/dockingport2.png differ diff --git a/Subsurface/Content/Items/Door/doors.xml b/Subsurface/Content/Items/Door/doors.xml index e628549ff..3b709c5e1 100644 --- a/Subsurface/Content/Items/Door/doors.xml +++ b/Subsurface/Content/Items/Door/doors.xml @@ -82,4 +82,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Subsurface/Content/Items/Engine/engine.png b/Subsurface/Content/Items/Engine/engine.png index ff3ed0c09..a99150aa1 100644 Binary files a/Subsurface/Content/Items/Engine/engine.png and b/Subsurface/Content/Items/Engine/engine.png differ diff --git a/Subsurface/Content/Items/Engine/engine.xml b/Subsurface/Content/Items/Engine/engine.xml index 51a20b46b..c7739754e 100644 --- a/Subsurface/Content/Items/Engine/engine.xml +++ b/Subsurface/Content/Items/Engine/engine.xml @@ -8,7 +8,7 @@ pickthroughwalls="true" pickdistance="150"> - + @@ -29,6 +29,34 @@ + + + + + + + + + + + + + + + + + + + + + + + - - + - - + @@ -100,8 +98,7 @@ - - + diff --git a/Subsurface/Source/Camera.cs b/Subsurface/Source/Camera.cs index 0c48b5ecc..7a3ab5361 100644 --- a/Subsurface/Source/Camera.cs +++ b/Subsurface/Source/Camera.cs @@ -1,6 +1,7 @@ using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; +using System.Linq; namespace Barotrauma { @@ -124,10 +125,10 @@ namespace Barotrauma public void Translate(Vector2 amount) { position += amount; - //UpdateTransform(); + } - public void UpdateTransform(bool interpolate = true) + public void UpdateTransform(bool interpolate = true, bool clampPos = false) { Vector2 interpolatedPosition = interpolate ? Physics.Interpolate(prevPosition, position) : position; @@ -136,6 +137,13 @@ namespace Barotrauma worldView.X = (int)(interpolatedPosition.X - worldView.Width / 2.0); worldView.Y = (int)(interpolatedPosition.Y + worldView.Height / 2.0); + + if (Level.Loaded != null && clampPos) + { + position.Y -= Math.Max(worldView.Y - Level.Loaded.Size.Y, 0.0f); + interpolatedPosition.Y -= Math.Max(worldView.Y - Level.Loaded.Size.Y, 0.0f); + } + transform = Matrix.CreateTranslation( new Vector3(-interpolatedPosition.X, interpolatedPosition.Y, 0)) * Matrix.CreateScale(new Vector3(interpolatedZoom, interpolatedZoom, 1)) * @@ -178,9 +186,13 @@ namespace Barotrauma if (GameMain.Config.KeyBind(InputType.Up).IsDown()) moveCam.Y += moveSpeed; } - if (Submarine.Loaded!=null && Screen.Selected == GameMain.GameScreen) + if (Screen.Selected == GameMain.GameScreen) { - moveCam += FarseerPhysics.ConvertUnits.ToDisplayUnits(Submarine.Loaded.Velocity*deltaTime); + var closestSub = Submarine.GetClosest(WorldViewCenter); + if (closestSub != null) + { + moveCam += FarseerPhysics.ConvertUnits.ToDisplayUnits(closestSub.Velocity * deltaTime); + } } moveCam = moveCam * deltaTime * 60.0f; @@ -205,14 +217,14 @@ namespace Barotrauma Vector2 diff = (targetPos + offset) - position; - moveCam = diff / MoveSmoothness; + moveCam = diff / MoveSmoothness; } shakeTargetPosition = Rand.Vector(Shake); shakePosition = Vector2.Lerp(shakePosition, shakeTargetPosition, 0.5f); - Shake = MathHelper.Lerp(Shake, 0.0f, deltaTime*2.0f); + Shake = MathHelper.Lerp(Shake, 0.0f, deltaTime * 2.0f); - Translate(moveCam+shakePosition); + Translate(moveCam + shakePosition); } public Vector2 Position diff --git a/Subsurface/Source/Characters/AI/HumanAIController.cs b/Subsurface/Source/Characters/AI/HumanAIController.cs index fe14ee52d..89b4cf85a 100644 --- a/Subsurface/Source/Characters/AI/HumanAIController.cs +++ b/Subsurface/Source/Characters/AI/HumanAIController.cs @@ -164,15 +164,15 @@ namespace Barotrauma GUI.DrawLine(spriteBatch, new Vector2(Character.WorldPosition.X, -Character.WorldPosition.Y), - new Vector2(pathSteering.CurrentPath.CurrentNode.Position.X+Submarine.Loaded.Position.X, -(pathSteering.CurrentPath.CurrentNode.Position.Y+Submarine.Loaded.Position.Y)), + new Vector2(pathSteering.CurrentPath.CurrentNode.WorldPosition.X, -pathSteering.CurrentPath.CurrentNode.WorldPosition.Y), Color.LightGreen); for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++) { GUI.DrawLine(spriteBatch, - new Vector2(pathSteering.CurrentPath.Nodes[i].Position.X + Submarine.Loaded.Position.X, -(pathSteering.CurrentPath.Nodes[i].Position.Y + Submarine.Loaded.Position.Y)), - new Vector2(pathSteering.CurrentPath.Nodes[i - 1].Position.X + Submarine.Loaded.Position.X, -(pathSteering.CurrentPath.Nodes[i-1].Position.Y + Submarine.Loaded.Position.Y)), + new Vector2(pathSteering.CurrentPath.Nodes[i].WorldPosition.X, -pathSteering.CurrentPath.Nodes[i].WorldPosition.Y), + new Vector2(pathSteering.CurrentPath.Nodes[i - 1].WorldPosition.Y, -pathSteering.CurrentPath.Nodes[i-1].WorldPosition.Y), Color.LightGreen); } } diff --git a/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs b/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs index f84ef8287..872c6b697 100644 --- a/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs +++ b/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs @@ -76,9 +76,13 @@ namespace Barotrauma currentTarget = target; Vector2 pos = host.SimPosition; - if (character!=null && character.Submarine==null) + if (character != null && character.Submarine == null) { - pos -= Submarine.Loaded.SimPosition; + var targetHull = Hull.FindHull(FarseerPhysics.ConvertUnits.ToDisplayUnits(target), null, false); + if (targetHull!=null && targetHull.Submarine != null) + { + pos -= targetHull.SimPosition; + } } currentPath = pathFinder.FindPath(pos, target); @@ -99,15 +103,15 @@ namespace Barotrauma private Vector2 DiffToCurrentNode() { - if (currentPath == null) return Vector2.Zero; + if (currentPath == null || currentPath.Finished) return Vector2.Zero; - if (currentPath.CurrentIndex == currentPath.Nodes.Count) + if (currentPath.Finished) { - Vector2 pos2 = host.SimPosition; - if (character != null && character.Submarine == null) + if (character != null && character.Submarine == null && CurrentPath.Nodes.Last().Submarine != null) { - pos2 -= Submarine.Loaded.SimPosition; + //todo: take multiple subs into account + pos2 -= CurrentPath.Nodes.Last().Submarine.SimPosition; } return currentTarget-pos2; } @@ -118,9 +122,11 @@ namespace Barotrauma if (currentPath.CurrentNode!=null && currentPath.CurrentNode.SimPosition.Y > character.SimPosition.Y+1.0f) allowedDistance*=0.5f; Vector2 pos = host.SimPosition; - if (character != null && character.Submarine == null) + if (character != null && character.Submarine == null && + CurrentPath.CurrentNode != null && CurrentPath.CurrentNode.Submarine != null) { - pos -= Submarine.Loaded.SimPosition; + //todo: take multiple subs into account + pos -= CurrentPath.CurrentNode.Submarine.SimPosition; } if (currentPath.CurrentNode!= null && currentPath.CurrentNode.Ladders!=null) diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs index 2c1e84ce5..bdb54cf88 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -89,7 +89,7 @@ namespace Barotrauma } else if (target.Submarine == null) { - currTargetPos -= Submarine.Loaded.SimPosition; + currTargetPos -= character.Submarine.SimPosition; } } diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveIdle.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveIdle.cs index fe7275824..559c70ac9 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveIdle.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveIdle.cs @@ -41,7 +41,7 @@ namespace Barotrauma if (currentTarget != null) { Vector2 pos = character.SimPosition; - if (character != null && character.Submarine == null) pos -= Submarine.Loaded.SimPosition; + if (character != null && character.Submarine == null) pos -= Submarine.MainSub.SimPosition; var path = pathSteering.PathFinder.FindPath(pos, currentTarget.SimPosition); if (path.Cost > 200.0f && character.AnimController.CurrentHull!=null) return; diff --git a/Subsurface/Source/Characters/AI/SteeringPath.cs b/Subsurface/Source/Characters/AI/SteeringPath.cs index 671421195..2a98ac366 100644 --- a/Subsurface/Source/Characters/AI/SteeringPath.cs +++ b/Subsurface/Source/Characters/AI/SteeringPath.cs @@ -70,6 +70,11 @@ namespace Barotrauma } } + public bool Finished + { + get { return currentIndex >= nodes.Count; } + } + public void SkipToNextNode() { currentIndex++; diff --git a/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs b/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs index f1e758669..af711d721 100644 --- a/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs +++ b/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs @@ -734,6 +734,10 @@ namespace Barotrauma { ladderSimPos += character.SelectedConstruction.Submarine.SimPosition; } + else if (currentHull.Submarine != null && currentHull.Submarine != character.SelectedConstruction.Submarine) + { + ladderSimPos += character.SelectedConstruction.Submarine.SimPosition - currentHull.Submarine.SimPosition; + } MoveLimb(head, new Vector2(ladderSimPos.X - 0.27f * Dir, head.SimPosition.Y + 0.05f), 10.5f); MoveLimb(torso, new Vector2(ladderSimPos.X - 0.27f * Dir, torso.SimPosition.Y), 10.5f); @@ -742,7 +746,9 @@ namespace Barotrauma Vector2 handPos = new Vector2( ladderSimPos.X, - head.SimPosition.Y + 0.0f + movement.Y * 0.1f - ladderSimPos.Y); + head.SimPosition.Y + movement.Y * 0.1f - ladderSimPos.Y); + + handPos.Y = Math.Min(-0.5f, handPos.Y); MoveLimb(leftHand, new Vector2(handPos.X, diff --git a/Subsurface/Source/Characters/Animation/Ragdoll.cs b/Subsurface/Source/Characters/Animation/Ragdoll.cs index 769d44ca9..25f020050 100644 --- a/Subsurface/Source/Characters/Animation/Ragdoll.cs +++ b/Subsurface/Source/Characters/Animation/Ragdoll.cs @@ -572,6 +572,7 @@ namespace Barotrauma if (setSubmarine) { + //in -> out if (newHull == null && currentHull.Submarine != null) { for (int i = -1; i < 2; i += 2) @@ -584,17 +585,23 @@ namespace Barotrauma if (Gap.FindAdjacent(currentHull.ConnectedGaps, findPos, 150.0f) != null) return; Teleport(ConvertUnits.ToSimUnits(currentHull.Submarine.Position), currentHull.Submarine.Velocity, true); - } + //out -> in else if (currentHull == null && newHull.Submarine != null) { Teleport(-ConvertUnits.ToSimUnits(newHull.Submarine.Position), -newHull.Submarine.Velocity, false); } + //from one sub to another + else if (newHull != null && currentHull != null && newHull.Submarine != currentHull.Submarine) + { + Teleport(ConvertUnits.ToSimUnits(currentHull.Submarine.Position - newHull.Submarine.Position), + Vector2.Zero, false); + } } CurrentHull = newHull; - character.Submarine = CurrentHull == null ? null : Submarine.Loaded; + character.Submarine = currentHull == null ? null : currentHull.Submarine; UpdateCollisionCategories(); } @@ -609,20 +616,7 @@ namespace Barotrauma while (ce != null && ce.Contact != null) { ce.Contact.Enabled = false; - //if (ce.Contact.IsTouching && ce.Contact.Enabled && - // ((inToOut && ce.Contact.FixtureA.Body.UserData is Structure) || (!inToOut && ce.Contact.FixtureA.Body.UserData is Submarine))) - //{ - // Vector2 normal; - // FarseerPhysics.Common.FixedArray2 worldPoints; - // ce.Contact.GetWorldManifold(out normal, out worldPoints); - // foreach (Limb limb2 in Limbs) - // { - // limb2.body.FarseerBody.ApplyLinearImpulse(limb2.Mass * normal); - // } - - // return false; - //} ce = ce.Next; } } @@ -632,7 +626,7 @@ namespace Barotrauma limb.body.LinearVelocity += velocityChange; } - character.Stun = 0.1f; + //character.Stun = 0.1f; character.DisableImpactDamageTimer = 0.25f; SetPosition(refLimb.SimPosition + moveAmount); diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index aa6d60c8f..995f9ecaa 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -855,7 +855,10 @@ namespace Barotrauma } cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition); - if (AnimController.CurrentHull != null) cursorPosition -= Submarine.Loaded.Position; + if (AnimController.CurrentHull != null && AnimController.CurrentHull.Submarine != null) + { + cursorPosition -= AnimController.CurrentHull.Submarine.Position; + } Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition); @@ -1006,12 +1009,9 @@ namespace Barotrauma if (needsAir) { bool protectedFromPressure = PressureProtection > 0.0f; - - if (Submarine.Loaded != null && Level.Loaded != null) - { - protectedFromPressure = protectedFromPressure && WorldPosition.Y > SubmarineBody.DamageDepth; - } + protectedFromPressure = protectedFromPressure && WorldPosition.Y > SubmarineBody.DamageDepth; + if (!protectedFromPressure && (AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure >= 80.0f)) { diff --git a/Subsurface/Source/Characters/Limb.cs b/Subsurface/Source/Characters/Limb.cs index 2a77e3192..049c30f8d 100644 --- a/Subsurface/Source/Characters/Limb.cs +++ b/Subsurface/Source/Characters/Limb.cs @@ -428,7 +428,7 @@ namespace Barotrauma { if (LightSource != null) { - LightSource.Submarine = body.Submarine; + LightSource.ParentSub = body.Submarine; LightSource.Position = Position; } diff --git a/Subsurface/Source/CoroutineManager.cs b/Subsurface/Source/CoroutineManager.cs index 7d9187e9c..a6b9929d5 100644 --- a/Subsurface/Source/CoroutineManager.cs +++ b/Subsurface/Source/CoroutineManager.cs @@ -86,21 +86,21 @@ namespace Barotrauma } } - try - { + //try + //{ Coroutines[i].Coroutine.MoveNext(); - } + //} - catch (Exception e) - { - DebugConsole.ThrowError("Coroutine " + Coroutines[i].Name + " threw an exception: " + e.Message); + //catch (Exception e) + //{ + // DebugConsole.ThrowError("Coroutine " + Coroutines[i].Name + " threw an exception: " + e.Message); -#if DEBUG - throw e; -#endif +//#if DEBUG +// throw e; +//#endif - Coroutines.RemoveAt(i); - } +// Coroutines.RemoveAt(i); +// } } } diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs index d6d5ffd54..76ccb4097 100644 --- a/Subsurface/Source/DebugConsole.cs +++ b/Subsurface/Source/DebugConsole.cs @@ -213,8 +213,6 @@ namespace Barotrauma break; case "near": case "close": - if (Submarine.Loaded == null) break; - float closestDist = 0.0f; foreach (WayPoint wp in WayPoint.WayPointList) { @@ -223,7 +221,7 @@ namespace Barotrauma //don't spawn inside hulls if (Hull.FindHull(wp.WorldPosition, null) != null) continue; - float dist = Vector2.Distance(wp.WorldPosition, Submarine.Loaded.WorldPosition); + float dist = Vector2.Distance(wp.WorldPosition, GameMain.GameScreen.Cam.WorldViewCenter); if (spawnPoint == null || dist < closestDist) { @@ -298,12 +296,12 @@ namespace Barotrauma case "edit": if (commands.Length>1) { - Submarine.Load(string.Join(" ", commands.Skip(1))); + Submarine.Load(string.Join(" ", commands.Skip(1)), true); } GameMain.EditMapScreen.Select(); break; case "test": - Submarine.Load("aegir mark ii"); + Submarine.Load("aegir mark ii", true); GameMain.DebugDraw = true; GameMain.LightManager.LosEnabled = false; GameMain.EditMapScreen.Select(); @@ -319,7 +317,9 @@ namespace Barotrauma Character.Controlled = Character.CharacterList.Find(c => !c.IsNetworkPlayer && c.Name.ToLowerInvariant() == commands[1]); break; case "godmode": - Submarine.Loaded.GodMode = !Submarine.Loaded.GodMode; + if (Submarine.MainSub == null) return; + + Submarine.MainSub.GodMode = !Submarine.MainSub.GodMode; break; case "dumpids": int count = commands.Length < 2 ? 10 : int.Parse(commands[1]); @@ -438,8 +438,11 @@ namespace Barotrauma return; } - if (Submarine.SaveCurrent(System.IO.Path.Combine(Submarine.SavePath, fileName +".sub"))) NewMessage("map saved", Color.Green); - Submarine.Loaded.CheckForErrors(); + if (Submarine.SaveCurrent(System.IO.Path.Combine(Submarine.SavePath, fileName + ".sub"))) + { + NewMessage("Sub saved", Color.Green); + //Submarine.Loaded.First().CheckForErrors(); + } break; case "loadmap": @@ -447,10 +450,10 @@ namespace Barotrauma case "load": if (commands.Length < 2) break; - Submarine.Load(string.Join(" ", commands.Skip(1))); + Submarine.Load(string.Join(" ", commands.Skip(1)), true); break; case "cleansub": - for (int i = MapEntity.mapEntityList.Count-1; i>=0; i--) + for (int i = MapEntity.mapEntityList.Count - 1; i >= 0; i--) { MapEntity me = MapEntity.mapEntityList[i]; diff --git a/Subsurface/Source/Events/ArtifactEvent.cs b/Subsurface/Source/Events/ArtifactEvent.cs index eec8653d0..2ce06c449 100644 --- a/Subsurface/Source/Events/ArtifactEvent.cs +++ b/Subsurface/Source/Events/ArtifactEvent.cs @@ -55,7 +55,7 @@ namespace Barotrauma state = 2; break; case 2: - if (!Submarine.Loaded.AtEndPosition && !Submarine.Loaded.AtStartPosition) return; + if (!Submarine.MainSub.AtEndPosition && !Submarine.MainSub.AtStartPosition) return; Finished(); state = 3; diff --git a/Subsurface/Source/Events/Missions/CargoMission.cs b/Subsurface/Source/Events/Missions/CargoMission.cs index 27bb8dbe8..17002449c 100644 --- a/Subsurface/Source/Events/Missions/CargoMission.cs +++ b/Subsurface/Source/Events/Missions/CargoMission.cs @@ -96,7 +96,7 @@ namespace Barotrauma public override void End() { - if (Submarine.Loaded != null && Submarine.Loaded.AtEndPosition) + if (Submarine.MainSub != null && Submarine.MainSub.AtEndPosition) { int deliveredItemCount = items.Count(i => i.CurrentHull != null && i.Condition > 0.0f); diff --git a/Subsurface/Source/Events/Missions/MonsterMission.cs b/Subsurface/Source/Events/Missions/MonsterMission.cs index afab51956..503febcaa 100644 --- a/Subsurface/Source/Events/Missions/MonsterMission.cs +++ b/Subsurface/Source/Events/Missions/MonsterMission.cs @@ -44,7 +44,7 @@ namespace Barotrauma radarPosition = monster.Position; } else if (GameMain.Client == null) - { Vector2 diff = monster.WorldPosition-Submarine.Loaded.WorldPosition; + { Vector2 diff = monster.WorldPosition - Submarine.MainSub.WorldPosition; monster.Enabled = FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) < NetConfig.CharacterIgnoreDistance; } diff --git a/Subsurface/Source/Events/Missions/SalvageMission.cs b/Subsurface/Source/Events/Missions/SalvageMission.cs index b418cd62e..e0309ea79 100644 --- a/Subsurface/Source/Events/Missions/SalvageMission.cs +++ b/Subsurface/Source/Events/Missions/SalvageMission.cs @@ -69,7 +69,7 @@ namespace Barotrauma state = 1; break; case 1: - if (!Submarine.Loaded.AtEndPosition && !Submarine.Loaded.AtStartPosition) return; + if (!Submarine.MainSub.AtEndPosition && !Submarine.MainSub.AtStartPosition) return; ShowMessage(state); state = 2; break; diff --git a/Subsurface/Source/Events/MonsterEvent.cs b/Subsurface/Source/Events/MonsterEvent.cs index 1bd0e6eaa..7162c7937 100644 --- a/Subsurface/Source/Events/MonsterEvent.cs +++ b/Subsurface/Source/Events/MonsterEvent.cs @@ -83,7 +83,7 @@ namespace Barotrauma { if (monster.IsDead) continue; - if (!isStarted && Vector2.Distance(monster.WorldPosition, Submarine.Loaded.WorldPosition) < 5000.0f) isStarted = true; + if (!isStarted && Vector2.Distance(monster.WorldPosition, Submarine.MainSub.WorldPosition) < 5000.0f) isStarted = true; monstersDead = false; break; diff --git a/Subsurface/Source/GUI/GUI.cs b/Subsurface/Source/GUI/GUI.cs index 64b67e19d..eed1cbe28 100644 --- a/Subsurface/Source/GUI/GUI.cs +++ b/Subsurface/Source/GUI/GUI.cs @@ -414,10 +414,10 @@ namespace Barotrauma "Camera pos: " + GameMain.GameScreen.Cam.Position.ToPoint(), new Vector2(10, 40), Color.White); - if (Submarine.Loaded != null) + if (Submarine.MainSub != null) { spriteBatch.DrawString(SmallFont, - "Sub pos: " + Submarine.Loaded.Position.ToPoint(), + "Sub pos: " + Submarine.MainSub.Position.ToPoint(), new Vector2(10, 50), Color.White); } } diff --git a/Subsurface/Source/GUI/GUIDropDown.cs b/Subsurface/Source/GUI/GUIDropDown.cs index 01fd79766..a6bd02787 100644 --- a/Subsurface/Source/GUI/GUIDropDown.cs +++ b/Subsurface/Source/GUI/GUIDropDown.cs @@ -34,7 +34,7 @@ namespace Barotrauma if (parent != null) parent.AddChild(this); - button = new GUIButton(Rectangle.Empty, "", Color.White, Alignment.TopLeft, Alignment.TopLeft, null, this); + button = new GUIButton(Rectangle.Empty, text, Color.White, Alignment.TopLeft, Alignment.TopLeft, null, this); button.TextColor = Color.White; button.Color = Color.Black * 0.8f; diff --git a/Subsurface/Source/GUI/GUIImage.cs b/Subsurface/Source/GUI/GUIImage.cs index 1fb92135a..16dab4c83 100644 --- a/Subsurface/Source/GUI/GUIImage.cs +++ b/Subsurface/Source/GUI/GUIImage.cs @@ -83,12 +83,11 @@ namespace Barotrauma if (state == ComponentState.Hover) currColor = hoverColor; if (state == ComponentState.Selected) currColor = selectedColor; - if (sprite!=null) + if (sprite != null && sprite.Texture != null) { spriteBatch.Draw(sprite.Texture, new Vector2(rect.X, rect.Y), sourceRect, currColor * (currColor.A / 255.0f), 0.0f, Vector2.Zero, - Scale, SpriteEffects.None, 0.0f); - } - + Scale, SpriteEffects.None, 0.0f); + } DrawChildren(spriteBatch); } diff --git a/Subsurface/Source/GameSession/CrewManager.cs b/Subsurface/Source/GameSession/CrewManager.cs index 35261dd84..c9e2e3235 100644 --- a/Subsurface/Source/GameSession/CrewManager.cs +++ b/Subsurface/Source/GameSession/CrewManager.cs @@ -277,7 +277,7 @@ namespace Barotrauma listBox.ClearChildren(); characters.Clear(); - WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos); + WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); for (int i = 0; i < waypoints.Length; i++) { diff --git a/Subsurface/Source/GameSession/GameModes/SinglePlayerMode.cs b/Subsurface/Source/GameSession/GameModes/SinglePlayerMode.cs index 9e933d519..ce0f38c7f 100644 --- a/Subsurface/Source/GameSession/GameModes/SinglePlayerMode.cs +++ b/Subsurface/Source/GameSession/GameModes/SinglePlayerMode.cs @@ -53,7 +53,7 @@ namespace Barotrauma endShiftButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 220, 20, 200, 25), "End shift", Alignment.TopLeft, GUI.Style); endShiftButton.Font = GUI.SmallFont; - endShiftButton.OnClicked = EndShift; + endShiftButton.OnClicked = TryEndShift; for (int i = 0; i < 3; i++) { @@ -143,14 +143,14 @@ namespace Barotrauma CrewManager.Draw(spriteBatch); - if (Submarine.Loaded == null) return; + if (Submarine.MainSub == null) return; - if (Submarine.Loaded.AtEndPosition) + if (Submarine.MainSub.AtEndPosition) { endShiftButton.Text = "Enter " + Map.SelectedLocation.Name; endShiftButton.Draw(spriteBatch); } - else if (Submarine.Loaded.AtStartPosition) + else if (Submarine.MainSub.AtStartPosition) { endShiftButton.Text = "Enter " + Map.CurrentLocation.Name; endShiftButton.Draw(spriteBatch); @@ -199,7 +199,7 @@ namespace Barotrauma if (success) { - if (Submarine.Loaded.AtEndPosition) + if (Submarine.MainSub.AtEndPosition) { Map.MoveToNextLocation(); } @@ -236,11 +236,44 @@ namespace Barotrauma Submarine.Unload(); } + private bool TryEndShift(GUIButton button, object obj) + { + int subsNotDocked = Submarine.Loaded.Count(s => s != Submarine.MainSub && !s.DockedTo.Contains(Submarine.MainSub)); + + if (subsNotDocked > 0) + { + string msg = ""; + if (subsNotDocked == 1) + { + msg = "One of of your vessels hasn't been docked to " + Submarine.MainSub.Name + + ". If you leave now, you will permanently lose it." + + " Do you want to leave the vessel behind?"; + } + else + { + msg = "Some of of your vessels hasn't been docked to " + Submarine.MainSub.Name + + ". If you leave now, you will permanently lose them." + + " Do you want to leave the vessels behind?"; + } + + var msgBox = new GUIMessageBox("Warning", msg, new string[] {"Yes", "No"}); + msgBox.Buttons[0].OnClicked += EndShift; + msgBox.Buttons[0].OnClicked += msgBox.Close; + msgBox.Buttons[1].OnClicked += msgBox.Close; + } + else + { + EndShift(button, obj); + } + + return true; + } + private bool EndShift(GUIButton button, object obj) { isRunning = false; - var cinematic = new TransitionCinematic(Submarine.Loaded, GameMain.GameScreen.Cam, 5.0f); + var cinematic = new TransitionCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, 5.0f); SoundPlayer.OverrideMusicType = CrewManager.characters.Any(c => !c.IsDead) ? "endshift" : "crewdead"; @@ -253,12 +286,12 @@ namespace Barotrauma { while (cinematic.Running) { - if (Submarine.Loaded == null) yield return CoroutineStatus.Success; + if (Submarine.MainSub == null) yield return CoroutineStatus.Success; yield return CoroutineStatus.Running; } - if (Submarine.Loaded == null) yield return CoroutineStatus.Success; + if (Submarine.MainSub == null) yield return CoroutineStatus.Success; End(""); diff --git a/Subsurface/Source/GameSession/GameModes/TraitorMode.cs b/Subsurface/Source/GameSession/GameModes/TraitorMode.cs index 7051902a5..7c5d99018 100644 --- a/Subsurface/Source/GameSession/GameModes/TraitorMode.cs +++ b/Subsurface/Source/GameSession/GameModes/TraitorMode.cs @@ -95,7 +95,7 @@ namespace Barotrauma endMessage = traitorCharacter.Name + " was a traitor! "; endMessage += (traitorCharacter.Info.Gender == Gender.Male) ? "His" : "Her"; endMessage += " task was to assassinate " + targetCharacter.Name + ". "; - endMessage += (Submarine.Loaded.AtEndPosition) ? + endMessage += (Submarine.MainSub.AtEndPosition) ? "The task was unsuccessful - the has submarine reached its destination." : "The task was unsuccessful."; } diff --git a/Subsurface/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs b/Subsurface/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs index 228b79063..a600e0cfc 100644 --- a/Subsurface/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs +++ b/Subsurface/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs @@ -22,7 +22,7 @@ namespace Barotrauma.Tutorials //spawn some fish next to the player GameMain.GameScreen.BackgroundCreatureManager.SpawnSprites(2, - Submarine.Loaded.Position + Character.Controlled.Position); + Submarine.MainSub.Position + Character.Controlled.Position); yield return new WaitForSeconds(4.0f); @@ -276,7 +276,7 @@ namespace Barotrauma.Tutorials infoBox = CreateInfoFrame("Steer the submarine downwards, heading further into the cavern."); - while (Submarine.Loaded.WorldPosition.Y > 24600.0f) + while (Submarine.MainSub.WorldPosition.Y > 24600.0f) { yield return CoroutineStatus.Running; } @@ -300,7 +300,7 @@ namespace Barotrauma.Tutorials bool broken = false; do { - Submarine.Loaded.Velocity = Vector2.Zero; + Submarine.MainSub.Velocity = Vector2.Zero; moloch.AIController.SelectTarget(steering.Item.CurrentHull.AiTarget); Vector2 steeringDir = windows[0].WorldPosition - moloch.WorldPosition; @@ -349,7 +349,7 @@ namespace Barotrauma.Tutorials } } - Submarine.Loaded.GodMode = true; + Submarine.MainSub.GodMode = true; var capacitor1 = Item.ItemList.Find(i => i.HasTag("capacitor1")).GetComponent(); var capacitor2 = Item.ItemList.Find(i => i.HasTag("capacitor1")).GetComponent(); @@ -462,7 +462,7 @@ namespace Barotrauma.Tutorials yield return CoroutineStatus.Running; } - Submarine.Loaded.GodMode = false; + Submarine.MainSub.GodMode = false; infoBox = CreateInfoFrame("The creature has died. Now you should fix the damages in the control room: " + "Grab a welding tool from the closet in the railgun room."); @@ -588,7 +588,7 @@ namespace Barotrauma.Tutorials GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; GameMain.LightManager.LosEnabled = false; - var cinematic = new TransitionCinematic(Submarine.Loaded, GameMain.GameScreen.Cam, 5.0f); + var cinematic = new TransitionCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, 5.0f); while (cinematic.Running) { diff --git a/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialMode.cs b/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialMode.cs index 5a16434a4..d0b80c2ca 100644 --- a/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialMode.cs +++ b/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialMode.cs @@ -9,7 +9,7 @@ namespace Barotrauma public static void StartTutorial(TutorialType tutorialType) { - Submarine.Load("Content/Map/TutorialSub.sub", ""); + Submarine.Load("Content/Map/TutorialSub.sub", "", true); tutorialType.Initialize(); diff --git a/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialType.cs b/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialType.cs index 36af62a21..502ec7ec2 100644 --- a/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialType.cs +++ b/Subsurface/Source/GameSession/GameModes/Tutorials/TutorialType.cs @@ -36,7 +36,7 @@ namespace Barotrauma.Tutorials public virtual void Initialize() { - GameMain.GameSession = new GameSession(Submarine.Loaded, "", GameModePreset.list.Find(gm => gm.Name.ToLowerInvariant() == "tutorial")); + GameMain.GameSession = new GameSession(Submarine.MainSub, "", GameModePreset.list.Find(gm => gm.Name.ToLowerInvariant() == "tutorial")); (GameMain.GameSession.gameMode as TutorialMode).tutorialType = this; GameMain.GameSession.StartShift("tuto1"); diff --git a/Subsurface/Source/GameSession/GameSession.cs b/Subsurface/Source/GameSession/GameSession.cs index b16e0d567..28c67bb6a 100644 --- a/Subsurface/Source/GameSession/GameSession.cs +++ b/Subsurface/Source/GameSession/GameSession.cs @@ -68,6 +68,8 @@ namespace Barotrauma public GameSession(Submarine submarine, string saveFile, GameModePreset gameModePreset = null, string missionType="") { + Submarine.MainSub = submarine; + GameMain.GameSession = this; CrewManager = new CrewManager(); @@ -88,6 +90,8 @@ namespace Barotrauma public GameSession(Submarine selectedSub, string saveFile, XDocument doc) : this(selectedSub, saveFile) { + Submarine.MainSub = submarine; + GameMain.GameSession = this; CrewManager = new CrewManager(); @@ -121,7 +125,10 @@ namespace Barotrauma return; } - if (reloadSub || Submarine.Loaded != submarine) submarine.Load(); + if (reloadSub || Submarine.MainSub != submarine) submarine.Load(true); + + //var secondSub = new Submarine(submarine.FilePath, submarine.MD5Hash.Hash); + //secondSub.Load(false); if (level != null) { @@ -129,6 +136,8 @@ namespace Barotrauma submarine.SetPosition(level.StartPosition - new Vector2(0.0f, 2000.0f)); + //secondSub.SetPosition(level.EndPosition - new Vector2(0.0f, 2000.0f)); + GameMain.GameScreen.BackgroundCreatureManager.SpawnSprites(80); } diff --git a/Subsurface/Source/GameSession/InfoTextManager.cs b/Subsurface/Source/GameSession/InfoTextManager.cs index 3e28cfc0a..78bca7b25 100644 --- a/Subsurface/Source/GameSession/InfoTextManager.cs +++ b/Subsurface/Source/GameSession/InfoTextManager.cs @@ -51,7 +51,7 @@ namespace Barotrauma string text = infoList[Rand.Int(infoList.Count)]; - if (Submarine.Loaded!=null) text = text.Replace("[sub]", Submarine.Loaded.Name); + if (Submarine.MainSub != null) text = text.Replace("[sub]", Submarine.MainSub.Name); if (GameMain.GameSession != null && GameMain.GameSession.Map != null) { if (GameMain.GameSession.Map.CurrentLocation!=null) diff --git a/Subsurface/Source/GameSession/ShiftSummary.cs b/Subsurface/Source/GameSession/ShiftSummary.cs index 45c13bb6a..6c4c03c52 100644 --- a/Subsurface/Source/GameSession/ShiftSummary.cs +++ b/Subsurface/Source/GameSession/ShiftSummary.cs @@ -32,7 +32,7 @@ namespace Barotrauma bool singleplayer = GameMain.NetworkMember == null; bool gameOver = gameSession.CrewManager.characters.All(c => c.IsDead); - bool progress = Submarine.Loaded.AtEndPosition; + bool progress = Submarine.MainSub.AtEndPosition; GUIFrame frame = new GUIFrame(new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Black * 0.8f); diff --git a/Subsurface/Source/Items/Components/DockingPort.cs b/Subsurface/Source/Items/Components/DockingPort.cs new file mode 100644 index 000000000..83cd58e32 --- /dev/null +++ b/Subsurface/Source/Items/Components/DockingPort.cs @@ -0,0 +1,471 @@ +using FarseerPhysics; +using FarseerPhysics.Dynamics; +using FarseerPhysics.Dynamics.Joints; +using FarseerPhysics.Factories; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Barotrauma.Items.Components +{ + + class DockingPort : ItemComponent, IDrawableComponent + { + public static List list = new List(); + + private Sprite overlaySprite; + + private Vector2 distanceTolerance; + + private DockingPort dockingTarget; + + private float dockingState; + private int dockingDir; + + private Joint joint; + + private Hull[] hulls; + + private Body[] bodies; + + private Gap gap; + + private bool docked; + + [HasDefaultValue("32.0,32.0", false)] + public string DistanceTolerance + { + get { return ToolBox.Vector2ToString(distanceTolerance); } + set { distanceTolerance = ToolBox.ParseToVector2(value); } + } + + [HasDefaultValue(32.0f, false)] + public float DockedDistance + { + get; + set; + } + + [HasDefaultValue(true, false)] + public bool IsHorizontal + { + get; + set; + } + + public bool Docked + { + get + { + return docked; + } + set + { + if (!docked && value) + { + if (dockingTarget == null) AttemptDock(); + if (dockingTarget == null) return; + + docked = true; + } + else if (docked && !value) + { + Undock(); + } + + //base.IsActive = value; + } + } + + public DockingPort(Item item, XElement element) + : base(item, element) + { + // isOpen = false; + foreach (XElement subElement in element.Elements()) + { + string texturePath = ToolBox.GetAttributeString(subElement, "texture", ""); + switch (subElement.Name.ToString().ToLowerInvariant()) + { + case "sprite": + overlaySprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.ConfigFile)); + break; + } + } + + IsActive = true; + + list.Add(this); + } + + private DockingPort FindAdjacentPort() + { + foreach (DockingPort port in list) + { + if (port == this || port.item.Submarine == item.Submarine) continue; + + if (Math.Abs(port.item.WorldPosition.X - item.WorldPosition.X) > distanceTolerance.X) continue; + if (Math.Abs(port.item.WorldPosition.Y - item.WorldPosition.Y) > distanceTolerance.Y) continue; + + return port; + } + + return null; + } + + private void AttemptDock() + { + var adjacentPort = FindAdjacentPort(); + if (adjacentPort != null) Dock(adjacentPort); + } + + public void Dock(DockingPort target) + { + if (dockingTarget != null) + { + Undock(); + } + + PlaySound(ActionType.OnUse, item.WorldPosition); + + item.linkedTo.Add(target.item); + + if (!target.item.Submarine.DockedTo.Contains(item.Submarine)) target.item.Submarine.DockedTo.Add(item.Submarine); + if (!item.Submarine.DockedTo.Contains(target.item.Submarine)) item.Submarine.DockedTo.Add(target.item.Submarine); + + dockingTarget = target; + dockingTarget.dockingTarget = this; + + docked = true; + dockingTarget.Docked = true; + + if (Character.Controlled != null && + (Character.Controlled.Submarine == dockingTarget.item.Submarine || Character.Controlled.Submarine == item.Submarine)) + { + GameMain.GameScreen.Cam.Shake = Vector2.Distance(dockingTarget.item.Submarine.Velocity, item.Submarine.Velocity); + } + + dockingDir = IsHorizontal ? + Math.Sign(dockingTarget.item.WorldPosition.X - item.WorldPosition.X) : + Math.Sign(item.WorldPosition.Y - dockingTarget.item.WorldPosition.Y); + dockingTarget.dockingDir = -dockingDir; + + CreateJoint(false); + } + + + private void CreateJoint(bool useWeldJoint) + { + Vector2 offset = (IsHorizontal ? + Vector2.UnitX * Math.Sign(dockingTarget.item.WorldPosition.X - item.WorldPosition.X) : + Vector2.UnitY * Math.Sign(dockingTarget.item.WorldPosition.Y - item.WorldPosition.Y)); + offset *= DockedDistance * 0.5f; + + Vector2 pos1 = item.WorldPosition + offset; + + Vector2 pos2 = dockingTarget.item.WorldPosition - offset; + + if (useWeldJoint) + { + joint = JointFactory.CreateWeldJoint(GameMain.World, + item.Submarine.SubBody.Body, dockingTarget.item.Submarine.SubBody.Body, + ConvertUnits.ToSimUnits(pos1), FarseerPhysics.ConvertUnits.ToSimUnits(pos2), true); + + ((WeldJoint)joint).FrequencyHz = 1.0f; + } + else + { + var distanceJoint = JointFactory.CreateDistanceJoint(GameMain.World, + item.Submarine.SubBody.Body, dockingTarget.item.Submarine.SubBody.Body, + ConvertUnits.ToSimUnits(pos1), FarseerPhysics.ConvertUnits.ToSimUnits(pos2), true); + + distanceJoint.Length = 0.01f; + distanceJoint.Frequency = 1.0f; + distanceJoint.DampingRatio = 0.8f; + + joint = distanceJoint; + } + + + joint.CollideConnected = true; + } + + private void CreateHull() + { + var hullRects = new Rectangle[] { item.WorldRect, dockingTarget.item.WorldRect }; + var subs = new Submarine[] { item.Submarine, dockingTarget.item.Submarine }; + + hulls = new Hull[2]; + bodies = new Body[4]; + if (IsHorizontal) + { + if (hullRects[0].Center.X > hullRects[1].Center.X) + { + hullRects = new Rectangle[] { dockingTarget.item.WorldRect, item.WorldRect }; + subs = new Submarine[] { dockingTarget.item.Submarine,item.Submarine }; + } + + hullRects[0] = new Rectangle(hullRects[0].Center.X, hullRects[0].Y, ((int)DockedDistance / 2), hullRects[0].Height); + hullRects[1] = new Rectangle(hullRects[1].Center.X - ((int)DockedDistance / 2), hullRects[1].Y, ((int)DockedDistance / 2), hullRects[1].Height); + + for (int i = 0; i < 2;i++ ) + { + hullRects[i].Location -= (subs[i].WorldPosition - subs[i].HiddenSubPosition).ToPoint(); + hulls[i] = new Hull(MapEntityPrefab.list.Find(m => m.Name == "Hull"), hullRects[i], subs[i]); + hulls[i].AddToGrid(subs[i]); + + for (int j = 0; j < 2; j++) + { + bodies[i + j * 2] = BodyFactory.CreateEdge(GameMain.World, + ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X, hullRects[i].Y - hullRects[i].Height * j)), + ConvertUnits.ToSimUnits(new Vector2(hullRects[i].Right, hullRects[i].Y - hullRects[i].Height * j))); + } + } + + gap = new Gap(new Rectangle(hullRects[0].Right - 2, hullRects[0].Y, 4, hullRects[0].Height), true, subs[0]); + + gap.linkedTo.Clear(); + if (hulls[0].WorldRect.X < hulls[1].WorldRect.X) + { + gap.linkedTo.Add(hulls[0]); + gap.linkedTo.Add(hulls[1]); + } + else + { + gap.linkedTo.Add(hulls[1]); + gap.linkedTo.Add(hulls[0]); + } + + + } + else + { + if (hullRects[0].Center.Y > hullRects[1].Center.Y) + { + hullRects = new Rectangle[] { dockingTarget.item.WorldRect, item.WorldRect }; + subs = new Submarine[] { dockingTarget.item.Submarine, item.Submarine }; + } + + hullRects[0] = new Rectangle(hullRects[0].X, hullRects[0].Y + (int)(-hullRects[0].Height+DockedDistance)/2, hullRects[0].Width, ((int)DockedDistance / 2)); + hullRects[1] = new Rectangle(hullRects[1].X, hullRects[1].Y - hullRects[1].Height/2, hullRects[1].Width, ((int)DockedDistance / 2)); + + for (int i = 0; i < 2; i++) + { + hullRects[i].Location -= (subs[i].WorldPosition - subs[i].HiddenSubPosition).ToPoint(); + hulls[i] = new Hull(MapEntityPrefab.list.Find(m => m.Name == "Hull"), hullRects[i], subs[i]); + hulls[i].AddToGrid(subs[i]); + + //for (int j = 0; j < 2; j++) + //{ + // bodies[i + j * 2] = BodyFactory.CreateEdge(GameMain.World, + // ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X + hullRects[i].Width * j, hullRects[i].Y)), + // ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X + hullRects[i].Width * j, hullRects[i].Y-hullRects[i].Height))); + //} + } + + gap = new Gap(new Rectangle(hullRects[0].X, hullRects[0].Y+2, hullRects[0].Width, 4), false, subs[0]); + + gap.linkedTo.Clear(); + if (hulls[0].WorldRect.Y > hulls[1].WorldRect.Y) + { + gap.linkedTo.Add(hulls[0]); + gap.linkedTo.Add(hulls[1]); + } + else + { + gap.linkedTo.Add(hulls[1]); + gap.linkedTo.Add(hulls[0]); + } + } + + + foreach (Body body in bodies) + { + if (body == null) continue; + body.BodyType = BodyType.Static; + body.Friction = 0.5f; + + body.CollisionCategories = Physics.CollisionWall; + } + + + } + + private void Undock() + { + if (dockingTarget == null || !docked) return; + + PlaySound(ActionType.OnUse, item.WorldPosition); + + dockingTarget.item.Submarine.DockedTo.Remove(item.Submarine); + item.Submarine.DockedTo.Remove(dockingTarget.item.Submarine); + + item.linkedTo.Clear(); + + docked = false; + + dockingTarget.Undock(); + dockingTarget = null; + + if (joint != null) + { + GameMain.World.RemoveJoint(joint); + joint = null; + } + + if (hulls != null) + { + hulls[0].Remove(); + hulls[1].Remove(); + hulls = null; + } + + if (gap != null) + { + gap.Remove(); + gap = null; + } + + if (bodies!=null) + { + foreach (Body body in bodies) + { + if (body == null) continue; + GameMain.World.RemoveBody(body); + } + bodies = null; + } + + } + + public override void Update(float deltaTime, Camera cam) + { + + + if (dockingTarget == null) + { + dockingState = MathHelper.Lerp(dockingState, 0.0f, deltaTime * 10.0f); + if (dockingState < 0.01f) docked = false; + + item.SendSignal(0, "0", "state_out"); + + item.SendSignal(0, (FindAdjacentPort() != null) ? "1" : "0", "proximity_sensor"); + + } + else + { + if (joint is DistanceJoint) + { + item.SendSignal(0, "0", "state_out"); + + if (Vector2.Distance(joint.WorldAnchorA, joint.WorldAnchorB) < 0.05f) + { + GameMain.World.RemoveJoint(joint); + + PlaySound(ActionType.OnSecondaryUse, item.WorldPosition); + + CreateJoint(true); + CreateHull(); + } + dockingState = MathHelper.Lerp(dockingState, 0.5f, deltaTime * 10.0f); + } + else + { + item.SendSignal(0, "1", "state_out"); + + dockingState = MathHelper.Lerp(dockingState, 1.0f, deltaTime * 10.0f); + } + } + } + + public void Draw(SpriteBatch spriteBatch, bool editing) + { + if (dockingState == 0.0f) return; + + Vector2 drawPos = item.DrawPosition; + drawPos.Y = -drawPos.Y; + + var rect = overlaySprite.SourceRect; + + if (IsHorizontal) + { + drawPos.Y -= rect.Height / 2; + + if (dockingDir == 1) + { + spriteBatch.Draw(overlaySprite.Texture, + drawPos, + new Rectangle( + rect.Center.X + (int)(rect.Width / 2 * (1.0f - dockingState)), rect.Y, + (int)(rect.Width / 2 * dockingState), rect.Height), Color.White); + + } + else + { + spriteBatch.Draw(overlaySprite.Texture, + drawPos - Vector2.UnitX * (rect.Width / 2 * dockingState), + new Rectangle( + rect.X, rect.Y, + (int)(rect.Width / 2 * dockingState), rect.Height), Color.Red); + } + } + else + { + drawPos.X -= rect.Width / 2; + + if (dockingDir == 1) + { + spriteBatch.Draw(overlaySprite.Texture, + drawPos, + new Rectangle( + rect.X, rect.Y + rect.Height/2 + (int)(rect.Height / 2 * (1.0f - dockingState)), + rect.Width, (int)(rect.Height / 2 * dockingState)), Color.White); + + } + else + { + spriteBatch.Draw(overlaySprite.Texture, + drawPos - Vector2.UnitY * (rect.Height / 2 * dockingState), + new Rectangle( + rect.X, rect.Y, + rect.Width, (int)(rect.Height / 2 * dockingState)), Color.Red); + } + } + } + + protected override void RemoveComponentSpecific() + { + list.Remove(this); + } + + public override void OnMapLoaded() + { + if (!item.linkedTo.Any()) return; + + Item linkedItem = item.linkedTo.First() as Item; + if (linkedItem == null) return; + + DockingPort port = linkedItem.GetComponent(); + if (port != null) Dock(port); + } + + public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item sender, float power = 0.0f) + { + switch (connection.Name) + { + case "toggle": + Docked = !docked; + break; + case "set_active": + case "set_state": + Docked = signal != "0"; + break; + } + } + } +} diff --git a/Subsurface/Source/Items/Components/Door.cs b/Subsurface/Source/Items/Components/Door.cs index f9c33c541..ba75e1999 100644 --- a/Subsurface/Source/Items/Components/Door.cs +++ b/Subsurface/Source/Items/Components/Door.cs @@ -444,28 +444,31 @@ namespace Barotrauma.Items.Components if (connection.Name=="toggle") { - SetState(!isOpen, false); + SetState(!isOpen, false, true); } else if (connection.Name == "set_state") { - SetState(signal != "0", false); + SetState(signal != "0", false, true); } - - item.NewComponentEvent(this, false, true); } - private void SetState(bool state, bool isNetWorkMessage) + public void SetState(bool open, bool isNetworkMessage, bool sendNetworkMessage = false) { - if (GameMain.Client != null && !isNetWorkMessage) return; + if (GameMain.Client != null && !isNetworkMessage) return; - if (isStuck || isOpen == state) return; + if (isStuck || isOpen == open) return; PlaySound(ActionType.OnUse, item.WorldPosition); - isOpen = state; + isOpen = open; //opening a partially stuck door makes it less stuck if (isOpen) stuck = MathHelper.Clamp(stuck - 30.0f, 0.0f, 100.0f); + + if (sendNetworkMessage) + { + item.NewComponentEvent(this, false, true); + } } public override bool FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetBuffer message) diff --git a/Subsurface/Source/Items/Components/Holdable/Holdable.cs b/Subsurface/Source/Items/Components/Holdable/Holdable.cs index fffafd02e..4684d0a9e 100644 --- a/Subsurface/Source/Items/Components/Holdable/Holdable.cs +++ b/Subsurface/Source/Items/Components/Holdable/Holdable.cs @@ -101,7 +101,7 @@ namespace Barotrauma.Items.Components Msg = ""; } - if (attachedByDefault || (Screen.Selected == GameMain.EditMapScreen && Submarine.Loaded != null)) Use(1.0f); + if (attachedByDefault || (Screen.Selected == GameMain.EditMapScreen)) Use(1.0f); //holdAngle = ToolBox.GetAttributeFloat(element, "holdangle", 0.0f); diff --git a/Subsurface/Source/Items/Components/Holdable/RepairTool.cs b/Subsurface/Source/Items/Components/Holdable/RepairTool.cs index 63a4cdd7f..8b288773a 100644 --- a/Subsurface/Source/Items/Components/Holdable/RepairTool.cs +++ b/Subsurface/Source/Items/Components/Holdable/RepairTool.cs @@ -132,83 +132,19 @@ namespace Barotrauma.Items.Components IsActive = true; activeTimer = 0.1f; + Vector2 rayStart = ConvertUnits.ToSimUnits(item.WorldPosition); + Vector2 rayEnd = ConvertUnits.ToSimUnits(targetPosition); - for (int n = 0; n < 2; n++) + if (character.Submarine == null) { - Vector2 rayStart = ConvertUnits.ToSimUnits(item.WorldPosition); - Vector2 rayEnd = ConvertUnits.ToSimUnits(targetPosition); - - if (n == 0) + foreach (Submarine sub in Submarine.Loaded) { - //do a raycast in "submarine coordinates" - rayStart -= Submarine.Loaded.SimPosition; - rayEnd -= Submarine.Loaded.SimPosition; + Repair(rayStart - sub.SimPosition, rayEnd - sub.SimPosition, deltaTime, character, degreeOfSuccess, ignoredBodies); } - else - { - //do a raycast outside the sub if the character is outside - if (character.AnimController.CurrentHull != null) continue; - } - - Body targetBody = Submarine.PickBody(rayStart, rayEnd, ignoredBodies); - - pickedPosition = Submarine.LastPickedPosition; - - if (ExtinquishAmount > 0.0f && item.CurrentHull != null) - { - Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * Submarine.LastPickedFraction * 0.9f); - - displayPos += item.CurrentHull.Submarine.Position; - - Hull hull = Hull.FindHull(displayPos, item.CurrentHull); - if (hull != null) hull.Extinquish(deltaTime, ExtinquishAmount, displayPos); - } - - if (targetBody == null || targetBody.UserData == null) continue; - - Structure targetStructure; - Limb targetLimb; - Item targetItem; - if ((targetStructure = (targetBody.UserData as Structure)) != null) - { - if (!fixableEntities.Contains(targetStructure.Name)) continue; - - int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition)); - if (sectionIndex < 0) continue; - - targetStructure.HighLightSection(sectionIndex); - - targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess); - - //if the next section is small enough, apply the effect to it as well - //(to make it easier to fix a small "left-over" section) - for (int i = -1; i < 2; i += 2) - { - int nextSectionLength = targetStructure.SectionLength(sectionIndex + i); - if ((sectionIndex == 1 && i == -1) || - (sectionIndex == targetStructure.SectionCount - 2 && i == 1) || - (nextSectionLength > 0 && nextSectionLength < Structure.wallSectionSize * 0.3f)) - { - targetStructure.HighLightSection(sectionIndex + i); - targetStructure.AddDamage(sectionIndex + i, -StructureFixAmount * degreeOfSuccess); - } - } - - - } - else if ((targetLimb = (targetBody.UserData as Limb)) != null) - { - if (character.IsKeyDown(InputType.Aim)) - { - targetLimb.character.AddDamage(CauseOfDeath.Damage, -LimbFixAmount * degreeOfSuccess, character); - } - } - else if ((targetItem = (targetBody.UserData as Item)) != null) - { - targetItem.IsHighlighted = true; - - ApplyStatusEffects(ActionType.OnUse, targetItem.AllPropertyObjects, deltaTime); - } + } + else + { + Repair(rayStart - character.Submarine.SimPosition, rayEnd - character.Submarine.SimPosition, deltaTime, character, degreeOfSuccess, ignoredBodies); } GameMain.ParticleManager.CreateParticle(particles, item.WorldPosition + TransformedBarrelPos, @@ -217,6 +153,64 @@ namespace Barotrauma.Items.Components return true; } + private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List ignoredBodies) + { + if (ExtinquishAmount > 0.0f && item.CurrentHull != null) + { + Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * Submarine.LastPickedFraction * 0.9f); + + displayPos += item.CurrentHull.Submarine.Position; + + Hull hull = Hull.FindHull(displayPos, item.CurrentHull); + if (hull != null) hull.Extinquish(deltaTime, ExtinquishAmount, displayPos); + } + + Body targetBody = Submarine.PickBody(rayStart, rayEnd, ignoredBodies); + + if (targetBody == null || targetBody.UserData == null) return; + + Structure targetStructure; + Limb targetLimb; + Item targetItem; + if ((targetStructure = (targetBody.UserData as Structure)) != null) + { + if (!fixableEntities.Contains(targetStructure.Name)) return; + + int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition)); + if (sectionIndex < 0) return; + + targetStructure.HighLightSection(sectionIndex); + + targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess); + + //if the next section is small enough, apply the effect to it as well + //(to make it easier to fix a small "left-over" section) + for (int i = -1; i < 2; i += 2) + { + int nextSectionLength = targetStructure.SectionLength(sectionIndex + i); + if ((sectionIndex == 1 && i == -1) || + (sectionIndex == targetStructure.SectionCount - 2 && i == 1) || + (nextSectionLength > 0 && nextSectionLength < Structure.wallSectionSize * 0.3f)) + { + targetStructure.HighLightSection(sectionIndex + i); + targetStructure.AddDamage(sectionIndex + i, -StructureFixAmount * degreeOfSuccess); + } + } + + + } + else if ((targetLimb = (targetBody.UserData as Limb)) != null) + { + targetLimb.character.AddDamage(CauseOfDeath.Damage, -LimbFixAmount * degreeOfSuccess, user); + } + else if ((targetItem = (targetBody.UserData as Item)) != null) + { + targetItem.IsHighlighted = true; + + ApplyStatusEffects(ActionType.OnUse, targetItem.AllPropertyObjects, deltaTime); + } + } + public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective) { Gap leak = objective.OperateTarget as Gap; diff --git a/Subsurface/Source/Items/Components/Machines/Engine.cs b/Subsurface/Source/Items/Components/Machines/Engine.cs index a97d3030c..bf3be00fe 100644 --- a/Subsurface/Source/Items/Components/Machines/Engine.cs +++ b/Subsurface/Source/Items/Components/Machines/Engine.cs @@ -86,7 +86,7 @@ namespace Barotrauma.Items.Components { Vector2 currForce = new Vector2((force / 100.0f) * maxForce * (voltage / minVoltage), 0.0f); - Submarine.Loaded.ApplyForce(currForce); + item.Submarine.ApplyForce(currForce); if (item.CurrentHull != null) { diff --git a/Subsurface/Source/Items/Components/Machines/MiniMap.cs b/Subsurface/Source/Items/Components/Machines/MiniMap.cs index a03ecc9d2..55cef9917 100644 --- a/Subsurface/Source/Items/Components/Machines/MiniMap.cs +++ b/Subsurface/Source/Items/Components/Machines/MiniMap.cs @@ -36,6 +36,8 @@ namespace Barotrauma.Items.Components public override void DrawHUD(SpriteBatch spriteBatch, Character character) { + if (item.Submarine == null) return; + int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height; int x = GuiFrame.Rect.X; int y = GuiFrame.Rect.Y; @@ -48,12 +50,12 @@ namespace Barotrauma.Items.Components Rectangle miniMap = new Rectangle(x + 20, y + 40, width - 40, height - 60); - float size = Math.Min((float)miniMap.Width / (float)Submarine.Borders.Width, (float)miniMap.Height / (float)Submarine.Borders.Height); + float size = Math.Min((float)miniMap.Width / (float)item.Submarine.Borders.Width, (float)miniMap.Height / (float)item.Submarine.Borders.Height); foreach (Hull hull in Hull.hullList) { Rectangle hullRect = new Rectangle( - miniMap.X + (int)((hull.Rect.X - Submarine.HiddenSubPosition.X - Submarine.Borders.X) * size), - miniMap.Y - (int)((hull.Rect.Y - Submarine.HiddenSubPosition.Y - Submarine.Borders.Y) * size), + miniMap.X + (int)((hull.Rect.X - item.Submarine.HiddenSubPosition.X - item.Submarine.Borders.X) * size), + miniMap.Y - (int)((hull.Rect.Y - item.Submarine.HiddenSubPosition.Y - item.Submarine.Borders.Y) * size), (int)(hull.Rect.Width * size), (int)(hull.Rect.Height * size)); diff --git a/Subsurface/Source/Items/Components/Machines/Radar.cs b/Subsurface/Source/Items/Components/Machines/Radar.cs index be281b135..b35a82a98 100644 --- a/Subsurface/Source/Items/Components/Machines/Radar.cs +++ b/Subsurface/Source/Items/Components/Machines/Radar.cs @@ -124,38 +124,41 @@ namespace Barotrauma.Items.Components float radius = rect.Width / 2.0f; float displayScale = radius / range; - - if (DetectSubmarineWalls) + + foreach (Submarine submarine in Submarine.Loaded) { - for (int i = 0; i < Submarine.Loaded.HullVertices.Count; i++) - { - Vector2 start = ConvertUnits.ToDisplayUnits(Submarine.Loaded.HullVertices[i]); - Vector2 end = ConvertUnits.ToDisplayUnits(Submarine.Loaded.HullVertices[(i + 1) % Submarine.Loaded.HullVertices.Count]); + if (item.Submarine == submarine && !DetectSubmarineWalls) continue; - if (item.CurrentHull!=null) + for (int i = 0; i < submarine.HullVertices.Count; i++) + { + Vector2 start = ConvertUnits.ToDisplayUnits(submarine.HullVertices[i]); + Vector2 end = ConvertUnits.ToDisplayUnits(submarine.HullVertices[(i + 1) % submarine.HullVertices.Count]); + + if (item.Submarine == submarine) { start += Rand.Vector(500.0f); end += Rand.Vector(500.0f); } CreateBlipsForLine( - start + Submarine.Loaded.WorldPosition, - end + Submarine.Loaded.WorldPosition, + start + submarine.WorldPosition, + end + submarine.WorldPosition, radius, displayScale, 200.0f, 2.0f); } - } - else + + + if (item.Submarine != null && !DetectSubmarineWalls) { float simScale = displayScale * Physics.DisplayToSimRation; - Vector2 offset = ConvertUnits.ToSimUnits(Submarine.Loaded.WorldPosition - item.WorldPosition); + Vector2 offset = ConvertUnits.ToSimUnits(item.Submarine.WorldPosition - item.WorldPosition); - for (int i = 0; i < Submarine.Loaded.HullVertices.Count; i++) + for (int i = 0; i < item.Submarine.HullVertices.Count; i++) { - Vector2 start = (Submarine.Loaded.HullVertices[i] + offset) * simScale; + Vector2 start = (item.Submarine.HullVertices[i] + offset) * simScale; start.Y = -start.Y; - Vector2 end = (Submarine.Loaded.HullVertices[(i + 1) % Submarine.Loaded.HullVertices.Count] + offset) * simScale; + Vector2 end = (item.Submarine.HullVertices[(i + 1) % item.Submarine.HullVertices.Count] + offset) * simScale; end.Y = -end.Y; GUI.DrawLine(spriteBatch, center + start, center + end, Color.Green); diff --git a/Subsurface/Source/Items/Components/Machines/Steering.cs b/Subsurface/Source/Items/Components/Machines/Steering.cs index c625eeb59..b0afc57d6 100644 --- a/Subsurface/Source/Items/Components/Machines/Steering.cs +++ b/Subsurface/Source/Items/Components/Machines/Steering.cs @@ -33,8 +33,10 @@ namespace Barotrauma.Items.Components private float autopilotRayCastTimer; private float neutralBallastLevel; + + public Vector2? TargetPosition; - bool AutoPilot + public bool AutoPilot { get { return autoPilot; } set @@ -52,7 +54,7 @@ namespace Barotrauma.Items.Components if (pathFinder==null) pathFinder = new PathFinder(WayPoint.WayPointList, false); steeringPath = pathFinder.FindPath( ConvertUnits.ToSimUnits(item.WorldPosition), - ConvertUnits.ToSimUnits(Level.Loaded.EndPosition)); + TargetPosition == null ? ConvertUnits.ToSimUnits(Level.Loaded.EndPosition) : (Vector2)TargetPosition); } else { @@ -62,6 +64,12 @@ namespace Barotrauma.Items.Components } } + public bool MaintainPos + { + get { return maintainPosTickBox.Selected; } + set { maintainPosTickBox.Selected = value; } + } + [Editable, HasDefaultValue(0.5f, true)] public float NeutralBallastLevel @@ -128,7 +136,7 @@ namespace Barotrauma.Items.Components } } - if (voltage < minVoltage) return; + if (voltage < minVoltage && powerConsumption > 0.0f) return; if (autoPilot) { @@ -158,15 +166,15 @@ namespace Barotrauma.Items.Components GuiFrame.Update(1.0f / 60.0f); GuiFrame.Draw(spriteBatch); - if (voltage < minVoltage) return; + if (voltage < minVoltage && powerConsumption > 0.0f) return; Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40); //GUI.DrawRectangle(spriteBatch, velRect, Color.White, false); - if (Submarine.Loaded != null && Level.Loaded != null) + if (item.Submarine != null && Level.Loaded != null) { - Vector2 realWorldVelocity = ConvertUnits.ToDisplayUnits(Submarine.Loaded.Velocity * Physics.DisplayToRealWorldRatio) * 3.6f; - float realWorldDepth = Math.Abs(Submarine.Loaded.Position.Y - Level.Loaded.Size.Y) * Physics.DisplayToRealWorldRatio; + Vector2 realWorldVelocity = ConvertUnits.ToDisplayUnits(item.Submarine.Velocity * Physics.DisplayToRealWorldRatio) * 3.6f; + float realWorldDepth = Math.Abs(item.Submarine.Position.Y - Level.Loaded.Size.Y) * Physics.DisplayToRealWorldRatio; GUI.DrawString(spriteBatch, new Vector2(x + 20, y + height - 65), "Velocity: " + (int)realWorldVelocity.X + " km/h", Color.LightGreen, null, 0, GUI.SmallFont); GUI.DrawString(spriteBatch, new Vector2(x + 20, y + height - 50), @@ -220,7 +228,7 @@ namespace Barotrauma.Items.Components if (autopilotRayCastTimer <= 0.0f && steeringPath.NextNode != null) { - Vector2 diff = Vector2.Normalize(ConvertUnits.ToSimUnits(steeringPath.NextNode.Position - Submarine.Loaded.WorldPosition)); + Vector2 diff = Vector2.Normalize(ConvertUnits.ToSimUnits(steeringPath.NextNode.Position - item.Submarine.WorldPosition)); bool nextVisible = true; for (int x = -1; x < 2; x += 2) @@ -228,9 +236,9 @@ namespace Barotrauma.Items.Components for (int y = -1; y < 2; y += 2) { Vector2 cornerPos = - new Vector2(Submarine.Borders.Width * x, Submarine.Borders.Height * y) / 2.0f; + new Vector2(item.Submarine.Borders.Width * x, item.Submarine.Borders.Height * y) / 2.0f; - cornerPos = ConvertUnits.ToSimUnits(cornerPos * 1.2f + Submarine.Loaded.WorldPosition); + cornerPos = ConvertUnits.ToSimUnits(cornerPos * 1.2f + item.Submarine.WorldPosition); float dist = Vector2.Distance(cornerPos, steeringPath.NextNode.SimPosition); diff --git a/Subsurface/Source/Items/Components/Power/PowerContainer.cs b/Subsurface/Source/Items/Components/Power/PowerContainer.cs index f6400c72e..1fcf4a172 100644 --- a/Subsurface/Source/Items/Components/Power/PowerContainer.cs +++ b/Subsurface/Source/Items/Components/Power/PowerContainer.cs @@ -113,7 +113,7 @@ namespace Barotrauma.Items.Components public override void Update(float deltaTime, Camera cam) { float chargeRate = (float)(Math.Sqrt(charge / capacity)); - //float gridPower = 0.0f; + float gridPower = 0.0f; float gridLoad = 0.0f; //if (item.linkedTo.Count == 0) return; @@ -126,7 +126,8 @@ namespace Barotrauma.Items.Components PowerTransfer pt = c2.Item.GetComponent(); if (pt == null || !pt.IsActive) continue; - gridLoad += pt.PowerLoad; + gridLoad += pt.PowerLoad; + gridPower -= pt.CurrPowerConsumption; } } @@ -171,27 +172,21 @@ namespace Barotrauma.Items.Components // -maxOutput * chargeRate, // 0.1f); - if (outputVoltage < 1.0f) + if (gridPower < gridLoad) { + // CurrPowerOutput = MathHelper.Lerp( + //CurrPowerOutput, Math.Min(maxOutput * chargeRate, gridLoad), 0.05f); + CurrPowerOutput = MathHelper.Lerp( - CurrPowerOutput, Math.Min(maxOutput * chargeRate, gridLoad), 0.05f); + CurrPowerOutput, + Math.Min(maxOutput * chargeRate, gridLoad - (gridLoad * outputVoltage)), + 0.05f); } else { CurrPowerOutput = MathHelper.Lerp(CurrPowerOutput, 0.0f, 0.05f); } - CurrPowerOutput = MathHelper.Lerp( - CurrPowerOutput, - Math.Min(maxOutput * chargeRate, gridLoad - (gridLoad * outputVoltage)), - 0.05f); - - - - //powerConsumption = MathHelper.Lerp( - // powerConsumption, - // -Math.Min(maxOutput * chargeRate, gridLoad - (power)), - // 0.1f); //powerConsumption = Math.Min(powerConsumption, 0.0f); Charge -= CurrPowerOutput / 3600.0f; diff --git a/Subsurface/Source/Items/Components/Power/PowerTransfer.cs b/Subsurface/Source/Items/Components/Power/PowerTransfer.cs index c443b8e1d..3dbf0d3e4 100644 --- a/Subsurface/Source/Items/Components/Power/PowerTransfer.cs +++ b/Subsurface/Source/Items/Components/Power/PowerTransfer.cs @@ -62,6 +62,7 @@ namespace Barotrauma.Items.Components pt.powerLoad += (fullLoad - pt.powerLoad) / inertia; pt.currPowerConsumption += (-fullPower - pt.currPowerConsumption) / inertia; pt.Item.SendSignal(0, "", "power", fullPower / Math.Max(fullLoad, 1.0f)); + pt.Item.SendSignal(0, "", "power_out", fullPower / Math.Max(fullLoad, 1.0f)); //damage the item if voltage is too high //(except if running as a client) @@ -117,7 +118,6 @@ namespace Barotrauma.Items.Components { if (!c.IsPower) continue; - var recipients = c.Recipients; foreach (Connection recipient in recipients) @@ -138,7 +138,7 @@ namespace Barotrauma.Items.Components PowerContainer powerContainer = powered as PowerContainer; if (powerTransfer != null) { - if (powerTransfer.updateTimer>0) continue; + //if (powerTransfer.updateTimer>0) continue; powerTransfer.CheckJunctions(deltaTime); } else if (powerContainer != null) diff --git a/Subsurface/Source/Items/Components/Signal/LightComponent.cs b/Subsurface/Source/Items/Components/Signal/LightComponent.cs index 4fa63fdd7..a761383d3 100644 --- a/Subsurface/Source/Items/Components/Signal/LightComponent.cs +++ b/Subsurface/Source/Items/Components/Signal/LightComponent.cs @@ -102,7 +102,7 @@ namespace Barotrauma.Items.Components : base (item, element) { light = new LightSource(element); - light.Submarine = item.CurrentHull == null ? null : item.CurrentHull.Submarine; + light.ParentSub = item.CurrentHull == null ? null : item.CurrentHull.Submarine; light.Position = item.Position; light.CastShadows = castShadows; @@ -121,7 +121,7 @@ namespace Barotrauma.Items.Components { base.Update(deltaTime, cam); - light.Submarine = item.Submarine; + light.ParentSub = item.Submarine; ApplyStatusEffects(ActionType.OnActive, deltaTime); diff --git a/Subsurface/Source/Items/Components/Signal/SignalCheckComponent.cs b/Subsurface/Source/Items/Components/Signal/SignalCheckComponent.cs index b2e4133d9..82b7fa423 100644 --- a/Subsurface/Source/Items/Components/Signal/SignalCheckComponent.cs +++ b/Subsurface/Source/Items/Components/Signal/SignalCheckComponent.cs @@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components { class SignalCheckComponent : ItemComponent { - private string output; + private string output, falseOutput; private string targetSignal; @@ -14,6 +14,12 @@ namespace Barotrauma.Items.Components get { return output; } set { output = value; } } + [InGameEditable, HasDefaultValue("0", true)] + public string FalseOutput + { + get { return falseOutput; } + set { falseOutput = value; } + } [InGameEditable, HasDefaultValue("", true)] public string TargetSignal @@ -32,7 +38,10 @@ namespace Barotrauma.Items.Components switch (connection.Name) { case "signal_in": - item.SendSignal(stepsTaken, (signal == targetSignal) ? output : "0", "signal_out"); + string signalOut = (signal == targetSignal) ? output : falseOutput; + + if (string.IsNullOrWhiteSpace(signalOut)) return; + item.SendSignal(stepsTaken, signalOut, "signal_out"); break; case "set_output": diff --git a/Subsurface/Source/Items/Components/Signal/Wire.cs b/Subsurface/Source/Items/Components/Signal/Wire.cs index 9cb18be5f..a1bbe5540 100644 --- a/Subsurface/Source/Items/Components/Signal/Wire.cs +++ b/Subsurface/Source/Items/Components/Signal/Wire.cs @@ -109,6 +109,8 @@ namespace Barotrauma.Items.Components } } + item.Submarine = newConnection.Item.Submarine; + for (int i = 0; i < 2; i++) { if (connections[i] != null) continue; @@ -117,16 +119,18 @@ namespace Barotrauma.Items.Components if (!addNode) break; - if (Nodes.Count > 0 && Nodes[0] == newConnection.Item.Position - Submarine.HiddenSubPosition) break; - if (Nodes.Count > 1 && Nodes[Nodes.Count-1] == newConnection.Item.Position - Submarine.HiddenSubPosition) break; + if (Nodes.Count > 0 && Nodes[0] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break; + if (Nodes.Count > 1 && Nodes[Nodes.Count-1] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break; + + if (i == 0) { - Nodes.Insert(0, newConnection.Item.Position - Submarine.HiddenSubPosition); + Nodes.Insert(0, newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition); } else { - Nodes.Add(newConnection.Item.Position - Submarine.HiddenSubPosition); + Nodes.Add(newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition); } @@ -184,7 +188,7 @@ namespace Barotrauma.Items.Components { if (Nodes.Count == 0) return; - item.FindHull(); + //item.FindHull(); //Vector2 position = item.Position; @@ -200,7 +204,11 @@ namespace Barotrauma.Items.Components // position.Y += item.CurrentHull.Rect.Y - item.CurrentHull.Rect.Height; //} - newNodePos = RoundNode(item.Position, item.CurrentHull)-Submarine.HiddenSubPosition; + Submarine sub = null; + if (connections[0] != null && connections[0].Item.Submarine != null) sub = connections[0].Item.Submarine; + if (connections[1] != null && connections[1].Item.Submarine != null) sub = connections[1].Item.Submarine; + + newNodePos = RoundNode(item.Position, item.CurrentHull) - sub.HiddenSubPosition; //if (Vector2.Distance(position, nodes[nodes.Count - 1]) > nodeDistance*10) //{ @@ -366,7 +374,7 @@ namespace Barotrauma.Items.Components for (int i = 0; i < Nodes.Count; i++) { Vector2 worldPos = Nodes[i]; - if (Submarine.Loaded != null) worldPos += Submarine.Loaded.Position + Submarine.HiddenSubPosition; + if (item.Submarine != null) worldPos += item.Submarine.Position + item.Submarine.HiddenSubPosition; worldPos.Y = -worldPos.Y; GUI.DrawRectangle(spriteBatch, worldPos + new Vector2(-3, -3), new Vector2(6, 6), item.Color, true, 0.0f); @@ -407,7 +415,12 @@ namespace Barotrauma.Items.Components MapEntity.DisableSelect = true; //Nodes[(int)selectedNodeIndex] = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition)-Submarine.HiddenSubPosition+Submarine.Loaded.Position; - Vector2 nodeWorldPos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition) - Submarine.HiddenSubPosition - Submarine.Loaded.Position;// Nodes[(int)selectedNodeIndex]; + + Submarine sub = null; + if (connections[0] != null && connections[0].Item.Submarine != null) sub = connections[0].Item.Submarine; + if (connections[1] != null && connections[1].Item.Submarine != null) sub = connections[1].Item.Submarine; + + Vector2 nodeWorldPos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition) - sub.HiddenSubPosition - sub.Position;// Nodes[(int)selectedNodeIndex]; nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f); nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f); @@ -428,10 +441,10 @@ namespace Barotrauma.Items.Components private void DrawSection(SpriteBatch spriteBatch, Vector2 start, Vector2 end, Color color, float width = 0.3f) { - if (Submarine.Loaded!=null) + if (item.Submarine != null) { - start += Submarine.Loaded.DrawPosition + Submarine.HiddenSubPosition; - end += Submarine.Loaded.DrawPosition + Submarine.HiddenSubPosition; + start += item.Submarine.DrawPosition + item.Submarine.HiddenSubPosition; + end += item.Submarine.DrawPosition + item.Submarine.HiddenSubPosition; } start.Y = -start.Y; diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index 6ba173892..2f79d7a0a 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -19,7 +19,7 @@ namespace Barotrauma public enum ActionType { - Always, OnPicked, OnUse, + Always, OnPicked, OnUse, OnSecondaryUse, OnWearing, OnContaining, OnContained, OnActive, OnFailure, OnBroken, OnFire, InWater, @@ -523,9 +523,9 @@ namespace Barotrauma } CurrentHull = Hull.FindHull(WorldPosition, CurrentHull); - if (body != null) + if (body != null && body.Enabled) { - Submarine = CurrentHull == null ? null : Submarine.Loaded; + Submarine = CurrentHull == null ? null : CurrentHull.Submarine; body.Submarine = Submarine; } @@ -1248,6 +1248,7 @@ namespace Barotrauma { picked = true; ic.ApplyStatusEffects(ActionType.OnPicked, 1.0f, picker); + ic.PlaySound(ActionType.OnPicked, picker.WorldPosition); if (picker==Character.Controlled) GUIComponent.MouseOn = null; @@ -1432,12 +1433,14 @@ namespace Barotrauma return true; } - public override XElement Save(XDocument doc) + public override XElement Save(XElement parentElement) { XElement element = new XElement("Item"); element.Add(new XAttribute("name", prefab.Name), new XAttribute("ID", ID)); + + System.Diagnostics.Debug.Assert(Submarine != null); if (ResizeHorizontal || ResizeVertical) { @@ -1473,7 +1476,7 @@ namespace Barotrauma ic.Save(element); } - doc.Root.Add(element); + parentElement.Add(element); return element; } diff --git a/Subsurface/Source/Items/ItemPrefab.cs b/Subsurface/Source/Items/ItemPrefab.cs index e75d2e392..e23f345f3 100644 --- a/Subsurface/Source/Items/ItemPrefab.cs +++ b/Subsurface/Source/Items/ItemPrefab.cs @@ -109,7 +109,7 @@ namespace Barotrauma public override void UpdatePlacing(SpriteBatch spriteBatch, Camera cam) { - Vector2 position = Submarine.MouseToWorldGrid(cam); + Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub); if (PlayerInput.RightButtonClicked()) { @@ -121,10 +121,10 @@ namespace Barotrauma { if (PlayerInput.LeftButtonClicked()) { - var item = new Item(new Rectangle((int)position.X, (int)position.Y, (int)sprite.size.X, (int)sprite.size.Y), this, Submarine.Loaded); + var item = new Item(new Rectangle((int)position.X, (int)position.Y, (int)sprite.size.X, (int)sprite.size.Y), this, Submarine.MainSub); //constructor.Invoke(lobject); - item.Submarine = Submarine.Loaded; - item.SetTransform(ConvertUnits.ToSimUnits(Submarine.Loaded==null ? item.Position : item.Position - Submarine.Loaded.Position), 0.0f); + item.Submarine = Submarine.MainSub; + item.SetTransform(ConvertUnits.ToSimUnits(Submarine.MainSub==null ? item.Position : item.Position - Submarine.MainSub.Position), 0.0f); item.FindHull(); placePosition = Vector2.Zero; @@ -152,11 +152,11 @@ namespace Barotrauma if (PlayerInput.LeftButtonReleased()) { - var item = new Item(new Rectangle((int)placePosition.X, (int)placePosition.Y, (int)placeSize.X, (int)placeSize.Y), this, Submarine.Loaded); + var item = new Item(new Rectangle((int)placePosition.X, (int)placePosition.Y, (int)placeSize.X, (int)placeSize.Y), this, Submarine.MainSub); placePosition = Vector2.Zero; - item.Submarine = Submarine.Loaded; - item.SetTransform(ConvertUnits.ToSimUnits(Submarine.Loaded == null ? item.Position : item.Position - Submarine.Loaded.Position), 0.0f); + item.Submarine = Submarine.MainSub; + item.SetTransform(ConvertUnits.ToSimUnits(Submarine.MainSub == null ? item.Position : item.Position - Submarine.MainSub.Position), 0.0f); item.FindHull(); //selected = null; diff --git a/Subsurface/Source/Items/ItemSpawner.cs b/Subsurface/Source/Items/ItemSpawner.cs index 73a53a293..7899ba652 100644 --- a/Subsurface/Source/Items/ItemSpawner.cs +++ b/Subsurface/Source/Items/ItemSpawner.cs @@ -13,20 +13,20 @@ namespace Barotrauma spawnQueue = new Queue>(); } - public void QueueItem(ItemPrefab itemPrefab, Vector2 position, bool isNetworkMessage = false) - { - if (!isNetworkMessage && GameMain.Client!=null) - { - //clients aren't allowed to spawn new items unless the server says so - return; - } + //public void QueueItem(ItemPrefab itemPrefab, Vector2 position, bool isNetworkMessage = false) + //{ + // if (!isNetworkMessage && GameMain.Client!=null) + // { + // //clients aren't allowed to spawn new items unless the server says so + // return; + // } - var itemInfo = new Pair(); - itemInfo.First = itemPrefab; - itemInfo.Second = position; + // var itemInfo = new Pair(); + // itemInfo.First = itemPrefab; + // itemInfo.Second = position; - spawnQueue.Enqueue(itemInfo); - } + // spawnQueue.Enqueue(itemInfo); + //} public void QueueItem(ItemPrefab itemPrefab, Inventory inventory, bool isNetworkMessage = false) { @@ -54,15 +54,17 @@ namespace Barotrauma { var itemInfo = spawnQueue.Dequeue(); - if (itemInfo.Second is Vector2) - { - Vector2 position = (Vector2)itemInfo.Second - Submarine.HiddenSubPosition; + //if (itemInfo.Second is Vector2) + //{ + // //todo: take multiple subs into account + // Vector2 position = (Vector2)itemInfo.Second - Submarine.MainSub.HiddenSubPosition; - items.Add(new Item(itemInfo.First, position, null)); - inventories.Add(null); + // items.Add(new Item(itemInfo.First, position, null)); + // inventories.Add(null); - } - else if (itemInfo.Second is Inventory) + //} + //else + if (itemInfo.Second is Inventory) { var item = new Item(itemInfo.First, Vector2.Zero, null); diff --git a/Subsurface/Source/Map/Entity.cs b/Subsurface/Source/Map/Entity.cs index cad366b60..ccb0f386c 100644 --- a/Subsurface/Source/Map/Entity.cs +++ b/Subsurface/Source/Map/Entity.cs @@ -81,7 +81,7 @@ namespace Barotrauma //give an unique ID bool IDfound; - id = 1;//Rand.Int(int.MaxValue); + id = submarine == null ? (ushort)1 : submarine.IdOffset; do { id += 1; diff --git a/Subsurface/Source/Map/EntityGrid.cs b/Subsurface/Source/Map/EntityGrid.cs index b5b5b9d90..efd1088ef 100644 --- a/Subsurface/Source/Map/EntityGrid.cs +++ b/Subsurface/Source/Map/EntityGrid.cs @@ -12,9 +12,12 @@ namespace Barotrauma private float cellSize; - public EntityGrid(Rectangle limits, float cellSize) + public readonly Submarine Submarine; + + public EntityGrid(Submarine submarine, float cellSize) { - this.limits = limits; + this.limits = submarine.Borders; + this.Submarine = submarine; this.cellSize = cellSize; entities = new List[(int)Math.Ceiling(limits.Width / cellSize), (int)Math.Ceiling(limits.Height / cellSize)]; @@ -71,11 +74,28 @@ namespace Barotrauma } } + public static List GetEntities(List entityGrids, Vector2 position, bool useWorldCoordinates = true) + { + List entities = new List(); + foreach (EntityGrid entityGrid in entityGrids) + { + Vector2 transformedPosition = position; + if (useWorldCoordinates) + { + transformedPosition -= entityGrid.Submarine.Position; + } + + entities.AddRange(entityGrid.GetEntities(transformedPosition)); + } + + return entities; + } + public List GetEntities(Vector2 position) { if (!MathUtils.IsValid(position)) new List(); - if (Submarine.Loaded != null) position -= Submarine.HiddenSubPosition; + if (Submarine != null) position -= Submarine.HiddenSubPosition; Point indices = GetIndices(position); diff --git a/Subsurface/Source/Map/Gap.cs b/Subsurface/Source/Map/Gap.cs index 930cb574c..7c266cac7 100644 --- a/Subsurface/Source/Map/Gap.cs +++ b/Subsurface/Source/Map/Gap.cs @@ -83,7 +83,7 @@ namespace Barotrauma } public Gap(MapEntityPrefab prefab, Rectangle rectangle) - : this (rectangle, Submarine.Loaded) + : this (rectangle, Submarine.MainSub) { } public Gap(Rectangle newRect, Submarine submarine) @@ -173,8 +173,6 @@ namespace Barotrauma { Vector2 center = new Vector2(WorldRect.X + rect.Width / 2.0f, -(WorldRect.Y - rect.Height/ 2.0f)); - - GUI.DrawLine(sb, center, center + new Vector2(flowForce.X, -flowForce.Y)/10.0f, Color.Red); GUI.DrawLine(sb, center + Vector2.One * 5.0f, center + new Vector2(lerpedFlowForce.X, -lerpedFlowForce.Y) / 10.0f + Vector2.One * 5.0f, Color.Orange); @@ -253,7 +251,7 @@ namespace Barotrauma var particle = GameMain.ParticleManager.CreateParticle( "watersplash", - (Submarine.Loaded == null ? pos : pos + Submarine.Loaded.Position) - Vector2.UnitY * Rand.Range(0.0f, 10.0f), + (Submarine == null ? pos : pos + Submarine.Position) - Vector2.UnitY * Rand.Range(0.0f, 10.0f), velocity); if (particle != null) @@ -269,7 +267,7 @@ namespace Barotrauma GameMain.ParticleManager.CreateParticle( "bubbles", - Submarine.Loaded == null ? pos : pos + Submarine.Loaded.Position, + Submarine == null ? pos : pos + Submarine.Position, flowForce / 10.0f); } } @@ -288,14 +286,14 @@ namespace Barotrauma var splash = GameMain.ParticleManager.CreateParticle( "watersplash", - Submarine.Loaded == null ? pos : pos + Submarine.Loaded.Position, + Submarine == null ? pos : pos + Submarine.Position, -velocity, 0, FlowTargetHull); if (splash != null) splash.Size = splash.Size * MathHelper.Clamp(rect.Width / 50.0f, 0.8f, 4.0f); GameMain.ParticleManager.CreateParticle( "bubbles", - Submarine.Loaded == null ? pos : pos + Submarine.Loaded.Position, + Submarine == null ? pos : pos + Submarine.Position, flowForce / 2.0f, 0, FlowTargetHull); } } @@ -329,6 +327,18 @@ namespace Barotrauma if (linkedTo.Count < 2) return; Hull hull1 = (Hull)linkedTo[0]; Hull hull2 = (Hull)linkedTo[1]; + + Vector2 subOffset = Vector2.Zero; + if (hull1.Submarine != Submarine) + { + subOffset =Submarine.Position - hull1.Submarine.Position; + } + else if (hull2.Submarine != Submarine) + { + + subOffset = hull2.Submarine.Position - Submarine.Position; + + } if (hull1.Volume == 0.0 && hull2.Volume == 0.0) return; @@ -341,13 +351,14 @@ namespace Barotrauma //horizontal gap (such as a regular door) if (isHorizontal) { - higherSurface = Math.Max(hull1.Surface,hull2.Surface); - float delta=0.0f; + higherSurface = Math.Max(hull1.Surface, hull2.Surface + subOffset.Y); + float delta=0.0f; + //water level is above the lower boundary of the gap - if (Math.Max(hull1.Surface+hull1.WaveY[hull1.WaveY.Length - 1], hull2.Surface+hull2.WaveY[0]) > rect.Y - size) + if (Math.Max(hull1.Surface+hull1.WaveY[hull1.WaveY.Length - 1], hull2.Surface + subOffset.Y +hull2.WaveY[0]) > rect.Y - size) { - int dir = (hull1.Pressure > hull2.Pressure) ? 1 : -1; + int dir = (hull1.Pressure > hull2.Pressure+subOffset.Y) ? 1 : -1; //water flowing from the righthand room to the lefthand room if (dir == -1) @@ -360,38 +371,42 @@ namespace Barotrauma flowTargetHull = hull1; //make sure not to move more than what the room contains - delta = Math.Min((hull2.Pressure - hull1.Pressure) * 5.0f * sizeModifier, Math.Min(hull2.Volume, hull2.FullVolume)); + delta = Math.Min(((hull2.Pressure + subOffset.Y) - hull1.Pressure) * 5.0f * sizeModifier, Math.Min(hull2.Volume, hull2.FullVolume)); //make sure not to place more water to the target room than it can hold delta = Math.Min(delta, hull1.FullVolume + Hull.MaxCompress - (hull1.Volume)); hull1.Volume += delta; hull2.Volume -= delta; if (hull1.Volume > hull1.FullVolume) - hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + hull2.Pressure) / 2); + { + hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + hull2.Pressure+subOffset.Y) / 2); + } flowForce = new Vector2(-delta, 0.0f); } else if (dir == 1) { if (!(hull1.Volume > 0.0f)) return; - lowerSurface = hull2.Surface - hull2.WaveY[1]; + //lowerSurface = hull2.Surface - hull2.WaveY[1]; flowTargetHull = hull2; //make sure not to move more than what the room contains - delta = Math.Min((hull1.Pressure - hull2.Pressure) * 5.0f * sizeModifier, Math.Min(hull1.Volume, hull1.FullVolume)); + delta = Math.Min((hull1.Pressure - (hull2.Pressure + subOffset.Y)) * 5.0f * sizeModifier, Math.Min(hull1.Volume, hull1.FullVolume)); //make sure not to place more water to the target room than it can hold delta = Math.Min(delta, hull2.FullVolume + Hull.MaxCompress - (hull2.Volume)); hull1.Volume -= delta; hull2.Volume += delta; if (hull2.Volume > hull2.FullVolume) - hull2.Pressure = Math.Max(hull2.Pressure, (hull1.Pressure + hull2.Pressure) / 2); + { + hull2.Pressure = Math.Max(hull2.Pressure, ((hull1.Pressure-subOffset.Y) + hull2.Pressure) / 2); + } flowForce = new Vector2(delta, 0.0f); } - if (delta>100.0f) + if (delta>100.0f && subOffset == Vector2.Zero) { float avg = (hull1.Surface + hull2.Surface) / 2.0f; //float avgVel = (hull2.WaveVel[1] + hull1.WaveVel[hull1.WaveY.Length - 2]) / 2.0f; @@ -419,11 +434,11 @@ namespace Barotrauma else { //lower room is full of water - if (hull2.Pressure > hull1.Pressure) + if ((hull2.Pressure + subOffset.Y) > hull1.Pressure) { float delta = Math.Min(hull2.Volume - hull2.FullVolume + Hull.MaxCompress / 2.0f, deltaTime * 8000.0f * sizeModifier); - flowForce = new Vector2(0.0f, Math.Min(hull2.Pressure - hull1.Pressure, 500.0f)); + flowForce = new Vector2(0.0f, Math.Min((hull2.Pressure + subOffset.Y) - hull1.Pressure, 500.0f)); delta = Math.Max(delta, 0.0f); hull1.Volume += delta; @@ -433,7 +448,7 @@ namespace Barotrauma if (hull1.Volume > hull1.FullVolume) { - hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + hull2.Pressure) / 2); + hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + (hull2.Pressure + subOffset.Y)) / 2); } } @@ -446,16 +461,16 @@ namespace Barotrauma float delta = Math.Min(hull1.Volume, deltaTime * 25000f * sizeModifier); //make sure not to place more water to the target room than it can hold delta = Math.Min(delta, (hull2.FullVolume + Math.Max(hull1.Volume - hull1.FullVolume, 0.0f)) - hull2.Volume + Hull.MaxCompress / 4.0f); - + hull1.Volume -= delta; hull2.Volume += delta; if (hull2.Volume > hull2.FullVolume) { - hull2.Pressure = Math.Max(hull2.Pressure, (hull1.Pressure + hull2.Pressure) / 2); + hull2.Pressure = Math.Max(hull2.Pressure, ((hull1.Pressure - subOffset.Y) + hull2.Pressure) / 2); } - flowForce = new Vector2(0.0f,-delta); + flowForce = new Vector2(0.0f, -delta); flowForce.X = hull1.WaveY[hull1.GetWaveIndex(rect.X)] - hull1.WaveY[hull1.GetWaveIndex(rect.Right)] * 10.0f; @@ -552,7 +567,7 @@ namespace Barotrauma } else { - hull1.LethalPressure += (Submarine.Loaded != null && Submarine.Loaded.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime; + hull1.LethalPressure += (Submarine != null && Submarine.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime; } } else @@ -567,7 +582,7 @@ namespace Barotrauma } if (hull1.Volume >= hull1.FullVolume - Hull.MaxCompress) { - hull1.LethalPressure += (Submarine.Loaded != null && Submarine.Loaded.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime; + hull1.LethalPressure += (Submarine != null && Submarine.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime; } } @@ -625,10 +640,9 @@ namespace Barotrauma GapList.Remove(this); - foreach (MapEntity entity in linkedTo) + foreach (Hull hull in Hull.hullList) { - var hull = entity as Hull; - if (hull.ConnectedGaps.Contains(this)) hull.ConnectedGaps.Remove(this); + hull.ConnectedGaps.Remove(this); } } @@ -639,7 +653,7 @@ namespace Barotrauma FindHulls(); } - public override XElement Save(XDocument doc) + public override XElement Save(XElement parentElement) { XElement element = new XElement("Gap"); @@ -663,7 +677,7 @@ namespace Barotrauma // } //} - doc.Root.Add(element); + parentElement.Add(element); return element; } diff --git a/Subsurface/Source/Map/Hull.cs b/Subsurface/Source/Map/Hull.cs index 9b9fb22eb..681b02dd6 100644 --- a/Subsurface/Source/Map/Hull.cs +++ b/Subsurface/Source/Map/Hull.cs @@ -15,7 +15,7 @@ namespace Barotrauma class Hull : MapEntity, IPropertyObject { public static List hullList = new List(); - private static EntityGrid entityGrid; + private static List entityGrids = new List(); public static bool ShowHulls = true; @@ -53,6 +53,7 @@ namespace Barotrauma private bool update; + private Sound currentFlowSound; private int soundIndex; private float soundVolume; @@ -178,7 +179,7 @@ namespace Barotrauma } public Hull(MapEntityPrefab prefab, Rectangle rectangle) - : this (prefab, rectangle, Submarine.Loaded) + : this (prefab, rectangle, Submarine.MainSub) { } @@ -248,13 +249,30 @@ namespace Barotrauma return rect; } - public static void GenerateEntityGrid() + public static void GenerateEntityGrid(Submarine submarine) { - entityGrid = new EntityGrid(Submarine.Borders, 200.0f); + var newGrid = new EntityGrid(submarine, 200.0f); + + entityGrids.Add(newGrid); foreach (Hull hull in hullList) { - entityGrid.InsertEntity(hull); + if (hull.Submarine == submarine) newGrid.InsertEntity(hull); + } + } + + public void AddToGrid(Submarine submarine) + { + foreach (EntityGrid grid in entityGrids) + { + if (grid.Submarine != submarine) continue; + + rect.Location -= submarine.HiddenSubPosition.ToPoint(); + + grid.InsertEntity(this); + + rect.Location += submarine.HiddenSubPosition.ToPoint(); + return; } } @@ -293,6 +311,7 @@ namespace Barotrauma public override void Remove() { base.Remove(); + hullList.Remove(this); if (Submarine == null || !Submarine.Loading) { @@ -313,10 +332,15 @@ namespace Barotrauma } //renderer.Dispose(); + if (entityGrids != null) + { + foreach (EntityGrid entityGrid in entityGrids) + { + entityGrid.RemoveEntity(this); + } + } - if (entityGrid != null) entityGrid.RemoveEntity(this); - hullList.Remove(this); } public void AddFireSource(FireSource fireSource, bool createNetworkEvent = true) @@ -369,12 +393,24 @@ namespace Barotrauma foreach (Gap gap in ConnectedGaps) { float gapFlow = gap.LerpedFlowForce.Length(); + +#if DEBUG + var asd = MapEntity.FindEntityByID(gap.ID); + + if (asd != gap) + { + int adslkmfdlasfk = 9; + } +#endif + + if (gapFlow > strongestFlow) { strongestFlow = gapFlow; } } + if (strongestFlow>0.1f) { soundVolume = soundVolume + ((strongestFlow < 100.0f) ? -deltaTime * 0.5f : deltaTime * 0.5f); @@ -383,13 +419,24 @@ namespace Barotrauma int index = (int)Math.Floor(strongestFlow / 100.0f); index = Math.Min(index, 2); - soundIndex = SoundPlayer.flowSounds[index].Loop(soundIndex, soundVolume, WorldPosition, 2000.0f); + var flowSound = SoundPlayer.flowSounds[index]; + if (flowSound != currentFlowSound && soundIndex > -1) + { + Sounds.SoundManager.Stop(soundIndex); + currentFlowSound = null; + soundIndex = -1; + } + + currentFlowSound = flowSound; + + soundIndex = currentFlowSound.Loop(soundIndex, soundVolume, WorldPosition, 2000.0f); } else { if (soundIndex > -1) { Sounds.SoundManager.Stop(soundIndex); + currentFlowSound = null; soundIndex = -1; } } @@ -653,15 +700,14 @@ namespace Barotrauma //returns the water block which contains the point (or null if it isn't inside any) public static Hull FindHull(Vector2 position, Hull guess = null, bool useWorldCoordinates = true) { - if (entityGrid == null) return null; + if (entityGrids == null) return null; if (guess != null) { if (Submarine.RectContains(useWorldCoordinates ? guess.WorldRect : guess.rect, position)) return guess; } - var entities = entityGrid.GetEntities( - useWorldCoordinates && Submarine.Loaded!=null ? position-Submarine.Loaded.Position : position); + var entities = EntityGrid.GetEntities(entityGrids, position, useWorldCoordinates); foreach (Hull hull in entities) { @@ -706,7 +752,7 @@ namespace Barotrauma // return gaps; //} - public override XElement Save(XDocument doc) + public override XElement Save(XElement parentElement) { XElement element = new XElement("Hull"); @@ -719,8 +765,8 @@ namespace Barotrauma rect.Width + "," + rect.Height), new XAttribute("water", volume) ); - - doc.Root.Add(element); + + parentElement.Add(element); return element; } @@ -836,7 +882,7 @@ namespace Barotrauma } else { - var newFire = new FireSource(pos + Submarine.Loaded.Position, this, true); + var newFire = new FireSource(pos + Submarine.Position, this, true); newFire.Size = new Vector2( newFire.Hull == null ? size : size * newFire.Hull.rect.Width, newFire.Size.Y); diff --git a/Subsurface/Source/Map/Levels/Level.cs b/Subsurface/Source/Map/Levels/Level.cs index 338de50a6..5516f9ed2 100644 --- a/Subsurface/Source/Map/Levels/Level.cs +++ b/Subsurface/Source/Map/Levels/Level.cs @@ -17,6 +17,8 @@ namespace Barotrauma class Level { + public const float ShaftHeight = 1000.0f; + public static Level Loaded { get { return loaded; } @@ -56,7 +58,7 @@ namespace Barotrauma private WrappingWall[,] wrappingWalls; - private float shaftHeight; + //private float shaftHeight; //List bodies; private List cells; @@ -121,7 +123,7 @@ namespace Barotrauma { get { return backgroundColor; } } - + public Level(string seed, float difficulty, int width, int height, int siteInterval) { this.seed = seed; @@ -181,7 +183,7 @@ namespace Barotrauma float avgValue = (backgroundColor.R + backgroundColor.G + backgroundColor.G) / 3; GameMain.LightManager.AmbientLight = new Color(backgroundColor*(40.0f/avgValue), 1.0f); - float minWidth = Submarine.Loaded == null ? 0.0f : Math.Max(Submarine.Borders.Width, Submarine.Borders.Height); + float minWidth = Submarine.MainSub == null ? 0.0f : Math.Max(Submarine.MainSub.Borders.Width, Submarine.MainSub.Borders.Height); minWidth = Math.Max(minWidth, 6500.0f); startPosition = new Vector2(minWidth * 2, Rand.Range(minWidth * 2, borders.Height - minWidth * 2, false)); @@ -513,7 +515,7 @@ namespace Barotrauma ShaftBodies = new Body[2]; for (int i = 0; i < 2; i++) { - ShaftBodies[i] = BodyFactory.CreateRectangle(GameMain.World, 200.0f, 10.0f, 5.0f); + ShaftBodies[i] = BodyFactory.CreateRectangle(GameMain.World, 200.0f, ConvertUnits.ToSimUnits(ShaftHeight), 5.0f); ShaftBodies[i].BodyType = BodyType.Static; ShaftBodies[i].CollisionCategories = Physics.CollisionLevel; @@ -585,7 +587,7 @@ namespace Barotrauma { List wayPoints = new List(); - var newWaypoint = new WayPoint(new Rectangle((int)pathCells[0].Center.X, (int)(borders.Height + shaftHeight), 10, 10), null); + var newWaypoint = new WayPoint(new Rectangle((int)pathCells[0].Center.X, borders.Height, 10, 10), null); newWaypoint.MoveWithLevel = true; wayPoints.Add(newWaypoint); @@ -625,7 +627,7 @@ namespace Barotrauma //prevWaypoint = newWaypoint; } - newWaypoint = new WayPoint(new Rectangle((int)pathCells[pathCells.Count - 1].Center.X, (int)(borders.Height + shaftHeight), 10, 10), null); + newWaypoint = new WayPoint(new Rectangle((int)pathCells[pathCells.Count - 1].Center.X, borders.Height, 10, 10), null); newWaypoint.MoveWithLevel = true; wayPoints.Add(newWaypoint); @@ -783,9 +785,9 @@ namespace Barotrauma public void Update (float deltaTime) { - if (Submarine.Loaded != null) + if (Submarine.MainSub != null) { - WrappingWall.UpdateWallShift(Submarine.Loaded.WorldPosition, wrappingWalls); + WrappingWall.UpdateWallShift(Submarine.MainSub.WorldPosition, wrappingWalls); } renderer.Update(deltaTime); diff --git a/Subsurface/Source/Map/Levels/Ruins/RuinGenerator.cs b/Subsurface/Source/Map/Levels/Ruins/RuinGenerator.cs index cf4c1e67f..832339281 100644 --- a/Subsurface/Source/Map/Levels/Ruins/RuinGenerator.cs +++ b/Subsurface/Source/Map/Levels/Ruins/RuinGenerator.cs @@ -319,9 +319,11 @@ namespace Barotrauma.RuinGeneration (int)((wall.B.X - wall.A.X) + radius*2.0f), (int)((wall.B.Y - wall.A.Y) + radius*2.0f)); + //cut a section off from both ends of a horizontal wall to get nicer looking corners if (wall.A.Y == wall.B.Y) { rect.Inflate(-32, 0); + if (rect.Width < Submarine.GridSize.X) continue; } var structure = new Structure(rect, structurePrefab.Prefab as StructurePrefab, null); diff --git a/Subsurface/Source/Map/Lights/ConvexHull.cs b/Subsurface/Source/Map/Lights/ConvexHull.cs index 7453f2246..73e791966 100644 --- a/Subsurface/Source/Map/Lights/ConvexHull.cs +++ b/Subsurface/Source/Map/Lights/ConvexHull.cs @@ -42,9 +42,21 @@ namespace Barotrauma.Lights } } + class ConvexHullList + { + public readonly Submarine Submarine; + public List List; + + public ConvexHullList(Submarine submarine) + { + Submarine = submarine; + List = new List(); + } + } + class ConvexHull { - public static List list = new List(); + public static List HullLists = new List(); static BasicEffect shadowEffect; static BasicEffect penumbraEffect; @@ -116,15 +128,20 @@ namespace Barotrauma.Lights Enabled = true; - foreach (ConvexHull ch in list) + var chList = HullLists.Find(x => x.Submarine == parent.Submarine); + if (chList == null) + { + chList = new ConvexHullList(parent.Submarine); + HullLists.Add(chList); + } + + foreach (ConvexHull ch in chList.List) { UpdateIgnoredEdges(ch); ch.UpdateIgnoredEdges(this); } - - list.Add(this); - + chList.List.Add(this); } private void UpdateIgnoredEdges(ConvexHull ch) @@ -219,7 +236,7 @@ namespace Barotrauma.Lights { foreach (KeyValuePair cachedShadow in cachedShadows) { - cachedShadow.Key.NeedsHullUpdate(); + cachedShadow.Key.NeedsHullUpdate = true; cachedShadow.Value.Dispose(); } cachedShadows.Clear(); @@ -375,7 +392,18 @@ namespace Barotrauma.Lights Vector2 lightSourcePos = light.Position; - if (light.Submarine==null && parentEntity != null && parentEntity.Submarine != null) lightSourcePos -= parentEntity.Submarine.Position; + if (parentEntity != null && parentEntity.Submarine != null) + { + if (light.ParentSub == null) + { + lightSourcePos -= parentEntity.Submarine.Position; + } + else if (light.ParentSub != parentEntity.Submarine) + { + lightSourcePos += (light.ParentSub.Position-parentEntity.Submarine.Position); + } + + } CachedShadow cachedShadow = null; if (!cachedShadows.TryGetValue(light, out cachedShadow) || @@ -456,7 +484,16 @@ namespace Barotrauma.Lights { ClearCachedShadows(); - list.Remove(this); + var chList = HullLists.Find(x => x.Submarine == parentEntity.Submarine); + + if (chList != null) + { + chList.List.Remove(this); + if (chList.List.Count == 0) + { + HullLists.Remove(chList); + } + } } diff --git a/Subsurface/Source/Map/Lights/LightManager.cs b/Subsurface/Source/Map/Lights/LightManager.cs index 21093cc70..7281cf055 100644 --- a/Subsurface/Source/Map/Lights/LightManager.cs +++ b/Subsurface/Source/Map/Lights/LightManager.cs @@ -73,7 +73,7 @@ namespace Barotrauma.Lights { foreach (LightSource light in lights) { - light.UpdateHullsInRange(); + light.NeedsHullUpdate = true; } } @@ -94,9 +94,8 @@ namespace Barotrauma.Lights foreach (LightSource light in lights) { - if (light.Color.A < 0.01f || light.Range < 1.0f) continue; - if (light.hullsInRange == null) light.UpdateHullsInRange(); - if (!light.hullsInRange.Any() || !MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; + if (light.Color.A < 0.01f || light.Range < 1.0f || !light.CastShadows) continue; + if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; //clear alpha to 1 ClearAlphaToOne(graphics, spriteBatch); @@ -106,12 +105,7 @@ namespace Barotrauma.Lights graphics.RasterizerState = RasterizerState.CullNone; graphics.BlendState = CustomBlendStates.WriteToAlpha; - foreach (ConvexHull ch in light.hullsInRange) - { - //if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, ch.BoundingBox)) continue; - //draw shadow - ch.DrawShadows(graphics, cam, light, shadowTransform, false); - } + light.DrawShadows(graphics, cam, shadowTransform); //draw the light shape //where Alpha is 0, nothing will be written @@ -130,7 +124,7 @@ namespace Barotrauma.Lights foreach (LightSource light in lights) { - if (light.hullsInRange==null || light.hullsInRange.Any() || light.Color.A < 0.01f) continue; + if (light.Color.A < 0.01f || light.Range < 1.0f || light.CastShadows) continue; //if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue; light.Draw(spriteBatch); @@ -185,13 +179,18 @@ namespace Barotrauma.Lights Matrix shadowTransform = cam.ShaderTransform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f; - foreach (ConvexHull convexHull in ConvexHull.list) - { - if (!convexHull.Intersects(camView)) continue; - //if (!camView.Intersects(convexHull.BoundingBox)) continue; + var convexHulls = LightSource.GetHullsInRange(viewTarget.Position, cam.WorldView.Width*0.75f, viewTarget.Submarine); - convexHull.DrawShadows(graphics, cam, pos, shadowTransform); - } + if (convexHulls != null) + { + foreach (ConvexHull convexHull in convexHulls) + { + if (!convexHull.Intersects(camView)) continue; + //if (!camView.Intersects(convexHull.BoundingBox)) continue; + + convexHull.DrawShadows(graphics, cam, pos, shadowTransform); + } + } } graphics.SetRenderTarget(null); } diff --git a/Subsurface/Source/Map/Lights/LightSource.cs b/Subsurface/Source/Map/Lights/LightSource.cs index 46e04bf90..0542cd359 100644 --- a/Subsurface/Source/Map/Lights/LightSource.cs +++ b/Subsurface/Source/Map/Lights/LightSource.cs @@ -12,7 +12,7 @@ namespace Barotrauma.Lights { private static Texture2D lightTexture; - public List hullsInRange; + private List hullsInRange; private Color color; @@ -24,7 +24,7 @@ namespace Barotrauma.Lights private Sprite overrideLightTexture; - public Entity Submarine; + public Entity ParentSub; public bool CastShadows; @@ -33,6 +33,8 @@ namespace Barotrauma.Lights private Vector2 prevHullUpdatePosition; + public bool NeedsHullUpdate; + private Vector2 position; public Vector2 Position { @@ -43,8 +45,8 @@ namespace Barotrauma.Lights position = value; if (Vector2.Distance(prevHullUpdatePosition, position) < 5.0f) return; - - UpdateHullsInRange(); + + NeedsHullUpdate = true; prevHullUpdatePosition = position; } } @@ -57,7 +59,7 @@ namespace Barotrauma.Lights public Vector2 WorldPosition { - get { return (Submarine == null) ? position : position + Submarine.Position; } + get { return (ParentSub == null) ? position : position + ParentSub.Position; } } public static Texture2D LightTexture @@ -86,9 +88,9 @@ namespace Barotrauma.Lights { range = MathHelper.Clamp(value, 0.0f, 2048.0f); - if (Math.Abs(prevHullUpdateRange - range) < 5.0f) return; - - UpdateHullsInRange(); + if (Math.Abs(prevHullUpdateRange - range) < 10.0f) return; + + NeedsHullUpdate = true; prevHullUpdateRange = range; } } @@ -117,9 +119,9 @@ namespace Barotrauma.Lights public LightSource(Vector2 position, float range, Color color, Submarine submarine) { - hullsInRange = new List(); + hullsInRange = new List(); - this.Submarine = submarine; + this.ParentSub = submarine; this.position = position; this.range = range; @@ -132,37 +134,166 @@ namespace Barotrauma.Lights GameMain.LightManager.AddLight(this); } - public void UpdateHullsInRange() + public void DrawShadows(GraphicsDevice graphics, Camera cam, Matrix shadowTransform) { if (!CastShadows) return; - - if (hullsInRange == null) hullsInRange = new List(); - - hullsInRange.Clear(); if (range < 1.0f || color.A < 0.01f) return; - foreach (ConvexHull ch in ConvexHull.list) + foreach (Submarine sub in Submarine.Loaded) { - if (Submarine == null && ch.ParentEntity.Submarine != null) + var hulls = GetHullsInRange(sub); + + if (hulls == null) continue; + + foreach ( ConvexHull ch in hulls) { - if (MathUtils.CircleIntersectsRectangle(position - ch.ParentEntity.Submarine.Position, range, ch.BoundingBox)) + ch.DrawShadows(graphics, cam, this, shadowTransform, false); + } + } + + var outsideHulls = GetHullsInRange(null); + + NeedsHullUpdate = false; + + if (outsideHulls == null) return; + foreach (ConvexHull ch in outsideHulls) + { + ch.DrawShadows(graphics, cam, this, shadowTransform, false); + } + } + + private List GetHullsInRange(Submarine sub) + { + var chList = hullsInRange.Find(x => x.Submarine == sub); + + if (chList == null) + { + chList = new ConvexHullList(sub); + hullsInRange.Add(chList); + } + List list = chList.List; + + + Vector2 lightPos = position; + if (ParentSub == null) + { + //light and the convexhull are both outside + if (sub == null) + { + if (NeedsHullUpdate) { - hullsInRange.Add(ch); + var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); + + list = fullChList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); + chList.List = list; } } - else if (MathUtils.CircleIntersectsRectangle(position, range, ch.BoundingBox)) + //light is outside, convexhull inside a sub + else { - hullsInRange.Add(ch); + //todo: check + lightPos -= sub.Position; + + Rectangle subBorders = sub.Borders; + subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height); + + //only draw if the light overlaps with the sub + if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) return null; + + var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); + list = fullChList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); } - } + else + { + //light is inside, convexhull outside + if (sub == null) return null; + + //light and convexhull are both inside the same sub + if (sub == ParentSub) + { + if (NeedsHullUpdate) + { + var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); + + list = fullChList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); + chList.List = list; + } + } + //light and convexhull are inside different subs + else + { + lightPos -= (sub.Position - ParentSub.Position); + + Rectangle subBorders = sub.Borders; + subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height); + + //only draw if the light overlaps with the sub + if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) return null; + + var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub); + list = fullChList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)); + } + } + + return list; } - public void NeedsHullUpdate() + public static List GetHullsInRange(Vector2 position, float range, Submarine ParentSub) { - hullsInRange = null; + List list = new List(); + + foreach (ConvexHullList chList in ConvexHull.HullLists) + { + Vector2 lightPos = position; + if (ParentSub == null) + { + //light and the convexhull are both outside + if (chList.Submarine == null) + { + list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); + + } + //light is outside, convexhull inside a sub + else + { + if (!MathUtils.CircleIntersectsRectangle(lightPos - chList.Submarine.WorldPosition, range, chList.Submarine.Borders)) continue; + + lightPos -= (chList.Submarine.WorldPosition - chList.Submarine.HiddenSubPosition); + + list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); + } + } + else + { + //light is inside, convexhull outside + if (chList.Submarine == null) continue; + + //light and convexhull are both inside the same sub + if (chList.Submarine == ParentSub) + { + list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); + } + //light and convexhull are inside different subs + else + { + lightPos -= (chList.Submarine.Position - ParentSub.Position); + + Rectangle subBorders = chList.Submarine.Borders; + subBorders.Location += chList.Submarine.HiddenSubPosition.ToPoint() - new Point(0, chList.Submarine.Borders.Height); + + if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders)) continue; + + list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox))); + } + } + } + + + return list; } + public void Draw(SpriteBatch spriteBatch) { if (range > 1.0f) diff --git a/Subsurface/Source/Map/LinkedSubmarine.cs b/Subsurface/Source/Map/LinkedSubmarine.cs new file mode 100644 index 000000000..90286dfb0 --- /dev/null +++ b/Subsurface/Source/Map/LinkedSubmarine.cs @@ -0,0 +1,310 @@ +using Barotrauma.Items.Components; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Barotrauma +{ + + class LinkedSubmarinePrefab : MapEntityPrefab + { + public readonly Submarine mainSub; + + public LinkedSubmarinePrefab(Submarine submarine) + { + this.mainSub = submarine; + } + + protected override void CreateInstance(Rectangle rect) + { + System.Diagnostics.Debug.Assert(Submarine.MainSub != null); + + LinkedSubmarine.Create(Submarine.MainSub, mainSub.FilePath, rect.Location.ToVector2()); + } + } + + class LinkedSubmarine : MapEntity + { + private List wallVertices; + + private string filePath; + + private Submarine sub; + + private XElement saveElement; + + public override bool IsLinkable + { + get + { + return true; + } + } + + public LinkedSubmarine(Submarine submarine) + : base(null, submarine) + { + linkedTo = new System.Collections.ObjectModel.ObservableCollection(); + linkedToID = new List(); + + InsertToList(); + } + + public static LinkedSubmarine Create(Submarine mainSub, string filePath, Vector2 position) + { + LinkedSubmarine sl = new LinkedSubmarine(mainSub); + sl.filePath = filePath; + + XDocument doc = Submarine.OpenFile(filePath); + if (doc == null || doc.Root == null) return null; + + sl.GenerateWallVertices(doc.Root); + + //for (int i = 0; i < sl.wallVertices.Count; i++) + //{ + // sl.wallVertices[i] = sl.wallVertices[i] += position; + //} + + sl.Rect = new Rectangle( + (int)sl.wallVertices.Min(v => v.X + position.X), + (int)sl.wallVertices.Max(v => v.Y + position.Y), + (int)sl.wallVertices.Max(v => v.X + position.X), + (int)sl.wallVertices.Min(v => v.Y + position.Y)); + + sl.rect = new Rectangle(sl.rect.X, sl.rect.Y, sl.rect.Width - sl.rect.X, sl.rect.Y - sl.rect.Height); + + return sl; + } + + public override bool IsMouseOn(Vector2 position) + { + return Vector2.Distance(position, WorldPosition) < 50.0f; + } + + public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true) + { + if (!editing || wallVertices == null) return; + + Color color = (isHighlighted) ? Color.Orange : Color.Green; + if (isSelected) color = Color.Red; + + Vector2 pos = new Vector2(rect.X + rect.Width/2, rect.Y - rect.Height/2); + + for (int i = 0; i < wallVertices.Count; i++) + { + Vector2 startPos = wallVertices[i] + pos; + startPos.Y = -startPos.Y; + + Vector2 endPos = wallVertices[(i + 1) % wallVertices.Count] + pos; + endPos.Y = -endPos.Y; + + GUI.DrawLine(spriteBatch, + startPos, + endPos, + color, 0.0f, 5); + } + + pos.Y = -pos.Y; + GUI.DrawLine(spriteBatch, pos + Vector2.UnitY * 50.0f, pos - Vector2.UnitY * 50.0f, color, 0.0f, 5); + GUI.DrawLine(spriteBatch, pos + Vector2.UnitX * 50.0f, pos - Vector2.UnitX * 50.0f, color, 0.0f, 5); + + + foreach (MapEntity e in linkedTo) + { + GUI.DrawLine(spriteBatch, + new Vector2(WorldPosition.X, -WorldPosition.Y), + new Vector2(e.WorldPosition.X, -e.WorldPosition.Y), + Color.Red * 0.3f); + } + } + + public override void DrawEditing(SpriteBatch spriteBatch, Camera cam) + { + if (editingHUD == null || editingHUD.UserData as LinkedSubmarine != this) + { + editingHUD = CreateEditingHUD(); + } + + editingHUD.Draw(spriteBatch); + editingHUD.Update((float)Physics.step); + + if (!PlayerInput.LeftButtonClicked() || !PlayerInput.KeyDown(Keys.Space)) return; + + Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); + + foreach (MapEntity entity in mapEntityList) + { + if (entity == this || !entity.IsHighlighted || !(entity is Item) || !entity.IsMouseOn(position)) continue; + if (((Item)entity).GetComponent() == null) continue; + if (linkedTo.Contains(entity)) + { + linkedTo.Remove(entity); + } + else + { + linkedTo.Add(entity); + } + } + } + + + private GUIComponent CreateEditingHUD(bool inGame = false) + { + int width = 450; + int x = GameMain.GraphicsWidth / 2 - width / 2, y = 10; + + editingHUD = new GUIFrame(new Rectangle(x, y, width, 100), GUI.Style); + editingHUD.Padding = new Vector4(10, 10, 0, 0); + editingHUD.UserData = this; + + new GUITextBlock(new Rectangle(0, 0, 100, 20), "Linked submarine", GUI.Style, + Alignment.TopLeft, Alignment.TopLeft, editingHUD, false, GUI.LargeFont); + + y += 20; + + if (!inGame) + { + new GUITextBlock(new Rectangle(0, 0, 0, 20), "Hold space to link to a docking port", + GUI.Style, Alignment.TopRight, Alignment.TopRight, editingHUD).Font = GUI.SmallFont; + y += 25; + + } + return editingHUD; + } + + + private void GenerateWallVertices(XElement rootElement) + { + List points = new List(); + + var wallPrefabs = + MapEntityPrefab.list.FindAll(mp => (mp is StructurePrefab) && ((StructurePrefab)mp).HasBody); + + foreach (XElement element in rootElement.Elements()) + { + if (element.Name != "Structure") continue; + + string name = ToolBox.GetAttributeString(element, "name", ""); + if (!wallPrefabs.Any(wp => wp.Name == name)) continue; + + var rect = ToolBox.GetAttributeVector4(element, "rect", Vector4.Zero); + + points.Add(new Vector2(rect.X, rect.Y)); + points.Add(new Vector2(rect.X + rect.Z, rect.Y)); + points.Add(new Vector2(rect.X, rect.Y - rect.W)); + points.Add(new Vector2(rect.X + rect.Z, rect.Y - rect.W)); + } + + wallVertices = MathUtils.GiftWrap(points); + } + + public override XElement Save(XElement parentElement) + { + XElement saveElement = null; + + if (sub == null) + { + var doc = Submarine.OpenFile(filePath); + saveElement = doc.Root; + + saveElement.Name = "LinkedSubmarine"; + + saveElement.Add(new XAttribute("filepath", filePath)); + + var linkedPort = linkedTo.FirstOrDefault(lt => (lt is Item) && ((Item)lt).GetComponent() != null); + if (linkedPort != null) + { + saveElement.Add(new XAttribute("linkedto", linkedPort.ID)); + } + } + else + { + if (!sub.DockedTo.Contains(Submarine.MainSub)) return null; + + saveElement = new XElement("LinkedSubmarine"); + + sub.SaveToXElement(saveElement); + } + + saveElement.Add(new XAttribute("pos", ToolBox.Vector2ToString(Position - Submarine.HiddenSubPosition))); + + parentElement.Add(saveElement); + + return saveElement; + } + + public static void Load(XElement element, Submarine submarine) + { + Vector2 pos = ToolBox.GetAttributeVector2(element, "pos", Vector2.Zero); + + LinkedSubmarine linkedSub = null; + + if (Screen.Selected == GameMain.EditMapScreen) + { + string filePath = ToolBox.GetAttributeString(element, "filepath", ""); + + linkedSub = Create(submarine, filePath, pos); + } + else + { + linkedSub = new LinkedSubmarine(submarine); + linkedSub.saveElement = element; + + linkedSub.rect.Location = pos.ToPoint(); + } + + string linkedToString = ToolBox.GetAttributeString(element, "linkedto", ""); + if (linkedToString != "") + { + string[] linkedToIds = linkedToString.Split(','); + for (int i = 0; i < linkedToIds.Length; i++) + { + linkedSub.linkedToID.Add((ushort)int.Parse(linkedToIds[i])); + } + } + + } + + public override void OnMapLoaded() + { + if (saveElement == null) return; + + sub = Submarine.Load(saveElement, false); + sub.SetPosition(WorldPosition - Submarine.WorldPosition); + sub.Submarine = Submarine; + + var linkedItem = linkedTo.FirstOrDefault(lt => (lt is Item) && ((Item)lt).GetComponent() != null); + + if (linkedItem != null) + { + var linkedPort = ((Item)linkedItem).GetComponent(); + + DockingPort myPort = null; + float closestDistance = 0.0f; + + foreach (DockingPort port in DockingPort.list) + { + if (port.Item.Submarine != sub || port.IsHorizontal != linkedPort.IsHorizontal) continue; + + float dist = Vector2.Distance(port.Item.WorldPosition, linkedPort.Item.WorldPosition); + if (myPort == null || dist < closestDistance) + { + myPort = port; + closestDistance = dist; + } + } + + if (myPort != null) + { + myPort.Dock(linkedPort); + } + } + } + } +} diff --git a/Subsurface/Source/Map/MapEntity.cs b/Subsurface/Source/Map/MapEntity.cs index 0e9867f99..f079fb7d9 100644 --- a/Subsurface/Source/Map/MapEntity.cs +++ b/Subsurface/Source/Map/MapEntity.cs @@ -518,7 +518,7 @@ namespace Barotrauma Vector2 placePosition = new Vector2(rect.X, rect.Y); Vector2 placeSize = new Vector2(rect.Width, rect.Height); - Vector2 mousePos = Submarine.MouseToWorldGrid(cam); + Vector2 mousePos = Submarine.MouseToWorldGrid(cam, Submarine.MainSub); if (resizeDirX >0) { @@ -596,7 +596,7 @@ namespace Barotrauma } - public virtual XElement Save(XDocument doc) + public virtual XElement Save(XElement parentElement) { DebugConsole.ThrowError("Saving entity " + GetType() + " failed."); return null; @@ -607,10 +607,11 @@ namespace Barotrauma /// Has to be done after all the entities have been loaded (an entity can't /// be linked to some other entity that hasn't been loaded yet) /// - public static void MapLoaded() + public static void MapLoaded(Submarine sub) { foreach (MapEntity e in mapEntityList) { + if (e.Submarine != sub) continue; if (e.linkedToID == null) continue; if (e.linkedToID.Count == 0) continue; @@ -623,14 +624,29 @@ namespace Barotrauma if (linked != null) e.linkedTo.Add(linked); } } + + List linkedSubs = new List(); for (int i = 0; i x.Remove()); } @@ -520,7 +528,7 @@ namespace Barotrauma public AttackResult AddDamage(IDamageable attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = false) { - if (Submarine.Loaded != null && Submarine.Loaded.GodMode && Submarine == Submarine.Loaded) return new AttackResult(0.0f, 0.0f); + if (Submarine != null && Submarine.GodMode) return new AttackResult(0.0f, 0.0f); if (!prefab.HasBody || prefab.IsPlatform) return new AttackResult(0.0f, 0.0f); Vector2 transformedPos = worldPosition; @@ -546,7 +554,7 @@ namespace Barotrauma private void SetDamage(int sectionIndex, float damage) { - if (Submarine.Loaded != null && Submarine.Loaded.GodMode) return; + if (Submarine != null && Submarine.GodMode) return; if (!prefab.HasBody) return; if (!MathUtils.IsValid(damage)) return; @@ -668,7 +676,7 @@ namespace Barotrauma } - public override XElement Save(XDocument doc) + public override XElement Save(XElement parentElement) { XElement element = new XElement("Structure"); @@ -696,7 +704,7 @@ namespace Barotrauma element.Add(sectionElement); } - doc.Root.Add(element); + parentElement.Add(element); return element; } diff --git a/Subsurface/Source/Map/StructurePrefab.cs b/Subsurface/Source/Map/StructurePrefab.cs index abedc550c..9d9f7f123 100644 --- a/Subsurface/Source/Map/StructurePrefab.cs +++ b/Subsurface/Source/Map/StructurePrefab.cs @@ -128,7 +128,7 @@ namespace Barotrauma public override void UpdatePlacing(SpriteBatch spriteBatch, Camera cam) { - Vector2 position = Submarine.MouseToWorldGrid(cam); + Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub); //Vector2 placeSize = size; Rectangle newRect = new Rectangle((int)position.X, (int)position.Y, (int)size.X, (int)size.Y); @@ -137,7 +137,7 @@ namespace Barotrauma if (placePosition == Vector2.Zero) { if (PlayerInput.LeftButtonHeld()) - placePosition = Submarine.MouseToWorldGrid(cam); + placePosition = Submarine.MouseToWorldGrid(cam, Submarine.MainSub); newRect.X = (int)position.X; newRect.Y = (int)position.Y; @@ -154,14 +154,10 @@ namespace Barotrauma if (PlayerInput.LeftButtonReleased()) { - if (Submarine.Loaded != null) - { - newRect.Location -= Submarine.Loaded.Position.ToPoint(); - } + newRect.Location -= Submarine.MainSub.Position.ToPoint(); - var structure = new Structure(newRect, this, Submarine.Loaded); - - structure.Submarine = Submarine.Loaded; + var structure = new Structure(newRect, this, Submarine.MainSub); + structure.Submarine = Submarine.MainSub; selected = null; return; diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 59446d81d..cc0d87b10 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -22,22 +22,36 @@ namespace Barotrauma { public static string SavePath = "Submarines"; + public static readonly Vector2 HiddenSubStartPosition = new Vector2(-50000.0f, 80000.0f); //position of the "actual submarine" which is rendered wherever the SubmarineBody is //should be in an unreachable place - public static readonly Vector2 HiddenSubPosition = new Vector2(-50000.0f, 80000.0f); + public Vector2 HiddenSubPosition + { + get; + private set; + } + + public ushort IdOffset + { + get; + private set; + } public static List SavedSubmarines = new List(); public static readonly Vector2 GridSize = new Vector2(16.0f, 16.0f); - private static Submarine loaded; + public static Submarine MainSub; + private static List loaded = new List(); private SubmarineBody subBody; + public readonly List DockedTo; + private static Vector2 lastPickedPosition; private static float lastPickedFraction; - Md5Hash hash; + private Md5Hash hash; private string filePath; private string name; @@ -45,8 +59,7 @@ namespace Barotrauma private Vector2 prevPosition; private float lastNetworkUpdate; - - + //properties ---------------------------------------------------- public string Name @@ -89,23 +102,28 @@ namespace Barotrauma { if (hash != null) return hash; - XDocument doc = OpenDoc(filePath); + XDocument doc = OpenFile(filePath); hash = new Md5Hash(doc); return hash; } } - public static Submarine Loaded + public static List Loaded { get { return loaded; } } - public static Rectangle Borders + public SubmarineBody SubBody + { + get { return subBody; } + } + + public Rectangle Borders { get { - return (loaded==null) ? Rectangle.Empty : Loaded.subBody.Borders; + return subBody.Borders; } } @@ -206,7 +224,7 @@ namespace Barotrauma if (tryLoad) { - XDocument doc = OpenDoc(filePath); + XDocument doc = OpenFile(filePath); if (doc != null && doc.Root != null) { @@ -214,6 +232,8 @@ namespace Barotrauma } } + DockedTo = new List(); + ID = ushort.MaxValue; base.Remove(); @@ -255,17 +275,17 @@ namespace Barotrauma //math/physics stuff ---------------------------------------------------- - public static Vector2 MouseToWorldGrid(Camera cam) + public static Vector2 MouseToWorldGrid(Camera cam, Submarine sub) { Vector2 position = PlayerInput.MousePosition; position = cam.ScreenToWorld(position); Vector2 worldGridPos = VectorToWorldGrid(position); - if (loaded != null) + if (sub != null) { - worldGridPos.X += loaded.Position.X % GridSize.X; - worldGridPos.Y += loaded.Position.Y % GridSize.Y; + worldGridPos.X += sub.Position.X % GridSize.X; + worldGridPos.Y += sub.Position.Y % GridSize.Y; } return worldGridPos; @@ -421,7 +441,19 @@ namespace Barotrauma { if (!MathUtils.IsValid(position)) return; + Vector2 prevPos = subBody.Position; + subBody.SetPosition(position); + + foreach (Submarine sub in loaded) + { + if (sub != this && sub.Submarine == this) + { + sub.SetPosition(position + sub.WorldPosition); + sub.Submarine = null; + } + + } //Level.Loaded.SetPosition(-position); //prevPosition = position; } @@ -435,6 +467,23 @@ namespace Barotrauma //Level.Loaded.Move(-amount); } + public static Submarine GetClosest(Vector2 worldPosition) + { + Submarine closest = null; + float closestDist = 0.0f; + foreach (Submarine sub in Submarine.loaded) + { + float dist = Vector2.Distance(worldPosition, sub.WorldPosition); + if (closest == null || dist < closestDist) + { + closest = sub; + closestDist = dist; + } + } + + return closest; + } + public override bool FillNetworkData(Networking.NetworkEventType type, NetBuffer message, object data) { if (subBody == null) return false; @@ -492,14 +541,7 @@ namespace Barotrauma name = System.IO.Path.GetFileNameWithoutExtension(filePath); XDocument doc = new XDocument(new XElement("Submarine")); - doc.Root.Add(new XAttribute("name", name)); - doc.Root.Add(new XAttribute("description", Description == null ? "" : Description)); - - foreach (MapEntity e in MapEntity.mapEntityList) - { - if (e.MoveWithLevel) continue; - e.Save(doc); - } + SaveToXElement(doc.Root); hash = new Md5Hash(doc); doc.Root.Add(new XAttribute("md5hash", hash.Hash)); @@ -517,17 +559,29 @@ namespace Barotrauma return true; } + public void SaveToXElement(XElement element) + { + element.Add(new XAttribute("name", name)); + element.Add(new XAttribute("description", Description == null ? "" : Description)); + + foreach (MapEntity e in MapEntity.mapEntityList) + { + if (e.MoveWithLevel || e.Submarine != this) continue; + e.Save(element); + } + } + public static bool SaveCurrent(string filePath) { - if (loaded==null) + if (Submarine.MainSub == null) { - loaded = new Submarine(filePath); + Submarine.MainSub = new Submarine(filePath); // return; } - loaded.filePath = filePath; + Submarine.MainSub.filePath = filePath; - return loaded.SaveAs(filePath); + return Submarine.MainSub.SaveAs(filePath); } public void CheckForErrors() @@ -614,7 +668,7 @@ namespace Barotrauma //if (GameMain.NetLobbyScreen!=null) GameMain.NetLobbyScreen.UpdateSubList(Submarine.SavedSubmarines); } - private XDocument OpenDoc(string file) + public static XDocument OpenFile(string file) { XDocument doc = null; string extension = ""; @@ -684,18 +738,36 @@ namespace Barotrauma return doc; } - public void Load() + public void Load(bool unloadPrevious, XElement submarineElement = null) { - Unload(); + if (unloadPrevious) Unload(); Loading = true; - XDocument doc = OpenDoc(filePath); - if (doc == null || doc.Root == null) return; + if (submarineElement == null) + { + XDocument doc = OpenFile(filePath); + if (doc == null || doc.Root == null) return; - Description = ToolBox.GetAttributeString(doc.Root, "description", ""); + submarineElement = doc.Root; + } - foreach (XElement element in doc.Root.Elements()) + Description = ToolBox.GetAttributeString(submarineElement, "description", ""); + + + HiddenSubPosition = HiddenSubStartPosition; + foreach (Submarine sub in Submarine.loaded) + { + HiddenSubPosition += Vector2.UnitY * (sub.Borders.Height + 5000.0f); + } + + IdOffset = 0; + foreach (MapEntity me in MapEntity.mapEntityList) + { + IdOffset = Math.Max(IdOffset, me.ID); + } + + foreach (XElement element in submarineElement.Elements()) { string typeName = element.Name.ToString(); @@ -728,11 +800,13 @@ namespace Barotrauma Vector2 center = Vector2.Zero; - if (Hull.hullList.Any()) + var matchingHulls = Hull.hullList.FindAll(h => h.Submarine == this); + + if (matchingHulls.Any()) { - Vector2 topLeft = new Vector2(Hull.hullList[0].Rect.X, Hull.hullList[0].Rect.Y); - Vector2 bottomRight = new Vector2(Hull.hullList[0].Rect.X, Hull.hullList[0].Rect.Y); - foreach (Hull hull in Hull.hullList) + Vector2 topLeft = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y); + Vector2 bottomRight = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y); + foreach (Hull hull in matchingHulls) { if (hull.Rect.X < topLeft.X) topLeft.X = hull.Rect.X; if (hull.Rect.Y > topLeft.Y) topLeft.Y = hull.Rect.Y; @@ -747,6 +821,8 @@ namespace Barotrauma foreach (Item item in Item.ItemList) { + if (item.Submarine != this) continue; + var wire = item.GetComponent(); if (wire == null) continue; @@ -758,7 +834,7 @@ namespace Barotrauma for (int i = 0; i < MapEntity.mapEntityList.Count; i++) { - if (MapEntity.mapEntityList[i].Submarine == null) continue; + if (MapEntity.mapEntityList[i].Submarine != this) continue; MapEntity.mapEntityList[i].Move(-center); } @@ -766,10 +842,10 @@ namespace Barotrauma subBody = new SubmarineBody(this); subBody.SetPosition(HiddenSubPosition); - - loaded = this; - Hull.GenerateEntityGrid(); + loaded.Add(this); + + Hull.GenerateEntityGrid(this); for (int i = 0; i < MapEntity.mapEntityList.Count; i++) { @@ -779,28 +855,40 @@ namespace Barotrauma Loading = false; - MapEntity.MapLoaded(); + MapEntity.MapLoaded(this); //WayPoint.GenerateSubWaypoints(); GameMain.LightManager.OnMapLoaded(); - ID = ushort.MaxValue; + ID = (ushort)(ushort.MaxValue - Submarine.loaded.IndexOf(this)); } - public static Submarine Load(string fileName) + public static Submarine Load(XElement element, bool unloadPrevious) { - return Load(fileName, SavePath); + if (unloadPrevious) Unload(); + + //tryload -> false + + Submarine sub = new Submarine(ToolBox.GetAttributeString(element, "name", ""), "", false); + sub.Load(unloadPrevious, element); + + return sub; } - public static Submarine Load(string fileName, string folder) + public static Submarine Load(string fileName, bool unloadPrevious) { - Unload(); + return Load(fileName, SavePath, unloadPrevious); + } + + public static Submarine Load(string fileName, string folder, bool unloadPrevious) + { + if (unloadPrevious) Unload(); string path = string.IsNullOrWhiteSpace(folder) ? fileName : System.IO.Path.Combine(SavePath, fileName); Submarine sub = new Submarine(path); - sub.Load(); + sub.Load(unloadPrevious); //Entity.dictionary.Add(int.MaxValue, sub); @@ -809,33 +897,38 @@ namespace Barotrauma public static void Unload() { - if (loaded == null) return; Sound.OnGameEnd(); if (GameMain.LightManager != null) GameMain.LightManager.ClearLights(); - - loaded.Remove(); + + + foreach (Submarine sub in loaded) + { + sub.Remove(); + } loaded.Clear(); - loaded = null; - } - private void Clear() - { if (GameMain.GameScreen.Cam != null) GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; Entity.RemoveAll(); - - subBody = null; - - PhysicsBody.list.Clear(); + PhysicsBody.list.Clear(); + Ragdoll.list.Clear(); GameMain.World.Clear(); } + public override void Remove() + { + base.Remove(); + + subBody = null; + + DockedTo.Clear(); + } } } diff --git a/Subsurface/Source/Map/SubmarineBody.cs b/Subsurface/Source/Map/SubmarineBody.cs index 5341d9f7a..2802e4fd0 100644 --- a/Subsurface/Source/Map/SubmarineBody.cs +++ b/Subsurface/Source/Map/SubmarineBody.cs @@ -33,11 +33,11 @@ namespace Barotrauma private readonly Submarine submarine; - private readonly Body body; + public readonly Body Body; private Vector2? targetPosition; - private float mass = 10000.0f; + //private float mass = 10000.0f; public Rectangle Borders { @@ -47,11 +47,11 @@ namespace Barotrauma public Vector2 Velocity { - get { return body.LinearVelocity; } + get { return Body.LinearVelocity; } set { if (!MathUtils.IsValid(value)) return; - body.LinearVelocity = value; + Body.LinearVelocity = value; } } @@ -67,7 +67,7 @@ namespace Barotrauma public Vector2 Position { - get { return ConvertUnits.ToDisplayUnits(body.Position); } + get { return ConvertUnits.ToDisplayUnits(Body.Position); } } public bool AtDamageDepth @@ -82,7 +82,7 @@ namespace Barotrauma if (!Hull.hullList.Any()) { - body = BodyFactory.CreateRectangle(GameMain.World, 1.0f, 1.0f, 1.0f); + 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."); } else @@ -110,59 +110,53 @@ namespace Barotrauma //var triangulatedVertices = Triangulate.ConvexPartition(shapevertices, TriangulationAlgorithm.Bayazit); - body = BodyFactory.CreateBody(GameMain.World, this); + Body = BodyFactory.CreateBody(GameMain.World, this); foreach (Structure wall in Structure.WallList) { + if (wall.Submarine != submarine) continue; + Rectangle rect = wall.Rect; FixtureFactory.AttachRectangle( ConvertUnits.ToSimUnits(rect.Width), ConvertUnits.ToSimUnits(rect.Height), - 5.0f, + 50.0f, ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)), - body, this); + Body, 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); - //} + foreach (Hull hull in Hull.hullList) + { + Rectangle rect = hull.Rect; + 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.CollisionWall; - body.CollidesWith = Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionCharacter | Physics.CollisionProjectile; - body.Restitution = Restitution; - body.Friction = Friction; - body.FixedRotation = true; - body.Mass = mass; - body.Awake = true; - body.SleepingAllowed = false; - body.IgnoreGravity = true; - body.OnCollision += OnCollision; - body.UserData = submarine; + Body.BodyType = BodyType.Dynamic; + Body.CollisionCategories = Physics.CollisionWall; + Body.CollidesWith = + Physics.CollisionItem | + Physics.CollisionLevel | + Physics.CollisionCharacter | + Physics.CollisionProjectile | + Physics.CollisionWall; + + Body.Restitution = Restitution; + Body.Friction = Friction; + Body.FixedRotation = true; + //mass = Body.Mass; + Body.Awake = true; + Body.SleepingAllowed = false; + Body.IgnoreGravity = true; + Body.OnCollision += OnCollision; + Body.UserData = submarine; } @@ -175,48 +169,17 @@ namespace Barotrauma List points = new List(); - Vector2 leftMost = Vector2.Zero; - foreach (Structure wall in Structure.WallList) { - for (int x = -1; x <= 1; x += 2) - { - for (int y = -1; y <= 1; y += 2) - { - Vector2 corner = new Vector2(wall.Rect.X + wall.Rect.Width / 2.0f, wall.Rect.Y - wall.Rect.Height / 2.0f); - corner.X += x * wall.Rect.Width / 2.0f; - corner.Y += y * wall.Rect.Height / 2.0f; + if (wall.Submarine != submarine) continue; - if (points.Contains(corner)) continue; - - points.Add(corner); - if (leftMost == Vector2.Zero || corner.X < leftMost.X) leftMost = corner; - } - } + points.Add(new Vector2(wall.Rect.X, wall.Rect.Y)); + points.Add(new Vector2(wall.Rect.X + wall.Rect.Width, wall.Rect.Y)); + points.Add(new Vector2(wall.Rect.X, wall.Rect.Y - wall.Rect.Height)); + points.Add(new Vector2(wall.Rect.X + wall.Rect.Width, wall.Rect.Y - wall.Rect.Height)); } - List hullPoints = new List(); - - Vector2 currPoint = leftMost; - Vector2 endPoint; - do - { - hullPoints.Add(currPoint); - endPoint = points[0]; - - for (int i = 1; i < points.Count; i++) - { - if ((currPoint == endPoint) - || (MathUtils.VectorOrientation(currPoint, endPoint, points[i]) == -1)) - { - endPoint = points[i]; - } - } - - currPoint = endPoint; - - } - while (endPoint != hullPoints[0]); + List hullPoints = MathUtils.GiftWrap(points); return hullPoints; } @@ -229,11 +192,15 @@ namespace Barotrauma if (dist > 1000.0f) //immediately snap the sub to the target position if more than 1000.0f units away { - Vector2 moveAmount = (Vector2)targetPosition - ConvertUnits.ToDisplayUnits(body.Position); + Vector2 moveAmount = (Vector2)targetPosition - ConvertUnits.ToDisplayUnits(Body.Position); ForceTranslate(moveAmount); - GameMain.GameScreen.Cam.UpdateTransform(false); + if ((Character.Controlled != null && Character.Controlled.Submarine == submarine) || + (Character.Controlled == null && Submarine.GetClosest(GameMain.GameScreen.Cam.WorldViewCenter) == submarine)) + { + GameMain.GameScreen.Cam.UpdateTransform(false); + } submarine.SetPrevTransform(submarine.Position); submarine.UpdateTransform(); @@ -262,14 +229,14 @@ namespace Barotrauma Vector2 totalForce = CalculateBuoyancy(); - if (body.LinearVelocity.LengthSquared() > 0.000001f) + if (Body.LinearVelocity.LengthSquared() > 0.000001f) { float dragCoefficient = 0.01f; - float speedLength = (body.LinearVelocity == Vector2.Zero) ? 0.0f : body.LinearVelocity.Length(); - float drag = speedLength * speedLength * dragCoefficient * mass; + float speedLength = (Body.LinearVelocity == Vector2.Zero) ? 0.0f : Body.LinearVelocity.Length(); + float drag = speedLength * speedLength * dragCoefficient * Body.Mass; - totalForce += -Vector2.Normalize(body.LinearVelocity) * drag; + totalForce += -Vector2.Normalize(Body.LinearVelocity) * drag; } ApplyForce(totalForce); @@ -284,11 +251,15 @@ namespace Barotrauma /// Amount to move in display units private void ForceTranslate(Vector2 amount) { - body.SetTransform(body.Position + ConvertUnits.ToSimUnits(amount), 0.0f); + Body.SetTransform(Body.Position + ConvertUnits.ToSimUnits(amount), 0.0f); if (Character.Controlled != null) Character.Controlled.CursorPosition += amount; - GameMain.GameScreen.Cam.Position += amount; - if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += amount; + if ((Character.Controlled != null && Character.Controlled.Submarine == submarine) || + (Character.Controlled == null && Submarine.GetClosest(GameMain.GameScreen.Cam.WorldViewCenter) == submarine)) + { + GameMain.GameScreen.Cam.Position += amount; + if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += amount; + } } @@ -300,7 +271,7 @@ namespace Barotrauma private void DisplaceCharacters(Vector2 subTranslation) { Rectangle worldBorders = Borders; - worldBorders.Location += ConvertUnits.ToDisplayUnits(body.Position).ToPoint(); + worldBorders.Location += ConvertUnits.ToDisplayUnits(Body.Position).ToPoint(); Vector2 translateDir = Vector2.Normalize(subTranslation); @@ -336,6 +307,8 @@ namespace Barotrauma float volume = 0.0f; foreach (Hull hull in Hull.hullList) { + if (hull.Submarine != submarine) continue; + waterVolume += hull.Volume; volume += hull.FullVolume; } @@ -345,19 +318,19 @@ namespace Barotrauma float neutralPercentage = 0.07f; float buoyancy = Math.Max(neutralPercentage - waterPercentage, -neutralPercentage*2.0f); - buoyancy *= mass; + buoyancy *= Body.Mass; return new Vector2(0.0f, buoyancy*10.0f); } public void ApplyForce(Vector2 force) { - body.ApplyForce(force); + Body.ApplyForce(force); } public void SetPosition(Vector2 position) { - body.SetTransform(ConvertUnits.ToSimUnits(position), 0.0f); + Body.SetTransform(ConvertUnits.ToSimUnits(position), 0.0f); } private void UpdateDepthDamage(float deltaTime) @@ -392,7 +365,7 @@ namespace Barotrauma (Rand.Int(2) == 0) ? Borders.Y : Borders.Y - Borders.Height); } - damagePos += submarine.Position + Submarine.HiddenSubPosition; + damagePos += submarine.Position + submarine.HiddenSubPosition; SoundPlayer.PlayDamageSound(DamageSoundType.Pressure, 50.0f, damagePos, 10000.0f); GameMain.GameScreen.Cam.Shake = depth * PressureDamageMultiplier * 0.1f; @@ -405,18 +378,15 @@ namespace Barotrauma public bool OnCollision(Fixture f1, Fixture f2, Contact contact) { - VoronoiCell cell = f2.Body.UserData as VoronoiCell; - - if (cell == null) + Limb limb = f2.Body.UserData as Limb; + if (limb!= null) { - Limb limb = f2.Body.UserData as Limb; - if (limb == null) return true; bool collision = HandleLimbCollision(contact, limb); if (collision && limb.Mass > 100.0f) { - Vector2 normal = Vector2.Normalize(body.Position - limb.SimPosition); + Vector2 normal = Vector2.Normalize(Body.Position - limb.SimPosition); float impact = Math.Min(Vector2.Dot(Velocity - limb.LinearVelocity, -normal), 5.0f); @@ -426,12 +396,32 @@ namespace Barotrauma return collision; } - var collisionNormal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(body.Position) - cell.Center); + VoronoiCell cell = f2.Body.UserData as VoronoiCell; + if (cell != null) + { + var collisionNormal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(Body.Position) - cell.Center); - float wallImpact = Vector2.Dot(Velocity, -collisionNormal); + float wallImpact = Vector2.Dot(Velocity, -collisionNormal); - ApplyImpact(wallImpact, -collisionNormal, contact); + ApplyImpact(wallImpact, -collisionNormal, contact); + return true; + } + + Submarine sub = f2.Body.UserData as Submarine; + if (sub != null) + { + Debug.Assert(sub != submarine); + + Vector2 normal; + FixedArray2 points; + contact.GetWorldManifold(out normal, out points); + + ApplyImpact(Vector2.Dot(Velocity - sub.Velocity, normal) / 2.0f, normal, contact); + + return true; + } + return true; } @@ -498,7 +488,7 @@ namespace Barotrauma foreach (Character c in Character.CharacterList) { - if (c.AnimController.CurrentHull == null) continue; + if (c.Submarine != submarine) continue; if (impact > 2.0f) c.StartStun((impact - 2.0f) * 0.1f); diff --git a/Subsurface/Source/Map/TransitionCinematic.cs b/Subsurface/Source/Map/TransitionCinematic.cs index ce2fa7f5c..b0e14352b 100644 --- a/Subsurface/Source/Map/TransitionCinematic.cs +++ b/Subsurface/Source/Map/TransitionCinematic.cs @@ -66,7 +66,7 @@ namespace Barotrauma cam.Zoom = Math.Max(0.2f, cam.Zoom - CoroutineManager.UnscaledDeltaTime * 0.1f); - Vector2 cameraPos = sub.Position + Submarine.HiddenSubPosition; + Vector2 cameraPos = sub.Position + Submarine.MainSub.HiddenSubPosition; cameraPos.Y = Math.Min(cameraPos.Y, ConvertUnits.ToDisplayUnits(Level.Loaded.ShaftBodies[0].Position.Y) - cam.WorldView.Height/2.0f); GUI.ScreenOverlayColor = Color.Lerp(Color.TransparentBlack, Color.Black, timer/duration); diff --git a/Subsurface/Source/Map/WayPoint.cs b/Subsurface/Source/Map/WayPoint.cs index 2197edc70..1a0f77b70 100644 --- a/Subsurface/Source/Map/WayPoint.cs +++ b/Subsurface/Source/Map/WayPoint.cs @@ -83,7 +83,7 @@ namespace Barotrauma } public WayPoint(MapEntityPrefab prefab, Rectangle rectangle) - : this (rectangle, Submarine.Loaded) + : this (rectangle, Submarine.MainSub) { if (prefab.Name.Contains("Spawn")) { @@ -306,7 +306,7 @@ namespace Barotrauma return editingHUD; } - public static void GenerateSubWaypoints() + public static void GenerateSubWaypoints(Submarine submarine) { if (!Hull.hullList.Any()) { @@ -332,13 +332,13 @@ namespace Barotrauma if (hull.Rect.Width(); if (door != null) { - WayPoint newPoint = new WayPoint(door.Item.Position, SpawnType.Path, Submarine.Loaded); + WayPoint newPoint = new WayPoint(door.Item.Position, SpawnType.Path, submarine); newPoint.Ladders = ladders; newPoint.ConnectedGap = door.LinkedGap; @@ -538,7 +539,7 @@ namespace Barotrauma if (gap.Rect.Height < 150.0f) continue; var wayPoint = new WayPoint( - new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height + heightFromFloor), SpawnType.Path, Submarine.Loaded, gap); + new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height + heightFromFloor), SpawnType.Path, submarine, gap); for (int dir = -1; dir <= 1; dir += 2) { @@ -557,7 +558,7 @@ namespace Barotrauma if (gap.Rect.Width < 100.0f) continue; var wayPoint = new WayPoint( - new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height/2), SpawnType.Path, Submarine.Loaded, gap); + new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height/2), SpawnType.Path, submarine, gap); for (int dir = -1; dir <= 1; dir += 2) { @@ -583,35 +584,35 @@ namespace Barotrauma WayPoint closest = null; - foreach (WayPoint wp in WayPointList) + foreach (WayPoint wp in WayPointList) + { + if (wp.SpawnType != SpawnType.Path || wp == this) continue; + + float diff = 0.0f; + if (horizontalSearch) { - if (wp.SpawnType != SpawnType.Path || wp == this) continue; + if ((wp.Position.Y - Position.Y) < tolerance.X || (wp.Position.Y - Position.Y) > tolerance.Y) continue; - float diff = 0.0f; - if (horizontalSearch) - { - if ((wp.Position.Y - Position.Y) < tolerance.X || (wp.Position.Y - Position.Y) > tolerance.Y) continue; - - diff = wp.Position.X - Position.X; - } - else - { - if ((wp.Position.X - Position.X) < tolerance.X || (wp.Position.X - Position.X) > tolerance.Y) continue; - - diff = wp.Position.Y - Position.Y; - } - - if (Math.Sign(diff) != dir) continue; - - float dist = Vector2.Distance(wp.Position, Position); - if (closest == null || dist < closestDist) - { - if (Submarine.CheckVisibility(SimPosition, wp.SimPosition) != null) continue; - - closestDist = dist; - closest = wp; - } + diff = wp.Position.X - Position.X; } + else + { + if ((wp.Position.X - Position.X) < tolerance.X || (wp.Position.X - Position.X) > tolerance.Y) continue; + + diff = wp.Position.Y - Position.Y; + } + + if (Math.Sign(diff) != dir) continue; + + float dist = Vector2.Distance(wp.Position, Position); + if (closest == null || dist < closestDist) + { + if (Submarine.CheckVisibility(SimPosition, wp.SimPosition) != null) continue; + + closestDist = dist; + closest = wp; + } + } return closest; @@ -640,13 +641,11 @@ namespace Barotrauma return wayPoints[Rand.Int(wayPoints.Count(), false)]; } - public static WayPoint[] SelectCrewSpawnPoints(List crew) + public static WayPoint[] SelectCrewSpawnPoints(List crew, Submarine submarine) { - List unassignedWayPoints = new List(); - foreach (WayPoint wp in WayPointList) - { - if (wp.spawnType == SpawnType.Human) unassignedWayPoints.Add(wp); - } + List subWayPoints = WayPointList.FindAll(wp => wp.Submarine == submarine); + + List unassignedWayPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human); WayPoint[] assignedWayPoints = new WayPoint[crew.Count]; @@ -669,7 +668,7 @@ namespace Barotrauma if (assignedWayPoints[i] != null) continue; //try to assign a spawnpoint that matches the job, even if the spawnpoint is already assigned to someone else - foreach (WayPoint wp in WayPointList) + foreach (WayPoint wp in subWayPoints) { if (wp.spawnType != SpawnType.Human || wp.assignedJob != crew[i].Job.Prefab) continue; @@ -680,7 +679,7 @@ namespace Barotrauma if (assignedWayPoints[i] != null) continue; //try to assign a spawnpoint that isn't meant for any specific job - var nonJobSpecificPoints = WayPointList.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null); + var nonJobSpecificPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null); if (nonJobSpecificPoints.Any()) { @@ -719,7 +718,7 @@ namespace Barotrauma } } - public override XElement Save(XDocument doc) + public override XElement Save(XElement parentElement) { if (MoveWithLevel) return null; XElement element = new XElement("WayPoint"); @@ -740,7 +739,7 @@ namespace Barotrauma if (ConnectedGap != null) element.Add(new XAttribute("gap", ConnectedGap.ID)); if (Ladders != null) element.Add(new XAttribute("ladders", Ladders.Item.ID)); - doc.Root.Add(element); + parentElement.Add(element); if (linkedTo != null) { diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 0cc704603..bfc5100d6 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -413,6 +413,11 @@ namespace Barotrauma.Networking reliableChannel.Update(deltaTime); + if (gameStarted && respawnManager != null) + { + respawnManager.Update(deltaTime); + } + if (updateTimer > DateTime.Now) return; if (myCharacter != null) @@ -518,6 +523,9 @@ namespace Barotrauma.Networking string endMessage = inc.ReadString(); CoroutineManager.StartCoroutine(EndGame(endMessage)); break; + case (byte)PacketTypes.Respawn: + if (gameStarted && respawnManager != null) respawnManager.ReadNetworkEvent(inc); + break; case (byte)PacketTypes.PlayerJoined: Client otherClient = new Client(inc.ReadString(), inc.ReadByte()); @@ -672,7 +680,9 @@ namespace Barotrauma.Networking GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, Mission.MissionTypes[missionTypeIndex]); GameMain.GameSession.StartShift(levelSeed); - + + respawnManager = new RespawnManager(this); + yield return CoroutineStatus.Running; //myCharacter = ReadCharacterData(inc); @@ -725,11 +735,13 @@ namespace Barotrauma.Networking GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; GameMain.LightManager.LosEnabled = false; + respawnManager = null; + float endPreviewLength = 10.0f; if (Screen.Selected == GameMain.GameScreen) { - var cinematic = new TransitionCinematic(Submarine.Loaded, GameMain.GameScreen.Cam, endPreviewLength); + var cinematic = new TransitionCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, endPreviewLength); float secondsLeft = endPreviewLength; @@ -774,11 +786,6 @@ namespace Barotrauma.Networking if (fileStreamReceiver != null && (fileStreamReceiver.Status == FileTransferStatus.Receiving || fileStreamReceiver.Status == FileTransferStatus.NotStarted)) { - //Vector2 pos = Screen.Selected == GameMain.NetLobbyScreen ? - // new Vector2(GameMain.NetLobbyScreen.SubList.Rect.X, GameMain.NetLobbyScreen.SubList.Rect.Bottom+5) : new Vector2(GameMain.GraphicsWidth / 2 - 200, 10); - - - Vector2 pos = new Vector2(GameMain.GraphicsWidth / 2 - 130, GameMain.NetLobbyScreen.InfoFrame.Rect.Y / 2 - 15); GUI.DrawString(spriteBatch, @@ -799,6 +806,16 @@ namespace Barotrauma.Networking } } + if (respawnManager != null && respawnManager.CurrentState == RespawnManager.State.Waiting && + myCharacter != null && myCharacter.IsDead) + { + GUI.DrawString(spriteBatch, + new Vector2(GameMain.GraphicsWidth - 300.0f, 20), + "Respawning in " + (int)respawnManager.RespawnTimer + " s", + Color.White, null, 0, GUI.SmallFont); + } + + if (!GameMain.DebugDraw) return; int width = 200, height = 300; @@ -1023,7 +1040,7 @@ namespace Barotrauma.Networking client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } - private Character ReadCharacterData(NetIncomingMessage inc, bool isMyCharacter) + public Character ReadCharacterData(NetIncomingMessage inc, bool isMyCharacter) { string newName = inc.ReadString(); ushort ID = inc.ReadUInt16(); diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 27a98914e..f29fad662 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -282,6 +282,8 @@ namespace Barotrauma.Networking { inGameHUD.Update((float)Physics.step); + respawnManager.Update(deltaTime); + bool isCrewDead = connectedClients.Find(c => c.Character != null && !c.Character.IsDead)==null && (myCharacter == null || myCharacter.IsDead); @@ -289,7 +291,7 @@ namespace Barotrauma.Networking //restart if all characters are dead or submarine is at the end of the level if ((autoRestart && isCrewDead) || - (endRoundAtLevelEnd && Submarine.Loaded!=null && Submarine.Loaded.AtEndPosition)) + (endRoundAtLevelEnd && Submarine.MainSub != null && Submarine.MainSub.AtEndPosition)) { if (AutoRestart && isCrewDead) { @@ -363,9 +365,10 @@ namespace Barotrauma.Networking { if (!(c is AICharacter) || c.IsDead) continue; - Vector2 diff = c.WorldPosition-Submarine.Loaded.WorldPosition; + //todo: take multiple subs into account + //Vector2 diff = c.WorldPosition - Submarine.MainSub.WorldPosition; - if (FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) > NetConfig.CharacterIgnoreDistance) continue; + //if (FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) > NetConfig.CharacterIgnoreDistance) continue; new NetworkEvent(NetworkEventType.EntityUpdate, c.ID, false); } @@ -389,7 +392,13 @@ namespace Barotrauma.Networking private void SparseUpdate() { - if (gameStarted) new NetworkEvent(Submarine.Loaded.ID, false); + if (gameStarted) + { + foreach (Submarine sub in Submarine.Loaded) + { + new NetworkEvent(sub.ID, false); + } + } foreach (Character c in Character.CharacterList) { @@ -397,9 +406,10 @@ namespace Barotrauma.Networking if (c is AICharacter) { - Vector2 diff = c.WorldPosition - Submarine.Loaded.WorldPosition; + //todo: take multiple subs into account + //Vector2 diff = c.WorldPosition - Submarine.MainSub.WorldPosition; - if (FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) > NetConfig.CharacterIgnoreDistance) continue; + //if (FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) > NetConfig.CharacterIgnoreDistance) continue; } new NetworkEvent(NetworkEventType.ImportantEntityUpdate, c.ID, false); @@ -601,7 +611,7 @@ namespace Barotrauma.Networking case (byte)PacketTypes.SpectateRequest: if (gameStarted && allowSpectating) { - var startMessage = CreateStartMessage(roundStartSeed, Submarine.Loaded, GameMain.GameSession.gameMode.Preset); + var startMessage = CreateStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.gameMode.Preset); server.SendMessage(startMessage, inc.SenderConnection, NetDeliveryMethod.ReliableUnordered); dataSender.Spectating = true; @@ -840,6 +850,10 @@ namespace Barotrauma.Networking //save "normal" events again existingEvents = new List(NetworkEvent.Events); } + + yield return new WaitForSeconds(0.1f); + + sender.inGame = true; yield return CoroutineStatus.Success; } @@ -941,6 +955,8 @@ namespace Barotrauma.Networking GameServer.Log("Game mode: " + selectedMode.Name, Color.Cyan); GameServer.Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, Color.Cyan); + respawnManager = new RespawnManager(this); + yield return CoroutineStatus.Running; List characterInfos = new List(); @@ -964,7 +980,7 @@ namespace Barotrauma.Networking characterInfos.Add(characterInfo); } - WayPoint[] assignedWayPoints = WayPoint.SelectCrewSpawnPoints(characterInfos); + WayPoint[] assignedWayPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); for (int i = 0; i < connectedClients.Count; i++) { @@ -985,7 +1001,7 @@ namespace Barotrauma.Networking GameMain.GameSession.CrewManager.characters.Add(myCharacter); } - var startMessage = CreateStartMessage(roundStartSeed, Submarine.Loaded, GameMain.GameSession.gameMode.Preset); + var startMessage = CreateStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.gameMode.Preset); SendMessage(startMessage, NetDeliveryMethod.ReliableUnordered); @@ -1090,6 +1106,8 @@ namespace Barotrauma.Networking GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; GameMain.LightManager.LosEnabled = false; + respawnManager = null; + gameStarted = false; if (connectedClients.Count > 0) @@ -1113,7 +1131,7 @@ namespace Barotrauma.Networking float endPreviewLength = 10.0f; - var cinematic = new TransitionCinematic(Submarine.Loaded, GameMain.GameScreen.Cam, endPreviewLength); + var cinematic = new TransitionCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, endPreviewLength); float secondsLeft = endPreviewLength; @@ -1132,6 +1150,14 @@ namespace Barotrauma.Networking } + public void SendRespawnManagerMsg() + { + NetOutgoingMessage msg = server.CreateMessage(); + respawnManager.WriteNetworkEvent(msg); + + SendMessage(msg, NetDeliveryMethod.ReliableUnordered); + } + private void DisconnectClient(NetConnection senderConnection, string msg = "", string targetmsg = "") { Client client = connectedClients.Find(x => x.Connection == senderConnection); @@ -1322,6 +1348,14 @@ namespace Barotrauma.Networking log.LogFrame.Draw(spriteBatch); } + if (respawnManager != null && respawnManager.CurrentState == RespawnManager.State.Waiting && respawnManager.CountdownStarted) + { + GUI.DrawString(spriteBatch, + new Vector2(GameMain.GraphicsWidth - 500.0f, 20), + "Respawning in " + (int)respawnManager.RespawnTimer + " s", + Color.White, null, 0, GUI.SmallFont); + } + if (!ShowNetStats) return; int width = 200, height = 300; @@ -1603,7 +1637,7 @@ namespace Barotrauma.Networking } } - private void WriteCharacterData(NetOutgoingMessage message, string name, Character character) + public void WriteCharacterData(NetOutgoingMessage message, string name, Character character) { message.Write(name); message.Write(character.ID); diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index 7a167d71f..6b7edd427 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -39,7 +39,9 @@ namespace Barotrauma.Networking RequestFile, FileStream, - SpectateRequest + SpectateRequest, + + Respawn } enum VoteType @@ -74,6 +76,9 @@ namespace Barotrauma.Networking protected Character myCharacter; protected CharacterInfo characterInfo; + + protected RespawnManager respawnManager; + public Voting Voting; public Character Character diff --git a/Subsurface/Source/Networking/RespawnManager.cs b/Subsurface/Source/Networking/RespawnManager.cs new file mode 100644 index 000000000..1b5a4d2f5 --- /dev/null +++ b/Subsurface/Source/Networking/RespawnManager.cs @@ -0,0 +1,312 @@ +using Barotrauma.Items.Components; +using FarseerPhysics; +using Lidgren.Network; +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Barotrauma.Networking +{ + class RespawnManager + { + const int MinCharactersToRespawn = 1; + + const float RespawnInterval = 20.0f; + + public enum State + { + Waiting, + Transporting, + Returning + } + + private NetworkMember networkMember; + + private State state; + + private Submarine respawnShuttle; + private Steering shuttleSteering; + private List shuttleDoors; + + public float RespawnTimer + { + get { return respawnTimer; } + } + + public bool CountdownStarted + { + get; + private set; + } + + public State CurrentState + { + get { return state; } + } + + private float respawnTimer, shuttleReturnTimer; + + public RespawnManager(NetworkMember server) + { + this.networkMember = server; + + respawnShuttle = new Submarine("Submarines/Shuttle Mark I.sub"); + respawnShuttle.Load(false); + + ResetShuttlePos(); + + respawnShuttle.GodMode = true; + + shuttleDoors = new List(); + foreach (Item item in Item.ItemList) + { + if (item.Submarine != respawnShuttle) continue; + + var steering = item.GetComponent(); + if (steering != null) shuttleSteering = steering; + + var door = item.GetComponent(); + if (door != null) shuttleDoors.Add(door); + } + + shuttleSteering.TargetPosition = ConvertUnits.ToSimUnits(Level.Loaded.StartPosition); + + respawnTimer = RespawnInterval; + } + + private List GetClientsToRespawn() + { + return networkMember.ConnectedClients.FindAll(c => c.inGame && (c.Character == null || c.Character.IsDead)); + } + + public void Update(float deltaTime) + { + switch (state) + { + case State.Waiting: + UpdateWaiting(deltaTime); + break; + case State.Transporting: + UpdateTransporting(deltaTime); + break; + case State.Returning: + UpdateReturning(deltaTime); + break; + } + } + + private void UpdateWaiting(float deltaTime) + { + var server = networkMember as GameServer; + if (server == null) + { + if (CountdownStarted) + { + respawnTimer = Math.Max(0.0f, respawnTimer - deltaTime); + } + return; + } + + respawnShuttle.Velocity = Vector2.Zero; + + shuttleSteering.AutoPilot = false; + shuttleSteering.MaintainPos = false; + + int characterToRespawnCount = GetClientsToRespawn().Count; + if (server.Character != null && server.Character.IsDead) characterToRespawnCount++; + + CountdownStarted = characterToRespawnCount >= MinCharactersToRespawn; + + if (!CountdownStarted) return; + + respawnTimer -= deltaTime; + if (respawnTimer <= 0.0f) + { + respawnTimer = RespawnInterval; + + Respawn(); + } + } + + private void UpdateTransporting(float deltaTime) + { + var server = networkMember as GameServer; + if (server == null) return; + + if (Character.CharacterList.Any(c => c.Submarine == respawnShuttle && !c.IsDead)) return; + + shuttleReturnTimer += deltaTime; + if (shuttleReturnTimer > 10.0f) + { + state = State.Returning; + + server.SendRespawnManagerMsg(); + shuttleReturnTimer = 0.0f; + } + } + + private void UpdateReturning(float deltaTime) + { + shuttleReturnTimer += deltaTime; + + if (shuttleReturnTimer > 1.0f) + { + shuttleSteering.AutoPilot = true; + shuttleSteering.MaintainPos = false; + + foreach (Door door in shuttleDoors) + { + if (door.IsOpen) door.SetState(false, false, true); + } + + var server = networkMember as GameServer; + if (server == null) return; + + //shuttle has returned if the path has been traversed or the shuttle is close enough to the exit + if (shuttleSteering.SteeringPath != null && shuttleSteering.SteeringPath.Finished + || (respawnShuttle.WorldPosition.Y + respawnShuttle.Borders.Y > Level.Loaded.StartPosition.Y - Level.ShaftHeight && + Math.Abs(Level.Loaded.StartPosition.X - respawnShuttle.WorldPosition.X) < 1000.0f)) + { + CoroutineManager.StartCoroutine( + ForceShuttleToPos(new Vector2(Level.Loaded.StartPosition.X, Level.Loaded.Size.Y + 1000.0f), 100.0f)); + + if (GameMain.GameSession != null && GameMain.GameSession.Map != null) + { + string msg = "The transportation shuttle has returned to " + GameMain.GameSession.Map.SelectedLocation; + + server.SendChatMessage(ChatMessage.Create("", msg, ChatMessageType.Server, null), server.ConnectedClients); + } + + state = State.Waiting; + server.SendRespawnManagerMsg(); + } + + shuttleReturnTimer = 0.0f; + } + } + + private void Respawn() + { + var server = networkMember as GameServer; + if (server == null) return; + + state = State.Transporting; + + ResetShuttlePos(); + + server.SendChatMessage(ChatMessage.Create("", "Transportation shuttle dispatched", ChatMessageType.Server, null), server.ConnectedClients); + + server.SendRespawnManagerMsg(); + + CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition - Vector2.UnitY * Level.ShaftHeight, 100.0f)); + } + + private IEnumerable ForceShuttleToPos(Vector2 position, float speed) + { + respawnShuttle.SubBody.Body.IgnoreCollisionWith(Level.Loaded.ShaftBodies[0]); + + while (Math.Abs(position.Y - respawnShuttle.WorldPosition.Y) > 100.0f) + { + Vector2 displayVel = Vector2.Normalize(position - respawnShuttle.WorldPosition) * speed; + respawnShuttle.SubBody.Body.LinearVelocity = ConvertUnits.ToSimUnits(displayVel); + yield return CoroutineStatus.Running; + + if (respawnShuttle.SubBody == null) yield return CoroutineStatus.Success; + } + + respawnShuttle.SubBody.Body.RestoreCollisionWith(Level.Loaded.ShaftBodies[0]); + + yield return CoroutineStatus.Success; + } + + private void ResetShuttlePos() + { + respawnShuttle.SetPosition(new Vector2(Level.Loaded.StartPosition.X, Level.Loaded.Size.Y + respawnShuttle.Borders.Height)); + + respawnShuttle.Velocity = Vector2.Zero; + } + + public void WriteNetworkEvent(NetOutgoingMessage msg) + { + var server = networkMember as GameServer; + + msg.Write((byte)PacketTypes.Respawn); + + msg.WriteRangedInteger(0, Enum.GetNames(typeof(State)).Length, (int)state); + + switch (state) + { + case State.Transporting: + var clients = GetClientsToRespawn(); + + List characterInfos = clients.Select(c => c.characterInfo).ToList(); + if (server.Character != null && server.Character.IsDead) characterInfos.Add(server.CharacterInfo); + + var waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, respawnShuttle); + + msg.Write((byte)characterInfos.Count); + for (int i = 0; i < characterInfos.Count; i++) + { + var character = Character.Create(characterInfos[i], waypoints[i].WorldPosition, true, false); + + if (i < clients.Count) + { + msg.Write((byte)clients[i].ID); + } + else + { + msg.Write((byte)0); + server.Character = character; + Character.Controlled = character; + } + + character.GiveJobItems(waypoints[i]); + + GameMain.GameSession.CrewManager.characters.Add(character); + + server.WriteCharacterData(msg, character.Name, character); + } + + break; + case State.Waiting: + msg.Write(respawnTimer); + break; + } + } + + public void ReadNetworkEvent(NetIncomingMessage inc) + { + state = (State)inc.ReadRangedInteger(0, Enum.GetNames(typeof(State)).Length); + + switch (state) + { + case State.Transporting: + CountdownStarted = false; + ResetShuttlePos(); + + var client = networkMember as GameClient; + + int clientCount = inc.ReadByte(); + for (int i = 0; i < clientCount; i++) + { + byte clientId = inc.ReadByte(); + + client.ReadCharacterData(inc, clientId == client.ID); + } + + CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition - Vector2.UnitY * Level.ShaftHeight, 100.0f)); + break; + case State.Waiting: + CountdownStarted = true; + respawnTimer = inc.ReadSingle(); + break; + case State.Returning: + CountdownStarted = false; + break; + } + } + } +} diff --git a/Subsurface/Source/Program.cs b/Subsurface/Source/Program.cs index d330ef949..a9467f510 100644 --- a/Subsurface/Source/Program.cs +++ b/Subsurface/Source/Program.cs @@ -65,7 +65,7 @@ namespace Barotrauma sb.AppendLine("Game version " + GameMain.Version); sb.AppendLine("Selected content package: " + GameMain.SelectedPackage.Name); sb.AppendLine("Level seed: "+ ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed)); - sb.AppendLine("Loaded submarine: " + ((Submarine.Loaded == null) ? "none" : Submarine.Loaded.Name +" ("+Submarine.Loaded.MD5Hash+")")); + sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "none" : Submarine.MainSub.Name +" ("+Submarine.MainSub.MD5Hash+")")); sb.AppendLine("Selected screen: " + (Screen.Selected == null ? "None" : Screen.Selected.ToString())); if (GameMain.Server != null) diff --git a/Subsurface/Source/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs index eccca1c49..3d84d432f 100644 --- a/Subsurface/Source/Screens/EditMapScreen.cs +++ b/Subsurface/Source/Screens/EditMapScreen.cs @@ -46,7 +46,7 @@ namespace Barotrauma public string GetSubName() { - return ((Submarine.Loaded == null) ? "" : Submarine.Loaded.Name); + return (Submarine.MainSub == null) ? "" : Submarine.MainSub.Name; } private string GetItemCount() @@ -94,13 +94,23 @@ namespace Barotrauma button = new GUIButton(new Rectangle(310,0,70,20), "Save", GUI.Style, topPanel); button.OnClicked = SaveSub; - new GUITextBlock(new Rectangle(400, 0, 100, 20), "Description: ", GUI.Style, topPanel); + new GUITextBlock(new Rectangle(390, 0, 100, 20), "Description: ", GUI.Style, topPanel); - descriptionBox = new GUITextBox(new Rectangle(500, 0, 200, 20), null, null, Alignment.TopLeft, + descriptionBox = new GUITextBox(new Rectangle(490, 0, 200, 20), null, null, Alignment.TopLeft, Alignment.TopLeft, GUI.Style, topPanel); descriptionBox.Wrap = true; descriptionBox.OnSelected += ExpandDescriptionBox; descriptionBox.OnTextChanged = ChangeSubDescription; + + + //new GUITextBlock(new Rectangle(390, 0, 100, 20), "Link ", GUI.Style, topPanel); + + var linkedSubBox = new GUIDropDown(new Rectangle(750,0,200,20), "Add submarine", GUI.Style, topPanel); + foreach (Submarine sub in Submarine.SavedSubmarines) + { + linkedSubBox.AddItem(sub.Name, sub); + } + linkedSubBox.OnSelected += SelectLinkedSub; leftPanel = new GUIFrame(new Rectangle(0, 30, 150, GameMain.GraphicsHeight-30), GUI.Style); leftPanel.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f); @@ -231,17 +241,19 @@ namespace Barotrauma GUIComponent.MouseOn = null; characterMode = false; - if (Submarine.Loaded != null) + if (Submarine.MainSub != null) { - cam.Position = Submarine.Loaded.Position + Submarine.HiddenSubPosition; - nameBox.Text = Submarine.Loaded.Name; - descriptionBox.Text = ToolBox.LimitString(Submarine.Loaded.Description,15); + cam.Position = Submarine.MainSub.Position + Submarine.MainSub.HiddenSubPosition; + nameBox.Text = Submarine.MainSub.Name; + descriptionBox.Text = ToolBox.LimitString(Submarine.MainSub.Description, 15); } else { - cam.Position = Submarine.HiddenSubPosition; + cam.Position = Submarine.HiddenSubStartPosition; nameBox.Text = ""; descriptionBox.Text = ""; + + Submarine.MainSub = new Submarine(Path.Combine(Submarine.SavePath, "Unnamed.sub"), "", false); } nameBox.Deselect(); @@ -303,9 +315,9 @@ namespace Barotrauma string savePath = nameBox.Text + ".sub"; - if (Submarine.Loaded != null) + if (Submarine.MainSub != null) { - savePath = Path.Combine(Path.GetDirectoryName(Submarine.Loaded.FilePath), savePath); + savePath = Path.Combine(Path.GetDirectoryName(Submarine.MainSub.FilePath), savePath); } else { @@ -313,9 +325,9 @@ namespace Barotrauma } Submarine.SaveCurrent(savePath); - Submarine.Loaded.CheckForErrors(); + Submarine.MainSub.CheckForErrors(); - GUI.AddMessage("Submarine saved to " + Submarine.Loaded.FilePath, Color.Green, 3.0f); + GUI.AddMessage("Submarine saved to " + Submarine.MainSub.FilePath, Color.Green, 3.0f); return false; } @@ -399,7 +411,8 @@ namespace Barotrauma if (selectedSub == null) return false; - selectedSub.Load(); + Submarine.MainSub = selectedSub; + selectedSub.Load(true); nameBox.Text = selectedSub.Name; descriptionBox.Text = ToolBox.LimitString(selectedSub.Description,15); @@ -521,6 +534,18 @@ namespace Barotrauma return frame; } + private bool SelectLinkedSub(GUIComponent selected) + { + var submarine = selected.UserData as Submarine; + if (submarine == null) return false; + + var prefab = new LinkedSubmarinePrefab(submarine); + + MapEntityPrefab.SelectPrefab(prefab); + + return true; + } + private bool SelectWire(GUIComponent component, object userData) { if (dummyCharacter == null) return false; @@ -560,7 +585,7 @@ namespace Barotrauma return false; } - if (Submarine.Loaded != null) Submarine.Loaded.Name = text; + if (Submarine.MainSub != null) Submarine.MainSub.Name = text; textBox.Deselect(); textBox.Text = text; @@ -572,9 +597,9 @@ namespace Barotrauma private bool ChangeSubDescription(GUITextBox textBox, string text) { - if (Submarine.Loaded != null) + if (Submarine.MainSub != null) { - Submarine.Loaded.Description = text; + Submarine.MainSub.Description = text; } else { @@ -593,9 +618,9 @@ namespace Barotrauma private void ExpandDescriptionBox(GUITextBox textBox, Keys key) { - if (Submarine.Loaded != null) + if (Submarine.MainSub != null) { - textBox.Text = Submarine.Loaded.Description; + textBox.Text = Submarine.MainSub.Description; } else if (textBox.UserData is string) { @@ -617,7 +642,9 @@ namespace Barotrauma private bool GenerateWaypoints(GUIButton button, object obj) { - WayPoint.GenerateSubWaypoints(); + if (Submarine.MainSub == null) return false; + + WayPoint.GenerateSubWaypoints(Submarine.MainSub); return true; } @@ -684,6 +711,9 @@ namespace Barotrauma dummyCharacter.ControlLocalPlayer((float)deltaTime, cam, false); dummyCharacter.Control((float)deltaTime, cam); + + dummyCharacter.Submarine = Submarine.MainSub; + cam.TargetPos = Vector2.Zero; } @@ -737,7 +767,7 @@ namespace Barotrauma if (GameMain.DebugDraw) { GUI.DrawLine(spriteBatch, new Vector2(0.0f, -cam.WorldView.Y), new Vector2(0.0f, -(cam.WorldView.Y - cam.WorldView.Height)), Color.White*0.5f, 1.0f, (int)(2.0f/cam.Zoom)); - GUI.DrawLine(spriteBatch, new Vector2(cam.WorldView.X, -Submarine.HiddenSubPosition.Y), new Vector2(cam.WorldView.Right, -Submarine.HiddenSubPosition.Y), Color.White * 0.5f, 1.0f, (int)(2.0f / cam.Zoom)); + GUI.DrawLine(spriteBatch, new Vector2(cam.WorldView.X, -Submarine.MainSub.HiddenSubPosition.Y), new Vector2(cam.WorldView.Right, -Submarine.MainSub.HiddenSubPosition.Y), Color.White * 0.5f, 1.0f, (int)(2.0f / cam.Zoom)); } Submarine.Draw(spriteBatch, true); diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index a00726b7c..0b991f2a8 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -56,9 +56,9 @@ namespace Barotrauma { cam.Position = Character.Controlled.WorldPosition; } - else if (Submarine.Loaded != null) + else if (Submarine.MainSub != null) { - cam.Position = Submarine.Loaded.WorldPosition; + cam.Position = Submarine.MainSub.WorldPosition; } foreach (MapEntity entity in MapEntity.mapEntityList) @@ -119,9 +119,11 @@ namespace Barotrauma //Lights.LightManager.ViewPos = Character.Controlled.WorldPosition; } cam.MoveCamera((float)Physics.step); - - - if (Submarine.Loaded != null) Submarine.Loaded.SetPrevTransform(Submarine.Loaded.Position); + + foreach (Submarine sub in Submarine.Loaded) + { + sub.SetPrevTransform(sub.Position); + } foreach (PhysicsBody pb in PhysicsBody.list) { @@ -134,11 +136,11 @@ namespace Barotrauma Ragdoll.UpdateAll(cam, (float)Physics.step); - if (GameMain.GameSession != null && GameMain.GameSession.Level != null && GameMain.GameSession.Submarine!=null) + foreach (Submarine sub in Submarine.Loaded) { - GameMain.GameSession.Submarine.Update((float)Physics.step); + sub.Update((float)Physics.step); } - + GameMain.World.Step((float)Physics.step); //Level.AfterWorldStep(); @@ -153,8 +155,8 @@ namespace Barotrauma public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) { - cam.UpdateTransform(); - + cam.UpdateTransform(true, !GameMain.DebugDraw); + DrawMap(graphics, spriteBatch); spriteBatch.Begin(); @@ -175,7 +177,7 @@ namespace Barotrauma if (GameMain.GameSession != null) GameMain.GameSession.Draw(spriteBatch); - if (Character.Controlled == null && Submarine.Loaded != null) DrawSubmarineIndicator(spriteBatch, Submarine.Loaded); + if (Character.Controlled == null && Submarine.MainSub != null) DrawSubmarineIndicator(spriteBatch, Submarine.MainSub); GUI.Draw((float)deltaTime, spriteBatch, cam); @@ -187,7 +189,10 @@ namespace Barotrauma public void DrawMap(GraphicsDevice graphics, SpriteBatch spriteBatch) { - if (Submarine.Loaded != null) Submarine.Loaded.UpdateTransform(); + foreach (Submarine sub in Submarine.Loaded) + { + sub.UpdateTransform(); + } GameMain.LightManager.ObstructVision = Character.Controlled != null && Character.Controlled.ObstructVision; diff --git a/Subsurface/Source/Sounds/SoundPlayer.cs b/Subsurface/Source/Sounds/SoundPlayer.cs index 6663693a2..5266dbf48 100644 --- a/Subsurface/Source/Sounds/SoundPlayer.cs +++ b/Subsurface/Source/Sounds/SoundPlayer.cs @@ -183,7 +183,8 @@ namespace Barotrauma startDrone = null; } - if (Submarine.Loaded==null) + //stop submarine ambient sounds if no sub is loaded + if (Submarine.MainSub == null) { for (int i = 0; i < waterAmbienceIndexes.Length; i++) { @@ -212,17 +213,31 @@ namespace Barotrauma } //how fast the sub is moving, scaled to 0.0 -> 1.0 - float movementFactor = 0.0f; - if (Submarine.Loaded != null) - { - movementFactor = (Submarine.Loaded.Velocity == Vector2.Zero) ? 0.0f : Submarine.Loaded.Velocity.Length() / 5.0f; + float movementSoundVolume = 0.0f; + foreach (Submarine sub in Submarine.Loaded) + { + float movementFactor = (sub.Velocity == Vector2.Zero) ? 0.0f : sub.Velocity.Length() / 5.0f; movementFactor = MathHelper.Clamp(movementFactor, 0.0f, 1.0f); + + if (Character.Controlled==null || Character.Controlled.Submarine != sub) + { + float dist = Vector2.Distance(GameMain.GameScreen.Cam.WorldViewCenter, sub.WorldPosition); + movementFactor = movementFactor / Math.Max(dist / 1000.0f, 1.0f); + } + + movementSoundVolume = Math.Max(movementSoundVolume, movementFactor); } + //if (Submarine.MainSub != null) + //{ + // movementFactor = (Submarine.MainSub.Velocity == Vector2.Zero) ? 0.0f : Submarine.MainSub.Velocity.Length() / 5.0f; + // movementFactor = MathHelper.Clamp(movementFactor, 0.0f, 1.0f); + //} + SoundManager.LowPassHFGain = lowpassHFGain; - waterAmbienceIndexes[0] = waterAmbiences[0].Loop(waterAmbienceIndexes[0], ambienceVolume * (1.0f-movementFactor)); - waterAmbienceIndexes[1] = waterAmbiences[1].Loop(waterAmbienceIndexes[1], ambienceVolume * movementFactor); + waterAmbienceIndexes[0] = waterAmbiences[0].Loop(waterAmbienceIndexes[0], ambienceVolume * (1.0f - movementSoundVolume)); + waterAmbienceIndexes[1] = waterAmbiences[1].Loop(waterAmbienceIndexes[1], ambienceVolume * movementSoundVolume); } @@ -303,7 +318,7 @@ namespace Barotrauma { return musicClips.Where(x => x != null && x.type == "ruins").ToList(); } - else if (Submarine.Loaded != null && Submarine.Loaded.AtDamageDepth) + else if (Submarine.MainSub != null && Submarine.MainSub.AtDamageDepth) { return musicClips.Where(x => x != null && x.type == "deep").ToList(); } diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs index 37fc9339f..695be7904 100644 --- a/Subsurface/Source/Utils/MathUtils.cs +++ b/Subsurface/Source/Utils/MathUtils.cs @@ -241,20 +241,22 @@ namespace Barotrauma public static bool CircleIntersectsRectangle(Vector2 circlePos, float radius, Rectangle rect) { - Vector2 circleDistance = new Vector2(Math.Abs(circlePos.X - rect.Center.X), Math.Abs(circlePos.Y -rect.Center.Y)); + float xDist = Math.Abs(circlePos.X - rect.Center.X); + int halfWidth = rect.Width / 2; - if (circleDistance.X > (rect.Width / 2 + radius)) { return false; } - if (circleDistance.Y > (rect.Height / 2 + radius)) { return false; } + if (xDist > (halfWidth + radius)) { return false; } + if (xDist <= (halfWidth)) { return true; } - if (circleDistance.X <= (rect.Width / 2)) { return true; } - if (circleDistance.Y <= (rect.Height / 2)) { return true; } + float yDist = Math.Abs(circlePos.Y - rect.Center.Y); + int halfHeight = rect.Height / 2; - float distSqX = circleDistance.X - rect.Width / 2; - float distSqY = circleDistance.Y - rect.Height / 2; + if (yDist > (halfHeight + radius)) { return false; } + if (yDist <= (halfHeight)) { return true; } - float cornerDistanceSq = distSqX * distSqX + distSqY * distSqY; + float distSqX = xDist - halfWidth; + float distSqY = yDist - halfHeight; - return (cornerDistanceSq <= (radius * radius)); + return (distSqX * distSqX + distSqY * distSqY <= (radius * radius)); } /// @@ -288,6 +290,41 @@ namespace Barotrauma return triangles; } + public static List GiftWrap(List points) + { + Vector2 leftMost = points[0]; + foreach (Vector2 point in points) + { + if (point.X < leftMost.X) leftMost = point; + } + + List wrappedPoints = new List(); + + Vector2 currPoint = leftMost; + Vector2 endPoint; + do + { + wrappedPoints.Add(currPoint); + endPoint = points[0]; + + for (int i = 1; i < points.Count; i++) + { + if (points[i] == currPoint) continue; + if (currPoint == endPoint || + MathUtils.VectorOrientation(currPoint, endPoint, points[i]) == -1) + { + endPoint = points[i]; + } + } + + currPoint = endPoint; + + } + while (endPoint != leftMost); + + return wrappedPoints; + } + public static List GenerateJaggedLine(Vector2 start, Vector2 end, int generations, float offsetAmount) { List segments = new List(); diff --git a/Subsurface/Source/Utils/SaveUtil.cs b/Subsurface/Source/Utils/SaveUtil.cs index cd6903cd3..154857dae 100644 --- a/Subsurface/Source/Utils/SaveUtil.cs +++ b/Subsurface/Source/Utils/SaveUtil.cs @@ -23,16 +23,17 @@ namespace Barotrauma string tempPath = Path.Combine(SaveFolder, "temp"); - if (!Directory.Exists(tempPath)) + if (Directory.Exists(tempPath)) { - Directory.CreateDirectory(tempPath); + Directory.Delete(tempPath, true); } + Directory.CreateDirectory(tempPath); - try + try { - if (Submarine.Loaded != null) + if (Submarine.MainSub != null) { - Submarine.Loaded.SaveAs(Path.Combine(tempPath, Submarine.Loaded.Name+".sub")); + Submarine.MainSub.SaveAs(Path.Combine(tempPath, Submarine.MainSub.Name+".sub")); } } catch (Exception e) diff --git a/Subsurface/Submarines/Shuttle Mark I.sub b/Subsurface/Submarines/Shuttle Mark I.sub new file mode 100644 index 000000000..1de548faa Binary files /dev/null and b/Subsurface/Submarines/Shuttle Mark I.sub differ diff --git a/Subsurface/Submarines/Vellamo.sub b/Subsurface/Submarines/Vellamo.sub index 3245978b5..f515d63eb 100644 Binary files a/Subsurface/Submarines/Vellamo.sub and b/Subsurface/Submarines/Vellamo.sub differ diff --git a/Subsurface_Solution.sln b/Subsurface_Solution.sln index acdb73956..19e687774 100644 --- a/Subsurface_Solution.sln +++ b/Subsurface_Solution.sln @@ -11,8 +11,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lidgren.Network", "Lidgren. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher", "Launcher2\Launcher.csproj", "{251AAFE1-F24B-4837-9128-9D04FCBFD528}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrashReporter", "CrashReporter\CrashReporter.csproj", "{6BE950CD-9A34-49C9-939A-786AC89C287E}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D32A29D8-AC7B-4189-B734-8ED9EB4120D0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hyper.ComponentModel", "Hyper.ComponentModel\Hyper.ComponentModel.csproj", "{3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}" @@ -228,51 +226,6 @@ Global {251AAFE1-F24B-4837-9128-9D04FCBFD528}.Windows8|Mixed Platforms.Build.0 = Release|x86 {251AAFE1-F24B-4837-9128-9D04FCBFD528}.Windows8|x86.ActiveCfg = Release|x86 {251AAFE1-F24B-4837-9128-9D04FCBFD528}.Windows8|x86.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Android|Any CPU.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Android|Mixed Platforms.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Android|Mixed Platforms.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Android|x86.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Android|x86.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Debug|Any CPU.ActiveCfg = Debug|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Debug|x86.ActiveCfg = Debug|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Debug|x86.Build.0 = Debug|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.iOS|Any CPU.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.iOS|Mixed Platforms.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.iOS|Mixed Platforms.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.iOS|x86.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.iOS|x86.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Linux|Any CPU.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Linux|Mixed Platforms.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Linux|Mixed Platforms.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Linux|x86.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Linux|x86.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.OSX|Any CPU.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.OSX|Mixed Platforms.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.OSX|Mixed Platforms.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.OSX|x86.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.OSX|x86.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.PSM|Any CPU.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.PSM|Mixed Platforms.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.PSM|Mixed Platforms.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.PSM|x86.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.PSM|x86.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Release|Any CPU.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Release|Mixed Platforms.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Release|x86.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Release|x86.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows|Any CPU.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows|Mixed Platforms.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows|Mixed Platforms.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows|x86.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows|x86.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows8|Any CPU.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows8|Mixed Platforms.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows8|Mixed Platforms.Build.0 = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows8|x86.ActiveCfg = Release|x86 - {6BE950CD-9A34-49C9-939A-786AC89C287E}.Windows8|x86.Build.0 = Release|x86 {3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Android|Any CPU.ActiveCfg = Release|Any CPU {3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Android|Any CPU.Build.0 = Release|Any CPU {3B8F9EDB-6E5E-450C-ABC2-EC49075D0B50}.Android|Mixed Platforms.ActiveCfg = Release|Any CPU