3 using FarseerPhysics.Dynamics;
4 using Microsoft.Xna.Framework;
6 using System.Collections.Generic;
25 private string[] idCardTags;
26 private ushort ladderId;
30 private HashSet<Identifier> tags;
40 private HashSet<Gap> openGaps;
48 openGaps ??=
new HashSet<Gap>();
74 public RuinGeneration.Ruin
Ruin;
92 public override string Name
103 get {
return idCardTags; }
107 for (
int i = 0; i < idCardTags.Length; i++)
109 idCardTags[i] = idCardTags[i].Trim().ToLowerInvariant();
114 public IEnumerable<Identifier>
Tags => tags;
119 : this(new Rectangle((int)position.X - 3, (int)position.Y + 3, 6, 6), submarine)
138 if (SubEditorScreen.IsSubEditor())
140 SubEditorScreen.StoreCommand(
new AddOrDeleteCommand(
new List<MapEntity> {
this },
false));
162 idCardTags = Array.Empty<
string>();
163 tags =
new HashSet<Identifier>();
166 if (iconSprites ==
null)
168 iconSprites =
new Dictionary<string, Sprite>()
170 {
"Path",
new Sprite(
"Content/UI/MainIconsAtlas.png",
new Rectangle(0,0,128,128)) },
171 {
"Human",
new Sprite(
"Content/UI/MainIconsAtlas.png",
new Rectangle(128,0,128,128)) },
172 {
"Enemy",
new Sprite(
"Content/UI/MainIconsAtlas.png",
new Rectangle(256,0,128,128)) },
173 {
"Cargo",
new Sprite(
"Content/UI/MainIconsAtlas.png",
new Rectangle(384,0,128,128)) },
174 {
"Corpse",
new Sprite(
"Content/UI/MainIconsAtlas.png",
new Rectangle(512,0,128,128)) },
175 {
"Ladder",
new Sprite(
"Content/UI/MainIconsAtlas.png",
new Rectangle(0,128,128,128)) },
176 {
"Door",
new Sprite(
"Content/UI/MainIconsAtlas.png",
new Rectangle(128,128,128,128)) },
177 {
"Submarine",
new Sprite(
"Content/UI/CommandUIBackground.png",
new Rectangle(0,896,128,128)) },
178 {
"ExitPoint",
new Sprite(
"Content/UI/CommandUIBackground.png",
new Rectangle(0,896,128,128)) }
186 DebugConsole.Log(
"Created waypoint (" +
ID +
")");
196 idCardTags = idCardTags,
209 DebugConsole.ThrowError(
"Couldn't generate waypoints: no hulls found.");
214 foreach (
WayPoint wayPoint
in existingWaypoints)
221 List<Door> openDoors =
new List<Door>();
224 var door = item.GetComponent<
Door>();
225 if (door !=
null && !door.Body.Enabled)
231 bool isRuin = submarine.Info.ShouldBeRuin;
232 float diffFromHullEdge = 50;
233 float minDist = 100.0f;
234 float heightFromFloor = 110.0f;
235 float hullMinHeight = 100;
237 var removals =
new HashSet<WayPoint>();
242 diffFromHullEdge = 75;
243 var hullWaypoints =
new List<WayPoint>();
244 float top = hull.
Rect.Y;
245 float bottom = hull.
Rect.Y - hull.
Rect.Height;
246 if (hull.
Rect.Width < 300 || hull.
Rect.Height < 300)
249 if (hull.
Rect.Width > hull.
Rect.Height)
252 float y = hull.
Rect.Y - hull.
Rect.Height / 2;
253 for (
float x = hull.
Rect.X + diffFromHullEdge; x <= hull.
Rect.Right - diffFromHullEdge; x += minDist)
261 float x = hull.
Rect.X + hull.
Rect.Width / 2;
262 for (
float y = top - diffFromHullEdge; y >= bottom + diffFromHullEdge; y -= minDist)
268 if (hullWaypoints.None())
271 for (
float x = hull.
Rect.X + diffFromHullEdge; x <= hull.
Rect.Right - diffFromHullEdge; x += minDist)
273 for (
float y = top - diffFromHullEdge; y >= bottom + diffFromHullEdge; y -= minDist)
278 if (hullWaypoints.None())
283 foreach (
WayPoint wp
in hullWaypoints)
291 rect.Inflate(10, 10);
301 foreach (var wayPoint
in hullWaypoints)
303 for (
int dir = -1; dir <= 1; dir += 2)
305 WayPoint closest = wayPoint.FindClosest(dir, horizontalSearch:
true,
new Vector2(minDist * 1.9f, minDist));
306 if (closest !=
null && closest.
CurrentHull == wayPoint.CurrentHull)
310 closest = wayPoint.FindClosest(dir, horizontalSearch:
false,
new Vector2(minDist, minDist * 1.9f));
311 if (closest !=
null && closest.
CurrentHull == wayPoint.CurrentHull)
320 if (hull.
Rect.Height < hullMinHeight) {
continue; }
323 for (
int i = 0; i < 5; i++)
325 float horizontalOffset = 0;
329 horizontalOffset = hull.
RectWidth * 0.2f;
332 horizontalOffset = hull.
RectWidth * 0.4f;
335 horizontalOffset = -hull.
RectWidth * 0.2f;
338 horizontalOffset = -hull.
RectWidth * 0.4f;
341 horizontalOffset = ConvertUnits.ToSimUnits(horizontalOffset);
342 Vector2 floorPos =
new Vector2(hull.
SimPosition.X + horizontalOffset, ConvertUnits.ToSimUnits(hull.
Rect.Y - hull.
RectHeight - 50));
344 if (floor !=
null) {
break; }
346 if (floor ==
null) {
continue; }
347 float waypointHeight = hull.
Rect.Height > heightFromFloor * 2 ? heightFromFloor : hull.
Rect.Height / 2;
348 if (hull.
Rect.Width < diffFromHullEdge * 3.0f)
355 for (
float x = hull.
Rect.X + diffFromHullEdge; x <= hull.
Rect.Right - diffFromHullEdge; x += minDist)
359 if (wayPoint.FindStairs() !=
null)
361 removals.Add(wayPoint);
364 if (previousWaypoint !=
null)
366 wayPoint.ConnectTo(previousWaypoint);
368 previousWaypoint = wayPoint;
370 if (previousWaypoint ==
null)
383 float waypointHeight = heightFromFloor;
385 for (
float x = platform.
Rect.X + diffFromHullEdge; x <= platform.
Rect.Right - diffFromHullEdge; x += minDist)
388 if (prevWaypoint !=
null)
393 if (wayPoint !=
null)
395 for (
int dir = -1; dir <= 1; dir += 2)
397 if (wayPoint.FindClosest(dir, horizontalSearch:
true, tolerance:
new Vector2(minDist, heightFromFloor), ignored: prevWaypoint.ToEnumerable()) !=
null)
405 prevWaypoint = wayPoint;
409 float outSideWaypointInterval = 100.0f;
410 if (!isRuin && submarine.Info.Type !=
SubmarineType.OutpostModule)
415 int originalWidth = borders.Width;
416 int originalHeight = borders.Height;
417 borders.X -= Math.Min(500, originalWidth / 4);
418 borders.Y += Math.Min(500, originalHeight / 4);
419 borders.Width += Math.Min(1500, originalWidth / 2);
420 borders.Height += Math.Min(1000, originalHeight / 2);
421 borders.Location -= MathUtils.ToPoint(submarine.HiddenSubPosition);
423 if (borders.Width <= outSideWaypointInterval * 2)
425 borders.Inflate(outSideWaypointInterval * 2 - borders.Width, 0);
428 if (borders.Height <= outSideWaypointInterval * 2)
430 int inflateAmount = (int)(outSideWaypointInterval * 2) - borders.Height;
431 borders.Y += inflateAmount / 2;
432 borders.Height += inflateAmount;
436 for (
int i = 0; i < 2; i++)
438 for (
float x = borders.X + outSideWaypointInterval; x < borders.Right - outSideWaypointInterval; x += outSideWaypointInterval)
441 new Vector2(x, borders.Y - borders.Height * i) + submarine.HiddenSubPosition,
444 outsideWaypoints.Add((wayPoint, i));
446 if (x == borders.X + outSideWaypointInterval)
448 cornerWaypoint[i, 0] = wayPoint;
459 for (
int i = 0; i < 2; i++)
462 for (
float y = borders.Y - borders.Height; y < borders.Y; y += outSideWaypointInterval)
465 new Vector2(borders.X + borders.Width * i, y) + submarine.HiddenSubPosition,
468 outsideWaypoints.Add((wayPoint, i));
470 if (y == borders.Y - borders.Height)
472 wayPoint.
ConnectTo(cornerWaypoint[1, i]);
480 wayPoint.
ConnectTo(cornerWaypoint[0, i]);
483 Vector2 center = ConvertUnits.ToSimUnits(submarine.HiddenSubPosition);
484 float halfHeight = ConvertUnits.ToSimUnits(borders.Height / 2);
486 foreach (var wayPoint
in outsideWaypoints)
490 Vector2 targetPos =
new Vector2(center.X - xDiff * 0.5f, center.Y);
495 targetPos =
new Vector2(center.X - xDiff, center.Y);
500 float distanceFromWall = 1;
501 if (xDiff > 0 && !submarine.Info.HasTag(
SubmarineTag.Shuttle))
504 float yDist = Math.Abs(center.Y - wp.
SimPosition.Y);
505 distanceFromWall = MathHelper.Lerp(1, 3, MathUtils.InverseLerp(halfHeight, 0, yDist));
508 wp.
rect =
new Rectangle(ConvertUnits.ToDisplayUnits(newPos).ToPoint(), wp.
rect.Size);
514 float tooClose = outSideWaypointInterval / 2;
515 foreach (var wayPoint
in outsideWaypoints)
526 foreach (var otherWayPoint
in outsideWaypoints)
528 WayPoint otherWp = otherWayPoint.Item1;
529 if (otherWp == wp) {
continue; }
530 if (removals.Contains(otherWp)) {
continue; }
531 float sqrDist = Vector2.DistanceSquared(wp.Position, otherWp.
Position);
533 if (!removals.Contains(previous) && sqrDist < tooClose * tooClose)
542 outsideWaypoints.
RemoveAll(w => w.Item1 == wp);
544 removals.ForEach(wp => wp.
Remove());
545 for (
int i = 0; i < outsideWaypoints.Count; i++)
547 WayPoint current = outsideWaypoints[i].Item1;
548 if (current.
linkedTo.Count(l => !removals.Contains(l)) > 1) {
continue; }
550 int maxConnections = 2;
551 float tooFar = outSideWaypointInterval * 5;
552 for (
int j = 0; j < maxConnections; j++)
554 if (current.
linkedTo.Count >= maxConnections) {
break; }
555 tooFar /= current.
linkedTo.Count(l => !removals.Contains(l));
556 next = current.FindClosestOutside(outsideWaypoints, tolerance: tooFar, filter: wp => wp.Item1 != next && wp.Item1.
linkedTo.None(e => current.
linkedTo.Contains(e)) && wp.Item1.
linkedTo.Count < 2 && wp.Item2 < i);
564 removals.ForEach(wp => wp.
Remove());
569 if (!(mapEntity is
Structure structure)) {
continue; }
570 if (structure.StairDirection ==
Direction.None) {
continue; }
574 stairPoints[0] =
new WayPoint(
new Vector2(
575 structure.Rect.X + 5,
576 structure.Rect.Y - (structure.StairDirection ==
Direction.Left ? margin : structure.Rect.Height - 100)),
SpawnType.Path, submarine);
578 stairPoints[1] =
new WayPoint(
new Vector2(
579 structure.Rect.Right - 5,
580 structure.Rect.Y - (structure.StairDirection ==
Direction.Left ? structure.Rect.Height - 100 : margin)),
SpawnType.Path, submarine);
582 for (
int i = 0; i < 2; i++)
584 for (
int dir = -1; dir <= 1; dir += 2)
586 WayPoint closest = stairPoints[i].FindClosest(dir, horizontalSearch:
true,
new Vector2(minDist * 1.5f, minDist / 2));
587 if (closest ==
null) {
continue; }
593 stairPoints[0].
ConnectTo(stairPoints[2]);
594 stairPoints[2].
ConnectTo(stairPoints[1]);
595 stairPoints.ForEach(wp => wp.FindStairs());
601 var ladders = item.GetComponent<
Ladder>();
602 if (ladders ==
null) {
continue; }
604 Vector2 bottomPoint =
new Vector2(item.
Rect.Center.X, item.
Rect.Top - item.
Rect.Height + 10);
605 List<(
WayPoint wp,
bool connectHullPoints)> ladderPoints =
new List<(
WayPoint,
bool)>
610 List<Body> ignoredBodies =
new List<Body>();
613 WayPoint lowestPoint = ladderPoints[0].wp;
617 collisionCategory: Physics.CollisionWall | Physics.CollisionPlatform | Physics.CollisionStairs,
618 customPredicate: f => !(f.Body.UserData is
Submarine));
619 float startHeight = ground !=
null ? ConvertUnits.ToDisplayUnits(ground.Position.Y) : bottomPoint.Y;
620 startHeight += heightFromFloor;
622 Vector2 nextPos =
new Vector2(item.
Rect.Center.X, startHeight);
625 if (lowestPoint ==
null || Math.Abs(startPoint.
Position.Y - startHeight) > 40 &&
Hull.
FindHull(nextPos) !=
null)
628 ladderPoints.Add((startPoint,
true));
629 if (lowestPoint !=
null)
633 prevPoint = startPoint;
641 ConvertUnits.ToSimUnits(
new Vector2(startPoint.
Position.X, y)),
642 prevPos, ignoredBodies, Physics.CollisionWall,
false,
643 (Fixture f) => f.Body.UserData is
Item pickedItem && pickedItem.GetComponent<
Door>() !=
null);
645 Door pickedDoor =
null;
646 if (pickedBody !=
null)
648 pickedDoor = (pickedBody?.UserData as
Item).GetComponent<Door>();
654 ConvertUnits.ToSimUnits(
new Vector2(startPoint.
Position.X, y)), prevPos, ignoredBodies,
null,
false,
655 (Fixture f) => f.Body.UserData is
Structure);
658 if (pickedBody !=
null)
660 ignoredBodies.Add(pickedBody);
663 if (pickedDoor !=
null)
666 ladderPoints.Add((newPoint,
true));
670 prevPoint = newPoint;
671 prevPos =
new Vector2(prevPos.X, ConvertUnits.ToSimUnits(pickedDoor.
Item.
Position.Y - pickedDoor.
Item.
Rect.Height));
677 Vector2 pos = pickedBody ==
null ?
new Vector2(startPoint.
Position.X, y) :
680 ladderPoints.Add((newPoint, pickedBody !=
null));
682 prevPoint = newPoint;
683 prevPos = ConvertUnits.ToSimUnits(newPoint.
Position);
684 if (pickedBody !=
null)
687 y = Math.Max(newPoint.
Position.Y, y);
693 if (prevPoint.
rect.Y < item.
Rect.Y - 40)
696 ladderPoints.Add((wayPoint,
true));
701 var ladderWaypoints = ladderPoints.Select(lp => lp.wp);
702 foreach (var ladderPoint
in ladderPoints)
704 var wp = ladderPoint.wp;
705 wp.Ladders = ladders;
706 if (!ladderPoint.connectHullPoints) {
continue; }
707 bool isHatch = wp.ConnectedGap !=
null && !wp.ConnectedGap.IsRoomToRoom;
708 for (
int dir = -1; dir <= 1; dir += 2)
711 wp.FindClosest(dir, horizontalSearch:
true,
new Vector2(500, 1000), wp.ConnectedGap?.ConnectedDoor?.Body.FarseerBody, filter: wp => wp.CurrentHull ==
null, ignored: ladderWaypoints) :
712 wp.FindClosest(dir, horizontalSearch:
true,
new Vector2(150, 100), wp.ConnectedGap?.ConnectedDoor?.Body.FarseerBody, ignored: ladderWaypoints);
713 if (closest ==
null) {
continue; }
722 var ladders = item.GetComponent<
Ladder>();
723 if (ladders ==
null) {
continue; }
724 var wps =
WayPointList.Where(wp => wp.Ladders == ladders).OrderByDescending(wp => wp.Rect.Y);
726 WayPoint above = cap.FindClosest(1, horizontalSearch:
false, tolerance:
new Vector2(25, 50), filter: wp => wp.Ladders !=
null && wp.Ladders != ladders);
729 WayPoint below = bottom.FindClosest(-1, horizontalSearch:
false, tolerance:
new Vector2(25, 50), filter: wp => wp.Ladders !=
null && wp.Ladders != ladders);
740 if (gap.
Rect.Height < 50) {
continue; }
745 if (gap.
Rect.Height < hullMinHeight) {
continue; }
748 Vector2 pos =
new Vector2(gap.
Rect.Center.X, gap.
Rect.Y - gap.
Rect.Height + heightFromFloor);
751 pos.Y = gap.
Rect.Y - gap.
Rect.Height / 2;
755 Vector2 tolerance = gap.
IsRoomToRoom && !isRuin ?
new Vector2(150, 70) :
new Vector2(1000, 1000);
756 for (
int dir = -1; dir <= 1; dir += 2)
770 if (gap.
Rect.Width < 50.0f) {
continue; }
771 Vector2 pos =
new Vector2(gap.
Rect.Center.X, gap.
Rect.Y - gap.
Rect.Height / 2);
773 if (
WayPointList.Any(wp => wp.ConnectedGap == gap)) {
continue; }
777 WayPoint closest = wayPoint.FindClosest(dir, horizontalSearch:
false, isRuin ?
new Vector2(500, 500) :
new Vector2(50, 100));
784 closest = wayPoint.FindClosest(-dir, horizontalSearch:
false, isRuin ?
new Vector2(500, 500) :
new Vector2(50, 100));
791 for (dir = -1; dir <= 1; dir += 2)
793 closest = wayPoint.FindClosest(dir, horizontalSearch:
true,
new Vector2(500, 1000), gap.
ConnectedDoor?.
Body.
FarseerBody, filter: wp => wp.CurrentHull ==
null);
812 DebugConsole.ThrowError($
"Couldn't automatically link the waypoint {wp.ID} outside of the submarine. You should do it manually. The waypoint ID is shown in red color.");
817 foreach (
Door door
in openDoors)
825 private WayPoint FindClosestOutside(IEnumerable<(
WayPoint,
int)> waypointList,
float tolerance, Body ignoredBody =
null, IEnumerable<WayPoint> ignored =
null, Func<(
WayPoint,
int),
bool> filter =
null)
827 float closestDist = 0;
829 foreach (var wayPoint
in waypointList)
834 if (
linkedTo.Contains(wp)) {
continue; }
835 if (ignored !=
null && ignored.Contains(wp)) {
continue; }
836 if (filter !=
null && !filter(wayPoint)) {
continue; }
838 if (sqrDist > tolerance * tolerance) {
continue; }
839 if (closest ==
null || sqrDist < closestDist)
842 if (body !=
null && body != ignoredBody && !(body.UserData is
Submarine))
844 if (body.UserData is Structure || body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall))
849 closestDist = sqrDist;
856 private WayPoint FindClosest(
int dir,
bool horizontalSearch, Vector2 tolerance, Body ignoredBody =
null, IEnumerable<WayPoint> ignored =
null, Func<WayPoint, bool> filter =
null)
858 if (dir != -1 && dir != 1) {
return null; }
860 float closestDist = 0.0f;
865 if (wp.SpawnType !=
SpawnType.Path || wp ==
this) {
continue; }
868 float yDiff = wp.Position.Y -
Position.Y;
869 float xDist = Math.Abs(xDiff);
870 float yDist = Math.Abs(yDiff);
871 if (tolerance.X < xDist) {
continue; }
872 if (tolerance.Y < yDist) {
continue; }
876 if (horizontalSearch)
879 dist = xDist + yDist / 5.0f;
884 dist = yDist + xDist / 5.0f;
886 if (wp.Ladders !=
null) { dist *= 0.5f; }
889 if (Math.Sign(diff) != dir) {
continue; }
891 if (
linkedTo.Contains(wp)) {
continue; }
892 if (ignored !=
null && ignored.Contains(wp)) {
continue; }
893 if (filter !=
null && !filter(wp)) {
continue; }
895 if (closest ==
null || dist < closestDist)
898 if (body !=
null && body != ignoredBody && !(body.UserData is
Submarine))
900 if (body.UserData is Structure)
904 if (body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall) && body.UserData is
Item i && i.GetComponent<
Door>() !=
null)
920 System.Diagnostics.Debug.Assert(
this != wayPoint2);
926 if (!wayPoint2.
linkedTo.Contains(
this))
936 (ignoreSubmarine || wp.Submarine == sub) &&
939 !wp.spawnType.HasFlag(
SpawnType.Disabled) &&
941 (spawnPointTag.IsNullOrEmpty() || wp.Tags.Any(t => t == spawnPointTag)) &&
942 (assignedJob ==
null || (assignedJob !=
null && wp.AssignedJob == assignedJob)),
943 useSyncedRand ? Rand.RandSync.ServerAndClient : Rand.RandSync.Unsynced);
948 List<WayPoint> subWayPoints =
WayPointList.FindAll(wp => wp.Submarine == submarine);
955 subWayPoints.Shuffle(Rand.RandSync.Unsynced);
957 List<WayPoint> unassignedWayPoints = subWayPoints.FindAll(wp => wp.spawnType ==
SpawnType.Human);
961 for (
int i = 0; i < crew.Count; i++ )
964 for (
int n = 0; n < unassignedWayPoints.Count; n++)
966 if (crew[i].
Job.
Prefab != unassignedWayPoints[n].AssignedJob) {
continue; }
967 assignedWayPoints[i] = unassignedWayPoints[n];
968 unassignedWayPoints.RemoveAt(n);
975 for (
int i = 0; i < crew.Count; i++)
977 if (assignedWayPoints[i] !=
null) {
continue; }
980 foreach (
WayPoint wp
in subWayPoints)
984 assignedWayPoints[i] = wp;
987 if (assignedWayPoints[i] !=
null) {
continue; }
991 if (nonJobSpecificPoints.Any())
993 assignedWayPoints[i] = nonJobSpecificPoints[Rand.Int(nonJobSpecificPoints.Count, Rand.RandSync.ServerAndClient)];
996 if (assignedWayPoints[i] !=
null) {
continue; }
999 assignedWayPoints[i] =
GetRandom(
SpawnType.Human,
null, submarine, useSyncedRand:
true);
1002 for (
int i = 0; i < assignedWayPoints.Length; i++)
1004 if (assignedWayPoints[i] ==
null)
1006 DebugConsole.AddWarning(
"Couldn't find a waypoint for " + crew[i].
Name +
"!");
1011 return assignedWayPoints;
1016 List<WayPoint> spawnWaypoints =
WayPointList.FindAll(wp =>
1021 Identifier teamSpawnTag = (
"deathmatch" + teamID).ToIdentifier();
1022 if (spawnWaypoints.Any(wp => wp.Tags.Contains(teamSpawnTag)))
1024 spawnWaypoints = spawnWaypoints.FindAll(wp => wp.Tags.Contains(teamSpawnTag));
1029 spawnWaypoints = spawnWaypoints.FindAll(wp =>
1030 wp.CurrentHull?.OutpostModuleTags !=
null &&
1031 wp.CurrentHull.OutpostModuleTags.Contains(
Barotrauma.Tags.Airlock));
1033 return spawnWaypoints;
1088 Rectangle
rect =
new Rectangle(
1101 if (!
string.IsNullOrWhiteSpace(idCardDescString))
1106 if (!
string.IsNullOrWhiteSpace(idCardTagString))
1116 if (!jobIdentifier.IsEmpty)
1128 int srcId =
int.Parse(element.
GetAttribute(
"linkedto" + i).Value);
1144 public override XElement
Save(XElement parentElement)
1147 XElement element =
new XElement(
"WayPoint");
1149 element.Add(
new XAttribute(
"ID",
ID),
1153 new XAttribute(nameof(
Layer),
Layer ??
string.Empty));
1156 element.Add(
new XAttribute(
"exitpointsize", XMLExtensions.PointToString(
ExitPointSize)));
1159 if (!
string.IsNullOrWhiteSpace(
IdCardDesc)) element.Add(
new XAttribute(
"idcarddesc",
IdCardDesc));
1160 if (idCardTags.Length > 0)
1162 element.Add(
new XAttribute(
"idcardtags",
string.Join(
",", idCardTags)));
1166 element.Add(
new XAttribute(
"tags",
string.Join(
",", tags)));
1173 parentElement.Add(element);
1182 element.Add(
new XAttribute(
"linkedto" + i, e.
ID));
1192 base.ShallowRemove();
string? GetAttributeString(string key, string? def)
Identifier[] GetAttributeIdentifierArray(Identifier[] def, params string[] keys)
Point GetAttributePoint(string key, in Point def)
int GetAttributeInt(string key, int def)
XAttribute? GetAttribute(string name)
Identifier GetAttributeIdentifier(string key, string def)
virtual Vector2 WorldPosition
const ushort NullEntityID
readonly ushort ID
Unique, but non-persistent identifier. Stays the same if the entities are created in the exactly same...
static Entity FindEntityByID(ushort ID)
Find an entity based on the ID
static GameSession GameSession
static readonly Screen SubEditorScreen
static List< Gap > GapList
static Hull FindHull(Vector2 position, Hull guess=null, bool useWorldCoordinates=true, bool inclusive=true)
Returns the hull which contains the point (or null if it isn't inside any)
static Rectangle GetBorders()
static readonly List< Hull > HullList
static Hull FindHullUnoptimized(Vector2 position, Hull guess=null, bool useWorldCoordinates=true, bool inclusive=true)
Returns the hull which contains the point (or null if it isn't inside any). The difference to FindHul...
ushort GetOffsetId(XElement element)
override Vector2? Position
static readonly List< Item > ItemList
static JobPrefab Get(Identifier identifier)
static readonly List< MapEntity > MapEntityList
List< ushort > linkedToID
override Vector2 Position
List< ushort > unresolvedLinkedToID
readonly List< MapEntity > linkedTo
override Vector2 SimPosition
Prefab(ContentFile file, Identifier identifier)
readonly Identifier Identifier
static List< Structure > WallList
static Vector2 LastPickedNormal
static Body CheckVisibility(Vector2 rayStart, Vector2 rayEnd, bool ignoreLevel=false, bool ignoreSubs=false, bool ignoreSensors=true, bool ignoreDisabledWalls=true, bool ignoreBranches=true, Predicate< Fixture > blocksVisibilityPredicate=null)
Check visibility between two points (in sim units).
List< WayPoint > ForcedOutpostModuleWayPoints
Vector2 HiddenSubPosition
static readonly Vector2 GridSize
static Body PickBody(Vector2 rayStart, Vector2 rayEnd, IEnumerable< Body > ignoredBodies=null, Category? collisionCategory=null, bool ignoreSensors=true, Predicate< Fixture > customPredicate=null, bool allowInsideFixture=false)
static Vector2 LastPickedPosition
static bool ShowWayPoints
const float LadderWaypointInterval
static WayPoint Load(ContentXElement element, Submarine submarine, IdRemap idRemap)
WayPoint(MapEntityPrefab prefab, Rectangle rectangle)
static List< WayPoint > WayPointList
IEnumerable< Identifier > Tags
WayPoint(Rectangle newRect, Submarine submarine)
WayPoint(Type type, Rectangle newRect, Submarine submarine, ushort id=Entity.NullEntityID)
Rectangle ExitPointWorldRect
void OnGapStateChanged(bool open, Gap gap)
Only called by a Gap when the state changes. So in practice used like an event callback,...
static WayPoint GetRandom(SpawnType spawnType=SpawnType.Human, JobPrefab assignedJob=null, Submarine sub=null, bool useSyncedRand=false, string spawnPointTag=null, bool ignoreSubmarine=false)
override void OnMapLoaded()
WayPoint(Vector2 position, SpawnType spawnType, Submarine submarine, Gap gap=null)
override void ShallowRemove()
Remove the entity from the entity list without removing links to other entities
Action< WayPoint > OnLinksChanged
override MapEntity Clone()
static List< WayPoint > GetOutpostSpawnPoints(CharacterTeamType teamID)
static bool GenerateSubWaypoints(Submarine submarine)
override XElement Save(XElement parentElement)
static WayPoint[] SelectCrewSpawnPoints(List< CharacterInfo > crew, Submarine submarine)
void ConnectTo(WayPoint wayPoint2)