コード例 #1
0
        public static bool GenerateSubWaypoints(Submarine submarine)
        {
            if (!Hull.hullList.Any())
            {
                DebugConsole.ThrowError("Couldn't generate waypoints: no hulls found.");
                return(false);
            }

            List <WayPoint> existingWaypoints = WayPointList.FindAll(wp => wp.spawnType == SpawnType.Path);

            foreach (WayPoint wayPoint in existingWaypoints)
            {
                wayPoint.Remove();
            }

            //find all open doors and temporarily activate their bodies to prevent visibility checks
            //from ignoring the doors and generating waypoint connections that go straight through the door
            List <Door> openDoors = new List <Door>();

            foreach (Item item in Item.ItemList)
            {
                var door = item.GetComponent <Door>();
                if (door != null && !door.Body.Enabled)
                {
                    openDoors.Add(door);
                    door.Body.Enabled = true;
                }
            }

            float diffFromHullEdge = 50;
            float minDist          = 100.0f;
            float heightFromFloor  = 110.0f;
            float hullMinHeight    = 100;

            foreach (Hull hull in Hull.hullList)
            {
                // Ignore hulls that a human couldn't fit in.
                // Doesn't take multi-hull rooms into account, but it's probably best to leave them to be setup manually.
                if (hull.Rect.Height < hullMinHeight)
                {
                    continue;
                }
                // Do five raycasts to check if there's a floor. Don't create waypoints unless we can find a floor.
                Body floor = null;
                for (int i = 0; i < 5; i++)
                {
                    float horizontalOffset = 0;
                    switch (i)
                    {
                    case 1:
                        horizontalOffset = hull.RectWidth * 0.2f;
                        break;

                    case 2:
                        horizontalOffset = hull.RectWidth * 0.4f;
                        break;

                    case 3:
                        horizontalOffset = -hull.RectWidth * 0.2f;
                        break;

                    case 4:
                        horizontalOffset = -hull.RectWidth * 0.4f;
                        break;
                    }
                    horizontalOffset = ConvertUnits.ToSimUnits(horizontalOffset);
                    Vector2 floorPos = new Vector2(hull.SimPosition.X + horizontalOffset, ConvertUnits.ToSimUnits(hull.Rect.Y - hull.RectHeight - 50));
                    floor = Submarine.PickBody(new Vector2(hull.SimPosition.X + horizontalOffset, hull.SimPosition.Y), floorPos, collisionCategory: Physics.CollisionWall | Physics.CollisionPlatform, customPredicate: f => !(f.Body.UserData is Submarine));
                    if (floor != null)
                    {
                        break;
                    }
                }
                if (floor == null)
                {
                    continue;
                }
                float waypointHeight = hull.Rect.Height > heightFromFloor * 2 ? heightFromFloor : hull.Rect.Height / 2;
                if (hull.Rect.Width < diffFromHullEdge * 3.0f)
                {
                    new WayPoint(new Vector2(hull.Rect.X + hull.Rect.Width / 2.0f, hull.Rect.Y - hull.Rect.Height + waypointHeight), SpawnType.Path, submarine);
                }
                else
                {
                    WayPoint prevWaypoint = null;
                    for (float x = hull.Rect.X + diffFromHullEdge; x <= hull.Rect.Right - diffFromHullEdge; x += minDist)
                    {
                        var wayPoint = new WayPoint(new Vector2(x, hull.Rect.Y - hull.Rect.Height + waypointHeight), SpawnType.Path, submarine);
                        if (prevWaypoint != null)
                        {
                            wayPoint.ConnectTo(prevWaypoint);
                        }
                        prevWaypoint = wayPoint;
                    }
                    if (prevWaypoint == null)
                    {
                        // Ensure that we always create at least one waypoint per hull.
                        new WayPoint(new Vector2(hull.Rect.X + hull.Rect.Width / 2.0f, hull.Rect.Y - hull.Rect.Height + waypointHeight), SpawnType.Path, submarine);
                    }
                }
            }

            // Platforms
            foreach (Structure platform in Structure.WallList)
            {
                if (!platform.IsPlatform)
                {
                    continue;
                }
                float    waypointHeight = heightFromFloor;
                WayPoint prevWaypoint   = null;
                for (float x = platform.Rect.X + diffFromHullEdge; x <= platform.Rect.Right - diffFromHullEdge; x += minDist)
                {
                    WayPoint wayPoint = new WayPoint(new Vector2(x, platform.Rect.Y + waypointHeight), SpawnType.Path, submarine);
                    if (prevWaypoint != null)
                    {
                        wayPoint.ConnectTo(prevWaypoint);
                    }
                    // If the waypoint is close to hull waypoints, remove it.
                    if (wayPoint != null)
                    {
                        for (int dir = -1; dir <= 1; dir += 2)
                        {
                            if (wayPoint.FindClosest(dir, horizontalSearch: true, tolerance: new Vector2(minDist, heightFromFloor), ignored: prevWaypoint.ToEnumerable()) != null)
                            {
                                wayPoint.Remove();
                                wayPoint = null;
                                break;
                            }
                        }
                    }
                    prevWaypoint = wayPoint;
                }
            }

            float outSideWaypointInterval = 100.0f;

            if (submarine.Info.Type != SubmarineType.OutpostModule)
            {
                List <(WayPoint, int)> outsideWaypoints = new List <(WayPoint, int)>();

                Rectangle borders        = Hull.GetBorders();
                int       originalWidth  = borders.Width;
                int       originalHeight = borders.Height;
                borders.X        -= Math.Min(500, originalWidth / 4);
                borders.Y        += Math.Min(500, originalHeight / 4);
                borders.Width    += Math.Min(1500, originalWidth / 2);
                borders.Height   += Math.Min(1000, originalHeight / 2);
                borders.Location -= MathUtils.ToPoint(submarine.HiddenSubPosition);

                if (borders.Width <= outSideWaypointInterval * 2)
                {
                    borders.Inflate(outSideWaypointInterval * 2 - borders.Width, 0);
                }

                if (borders.Height <= outSideWaypointInterval * 2)
                {
                    int inflateAmount = (int)(outSideWaypointInterval * 2) - borders.Height;
                    borders.Y      += inflateAmount / 2;
                    borders.Height += inflateAmount;
                }

                WayPoint[,] cornerWaypoint = new WayPoint[2, 2];
                for (int i = 0; i < 2; i++)
                {
                    for (float x = borders.X + outSideWaypointInterval; x < borders.Right - outSideWaypointInterval; x += outSideWaypointInterval)
                    {
                        var wayPoint = new WayPoint(
                            new Vector2(x, borders.Y - borders.Height * i) + submarine.HiddenSubPosition,
                            SpawnType.Path, submarine);

                        outsideWaypoints.Add((wayPoint, i));

                        if (x == borders.X + outSideWaypointInterval)
                        {
                            cornerWaypoint[i, 0] = wayPoint;
                        }
                        else
                        {
                            wayPoint.ConnectTo(WayPointList[WayPointList.Count - 2]);
                        }
                    }

                    cornerWaypoint[i, 1] = WayPointList[WayPointList.Count - 1];
                }

                for (int i = 0; i < 2; i++)
                {
                    WayPoint wayPoint = null;
                    for (float y = borders.Y - borders.Height; y < borders.Y; y += outSideWaypointInterval)
                    {
                        wayPoint = new WayPoint(
                            new Vector2(borders.X + borders.Width * i, y) + submarine.HiddenSubPosition,
                            SpawnType.Path, submarine);

                        outsideWaypoints.Add((wayPoint, i));

                        if (y == borders.Y - borders.Height)
                        {
                            wayPoint.ConnectTo(cornerWaypoint[1, i]);
                        }
                        else
                        {
                            wayPoint.ConnectTo(WayPointList[WayPointList.Count - 2]);
                        }
                    }

                    wayPoint.ConnectTo(cornerWaypoint[0, i]);
                }

                Vector2 center     = ConvertUnits.ToSimUnits(submarine.HiddenSubPosition);
                float   halfHeight = ConvertUnits.ToSimUnits(borders.Height / 2);
                // Try to move the waypoints so that they are near the walls, roughly following the shape of the sub.
                foreach (var wayPoint in outsideWaypoints)
                {
                    WayPoint wp        = wayPoint.Item1;
                    float    xDiff     = center.X - wp.SimPosition.X;
                    Vector2  targetPos = new Vector2(center.X - xDiff * 0.5f, center.Y);
                    Body     wall      = Submarine.PickBody(wp.SimPosition, targetPos, collisionCategory: Physics.CollisionWall, customPredicate: f => !(f.Body.UserData is Submarine));
                    if (wall == null)
                    {
                        // Try again, and shoot to the center now. It happens with some subs that the first, offset raycast don't hit the walls.
                        targetPos = new Vector2(center.X - xDiff, center.Y);
                        wall      = Submarine.PickBody(wp.SimPosition, targetPos, collisionCategory: Physics.CollisionWall, customPredicate: f => !(f.Body.UserData is Submarine));
                    }
                    if (wall != null)
                    {
                        float distanceFromWall = 1;
                        if (xDiff > 0 && !submarine.Info.HasTag(SubmarineTag.Shuttle))
                        {
                            // We don't want to move the waypoints near the tail too close to the engine.
                            float yDist = Math.Abs(center.Y - wp.SimPosition.Y);
                            distanceFromWall = MathHelper.Lerp(1, 3, MathUtils.InverseLerp(halfHeight, 0, yDist));
                        }
                        Vector2 newPos = Submarine.LastPickedPosition + Submarine.LastPickedNormal * distanceFromWall;
                        wp.rect = new Rectangle(ConvertUnits.ToDisplayUnits(newPos).ToPoint(), wp.rect.Size);
                        wp.FindHull();
                    }
                }
                // Remove unwanted points
                var      removals = new List <WayPoint>();
                WayPoint previous = null;
                float    tooClose = outSideWaypointInterval / 2;
                foreach (var wayPoint in outsideWaypoints)
                {
                    WayPoint wp = wayPoint.Item1;
                    if (wp.CurrentHull != null ||
                        Submarine.PickBody(wp.SimPosition, wp.SimPosition + Vector2.Normalize(center - wp.SimPosition) * 0.1f, collisionCategory: Physics.CollisionWall | Physics.CollisionItem, customPredicate: f => !(f.Body.UserData is Submarine), allowInsideFixture: true) != null)
                    {
                        // Remove waypoints that got inside/too near the sub.
                        removals.Add(wp);
                        previous = wp;
                        continue;
                    }
                    foreach (var otherWayPoint in outsideWaypoints)
                    {
                        WayPoint otherWp = otherWayPoint.Item1;
                        if (otherWp == wp)
                        {
                            continue;
                        }
                        if (removals.Contains(otherWp))
                        {
                            continue;
                        }
                        float sqrDist = Vector2.DistanceSquared(wp.Position, otherWp.Position);
                        // Remove waypoints that are too close to each other.
                        if (!removals.Contains(previous) && sqrDist < tooClose * tooClose)
                        {
                            removals.Add(wp);
                        }
                    }
                    previous = wp;
                }
                foreach (WayPoint wp in removals)
                {
                    outsideWaypoints.RemoveAll(w => w.Item1 == wp);
                    wp.Remove();
                }
                for (int i = 0; i < outsideWaypoints.Count; i++)
                {
                    WayPoint current = outsideWaypoints[i].Item1;
                    if (current.linkedTo.Count > 1)
                    {
                        continue;
                    }
                    WayPoint next           = null;
                    int      maxConnections = 2;
                    float    tooFar         = outSideWaypointInterval * 5;
                    for (int j = 0; j < maxConnections; j++)
                    {
                        if (current.linkedTo.Count >= maxConnections)
                        {
                            break;
                        }
                        tooFar /= current.linkedTo.Count;
                        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);
                        if (next != null)
                        {
                            current.ConnectTo(next);
                        }
                    }
                }
            }

            List <Structure> stairList = new List <Structure>();

            foreach (MapEntity me in mapEntityList)
            {
                if (!(me is Structure stairs))
                {
                    continue;
                }

                if (stairs.StairDirection != Direction.None)
                {
                    stairList.Add(stairs);
                }
            }

            foreach (Structure stairs in stairList)
            {
                WayPoint[] stairPoints = new WayPoint[3];

                stairPoints[0] = new WayPoint(
                    new Vector2(stairs.Rect.X - 32.0f,
                                stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? 80 : stairs.Rect.Height) + heightFromFloor), SpawnType.Path, submarine);

                stairPoints[1] = new WayPoint(
                    new Vector2(stairs.Rect.Right + 32.0f,
                                stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? stairs.Rect.Height : 80) + heightFromFloor), SpawnType.Path, submarine);

                for (int i = 0; i < 2; i++)
                {
                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = stairPoints[i].FindClosest(dir, horizontalSearch: true, new Vector2(100, 70));
                        if (closest == null)
                        {
                            continue;
                        }
                        stairPoints[i].ConnectTo(closest);
                    }
                }

                stairPoints[2] = new WayPoint((stairPoints[0].Position + stairPoints[1].Position) / 2, SpawnType.Path, submarine);
                stairPoints[0].ConnectTo(stairPoints[2]);
                stairPoints[2].ConnectTo(stairPoints[1]);
            }

            foreach (Item item in Item.ItemList)
            {
                var ladders = item.GetComponent <Ladder>();
                if (ladders == null)
                {
                    continue;
                }

                Vector2         bottomPoint  = new Vector2(item.Rect.Center.X, item.Rect.Top - item.Rect.Height + 10);
                List <WayPoint> ladderPoints = new List <WayPoint>
                {
                    new WayPoint(bottomPoint, SpawnType.Path, submarine),
                };

                List <Body> ignoredBodies = new List <Body>();
                // Lowest point is only meaningful for hanging ladders inside the sub, but it shouldn't matter in other cases either.
                // Start point is where the bots normally grasp the ladder when they stand on ground.
                WayPoint lowestPoint = ladderPoints[0];
                WayPoint prevPoint   = lowestPoint;
                Vector2  prevPos     = prevPoint.SimPosition;
                Body     ground      = Submarine.PickBody(lowestPoint.SimPosition, lowestPoint.SimPosition - Vector2.UnitY, ignoredBodies,
                                                          collisionCategory: Physics.CollisionWall | Physics.CollisionPlatform | Physics.CollisionStairs,
                                                          customPredicate: f => !(f.Body.UserData is Submarine));
                float startHeight = ground != null?ConvertUnits.ToDisplayUnits(ground.Position.Y) : bottomPoint.Y;

                startHeight += heightFromFloor;
                WayPoint startPoint = lowestPoint;
                Vector2  nextPos    = new Vector2(item.Rect.Center.X, startHeight);
                // Don't create the start point if it's too close to the lowest point or if it's outside of the sub.
                // If we skip creating the start point, the lowest point is used instead.
                if (lowestPoint == null || Math.Abs(startPoint.Position.Y - startHeight) > 40 && Hull.FindHull(nextPos) != null)
                {
                    startPoint = new WayPoint(nextPos, SpawnType.Path, submarine);
                    ladderPoints.Add(startPoint);
                    if (lowestPoint != null)
                    {
                        startPoint.ConnectTo(lowestPoint);
                    }
                    prevPoint = startPoint;
                    prevPos   = prevPoint.SimPosition;
                }
                for (float y = startPoint.Position.Y + LadderWaypointInterval; y < item.Rect.Y - 1.0f; y += LadderWaypointInterval)
                {
                    //first check if there's a door in the way
                    //(we need to create a waypoint linked to the door for NPCs to open it)
                    Body pickedBody = Submarine.PickBody(
                        ConvertUnits.ToSimUnits(new Vector2(startPoint.Position.X, y)),
                        prevPos, ignoredBodies, Physics.CollisionWall, false,
                        (Fixture f) => f.Body.UserData is Item && ((Item)f.Body.UserData).GetComponent <Door>() != null);

                    Door pickedDoor = null;
                    if (pickedBody != null)
                    {
                        pickedDoor = (pickedBody?.UserData as Item).GetComponent <Door>();
                    }
                    else
                    {
                        //no door, check for walls
                        pickedBody = Submarine.PickBody(
                            ConvertUnits.ToSimUnits(new Vector2(startPoint.Position.X, y)), prevPos, ignoredBodies, null, false,
                            (Fixture f) => f.Body.UserData is Structure);
                    }

                    if (pickedBody == null)
                    {
                        prevPos = Submarine.LastPickedPosition;
                        continue;
                    }
                    else
                    {
                        ignoredBodies.Add(pickedBody);
                    }

                    if (pickedDoor != null)
                    {
                        WayPoint newPoint = new WayPoint(pickedDoor.Item.Position, SpawnType.Path, submarine);
                        ladderPoints.Add(newPoint);
                        newPoint.ConnectedGap = pickedDoor.LinkedGap;
                        newPoint.ConnectTo(prevPoint);
                        prevPoint = newPoint;
                        prevPos   = new Vector2(prevPos.X, ConvertUnits.ToSimUnits(pickedDoor.Item.Position.Y - pickedDoor.Item.Rect.Height));
                    }
                    else
                    {
                        WayPoint newPoint = new WayPoint(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition) + Vector2.UnitY * heightFromFloor, SpawnType.Path, submarine);
                        ladderPoints.Add(newPoint);
                        newPoint.ConnectTo(prevPoint);
                        prevPoint = newPoint;
                        prevPos   = ConvertUnits.ToSimUnits(newPoint.Position);
                    }
                }

                // Cap
                if (prevPoint.rect.Y < item.Rect.Y - 40)
                {
                    WayPoint wayPoint = new WayPoint(new Vector2(item.Rect.Center.X, item.Rect.Y - 1.0f), SpawnType.Path, submarine);
                    ladderPoints.Add(wayPoint);
                    wayPoint.ConnectTo(prevPoint);
                }

                // Connect ladder waypoints to hull points at the right and left side
                foreach (WayPoint ladderPoint in ladderPoints)
                {
                    ladderPoint.Ladders = ladders;
                    bool isHatch = ladderPoint.ConnectedGap != null && !ladderPoint.ConnectedGap.IsRoomToRoom;
                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = null;
                        if (isHatch)
                        {
                            closest = ladderPoint.FindClosest(dir, horizontalSearch: true, new Vector2(500, 1000), ladderPoint.ConnectedGap?.ConnectedDoor?.Body.FarseerBody, filter: wp => wp.CurrentHull == null, ignored: ladderPoints);
                        }
                        else
                        {
                            closest = ladderPoint.FindClosest(dir, horizontalSearch: true, new Vector2(150, 100), ladderPoint.ConnectedGap?.ConnectedDoor?.Body.FarseerBody, ignored: ladderPoints);
                        }
                        if (closest == null)
                        {
                            continue;
                        }
                        ladderPoint.ConnectTo(closest);
                    }
                }
            }

            // Another pass: connect cap and bottom points with other ladders when they are vertically adjacent to another (double ladders)
            foreach (Item item in Item.ItemList)
            {
                var ladders = item.GetComponent <Ladder>();
                if (ladders == null)
                {
                    continue;
                }
                var      wps   = WayPointList.Where(wp => wp.Ladders == ladders).OrderByDescending(wp => wp.Rect.Y);
                WayPoint cap   = wps.First();
                WayPoint above = cap.FindClosest(1, horizontalSearch: false, tolerance: new Vector2(25, 50), filter: wp => wp.Ladders != null && wp.Ladders != ladders);
                above?.ConnectTo(cap);
                WayPoint bottom = wps.Last();
                WayPoint below  = bottom.FindClosest(-1, horizontalSearch: false, tolerance: new Vector2(25, 50), filter: wp => wp.Ladders != null && wp.Ladders != ladders);
                below?.ConnectTo(bottom);
            }

            foreach (Gap gap in Gap.GapList)
            {
                if (gap.IsHorizontal)
                {
                    // Too small to walk through
                    if (gap.Rect.Height < hullMinHeight)
                    {
                        continue;
                    }
                    Vector2 pos      = new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height + heightFromFloor);
                    var     wayPoint = new WayPoint(pos, SpawnType.Path, submarine, gap);
                    // The closest waypoint can be quite far if the gap is at an exterior door.
                    Vector2 tolerance = gap.IsRoomToRoom ? new Vector2(150, 70) : new Vector2(1000, 1000);
                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = wayPoint.FindClosest(dir, horizontalSearch: true, tolerance, gap.ConnectedDoor?.Body.FarseerBody);
                        if (closest != null)
                        {
                            wayPoint.ConnectTo(closest);
                        }
                    }
                }
                else
                {
                    // Create waypoints on vertical gaps on the outer walls, also hatches.
                    if (gap.IsRoomToRoom || gap.linkedTo.None(l => l is Hull))
                    {
                        continue;
                    }
                    // Too small to swim through
                    if (gap.Rect.Width < 50.0f)
                    {
                        continue;
                    }
                    Vector2 pos = new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height / 2);
                    // Some hatches are created in the block above where we handle the ladder waypoints. So we need to check for duplicates.
                    if (WayPointList.Any(wp => wp.ConnectedGap == gap))
                    {
                        continue;
                    }
                    var      wayPoint      = new WayPoint(pos, SpawnType.Path, submarine, gap);
                    Hull     connectedHull = (Hull)gap.linkedTo.First(l => l is Hull);
                    int      dir           = Math.Sign(connectedHull.Position.Y - gap.Position.Y);
                    WayPoint closest       = wayPoint.FindClosest(dir, horizontalSearch: false, new Vector2(50, 100));
                    if (closest != null)
                    {
                        wayPoint.ConnectTo(closest);
                    }
                    for (dir = -1; dir <= 1; dir += 2)
                    {
                        closest = wayPoint.FindClosest(dir, horizontalSearch: true, new Vector2(500, 1000), gap.ConnectedDoor?.Body.FarseerBody, filter: wp => wp.CurrentHull == null);
                        if (closest != null)
                        {
                            wayPoint.ConnectTo(closest);
                        }
                    }
                }
            }

            var orphans = WayPointList.FindAll(w => w.spawnType == SpawnType.Path && w.linkedTo.None());

            foreach (WayPoint wp in orphans)
            {
                wp.Remove();
            }

            foreach (WayPoint wp in WayPointList)
            {
                if (wp.CurrentHull == null && wp.Ladders == null && wp.linkedTo.Count < 2)
                {
                    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.");
                }
            }

            //re-disable the bodies of the doors that are supposed to be open
            foreach (Door door in openDoors)
            {
                door.Body.Enabled = false;
            }

            return(true);
        }
コード例 #2
0
        private void CheckDoorsInPath()
        {
            for (int i = 0; i < 2; i++)
            {
                WayPoint node     = null;
                WayPoint nextNode = null;

                if (i == 0)
                {
                    node     = currentPath.CurrentNode;
                    nextNode = currentPath.NextNode;
                }
                else
                {
                    node     = currentPath.PrevNode;
                    nextNode = currentPath.CurrentNode;
                }

                if (node == null || node.ConnectedGap == null || node.ConnectedGap.ConnectedDoor == null)
                {
                    continue;
                }

                if (nextNode == null)
                {
                    continue;
                }

                var door = node.ConnectedGap.ConnectedDoor;

                bool shouldBeOpen = false;

                if (door.LinkedGap.IsHorizontal)
                {
                    int currentDir = Math.Sign(nextNode.WorldPosition.X - door.Item.WorldPosition.X);

                    shouldBeOpen = (door.Item.WorldPosition.X - character.WorldPosition.X) * currentDir > -50.0f;
                }
                else
                {
                    int currentDir = Math.Sign(nextNode.WorldPosition.Y - door.Item.WorldPosition.Y);

                    shouldBeOpen = (door.Item.WorldPosition.Y - character.WorldPosition.Y) * currentDir > -80.0f;
                }


                //toggle the door if it's the previous node and open, or if it's current node and closed
                if (door.IsOpen != shouldBeOpen)
                {
                    var buttons = door.Item.GetConnectedComponents <Controller>(true);

                    Controller closestButton = null;
                    float      closestDist   = 0.0f;

                    foreach (Controller controller in buttons)
                    {
                        float dist = Vector2.Distance(controller.Item.WorldPosition, character.WorldPosition);
                        if (dist > controller.Item.InteractDistance * 2.0f)
                        {
                            continue;
                        }

                        if (dist < closestDist || closestButton == null)
                        {
                            closestButton = controller;
                            closestDist   = dist;
                        }
                    }

                    if (closestButton != null)
                    {
                        if (!closestButton.HasRequiredItems(character, false) && shouldBeOpen)
                        {
                            currentPath.Unreachable = true;
                            return;
                        }

                        closestButton.Item.TryInteract(character, false, true, true);
                        break;
                    }
                }
            }
        }
コード例 #3
0
        public static void CreateItems(List <ItemPrefab> itemsToSpawn)
        {
            WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub);

            if (wp == null)
            {
                DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!");
                return;
            }

            Hull cargoRoom = Hull.FindHull(wp.WorldPosition);

            if (cargoRoom == null)
            {
                DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!");
                return;
            }

            Dictionary <ItemContainer, int> availableContainers = new Dictionary <ItemContainer, int>();

            foreach (ItemPrefab prefab in itemsToSpawn)
            {
                Vector2 position = new Vector2(
                    Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20),
                    cargoRoom.Rect.Y - cargoRoom.Rect.Height + prefab.Size.Y / 2);

                ItemContainer itemContainer = null;
                if (!string.IsNullOrEmpty(prefab.CargoContainerName))
                {
                    itemContainer = availableContainers.Keys.ToList().Find(ac =>
                                                                           ac.Item.Prefab.NameMatches(prefab.CargoContainerName) ||
                                                                           ac.Item.Prefab.Tags.Contains(prefab.CargoContainerName.ToLowerInvariant()));

                    if (itemContainer == null)
                    {
                        var containerPrefab = MapEntityPrefab.List.Find(ep =>
                                                                        ep.NameMatches(prefab.CargoContainerName) ||
                                                                        (ep.Tags != null && ep.Tags.Contains(prefab.CargoContainerName.ToLowerInvariant()))) as ItemPrefab;

                        if (containerPrefab == null)
                        {
                            DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + containerPrefab.Name + "\"!");
                            continue;
                        }

                        Item containerItem = new Item(containerPrefab, position, wp.Submarine);
                        itemContainer = containerItem.GetComponent <ItemContainer>();
                        if (itemContainer == null)
                        {
                            DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!");
                            continue;
                        }
                        availableContainers.Add(itemContainer, itemContainer.Capacity);
                        if (GameMain.Server != null)
                        {
                            Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                        }
                    }
                }

                if (itemContainer == null)
                {
                    //no container, place at the waypoint
                    if (GameMain.Server != null)
                    {
                        Entity.Spawner.AddToSpawnQueue(prefab, position, wp.Submarine);
                    }
                    else
                    {
                        new Item(prefab, position, wp.Submarine);
                    }
                }
                else
                {
                    //place in the container
                    if (GameMain.Server != null)
                    {
                        Entity.Spawner.AddToSpawnQueue(prefab, itemContainer.Inventory);
                    }
                    else
                    {
                        var item = new Item(prefab, position, wp.Submarine);
                        itemContainer.Inventory.TryPutItem(item, null);
                    }

                    //reduce the number of available slots in the container
                    availableContainers[itemContainer]--;
                    if (availableContainers[itemContainer] <= 0)
                    {
                        availableContainers.Remove(itemContainer);
                    }
                }
            }

            itemsToSpawn.Clear();
        }
コード例 #4
0
ファイル: WayPoint.cs プロジェクト: jamiebidelia/Barotrauma
        public static void GenerateSubWaypoints(Submarine submarine)
        {
            if (!Hull.hullList.Any())
            {
                DebugConsole.ThrowError("Couldn't generate waypoints: no hulls found.");
                return;
            }

            List <WayPoint> existingWaypoints = WayPointList.FindAll(wp => wp.spawnType == SpawnType.Path);

            foreach (WayPoint wayPoint in existingWaypoints)
            {
                wayPoint.Remove();
            }

            //find all open doors and temporarily activate their bodies to prevent visibility checks
            //from ignoring the doors and generating waypoint connections that go straight through the door
            List <Door> openDoors = new List <Door>();

            foreach (Item item in Item.ItemList)
            {
                var door = item.GetComponent <Door>();
                if (door != null && !door.Body.Enabled)
                {
                    openDoors.Add(door);
                    door.Body.Enabled = true;
                }
            }


            float minDist         = 150.0f;
            float heightFromFloor = 110.0f;

            foreach (Hull hull in Hull.hullList)
            {
                if (hull.Rect.Height < 150)
                {
                    continue;
                }

                WayPoint prevWaypoint = null;

                if (hull.Rect.Width < minDist * 3.0f)
                {
                    new WayPoint(
                        new Vector2(hull.Rect.X + hull.Rect.Width / 2.0f, hull.Rect.Y - hull.Rect.Height + heightFromFloor), SpawnType.Path, submarine);
                    continue;
                }

                for (float x = hull.Rect.X + minDist; x <= hull.Rect.Right - minDist; x += minDist)
                {
                    var wayPoint = new WayPoint(new Vector2(x, hull.Rect.Y - hull.Rect.Height + heightFromFloor), SpawnType.Path, submarine);

                    if (prevWaypoint != null)
                    {
                        wayPoint.ConnectTo(prevWaypoint);
                    }

                    prevWaypoint = wayPoint;
                }
            }

            float outSideWaypointInterval = 200.0f;
            int   outsideWaypointDist     = 100;

            Rectangle borders = Hull.GetBorders();

            borders.X -= outsideWaypointDist;
            borders.Y += outsideWaypointDist;

            borders.Width  += outsideWaypointDist * 2;
            borders.Height += outsideWaypointDist * 2;

            borders.Location -= MathUtils.ToPoint(submarine.HiddenSubPosition);

            if (borders.Width <= outSideWaypointInterval * 2)
            {
                borders.Inflate(outSideWaypointInterval * 2 - borders.Width, 0);
            }

            if (borders.Height <= outSideWaypointInterval * 2)
            {
                int inflateAmount = (int)(outSideWaypointInterval * 2) - borders.Height;
                borders.Y += inflateAmount / 2;

                borders.Height += inflateAmount;
            }

            WayPoint[,] cornerWaypoint = new WayPoint[2, 2];

            for (int i = 0; i < 2; i++)
            {
                for (float x = borders.X + outSideWaypointInterval; x < borders.Right - outSideWaypointInterval; x += outSideWaypointInterval)
                {
                    var wayPoint = new WayPoint(
                        new Vector2(x, borders.Y - borders.Height * i) + submarine.HiddenSubPosition,
                        SpawnType.Path, submarine);

                    if (x == borders.X + outSideWaypointInterval)
                    {
                        cornerWaypoint[i, 0] = wayPoint;
                    }
                    else
                    {
                        wayPoint.ConnectTo(WayPointList[WayPointList.Count - 2]);
                    }
                }

                cornerWaypoint[i, 1] = WayPointList[WayPointList.Count - 1];
            }

            for (int i = 0; i < 2; i++)
            {
                WayPoint wayPoint = null;
                for (float y = borders.Y - borders.Height; y < borders.Y; y += outSideWaypointInterval)
                {
                    wayPoint = new WayPoint(
                        new Vector2(borders.X + borders.Width * i, y) + submarine.HiddenSubPosition,
                        SpawnType.Path, submarine);

                    if (y == borders.Y - borders.Height)
                    {
                        wayPoint.ConnectTo(cornerWaypoint[1, i]);
                    }
                    else
                    {
                        wayPoint.ConnectTo(WayPoint.WayPointList[WayPointList.Count - 2]);
                    }
                }

                wayPoint.ConnectTo(cornerWaypoint[0, i]);
            }

            List <Structure> stairList = new List <Structure>();

            foreach (MapEntity me in mapEntityList)
            {
                Structure stairs = me as Structure;
                if (stairs == null)
                {
                    continue;
                }

                if (stairs.StairDirection != Direction.None)
                {
                    stairList.Add(stairs);
                }
            }

            foreach (Structure stairs in stairList)
            {
                WayPoint[] stairPoints = new WayPoint[3];

                stairPoints[0] = new WayPoint(
                    new Vector2(stairs.Rect.X - 32.0f,
                                stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? 80 : stairs.Rect.Height) + heightFromFloor), SpawnType.Path, submarine);

                stairPoints[1] = new WayPoint(
                    new Vector2(stairs.Rect.Right + 32.0f,
                                stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? stairs.Rect.Height : 80) + heightFromFloor), SpawnType.Path, submarine);

                for (int i = 0; i < 2; i++)
                {
                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = stairPoints[i].FindClosest(dir, true, new Vector2(-30.0f, 30f));
                        if (closest == null)
                        {
                            continue;
                        }
                        stairPoints[i].ConnectTo(closest);
                    }
                }

                stairPoints[2] = new WayPoint((stairPoints[0].Position + stairPoints[1].Position) / 2, SpawnType.Path, submarine);
                stairPoints[0].ConnectTo(stairPoints[2]);
                stairPoints[2].ConnectTo(stairPoints[1]);
            }

            foreach (Item item in Item.ItemList)
            {
                var ladders = item.GetComponent <Ladder>();
                if (ladders == null)
                {
                    continue;
                }

                List <WayPoint> ladderPoints = new List <WayPoint>();
                ladderPoints.Add(new WayPoint(new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height + heightFromFloor), SpawnType.Path, submarine));

                WayPoint    prevPoint     = ladderPoints[0];
                Vector2     prevPos       = prevPoint.SimPosition;
                List <Body> ignoredBodies = new List <Body>();

                for (float y = ladderPoints[0].Position.Y + 100.0f; y < item.Rect.Y - 1.0f; y += 100.0f)
                {
                    //first check if there's a door in the way
                    //(we need to create a waypoint linked to the door for NPCs to open it)
                    Body pickedBody = Submarine.PickBody(
                        ConvertUnits.ToSimUnits(new Vector2(ladderPoints[0].Position.X, y)),
                        prevPos, ignoredBodies, Physics.CollisionWall, false,
                        (Fixture f) => f.Body.UserData is Item && ((Item)f.Body.UserData).GetComponent <Door>() != null);

                    Door pickedDoor = null;
                    if (pickedBody != null)
                    {
                        pickedDoor = (pickedBody?.UserData as Item).GetComponent <Door>();
                    }
                    else
                    {
                        //no door, check for walls
                        pickedBody = Submarine.PickBody(
                            ConvertUnits.ToSimUnits(new Vector2(ladderPoints[0].Position.X, y)), prevPos, ignoredBodies, null, false);
                    }

                    if (pickedBody == null)
                    {
                        prevPos = Submarine.LastPickedPosition;
                        continue;
                    }
                    else
                    {
                        ignoredBodies.Add(pickedBody);
                    }


                    if (pickedDoor != null)
                    {
                        WayPoint newPoint = new WayPoint(pickedDoor.Item.Position, SpawnType.Path, submarine);
                        ladderPoints.Add(newPoint);
                        newPoint.ConnectedGap = pickedDoor.LinkedGap;
                        newPoint.ConnectTo(prevPoint);
                        prevPoint = newPoint;
                        prevPos   = new Vector2(prevPos.X, ConvertUnits.ToSimUnits(pickedDoor.Item.Position.Y - pickedDoor.Item.Rect.Height));
                    }
                    else
                    {
                        WayPoint newPoint = new WayPoint(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition) + Vector2.UnitY * heightFromFloor, SpawnType.Path, submarine);
                        ladderPoints.Add(newPoint);
                        newPoint.ConnectTo(prevPoint);
                        prevPoint = newPoint;
                        prevPos   = ConvertUnits.ToSimUnits(newPoint.Position);
                    }
                }

                if (prevPoint.rect.Y < item.Rect.Y - 10.0f)
                {
                    WayPoint newPoint = new WayPoint(new Vector2(item.Rect.Center.X, item.Rect.Y - 1.0f), SpawnType.Path, submarine);
                    ladderPoints.Add(newPoint);
                    newPoint.ConnectTo(prevPoint);
                }

                //connect ladder waypoints to hull points at the right and left side
                foreach (WayPoint ladderPoint in ladderPoints)
                {
                    ladderPoint.Ladders = ladders;
                    //don't connect if the waypoint is at a gap (= at the boundary of hulls and/or at a hatch)
                    if (ladderPoint.ConnectedGap != null)
                    {
                        continue;
                    }

                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = ladderPoint.FindClosest(dir, true, new Vector2(-150.0f, 10f));
                        if (closest == null)
                        {
                            continue;
                        }
                        ladderPoint.ConnectTo(closest);
                    }
                }
            }

            foreach (Gap gap in Gap.GapList)
            {
                if (!gap.IsHorizontal)
                {
                    continue;
                }

                //too small to walk through
                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, gap);

                for (int dir = -1; dir <= 1; dir += 2)
                {
                    float tolerance = gap.IsRoomToRoom ? 50.0f : outSideWaypointInterval / 2.0f;

                    WayPoint closest = wayPoint.FindClosest(
                        dir, true, new Vector2(-tolerance, tolerance),
                        gap.ConnectedDoor?.Body.FarseerBody);

                    if (closest != null)
                    {
                        wayPoint.ConnectTo(closest);
                    }
                }
            }

            foreach (Gap gap in Gap.GapList)
            {
                if (gap.IsHorizontal || gap.IsRoomToRoom || !gap.linkedTo.Any(l => l is Hull))
                {
                    continue;
                }

                //too small to walk through
                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, gap);

                float tolerance     = outSideWaypointInterval / 2.0f;
                Hull  connectedHull = (Hull)gap.linkedTo.First(l => l is Hull);
                int   dir           = Math.Sign(connectedHull.Position.Y - gap.Position.Y);

                WayPoint closest = wayPoint.FindClosest(
                    dir, false, new Vector2(-tolerance, tolerance),
                    gap.ConnectedDoor?.Body.FarseerBody);

                if (closest != null)
                {
                    wayPoint.ConnectTo(closest);
                }
            }

            var orphans = WayPointList.FindAll(w => w.spawnType == SpawnType.Path && !w.linkedTo.Any());

            foreach (WayPoint wp in orphans)
            {
                wp.Remove();
            }

            //re-disable the bodies of the doors that are supposed to be open
            foreach (Door door in openDoors)
            {
                door.Body.Enabled = false;
            }
        }
コード例 #5
0
ファイル: WayPoint.cs プロジェクト: jamiebidelia/Barotrauma
        public static WayPoint[] SelectCrewSpawnPoints(List <CharacterInfo> crew, Submarine submarine)
        {
            List <WayPoint> subWayPoints = WayPointList.FindAll(wp => wp.Submarine == submarine);

            List <WayPoint> unassignedWayPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human);

            WayPoint[] assignedWayPoints = new WayPoint[crew.Count];

            for (int i = 0; i < crew.Count; i++)
            {
                //try to give the crew member a spawnpoint that hasn't been assigned to anyone and matches their job
                for (int n = 0; n < unassignedWayPoints.Count; n++)
                {
                    if (crew[i].Job.Prefab != unassignedWayPoints[n].assignedJob)
                    {
                        continue;
                    }
                    assignedWayPoints[i] = unassignedWayPoints[n];
                    unassignedWayPoints.RemoveAt(n);

                    break;
                }
            }

            //go through the crewmembers that don't have a spawnpoint yet (if any)
            for (int i = 0; i < crew.Count; i++)
            {
                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 subWayPoints)
                {
                    if (wp.spawnType != SpawnType.Human || wp.assignedJob != crew[i].Job.Prefab)
                    {
                        continue;
                    }

                    assignedWayPoints[i] = wp;
                    break;
                }
                if (assignedWayPoints[i] != null)
                {
                    continue;
                }

                //try to assign a spawnpoint that isn't meant for any specific job
                var nonJobSpecificPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null);
                if (nonJobSpecificPoints.Any())
                {
                    assignedWayPoints[i] = nonJobSpecificPoints[Rand.Int(nonJobSpecificPoints.Count, Rand.RandSync.Server)];
                }

                if (assignedWayPoints[i] != null)
                {
                    continue;
                }

                //everything else failed -> just give a random spawnpoint inside the sub
                assignedWayPoints[i] = GetRandom(SpawnType.Human, null, submarine, true);
            }

            for (int i = 0; i < assignedWayPoints.Length; i++)
            {
                if (assignedWayPoints[i] == null)
                {
                    DebugConsole.ThrowError("Couldn't find a waypoint for " + crew[i].Name + "!");
                    assignedWayPoints[i] = WayPointList[0];
                }
            }

            return(assignedWayPoints);
        }
コード例 #6
0
 public PathNode(WayPoint wayPoint)
 {
     Waypoint   = wayPoint;
     Position   = wayPoint.SimPosition;
     WayPointID = Waypoint.ID;
 }
コード例 #7
0
        private void InitializeJobItem(Character character, XElement itemElement, WayPoint spawnPoint = null, Item parentItem = null)
        {
            ItemPrefab itemPrefab;

            if (itemElement.Attribute("name") != null)
            {
                string itemName = itemElement.Attribute("name").Value;
                DebugConsole.ThrowError("Error in Job config (" + Name + ") - use item identifiers instead of names to configure the items.");
                itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
                if (itemPrefab == null)
                {
                    DebugConsole.ThrowError("Tried to spawn \"" + Name + "\" with the item \"" + itemName + "\". Matching item prefab not found.");
                    return;
                }
            }
            else
            {
                string itemIdentifier = itemElement.GetAttributeString("identifier", "");
                itemPrefab = MapEntityPrefab.Find(null, itemIdentifier) as ItemPrefab;
                if (itemPrefab == null)
                {
                    DebugConsole.ThrowError("Tried to spawn \"" + Name + "\" with the item \"" + itemIdentifier + "\". Matching item prefab not found.");
                    return;
                }
            }

            Item item = new Item(itemPrefab, character.Position, null);

#if SERVER
            if (GameMain.Server != null && Entity.Spawner != null)
            {
                if (GameMain.Server.EntityEventManager.UniqueEvents.Any(ev => ev.Entity == item))
                {
                    string errorMsg = $"Error while spawning job items. Item {item.Name} created network events before the spawn event had been created.";
                    DebugConsole.ThrowError(errorMsg);
                    GameAnalyticsManager.AddErrorEventOnce("Job.InitializeJobItem:EventsBeforeSpawning", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
                    GameMain.Server.EntityEventManager.UniqueEvents.RemoveAll(ev => ev.Entity == item);
                    GameMain.Server.EntityEventManager.Events.RemoveAll(ev => ev.Entity == item);
                }

                Entity.Spawner.CreateNetworkEvent(item, false);
            }
#endif

            if (itemElement.GetAttributeBool("equip", false))
            {
                List <InvSlotType> allowedSlots = new List <InvSlotType>(item.AllowedSlots);
                allowedSlots.Remove(InvSlotType.Any);

                character.Inventory.TryPutItem(item, null, allowedSlots);
            }
            else
            {
                character.Inventory.TryPutItem(item, null, item.AllowedSlots);
            }

            Wearable wearable = ((List <ItemComponent>)item.Components)?.Find(c => c is Wearable) as Wearable;
            if (wearable != null)
            {
                if (Variant > 0 && Variant <= wearable.Variants)
                {
                    wearable.Variant = Variant;
                }
                else
                {
                    wearable.Variant = wearable.Variant; //force server event
                    if (wearable.Variants > 0 && Variant == 0)
                    {
                        //set variant to the same as the wearable to get the rest of the character's gear
                        //to use the same variant (if possible)
                        Variant = wearable.Variant;
                    }
                }
            }

            if (item.Prefab.Identifier == "idcard" && spawnPoint != null)
            {
                foreach (string s in spawnPoint.IdCardTags)
                {
                    item.AddTag(s);
                }
                item.AddTag("name:" + character.Name);
                item.AddTag("job:" + Name);
                if (!string.IsNullOrWhiteSpace(spawnPoint.IdCardDesc))
                {
                    item.Description = spawnPoint.IdCardDesc;
                }
            }

            foreach (WifiComponent wifiComponent in item.GetComponents <WifiComponent>())
            {
                wifiComponent.TeamID = character.TeamID;
            }

            if (parentItem != null)
            {
                parentItem.Combine(item, user: null);
            }

            foreach (XElement childItemElement in itemElement.Elements())
            {
                InitializeJobItem(character, childItemElement, spawnPoint, item);
            }
        }
コード例 #8
0
ファイル: DebugConsole.cs プロジェクト: MSylvia/Barotrauma
        static DebugConsole()
        {
            commands.Add(new Command("help", "", (string[] args) =>
            {
                if (args.Length == 0)
                {
                    foreach (Command c in commands)
                    {
                        if (string.IsNullOrEmpty(c.help))
                        {
                            continue;
                        }
                        NewMessage(c.help, Color.Cyan);
                    }
                }
                else
                {
                    var matchingCommand = commands.Find(c => c.names.Any(name => name == args[0]));
                    if (matchingCommand == null)
                    {
                        NewMessage("Command " + args[0] + " not found.", Color.Red);
                    }
                    else
                    {
                        NewMessage(matchingCommand.help, Color.Cyan);
                    }
                }
            }));

            commands.Add(new Command("clientlist", "clientlist: List all the clients connected to the server.", (string[] args) =>
            {
                if (GameMain.Server == null)
                {
                    return;
                }
                NewMessage("***************", Color.Cyan);
                foreach (Client c in GameMain.Server.ConnectedClients)
                {
                    NewMessage("- " + c.ID.ToString() + ": " + c.Name + ", " + c.Connection.RemoteEndPoint.Address.ToString(), Color.Cyan);
                }
                NewMessage("***************", Color.Cyan);
            }));


            commands.Add(new Command("createfilelist", "", (string[] args) =>
            {
                UpdaterUtil.SaveFileList("filelist.xml");
            }));

            commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename] [near/inside/outside]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine).", (string[] args) =>
            {
                if (args.Length == 0)
                {
                    return;
                }

                Character spawnedCharacter = null;

                Vector2 spawnPosition = Vector2.Zero;
                WayPoint spawnPoint   = null;

                if (args.Length > 1)
                {
                    switch (args[1].ToLowerInvariant())
                    {
                    case "inside":
                        spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
                        break;

                    case "outside":
                        spawnPoint = WayPoint.GetRandom(SpawnType.Enemy);
                        break;

                    case "near":
                    case "close":
                        float closestDist = -1.0f;
                        foreach (WayPoint wp in WayPoint.WayPointList)
                        {
                            if (wp.Submarine != null)
                            {
                                continue;
                            }

                            //don't spawn inside hulls
                            if (Hull.FindHull(wp.WorldPosition, null) != null)
                            {
                                continue;
                            }

                            float dist = Vector2.Distance(wp.WorldPosition, GameMain.GameScreen.Cam.WorldViewCenter);

                            if (closestDist < 0.0f || dist < closestDist)
                            {
                                spawnPoint  = wp;
                                closestDist = dist;
                            }
                        }
                        break;

                    case "cursor":
                        spawnPosition = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                        break;

                    default:
                        spawnPoint = WayPoint.GetRandom(args[0].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy);
                        break;
                    }
                }
                else
                {
                    spawnPoint = WayPoint.GetRandom(args[0].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy);
                }

                if (string.IsNullOrWhiteSpace(args[0]))
                {
                    return;
                }

                if (spawnPoint != null)
                {
                    spawnPosition = spawnPoint.WorldPosition;
                }

                if (args[0].ToLowerInvariant() == "human")
                {
                    spawnedCharacter = Character.Create(Character.HumanConfigFile, spawnPosition);

#if CLIENT
                    if (GameMain.GameSession != null)
                    {
                        SinglePlayerCampaign mode = GameMain.GameSession.GameMode as SinglePlayerCampaign;
                        if (mode != null)
                        {
                            Character.Controlled = spawnedCharacter;
                            GameMain.GameSession.CrewManager.AddCharacter(Character.Controlled);
                            GameMain.GameSession.CrewManager.SelectCharacter(null, Character.Controlled);
                        }
                    }
#endif
                }
                else
                {
                    List <string> characterFiles = GameMain.Config.SelectedContentPackage.GetFilesOfType(ContentType.Character);

                    foreach (string characterFile in characterFiles)
                    {
                        if (Path.GetFileNameWithoutExtension(characterFile).ToLowerInvariant() == args[0].ToLowerInvariant())
                        {
                            Character.Create(characterFile, spawnPosition);
                            return;
                        }
                    }

                    ThrowError("No character matching the name \"" + args[0] + "\" found in the selected content package.");

                    //attempt to open the config from the default path (the file may still be present even if it isn't included in the content package)
                    string configPath = "Content/Characters/"
                                        + args[0].First().ToString().ToUpper() + args[0].Substring(1)
                                        + "/" + args[0].ToLower() + ".xml";
                    Character.Create(configPath, spawnPosition);
                }
            }));

            commands.Add(new Command("spawnitem", "spawnitem [itemname] [cursor/inventory]: Spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted.", (string[] args) =>
            {
                if (args.Length < 1)
                {
                    return;
                }

                Vector2?spawnPos         = null;
                Inventory spawnInventory = null;

                int extraParams = 0;
                switch (args.Last())
                {
                case "cursor":
                    extraParams = 1;
                    spawnPos    = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                    break;

                case "inventory":
                    extraParams    = 1;
                    spawnInventory = Character.Controlled == null ? null : Character.Controlled.Inventory;
                    break;

                default:
                    extraParams = 0;
                    break;
                }

                string itemName = string.Join(" ", args.Take(args.Length - extraParams)).ToLowerInvariant();

                var itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
                if (itemPrefab == null)
                {
                    ThrowError("Item \"" + itemName + "\" not found!");
                    return;
                }

                if (spawnPos == null && spawnInventory == null)
                {
                    var wp   = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
                    spawnPos = wp == null ? Vector2.Zero : wp.WorldPosition;
                }

                if (spawnPos != null)
                {
                    Entity.Spawner.AddToSpawnQueue(itemPrefab, (Vector2)spawnPos);
                }
                else if (spawnInventory != null)
                {
                    Entity.Spawner.AddToSpawnQueue(itemPrefab, spawnInventory);
                }
            }));

            commands.Add(new Command("disablecrewai", "disablecrewai: Disable the AI of the NPCs in the crew.", (string[] args) =>
            {
                HumanAIController.DisableCrewAI = true;
                NewMessage("Crew AI disabled", Color.White);
            }));

            commands.Add(new Command("enablecrewai", "enablecrewai: Enable the AI of the NPCs in the crew.", (string[] args) =>
            {
                HumanAIController.DisableCrewAI = false;
                NewMessage("Crew AI enabled", Color.White);
            }));

            commands.Add(new Command("autorestartinterval", "autorestartinterval [seconds]: Set how long the server waits between rounds before automatically starting a new one.", (string[] args) =>
            {
                if (GameMain.Server == null)
                {
                    return;
                }
                if (args.Length > 0)
                {
                    int parsedInt = 0;
                    if (int.TryParse(args[0], out parsedInt) && parsedInt >= 0)
                    {
                        GameMain.Server.AutoRestartInterval = parsedInt;
                        NewMessage("Autorestart interval set to " + GameMain.Server.AutoRestartInterval + " seconds.", Color.White);
                    }
                }
            }));


            commands.Add(new Command("autorestarttimer", "autorestarttimer [seconds]: Set the current autorestart countdown to the specified value.", (string[] args) =>
            {
                if (GameMain.Server == null)
                {
                    return;
                }
                if (args.Length > 0)
                {
                    int parsedInt = 0;
                    if (int.TryParse(args[0], out parsedInt) && parsedInt >= 0)
                    {
                        GameMain.Server.AutoRestartTimer = parsedInt;
                        GameMain.NetLobbyScreen.LastUpdateID++;
                        NewMessage("Autorestart timer set to " + GameMain.Server.AutoRestartTimer + " seconds.", Color.White);
                    }
                }
            }));

            commands.Add(new Command("kick", "kick [name]: Kick a player out of the server.", (string[] args) =>
            {
                if (GameMain.NetworkMember == null || args.Length == 0)
                {
                    return;
                }

                string playerName = string.Join(" ", args);

                ShowQuestionPrompt("Reason for kicking \"" + playerName + "\"?", (reason) =>
                {
                    GameMain.NetworkMember.KickPlayer(playerName, reason);
                });
            }));

            commands.Add(new Command("kickid", "kickid [id]: Kick the player with the specified client ID out of the server.", (string[] args) =>
            {
                if (GameMain.Server == null || args.Length == 0)
                {
                    return;
                }

                int id = 0;
                int.TryParse(args[0], out id);
                var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
                if (client == null)
                {
                    ThrowError("Client id \"" + id + "\" not found.");
                    return;
                }

                ShowQuestionPrompt("Reason for kicking \"" + client.Name + "\"?", (reason) =>
                {
                    GameMain.Server.KickPlayer(client.Name, reason);
                });
            }));

            commands.Add(new Command("ban", "ban [name]: Kick and ban the player from the server.", (string[] args) =>
            {
                if (GameMain.NetworkMember == null || args.Length == 0)
                {
                    return;
                }

                string clientName = string.Join(" ", args);
                ShowQuestionPrompt("Reason for banning \"" + clientName + "\"?", (reason) =>
                {
                    ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
                    {
                        TimeSpan?banDuration = null;
                        if (!string.IsNullOrWhiteSpace(duration))
                        {
                            TimeSpan parsedBanDuration;
                            if (!TryParseTimeSpan(duration, out parsedBanDuration))
                            {
                                ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
                                return;
                            }
                            banDuration = parsedBanDuration;
                        }

                        GameMain.NetworkMember.BanPlayer(clientName, reason, false, banDuration);
                    });
                });
            }));

            commands.Add(new Command("banid", "banid [id]: Kick and ban the player with the specified client ID from the server.", (string[] args) =>
            {
                if (GameMain.Server == null || args.Length == 0)
                {
                    return;
                }

                int id = 0;
                int.TryParse(args[0], out id);
                var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
                if (client == null)
                {
                    ThrowError("Client id \"" + id + "\" not found.");
                    return;
                }

                ShowQuestionPrompt("Reason for banning \"" + client.Name + "\"?", (reason) =>
                {
                    ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
                    {
                        TimeSpan?banDuration = null;
                        if (!string.IsNullOrWhiteSpace(duration))
                        {
                            TimeSpan parsedBanDuration;
                            if (!TryParseTimeSpan(duration, out parsedBanDuration))
                            {
                                ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
                                return;
                            }
                            banDuration = parsedBanDuration;
                        }

                        GameMain.Server.BanPlayer(client.Name, reason, false, banDuration);
                    });
                });
            }));


            commands.Add(new Command("banip", "banip [ip]: Ban the IP address from the server.", (string[] args) =>
            {
                if (GameMain.Server == null || args.Length == 0)
                {
                    return;
                }

                ShowQuestionPrompt("Reason for banning the ip \"" + commands[1] + "\"?", (reason) =>
                {
                    ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
                    {
                        TimeSpan?banDuration = null;
                        if (!string.IsNullOrWhiteSpace(duration))
                        {
                            TimeSpan parsedBanDuration;
                            if (!TryParseTimeSpan(duration, out parsedBanDuration))
                            {
                                ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
                                return;
                            }
                            banDuration = parsedBanDuration;
                        }

                        var client = GameMain.Server.ConnectedClients.Find(c => c.Connection.RemoteEndPoint.Address.ToString() == args[0]);
                        if (client == null)
                        {
                            GameMain.Server.BanList.BanPlayer("Unnamed", args[0], reason, banDuration);
                        }
                        else
                        {
                            GameMain.Server.KickClient(client, reason);
                        }
                    });
                });
            }));

            commands.Add(new Command("teleportcharacter|teleport", "teleport [character name]: Teleport the specified character to the position of the cursor. If the name parameter is omitted, the controlled character will be teleported.", (string[] args) =>
            {
                Character tpCharacter = null;

                if (args.Length == 0)
                {
                    tpCharacter = Character.Controlled;
                }
                else
                {
                    tpCharacter = FindMatchingCharacter(args, false);
                }

                if (tpCharacter == null)
                {
                    return;
                }

                var cam = GameMain.GameScreen.Cam;
                tpCharacter.AnimController.CurrentHull = null;
                tpCharacter.Submarine = null;
                tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cam.ScreenToWorld(PlayerInput.MousePosition)));
                tpCharacter.AnimController.FindHull(cam.ScreenToWorld(PlayerInput.MousePosition), true);
            }));

            commands.Add(new Command("godmode", "godmode: Toggle submarine godmode. Makes the main submarine invulnerable to damage.", (string[] args) =>
            {
                if (Submarine.MainSub == null)
                {
                    return;
                }

                Submarine.MainSub.GodMode = !Submarine.MainSub.GodMode;
                NewMessage(Submarine.MainSub.GodMode ? "Godmode on" : "Godmode off", Color.White);
            }));

            commands.Add(new Command("lockx", "lockx: Lock horizontal movement of the main submarine.", (string[] args) =>
            {
                Submarine.LockX = !Submarine.LockX;
            }));

            commands.Add(new Command("locky", "loxky: Lock vertical movement of the main submarine.", (string[] args) =>
            {
                Submarine.LockY = !Submarine.LockY;
            }));

            commands.Add(new Command("dumpids", "", (string[] args) =>
            {
                try
                {
                    int count = args.Length == 0 ? 10 : int.Parse(args[0]);
                    Entity.DumpIds(count);
                }
                catch (Exception e)
                {
                    ThrowError("Failed to dump ids", e);
                }
            }));

            commands.Add(new Command("heal", "heal [character name]: Restore the specified character to full health. If the name parameter is omitted, the controlled character will be healed.", (string[] args) =>
            {
                Character healedCharacter = null;
                if (args.Length == 0)
                {
                    healedCharacter = Character.Controlled;
                }
                else
                {
                    healedCharacter = FindMatchingCharacter(args);
                }

                if (healedCharacter != null)
                {
                    healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null);
                    healedCharacter.Oxygen   = 100.0f;
                    healedCharacter.Bleeding = 0.0f;
                    healedCharacter.SetStun(0.0f, true);
                }
            }));

            commands.Add(new Command("revive", "revive [character name]: Bring the specified character back from the dead. If the name parameter is omitted, the controlled character will be revived.", (string[] args) =>
            {
                Character revivedCharacter = null;
                if (args.Length == 0)
                {
                    revivedCharacter = Character.Controlled;
                }
                else
                {
                    revivedCharacter = FindMatchingCharacter(args);
                }

                if (revivedCharacter == null)
                {
                    return;
                }

                revivedCharacter.Revive(false);
                if (GameMain.Server != null)
                {
                    foreach (Client c in GameMain.Server.ConnectedClients)
                    {
                        if (c.Character != revivedCharacter)
                        {
                            continue;
                        }

                        //clients stop controlling the character when it dies, force control back
                        GameMain.Server.SetClientCharacter(c, revivedCharacter);
                        break;
                    }
                }
            }));

            commands.Add(new Command("freeze", "", (string[] args) =>
            {
                if (Character.Controlled != null)
                {
                    Character.Controlled.AnimController.Frozen = !Character.Controlled.AnimController.Frozen;
                }
            }));

            commands.Add(new Command("freecamera|freecam", "freecam: Detach the camera from the controlled character.", (string[] args) =>
            {
                Character.Controlled = null;
                GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
            }));

            commands.Add(new Command("water|editwater", "water/editwater: Toggle water editing. Allows adding water into rooms by holding the left mouse button and removing it by holding the right mouse button.", (string[] args) =>
            {
                if (GameMain.Client == null)
                {
                    Hull.EditWater = !Hull.EditWater;
                    NewMessage(Hull.EditWater ? "Water editing on" : "Water editing off", Color.White);
                }
            }));

            commands.Add(new Command("fire|editfire", "fire/editfire: Allows putting up fires by left clicking.", (string[] args) =>
            {
                if (GameMain.Client == null)
                {
                    Hull.EditFire = !Hull.EditFire;
                    NewMessage(Hull.EditFire ? "Fire spawning on" : "Fire spawning off", Color.White);
                }
            }));

            commands.Add(new Command("explosion", "explosion [range] [force] [damage] [structuredamage]: Creates an explosion at the position of the cursor.", (string[] args) =>
            {
                Vector2 explosionPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                float range          = 500, force = 10, damage = 50, structureDamage = 10;
                if (args.Length > 0)
                {
                    float.TryParse(args[0], out range);
                }
                if (args.Length > 1)
                {
                    float.TryParse(args[1], out force);
                }
                if (args.Length > 2)
                {
                    float.TryParse(args[2], out damage);
                }
                if (args.Length > 3)
                {
                    float.TryParse(args[3], out structureDamage);
                }
                new Explosion(range, force, damage, structureDamage).Explode(explosionPos);
            }));

            commands.Add(new Command("fixitems", "fixitems: Repairs all items and restores them to full condition.", (string[] args) =>
            {
                foreach (Item it in Item.ItemList)
                {
                    it.Condition = it.Prefab.Health;
                }
            }));

            commands.Add(new Command("fixhulls|fixwalls", "fixwalls/fixhulls: Fixes all walls.", (string[] args) =>
            {
                foreach (Structure w in Structure.WallList)
                {
                    for (int i = 0; i < w.SectionCount; i++)
                    {
                        w.AddDamage(i, -100000.0f);
                    }
                }
            }));

            commands.Add(new Command("power", "power [temperature]: Immediately sets the temperature of the nuclear reactor to the specified value.", (string[] args) =>
            {
                Item reactorItem = Item.ItemList.Find(i => i.GetComponent <Reactor>() != null);
                if (reactorItem == null)
                {
                    return;
                }

                float power = 5000.0f;
                if (args.Length > 0)
                {
                    float.TryParse(args[0], out power);
                }

                var reactor          = reactorItem.GetComponent <Reactor>();
                reactor.ShutDownTemp = power == 0 ? 0 : 7000.0f;
                reactor.AutoTemp     = true;
                reactor.Temperature  = power;

                if (GameMain.Server != null)
                {
                    reactorItem.CreateServerEvent(reactor);
                }
            }));

            commands.Add(new Command("oxygen|air", "oxygen/air: Replenishes the oxygen levels in every room to 100%.", (string[] args) =>
            {
                foreach (Hull hull in Hull.hullList)
                {
                    hull.OxygenPercentage = 100.0f;
                }
            }));

            commands.Add(new Command("killmonsters", "killmonsters: Immediately kills all AI-controlled enemies in the level.", (string[] args) =>
            {
                foreach (Character c in Character.CharacterList)
                {
                    if (!(c.AIController is EnemyAIController))
                    {
                        continue;
                    }
                    c.AddDamage(CauseOfDeath.Damage, 10000.0f, null);
                }
            }));

            commands.Add(new Command("netstats", "netstats: Toggles the visibility of the network statistics UI.", (string[] args) =>
            {
                if (GameMain.Server == null)
                {
                    return;
                }
                GameMain.Server.ShowNetStats = !GameMain.Server.ShowNetStats;
            }));

            commands.Add(new Command("setclientcharacter", "setclientcharacter [client name] ; [character name]: Gives the client control of the specified character.", (string[] args) =>
            {
                if (GameMain.Server == null)
                {
                    return;
                }

                int separatorIndex = Array.IndexOf(args, ";");

                if (separatorIndex == -1 || args.Length < 3)
                {
                    ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\"");
                    return;
                }

                string[] argsLeft  = args.Take(separatorIndex).ToArray();
                string[] argsRight = args.Skip(separatorIndex + 1).ToArray();

                string clientName = String.Join(" ", argsLeft);

                var client = GameMain.Server.ConnectedClients.Find(c => c.Name == clientName);
                if (client == null)
                {
                    ThrowError("Client \"" + clientName + "\" not found.");
                }

                var character = FindMatchingCharacter(argsRight, false);
                GameMain.Server.SetClientCharacter(client, character);
            }));

            commands.Add(new Command("campaigninfo|campaignstatus", "campaigninfo: Display information about the state of the currently active campaign.", (string[] args) =>
            {
                var campaign = GameMain.GameSession?.GameMode as CampaignMode;
                if (campaign == null)
                {
                    ThrowError("No campaign active!");
                    return;
                }

                campaign.LogState();
            }));

            commands.Add(new Command("campaigndestination|setcampaigndestination", "campaigndestination [index]: Set the location to head towards in the currently active campaign.", (string[] args) =>
            {
                var campaign = GameMain.GameSession?.GameMode as CampaignMode;
                if (campaign == null)
                {
                    ThrowError("No campaign active!");
                    return;
                }

                if (args.Length == 0)
                {
                    int i = 0;
                    foreach (LocationConnection connection in campaign.Map.CurrentLocation.Connections)
                    {
                        NewMessage("     " + i + ". " + connection.OtherLocation(campaign.Map.CurrentLocation).Name, Color.White);
                        i++;
                    }
                    ShowQuestionPrompt("Select a destination (0 - " + (campaign.Map.CurrentLocation.Connections.Count - 1) + "):", (string selectedDestination) =>
                    {
                        int destinationIndex = -1;
                        if (!int.TryParse(selectedDestination, out destinationIndex))
                        {
                            return;
                        }
                        if (destinationIndex < 0 || destinationIndex >= campaign.Map.CurrentLocation.Connections.Count)
                        {
                            NewMessage("Index out of bounds!", Color.Red);
                            return;
                        }
                        Location location = campaign.Map.CurrentLocation.Connections[destinationIndex].OtherLocation(campaign.Map.CurrentLocation);
                        campaign.Map.SelectLocation(location);
                        NewMessage(location.Name + " selected.", Color.White);
                    });
                }
                else
                {
                    int destinationIndex = -1;
                    if (!int.TryParse(args[0], out destinationIndex))
                    {
                        return;
                    }
                    if (destinationIndex < 0 || destinationIndex >= campaign.Map.CurrentLocation.Connections.Count)
                    {
                        NewMessage("Index out of bounds!", Color.Red);
                        return;
                    }
                    Location location = campaign.Map.CurrentLocation.Connections[destinationIndex].OtherLocation(campaign.Map.CurrentLocation);
                    campaign.Map.SelectLocation(location);
                    NewMessage(location.Name + " selected.", Color.White);
                }
            }));

#if DEBUG
            commands.Add(new Command("spamevents", "A debug command that immediately creates entity events for all items, characters and structures.", (string[] args) =>
            {
                foreach (Item item in Item.ItemList)
                {
                    for (int i = 0; i < item.components.Count; i++)
                    {
                        if (item.components[i] is IServerSerializable)
                        {
                            GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, i });
                        }
                        var itemContainer = item.GetComponent <ItemContainer>();
                        if (itemContainer != null)
                        {
                            GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.InventoryState });
                        }

                        GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.Status });

                        item.NeedsPositionUpdate = true;
                    }
                }

                foreach (Character c in Character.CharacterList)
                {
                    GameMain.Server.CreateEntityEvent(c, new object[] { NetEntityEvent.Type.Status });
                }

                foreach (Structure wall in Structure.WallList)
                {
                    GameMain.Server.CreateEntityEvent(wall);
                }
            }));
#endif
            InitProjectSpecific();

            commands.Sort((c1, c2) => c1.names[0].CompareTo(c2.names[0]));
        }
コード例 #9
0
        private void CheckDoorsInPath()
        {
            for (int i = 0; i < 2; i++)
            {
                Door door = null;
                bool shouldBeOpen = false;

                if (currentPath.Nodes.Count == 1)
                {
                    door = currentPath.Nodes.First().ConnectedDoor;
                    shouldBeOpen = door != null;
                }
                else
                {
                    WayPoint node = null;
                    WayPoint nextNode = null;
                    if (i == 0)
                    {
                        node = currentPath.CurrentNode;
                        nextNode = currentPath.NextNode;
                    }
                    else
                    {
                        node = currentPath.PrevNode;
                        nextNode = currentPath.CurrentNode;
                    }
                    if (node?.ConnectedDoor == null) continue;

                    if (nextNode == null)
                    {
                        //the node we're heading towards is the last one in the path, and at a door
                        //the door needs to be open for the character to reach the node
                        shouldBeOpen = true;
                    }
                    else
                    {
                        door = node.ConnectedGap.ConnectedDoor;
                        if (door.LinkedGap.IsHorizontal)
                        {
                            int currentDir = Math.Sign(nextNode.WorldPosition.X - door.Item.WorldPosition.X);
                            shouldBeOpen = (door.Item.WorldPosition.X - character.WorldPosition.X) * currentDir > -50.0f;
                        }
                        else
                        {
                            int currentDir = Math.Sign(nextNode.WorldPosition.Y - door.Item.WorldPosition.Y);
                            shouldBeOpen = (door.Item.WorldPosition.Y - character.WorldPosition.Y) * currentDir > -80.0f;
                        }
                    }
                }

                if (door == null) return;
                
                //toggle the door if it's the previous node and open, or if it's current node and closed
                if (door.IsOpen != shouldBeOpen)
                {
                    var buttons = door.Item.GetConnectedComponents<Controller>(true);

                    Controller closestButton = null;
                    float closestDist = 0.0f;

                    foreach (Controller controller in buttons)
                    {
                        float dist = Vector2.Distance(controller.Item.WorldPosition, character.WorldPosition);
                        if (dist > controller.Item.InteractDistance * 2.0f) continue;

                        if (dist < closestDist || closestButton == null)
                        {
                            closestButton = controller;
                            closestDist = dist;
                        }
                    }

                    if (closestButton != null)
                    {
                        if (!closestButton.HasRequiredItems(character, false) && shouldBeOpen)
                        {
                            currentPath.Unreachable = true;
                            return;
                        }

                        closestButton.Item.TryInteract(character, false, true, false);
                        buttonPressCooldown = ButtonPressInterval;
                        break;
                    }
                    else
                    {
                        if (!door.HasRequiredItems(character, false) && shouldBeOpen)
                        {
                            currentPath.Unreachable = true;
                            return;
                        }

                        door.Item.TryInteract(character, false, true, true);
                        buttonPressCooldown = ButtonPressInterval;
                        break;
                    }
                }
            }
        }
コード例 #10
0
        private void InitializeJobItem(Character character, WayPoint spawnPoint, XElement itemElement, Item parentItem = null)
        {
            string itemName = itemElement.GetAttributeString("name", "");

            ItemPrefab itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;

            if (itemPrefab == null)
            {
                DebugConsole.ThrowError("Tried to spawn \"" + Name + "\" with the item \"" + itemName + "\". Matching item prefab not found.");
                return;
            }

            Item item = new Item(itemPrefab, character.Position, null);

            if (GameMain.Server != null && Entity.Spawner != null)
            {
                Entity.Spawner.CreateNetworkEvent(item, false);
            }

            if (itemElement.GetAttributeBool("equip", false))
            {
                List <InvSlotType> allowedSlots = new List <InvSlotType>(item.AllowedSlots);
                allowedSlots.Remove(InvSlotType.Any);

                character.Inventory.TryPutItem(item, null, allowedSlots);
            }
            else
            {
                character.Inventory.TryPutItem(item, null, item.AllowedSlots);
            }

            if (item.Prefab.NameMatches("ID Card") && spawnPoint != null)
            {
                foreach (string s in spawnPoint.IdCardTags)
                {
                    item.AddTag(s);
                }
                item.AddTag("name:" + character.Name);
                item.AddTag("job:" + Name);
                if (!string.IsNullOrWhiteSpace(spawnPoint.IdCardDesc))
                {
                    item.Description = spawnPoint.IdCardDesc;
                }
            }

            item.AddTag("Starter_Item");

            foreach (WifiComponent wifiComponent in item.GetComponents <WifiComponent>())
            {
                wifiComponent.TeamID = character.TeamID;
            }

            if (parentItem != null)
            {
                parentItem.Combine(item);
            }

            foreach (XElement childItemElement in itemElement.Elements())
            {
                InitializeJobItem(character, spawnPoint, childItemElement, item);
            }
        }
コード例 #11
0
        private void FindSpawnPosition(bool affectSubImmediately)
        {
            if (disallowed)
            {
                return;
            }

            if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability)
            {
                spawnPos = null;
                Finished();
                return;
            }

            spawnPos = Vector2.Zero;
            var  availablePositions = GetAvailableSpawnPositions();
            var  chosenPosition     = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false);
            bool isSubOrWreck       = spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Wreck;

            if (affectSubImmediately && !isSubOrWreck)
            {
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    spawnPos = null;
                    Finished();
                    return;
                }
                Submarine refSub = GetReferenceSub();
                if (Submarine.MainSubs.Length == 2 && Submarine.MainSubs[1] != null)
                {
                    refSub = Submarine.MainSubs.GetRandom(Rand.RandSync.Unsynced);
                }
                float closestDist = float.PositiveInfinity;
                //find the closest spawnposition that isn't too close to any of the subs
                foreach (var position in availablePositions)
                {
                    Vector2 pos  = position.Position.ToVector2();
                    float   dist = Vector2.DistanceSquared(pos, refSub.WorldPosition);
                    foreach (Submarine sub in Submarine.Loaded)
                    {
                        if (sub.Info.Type != SubmarineType.Player)
                        {
                            continue;
                        }

                        float minDistToSub = GetMinDistanceToSub(sub);
                        if (dist < minDistToSub * minDistToSub)
                        {
                            continue;
                        }

                        if (closestDist == float.PositiveInfinity)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                            continue;
                        }

                        //chosen position behind the sub -> override with anything that's closer or to the right
                        if (chosenPosition.Position.X < refSub.WorldPosition.X)
                        {
                            if (dist < closestDist || pos.X > refSub.WorldPosition.X)
                            {
                                closestDist    = dist;
                                chosenPosition = position;
                            }
                        }
                        //chosen position ahead of the sub -> only override with a position that's also ahead
                        else if (chosenPosition.Position.X > refSub.WorldPosition.X)
                        {
                            if (dist < closestDist && pos.X > refSub.WorldPosition.X)
                            {
                                closestDist    = dist;
                                chosenPosition = position;
                            }
                        }
                    }
                }
                //only found a spawnpos that's very far from the sub, pick one that's closer
                //and wait for the sub to move further before spawning
                if (closestDist > 15000.0f * 15000.0f)
                {
                    foreach (var position in availablePositions)
                    {
                        float dist = Vector2.DistanceSquared(position.Position.ToVector2(), refSub.WorldPosition);
                        if (dist < closestDist)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                        }
                    }
                }
            }
            else
            {
                if (!isSubOrWreck)
                {
                    float minDistance = 20000;
                    var   refSub      = GetReferenceSub();
                    availablePositions.RemoveAll(p => Vector2.DistanceSquared(refSub.WorldPosition, p.Position.ToVector2()) < minDistance * minDistance);
                    if (Submarine.MainSubs.Length > 1)
                    {
                        for (int i = 1; i < Submarine.MainSubs.Length; i++)
                        {
                            availablePositions.RemoveAll(p => Vector2.DistanceSquared(Submarine.MainSubs[i].WorldPosition, p.Position.ToVector2()) < minDistance * minDistance);
                        }
                    }
                }
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    spawnPos = null;
                    Finished();
                    return;
                }
                chosenPosition = availablePositions.GetRandom();
            }
            if (chosenPosition.IsValid)
            {
                spawnPos = chosenPosition.Position.ToVector2();
                if (chosenPosition.Submarine != null || chosenPosition.Ruin != null)
                {
                    var spawnPoint = WayPoint.GetRandom(SpawnType.Enemy, sub: chosenPosition.Submarine, ruin: chosenPosition.Ruin, useSyncedRand: false);
                    if (spawnPoint != null)
                    {
                        System.Diagnostics.Debug.Assert(spawnPoint.Submarine == chosenPosition.Submarine);
                        System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin);
                        spawnPos = spawnPoint.WorldPosition;
                    }
                }
                else if ((chosenPosition.PositionType == Level.PositionType.MainPath || chosenPosition.PositionType == Level.PositionType.SidePath) &&
                         offset > 0)
                {
                    Vector2 dir;
                    var     waypoints       = WayPoint.WayPointList.FindAll(wp => wp.Submarine == null);
                    var     nearestWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, spawnPos.Value)).FirstOrDefault();
                    if (nearestWaypoint != null)
                    {
                        int currentIndex = waypoints.IndexOf(nearestWaypoint);
                        var nextWaypoint = waypoints[Math.Min(currentIndex + 20, waypoints.Count - 1)];
                        dir = Vector2.Normalize(nextWaypoint.WorldPosition - nearestWaypoint.WorldPosition);
                        // Ensure that the spawn position is not offset to the left.
                        if (dir.X < 0)
                        {
                            dir.X = 0;
                        }
                    }
                    else
                    {
                        dir = new Vector2(1, Rand.Range(-1, 1));
                    }
                    Vector2 targetPos      = spawnPos.Value + dir * offset;
                    var     targetWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, targetPos)).FirstOrDefault();
                    if (targetWaypoint != null)
                    {
                        spawnPos = targetWaypoint.WorldPosition;
                    }
                }
                spawnPending = true;
            }
        }
コード例 #12
0
        private void InitEscort()
        {
            characters.Clear();
            characterItems.Clear();

            WayPoint explicitStayInHullPos = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);

            Rand.RandSync randSync = Rand.RandSync.Server;

            if (terroristChance > 0f)
            {
                // in terrorist missions, reroll characters each retry to avoid confusion as to who the terrorists are
                randSync = Rand.RandSync.Unsynced;
            }

            //if any of the escortees have a job defined, try to use a spawnpoint designated for that job
            foreach (XElement element in characterConfig.Elements())
            {
                var humanPrefab = GetHumanPrefabFromElement(element);
                if (humanPrefab == null || string.IsNullOrEmpty(humanPrefab.Job) || humanPrefab.Job.Equals("any", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var jobPrefab = humanPrefab.GetJobPrefab();
                if (jobPrefab != null)
                {
                    var jobSpecificSpawnPos = WayPoint.GetRandom(SpawnType.Human, jobPrefab, Submarine.MainSub);
                    if (jobSpecificSpawnPos != null)
                    {
                        explicitStayInHullPos = jobSpecificSpawnPos;
                        break;
                    }
                }
            }

            foreach (XElement element in characterConfig.Elements())
            {
                int count = CalculateScalingEscortedCharacterCount(inMission: true);
                for (int i = 0; i < count; i++)
                {
                    Character spawnedCharacter = CreateHuman(GetHumanPrefabFromElement(element), characters, characterItems, Submarine.MainSub, CharacterTeamType.FriendlyNPC, explicitStayInHullPos, humanPrefabRandSync: randSync);
                    if (spawnedCharacter.AIController is HumanAIController humanAI)
                    {
                        humanAI.InitMentalStateManager();
                    }
                }
            }

            if (terroristChance > 0f)
            {
                int terroristCount = (int)Math.Ceiling(terroristChance * Rand.Range(0.8f, 1.2f) * characters.Count);
                terroristCount = Math.Clamp(terroristCount, 1, characters.Count);

                terroristCharacters.Clear();
                characters.GetRange(0, terroristCount).ForEach(c => terroristCharacters.Add(c));

                terroristDistanceSquared = Vector2.DistanceSquared(Level.Loaded.StartPosition, Level.Loaded.EndPosition) * Rand.Range(0.35f, 0.65f);

#if DEBUG
                DebugConsole.AddWarning("Terrorists will trigger at range  " + Math.Sqrt(terroristDistanceSquared));
                foreach (Character character in terroristCharacters)
                {
                    DebugConsole.AddWarning(character.Name + " is a terrorist.");
                }
#endif
            }
        }
コード例 #13
0
ファイル: CargoManager.cs プロジェクト: juanjp600/Barotrauma
        public static void CreateItems(List <PurchasedItem> itemsToSpawn)
        {
            WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub);

            if (wp == null)
            {
                DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!");
                return;
            }

            Hull cargoRoom = Hull.FindHull(wp.WorldPosition);

            if (cargoRoom == null)
            {
                DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!");
                return;
            }

            Dictionary <ItemContainer, int> availableContainers = new Dictionary <ItemContainer, int>();
            ItemPrefab containerPrefab = null;

            foreach (PurchasedItem pi in itemsToSpawn)
            {
                Vector2 position = new Vector2(
                    Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20),
                    cargoRoom.Rect.Y - cargoRoom.Rect.Height + pi.ItemPrefab.Size.Y / 2);

                ItemContainer itemContainer = null;
                if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier))
                {
                    itemContainer = availableContainers.Keys.ToList().Find(ac =>
                                                                           ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                           ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()));

                    if (itemContainer == null)
                    {
                        containerPrefab = MapEntityPrefab.List.Find(ep =>
                                                                    ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                    (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()))) as ItemPrefab;

                        if (containerPrefab == null)
                        {
                            DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + containerPrefab.Name + "\"!");
                            continue;
                        }

                        Item containerItem = new Item(containerPrefab, position, wp.Submarine);
                        itemContainer = containerItem.GetComponent <ItemContainer>();
                        if (itemContainer == null)
                        {
                            DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!");
                            continue;
                        }
                        availableContainers.Add(itemContainer, itemContainer.Capacity);
#if SERVER
                        if (GameMain.Server != null)
                        {
                            Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                        }
#endif
                    }
                }
                for (int i = 0; i < pi.Quantity; i++)
                {
                    if (itemContainer == null)
                    {
                        //no container, place at the waypoint
#if SERVER
                        if (GameMain.Server != null)
                        {
                            Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine);
                        }
                        else
                        {
#endif
                        new Item(pi.ItemPrefab, position, wp.Submarine);
#if SERVER
                    }
#endif
                        continue;
                    }
                    //if the intial container has been removed due to it running out of space, add a new container
                    //of the same type and begin filling it
                    if (!availableContainers.ContainsKey(itemContainer))
                    {
                        Item containerItemOverFlow = new Item(containerPrefab, position, wp.Submarine);
                        itemContainer = containerItemOverFlow.GetComponent <ItemContainer>();
                        availableContainers.Add(itemContainer, itemContainer.Capacity);
#if SERVER
                        if (GameMain.Server != null)
                        {
                            Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                        }
#endif
                    }

                    //place in the container
#if SERVER
                    if (GameMain.Server != null)
                    {
                        Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory);
                    }
                    else
                    {
#endif
                    var item = new Item(pi.ItemPrefab, position, wp.Submarine);
                    itemContainer.Inventory.TryPutItem(item, null);
#if SERVER
                }
#endif

                    //reduce the number of available slots in the container
                    //if there is a container
                    if (availableContainers.ContainsKey(itemContainer))
                    {
                        availableContainers[itemContainer]--;
                    }
                    if (availableContainers.ContainsKey(itemContainer) && availableContainers[itemContainer] <= 0)
                    {
                        availableContainers.Remove(itemContainer);
                    }
                }
            }
            itemsToSpawn.Clear();
        }
コード例 #14
0
        private WayPoint FindClosest(int dir, bool horizontalSearch, Vector2 tolerance, Body ignoredBody = null, IEnumerable <WayPoint> ignored = null, Func <WayPoint, bool> filter = null)
        {
            if (dir != -1 && dir != 1)
            {
                return(null);
            }

            float    closestDist = 0.0f;
            WayPoint closest     = null;

            foreach (WayPoint wp in WayPointList)
            {
                if (wp.SpawnType != SpawnType.Path || wp == this)
                {
                    continue;
                }

                float xDiff = wp.Position.X - Position.X;
                float yDiff = wp.Position.Y - Position.Y;
                float xDist = Math.Abs(xDiff);
                float yDist = Math.Abs(yDiff);
                if (tolerance.X < xDist)
                {
                    continue;
                }
                if (tolerance.Y < yDist)
                {
                    continue;
                }

                float dist = 0.0f;
                float diff = 0.0f;
                if (horizontalSearch)
                {
                    diff = xDiff;
                    dist = xDist + yDist / 5.0f;
                }
                else
                {
                    diff = yDiff;
                    dist = yDist + xDist / 5.0f;
                    //prefer ladder waypoints when moving vertically
                    if (wp.Ladders != null)
                    {
                        dist *= 0.5f;
                    }
                }

                if (Math.Sign(diff) != dir)
                {
                    continue;
                }
                // Ignore if already linked
                if (linkedTo.Contains(wp))
                {
                    continue;
                }
                if (ignored != null && ignored.Contains(wp))
                {
                    continue;
                }
                if (filter != null && !filter(wp))
                {
                    continue;
                }

                if (closest == null || dist < closestDist)
                {
                    var body = Submarine.CheckVisibility(SimPosition, wp.SimPosition, ignoreLevel: true, ignoreSubs: true, ignoreSensors: false);
                    if (body != null && body != ignoredBody && !(body.UserData is Submarine))
                    {
                        if (body.UserData is Structure || body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall))
                        {
                            continue;
                        }
                    }

                    closestDist = dist;
                    closest     = wp;
                }
            }

            return(closest);
        }
コード例 #15
0
        public MainMenuScreen(GameMain game)
        {
            buttonsParent = new GUILayoutGroup(new RectTransform(new Vector2(0.15f, 0.5f), parent: Frame.RectTransform, anchor: Anchor.BottomLeft)
            {
                RelativeOffset = new Vector2(0, 0.1f),
                AbsoluteOffset = new Point(50, 0)
            })
            {
                Stretch         = true,
                RelativeSpacing = 0.02f
            };

            //debug button for quickly starting a new round
            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform, Anchor.TopCenter, Pivot.BottomCenter)
            {
                AbsoluteOffset = new Point(0, -40)
            },
                          "Quickstart (dev)", style: "GUIButtonLarge", color: Color.Red)
            {
                IgnoreLayoutGroups = true,
                OnClicked          = (tb, userdata) =>
                {
                    Submarine selectedSub = null;
                    string    subName     = GameMain.Config.QuickStartSubmarineName;
                    if (!string.IsNullOrEmpty(subName))
                    {
                        DebugConsole.NewMessage($"Loading the predefined quick start sub \"{subName}\"", Color.White);
                        selectedSub = Submarine.SavedSubmarines.FirstOrDefault(s =>
                                                                               s.Name.ToLower() == subName.ToLower());

                        if (selectedSub == null)
                        {
                            DebugConsole.NewMessage($"Cannot find a sub that matches the name \"{subName}\".", Color.Red);
                        }
                    }
                    if (selectedSub == null)
                    {
                        DebugConsole.NewMessage("Loading a random sub.", Color.White);
                        var subs = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.Shuttle) && !s.HasTag(SubmarineTag.HideInMenus));
                        selectedSub = subs.ElementAt(Rand.Int(subs.Count()));
                    }
                    var gamesession = new GameSession(
                        selectedSub,
                        "Data/Saves/test.xml",
                        GameModePreset.list.Find(gm => gm.Name == "SPSandbox"),
                        missionPrefab: null);
                    //(gamesession.GameMode as SinglePlayerCampaign).GenerateMap(ToolBox.RandomSeed(8));
                    gamesession.StartRound(ToolBox.RandomSeed(8));
                    GameMain.GameScreen.Select();

                    string[] jobIdentifiers = new string[] { "captain", "engineer", "mechanic" };
                    for (int i = 0; i < 3; i++)
                    {
                        var spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
                        if (spawnPoint == null)
                        {
                            DebugConsole.ThrowError("No spawnpoints found in the selected submarine. Quickstart failed.");
                            GameMain.MainMenuScreen.Select();
                            return(true);
                        }
                        var characterInfo = new CharacterInfo(
                            Character.HumanConfigFile,
                            jobPrefab: JobPrefab.List.Find(j => j.Identifier == jobIdentifiers[i]));
                        if (characterInfo.Job == null)
                        {
                            DebugConsole.ThrowError("Failed to find the job \"" + jobIdentifiers[i] + "\"!");
                        }

                        var newCharacter = Character.Create(Character.HumanConfigFile, spawnPoint.WorldPosition, ToolBox.RandomSeed(8), characterInfo);
                        newCharacter.GiveJobItems(spawnPoint);
                        gamesession.CrewManager.AddCharacter(newCharacter);
                        Character.Controlled = newCharacter;
                    }
                    return(true);
                }
            };

            var minButtonSize = new Point(120, 20);
            var maxButtonSize = new Point(240, 40);

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("TutorialButton"), style: "GUIButtonLarge")
            {
                UserData  = Tab.Tutorials,
                OnClicked = SelectTab,
                Enabled   = false
            };

            new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), buttonsParent.RectTransform), style: null); //spacing

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("NewGameButton"), style: "GUIButtonLarge")
            {
                UserData  = Tab.NewGame,
                OnClicked = SelectTab
            };
            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("LoadGameButton"), style: "GUIButtonLarge")
            {
                UserData  = Tab.LoadGame,
                OnClicked = SelectTab
            };

            new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), buttonsParent.RectTransform), style: null); //spacing

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("JoinServerButton"), style: "GUIButtonLarge")
            {
                OnClicked = JoinServerClicked
            };
            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("HostServerButton"), style: "GUIButtonLarge")
            {
                UserData  = Tab.HostServer,
                OnClicked = SelectTab
            };


            new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), buttonsParent.RectTransform), style: null); //spacing

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("SubEditorButton"), style: "GUIButtonLarge")
            {
                OnClicked = (btn, userdata) => { GameMain.SubEditorScreen.Select(); return(true); }
            };

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("CharacterEditorButton"), style: "GUIButtonLarge")
            {
                OnClicked = (btn, userdata) =>
                {
                    Submarine.MainSub = null;
                    GameMain.CharacterEditorScreen.Select();
                    return(true);
                }
            };

            if (Steam.SteamManager.USE_STEAM)
            {
                steamWorkshopButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("SteamWorkshopButton"), style: "GUIButtonLarge")
                {
                    Enabled   = false,
                    OnClicked = SteamWorkshopClicked
                };
            }

            new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), buttonsParent.RectTransform), style: null); //spacing

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("SettingsButton"), style: "GUIButtonLarge")
            {
                UserData  = Tab.Settings,
                OnClicked = SelectTab
            };
            new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("QuitButton"), style: "GUIButtonLarge")
            {
                OnClicked = QuitClicked
            };


            /* var buttons = GUI.CreateButtons(9, new Vector2(1, 0.04f), buttonsParent.RectTransform, anchor: Anchor.BottomLeft,
             *   minSize: minButtonSize, maxSize: maxButtonSize, relativeSpacing: 0.005f, extraSpacing: i => i % 2 == 0 ? 20 : 0);
             * buttons.ForEach(b => b.Color *= 0.8f);
             * SetupButtons(buttons);
             * buttons.ForEach(b => b.TextBlock.SetTextPos());*/

            var relativeSize = new Vector2(0.5f, 0.5f);
            var minSize      = new Point(600, 400);
            var maxSize      = new Point(900, 600);
            var anchor       = Anchor.Center;
            var pivot        = Pivot.Center;

            menuTabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length + 1];

            menuTabs[(int)Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize, Frame.RectTransform, anchor, pivot, minSize, maxSize));
            var paddedNewGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.NewGame].RectTransform, Anchor.Center), style: null);

            menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, Frame.RectTransform, anchor, pivot, minSize, maxSize));
            var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center), style: null);

            campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame)
            {
                LoadGame     = LoadGame,
                StartNewGame = StartGame
            };

            var hostServerScale = new Vector2(0.7f, 1.0f);

            menuTabs[(int)Tab.HostServer] = new GUIFrame(new RectTransform(
                                                             Vector2.Multiply(relativeSize, hostServerScale), Frame.RectTransform, anchor, pivot, minSize.Multiply(hostServerScale), maxSize.Multiply(hostServerScale)));

            CreateHostServerFields();

            //----------------------------------------------------------------------

            menuTabs[(int)Tab.Tutorials] = new GUIFrame(new RectTransform(relativeSize, Frame.RectTransform, anchor, pivot, minSize, maxSize));

            //PLACEHOLDER
            var tutorialList = new GUIListBox(
                new RectTransform(new Vector2(0.95f, 0.85f), menuTabs[(int)Tab.Tutorials].RectTransform, Anchor.TopCenter)
            {
                RelativeOffset = new Vector2(0.0f, 0.1f)
            },
                false, null, "");

            foreach (Tutorial tutorial in Tutorial.Tutorials)
            {
                var tutorialText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), tutorialList.Content.RectTransform), tutorial.Name, textAlignment: Alignment.Center, font: GUI.LargeFont)
                {
                    UserData = tutorial
                };
            }
            tutorialList.OnSelected += (component, obj) =>
            {
                TutorialMode.StartTutorial(obj as Tutorial);
                return(true);
            };

            UpdateTutorialList();

            this.game = game;
        }
コード例 #16
0
        public static void CreateItems(List <PurchasedItem> itemsToSpawn)
        {
            if (itemsToSpawn.Count == 0)
            {
                return;
            }

            WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub);

            if (wp == null)
            {
                DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!");
                return;
            }

            Hull cargoRoom = Hull.FindHull(wp.WorldPosition);

            if (cargoRoom == null)
            {
                DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!");
                return;
            }

#if CLIENT
            new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true));
#endif

            Dictionary <ItemContainer, int> availableContainers = new Dictionary <ItemContainer, int>();
            ItemPrefab containerPrefab = null;
            foreach (PurchasedItem pi in itemsToSpawn)
            {
                float floorPos = cargoRoom.Rect.Y - cargoRoom.Rect.Height;

                Vector2 position = new Vector2(
                    Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20),
                    floorPos);

                //check where the actual floor structure is in case the bottom of the hull extends below it
                if (Submarine.PickBody(
                        ConvertUnits.ToSimUnits(new Vector2(position.X, cargoRoom.Rect.Y - cargoRoom.Rect.Height / 2)),
                        ConvertUnits.ToSimUnits(position),
                        collisionCategory: Physics.CollisionWall) != null)
                {
                    float floorStructurePos = ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition.Y);
                    if (floorStructurePos > floorPos)
                    {
                        floorPos = floorStructurePos;
                    }
                }
                position.Y = floorPos + pi.ItemPrefab.Size.Y / 2;

                ItemContainer itemContainer = null;
                if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier))
                {
                    itemContainer = availableContainers.Keys.ToList().Find(ac =>
                                                                           ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                           ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()));

                    if (itemContainer == null)
                    {
                        containerPrefab = ItemPrefab.Prefabs.Find(ep =>
                                                                  ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                  (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant())));

                        if (containerPrefab == null)
                        {
                            DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + containerPrefab.Name + "\"!");
                            continue;
                        }

                        Item containerItem = new Item(containerPrefab, position, wp.Submarine);
                        itemContainer = containerItem.GetComponent <ItemContainer>();
                        if (itemContainer == null)
                        {
                            DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!");
                            continue;
                        }
                        availableContainers.Add(itemContainer, itemContainer.Capacity);
#if SERVER
                        if (GameMain.Server != null)
                        {
                            Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                        }
#endif
                    }
                }
                for (int i = 0; i < pi.Quantity; i++)
                {
                    if (itemContainer == null)
                    {
                        //no container, place at the waypoint
                        if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
                        {
                            Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine);
                        }
                        else
                        {
                            new Item(pi.ItemPrefab, position, wp.Submarine);
                        }
                        continue;
                    }
                    //if the intial container has been removed due to it running out of space, add a new container
                    //of the same type and begin filling it
                    if (!availableContainers.ContainsKey(itemContainer))
                    {
                        Item containerItemOverFlow = new Item(containerPrefab, position, wp.Submarine);
                        itemContainer = containerItemOverFlow.GetComponent <ItemContainer>();
                        availableContainers.Add(itemContainer, itemContainer.Capacity);
#if SERVER
                        if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
                        {
                            Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                        }
#endif
                    }

                    //place in the container
                    if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
                    {
                        Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory);
                    }
                    else
                    {
                        var item = new Item(pi.ItemPrefab, position, wp.Submarine);
                        itemContainer.Inventory.TryPutItem(item, null);
                    }

                    //reduce the number of available slots in the container
                    //if there is a container
                    if (availableContainers.ContainsKey(itemContainer))
                    {
                        availableContainers[itemContainer]--;
                    }
                    if (availableContainers.ContainsKey(itemContainer) && availableContainers[itemContainer] <= 0)
                    {
                        availableContainers.Remove(itemContainer);
                    }
                }
            }
            itemsToSpawn.Clear();
        }
コード例 #17
0
        public void InitRound()
        {
            characters.Clear();

            List <WayPoint> spawnWaypoints   = null;
            List <WayPoint> mainSubWaypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub).ToList();

            if (Level.IsLoadedOutpost)
            {
                spawnWaypoints = WayPoint.WayPointList.FindAll(wp =>
                                                               wp.SpawnType == SpawnType.Human &&
                                                               wp.Submarine == Level.Loaded.StartOutpost &&
                                                               wp.CurrentHull?.OutpostModuleTags != null &&
                                                               wp.CurrentHull.OutpostModuleTags.Contains("airlock"));
                while (spawnWaypoints.Count > characterInfos.Count)
                {
                    spawnWaypoints.RemoveAt(Rand.Int(spawnWaypoints.Count));
                }
                while (spawnWaypoints.Any() && spawnWaypoints.Count < characterInfos.Count)
                {
                    spawnWaypoints.Add(spawnWaypoints[Rand.Int(spawnWaypoints.Count)]);
                }
            }

            if (spawnWaypoints == null || !spawnWaypoints.Any())
            {
                spawnWaypoints = mainSubWaypoints;
            }

            System.Diagnostics.Debug.Assert(spawnWaypoints.Count == mainSubWaypoints.Count);

            for (int i = 0; i < spawnWaypoints.Count; i++)
            {
                var info = characterInfos[i];
                info.TeamID = CharacterTeamType.Team1;
                Character character = Character.Create(info, spawnWaypoints[i].WorldPosition, info.Name);
                if (character.Info != null)
                {
                    if (!character.Info.StartItemsGiven && character.Info.InventoryData != null)
                    {
                        DebugConsole.AddWarning($"Error when initializing a round: character \"{character.Name}\" has not been given their initial items but has saved inventory data. Using the saved inventory data instead of giving the character new items.");
                    }
                    if (character.Info.InventoryData != null)
                    {
                        character.SpawnInventoryItems(character.Inventory, character.Info.InventoryData);
                    }
                    else if (!character.Info.StartItemsGiven)
                    {
                        character.GiveJobItems(mainSubWaypoints[i]);
                    }
                    if (character.Info.HealthData != null)
                    {
                        character.Info.ApplyHealthData(character, character.Info.HealthData);
                    }
                    character.GiveIdCardTags(spawnWaypoints[i]);
                    character.Info.StartItemsGiven = true;
                }

                AddCharacter(character);
#if CLIENT
                if (IsSinglePlayer && (Character.Controlled == null || character.Info.LastControlled))
                {
                    Character.Controlled = character;
                }
#endif
            }

            //longer delay in multiplayer to prevent the server from triggering NPC conversations while the players are still loading the round
            conversationTimer = IsSinglePlayer ? Rand.Range(5.0f, 10.0f) : Rand.Range(45.0f, 60.0f);
        }
コード例 #18
0
        public static void CreateItems(List <PurchasedItem> itemsToSpawn)
        {
            if (itemsToSpawn.Count == 0)
            {
                return;
            }

            WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub);

            if (wp == null)
            {
                DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!");
                return;
            }

            Hull cargoRoom = Hull.FindHull(wp.WorldPosition);

            if (cargoRoom == null)
            {
                DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!");
                return;
            }

#if CLIENT
            new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true), new string[0], type: GUIMessageBox.Type.InGame, iconStyle: "StoreShoppingCrateIcon");
#else
            foreach (Client client in GameMain.Server.ConnectedClients)
            {
                ChatMessage msg = ChatMessage.Create("",
                                                     TextManager.ContainsTag(cargoRoom.RoomName) ? $"CargoSpawnNotification~[roomname]=§{cargoRoom.RoomName}" : $"CargoSpawnNotification~[roomname]={cargoRoom.RoomName}",
                                                     ChatMessageType.ServerMessageBoxInGame, null);
                msg.IconStyle = "StoreShoppingCrateIcon";
                GameMain.Server.SendDirectChatMessage(msg, client);
            }
#endif

            List <ItemContainer> availableContainers = new List <ItemContainer>();
            ItemPrefab           containerPrefab     = null;
            foreach (PurchasedItem pi in itemsToSpawn)
            {
                Vector2 position = GetCargoPos(cargoRoom, pi.ItemPrefab);

                for (int i = 0; i < pi.Quantity; i++)
                {
                    ItemContainer itemContainer = null;
                    if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier))
                    {
                        itemContainer = availableContainers.Find(ac =>
                                                                 ac.Inventory.CanBePut(pi.ItemPrefab) &&
                                                                 (ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                  ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant())));

                        if (itemContainer == null)
                        {
                            containerPrefab = ItemPrefab.Prefabs.Find(ep =>
                                                                      ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier ||
                                                                      (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant())));

                            if (containerPrefab == null)
                            {
                                DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + pi.ItemPrefab.CargoContainerIdentifier + "\"!");
                                continue;
                            }

                            Item containerItem = new Item(containerPrefab, position, wp.Submarine);
                            itemContainer = containerItem.GetComponent <ItemContainer>();
                            if (itemContainer == null)
                            {
                                DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!");
                                continue;
                            }
                            availableContainers.Add(itemContainer);
    #if SERVER
                            if (GameMain.Server != null)
                            {
                                Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
                            }
    #endif
                        }
                    }

                    if (itemContainer == null)
                    {
                        //no container, place at the waypoint
                        if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
                        {
                            Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine, onSpawned: itemSpawned);
                        }
                        else
                        {
                            var item = new Item(pi.ItemPrefab, position, wp.Submarine);
                            itemSpawned(item);
                        }
                        continue;
                    }

                    //place in the container
                    if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
                    {
                        Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory, onSpawned: itemSpawned);
                    }
                    else
                    {
                        var item = new Item(pi.ItemPrefab, position, wp.Submarine);
                        itemContainer.Inventory.TryPutItem(item, null);
                        itemSpawned(item);
                    }
コード例 #19
0
        private void CheckDoorsInPath()
        {
            for (int i = 0; i < 2; i++)
            {
                WayPoint currentWaypoint = null;
                WayPoint nextWaypoint    = null;
                Door     door            = null;
                bool     shouldBeOpen    = false;

                if (currentPath.Nodes.Count == 1)
                {
                    door         = currentPath.Nodes.First().ConnectedDoor;
                    shouldBeOpen = door != null;
                }
                else
                {
                    if (i == 0)
                    {
                        currentWaypoint = currentPath.CurrentNode;
                        nextWaypoint    = currentPath.NextNode;
                    }
                    else
                    {
                        currentWaypoint = currentPath.PrevNode;
                        nextWaypoint    = currentPath.CurrentNode;
                    }
                    if (currentWaypoint?.ConnectedDoor == null)
                    {
                        continue;
                    }

                    if (nextWaypoint == null)
                    {
                        //the node we're heading towards is the last one in the path, and at a door
                        //the door needs to be open for the character to reach the node
                        if (currentWaypoint.ConnectedDoor.LinkedGap != null && currentWaypoint.ConnectedDoor.LinkedGap.IsRoomToRoom)
                        {
                            shouldBeOpen = true;
                            door         = currentWaypoint.ConnectedDoor;
                        }
                    }
                    else
                    {
                        door = currentWaypoint.ConnectedGap.ConnectedDoor;
                        if (door.LinkedGap.IsHorizontal)
                        {
                            int dir = Math.Sign(nextWaypoint.WorldPosition.X - door.Item.WorldPosition.X);
                            shouldBeOpen = (door.Item.WorldPosition.X - character.WorldPosition.X) * dir > -50.0f;
                        }
                        else
                        {
                            int dir = Math.Sign(nextWaypoint.WorldPosition.Y - door.Item.WorldPosition.Y);
                            shouldBeOpen = (door.Item.WorldPosition.Y - character.WorldPosition.Y) * dir > -80.0f;
                        }
                    }
                }

                if (door == null)
                {
                    return;
                }

                //toggle the door if it's the previous node and open, or if it's current node and closed
                if (door.IsOpen != shouldBeOpen)
                {
                    Controller closestButton = null;
                    float      closestDist   = 0;
                    bool       canAccess     = CanAccessDoor(door, button =>
                    {
                        if (currentWaypoint == null)
                        {
                            return(true);
                        }
                        // Check that the button is on the right side of the door.
                        if (door.LinkedGap.IsHorizontal)
                        {
                            int dir = Math.Sign(nextWaypoint.WorldPosition.X - door.Item.WorldPosition.X);
                            if (button.Item.WorldPosition.X * dir > door.Item.WorldPosition.X * dir)
                            {
                                return(false);
                            }
                        }
                        else
                        {
                            int dir = Math.Sign(nextWaypoint.WorldPosition.Y - door.Item.WorldPosition.Y);
                            if (button.Item.WorldPosition.Y * dir > door.Item.WorldPosition.Y * dir)
                            {
                                return(false);
                            }
                        }
                        float distance = Vector2.DistanceSquared(button.Item.WorldPosition, character.WorldPosition);
                        if (closestButton == null || distance < closestDist)
                        {
                            closestButton = button;
                            closestDist   = distance;
                        }
                        return(true);
                    });
                    if (canAccess)
                    {
                        if (door.HasIntegratedButtons)
                        {
                            door.Item.TryInteract(character, false, true);
                            buttonPressCooldown = ButtonPressInterval;
                            break;
                        }
                        else if (closestButton != null)
                        {
                            if (Vector2.DistanceSquared(closestButton.Item.WorldPosition, character.WorldPosition) < MathUtils.Pow(closestButton.Item.InteractDistance * 2, 2))
                            {
                                closestButton.Item.TryInteract(character, false, true);
                                buttonPressCooldown = ButtonPressInterval;
                                break;
                            }
                            else
                            {
                                // Can't reach the button closest to the character.
                                // It's possible that we could reach another buttons.
                                // If this becomes an issue, we could go through them here and check if any of them are reachable
                                // (would have to cache a collection of buttons instead of a single reference in the CanAccess filter method above)
                                var body = Submarine.PickBody(character.SimPosition, character.GetRelativeSimPosition(closestButton.Item), collisionCategory: Physics.CollisionWall | Physics.CollisionLevel);
                                if (body != null)
                                {
                                    if (body.UserData is Item item)
                                    {
                                        var d = item.GetComponent <Door>();
                                        if (d == null || d.IsOpen)
                                        {
                                            return;
                                        }
                                    }
                                    // The button is on the wrong side of the door or a wall
                                    currentPath.Unreachable = true;
                                }
                                return;
                            }
                        }
                    }
                    else if (shouldBeOpen)
                    {
#if DEBUG
                        DebugConsole.NewMessage($"{character.Name}: Pathfinding error: Cannot access the door", Color.Yellow);
#endif
                        currentPath.Unreachable = true;
                        return;
                    }
                }
            }
        }
コード例 #20
0
        private void CheckDoorsInPath()
        {
            for (int i = 0; i < 2; i++)
            {
                WayPoint currentWaypoint = null;
                WayPoint nextWaypoint    = null;
                Door     door            = null;
                bool     shouldBeOpen    = false;

                if (currentPath.Nodes.Count == 1)
                {
                    door         = currentPath.Nodes.First().ConnectedDoor;
                    shouldBeOpen = door != null;
                }
                else
                {
                    if (i == 0)
                    {
                        currentWaypoint = currentPath.CurrentNode;
                        nextWaypoint    = currentPath.NextNode;
                    }
                    else
                    {
                        currentWaypoint = currentPath.PrevNode;
                        nextWaypoint    = currentPath.CurrentNode;
                    }
                    if (currentWaypoint?.ConnectedDoor == null)
                    {
                        continue;
                    }

                    if (nextWaypoint == null)
                    {
                        //the node we're heading towards is the last one in the path, and at a door
                        //the door needs to be open for the character to reach the node
                        shouldBeOpen = true;
                    }
                    else
                    {
                        door = currentWaypoint.ConnectedGap.ConnectedDoor;
                        if (door.LinkedGap.IsHorizontal)
                        {
                            int currentDir = Math.Sign(nextWaypoint.WorldPosition.X - door.Item.WorldPosition.X);
                            shouldBeOpen = (door.Item.WorldPosition.X - character.WorldPosition.X) * currentDir > -50.0f;
                        }
                        else
                        {
                            int currentDir = Math.Sign(nextWaypoint.WorldPosition.Y - door.Item.WorldPosition.Y);
                            shouldBeOpen = (door.Item.WorldPosition.Y - character.WorldPosition.Y) * currentDir > -80.0f;
                        }
                    }
                }

                if (door == null)
                {
                    return;
                }

                //toggle the door if it's the previous node and open, or if it's current node and closed
                if (door.IsOpen != shouldBeOpen)
                {
                    Controller closestButton = null;
                    float      closestDist   = 0;
                    bool       canAccess     = CanAccessDoor(door, button =>
                    {
                        if (currentWaypoint == null)
                        {
                            return(true);
                        }
                        float distance = Vector2.DistanceSquared(button.Item.WorldPosition, door.Item.WorldPosition);
                        if (closestButton == null || distance < closestDist)
                        {
                            closestButton = button;
                            closestDist   = distance;
                        }
                        return(true);
                    });
                    if (canAccess)
                    {
                        if (door.HasIntegratedButtons)
                        {
                            door.Item.TryInteract(character, false, true);
                            buttonPressCooldown = ButtonPressInterval;
                            break;
                        }
                        else if (closestButton != null)
                        {
                            if (Vector2.DistanceSquared(closestButton.Item.WorldPosition, character.WorldPosition) < MathUtils.Pow(closestButton.Item.InteractDistance * 2, 2))
                            {
                                closestButton.Item.TryInteract(character, false, true);
                                buttonPressCooldown = ButtonPressInterval;
                                break;
                            }
                            else
                            {
                                // Can't reach the button closest to the door.
                                // It's possible that we could reach another buttons.
                                // If this becomes an issue, we could go through them here and check if any of them are reachable
                                // (would have to cache a collection of buttons instead of a single reference in the CanAccess filter method above)
                                //currentPath.Unreachable = true;
                                return;
                            }
                        }
                    }
                    else if (shouldBeOpen)
                    {
                        currentPath.Unreachable = true;
                        return;
                    }
                }
            }
        }
コード例 #21
0
        void WaypointLinksChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (Submarine.Unloading)
            {
                return;
            }

            var waypoints = sender as IEnumerable <MapEntity>;

            foreach (MapEntity me in waypoints)
            {
                WayPoint wp = me as WayPoint;
                if (me == null)
                {
                    continue;
                }

                var node = nodes.Find(n => n.Waypoint == wp);
                if (node == null)
                {
                    return;
                }

                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
                {
                    for (int i = node.connections.Count - 1; i >= 0; i--)
                    {
                        //remove connection if the waypoint isn't connected anymore
                        if (wp.linkedTo.FirstOrDefault(l => l == node.connections[i].Waypoint) == null)
                        {
                            node.connections.RemoveAt(i);
                            node.distances.RemoveAt(i);
                        }
                    }
                }
                else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    for (int i = 0; i < wp.linkedTo.Count; i++)
                    {
                        if (!(wp.linkedTo[i] is WayPoint connected))
                        {
                            continue;
                        }

                        //already connected, continue
                        if (node.connections.Any(n => n.Waypoint == connected))
                        {
                            continue;
                        }

                        var matchingNode = nodes.Find(n => n.Waypoint == connected);
                        if (matchingNode == null)
                        {
#if DEBUG
                            DebugConsole.ThrowError("Waypoint connections were changed, no matching path node found in PathFinder");
#endif
                            return;
                        }

                        node.connections.Add(matchingNode);
                        node.distances.Add(Vector2.Distance(node.Position, matchingNode.Position));
                    }
                }
            }
        }
コード例 #22
0
ファイル: MonsterEvent.cs プロジェクト: yweber/Barotrauma
        private void FindSpawnPosition(bool affectSubImmediately)
        {
            if (disallowed)
            {
                return;
            }

            spawnPos = Vector2.Zero;
            var availablePositions = GetAvailableSpawnPositions();
            var chosenPosition     = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false);
            var removedPositions   = new List <Level.InterestingPosition>();

            foreach (var position in availablePositions)
            {
                if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability)
                {
                    removedPositions.Add(position);
                    if (prefab.AllowOnlyOnce)
                    {
                        Level.Loaded.UsedPositions.Add(position);
                    }
                }
            }
            removedPositions.ForEach(p => availablePositions.Remove(p));
            bool isSubOrWreck = spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Wreck;

            if (affectSubImmediately && !isSubOrWreck)
            {
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    Finished();
                    return;
                }
                float closestDist = float.PositiveInfinity;
                //find the closest spawnposition that isn't too close to any of the subs
                foreach (var position in availablePositions)
                {
                    Vector2 pos  = position.Position.ToVector2();
                    float   dist = Vector2.DistanceSquared(pos, Submarine.MainSub.WorldPosition);
                    foreach (Submarine sub in Submarine.Loaded)
                    {
                        if (sub.Info.Type != SubmarineInfo.SubmarineType.Player)
                        {
                            continue;
                        }
                        float minDistToSub = GetMinDistanceToSub(sub);
                        if (dist > minDistToSub * minDistToSub && dist < closestDist)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                        }
                    }
                }
                //only found a spawnpos that's very far from the sub, pick one that's closer
                //and wait for the sub to move further before spawning
                if (closestDist > 15000.0f * 15000.0f)
                {
                    foreach (var position in availablePositions)
                    {
                        float dist = Vector2.DistanceSquared(position.Position.ToVector2(), Submarine.MainSub.WorldPosition);
                        if (dist < closestDist)
                        {
                            closestDist    = dist;
                            chosenPosition = position;
                        }
                    }
                }
            }
            else
            {
                if (!isSubOrWreck)
                {
                    float minDistance = 20000;
                    availablePositions.RemoveAll(p => Vector2.DistanceSquared(Submarine.MainSub.WorldPosition, p.Position.ToVector2()) < minDistance * minDistance);
                }
                if (availablePositions.None())
                {
                    //no suitable position found, disable the event
                    Finished();
                    return;
                }
                chosenPosition = availablePositions.GetRandom();
            }
            if (chosenPosition.IsValid)
            {
                spawnPos = chosenPosition.Position.ToVector2();
                if (chosenPosition.Submarine != null || chosenPosition.Ruin != null)
                {
                    var spawnPoint = WayPoint.GetRandom(SpawnType.Enemy, sub: chosenPosition.Submarine, ruin: chosenPosition.Ruin, useSyncedRand: false);
                    if (spawnPoint != null)
                    {
                        System.Diagnostics.Debug.Assert(spawnPoint.Submarine == chosenPosition.Submarine);
                        System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin);
                        spawnPos = spawnPoint.WorldPosition;
                    }
                }
                spawnPending = true;
                if (prefab.AllowOnlyOnce)
                {
                    Level.Loaded.UsedPositions.Add(chosenPosition);
                }
            }
        }
コード例 #23
0
ファイル: WayPoint.cs プロジェクト: jamiebidelia/Barotrauma
        private WayPoint FindClosest(int dir, bool horizontalSearch, Vector2 tolerance, Body ignoredBody = null)
        {
            if (dir != -1 && dir != 1)
            {
                return(null);
            }

            float    closestDist = 0.0f;
            WayPoint closest     = null;


            foreach (WayPoint wp in WayPointList)
            {
                if (wp.SpawnType != SpawnType.Path || wp == this)
                {
                    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)
                {
                    var body = Submarine.CheckVisibility(SimPosition, wp.SimPosition, true, true, false);
                    if (body != null && body != ignoredBody && !(body.UserData is Submarine))
                    {
                        if (body.UserData is Structure || body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall))
                        {
                            continue;
                        }
                    }

                    closestDist = dist;
                    closest     = wp;
                }
            }

            return(closest);
        }
コード例 #24
0
        public void Generate(bool mirror = false)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();

            if (loaded != null)
            {
                loaded.Unload();
            }
            loaded = this;

            positionsOfInterest = new List <InterestingPosition>();

            Voronoi voronoi = new Voronoi(1.0);

            List <Vector2> sites = new List <Vector2>();

            bodies = new List <Body>();

            Rand.SetSyncedSeed(ToolBox.StringToInt(seed));

#if CLIENT
            renderer = new LevelRenderer(this);

            backgroundColor = generationParams.BackgroundColor;
            float avgValue = (backgroundColor.R + backgroundColor.G + backgroundColor.G) / 3;
            GameMain.LightManager.AmbientLight = new Color(backgroundColor * (10.0f / avgValue), 1.0f);
#endif

            float minWidth = 6500.0f;
            if (Submarine.MainSub != null)
            {
                Rectangle dockedSubBorders = Submarine.MainSub.GetDockedBorders();
                minWidth = Math.Max(minWidth, Math.Max(dockedSubBorders.Width, dockedSubBorders.Height));
            }

            startPosition = new Vector2(
                Rand.Range(minWidth, minWidth * 2, Rand.RandSync.Server),
                Rand.Range(borders.Height * 0.5f, borders.Height - minWidth * 2, Rand.RandSync.Server));

            endPosition = new Vector2(
                borders.Width - Rand.Range(minWidth, minWidth * 2, Rand.RandSync.Server),
                Rand.Range(borders.Height * 0.5f, borders.Height - minWidth * 2, Rand.RandSync.Server));

            List <Vector2> pathNodes   = new List <Vector2>();
            Rectangle      pathBorders = borders;// new Rectangle((int)minWidth, (int)minWidth, borders.Width - (int)minWidth * 2, borders.Height - (int)minWidth);
            pathBorders.Inflate(-minWidth * 2, -minWidth * 2);

            pathNodes.Add(new Vector2(startPosition.X, borders.Height));

            Vector2 nodeInterval = generationParams.MainPathNodeIntervalRange;

            for (float x = startPosition.X + Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server);
                 x < endPosition.X - Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server);
                 x += Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server))
            {
                pathNodes.Add(new Vector2(x, Rand.Range(pathBorders.Y, pathBorders.Bottom, Rand.RandSync.Server)));
            }

            pathNodes.Add(new Vector2(endPosition.X, borders.Height));

            if (pathNodes.Count <= 2)
            {
                pathNodes.Add((startPosition + endPosition) / 2);
            }

            List <List <Vector2> > smallTunnels = new List <List <Vector2> >();
            for (int i = 0; i < generationParams.SmallTunnelCount; i++)
            {
                var tunnelStartPos = pathNodes[Rand.Range(2, pathNodes.Count - 2, Rand.RandSync.Server)];
                tunnelStartPos.X = MathHelper.Clamp(tunnelStartPos.X, pathBorders.X, pathBorders.Right);

                float tunnelLength = Rand.Range(
                    generationParams.SmallTunnelLengthRange.X,
                    generationParams.SmallTunnelLengthRange.Y,
                    Rand.RandSync.Server);

                var tunnelNodes = MathUtils.GenerateJaggedLine(
                    tunnelStartPos,
                    new Vector2(tunnelStartPos.X, pathBorders.Bottom) + Rand.Vector(tunnelLength, Rand.RandSync.Server),
                    4, 1000.0f);

                List <Vector2> tunnel = new List <Vector2>();
                foreach (Vector2[] tunnelNode in tunnelNodes)
                {
                    if (!pathBorders.Contains(tunnelNode[0]))
                    {
                        continue;
                    }
                    tunnel.Add(tunnelNode[0]);
                }

                if (tunnel.Any())
                {
                    smallTunnels.Add(tunnel);
                }
            }

            Vector2 siteInterval = generationParams.VoronoiSiteInterval;
            Vector2 siteVariance = generationParams.VoronoiSiteVariance;
            for (float x = siteInterval.X / 2; x < borders.Width; x += siteInterval.X)
            {
                for (float y = siteInterval.Y / 2; y < borders.Height; y += siteInterval.Y)
                {
                    Vector2 site = new Vector2(
                        x + Rand.Range(-siteVariance.X, siteVariance.X, Rand.RandSync.Server),
                        y + Rand.Range(-siteVariance.Y, siteVariance.Y, Rand.RandSync.Server));

                    if (smallTunnels.Any(t => t.Any(node => Vector2.Distance(node, site) < siteInterval.Length())))
                    {
                        //add some more sites around the small tunnels to generate more small voronoi cells
                        if (x < borders.Width - siteInterval.X)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.UnitX * siteInterval * 0.5f);
                        }
                        if (y < borders.Height - siteInterval.Y)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.UnitY * siteInterval * 0.5f);
                        }
                        if (x < borders.Width - siteInterval.X && y < borders.Height - siteInterval.Y)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.One * siteInterval * 0.5f);
                        }
                    }

                    if (mirror)
                    {
                        site.X = borders.Width - site.X;
                    }

                    sites.Add(site);
                }
            }

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();

            List <GraphEdge> graphEdges = voronoi.MakeVoronoiGraph(sites, borders.Width, borders.Height);

            Debug.WriteLine("MakeVoronoiGraph: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            //construct voronoi cells based on the graph edges
            cells = CaveGenerator.GraphEdgesToCells(graphEdges, borders, GridCellSize, out cellGrid);

            Debug.WriteLine("find cells: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            List <VoronoiCell> mainPath = CaveGenerator.GeneratePath(pathNodes, cells, cellGrid, GridCellSize,
                                                                     new Rectangle(pathBorders.X, pathBorders.Y, pathBorders.Width, borders.Height), 0.5f, mirror);

            for (int i = 2; i < mainPath.Count; i += 3)
            {
                positionsOfInterest.Add(new InterestingPosition(mainPath[i].Center, PositionType.MainPath));
            }

            List <VoronoiCell> pathCells = new List <VoronoiCell>(mainPath);

            EnlargeMainPath(pathCells, minWidth);

            foreach (InterestingPosition positionOfInterest in positionsOfInterest)
            {
                WayPoint wayPoint = new WayPoint(positionOfInterest.Position, SpawnType.Enemy, null);
                wayPoint.MoveWithLevel = true;
            }

            startPosition.X = pathCells[0].Center.X;

            foreach (List <Vector2> tunnel in smallTunnels)
            {
                if (tunnel.Count < 2)
                {
                    continue;
                }

                //find the cell which the path starts from
                int startCellIndex = CaveGenerator.FindCellIndex(tunnel[0], cells, cellGrid, GridCellSize, 1);
                if (startCellIndex < 0)
                {
                    continue;
                }

                //if it wasn't one of the cells in the main path, don't create a tunnel
                if (cells[startCellIndex].CellType != CellType.Path)
                {
                    continue;
                }

                var newPathCells = CaveGenerator.GeneratePath(tunnel, cells, cellGrid, GridCellSize, pathBorders);

                positionsOfInterest.Add(new InterestingPosition(tunnel.Last(), PositionType.Cave));

                if (tunnel.Count > 4)
                {
                    positionsOfInterest.Add(new InterestingPosition(tunnel[tunnel.Count / 2], PositionType.Cave));
                }

                pathCells.AddRange(newPathCells);
            }

            Debug.WriteLine("path: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            cells = CleanCells(pathCells);

            pathCells.AddRange(CreateBottomHoles(generationParams.BottomHoleProbability, new Rectangle(
                                                     (int)(borders.Width * 0.2f), 0,
                                                     (int)(borders.Width * 0.6f), (int)(borders.Height * 0.8f))));

            foreach (VoronoiCell cell in cells)
            {
                if (cell.Center.Y < borders.Height / 2)
                {
                    continue;
                }
                cell.edges.ForEach(e => e.OutsideLevel = true);
            }

            foreach (VoronoiCell cell in pathCells)
            {
                cell.edges.ForEach(e => e.OutsideLevel = false);

                cell.CellType = CellType.Path;
                cells.Remove(cell);
            }

            //generate some narrow caves
            int caveAmount = 0;// Rand.Int(3, false);
            List <VoronoiCell> usedCaveCells = new List <VoronoiCell>();
            for (int i = 0; i < caveAmount; i++)
            {
                Vector2     startPoint = Vector2.Zero;
                VoronoiCell startCell  = null;

                var caveCells = new List <VoronoiCell>();

                int maxTries = 5, tries = 0;
                while (tries < maxTries)
                {
                    startCell = cells[Rand.Int(cells.Count, Rand.RandSync.Server)];

                    //find an edge between the cell and the already carved path
                    GraphEdge startEdge =
                        startCell.edges.Find(e => pathCells.Contains(e.AdjacentCell(startCell)));

                    if (startEdge != null)
                    {
                        startPoint  = (startEdge.point1 + startEdge.point2) / 2.0f;
                        startPoint += startPoint - startCell.Center;

                        //get the cells in which the cave will be carved
                        caveCells = GetCells(startCell.Center, 2);
                        //remove cells that have already been "carved" out
                        caveCells.RemoveAll(c => c.CellType == CellType.Path);

                        //if any of the cells have already been used as a cave, continue and find some other cells
                        if (usedCaveCells.Any(c => caveCells.Contains(c)))
                        {
                            continue;
                        }
                        break;
                    }

                    tries++;
                }

                //couldn't find a place for a cave -> abort
                if (tries >= maxTries)
                {
                    break;
                }

                if (!caveCells.Any())
                {
                    continue;
                }

                usedCaveCells.AddRange(caveCells);

                List <VoronoiCell> caveSolidCells;
                var cavePathCells = CaveGenerator.CarveCave(caveCells, startPoint, out caveSolidCells);

                //remove the large cells used as a "base" for the cave (they've now been replaced with smaller ones)
                caveCells.ForEach(c => cells.Remove(c));

                cells.AddRange(caveSolidCells);

                foreach (VoronoiCell cell in cavePathCells)
                {
                    cells.Remove(cell);
                }

                pathCells.AddRange(cavePathCells);

                for (int j = cavePathCells.Count / 2; j < cavePathCells.Count; j += 10)
                {
                    positionsOfInterest.Add(new InterestingPosition(cavePathCells[j].Center, PositionType.Cave));
                }
            }

            for (int x = 0; x < cellGrid.GetLength(0); x++)
            {
                for (int y = 0; y < cellGrid.GetLength(1); y++)
                {
                    cellGrid[x, y].Clear();
                }
            }

            foreach (VoronoiCell cell in cells)
            {
                int x = (int)Math.Floor(cell.Center.X / GridCellSize);
                int y = (int)Math.Floor(cell.Center.Y / GridCellSize);

                if (x < 0 || y < 0 || x >= cellGrid.GetLength(0) || y >= cellGrid.GetLength(1))
                {
                    continue;
                }

                cellGrid[x, y].Add(cell);
            }

            ruins = new List <Ruin>();
            for (int i = 0; i < generationParams.RuinCount; i++)
            {
                GenerateRuin(mainPath);
            }

            startPosition.Y = borders.Height;
            endPosition.Y   = borders.Height;

            List <VoronoiCell> cellsWithBody = new List <VoronoiCell>(cells);

            List <Vector2[]> triangles;
            bodies = CaveGenerator.GeneratePolygons(cellsWithBody, out triangles);

#if CLIENT
            List <VertexPositionTexture> bodyVertices = CaveGenerator.GenerateRenderVerticeList(triangles);

            renderer.SetBodyVertices(bodyVertices.ToArray());
            renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells));

            renderer.PlaceSprites(generationParams.BackgroundSpriteAmount);
#endif

            ShaftBody = BodyFactory.CreateEdge(GameMain.World,
                                               ConvertUnits.ToSimUnits(new Vector2(borders.X, 0)),
                                               ConvertUnits.ToSimUnits(new Vector2(borders.Right, 0)));

            ShaftBody.SetTransform(ConvertUnits.ToSimUnits(new Vector2(0.0f, borders.Height)), 0.0f);

            ShaftBody.BodyType            = BodyType.Static;
            ShaftBody.CollisionCategories = Physics.CollisionLevel;

            bodies.Add(ShaftBody);

            foreach (VoronoiCell cell in cells)
            {
                foreach (GraphEdge edge in cell.edges)
                {
                    edge.cell1 = null;
                    edge.cell2 = null;
                    edge.site1 = null;
                    edge.site2 = null;
                }
            }

            //initialize MapEntities that aren't in any sub (e.g. items inside ruins)
            MapEntity.MapLoaded(null);

            Debug.WriteLine("Generatelevel: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            if (mirror)
            {
                Vector2 temp = startPosition;
                startPosition = endPosition;
                endPosition   = temp;
            }

            Debug.WriteLine("**********************************************************************************");
            Debug.WriteLine("Generated a map with " + sites.Count + " sites in " + sw.ElapsedMilliseconds + " ms");
            Debug.WriteLine("Seed: " + seed);
            Debug.WriteLine("**********************************************************************************");
        }
コード例 #25
0
ファイル: CargoMission.cs プロジェクト: lexuv2/Barotrauma
        private void LoadItemAsChild(XElement element, Item parent)
        {
            ItemPrefab itemPrefab;

            if (element.Attribute("name") != null)
            {
                DebugConsole.ThrowError("Error in cargo mission \"" + Name + "\" - use item identifiers instead of names to configure the items.");
                string itemName = element.GetAttributeString("name", "");
                itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
                if (itemPrefab == null)
                {
                    DebugConsole.ThrowError("Couldn't spawn item for cargo mission: item prefab \"" + itemName + "\" not found");
                    return;
                }
            }
            else
            {
                string itemIdentifier = element.GetAttributeString("identifier", "");
                itemPrefab = MapEntityPrefab.Find(null, itemIdentifier) as ItemPrefab;
                if (itemPrefab == null)
                {
                    DebugConsole.ThrowError("Couldn't spawn item for cargo mission: item prefab \"" + itemIdentifier + "\" not found");
                    return;
                }
            }

            if (itemPrefab == null)
            {
                DebugConsole.ThrowError("Couldn't spawn item for cargo mission: item prefab \"" + element.Name.ToString() + "\" not found");
                return;
            }

            WayPoint cargoSpawnPos = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub, useSyncedRand: true);

            if (cargoSpawnPos == null)
            {
                DebugConsole.ThrowError("Couldn't spawn items for cargo mission, cargo spawnpoint not found");
                return;
            }

            var cargoRoom = cargoSpawnPos.CurrentHull;

            if (cargoRoom == null)
            {
                DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!");
                return;
            }

            Vector2 position = new Vector2(
                cargoSpawnPos.Position.X + Rand.Range(-20.0f, 20.0f, Rand.RandSync.Server),
                cargoRoom.Rect.Y - cargoRoom.Rect.Height + itemPrefab.Size.Y / 2);

            var item = new Item(itemPrefab, position, cargoRoom.Submarine);

            item.FindHull();
            items.Add(item);

            if (parent != null && parent.GetComponent <ItemContainer>() != null)
            {
                parentInventoryIDs.Add(item, parent.ID);
                parentItemContainerIndices.Add(item, (byte)parent.GetComponentIndex(parent.GetComponent <ItemContainer>()));
                parent.Combine(item, user: null);
            }

            foreach (XElement subElement in element.Elements())
            {
                int amount = subElement.GetAttributeInt("amount", 1);
                for (int i = 0; i < amount; i++)
                {
                    LoadItemAsChild(subElement, item);
                }
            }
        }
コード例 #26
0
        private void EnlargeMainPath(List <VoronoiCell> pathCells, float minWidth)
        {
            List <WayPoint> wayPoints = new List <WayPoint>();

            var newWaypoint = new WayPoint(new Rectangle((int)pathCells[0].Center.X, borders.Height, 10, 10), null);

            newWaypoint.MoveWithLevel = true;
            wayPoints.Add(newWaypoint);

            //WayPoint prevWaypoint = newWaypoint;

            for (int i = 0; i < pathCells.Count; i++)
            {
                ////clean "loops" from the path
                //for (int n = 0; n < i; n++)
                //{
                //    if (pathCells[n] != pathCells[i]) continue;

                //    pathCells.RemoveRange(n + 1, i - n);
                //    break;
                //}
                //if (i >= pathCells.Count) break;

                pathCells[i].CellType = CellType.Path;

                newWaypoint = new WayPoint(new Rectangle((int)pathCells[i].Center.X, (int)pathCells[i].Center.Y, 10, 10), null);
                newWaypoint.MoveWithLevel = true;
                wayPoints.Add(newWaypoint);

                wayPoints[wayPoints.Count - 2].linkedTo.Add(newWaypoint);
                newWaypoint.linkedTo.Add(wayPoints[wayPoints.Count - 2]);

                for (int n = 0; n < wayPoints.Count; n++)
                {
                    if (wayPoints[n].Position != newWaypoint.Position)
                    {
                        continue;
                    }

                    wayPoints[n].linkedTo.Add(newWaypoint);
                    newWaypoint.linkedTo.Add(wayPoints[n]);

                    break;
                }

                //prevWaypoint = newWaypoint;
            }

            newWaypoint = new WayPoint(new Rectangle((int)pathCells[pathCells.Count - 1].Center.X, borders.Height, 10, 10), null);
            newWaypoint.MoveWithLevel = true;
            wayPoints.Add(newWaypoint);

            wayPoints[wayPoints.Count - 2].linkedTo.Add(newWaypoint);
            newWaypoint.linkedTo.Add(wayPoints[wayPoints.Count - 2]);

            if (minWidth > 0.0f)
            {
                List <VoronoiCell> removedCells = GetTooCloseCells(pathCells, minWidth);
                foreach (VoronoiCell removedCell in removedCells)
                {
                    if (removedCell.CellType == CellType.Path)
                    {
                        continue;
                    }

                    pathCells.Add(removedCell);
                    removedCell.CellType = CellType.Path;
                }
            }
        }
コード例 #27
0
        public static void ExecuteCommand(string command, GameMain game)
        {
            if (string.IsNullOrWhiteSpace(command))
            {
                return;
            }
            string[] commands = command.Split(' ');

            if (!commands[0].ToLowerInvariant().Equals("admin"))
            {
                NewMessage(textBox.Text, Color.White);
            }

#if !DEBUG
            if (GameMain.Client != null && !IsCommandPermitted(commands[0].ToLowerInvariant(), GameMain.Client))
            {
                ThrowError("You're not permitted to use the command \"" + commands[0].ToLowerInvariant() + "\"!");
                return;
            }
#endif

            switch (commands[0].ToLowerInvariant())
            {
            case "help":
                NewMessage("menu: go to main menu", Color.Cyan);
                NewMessage("game: enter the \"game screen\"", Color.Cyan);
                NewMessage("edit: switch to submarine editor", Color.Cyan);
                NewMessage("edit [submarine name]: load a submarine and switch to submarine editor", Color.Cyan);
                NewMessage("load [submarine name]: load a submarine", Color.Cyan);
                NewMessage("save [submarine name]: save the current submarine using the specified name", Color.Cyan);

                NewMessage(" ", Color.Cyan);

                NewMessage("spawn [creaturename] [near/inside/outside]: spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine)", Color.Cyan);
                NewMessage("spawnitem [itemname] [cursor/inventory]: spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted", Color.Cyan);

                NewMessage(" ", Color.Cyan);

                NewMessage("lights: disable lighting", Color.Cyan);
                NewMessage("los: disable the line of sight effect", Color.Cyan);
                NewMessage("freecam: detach the camera from the controlled character", Color.Cyan);
                NewMessage("control [character name]: start controlling the specified character", Color.Cyan);

                NewMessage(" ", Color.Cyan);

                NewMessage("water: allows adding water into rooms or removing it by holding the left/right mouse buttons", Color.Cyan);
                NewMessage("fire: allows putting up fires by left clicking", Color.Cyan);

                NewMessage(" ", Color.Cyan);

                NewMessage("teleport: teleport the controlled character to the position of the cursor", Color.Cyan);
                NewMessage("teleport [character name]: teleport the specified character to the position of the cursor", Color.Cyan);
                NewMessage("heal: restore the controlled character to full health", Color.Cyan);
                NewMessage("heal [character name]: restore the specified character to full health", Color.Cyan);
                NewMessage("revive: bring the controlled character back from the dead", Color.Cyan);
                NewMessage("revive [character name]: bring the specified character back from the dead", Color.Cyan);
                NewMessage("killmonsters: immediately kills all AI-controlled enemies in the level", Color.Cyan);

                NewMessage(" ", Color.Cyan);

                NewMessage("fixwalls: fixes all the walls", Color.Cyan);
                NewMessage("fixitems: fixes every item/device in the sub", Color.Cyan);
                NewMessage("oxygen: replenishes the oxygen in every room to 100%", Color.Cyan);
                NewMessage("power [amount]: immediately sets the temperature of the reactor to the specified value", Color.Cyan);

                NewMessage(" ", Color.Cyan);

                NewMessage("kick [name]: kick a player out from the server", Color.Cyan);
                NewMessage("ban [name]: kick and ban the player from the server", Color.Cyan);
                NewMessage("banip [IP address]: ban the IP address from the server", Color.Cyan);
                NewMessage("debugdraw: toggles the \"debug draw mode\"", Color.Cyan);
                NewMessage("netstats: toggles the visibility of the network statistics panel", Color.Cyan);

                break;

            case "createfilelist":
                UpdaterUtil.SaveFileList("filelist.xml");
                break;

            case "spawn":
            case "spawncharacter":
                if (commands.Length == 1)
                {
                    return;
                }

                Character spawnedCharacter = null;

                Vector2  spawnPosition = Vector2.Zero;
                WayPoint spawnPoint    = null;

                if (commands.Length > 2)
                {
                    switch (commands[2].ToLowerInvariant())
                    {
                    case "inside":
                        spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
                        break;

                    case "outside":
                        spawnPoint = WayPoint.GetRandom(SpawnType.Enemy);
                        break;

                    case "near":
                    case "close":
                        float closestDist = -1.0f;
                        foreach (WayPoint wp in WayPoint.WayPointList)
                        {
                            if (wp.Submarine != null)
                            {
                                continue;
                            }

                            //don't spawn inside hulls
                            if (Hull.FindHull(wp.WorldPosition, null) != null)
                            {
                                continue;
                            }

                            float dist = Vector2.Distance(wp.WorldPosition, GameMain.GameScreen.Cam.WorldViewCenter);

                            if (closestDist < 0.0f || dist < closestDist)
                            {
                                spawnPoint  = wp;
                                closestDist = dist;
                            }
                        }
                        break;

                    case "cursor":
                        spawnPosition = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                        break;

                    default:
                        spawnPoint = WayPoint.GetRandom(commands[1].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy);
                        break;
                    }
                }
                else
                {
                    spawnPoint = WayPoint.GetRandom(commands[1].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy);
                }

                if (string.IsNullOrWhiteSpace(commands[1]))
                {
                    return;
                }

                if (spawnPoint != null)
                {
                    spawnPosition = spawnPoint.WorldPosition;
                }

                if (commands[1].ToLowerInvariant() == "human")
                {
                    spawnedCharacter = Character.Create(Character.HumanConfigFile, spawnPosition);

                    if (GameMain.GameSession != null)
                    {
                        SinglePlayerMode mode = GameMain.GameSession.gameMode as SinglePlayerMode;
                        if (mode != null)
                        {
                            Character.Controlled = spawnedCharacter;
                            GameMain.GameSession.CrewManager.AddCharacter(Character.Controlled);
                            GameMain.GameSession.CrewManager.SelectCharacter(null, Character.Controlled);
                        }
                    }
                }
                else
                {
                    spawnedCharacter = Character.Create(
                        "Content/Characters/"
                        + commands[1].First().ToString().ToUpper() + commands[1].Substring(1)
                        + "/" + commands[1].ToLower() + ".xml", spawnPosition);
                }

                break;

            case "spawnitem":
                if (commands.Length < 2)
                {
                    return;
                }

                Vector2?  spawnPos       = null;
                Inventory spawnInventory = null;

                int extraParams = 0;
                switch (commands.Last())
                {
                case "cursor":
                    extraParams = 1;
                    spawnPos    = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
                    break;

                case "inventory":
                    extraParams    = 1;
                    spawnInventory = Character.Controlled == null ? null : Character.Controlled.Inventory;
                    break;

                default:
                    extraParams = 0;
                    break;
                }

                string itemName = string.Join(" ", commands.Skip(1).Take(commands.Length - extraParams - 1)).ToLowerInvariant();

                var itemPrefab = MapEntityPrefab.list.Find(ip => ip.Name.ToLowerInvariant() == itemName) as ItemPrefab;
                if (itemPrefab == null)
                {
                    ThrowError("Item \"" + itemName + "\" not found!");
                    return;
                }

                if (spawnPos == null && spawnInventory == null)
                {
                    var wp = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
                    spawnPos = wp == null ? Vector2.Zero : wp.WorldPosition;
                }

                if (spawnPos != null)
                {
                    Item.Spawner.AddToSpawnQueue(itemPrefab, (Vector2)spawnPos);
                }
                else if (spawnInventory != null)
                {
                    Item.Spawner.AddToSpawnQueue(itemPrefab, spawnInventory);
                }

                break;

            case "disablecrewai":
                HumanAIController.DisableCrewAI = !HumanAIController.DisableCrewAI;
                break;

            case "enablecrewai":
                HumanAIController.DisableCrewAI = false;
                break;

            /*case "admin":
             *  if (commands.Length < 2) break;
             *
             *  if (GameMain.Server != null)
             *  {
             *      GameMain.Server.AdminAuthPass = commands[1];
             *
             *  }
             *  else if (GameMain.Client != null)
             *  {
             *      GameMain.Client.RequestAdminAuth(commands[1]);
             *  }
             *  break;*/
            case "kick":
                if (GameMain.NetworkMember == null || commands.Length < 2)
                {
                    break;
                }
                GameMain.NetworkMember.KickPlayer(string.Join(" ", commands.Skip(1)), false);

                break;

            case "ban":
                if (GameMain.NetworkMember == null || commands.Length < 2)
                {
                    break;
                }
                GameMain.NetworkMember.KickPlayer(string.Join(" ", commands.Skip(1)), true);

                break;

            case "banip":
            {
                if (GameMain.Server == null || commands.Length < 2)
                {
                    break;
                }

                var client = GameMain.Server.ConnectedClients.Find(c => c.Connection.RemoteEndPoint.Address.ToString() == commands[1]);
                if (client == null)
                {
                    GameMain.Server.BanList.BanPlayer("Unnamed", commands[1]);
                }
                else
                {
                    GameMain.Server.KickClient(client, true);
                }
            }
            break;

            case "startclient":
                if (commands.Length == 1)
                {
                    return;
                }
                if (GameMain.Client == null)
                {
                    GameMain.NetworkMember = new GameClient("Name");
                    GameMain.Client.ConnectToServer(commands[1]);
                }
                break;

            case "mainmenuscreen":
            case "mainmenu":
            case "menu":
                GameMain.GameSession = null;

                List <Character> characters = new List <Character>(Character.CharacterList);
                foreach (Character c in characters)
                {
                    c.Remove();
                }

                GameMain.MainMenuScreen.Select();
                break;

            case "gamescreen":
            case "game":
                GameMain.GameScreen.Select();
                break;

            case "editmapscreen":
            case "editmap":
            case "edit":
                if (commands.Length > 1)
                {
                    Submarine.Load(string.Join(" ", commands.Skip(1)), true);
                }
                GameMain.EditMapScreen.Select();
                break;

            case "test":
                Submarine.Load("aegir mark ii", true);
                GameMain.DebugDraw = true;
                GameMain.LightManager.LosEnabled = false;
                GameMain.EditMapScreen.Select();
                break;

            case "editcharacter":
            case "editchar":
                GameMain.EditCharacterScreen.Select();
                break;

            case "controlcharacter":
            case "control":
            {
                if (commands.Length < 2)
                {
                    break;
                }

                var character = FindMatchingCharacter(commands, true);

                if (character != null)
                {
                    Character.Controlled = character;
                }
            }
            break;

            case "setclientcharacter":
            {
                if (GameMain.Server == null)
                {
                    break;
                }

                int separatorIndex = Array.IndexOf(commands, ";");

                if (separatorIndex == -1 || commands.Length < 4)
                {
                    ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\"");
                    break;
                }

                string[] commandsLeft  = commands.Take(separatorIndex).ToArray();
                string[] commandsRight = commands.Skip(separatorIndex).ToArray();

                string clientName = String.Join(" ", commandsLeft.Skip(1));

                var client = GameMain.Server.ConnectedClients.Find(c => c.name == clientName);
                if (client == null)
                {
                    ThrowError("Client \"" + clientName + "\" not found.");
                }

                var character = FindMatchingCharacter(commandsRight, false);
                GameMain.Server.SetClientCharacter(client, character);
            }
            break;

            case "teleportcharacter":
            case "teleport":
                var tpCharacter = FindMatchingCharacter(commands, false);

                if (commands.Length < 2)
                {
                    tpCharacter = Character.Controlled;
                }

                if (tpCharacter != null)
                {
                    var cam = GameMain.GameScreen.Cam;
                    tpCharacter.AnimController.CurrentHull = null;
                    tpCharacter.Submarine = null;
                    tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cam.ScreenToWorld(PlayerInput.MousePosition)));
                    tpCharacter.AnimController.FindHull(cam.ScreenToWorld(PlayerInput.MousePosition), true);
                }
                break;

            case "godmode":
                if (Submarine.MainSub == null)
                {
                    return;
                }

                Submarine.MainSub.GodMode = !Submarine.MainSub.GodMode;
                break;

            case "lockx":
                Submarine.LockX = !Submarine.LockX;
                break;

            case "locky":
                Submarine.LockY = !Submarine.LockY;
                break;

            case "dumpids":
                try
                {
                    int count = commands.Length < 2 ? 10 : int.Parse(commands[1]);
                    Entity.DumpIds(count);
                }
                catch
                {
                    return;
                }
                break;

            case "heal":
                Character healedCharacter = null;
                if (commands.Length == 1)
                {
                    healedCharacter = Character.Controlled;
                }
                else
                {
                    healedCharacter = FindMatchingCharacter(commands);
                }

                if (healedCharacter != null)
                {
                    healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null);
                    healedCharacter.Oxygen   = 100.0f;
                    healedCharacter.Bleeding = 0.0f;
                    healedCharacter.Stun     = 0.0f;
                }

                break;

            case "revive":
                Character revivedCharacter = null;
                if (commands.Length == 1)
                {
                    revivedCharacter = Character.Controlled;
                }
                else
                {
                    revivedCharacter = FindMatchingCharacter(commands);
                }

                if (revivedCharacter != null)
                {
                    revivedCharacter.Revive(false);
                    if (GameMain.Server != null)
                    {
                        foreach (Client c in GameMain.Server.ConnectedClients)
                        {
                            if (c.Character != revivedCharacter)
                            {
                                continue;
                            }
                            //clients stop controlling the character when it dies, force control back
                            GameMain.Server.SetClientCharacter(c, revivedCharacter);
                            break;
                        }
                    }
                }
                break;

            case "freeze":
                if (Character.Controlled != null)
                {
                    Character.Controlled.AnimController.Frozen = !Character.Controlled.AnimController.Frozen;
                }
                break;

            case "freecamera":
            case "freecam":
                Character.Controlled = null;
                GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
                break;

            case "editwater":
            case "water":
                if (GameMain.Client == null)
                {
                    Hull.EditWater = !Hull.EditWater;
                }

                break;

            case "fire":
                if (GameMain.Client == null)
                {
                    Hull.EditFire = !Hull.EditFire;
                }

                break;

            case "fixitems":
                foreach (Item it in Item.ItemList)
                {
                    it.Condition = 100.0f;
                }
                break;

            case "fixhull":
            case "fixwalls":
                foreach (Structure w in Structure.WallList)
                {
                    for (int i = 0; i < w.SectionCount; i++)
                    {
                        w.AddDamage(i, -100000.0f);
                    }
                }
                break;

            case "power":
                Item reactorItem = Item.ItemList.Find(i => i.GetComponent <Reactor>() != null);
                if (reactorItem == null)
                {
                    return;
                }

                float power = 5000.0f;
                if (commands.Length > 1)
                {
                    float.TryParse(commands[1], out power);
                }

                var reactor = reactorItem.GetComponent <Reactor>();
                reactor.ShutDownTemp = power == 0 ? 0 : 7000.0f;
                reactor.AutoTemp     = true;
                reactor.Temperature  = power;

                if (GameMain.Server != null)
                {
                    reactorItem.CreateServerEvent(reactor);
                }
                break;

            case "shake":
                GameMain.GameScreen.Cam.Shake = 10.0f;
                break;

            case "losenabled":
            case "los":
            case "drawlos":
                GameMain.LightManager.LosEnabled = !GameMain.LightManager.LosEnabled;
                break;

            case "lighting":
            case "lightingenabled":
            case "light":
            case "lights":
                GameMain.LightManager.LightingEnabled = !GameMain.LightManager.LightingEnabled;
                break;

            case "oxygen":
            case "air":
                foreach (Hull hull in Hull.hullList)
                {
                    hull.OxygenPercentage = 100.0f;
                }
                break;

            case "tutorial":
                TutorialMode.StartTutorial(Tutorials.TutorialType.TutorialTypes[0]);


                break;

            case "editortutorial":
                GameMain.EditMapScreen.Select();
                GameMain.EditMapScreen.StartTutorial();
                break;

            case "lobbyscreen":
            case "lobby":
                GameMain.LobbyScreen.Select();
                break;

            case "savemap":
            case "savesub":
            case "save":
                if (commands.Length < 2)
                {
                    break;
                }

                if (GameMain.EditMapScreen.CharacterMode)
                {
                    GameMain.EditMapScreen.ToggleCharacterMode();
                }

                string fileName = string.Join(" ", commands.Skip(1));
                if (fileName.Contains("../"))
                {
                    DebugConsole.ThrowError("Illegal symbols in filename (../)");
                    return;
                }

                if (Submarine.SaveCurrent(System.IO.Path.Combine(Submarine.SavePath, fileName + ".sub")))
                {
                    NewMessage("Sub saved", Color.Green);
                    //Submarine.Loaded.First().CheckForErrors();
                }

                break;

            case "loadmap":
            case "loadsub":
            case "load":
                if (commands.Length < 2)
                {
                    break;
                }

                Submarine.Load(string.Join(" ", commands.Skip(1)), true);
                break;

            case "cleansub":
                for (int i = MapEntity.mapEntityList.Count - 1; i >= 0; i--)
                {
                    MapEntity me = MapEntity.mapEntityList[i];

                    if (me.SimPosition.Length() > 2000.0f)
                    {
                        DebugConsole.NewMessage("Removed " + me.Name + " (simposition " + me.SimPosition + ")", Color.Orange);
                        MapEntity.mapEntityList.RemoveAt(i);
                    }
                    else if (me.MoveWithLevel)
                    {
                        DebugConsole.NewMessage("Removed " + me.Name + " (MoveWithLevel==true)", Color.Orange);
                        MapEntity.mapEntityList.RemoveAt(i);
                    }
                    else if (me is Item)
                    {
                        Item item = me as Item;
                        var  wire = item.GetComponent <Wire>();
                        if (wire == null)
                        {
                            continue;
                        }

                        if (wire.GetNodes().Count > 0 && !wire.Connections.Any(c => c != null))
                        {
                            wire.Item.Drop(null);
                            DebugConsole.NewMessage("Dropped wire (ID: " + wire.Item.ID + ") - attached on wall but no connections found", Color.Orange);
                        }
                    }
                }
                break;

            case "messagebox":
                if (commands.Length < 3)
                {
                    break;
                }
                new GUIMessageBox(commands[1], commands[2]);
                break;

            case "debugdraw":
                GameMain.DebugDraw = !GameMain.DebugDraw;
                break;

            case "disablehud":
            case "hud":
                GUI.DisableHUD = !GUI.DisableHUD;
                GameMain.Instance.IsMouseVisible = !GameMain.Instance.IsMouseVisible;
                break;

            case "followsub":
                Camera.FollowSub = !Camera.FollowSub;
                break;

            case "drawaitargets":
            case "showaitargets":
                AITarget.ShowAITargets = !AITarget.ShowAITargets;
                break;

            case "killmonsters":
                foreach (Character c in Character.CharacterList)
                {
                    if (!(c.AIController is EnemyAIController))
                    {
                        continue;
                    }
                    c.AddDamage(CauseOfDeath.Damage, 10000.0f, null);
                }
                break;

            case "netstats":
                if (GameMain.Server == null)
                {
                    return;
                }

                GameMain.Server.ShowNetStats = !GameMain.Server.ShowNetStats;
                break;

#if DEBUG
            case "spamevents":
                foreach (Item item in Item.ItemList)
                {
                    for (int i = 0; i < item.components.Count; i++)
                    {
                        if (item.components[i] is IServerSerializable)
                        {
                            GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, i });
                        }
                        var itemContainer = item.GetComponent <ItemContainer>();
                        if (itemContainer != null)
                        {
                            GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.InventoryState });
                        }

                        GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.Status });

                        item.NeedsPositionUpdate = true;
                    }
                }

                foreach (Character c in Character.CharacterList)
                {
                    GameMain.Server.CreateEntityEvent(c, new object[] { NetEntityEvent.Type.Status });
                }

                foreach (Structure wall in Structure.WallList)
                {
                    GameMain.Server.CreateEntityEvent(wall);
                }
                break;

            case "spamchatmessages":
                int msgCount = 1000;
                if (commands.Length > 1)
                {
                    int.TryParse(commands[1], out msgCount);
                }
                int msgLength = 50;
                if (commands.Length > 2)
                {
                    int.TryParse(commands[2], out msgLength);
                }

                for (int i = 0; i < msgCount; i++)
                {
                    if (GameMain.Server != null)
                    {
                        GameMain.Server.SendChatMessage(ToolBox.RandomSeed(msgLength), ChatMessageType.Default);
                    }
                    else
                    {
                        GameMain.Client.SendChatMessage(ToolBox.RandomSeed(msgLength));
                    }
                }
                break;
#endif
            case "cleanbuild":
                GameMain.Config.MusicVolume = 0.5f;
                GameMain.Config.SoundVolume = 0.5f;
                DebugConsole.NewMessage("Music and sound volume set to 0.5", Color.Green);

                GameMain.Config.GraphicsWidth  = 0;
                GameMain.Config.GraphicsHeight = 0;
                GameMain.Config.WindowMode     = WindowMode.Fullscreen;
                DebugConsole.NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green);
                DebugConsole.NewMessage("Fullscreen enabled", Color.Green);

                GameSettings.VerboseLogging = false;

                if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster")
                {
                    DebugConsole.ThrowError("MasterServerUrl \"" + GameMain.Config.MasterServerUrl + "\"!");
                }

                GameMain.Config.Save("config.xml");

                var saveFiles = System.IO.Directory.GetFiles(SaveUtil.SaveFolder);

                foreach (string saveFile in saveFiles)
                {
                    System.IO.File.Delete(saveFile);
                    DebugConsole.NewMessage("Deleted " + saveFile, Color.Green);
                }

                if (System.IO.Directory.Exists(System.IO.Path.Combine(SaveUtil.SaveFolder, "temp")))
                {
                    System.IO.Directory.Delete(System.IO.Path.Combine(SaveUtil.SaveFolder, "temp"), true);
                    DebugConsole.NewMessage("Deleted temp save folder", Color.Green);
                }

                if (System.IO.Directory.Exists(ServerLog.SavePath))
                {
                    var logFiles = System.IO.Directory.GetFiles(ServerLog.SavePath);

                    foreach (string logFile in logFiles)
                    {
                        System.IO.File.Delete(logFile);
                        DebugConsole.NewMessage("Deleted " + logFile, Color.Green);
                    }
                }

                if (System.IO.File.Exists("filelist.xml"))
                {
                    System.IO.File.Delete("filelist.xml");
                    DebugConsole.NewMessage("Deleted filelist", Color.Green);
                }


                if (System.IO.File.Exists("Submarines/TutorialSub.sub"))
                {
                    System.IO.File.Delete("Submarines/TutorialSub.sub");

                    DebugConsole.NewMessage("Deleted TutorialSub from the submarine folder", Color.Green);
                }

                if (System.IO.File.Exists(GameServer.SettingsFile))
                {
                    System.IO.File.Delete(GameServer.SettingsFile);
                    DebugConsole.NewMessage("Deleted server settings", Color.Green);
                }

                if (System.IO.File.Exists(GameServer.ClientPermissionsFile))
                {
                    System.IO.File.Delete(GameServer.ClientPermissionsFile);
                    DebugConsole.NewMessage("Deleted client permission file", Color.Green);
                }

                if (System.IO.File.Exists("crashreport.txt"))
                {
                    System.IO.File.Delete("crashreport.txt");
                    DebugConsole.NewMessage("Deleted crashreport.txt", Color.Green);
                }

                if (!System.IO.File.Exists("Content/Map/TutorialSub.sub"))
                {
                    DebugConsole.ThrowError("TutorialSub.sub not found!");
                }

                break;

            default:
                NewMessage("Command not found", Color.Red);
                break;
            }
        }
コード例 #28
0
ファイル: Level.cs プロジェクト: kachnov/Barotrauma
        public void Generate(bool mirror = false)
        {
            if (backgroundSpriteManager == null)
            {
                var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundSpritePrefabs);
                if (files.Count > 0)
                {
                    backgroundSpriteManager = new BackgroundSpriteManager(files);
                }
                else
                {
                    backgroundSpriteManager = new BackgroundSpriteManager("Content/BackgroundSprites/BackgroundSpritePrefabs.xml");
                }
            }
#if CLIENT
            if (backgroundCreatureManager == null)
            {
                var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundCreaturePrefabs);
                if (files.Count > 0)
                {
                    backgroundCreatureManager = new BackgroundCreatureManager(files);
                }
                else
                {
                    backgroundCreatureManager = new BackgroundCreatureManager("Content/BackgroundSprites/BackgroundCreaturePrefabs.xml");
                }
            }
#endif

            Stopwatch sw = new Stopwatch();
            sw.Start();

            if (loaded != null)
            {
                loaded.Unload();
            }
            loaded = this;

            positionsOfInterest = new List <InterestingPosition>();

            Voronoi voronoi = new Voronoi(1.0);

            List <Vector2> sites = new List <Vector2>();

            bodies = new List <Body>();

            Rand.SetSyncedSeed(ToolBox.StringToInt(seed));

#if CLIENT
            renderer = new LevelRenderer(this);

            backgroundColor = generationParams.BackgroundColor;
            float avgValue = (backgroundColor.R + backgroundColor.G + backgroundColor.G) / 3;
            GameMain.LightManager.AmbientLight = new Color(backgroundColor * (10.0f / avgValue), 1.0f);
#endif

            SeaFloorTopPos = generationParams.SeaFloorDepth + generationParams.MountainHeightMax + generationParams.SeaFloorVariance;

            float minWidth = 6500.0f;
            if (Submarine.MainSub != null)
            {
                Rectangle dockedSubBorders = Submarine.MainSub.GetDockedBorders();
                minWidth = Math.Max(minWidth, Math.Max(dockedSubBorders.Width, dockedSubBorders.Height));
            }

            Rectangle pathBorders = borders;
            pathBorders.Inflate(-minWidth * 2, -minWidth * 2);

            startPosition = new Vector2(
                Rand.Range(minWidth, minWidth * 2, Rand.RandSync.Server),
                Rand.Range(borders.Height * 0.5f, borders.Height - minWidth * 2, Rand.RandSync.Server));

            endPosition = new Vector2(
                borders.Width - Rand.Range(minWidth, minWidth * 2, Rand.RandSync.Server),
                Rand.Range(borders.Height * 0.5f, borders.Height - minWidth * 2, Rand.RandSync.Server));

            //----------------------------------------------------------------------------------
            //generate the initial nodes for the main path and smaller tunnels
            //----------------------------------------------------------------------------------

            List <Vector2> pathNodes = new List <Vector2>();
            pathNodes.Add(new Vector2(startPosition.X, borders.Height));

            Vector2 nodeInterval = generationParams.MainPathNodeIntervalRange;

            for (float x = startPosition.X + Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server);
                 x < endPosition.X - Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server);
                 x += Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server))
            {
                pathNodes.Add(new Vector2(x, Rand.Range(pathBorders.Y, pathBorders.Bottom, Rand.RandSync.Server)));
            }

            pathNodes.Add(new Vector2(endPosition.X, borders.Height));

            if (pathNodes.Count <= 2)
            {
                pathNodes.Add((startPosition + endPosition) / 2);
            }

            GenerateTunnels(pathNodes, minWidth);

            //----------------------------------------------------------------------------------
            //generate voronoi sites
            //----------------------------------------------------------------------------------

            Vector2 siteInterval = generationParams.VoronoiSiteInterval;
            Vector2 siteVariance = generationParams.VoronoiSiteVariance;
            for (float x = siteInterval.X / 2; x < borders.Width; x += siteInterval.X)
            {
                for (float y = siteInterval.Y / 2; y < borders.Height; y += siteInterval.Y)
                {
                    Vector2 site = new Vector2(
                        x + Rand.Range(-siteVariance.X, siteVariance.X, Rand.RandSync.Server),
                        y + Rand.Range(-siteVariance.Y, siteVariance.Y, Rand.RandSync.Server));

                    if (smallTunnels.Any(t => t.Any(node => Vector2.Distance(node, site) < siteInterval.Length())))
                    {
                        //add some more sites around the small tunnels to generate more small voronoi cells
                        if (x < borders.Width - siteInterval.X)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.UnitX * siteInterval * 0.5f);
                        }
                        if (y < borders.Height - siteInterval.Y)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.UnitY * siteInterval * 0.5f);
                        }
                        if (x < borders.Width - siteInterval.X && y < borders.Height - siteInterval.Y)
                        {
                            sites.Add(new Vector2(x, y) + Vector2.One * siteInterval * 0.5f);
                        }
                    }

                    if (mirror)
                    {
                        site.X = borders.Width - site.X;
                    }

                    sites.Add(site);
                }
            }


            //----------------------------------------------------------------------------------
            // construct the voronoi graph and cells
            //----------------------------------------------------------------------------------

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();

            List <GraphEdge> graphEdges = voronoi.MakeVoronoiGraph(sites, borders.Width, borders.Height);

            Debug.WriteLine("MakeVoronoiGraph: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            //construct voronoi cells based on the graph edges
            cells = CaveGenerator.GraphEdgesToCells(graphEdges, borders, GridCellSize, out cellGrid);

            Debug.WriteLine("find cells: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            //----------------------------------------------------------------------------------
            // generate a path through the initial path nodes
            //----------------------------------------------------------------------------------

            List <VoronoiCell> mainPath = CaveGenerator.GeneratePath(pathNodes, cells, cellGrid, GridCellSize,
                                                                     new Rectangle(pathBorders.X, pathBorders.Y, pathBorders.Width, borders.Height), 0.5f, mirror);

            for (int i = 2; i < mainPath.Count; i += 3)
            {
                positionsOfInterest.Add(new InterestingPosition(mainPath[i].Center, PositionType.MainPath));
            }

            List <VoronoiCell> pathCells = new List <VoronoiCell>(mainPath);

            //make sure the path is wide enough to pass through
            EnlargeMainPath(pathCells, minWidth);

            foreach (InterestingPosition positionOfInterest in positionsOfInterest)
            {
                WayPoint wayPoint = new WayPoint(positionOfInterest.Position, SpawnType.Enemy, null);
                wayPoint.MoveWithLevel = true;
            }

            startPosition.X = pathCells[0].Center.X;

            //----------------------------------------------------------------------------------
            // tunnels through the tunnel nodes
            //----------------------------------------------------------------------------------

            foreach (List <Vector2> tunnel in smallTunnels)
            {
                if (tunnel.Count < 2)
                {
                    continue;
                }

                //find the cell which the path starts from
                int startCellIndex = CaveGenerator.FindCellIndex(tunnel[0], cells, cellGrid, GridCellSize, 1);
                if (startCellIndex < 0)
                {
                    continue;
                }

                //if it wasn't one of the cells in the main path, don't create a tunnel
                if (cells[startCellIndex].CellType != CellType.Path)
                {
                    continue;
                }

                var newPathCells = CaveGenerator.GeneratePath(tunnel, cells, cellGrid, GridCellSize, pathBorders);

                positionsOfInterest.Add(new InterestingPosition(tunnel.Last(), PositionType.Cave));

                if (tunnel.Count > 4)
                {
                    positionsOfInterest.Add(new InterestingPosition(tunnel[tunnel.Count / 2], PositionType.Cave));
                }

                pathCells.AddRange(newPathCells);
            }

            Debug.WriteLine("path: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();


            //----------------------------------------------------------------------------------
            // remove unnecessary cells and create some holes at the bottom of the level
            //----------------------------------------------------------------------------------

            cells = CleanCells(pathCells);
            pathCells.AddRange(CreateBottomHoles(generationParams.BottomHoleProbability, new Rectangle(
                                                     (int)(borders.Width * 0.2f), 0,
                                                     (int)(borders.Width * 0.6f), (int)(borders.Height * 0.8f))));

            foreach (VoronoiCell cell in cells)
            {
                if (cell.Center.Y < borders.Height / 2)
                {
                    continue;
                }
                cell.edges.ForEach(e => e.OutsideLevel = true);
            }

            //----------------------------------------------------------------------------------
            // initialize the cells that are still left and insert them into the cell grid
            //----------------------------------------------------------------------------------

            foreach (VoronoiCell cell in pathCells)
            {
                cell.edges.ForEach(e => e.OutsideLevel = false);

                cell.CellType = CellType.Path;
                cells.Remove(cell);
            }

            for (int x = 0; x < cellGrid.GetLength(0); x++)
            {
                for (int y = 0; y < cellGrid.GetLength(1); y++)
                {
                    cellGrid[x, y].Clear();
                }
            }

            foreach (VoronoiCell cell in cells)
            {
                int x = (int)Math.Floor(cell.Center.X / GridCellSize);
                int y = (int)Math.Floor(cell.Center.Y / GridCellSize);

                if (x < 0 || y < 0 || x >= cellGrid.GetLength(0) || y >= cellGrid.GetLength(1))
                {
                    continue;
                }

                cellGrid[x, y].Add(cell);
            }


            //----------------------------------------------------------------------------------
            // create some ruins
            //----------------------------------------------------------------------------------

            ruins = new List <Ruin>();
            for (int i = 0; i < generationParams.RuinCount; i++)
            {
                GenerateRuin(mainPath);
            }


            //----------------------------------------------------------------------------------
            // generate the bodies and rendered triangles of the cells
            //----------------------------------------------------------------------------------

            startPosition.Y = borders.Height;
            endPosition.Y   = borders.Height;

            List <VoronoiCell> cellsWithBody = new List <VoronoiCell>(cells);

            List <Vector2[]> triangles;
            bodies = CaveGenerator.GeneratePolygons(cellsWithBody, out triangles);

#if CLIENT
            renderer.SetBodyVertices(CaveGenerator.GenerateRenderVerticeList(triangles).ToArray(), generationParams.WallColor);
            renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells), generationParams.WallColor);
#endif

            TopBarrier = BodyFactory.CreateEdge(GameMain.World,
                                                ConvertUnits.ToSimUnits(new Vector2(borders.X, 0)),
                                                ConvertUnits.ToSimUnits(new Vector2(borders.Right, 0)));

            TopBarrier.SetTransform(ConvertUnits.ToSimUnits(new Vector2(0.0f, borders.Height)), 0.0f);
            TopBarrier.BodyType            = BodyType.Static;
            TopBarrier.CollisionCategories = Physics.CollisionLevel;

            bodies.Add(TopBarrier);

            GenerateSeaFloor();

            backgroundSpriteManager.PlaceSprites(this, generationParams.BackgroundSpriteAmount);
#if CLIENT
            backgroundCreatureManager.SpawnSprites(80);
#endif

            foreach (VoronoiCell cell in cells)
            {
                foreach (GraphEdge edge in cell.edges)
                {
                    edge.cell1 = null;
                    edge.cell2 = null;
                    edge.site1 = null;
                    edge.site2 = null;
                }
            }

            //initialize MapEntities that aren't in any sub (e.g. items inside ruins)
            MapEntity.MapLoaded(null);

            Debug.WriteLine("Generatelevel: " + sw2.ElapsedMilliseconds + " ms");
            sw2.Restart();

            if (mirror)
            {
                Vector2 temp = startPosition;
                startPosition = endPosition;
                endPosition   = temp;
            }

            Debug.WriteLine("**********************************************************************************");
            Debug.WriteLine("Generated a map with " + sites.Count + " sites in " + sw.ElapsedMilliseconds + " ms");
            Debug.WriteLine("Seed: " + seed);
            Debug.WriteLine("**********************************************************************************");

            if (GameSettings.VerboseLogging)
            {
                DebugConsole.NewMessage("Generated level with the seed " + seed + " (type: " + generationParams.Name + ")", Color.White);
            }
        }