diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj
index 23966ab7d..75e2e93c9 100644
--- a/Subsurface/Barotrauma.csproj
+++ b/Subsurface/Barotrauma.csproj
@@ -118,6 +118,7 @@
+
@@ -143,6 +144,7 @@
+
@@ -492,6 +494,9 @@
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..86d928cda
Binary files /dev/null and b/Subsurface/Content/Items/Door/dockingport.png differ
diff --git a/Subsurface/Content/Items/Door/doors.xml b/Subsurface/Content/Items/Door/doors.xml
index e628549ff..7834d3d90 100644
--- a/Subsurface/Content/Items/Door/doors.xml
+++ b/Subsurface/Content/Items/Door/doors.xml
@@ -82,4 +82,29 @@
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs b/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs
index d8107f9d5..872c6b697 100644
--- a/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs
+++ b/Subsurface/Source/Characters/AI/IndoorsSteeringManager.cs
@@ -103,7 +103,7 @@ namespace Barotrauma
private Vector2 DiffToCurrentNode()
{
- if (currentPath == null) return Vector2.Zero;
+ if (currentPath == null || currentPath.Finished) return Vector2.Zero;
if (currentPath.Finished)
{
diff --git a/Subsurface/Source/Characters/Animation/Ragdoll.cs b/Subsurface/Source/Characters/Animation/Ragdoll.cs
index b84831684..e25b591b2 100644
--- a/Subsurface/Source/Characters/Animation/Ragdoll.cs
+++ b/Subsurface/Source/Characters/Animation/Ragdoll.cs
@@ -616,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;
}
}
@@ -639,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/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/Items/Components/DockingPort.cs b/Subsurface/Source/Items/Components/DockingPort.cs
new file mode 100644
index 000000000..69347b7bc
--- /dev/null
+++ b/Subsurface/Source/Items/Components/DockingPort.cs
@@ -0,0 +1,367 @@
+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
+ {
+ private static List list = new List();
+
+ private Sprite overlaySprite;
+
+ private Vector2 distanceTolerance;
+
+ private DockingPort dockingTarget;
+
+ private float dockingState;
+
+ private Joint joint;
+
+ private int dockingDir;
+
+ private Hull[] hulls;
+
+ private Body[] bodies;
+
+ private Gap gap;
+
+ [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 override bool IsActive
+ {
+ get
+ {
+ return base.IsActive;
+ }
+ set
+ {
+ if (!IsActive && value)
+ {
+ if (dockingTarget == null) AttemptDock();
+ if (dockingTarget == null) return;
+
+ base.IsActive = value;
+ }
+ else if (IsActive && !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;
+ }
+ }
+
+ list.Add(this);
+ }
+
+ private void AttemptDock()
+ {
+ 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;
+
+ Dock(port);
+ return;
+
+ }
+ }
+
+ private void Dock(DockingPort target)
+ {
+ if (dockingTarget!=null)
+ {
+ Undock();
+ }
+
+ dockingTarget = target;
+ dockingTarget.dockingTarget = this;
+ dockingTarget.IsActive = true;
+
+ dockingDir = Math.Sign(dockingTarget.item.WorldPosition.X - item.WorldPosition.X);
+ 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)));
+
+ //bodies[i + j * 2] = BodyFactory.CreateRectangle(GameMain.World, ConvertUnits.ToSimUnits(hullRects[i].Width), 0.1f, 5.0f);
+ //bodies[i + j * 2].SetTransform(ConvertUnits.ToSimUnits(new Vector2(hullRects[i].Center.X, hullRects[i].Y - (hullRects[i].Height+5) * j)), 0.0f);
+ }
+ }
+
+ gap = new Gap(new Rectangle(hullRects[0].Right-2, hullRects[0].Y, 4, hullRects[0].Height), true, item.Submarine);
+ gap.linkedTo.Clear();
+ gap.linkedTo.Add(hulls[0]);
+ gap.linkedTo.Add(hulls[1]);
+
+ //var hullRect1 = new Rectangle(hullRects.Min(h => h.Center.X), hullRect.Y, ((int)DockedDistance / 2), hullRects[0].Height);
+ //var hullRect2 = new Rectangle(hullRects.Max(h => h.Center.X), hullRect.Y, ((int)DockedDistance / 2), hullRects[0].Height);
+
+ //var sub1 = hullRect.Center.X < targetRect.Center.X ? item.Submarine : dockingTarget.item.Submarine;
+ //var sub2 = hullRect.Center.X > targetRect.Center.X ? item.Submarine : dockingTarget.item.Submarine;
+
+ // hullRect1.Location -= (sub1.WorldPosition - sub1.HiddenSubPosition).ToPoint();
+ //hulls[0] = new Hull(MapEntityPrefab.list.Find(m => m.Name == "Hull"), hullRect1, sub1);
+ //hulls[0].AddToGrid(sub1);
+
+ //hullRect2.Location -= (sub2.WorldPosition - sub2.HiddenSubPosition).ToPoint();
+ //hulls[1] = new Hull(MapEntityPrefab.list.Find(m => m.Name == "Hull"), hullRect2, sub2);
+ //hulls[1].AddToGrid(sub2);
+
+
+ }
+ else
+ {
+ //hullRect = new Rectangle(hullRect.X,
+ // Math.Max(hullRect.Y - hullRect.Height / 2, targetRect.Y - targetRect.Height / 2), hullRect.Width, (int)DockedDistance);
+ }
+
+ foreach (Body body in bodies)
+ {
+ body.BodyType = BodyType.Static;
+ body.Friction = 0.5f;
+
+ body.CollisionCategories = Physics.CollisionWall;
+ }
+
+
+ }
+
+ private void Undock()
+ {
+ if (dockingTarget == null) return;
+
+ dockingTarget.dockingTarget = null;
+ dockingTarget.IsActive = false;
+
+ dockingTarget = null;
+
+ GameMain.World.RemoveJoint(joint);
+ joint = null;
+
+ hulls[0].Remove();
+ hulls[1].Remove();
+
+ gap.Remove();
+ gap = null;
+
+ foreach (Body body in bodies)
+ {
+ GameMain.World.RemoveBody(body);
+ }
+ bodies = null;
+
+
+
+ //foreach (Gap g in hulls[0].ConnectedGaps)
+ //{
+ // g.Remove();
+ //}
+
+ //foreach (Gap g in hulls[1].ConnectedGaps)
+ //{
+ // g.Remove();
+ //}
+
+
+ hulls = 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) base.IsActive = false;
+ }
+ else
+ {
+ if (joint is DistanceJoint && Vector2.Distance(joint.WorldAnchorA, joint.WorldAnchorB) < 0.05f)
+ {
+ GameMain.World.RemoveJoint(joint);
+
+ CreateJoint(true);
+ CreateHull();
+ }
+
+ 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;
+ drawPos.Y -= rect.Height / 2;
+
+ if (IsHorizontal)
+ {
+ 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
+ {
+ 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);
+ }
+ }
+}
diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs
index 2243aef2e..836cbec2f 100644
--- a/Subsurface/Source/Items/Item.cs
+++ b/Subsurface/Source/Items/Item.cs
@@ -1432,7 +1432,7 @@ namespace Barotrauma
return true;
}
- public override XElement Save(XDocument doc)
+ public override XElement Save(XElement parentElement)
{
XElement element = new XElement("Item");
@@ -1475,7 +1475,7 @@ namespace Barotrauma
ic.Save(element);
}
- doc.Root.Add(element);
+ parentElement.Add(element);
return element;
}
diff --git a/Subsurface/Source/Map/Gap.cs b/Subsurface/Source/Map/Gap.cs
index 31452a2ca..621b15049 100644
--- a/Subsurface/Source/Map/Gap.cs
+++ b/Subsurface/Source/Map/Gap.cs
@@ -639,7 +639,7 @@ namespace Barotrauma
FindHulls();
}
- public override XElement Save(XDocument doc)
+ public override XElement Save(XElement parentElement)
{
XElement element = new XElement("Gap");
@@ -663,7 +663,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 d124b5305..f0f2c8793 100644
--- a/Subsurface/Source/Map/Hull.cs
+++ b/Subsurface/Source/Map/Hull.cs
@@ -260,6 +260,21 @@ namespace Barotrauma
}
}
+ 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;
+ }
+ }
+
public override bool IsMouseOn(Vector2 position)
{
if (!GameMain.DebugDraw && !ShowHulls) return false;
@@ -295,6 +310,7 @@ namespace Barotrauma
public override void Remove()
{
base.Remove();
+ hullList.Remove(this);
if (Submarine == null || !Submarine.Loading)
{
@@ -324,7 +340,6 @@ namespace Barotrauma
}
- hullList.Remove(this);
}
public void AddFireSource(FireSource fireSource, bool createNetworkEvent = true)
@@ -712,7 +727,7 @@ namespace Barotrauma
// return gaps;
//}
- public override XElement Save(XDocument doc)
+ public override XElement Save(XElement parentElement)
{
XElement element = new XElement("Hull");
@@ -725,8 +740,8 @@ namespace Barotrauma
rect.Width + "," + rect.Height),
new XAttribute("water", volume)
);
-
- doc.Root.Add(element);
+
+ parentElement.Add(element);
return element;
}
diff --git a/Subsurface/Source/Map/MapEntity.cs b/Subsurface/Source/Map/MapEntity.cs
index ed9051a21..958655ce0 100644
--- a/Subsurface/Source/Map/MapEntity.cs
+++ b/Subsurface/Source/Map/MapEntity.cs
@@ -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;
@@ -625,15 +625,29 @@ namespace Barotrauma
if (linked != null) e.linkedTo.Add(linked);
}
}
+
+ List linkedSubs = new List();
for (int i = 0; i false
+
+ Submarine sub = new Submarine(ToolBox.GetAttributeString(element, "name", ""));
+ sub.Load(unloadPrevious, element);
+
+ return sub;
}
public static Submarine Load(string fileName, bool unloadPrevious)
@@ -851,7 +880,7 @@ namespace Barotrauma
string path = string.IsNullOrWhiteSpace(folder) ? fileName : System.IO.Path.Combine(SavePath, fileName);
Submarine sub = new Submarine(path);
- sub.Load(false);
+ sub.Load(unloadPrevious);
//Entity.dictionary.Add(int.MaxValue, sub);
diff --git a/Subsurface/Source/Map/SubmarineBody.cs b/Subsurface/Source/Map/SubmarineBody.cs
index 1cc21f166..2802e4fd0 100644
--- a/Subsurface/Source/Map/SubmarineBody.cs
+++ b/Subsurface/Source/Map/SubmarineBody.cs
@@ -125,30 +125,16 @@ namespace Barotrauma
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);
+ }
}
@@ -183,50 +169,17 @@ namespace Barotrauma
List points = new List();
- Vector2 leftMost = Vector2.Zero;
-
foreach (Structure wall in Structure.WallList)
{
if (wall.Submarine != submarine) continue;
- 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 (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;
}
diff --git a/Subsurface/Source/Map/SubmarineLink.cs b/Subsurface/Source/Map/SubmarineLink.cs
new file mode 100644
index 000000000..68f671656
--- /dev/null
+++ b/Subsurface/Source/Map/SubmarineLink.cs
@@ -0,0 +1,171 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+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 XElement saveElement;
+
+ public LinkedSubmarine(Submarine submarine)
+ : base(null, submarine)
+ {
+ 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);
+
+ }
+
+ 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)
+ {
+ var doc = Submarine.OpenFile(filePath);
+
+ doc.Root.Name = "LinkedSubmarine";
+
+ doc.Root.Add(
+ new XAttribute("filepath", filePath),
+ new XAttribute("pos", ToolBox.Vector2ToString(Position - Submarine.HiddenSubPosition)));
+
+ parentElement.Add(doc.Root);
+
+ return doc.Root;
+ }
+
+ public static void Load(XElement element, Submarine submarine)
+ {
+ Vector2 pos = ToolBox.GetAttributeVector2(element, "pos", Vector2.Zero);
+
+ if (Screen.Selected == GameMain.EditMapScreen)
+ {
+ string filePath = ToolBox.GetAttributeString(element, "filepath", "");
+
+ Create(submarine, filePath, pos);
+
+ return;
+ }
+
+ var ls = new LinkedSubmarine(submarine);
+ ls.saveElement = element;
+
+ ls.rect.Location = pos.ToPoint();
+ }
+
+ public override void OnMapLoaded()
+ {
+ if (saveElement == null) return;
+ var sub = Submarine.Load(saveElement, false);
+ sub.SetPosition(WorldPosition - Submarine.WorldPosition);
+ sub.Submarine = Submarine;
+ }
+ }
+}
diff --git a/Subsurface/Source/Map/WayPoint.cs b/Subsurface/Source/Map/WayPoint.cs
index a5f9a49c4..1a0f77b70 100644
--- a/Subsurface/Source/Map/WayPoint.cs
+++ b/Subsurface/Source/Map/WayPoint.cs
@@ -718,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");
@@ -739,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/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs
index fa3599308..3d84d432f 100644
--- a/Subsurface/Source/Screens/EditMapScreen.cs
+++ b/Subsurface/Source/Screens/EditMapScreen.cs
@@ -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);
@@ -524,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;
diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs
index 37fc9339f..cb0b98697 100644
--- a/Subsurface/Source/Utils/MathUtils.cs
+++ b/Subsurface/Source/Utils/MathUtils.cs
@@ -288,6 +288,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();