public void PlaceObjects(Level level, int amount)
        {
            objectGrid = new List <LevelObject> [
                level.Size.X / GridSize,
                (level.Size.Y - level.BottomPos) / GridSize];

            List <SpawnPosition> availableSpawnPositions = new List <SpawnPosition>();
            var levelCells = level.GetAllCells();

            availableSpawnPositions.AddRange(GetAvailableSpawnPositions(levelCells, LevelObjectPrefab.SpawnPosType.Wall));
            availableSpawnPositions.AddRange(GetAvailableSpawnPositions(level.SeaFloor.Cells, LevelObjectPrefab.SpawnPosType.SeaFloor));

            foreach (RuinGeneration.Ruin ruin in level.Ruins)
            {
                foreach (var ruinShape in ruin.RuinShapes)
                {
                    foreach (var wall in ruinShape.Walls)
                    {
                        availableSpawnPositions.Add(new SpawnPosition(
                                                        new GraphEdge(wall.A, wall.B),
                                                        (wall.A + wall.B) / 2.0f - ruinShape.Center,
                                                        LevelObjectPrefab.SpawnPosType.RuinWall,
                                                        ruinShape.GetLineAlignment(wall)));
                    }
                }
            }

            foreach (var posOfInterest in level.PositionsOfInterest)
            {
                if (posOfInterest.PositionType != Level.PositionType.MainPath && posOfInterest.PositionType != Level.PositionType.SidePath)
                {
                    continue;
                }

                availableSpawnPositions.Add(new SpawnPosition(
                                                new GraphEdge(posOfInterest.Position.ToVector2(), posOfInterest.Position.ToVector2() + Vector2.UnitX),
                                                Vector2.UnitY,
                                                LevelObjectPrefab.SpawnPosType.MainPath,
                                                Alignment.Top));
            }

            availableSpawnPositions.Add(new SpawnPosition(
                                            new GraphEdge(level.StartPosition - Vector2.UnitX, level.StartPosition + Vector2.UnitX),
                                            -Vector2.UnitY, LevelObjectPrefab.SpawnPosType.LevelStart, Alignment.Top));
            availableSpawnPositions.Add(new SpawnPosition(
                                            new GraphEdge(level.EndPosition - Vector2.UnitX, level.EndPosition + Vector2.UnitX),
                                            -Vector2.UnitY, LevelObjectPrefab.SpawnPosType.LevelEnd, Alignment.Top));

            var availablePrefabs = new List <LevelObjectPrefab>(LevelObjectPrefab.List);

            objects           = new List <LevelObject>();
            updateableObjects = new List <LevelObject>();

            Dictionary <LevelObjectPrefab, List <SpawnPosition> > suitableSpawnPositions = new Dictionary <LevelObjectPrefab, List <SpawnPosition> >();
            Dictionary <LevelObjectPrefab, List <float> >         spawnPositionWeights   = new Dictionary <LevelObjectPrefab, List <float> >();

            for (int i = 0; i < amount; i++)
            {
                //get a random prefab and find a place to spawn it
                LevelObjectPrefab prefab = GetRandomPrefab(level.GenerationParams, availablePrefabs);
                if (prefab == null)
                {
                    continue;
                }
                if (!suitableSpawnPositions.ContainsKey(prefab))
                {
                    suitableSpawnPositions.Add(prefab,
                                               availableSpawnPositions.Where(sp =>
                                                                             sp.SpawnPosTypes.Any(type => prefab.SpawnPos.HasFlag(type)) &&
                                                                             sp.Length >= prefab.MinSurfaceWidth &&
                                                                             (sp.Alignment == Alignment.Any || prefab.Alignment.HasFlag(sp.Alignment))).ToList());
                    spawnPositionWeights.Add(prefab,
                                             suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
                }

                SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
                if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None)
                {
                    continue;
                }
                PlaceObject(prefab, spawnPosition, level);
                if (prefab.MaxCount < amount)
                {
                    if (objects.Count(o => o.Prefab == prefab) >= prefab.MaxCount)
                    {
                        availablePrefabs.Remove(prefab);
                    }
                }
            }

            foreach (Level.Cave cave in level.Caves)
            {
                availablePrefabs = new List <LevelObjectPrefab>(LevelObjectPrefab.List.FindAll(p => p.SpawnPos.HasFlag(LevelObjectPrefab.SpawnPosType.CaveWall)));
                availableSpawnPositions.Clear();
                suitableSpawnPositions.Clear();
                spawnPositionWeights.Clear();

                var caveCells = cave.Tunnels.SelectMany(t => t.Cells);
                List <VoronoiCell> caveWallCells = new List <VoronoiCell>();
                foreach (var edge in caveCells.SelectMany(c => c.Edges))
                {
                    if (!edge.NextToCave)
                    {
                        continue;
                    }
                    if (edge.Cell1?.CellType == CellType.Solid)
                    {
                        caveWallCells.Add(edge.Cell1);
                    }
                    if (edge.Cell2?.CellType == CellType.Solid)
                    {
                        caveWallCells.Add(edge.Cell2);
                    }
                }
                availableSpawnPositions.AddRange(GetAvailableSpawnPositions(caveWallCells.Distinct(), LevelObjectPrefab.SpawnPosType.CaveWall));

                for (int i = 0; i < cave.CaveGenerationParams.LevelObjectAmount; i++)
                {
                    //get a random prefab and find a place to spawn it
                    LevelObjectPrefab prefab = GetRandomPrefab(cave.CaveGenerationParams, availablePrefabs, requireCaveSpecificOverride: true);
                    if (prefab == null)
                    {
                        continue;
                    }
                    if (!suitableSpawnPositions.ContainsKey(prefab))
                    {
                        suitableSpawnPositions.Add(prefab,
                                                   availableSpawnPositions.Where(sp =>
                                                                                 sp.Length >= prefab.MinSurfaceWidth &&
                                                                                 (sp.Alignment == Alignment.Any || prefab.Alignment.HasFlag(sp.Alignment))).ToList());
                        spawnPositionWeights.Add(prefab,
                                                 suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
                    }
                    SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
                    if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None)
                    {
                        continue;
                    }
                    PlaceObject(prefab, spawnPosition, level, cave);
                    if (prefab.MaxCount < amount)
                    {
                        if (objects.Count(o => o.Prefab == prefab && o.ParentCave == cave) >= prefab.MaxCount)
                        {
                            availablePrefabs.Remove(prefab);
                        }
                    }
                }
            }
        }
Esempio n. 2
0
        public override void Update(float deltaTime)
        {
            if (IsClient)
            {
                foreach (Item item in items)
                {
                    if (item.ParentInventory != null && item.body != null)
                    {
                        item.body.FarseerBody.BodyType = BodyType.Dynamic;
                    }
                }
                return;
            }
            switch (State)
            {
            case 0:
                foreach (Item item in items)
                {
                    if (item.ParentInventory != null && item.body != null)
                    {
                        item.body.FarseerBody.BodyType = BodyType.Dynamic;
                    }
                    if (statusEffectOnApproach.ContainsKey(item))
                    {
                        foreach (Character character in Character.CharacterList)
                        {
                            if (character.IsPlayer && Vector2.DistanceSquared(nestPosition, character.WorldPosition) < approachItemsRadius * approachItemsRadius)
                            {
                                statusEffectOnApproach[item].Apply(statusEffectOnApproach[item].type, 1.0f, item, item);
                                statusEffectOnApproach.Remove(item);
                                break;
                            }
                        }
                    }
                }
                if (monsterPrefabs.Any())
                {
                    foreach (Character character in Character.CharacterList)
                    {
                        if (character.IsPlayer && Vector2.DistanceSquared(nestPosition, character.WorldPosition) < monsterSpawnRadius * monsterSpawnRadius)
                        {
                            foreach (var monster in monsterPrefabs)
                            {
                                int amount = Rand.Range(monster.Item2.X, monster.Item2.Y + 1);
                                for (int i = 0; i < amount; i++)
                                {
                                    Character.Create(monster.Item1.Identifier, nestPosition + Rand.Vector(100.0f), ToolBox.RandomSeed(8), createNetworkEvent: true);
                                }
                            }
                            monsterPrefabs.Clear();
                            break;
                        }
                    }
                }

                //continue when all items are in the sub or destroyed
                if (AllItemsDestroyedOrRetrieved())
                {
                    State = 1;
                }

                break;

            case 1:
                if (!Submarine.MainSub.AtEndExit && !Submarine.MainSub.AtStartExit)
                {
                    return;
                }
                State = 2;
                break;
            }
        }
Esempio n. 3
0
        private static void InitProjectSpecific()
        {
            commands.Add(new Command("autohull", "", (string[] args) =>
            {
                if (Screen.Selected != GameMain.SubEditorScreen)
                {
                    return;
                }

                if (MapEntity.mapEntityList.Any(e => e is Hull || e is Gap))
                {
                    ShowQuestionPrompt("This submarine already has hulls and/or gaps. This command will delete them. Do you want to continue? Y/N",
                                       (option) => {
                        if (option.ToLower() == "y")
                        {
                            GameMain.SubEditorScreen.AutoHull();
                        }
                    });
                }
                else
                {
                    GameMain.SubEditorScreen.AutoHull();
                }
            }));

            commands.Add(new Command("startclient", "", (string[] args) =>
            {
                if (args.Length == 0)
                {
                    return;
                }

                if (GameMain.Client == null)
                {
                    GameMain.NetworkMember = new GameClient("Name");
                    GameMain.Client.ConnectToServer(args[0]);
                }
            }));

            commands.Add(new Command("mainmenuscreen|mainmenu|menu", "mainmenu/menu: Go to the main menu.", (string[] args) =>
            {
                GameMain.GameSession = null;

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

                GameMain.MainMenuScreen.Select();
            }));

            commands.Add(new Command("gamescreen|game", "gamescreen/game: Go to the \"in-game\" view.", (string[] args) =>
            {
                GameMain.GameScreen.Select();
            }));

            commands.Add(new Command("editsubscreen|editsub|subeditor", "editsub/subeditor: Switch to the submarine editor.", (string[] args) =>
            {
                if (args.Length > 0)
                {
                    Submarine.Load(string.Join(" ", args), true);
                }
                GameMain.SubEditorScreen.Select();
            }));

            commands.Add(new Command("editcharacter", "", (string[] args) =>
            {
                GameMain.CharacterEditorScreen.Select();
            }));

            commands.Add(new Command("editparticles", "", (string[] args) =>
            {
                GameMain.ParticleEditorScreen.Select();
            }));


            commands.Add(new Command("control|controlcharacter", "control [character name]: Start controlling the specified character.", (string[] args) =>
            {
                if (args.Length < 1)
                {
                    return;
                }

                var character = FindMatchingCharacter(args, true);

                if (character != null)
                {
                    Character.Controlled = character;
                }
            },
                                     () =>
            {
                return(new string[][]
                {
                    Character.CharacterList.Select(c => c.Name).Distinct().ToArray()
                });
            }));

            commands.Add(new Command("shake", "", (string[] args) =>
            {
                GameMain.GameScreen.Cam.Shake = 10.0f;
            }));

            commands.Add(new Command("los", "los: Toggle the line of sight effect on/off.", (string[] args) =>
            {
                GameMain.LightManager.LosEnabled = !GameMain.LightManager.LosEnabled;
                NewMessage("Line of sight effect " + (GameMain.LightManager.LosEnabled ? "enabled" : "disabled"), Color.White);
            }));

            commands.Add(new Command("lighting|lights", "Toggle lighting on/off.", (string[] args) =>
            {
                GameMain.LightManager.LightingEnabled = !GameMain.LightManager.LightingEnabled;
                NewMessage("Lighting " + (GameMain.LightManager.LightingEnabled ? "enabled" : "disabled"), Color.White);
            }));

            commands.Add(new Command("tutorial", "", (string[] args) =>
            {
                TutorialMode.StartTutorial(Tutorials.TutorialType.TutorialTypes[0]);
            }));

            commands.Add(new Command("lobby|lobbyscreen", "", (string[] args) =>
            {
                GameMain.LobbyScreen.Select();
            }));

            commands.Add(new Command("save|savesub", "save [submarine name]: Save the currently loaded submarine using the specified name.", (string[] args) =>
            {
                if (args.Length < 1)
                {
                    return;
                }

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

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

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

            commands.Add(new Command("load|loadsub", "load [submarine name]: Load a submarine.", (string[] args) =>
            {
                if (args.Length == 0)
                {
                    return;
                }
                Submarine.Load(string.Join(" ", args), true);
            }));

            commands.Add(new Command("cleansub", "", (string[] args) =>
            {
                for (int i = MapEntity.mapEntityList.Count - 1; i >= 0; i--)
                {
                    MapEntity me = MapEntity.mapEntityList[i];

                    if (me.SimPosition.Length() > 2000.0f)
                    {
                        NewMessage("Removed " + me.Name + " (simposition " + me.SimPosition + ")", Color.Orange);
                        MapEntity.mapEntityList.RemoveAt(i);
                    }
                    else if (!me.ShouldBeSaved)
                    {
                        NewMessage("Removed " + me.Name + " (!ShouldBeSaved)", 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);
                            NewMessage("Dropped wire (ID: " + wire.Item.ID + ") - attached on wall but no connections found", Color.Orange);
                        }
                    }
                }
            }));

            commands.Add(new Command("messagebox", "", (string[] args) =>
            {
                new GUIMessageBox("", string.Join(" ", args));
            }));

            commands.Add(new Command("debugdraw", "debugdraw: Toggle the debug drawing mode on/off.", (string[] args) =>
            {
                GameMain.DebugDraw = !GameMain.DebugDraw;
                NewMessage("Debug draw mode " + (GameMain.DebugDraw ? "enabled" : "disabled"), Color.White);
            }));
            commands.Add(new Command("fpscounter", "fpscounter: Toggle the FPS counter.", (string[] args) =>
            {
                GameMain.ShowFPS = !GameMain.ShowFPS;
                NewMessage("FPS counter " + (GameMain.DebugDraw ? "enabled" : "disabled"), Color.White);
            }));

            commands.Add(new Command("togglehud|hud", "togglehud/hud: Toggle the character HUD (inventories, icons, buttons, etc) on/off.", (string[] args) =>
            {
                GUI.DisableHUD = !GUI.DisableHUD;
                GameMain.Instance.IsMouseVisible = !GameMain.Instance.IsMouseVisible;
                NewMessage(GUI.DisableHUD ? "Disabled HUD" : "Enabled HUD", Color.White);
            }));

            commands.Add(new Command("followsub", "followsub: Toggle whether the camera should follow the nearest submarine.", (string[] args) =>
            {
                Camera.FollowSub = !Camera.FollowSub;
                NewMessage(Camera.FollowSub ? "Set the camera to follow the closest submarine" : "Disabled submarine following.", Color.White);
            }));

            commands.Add(new Command("toggleaitargets|aitargets", "toggleaitargets/aitargets: Toggle the visibility of AI targets (= targets that enemies can detect and attack/escape from).", (string[] args) =>
            {
                AITarget.ShowAITargets = !AITarget.ShowAITargets;
                NewMessage(AITarget.ShowAITargets ? "Enabled AI target drawing" : "Disabled AI target drawing", Color.White);
            }));
#if DEBUG
            commands.Add(new Command("spamchatmessages", "", (string[] args) =>
            {
                int msgCount = 1000;
                if (args.Length > 0)
                {
                    int.TryParse(args[0], out msgCount);
                }
                int msgLength = 50;
                if (args.Length > 1)
                {
                    int.TryParse(args[1], out msgLength);
                }

                for (int i = 0; i < msgCount; i++)
                {
                    if (GameMain.Server != null)
                    {
                        GameMain.Server.SendChatMessage(ToolBox.RandomSeed(msgLength), ChatMessageType.Default);
                    }
                    else if (GameMain.Client != null)
                    {
                        GameMain.Client.SendChatMessage(ToolBox.RandomSeed(msgLength));
                    }
                }
            }));
#endif
            commands.Add(new Command("cleanbuild", "", (string[] args) =>
            {
                GameMain.Config.MusicVolume = 0.5f;
                GameMain.Config.SoundVolume = 0.5f;
                NewMessage("Music and sound volume set to 0.5", Color.Green);

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

                GameSettings.ShowUserStatisticsPrompt = true;

                GameSettings.VerboseLogging = false;

                if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster")
                {
                    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);
                    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);
                    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);
                        NewMessage("Deleted " + logFile, Color.Green);
                    }
                }

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

                if (System.IO.File.Exists("Data/bannedplayers.txt"))
                {
                    System.IO.File.Delete("Data/bannedplayers.txt");
                    NewMessage("Deleted bannedplayers.txt", Color.Green);
                }

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

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

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

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

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

                if (!System.IO.File.Exists("Content/Map/TutorialSub.sub"))
                {
                    ThrowError("TutorialSub.sub not found!");
                }
            }));
        }
Esempio n. 4
0
        private GameMode InstantiateGameMode(GameModePreset gameModePreset, string seed, SubmarineInfo selectedSub, CampaignSettings settings, IEnumerable <MissionPrefab> missionPrefabs = null, MissionType missionType = MissionType.None)
        {
            if (gameModePreset.GameModeType == typeof(CoOpMode) || gameModePreset.GameModeType == typeof(PvPMode))
            {
                //don't allow hidden mission types (e.g. GoTo) in single mission modes
                var missionTypes = (MissionType[])Enum.GetValues(typeof(MissionType));
                for (int i = 0; i < missionTypes.Length; i++)
                {
                    if (MissionPrefab.HiddenMissionClasses.Contains(missionTypes[i]))
                    {
                        missionType &= ~missionTypes[i];
                    }
                }
            }
            if (gameModePreset.GameModeType == typeof(CoOpMode))
            {
                return(missionPrefabs != null ?
                       new CoOpMode(gameModePreset, missionPrefabs) :
                       new CoOpMode(gameModePreset, missionType, seed ?? ToolBox.RandomSeed(8)));
            }
            else if (gameModePreset.GameModeType == typeof(PvPMode))
            {
                return(missionPrefabs != null ?
                       new PvPMode(gameModePreset, missionPrefabs) :
                       new PvPMode(gameModePreset, missionType, seed ?? ToolBox.RandomSeed(8)));
            }
            else if (gameModePreset.GameModeType == typeof(MultiPlayerCampaign))
            {
                var campaign = MultiPlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub, settings);
                if (campaign != null && selectedSub != null)
                {
                    campaign.Money = Math.Max(MultiPlayerCampaign.MinimumInitialMoney, campaign.Money - selectedSub.Price);
                }
                return(campaign);
            }
#if CLIENT
            else if (gameModePreset.GameModeType == typeof(SinglePlayerCampaign))
            {
                var campaign = SinglePlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub, settings);
                if (campaign != null && selectedSub != null)
                {
                    campaign.Money = Math.Max(SinglePlayerCampaign.MinimumInitialMoney, campaign.Money - selectedSub.Price);
                }
                return(campaign);
            }
            else if (gameModePreset.GameModeType == typeof(TutorialMode))
            {
                return(new TutorialMode(gameModePreset));
            }
            else if (gameModePreset.GameModeType == typeof(TestGameMode))
            {
                return(new TestGameMode(gameModePreset));
            }
#endif
            else if (gameModePreset.GameModeType == typeof(GameMode))
            {
                return(new GameMode(gameModePreset));
            }
            else
            {
                throw new Exception($"Could not find a game mode of the type \"{gameModePreset.GameModeType}\"");
            }
        }
Esempio n. 5
0
        public void SetTextPos()
        {
            if (text == null)
            {
                return;
            }

            censoredText = "";
            for (int i = 0; i < text.Length; i++)
            {
                censoredText += "\u2022";
            }

            var rect = Rect;

            overflowClipActive = false;
            wrappedText        = text;

            TextSize = MeasureText(text);

            if (Wrap && rect.Width > 0)
            {
                wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale, playerInput);
                TextSize    = MeasureText(wrappedText);
            }
            else if (OverflowClip)
            {
                overflowClipActive = TextSize.X > rect.Width - padding.X - padding.Z;
            }

            if (autoScale && textScale > 0.1f &&
                (TextSize.X * textScale > rect.Width - padding.X - padding.Z || TextSize.Y * textScale > rect.Height - padding.Y - padding.W))
            {
                TextScale = Math.Max(0.1f, Math.Min(
                                         (rect.Width - padding.X - padding.Z) / TextSize.X,
                                         (rect.Height - padding.Y - padding.W) / TextSize.Y)) - 0.01f;
                return;
            }

            textPos = new Vector2(padding.X + (rect.Width - padding.Z - padding.X) / 2.0f, padding.Y + (rect.Height - padding.Y - padding.W) / 2.0f);
            origin  = TextSize * 0.5f;

            if (textAlignment.HasFlag(Alignment.Left) && !overflowClipActive)
            {
                textPos.X = padding.X;
                origin.X  = 0;
            }
            if (textAlignment.HasFlag(Alignment.Right) || overflowClipActive)
            {
                textPos.X = rect.Width - padding.Z;
                origin.X  = TextSize.X;
            }
            if (textAlignment.HasFlag(Alignment.Top))
            {
                textPos.Y = padding.Y;
                origin.Y  = 0;
            }
            if (textAlignment.HasFlag(Alignment.Bottom))
            {
                textPos.Y = rect.Height - padding.W;
                origin.Y  = TextSize.Y;
            }

            origin.X = (int)(origin.X);
            origin.Y = (int)(origin.Y);

            textPos.X = (int)textPos.X;
            textPos.Y = (int)textPos.Y;
        }
        public GUIComponent CreateInfoFrame(GUIFrame frame, bool returnParent, Sprite permissionIcon = null)
        {
            var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.874f, 0.58f), frame.RectTransform, Anchor.TopCenter)
            {
                RelativeOffset = new Vector2(0.0f, 0.05f)
            })
            {
                RelativeSpacing = 0.05f
                                  //Stretch = true
            };

            var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.322f), paddedFrame.RectTransform), isHorizontal: true);

            new GUICustomComponent(new RectTransform(new Vector2(0.425f, 1.0f), headerArea.RectTransform),
                                   onDraw: (sb, component) => DrawInfoFrameCharacterIcon(sb, component.Rect));

            ScalableFont font = paddedFrame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;

            var headerTextArea = new GUILayoutGroup(new RectTransform(new Vector2(0.575f, 1.0f), headerArea.RectTransform))
            {
                RelativeSpacing = 0.02f,
                Stretch         = true
            };

            Color?nameColor = null;

            if (Job != null)
            {
                nameColor = Job.Prefab.UIColor;
            }

            GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), ToolBox.LimitString(Name, GUI.Font, headerTextArea.Rect.Width), textColor: nameColor, font: GUI.Font)
            {
                ForceUpperCase = true,
                Padding        = Vector4.Zero
            };

            if (permissionIcon != null)
            {
                Point iconSize  = permissionIcon.SourceRect.Size;
                int   iconWidth = (int)((float)characterNameBlock.Rect.Height / iconSize.Y * iconSize.X);
                new GUIImage(new RectTransform(new Point(iconWidth, characterNameBlock.Rect.Height), characterNameBlock.RectTransform)
                {
                    AbsoluteOffset = new Point(-iconWidth - 2, 0)
                }, permissionIcon)
                {
                    IgnoreLayoutGroups = true
                };
            }

            if (Job != null)
            {
                new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), Job.Name, textColor: Job.Prefab.UIColor, font: font)
                {
                    Padding = Vector4.Zero
                };
            }

            if (personalityTrait != null)
            {
                new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + personalityTrait.Name.Replace(" ", ""))), font: font)
                {
                    Padding = Vector4.Zero
                };
            }

            if (Job != null && (Character == null || !Character.IsDead))
            {
                var skillsArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.63f), paddedFrame.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter))
                {
                    Stretch = true
                };

                var skills = Job.Skills;
                skills.Sort((s1, s2) => - s1.Level.CompareTo(s2.Level));

                new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillsArea.RectTransform), TextManager.AddPunctuation(':', TextManager.Get("skills"), string.Empty), font: font)
                {
                    Padding = Vector4.Zero
                };

                foreach (Skill skill in skills)
                {
                    Color textColor = Color.White * (0.5f + skill.Level / 200.0f);

                    var skillName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillsArea.RectTransform), TextManager.Get("SkillName." + skill.Identifier), textColor: textColor, font: font)
                    {
                        Padding = Vector4.Zero
                    };
                    new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), skillName.RectTransform), ((int)skill.Level).ToString(), textColor: textColor, font: font, textAlignment: Alignment.CenterRight);
                }
            }
            else if (Character != null && Character.IsDead)
            {
                var deadArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.63f), paddedFrame.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter))
                {
                    Stretch = true
                };

                string deadDescription = TextManager.AddPunctuation(':', TextManager.Get("deceased") + "\n" + Character.CauseOfDeath.Affliction?.CauseOfDeathDescription ??
                                                                    TextManager.AddPunctuation(':', TextManager.Get("CauseOfDeath"), TextManager.Get("CauseOfDeath." + Character.CauseOfDeath.Type.ToString())));

                new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), deadArea.RectTransform), deadDescription, textColor: GUI.Style.Red, font: font, textAlignment: Alignment.TopLeft)
                {
                    Padding = Vector4.Zero
                };
            }

            if (returnParent)
            {
                return(frame);
            }
            else
            {
                return(paddedFrame);
            }
        }
Esempio n. 7
0
        public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable <Submarine> submarines, IEnumerable <string> saveFiles = null)
        {
            this.isMultiplayer     = isMultiplayer;
            this.newGameContainer  = newGameContainer;
            this.loadGameContainer = loadGameContainer;

            var columnContainer = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: true)
            {
                Stretch         = true,
                RelativeSpacing = isMultiplayer ? 0.0f : 0.05f
            };

            var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
            {
                Stretch         = true,
                RelativeSpacing = 0.015f
            };

            var rightColumn = new GUILayoutGroup(new RectTransform(isMultiplayer ? Vector2.Zero : new Vector2(1.5f, 1.0f), columnContainer.RectTransform))
            {
                Stretch         = true,
                RelativeSpacing = 0.015f
            };

            columnContainer.Recalculate();

            // New game left side
            new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform)
            {
                MinSize = new Point(0, 20)
            }, TextManager.Get("SaveName"));
            saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform)
            {
                MinSize = new Point(0, 20)
            }, string.Empty)
            {
                textFilterFunction = (string str) => { return(ToolBox.RemoveInvalidFileNameChars(str)); }
            };

            new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform)
            {
                MinSize = new Point(0, 20)
            }, TextManager.Get("MapSeed"));
            seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform)
            {
                MinSize = new Point(0, 20)
            }, ToolBox.RandomSeed(8));

            new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform)
            {
                MinSize = new Point(0, 20)
            }, TextManager.Get("SelectedSub"));
            var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), isHorizontal: true)
            {
                Stretch = true
            };

            subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform))
            {
                ScrollBarVisible = true
            };

            var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
            var searchBox   = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font);

            searchBox.OnSelected   += (sender, userdata) => { searchTitle.Visible = false; };
            searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };

            searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return(true); };
            var clearButton = new GUIButton(new RectTransform(new Vector2(0.075f, 1.0f), filterContainer.RectTransform), "x")
            {
                OnClicked = (btn, userdata) => { searchBox.Text = ""; FilterSubs(subList, ""); searchBox.Flash(Color.White); return(true); }
            };

            if (!isMultiplayer)
            {
                subList.OnSelected = OnSubSelected;
            }

            // New game right side
            subPreviewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform))
            {
                Stretch = true
            };

            var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.13f),
                                                                       (isMultiplayer ? leftColumn : rightColumn).RectTransform)
            {
                MaxSize = new Point(int.MaxValue, 60)
            }, childAnchor: Anchor.TopRight);

            var startButton = new GUIButton(new RectTransform(isMultiplayer ? new Vector2(0.5f, 1.0f) : Vector2.One,
                                                              buttonContainer.RectTransform, Anchor.BottomRight)
            {
                MaxSize = new Point(350, 60)
            },
                                            TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge")
            {
                OnClicked = (GUIButton btn, object userData) =>
                {
                    if (string.IsNullOrWhiteSpace(saveNameBox.Text))
                    {
                        saveNameBox.Flash(Color.Red);
                        return(false);
                    }

                    if (!(subList.SelectedData is Submarine selectedSub))
                    {
                        return(false);
                    }

                    if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
                    {
                        ((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
                        subList.SelectedComponent.CanBeFocused = false;
                        subList.Deselect();
                        return(false);
                    }

                    string savePath = SaveUtil.CreateSavePath(isMultiplayer ? SaveUtil.SaveType.Multiplayer : SaveUtil.SaveType.Singleplayer, saveNameBox.Text);
                    bool   hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;

                    if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
                    {
                        if (!hasRequiredContentPackages)
                        {
                            var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
                                                           TextManager.GetWithVariable("ContentPackageMismatchWarning", "[requiredcontentpackages]", string.Join(", ", selectedSub.RequiredContentPackages)),
                                                           new string[] { TextManager.Get("Yes"), TextManager.Get("No") });

                            msgBox.Buttons[0].OnClicked  = msgBox.Close;
                            msgBox.Buttons[0].OnClicked += (button, obj) =>
                            {
                                if (GUIMessageBox.MessageBoxes.Count == 0)
                                {
                                    StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text);
                                    if (isMultiplayer)
                                    {
                                        CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
                                    }
                                }
                                return(true);
                            };

                            msgBox.Buttons[1].OnClicked = msgBox.Close;
                        }

                        if (selectedSub.HasTag(SubmarineTag.Shuttle))
                        {
                            var msgBox = new GUIMessageBox(TextManager.Get("ShuttleSelected"),
                                                           TextManager.Get("ShuttleWarning"),
                                                           new string[] { TextManager.Get("Yes"), TextManager.Get("No") });

                            msgBox.Buttons[0].OnClicked = (button, obj) =>
                            {
                                StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text);
                                if (isMultiplayer)
                                {
                                    CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
                                }
                                return(true);
                            };
                            msgBox.Buttons[0].OnClicked += msgBox.Close;

                            msgBox.Buttons[1].OnClicked = msgBox.Close;
                            return(false);
                        }
                    }
                    else
                    {
                        StartNewGame?.Invoke(selectedSub, savePath, seedBox.Text);
                        if (isMultiplayer)
                        {
                            CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
                        }
                    }

                    return(true);
                }
            };


            if (!isMultiplayer)
            {
                var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform, Anchor.TopRight)
                {
                    AbsoluteOffset = new Point(5)
                }, style: "GUINotificationButton")
                {
                    IgnoreLayoutGroups = true,
                    OnClicked          = (btn, userdata) => { GameMain.Instance.ShowCampaignDisclaimer(); return(true); }
                };
                disclaimerBtn.RectTransform.MaxSize = new Point((int)(30 * GUI.Scale));
            }

            leftColumn.Recalculate();
            rightColumn.Recalculate();

            UpdateSubList(submarines);
            UpdateLoadMenu(saveFiles);
        }
Esempio n. 8
0
 public static string ParseContentPathFromUri(this XObject element) => ToolBox.ConvertAbsoluteToRelativePath(element.BaseUri);
Esempio n. 9
0
        public static void DrawSlot(SpriteBatch spriteBatch, Inventory inventory, InventorySlot slot, Item item, bool drawItem = true)
        {
            Rectangle rect = slot.Rect;

            rect.Location += slot.DrawOffset.ToPoint();

            if (slot.HighlightColor.A > 0)
            {
                float inflateAmount = (slot.HighlightColor.A / 255.0f) * slot.HighlightScaleUpAmount * 0.5f;
                rect.Inflate(rect.Width * inflateAmount, rect.Height * inflateAmount);
            }

            var itemContainer = item?.GetComponent <ItemContainer>();

            if (itemContainer != null && (itemContainer.InventoryTopSprite != null || itemContainer.InventoryBottomSprite != null))
            {
                if (!highlightedSubInventorySlots.Any(s => s.Slot == slot))
                {
                    itemContainer.InventoryBottomSprite?.Draw(spriteBatch, new Vector2(rect.Center.X, rect.Y), 0, UIScale);
                    itemContainer.InventoryTopSprite?.Draw(spriteBatch, new Vector2(rect.Center.X, rect.Y), 0, UIScale);
                }

                drawItem = false;
            }
            else
            {
                Sprite slotSprite = slot.SlotSprite ?? slotSpriteSmall;
                Color  slotColor  = slot.IsHighlighted ? Color.White : Color.White * 0.8f;
                if (inventory != null && inventory.Locked)
                {
                    slotColor = Color.Gray * 0.5f;
                }
                spriteBatch.Draw(slotSprite.Texture, rect, slotSprite.SourceRect, slotColor);

                if (item != null && drawItem)
                {
                    if (!item.IsFullCondition && (itemContainer == null || !itemContainer.ShowConditionInContainedStateIndicator))
                    {
                        GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Bottom - 8, rect.Width, 8), Color.Black * 0.8f, true);
                        GUI.DrawRectangle(spriteBatch,
                                          new Rectangle(rect.X, rect.Bottom - 8, (int)(rect.Width * item.Condition / item.MaxCondition), 8),
                                          Color.Lerp(Color.Red, Color.Green, item.Condition / item.MaxCondition) * 0.8f, true);
                    }

                    if (itemContainer != null)
                    {
                        float containedState = 0.0f;
                        if (itemContainer.ShowConditionInContainedStateIndicator)
                        {
                            containedState = item.Condition / item.MaxCondition;
                        }
                        else
                        {
                            containedState = itemContainer.Inventory.Capacity == 1 ?
                                             (itemContainer.Inventory.Items[0] == null ? 0.0f : itemContainer.Inventory.Items[0].Condition / itemContainer.Inventory.Items[0].MaxCondition) :
                                             itemContainer.Inventory.Items.Count(i => i != null) / (float)itemContainer.Inventory.capacity;
                        }

                        int       dir = slot.SubInventoryDir;
                        Rectangle containedIndicatorArea = new Rectangle(rect.X,
                                                                         dir < 0 ? rect.Bottom + HUDLayoutSettings.Padding / 2 : rect.Y - HUDLayoutSettings.Padding / 2 - ContainedIndicatorHeight, rect.Width, ContainedIndicatorHeight);
                        containedIndicatorArea.Inflate(-4, 0);

                        if (itemContainer.ContainedStateIndicator?.Texture == null)
                        {
                            containedIndicatorArea.Inflate(0, -2);
                            GUI.DrawRectangle(spriteBatch, containedIndicatorArea, Color.DarkGray * 0.9f, true);
                            GUI.DrawRectangle(spriteBatch,
                                              new Rectangle(containedIndicatorArea.X, containedIndicatorArea.Y, (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Height),
                                              Color.Lerp(Color.Red, Color.Green, containedState) * 0.8f, true);
                        }
                        else
                        {
                            Sprite indicatorSprite = itemContainer.ContainedStateIndicator;
                            float  indicatorScale  = Math.Min(
                                containedIndicatorArea.Width / (float)indicatorSprite.SourceRect.Width,
                                containedIndicatorArea.Height / (float)indicatorSprite.SourceRect.Height);

                            if (containedState > 0.0f && containedState < 0.25f)
                            {
                                indicatorScale += ((float)Math.Sin(Timing.TotalTime * 5.0f) + 1.0f) * 0.25f;
                            }

                            indicatorSprite.Draw(spriteBatch, containedIndicatorArea.Center.ToVector2(),
                                                 (inventory != null && inventory.Locked) ? Color.DarkGray * 0.5f : Color.DarkGray * 0.9f,
                                                 origin: indicatorSprite.size / 2,
                                                 rotate: 0.0f,
                                                 scale: indicatorScale);

                            Color indicatorColor = ToolBox.GradientLerp(containedState, Color.Red, Color.Orange, Color.Green);
                            if (inventory != null && inventory.Locked)
                            {
                                indicatorColor *= 0.5f;
                            }

                            spriteBatch.Draw(indicatorSprite.Texture, containedIndicatorArea.Center.ToVector2(),
                                             sourceRectangle: new Rectangle(indicatorSprite.SourceRect.Location, new Point((int)(indicatorSprite.SourceRect.Width * containedState), indicatorSprite.SourceRect.Height)),
                                             color: indicatorColor,
                                             rotation: 0.0f,
                                             origin: indicatorSprite.size / 2,
                                             scale: indicatorScale,
                                             effects: SpriteEffects.None, layerDepth: 0.0f);
                        }
                    }
                }
            }

            if (GameMain.DebugDraw)
            {
                GUI.DrawRectangle(spriteBatch, rect, Color.White, false, 0, 1);
                GUI.DrawRectangle(spriteBatch, slot.EquipButtonRect, Color.White, false, 0, 1);
            }

            if (slot.HighlightColor != Color.Transparent)
            {
                GUI.UIGlow.Draw(spriteBatch, rect, slot.HighlightColor);
            }

            if (item != null && drawItem)
            {
                Sprite  sprite  = item.Prefab.InventoryIcon ?? item.Sprite;
                float   scale   = Math.Min(Math.Min((rect.Width - 10) / sprite.size.X, (rect.Height - 10) / sprite.size.Y), 3.0f);
                Vector2 itemPos = rect.Center.ToVector2();
                if (itemPos.Y > GameMain.GraphicsHeight)
                {
                    itemPos.Y -= Math.Min(
                        (itemPos.Y + sprite.size.Y / 2 * scale) - GameMain.GraphicsHeight,
                        (itemPos.Y - sprite.size.Y / 2 * scale) - rect.Y);
                }

                float rotation = 0.0f;
                if (slot.HighlightColor.A > 0)
                {
                    rotation = (float)Math.Sin(slot.HighlightTimer * MathHelper.TwoPi) * slot.HighlightTimer * 0.3f;
                }

                Color spriteColor = sprite == item.Sprite ? item.GetSpriteColor() : item.GetInventoryIconColor();
                if (inventory != null && inventory.Locked)
                {
                    spriteColor *= 0.5f;
                }
                if (CharacterHealth.OpenHealthWindow != null && !item.UseInHealthInterface)
                {
                    spriteColor = Color.Lerp(spriteColor, Color.TransparentBlack, 0.5f);
                }
                else
                {
                    sprite.Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black * 0.6f, rotate: rotation, scale: scale);
                }
                sprite.Draw(spriteBatch, itemPos, spriteColor, rotation, scale);
            }

            if (inventory != null &&
                !inventory.Locked &&
                Character.Controlled?.Inventory == inventory &&
                slot.QuickUseKey != Keys.None)
            {
                GUI.DrawString(spriteBatch, rect.Location.ToVector2(),
                               slot.QuickUseKey.ToString().Substring(1, 1),
                               item == null || !drawItem ? Color.Gray : Color.White,
                               Color.Black * 0.8f);
            }
        }
Esempio n. 10
0
        public void StartRound(Level level)
        {
            if (isClient)
            {
                return;
            }

            pendingEventSets.Clear();
            selectedEvents.Clear();
            activeEvents.Clear();

            pathFinder      = new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
            totalPathLength = 0.0f;
            if (level != null)
            {
                var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(Level.Loaded.StartPosition), ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));
                totalPathLength = steeringPath.TotalLength;
            }

            this.level = level;
            SelectSettings();

            var initialEventSet = SelectRandomEvents(EventSet.List);

            if (initialEventSet != null)
            {
                pendingEventSets.Add(initialEventSet);
                int seed = ToolBox.StringToInt(level.Seed);
                foreach (var previousEvent in level.LevelData.EventHistory)
                {
                    seed ^= ToolBox.StringToInt(previousEvent.Identifier);
                }
                MTRandom rand = new MTRandom(seed);
                CreateEvents(initialEventSet, rand);
            }

            if (level?.LevelData?.Type == LevelData.LevelType.Outpost)
            {
                level.LevelData.EventHistory.AddRange(selectedEvents.Values.SelectMany(v => v).Select(e => e.Prefab).Where(e => !level.LevelData.EventHistory.Contains(e)));
                if (level.LevelData.EventHistory.Count > MaxEventHistory)
                {
                    level.LevelData.EventHistory.RemoveRange(0, level.LevelData.EventHistory.Count - MaxEventHistory);
                }
                AddChildEvents(initialEventSet);
                void AddChildEvents(EventSet eventSet)
                {
                    if (eventSet == null)
                    {
                        return;
                    }
                    foreach (EventPrefab ep in eventSet.EventPrefabs.Select(e => e.First))
                    {
                        if (!level.LevelData.NonRepeatableEvents.Contains(ep))
                        {
                            level.LevelData.NonRepeatableEvents.Add(ep);
                        }
                    }
                    foreach (EventSet childSet in eventSet.ChildSets)
                    {
                        AddChildEvents(childSet);
                    }
                }
            }

            PreloadContent(GetFilesToPreload());

            roundDuration        = 0.0f;
            intensityUpdateTimer = 0.0f;
            CalculateCurrentIntensity(0.0f);
            currentIntensity = targetIntensity;
            eventCoolDown    = 0.0f;
        }
Esempio n. 11
0
        public LevelEditorScreen()
        {
            cam = new Camera()
            {
                MinZoom = 0.01f,
                MaxZoom = 1.0f
            };

            leftPanel = new GUIFrame(new RectTransform(new Vector2(0.125f, 0.8f), Frame.RectTransform)
            {
                MinSize = new Point(150, 0)
            });
            var paddedLeftPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), leftPanel.RectTransform, Anchor.CenterLeft)
            {
                RelativeOffset = new Vector2(0.02f, 0.0f)
            })
            {
                Stretch         = true,
                RelativeSpacing = 0.01f
            };

            paramsList             = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.3f), paddedLeftPanel.RectTransform));
            paramsList.OnSelected += (GUIComponent component, object obj) =>
            {
                selectedParams = obj as LevelGenerationParams;
                editorContainer.ClearChildren();
                SortLevelObjectsList(selectedParams);
                new SerializableEntityEditor(editorContainer.Content.RectTransform, selectedParams, false, true, elementHeight: 20);
                return(true);
            };

            var ruinTitle = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedLeftPanel.RectTransform), TextManager.Get("leveleditor.ruinparams"), font: GUI.SubHeadingFont);

            ruinParamsList             = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.1f), paddedLeftPanel.RectTransform));
            ruinParamsList.OnSelected += (GUIComponent component, object obj) =>
            {
                var ruinGenerationParams = obj as RuinGenerationParams;
                editorContainer.ClearChildren();
                new SerializableEntityEditor(editorContainer.Content.RectTransform, ruinGenerationParams, false, true, elementHeight: 20);
                return(true);
            };

            var outpostTitle = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedLeftPanel.RectTransform), TextManager.Get("leveleditor.outpostparams"), font: GUI.SubHeadingFont);

            GUITextBlock.AutoScaleAndNormalize(ruinTitle, outpostTitle);

            outpostParamsList             = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), paddedLeftPanel.RectTransform));
            outpostParamsList.OnSelected += (GUIComponent component, object obj) =>
            {
                var outpostGenerationParams = obj as OutpostGenerationParams;
                editorContainer.ClearChildren();
                var outpostParamsEditor = new SerializableEntityEditor(editorContainer.Content.RectTransform, outpostGenerationParams, false, true, elementHeight: 20);

                // location type -------------------------

                var locationTypeGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, 20)), isHorizontal: true, childAnchor: Anchor.CenterLeft)
                {
                    Stretch = true
                };

                new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), locationTypeGroup.RectTransform), TextManager.Get("outpostmoduleallowedlocationtypes"), textAlignment: Alignment.CenterLeft);
                HashSet <string> availableLocationTypes = new HashSet <string> {
                    "any"
                };
                foreach (LocationType locationType in LocationType.List)
                {
                    availableLocationTypes.Add(locationType.Identifier);
                }

                var locationTypeDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), locationTypeGroup.RectTransform),
                                                           text: string.Join(", ", outpostGenerationParams.AllowedLocationTypes.Select(lt => TextManager.Capitalize(lt)) ?? "any".ToEnumerable()), selectMultiple: true);
                foreach (string locationType in availableLocationTypes)
                {
                    locationTypeDropDown.AddItem(TextManager.Capitalize(locationType), locationType);
                    if (outpostGenerationParams.AllowedLocationTypes.Contains(locationType))
                    {
                        locationTypeDropDown.SelectItem(locationType);
                    }
                }
                if (!outpostGenerationParams.AllowedLocationTypes.Any())
                {
                    locationTypeDropDown.SelectItem("any");
                }

                locationTypeDropDown.OnSelected += (_, __) =>
                {
                    outpostGenerationParams.SetAllowedLocationTypes(locationTypeDropDown.SelectedDataMultiple.Cast <string>());
                    locationTypeDropDown.Text = ToolBox.LimitString(locationTypeDropDown.Text, locationTypeDropDown.Font, locationTypeDropDown.Rect.Width);
                    return(true);
                };
                locationTypeGroup.RectTransform.MinSize = new Point(locationTypeGroup.Rect.Width, locationTypeGroup.RectTransform.Children.Max(c => c.MinSize.Y));

                outpostParamsEditor.AddCustomContent(locationTypeGroup, 100);

                // module count -------------------------

                var moduleLabel = new GUITextBlock(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(70 * GUI.Scale))), TextManager.Get("submarinetype.outpostmodules"), font: GUI.SubHeadingFont);
                outpostParamsEditor.AddCustomContent(moduleLabel, 100);

                foreach (KeyValuePair <string, int> moduleCount in outpostGenerationParams.ModuleCounts)
                {
                    var moduleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(25 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.CenterLeft);
                    new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), TextManager.Capitalize(moduleCount.Key), textAlignment: Alignment.CenterLeft);
                    new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), GUINumberInput.NumberType.Int)
                    {
                        MinValueInt    = 0,
                        MaxValueInt    = 100,
                        IntValue       = moduleCount.Value,
                        OnValueChanged = (numInput) =>
                        {
                            outpostGenerationParams.SetModuleCount(moduleCount.Key, numInput.IntValue);
                            if (numInput.IntValue == 0)
                            {
                                outpostParamsList.Select(outpostParamsList.SelectedData);
                            }
                        }
                    };
                    moduleCountGroup.RectTransform.MinSize = new Point(moduleCountGroup.Rect.Width, moduleCountGroup.RectTransform.Children.Max(c => c.MinSize.Y));
                    outpostParamsEditor.AddCustomContent(moduleCountGroup, 100);
                }

                // add module count -------------------------

                var addModuleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(40 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.Center);

                HashSet <string> availableFlags = new HashSet <string>();
                foreach (string flag in OutpostGenerationParams.Params.SelectMany(p => p.ModuleCounts.Select(m => m.Key)))
                {
                    availableFlags.Add(flag);
                }
                foreach (var sub in SubmarineInfo.SavedSubmarines)
                {
                    if (sub.OutpostModuleInfo == null)
                    {
                        continue;
                    }
                    foreach (string flag in sub.OutpostModuleInfo.ModuleFlags)
                    {
                        availableFlags.Add(flag);
                    }
                }

                var moduleTypeDropDown = new GUIDropDown(new RectTransform(new Vector2(0.8f, 0.8f), addModuleCountGroup.RectTransform),
                                                         text: TextManager.Get("leveleditor.addmoduletype"));
                foreach (string flag in availableFlags)
                {
                    if (outpostGenerationParams.ModuleCounts.Any(mc => mc.Key.Equals(flag, StringComparison.OrdinalIgnoreCase)))
                    {
                        continue;
                    }
                    moduleTypeDropDown.AddItem(TextManager.Capitalize(flag), flag);
                }
                moduleTypeDropDown.OnSelected += (_, userdata) =>
                {
                    outpostGenerationParams.SetModuleCount(userdata as string, 1);
                    outpostParamsList.Select(outpostParamsList.SelectedData);
                    return(true);
                };
                addModuleCountGroup.RectTransform.MinSize = new Point(addModuleCountGroup.Rect.Width, addModuleCountGroup.RectTransform.Children.Max(c => c.MinSize.Y));
                outpostParamsEditor.AddCustomContent(addModuleCountGroup, 100);

                return(true);
            };

            var createLevelObjButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
                                                     TextManager.Get("leveleditor.createlevelobj"))
            {
                OnClicked = (btn, obj) =>
                {
                    Wizard.Instance.Create();
                    return(true);
                }
            };

            GUITextBlock.AutoScaleAndNormalize(createLevelObjButton.TextBlock);

            lightingEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform),
                                             TextManager.Get("leveleditor.lightingenabled"));

            cursorLightEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform),
                                                TextManager.Get("leveleditor.cursorlightenabled"));

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
                          TextManager.Get("leveleditor.reloadtextures"))
            {
                OnClicked = (btn, obj) =>
                {
                    Level.Loaded?.ReloadTextures();
                    return(true);
                }
            };

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
                          TextManager.Get("editor.saveall"))
            {
                OnClicked = (btn, obj) =>
                {
                    SerializeAll();
                    return(true);
                }
            };

            rightPanel = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), Frame.RectTransform, Anchor.TopRight)
            {
                MinSize = new Point(450, 0)
            });
            var paddedRightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), rightPanel.RectTransform, Anchor.Center)
            {
                RelativeOffset = new Vector2(0.02f, 0.0f)
            })
            {
                Stretch         = true,
                RelativeSpacing = 0.01f
            };

            editorContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), paddedRightPanel.RectTransform));

            var seedContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform), isHorizontal: true);

            new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), TextManager.Get("leveleditor.levelseed"));
            seedBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), ToolBox.RandomSeed(8));

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
                          TextManager.Get("leveleditor.generate"))
            {
                OnClicked = (btn, obj) =>
                {
                    Submarine.Unload();
                    GameMain.LightManager.ClearLights();
                    LevelData levelData = LevelData.CreateRandom(seedBox.Text, generationParams: selectedParams);
                    levelData.ForceOutpostGenerationParams = outpostParamsList.SelectedData as OutpostGenerationParams;
                    Level.Generate(levelData, mirror: false);
                    GameMain.LightManager.AddLight(pointerLightSource);
                    cam.Position = new Vector2(Level.Loaded.Size.X / 2, Level.Loaded.Size.Y / 2);
                    foreach (GUITextBlock param in paramsList.Content.Children)
                    {
                        param.TextColor = param.UserData == selectedParams ? GUI.Style.Green : param.Style.TextColor;
                    }
                    seedBox.Deselect();
                    return(true);
                }
            };

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
                          TextManager.Get("leveleditor.test"))
            {
                OnClicked = (btn, obj) =>
                {
                    if (Level.Loaded?.LevelData == null)
                    {
                        return(false);
                    }

                    GameMain.GameScreen.Select();

                    var currEntities = Entity.GetEntities().ToList();
                    if (Submarine.MainSub != null)
                    {
                        var toRemove = Entity.GetEntities().Where(e => e.Submarine == Submarine.MainSub).ToList();
                        foreach (Entity ent in toRemove)
                        {
                            ent.Remove();
                        }
                        Submarine.MainSub.Remove();
                    }

                    //TODO: hacky workaround to check for wrecks and outposts, refactor SubmarineInfo and ContentType at some point
                    var nonPlayerFiles = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Wreck).ToList();
                    nonPlayerFiles.AddRange(ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Outpost));
                    nonPlayerFiles.AddRange(ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.OutpostModule));
                    SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name.Equals(GameMain.Config.QuickStartSubmarineName, StringComparison.InvariantCultureIgnoreCase));
                    subInfo ??= SubmarineInfo.SavedSubmarines.GetRandom(s =>
                                                                        s.IsPlayer && !s.HasTag(SubmarineTag.Shuttle) &&
                                                                        !nonPlayerFiles.Any(f => f.Path.CleanUpPath().Equals(s.FilePath.CleanUpPath(), StringComparison.InvariantCultureIgnoreCase)));
                    GameSession gameSession = new GameSession(subInfo, "", GameModePreset.TestMode, null);
                    gameSession.StartRound(Level.Loaded.LevelData);
                    (gameSession.GameMode as TestGameMode).OnRoundEnd = () =>
                    {
                        GameMain.LevelEditorScreen.Select();
                        Submarine.MainSub.Remove();

                        var toRemove = Entity.GetEntities().Where(e => !currEntities.Contains(e)).ToList();
                        foreach (Entity ent in toRemove)
                        {
                            ent.Remove();
                        }

                        Submarine.MainSub = null;
                    };

                    GameMain.GameSession = gameSession;

                    return(true);
                }
            };

            bottomPanel = new GUIFrame(new RectTransform(new Vector2(0.75f, 0.22f), Frame.RectTransform, Anchor.BottomLeft)
            {
                MaxSize = new Point(GameMain.GraphicsWidth - rightPanel.Rect.Width, 1000)
            }, style: "GUIFrameBottom");

            levelObjectList = new GUIListBox(new RectTransform(new Vector2(0.99f, 0.85f), bottomPanel.RectTransform, Anchor.Center))
            {
                UseGridLayout = true
            };
            levelObjectList.OnSelected += (GUIComponent component, object obj) =>
            {
                selectedLevelObject = obj as LevelObjectPrefab;
                CreateLevelObjectEditor(selectedLevelObject);
                return(true);
            };

            spriteEditDoneButton = new GUIButton(new RectTransform(new Point(200, 30), anchor: Anchor.BottomRight)
            {
                AbsoluteOffset = new Point(20, 20)
            },
                                                 TextManager.Get("leveleditor.spriteeditdone"))
            {
                OnClicked = (btn, userdata) =>
                {
                    editingSprite = null;
                    return(true);
                }
            };

            topPanel = new GUIFrame(new RectTransform(new Point(400, 100), GUI.Canvas)
            {
                RelativeOffset = new Vector2(leftPanel.RectTransform.RelativeSize.X * 2, 0.0f)
            }, style: "GUIFrameTop");
        }
Esempio n. 12
0
        private void CreateEvents(EventSet eventSet, Random rand)
        {
            if (level == null)
            {
                return;
            }
            int applyCount = 1;

            if (eventSet.PerRuin)
            {
                applyCount = Level.Loaded.Ruins.Count();
            }
            else if (eventSet.PerWreck)
            {
                applyCount = Submarine.Loaded.Count(s => s.Info.IsWreck && (s.WreckAI == null || !s.WreckAI.IsAlive));
            }
            for (int i = 0; i < applyCount; i++)
            {
                if (eventSet.ChooseRandom)
                {
                    if (eventSet.EventPrefabs.Count > 0)
                    {
                        List <Pair <EventPrefab, float> > unusedEvents = new List <Pair <EventPrefab, float> >(eventSet.EventPrefabs);
                        for (int j = 0; j < eventSet.EventCount; j++)
                        {
                            var eventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => CalculateCommonness(e)).ToList(), rand);
                            if (eventPrefab != null)
                            {
                                var newEvent = eventPrefab.First.CreateInstance();
                                if (newEvent == null)
                                {
                                    continue;
                                }
                                newEvent.Init(true);
                                DebugConsole.Log("Initialized event " + newEvent.ToString());
                                if (!selectedEvents.ContainsKey(eventSet))
                                {
                                    selectedEvents.Add(eventSet, new List <Event>());
                                }
                                selectedEvents[eventSet].Add(newEvent);
                                unusedEvents.Remove(eventPrefab);
                            }
                        }
                    }
                    if (eventSet.ChildSets.Count > 0)
                    {
                        var newEventSet = SelectRandomEvents(eventSet.ChildSets);
                        if (newEventSet != null)
                        {
                            CreateEvents(newEventSet, rand);
                        }
                    }
                }
                else
                {
                    foreach (Pair <EventPrefab, float> eventPrefab in eventSet.EventPrefabs)
                    {
                        var newEvent = eventPrefab.First.CreateInstance();
                        if (newEvent == null)
                        {
                            continue;
                        }
                        newEvent.Init(true);
                        DebugConsole.Log("Initialized event " + newEvent.ToString());
                        if (!selectedEvents.ContainsKey(eventSet))
                        {
                            selectedEvents.Add(eventSet, new List <Event>());
                        }
                        selectedEvents[eventSet].Add(newEvent);
                    }

                    foreach (EventSet childEventSet in eventSet.ChildSets)
                    {
                        CreateEvents(childEventSet, rand);
                    }
                }
            }
        }
Esempio n. 13
0
        partial void InitProjSpecific(XDocument doc)
        {
            if (doc == null)
            {
                GraphicsWidth  = 1024;
                GraphicsHeight = 678;

                MasterServerUrl = "";

                SelectedContentPackage = ContentPackage.list.Any() ? ContentPackage.list[0] : new ContentPackage("");

                JobNamePreferences = new List <string>();
                foreach (JobPrefab job in JobPrefab.List)
                {
                    JobNamePreferences.Add(job.Name);
                }
                return;
            }

            XElement graphicsMode = doc.Root.Element("graphicsmode");

            GraphicsWidth  = ToolBox.GetAttributeInt(graphicsMode, "width", 0);
            GraphicsHeight = ToolBox.GetAttributeInt(graphicsMode, "height", 0);
            VSyncEnabled   = ToolBox.GetAttributeBool(graphicsMode, "vsync", true);

            if (GraphicsWidth == 0 || GraphicsHeight == 0)
            {
                GraphicsWidth  = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
                GraphicsHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            }

            //FullScreenEnabled = ToolBox.GetAttributeBool(graphicsMode, "fullscreen", true);

            var windowModeStr = ToolBox.GetAttributeString(graphicsMode, "displaymode", "Fullscreen");

            if (!Enum.TryParse <WindowMode>(windowModeStr, out windowMode))
            {
                windowMode = WindowMode.Fullscreen;
            }

            SoundVolume = ToolBox.GetAttributeFloat(doc.Root, "soundvolume", 1.0f);
            MusicVolume = ToolBox.GetAttributeFloat(doc.Root, "musicvolume", 0.3f);

            EnableSplashScreen = ToolBox.GetAttributeBool(doc.Root, "enablesplashscreen", true);

            keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length];
            keyMapping[(int)InputType.Up]    = new KeyOrMouse(Keys.W);
            keyMapping[(int)InputType.Down]  = new KeyOrMouse(Keys.S);
            keyMapping[(int)InputType.Left]  = new KeyOrMouse(Keys.A);
            keyMapping[(int)InputType.Right] = new KeyOrMouse(Keys.D);
            keyMapping[(int)InputType.Run]   = new KeyOrMouse(Keys.LeftShift);


            keyMapping[(int)InputType.Chat]       = new KeyOrMouse(Keys.Tab);
            keyMapping[(int)InputType.CrewOrders] = new KeyOrMouse(Keys.C);

            keyMapping[(int)InputType.Select] = new KeyOrMouse(Keys.E);

            keyMapping[(int)InputType.Use] = new KeyOrMouse(0);
            keyMapping[(int)InputType.Aim] = new KeyOrMouse(1);

            foreach (XElement subElement in doc.Root.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "keymapping":
                    foreach (XAttribute attribute in subElement.Attributes())
                    {
                        InputType inputType;
                        if (Enum.TryParse(attribute.Name.ToString(), true, out inputType))
                        {
                            int mouseButton;
                            if (int.TryParse(attribute.Value.ToString(), out mouseButton))
                            {
                                keyMapping[(int)inputType] = new KeyOrMouse(mouseButton);
                            }
                            else
                            {
                                Keys key;
                                if (Enum.TryParse(attribute.Value.ToString(), true, out key))
                                {
                                    keyMapping[(int)inputType] = new KeyOrMouse(key);
                                }
                            }
                        }
                    }
                    break;

                case "gameplay":
                    JobNamePreferences = new List <string>();
                    foreach (XElement ele in subElement.Element("jobpreferences").Elements("job"))
                    {
                        JobNamePreferences.Add(ToolBox.GetAttributeString(ele, "name", ""));
                    }
                    break;
                }
            }

            foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
            {
                if (keyMapping[(int)inputType] == null)
                {
                    DebugConsole.ThrowError("Key binding for the input type \"" + inputType + " not set!");
                    keyMapping[(int)inputType] = new KeyOrMouse(Keys.D1);
                }
            }


            UnsavedSettings = false;
        }
Esempio n. 14
0
        protected override void Update(float deltaTime)
        {
            if (!Visible)
            {
                return;
            }

            UpdateChildrenRect();
            RepositionChildren();

            if (scrollBarNeedsRecalculation)
            {
                UpdateScrollBarSize();
            }


            if (FadeElements)
            {
                foreach (var(component, _) in childVisible)
                {
                    float lerp     = 0;
                    float y        = component.Rect.Y;
                    float contentY = Content.Rect.Y;
                    float height   = component.Rect.Height;
                    if (y < Content.Rect.Y)
                    {
                        float distance = (contentY - y) / height;
                        lerp = distance;
                    }

                    float centerY = Content.Rect.Y + Content.Rect.Height / 2.0f;
                    if (y > centerY)
                    {
                        float distance = (y - centerY) / (centerY - height);
                        lerp = distance;
                    }

                    component.Color         = component.HoverColor = ToolBox.GradientLerp(lerp, component.DefaultColor, Color.Transparent);
                    component.DisabledColor = ToolBox.GradientLerp(lerp, component.Style.DisabledColor, Color.Transparent);
                    component.HoverColor    = ToolBox.GradientLerp(lerp, component.Style.HoverColor, Color.Transparent);

                    foreach (var child in component.GetAllChildren())
                    {
                        Color gradient = ToolBox.GradientLerp(lerp, child.DefaultColor, Color.Transparent);
                        child.Color = child.HoverColor = gradient;
                        if (child is GUITextBlock block)
                        {
                            block.TextColor = block.HoverTextColor = gradient;
                        }
                    }
                }
            }

            if (SmoothScroll)
            {
                if (targetScroll > -1)
                {
                    float distance = Math.Abs(targetScroll - BarScroll);
                    float speed    = Math.Max(distance * BarSize, 0.1f);
                    BarScroll = (1.0f - speed) * BarScroll + speed * targetScroll;
                    if (MathUtils.NearlyEqual(BarScroll, targetScroll) || GUIScrollBar.DraggingBar != null)
                    {
                        targetScroll  = -1;
                        pendingScroll = null;
                    }
                }
            }

            if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && AllowMouseWheelScroll && PlayerInput.ScrollWheelSpeed != 0)
            {
                float speed = PlayerInput.ScrollWheelSpeed / 500.0f * BarSize;
                if (SmoothScroll)
                {
                    if (ClampScrollToElements)
                    {
                        bool scrollDown = Math.Clamp(PlayerInput.ScrollWheelSpeed, 0, 1) > 0;

                        if (scrollDown)
                        {
                            SelectPrevious(takeKeyBoardFocus: true);
                        }
                        else
                        {
                            SelectNext(takeKeyBoardFocus: true);
                        }
                    }
                    else
                    {
                        pendingScroll = null;
                        if (targetScroll < 0)
                        {
                            targetScroll = BarScroll;
                        }
                        targetScroll -= speed;
                        targetScroll  = Math.Clamp(targetScroll, ScrollBar.MinValue, ScrollBar.MaxValue);
                    }
                }
                else
                {
                    ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
                }
            }


            ScrollBar.Enabled = ScrollBarEnabled && BarSize < 1.0f;
            if (AutoHideScrollBar)
            {
                ScrollBarVisible = ScrollBar.Enabled;
            }
            if (dimensionsNeedsRecalculation)
            {
                UpdateDimensions();
            }
        }
Esempio n. 15
0
        public LevelEditorScreen()
        {
            cam = new Camera()
            {
                MinZoom = 0.01f,
                MaxZoom = 1.0f
            };

            leftPanel = new GUIFrame(new RectTransform(new Vector2(0.07f, 0.8f), Frame.RectTransform)
            {
                MinSize = new Point(150, 0)
            },
                                     style: "GUIFrameLeft");
            var paddedLeftPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), leftPanel.RectTransform, Anchor.CenterLeft)
            {
                RelativeOffset = new Vector2(0.02f, 0.0f)
            })
            {
                Stretch         = true,
                RelativeSpacing = 0.01f
            };

            paramsList             = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.3f), paddedLeftPanel.RectTransform));
            paramsList.OnSelected += (GUIComponent component, object obj) =>
            {
                selectedParams = obj as LevelGenerationParams;
                editorContainer.ClearChildren();
                SortLevelObjectsList(selectedParams);
                new SerializableEntityEditor(editorContainer.Content.RectTransform, selectedParams, false, true, elementHeight: 20);
                return(true);
            };

            ruinParamsList             = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), paddedLeftPanel.RectTransform));
            ruinParamsList.OnSelected += (GUIComponent component, object obj) =>
            {
                var ruinGenerationParams = obj as RuinGenerationParams;
                editorContainer.ClearChildren();
                new SerializableEntityEditor(editorContainer.Content.RectTransform, ruinGenerationParams, false, true, elementHeight: 20);
                return(true);
            };

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
                          "Create Level Object")
            {
                OnClicked = (btn, obj) =>
                {
                    Wizard.Instance.Create();
                    return(true);
                }
            };

            lightingEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform),
                                             TextManager.Get("LevelEditorLightingEnabled"));

            cursorLightEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.025f), paddedLeftPanel.RectTransform),
                                                TextManager.Get("LevelEditorCursorLightEnabled"));

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
                          TextManager.Get("LevelEditorReloadTextures"))
            {
                OnClicked = (btn, obj) =>
                {
                    Level.Loaded?.ReloadTextures();
                    return(true);
                }
            };

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedLeftPanel.RectTransform),
                          TextManager.Get("LevelEditorSaveAll"))
            {
                OnClicked = (btn, obj) =>
                {
                    SerializeAll();
                    return(true);
                }
            };

            rightPanel = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), Frame.RectTransform, Anchor.TopRight)
            {
                MinSize = new Point(450, 0)
            },
                                      style: "GUIFrameRight");
            var paddedRightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), rightPanel.RectTransform, Anchor.Center)
            {
                RelativeOffset = new Vector2(0.02f, 0.0f)
            })
            {
                Stretch         = true,
                RelativeSpacing = 0.01f
            };

            editorContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), paddedRightPanel.RectTransform));

            var seedContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform), isHorizontal: true);

            new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), TextManager.Get("LevelEditorLevelSeed"));
            seedBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), ToolBox.RandomSeed(8));

            new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
                          TextManager.Get("LevelEditorGenerate"))
            {
                OnClicked = (btn, obj) =>
                {
                    Submarine.Unload();
                    GameMain.LightManager.ClearLights();
                    Level.CreateRandom(seedBox.Text, generationParams: selectedParams).Generate(mirror: false);
                    GameMain.LightManager.AddLight(pointerLightSource);
                    cam.Position = new Vector2(Level.Loaded.Size.X / 2, Level.Loaded.Size.Y / 2);
                    foreach (GUITextBlock param in paramsList.Content.Children)
                    {
                        param.TextColor = param.UserData == selectedParams ? Color.LightGreen : param.Style.textColor;
                    }
                    seedBox.Deselect();
                    return(true);
                }
            };

            bottomPanel = new GUIFrame(new RectTransform(new Vector2(0.75f, 0.2f), Frame.RectTransform, Anchor.BottomLeft)
            {
                MaxSize = new Point(GameMain.GraphicsWidth - rightPanel.Rect.Width, 1000)
            }, style: "GUIFrameBottom");

            levelObjectList = new GUIListBox(new RectTransform(new Vector2(0.99f, 0.85f), bottomPanel.RectTransform, Anchor.Center))
            {
                UseGridLayout = true
            };
            levelObjectList.OnSelected += (GUIComponent component, object obj) =>
            {
                selectedLevelObject = obj as LevelObjectPrefab;
                CreateLevelObjectEditor(selectedLevelObject);
                return(true);
            };

            spriteEditDoneButton = new GUIButton(new RectTransform(new Point(200, 30), anchor: Anchor.BottomRight)
            {
                AbsoluteOffset = new Point(20, 20)
            },
                                                 TextManager.Get("LevelEditorSpriteEditDone"))
            {
                OnClicked = (btn, userdata) =>
                {
                    editingSprite = null;
                    return(true);
                }
            };

            topPanel = new GUIFrame(new RectTransform(new Point(400, 100), GUI.Canvas)
            {
                RelativeOffset = new Vector2(leftPanel.RectTransform.RelativeSize.X * 2, 0.0f)
            }, style: "GUIFrameTop");
        }
        public void SetTextPos()
        {
            if (text == null)
            {
                return;
            }

            censoredText = string.IsNullOrEmpty(text) ? "" : new string('\u2022', text.Length);

            var rect = Rect;

            overflowClipActive = false;
            wrappedText        = text;

            TextSize = MeasureText(text);

            if (Wrap && rect.Width > 0)
            {
                wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale, playerInput);
                TextSize    = MeasureText(wrappedText);
            }
            else if (OverflowClip)
            {
                overflowClipActive = TextSize.X > rect.Width - padding.X - padding.Z;
            }

            Vector2 minSize = new Vector2(
                Math.Max(rect.Width - padding.X - padding.Z, 5.0f),
                Math.Max(rect.Height - padding.Y - padding.W, 5.0f));

            if (!autoScaleHorizontal)
            {
                minSize.X = float.MaxValue;
            }
            if (!Wrap && !autoScaleVertical)
            {
                minSize.Y = float.MaxValue;
            }

            if ((autoScaleHorizontal || autoScaleVertical) && textScale > 0.1f &&
                (TextSize.X * textScale > minSize.X || TextSize.Y * textScale > minSize.Y))
            {
                TextScale = Math.Max(0.1f, Math.Min(minSize.X / TextSize.X, minSize.Y / TextSize.Y)) - 0.01f;
                return;
            }

            textPos = new Vector2(padding.X + (rect.Width - padding.Z - padding.X) / 2.0f, padding.Y + (rect.Height - padding.Y - padding.W) / 2.0f);
            origin  = TextSize * 0.5f;

            if (textAlignment.HasFlag(Alignment.Left) && !overflowClipActive)
            {
                textPos.X = padding.X;
                origin.X  = 0;
            }
            if (textAlignment.HasFlag(Alignment.Right) || overflowClipActive)
            {
                textPos.X = rect.Width - padding.Z;
                origin.X  = TextSize.X;
            }
            if (textAlignment.HasFlag(Alignment.Top))
            {
                textPos.Y = padding.Y;
                origin.Y  = 0;
            }
            if (textAlignment.HasFlag(Alignment.Bottom))
            {
                textPos.Y = rect.Height - padding.W;
                origin.Y  = TextSize.Y;
            }

            origin.X = (int)(origin.X);
            origin.Y = (int)(origin.Y);

            textPos.X = (int)textPos.X;
            textPos.Y = (int)textPos.Y;
        }
Esempio n. 17
0
 public override string ToDebugString()
 {
     return($"{ToolBox.GetDebugSymbol(isFinished)} {nameof(NPCFollowAction)} -> (NPCTag: {NPCTag.ColorizeObject()}, TargetTag: {TargetTag.ColorizeObject()}, Follow: {Follow.ColorizeObject()})");
 }
Esempio n. 18
0
        private void CreateEvents()
        {
            //don't create new events if docked to the start oupost
            if (Level.Loaded?.StartOutpost != null &&
                Submarine.MainSub.DockedTo.Contains(Level.Loaded.StartOutpost))
            {
                return;
            }

            for (int i = selectedEventSets.Count - 1; i >= 0; i--)
            {
                ScriptedEventSet eventSet = selectedEventSets[i];

                float distFromStart = Vector2.Distance(Submarine.MainSub.WorldPosition, level.StartPosition);
                float distFromEnd   = Vector2.Distance(Submarine.MainSub.WorldPosition, level.EndPosition);

                float distanceTraveled = MathHelper.Clamp(
                    (Submarine.MainSub.WorldPosition.X - level.StartPosition.X) / (level.EndPosition.X - level.StartPosition.X),
                    0.0f, 1.0f);

                //don't create new events if within 50 meters of the start/end of the level
                if (distanceTraveled <= 0.0f ||
                    distFromStart * Physics.DisplayToRealWorldRatio < 50.0f ||
                    distFromEnd * Physics.DisplayToRealWorldRatio < 50.0f)
                {
                    continue;
                }

                if ((Submarine.MainSub == null || distanceTraveled < eventSet.MinDistanceTraveled) &&
                    roundDuration < eventSet.MinMissionTime)
                {
                    continue;
                }

                if (CurrentIntensity < eventSet.MinIntensity || CurrentIntensity > eventSet.MaxIntensity)
                {
                    continue;
                }

                selectedEventSets.RemoveAt(i);

                if (eventSet.ChooseRandom)
                {
                    if (eventSet.EventPrefabs.Count > 0)
                    {
                        MTRandom rand        = new MTRandom(ToolBox.StringToInt(level.Seed));
                        var      eventPrefab = ToolBox.SelectWeightedRandom(eventSet.EventPrefabs, eventSet.EventPrefabs.Select(e => e.Commonness).ToList(), rand);
                        if (eventPrefab != null)
                        {
                            var newEvent = eventPrefab.CreateInstance();
                            newEvent.Init(true);
                            DebugConsole.Log("Initialized event " + newEvent.ToString());
                            events.Add(newEvent);
                        }
                    }
                    if (eventSet.ChildSets.Count > 0)
                    {
                        var newEventSet = SelectRandomEvents(eventSet.ChildSets);
                        if (newEventSet != null)
                        {
                            selectedEventSets.Add(newEventSet);
                        }
                    }
                }
                else
                {
                    foreach (ScriptedEventPrefab eventPrefab in eventSet.EventPrefabs)
                    {
                        var newEvent = eventPrefab.CreateInstance();
                        newEvent.Init(true);
                        DebugConsole.Log("Initialized event " + newEvent.ToString());
                        events.Add(newEvent);
                    }

                    selectedEventSets.AddRange(eventSet.ChildSets);
                }
            }
        }
Esempio n. 19
0
 public void RandomizeSeed()
 {
     seedBox.Text = ToolBox.RandomSeed(8);
 }
Esempio n. 20
0
 public override string ToDebugString()
 {
     return($"{ToolBox.GetDebugSymbol(isFinished)} {nameof(ReputationAction)} -> (FactionIdentifier: {Identifier.ColorizeObject()}, TargetType: {TargetType.ColorizeObject()}, Increase: {Increase.ColorizeObject()})");
 }
Esempio n. 21
0
        private void Start(GameServer server, int traitorCount)
        {
            if (server == null)
            {
                return;
            }

            List <Character> characters        = new List <Character>(); //ANYONE can be a target.
            List <Character> traitorCandidates = new List <Character>(); //Keep this to not re-pick traitors twice

            foreach (Client client in server.ConnectedClients)
            {
                if (client.Character != null)
                {
                    characters.Add(client.Character);
                    traitorCandidates.Add(client.Character);
                }
            }

            if (server.Character != null)
            {
                characters.Add(server.Character); //Add host character
                traitorCandidates.Add(server.Character);
            }

            if (characters.Count < 2)
            {
                return;
            }

            codeWords    = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt);
            codeResponse = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt);

            while (traitorCount-- > 0)
            {
                if (traitorCandidates.Count <= 0)
                {
                    break;
                }

                int       traitorIndex     = Rand.Int(traitorCandidates.Count);
                Character traitorCharacter = traitorCandidates[traitorIndex];
                traitorCandidates.Remove(traitorCharacter);

                //Add them to the list
                traitorList.Add(new Traitor(traitorCharacter));
            }

            //Now that traitors have been decided, let's do objectives in post for deciding things like Document Exchange.
            foreach (Traitor traitor in traitorList)
            {
                Character traitorCharacter = traitor.Character;
                int       targetIndex      = Rand.Int(characters.Count);
                while (characters[targetIndex] == traitorCharacter) //Cannot target self
                {
                    targetIndex = Rand.Int(characters.Count);
                }

                Character targetCharacter = characters[targetIndex];
                traitor.TargetCharacter = targetCharacter;
                traitor.Greet(server, codeWords, codeResponse);
            }
        }
Esempio n. 22
0
        private void ProgressWorld()
        {
            foreach (Location location in Locations)
            {
                if (furthestDiscoveredLocation == null ||
                    location.MapPosition.X > furthestDiscoveredLocation.MapPosition.X)
                {
                    furthestDiscoveredLocation = location;
                }
            }

            foreach (Location location in Locations)
            {
                if (location.MapPosition.X < furthestDiscoveredLocation.MapPosition.X)
                {
                    furthestDiscoveredLocation = location;
                }

                if (location == CurrentLocation || location == SelectedLocation)
                {
                    continue;
                }

                //find which types of locations this one can change to
                var cct = location.Type.CanChangeTo;
                List <LocationTypeChange> allowedTypeChanges = new List <LocationTypeChange>();
                List <int> readyTypeChanges = new List <int>();
                for (int i = 0; i < cct.Count; i++)
                {
                    LocationTypeChange typeChange = cct[i];
                    if (typeChange.RequireDiscovered && !location.Discovered)
                    {
                        continue;
                    }
                    //check if there are any adjacent locations that would prevent the change
                    bool disallowedFound = false;
                    foreach (string disallowedLocationName in typeChange.DisallowedAdjacentLocations)
                    {
                        if (location.Connections.Any(c => c.OtherLocation(location).Type.Identifier.Equals(disallowedLocationName, StringComparison.OrdinalIgnoreCase)))
                        {
                            disallowedFound = true;
                            break;
                        }
                    }
                    if (disallowedFound)
                    {
                        continue;
                    }

                    //check that there's a required adjacent location present
                    bool requiredFound = false;
                    foreach (string requiredLocationName in typeChange.RequiredAdjacentLocations)
                    {
                        if (location.Connections.Any(c => c.OtherLocation(location).Type.Identifier.Equals(requiredLocationName, StringComparison.OrdinalIgnoreCase)))
                        {
                            requiredFound = true;
                            break;
                        }
                    }
                    if (!requiredFound && typeChange.RequiredAdjacentLocations.Count > 0)
                    {
                        continue;
                    }

                    allowedTypeChanges.Add(typeChange);

                    if (location.TypeChangeTimer >= typeChange.RequiredDuration)
                    {
                        readyTypeChanges.Add(i);
                    }
                }

                List <float> readyTypeProbabilities = readyTypeChanges.Select(i => cct[i].DetermineProbability(location)).ToList();
                //select a random type change
                if (Rand.Range(0.0f, 1.0f) < readyTypeChanges.Sum(i => readyTypeProbabilities[i]))
                {
                    var selectedTypeChangeIndex =
                        ToolBox.SelectWeightedRandom(
                            readyTypeChanges,
                            readyTypeChanges.Select(i => readyTypeProbabilities[i]).ToList(),
                            Rand.RandSync.Unsynced);
                    var selectedTypeChange = cct[selectedTypeChangeIndex];
                    if (selectedTypeChange != null)
                    {
                        string prevName = location.Name;
                        location.ChangeType(LocationType.List.Find(lt => lt.Identifier.Equals(selectedTypeChange.ChangeToType, StringComparison.OrdinalIgnoreCase)));
                        ChangeLocationType(location, prevName, selectedTypeChange);
                        location.TypeChangeTimer = -1;
                    }
                }

                if (allowedTypeChanges.Count > 0)
                {
                    location.TypeChangeTimer++;
                }
                else
                {
                    location.TypeChangeTimer = 0;
                }

                location.UpdateStore();
            }
        }
Esempio n. 23
0
        public override void Update(float deltaTime)
        {
            if (disallowed)
            {
                Finished();
                return;
            }

            if (isFinished)
            {
                return;
            }

            if (spawnPos == null)
            {
                if (maxAmountPerLevel < int.MaxValue)
                {
                    if (Character.CharacterList.Count(c => c.SpeciesName == speciesName) >= maxAmountPerLevel)
                    {
                        disallowed = true;
                        return;
                    }
                }

                FindSpawnPosition(affectSubImmediately: true);
                //the event gets marked as finished if a spawn point is not found
                if (isFinished)
                {
                    return;
                }
                spawnPending = true;
            }

            bool spawnReady = false;

            if (spawnPending)
            {
                //wait until there are no submarines at the spawnpos
                if (spawnPosType.HasFlag(Level.PositionType.MainPath) || spawnPosType.HasFlag(Level.PositionType.SidePath) || spawnPosType.HasFlag(Level.PositionType.Abyss))
                {
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineType.Player)
                        {
                            continue;
                        }
                        float minDist = GetMinDistanceToSub(submarine);
                        if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos.Value) < minDist * minDist)
                        {
                            return;
                        }
                    }
                }

                //if spawning in a ruin/cave, wait for someone to be close to it to spawning
                //unnecessary monsters in places the players might never visit during the round
                if (spawnPosType.HasFlag(Level.PositionType.Ruin) || spawnPosType.HasFlag(Level.PositionType.Cave) || spawnPosType.HasFlag(Level.PositionType.Wreck))
                {
                    bool  someoneNearby = false;
                    float minDist       = Sonar.DefaultSonarRange * 0.8f;
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineType.Player)
                        {
                            continue;
                        }
                        if (Vector2.DistanceSquared(submarine.WorldPosition, spawnPos.Value) < minDist * minDist)
                        {
                            someoneNearby = true;
                            break;
                        }
                    }
                    foreach (Character c in Character.CharacterList)
                    {
                        if (c == Character.Controlled || c.IsRemotePlayer)
                        {
                            if (Vector2.DistanceSquared(c.WorldPosition, spawnPos.Value) < minDist * minDist)
                            {
                                someoneNearby = true;
                                break;
                            }
                        }
                    }
                    if (!someoneNearby)
                    {
                        return;
                    }
                }


                if (spawnPosType.HasFlag(Level.PositionType.Abyss) || spawnPosType.HasFlag(Level.PositionType.AbyssCave))
                {
                    bool anyInAbyss = false;
                    foreach (Submarine submarine in Submarine.Loaded)
                    {
                        if (submarine.Info.Type != SubmarineType.Player || submarine == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle)
                        {
                            continue;
                        }
                        if (submarine.WorldPosition.Y < 0)
                        {
                            anyInAbyss = true;
                            break;
                        }
                    }
                    if (!anyInAbyss)
                    {
                        return;
                    }
                }

                spawnPending = false;

                //+1 because Range returns an integer less than the max value
                int amount = Rand.Range(minAmount, maxAmount + 1);
                monsters = new List <Character>();
                float scatterAmount = scatter;
                if (spawnPosType.HasFlag(Level.PositionType.SidePath))
                {
                    var sidePaths = Level.Loaded.Tunnels.Where(t => t.Type == Level.TunnelType.SidePath);
                    if (sidePaths.Any())
                    {
                        scatterAmount = Math.Min(scatter, sidePaths.Min(t => t.MinWidth) / 2);
                    }
                    else
                    {
                        scatterAmount = scatter;
                    }
                }
                else if (!spawnPosType.HasFlag(Level.PositionType.MainPath))
                {
                    scatterAmount = 0;
                }
                for (int i = 0; i < amount; i++)
                {
                    string seed = Level.Loaded.Seed + i.ToString();
                    CoroutineManager.InvokeAfter(() =>
                    {
                        //round ended before the coroutine finished
                        if (GameMain.GameSession == null || Level.Loaded == null)
                        {
                            return;
                        }

                        System.Diagnostics.Debug.Assert(GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer, "Clients should not create monster events.");

                        Vector2 pos = spawnPos.Value + Rand.Vector(scatterAmount);
                        if (scatterAmount > 0)
                        {
                            if (Submarine.Loaded.Any(s => ToolBox.GetWorldBounds(s.Borders.Center, s.Borders.Size).ContainsWorld(pos)))
                            {
                                // Can't use the offset position, let's use the exact spawn position.
                                pos = spawnPos.Value;
                            }
                            else if (Level.Loaded.Ruins.Any(r => ToolBox.GetWorldBounds(r.Area.Center, r.Area.Size).ContainsWorld(pos)))
                            {
                                // Can't use the offset position, let's use the exact spawn position.
                                pos = spawnPos.Value;
                            }
                        }

                        Character createdCharacter = Character.Create(speciesName, pos, seed, characterInfo: null, isRemotePlayer: false, hasAi: true, createNetworkEvent: true);
                        if (GameMain.GameSession.IsCurrentLocationRadiated())
                        {
                            AfflictionPrefab radiationPrefab = AfflictionPrefab.RadiationSickness;
                            Affliction affliction            = new Affliction(radiationPrefab, radiationPrefab.MaxStrength);
                            createdCharacter?.CharacterHealth.ApplyAffliction(null, affliction);
                            // TODO test multiplayer
                            createdCharacter?.Kill(CauseOfDeathType.Affliction, affliction, log: false);
                        }
                        monsters.Add(createdCharacter);

                        if (monsters.Count == amount)
                        {
                            spawnReady = true;
                            //this will do nothing if the monsters have no swarm behavior defined,
                            //otherwise it'll make the spawned characters act as a swarm
                            SwarmBehavior.CreateSwarm(monsters.Cast <AICharacter>());
                        }
                    }, Rand.Range(0f, amount / 2f));
                }
            }

            if (!spawnReady)
            {
                return;
            }

            Entity targetEntity = Submarine.FindClosest(GameMain.GameScreen.Cam.WorldViewCenter);

#if CLIENT
            if (Character.Controlled != null)
            {
                targetEntity = Character.Controlled;
            }
#endif

            bool monstersDead = true;
            foreach (Character monster in monsters)
            {
                if (!monster.IsDead)
                {
                    monstersDead = false;

                    if (targetEntity != null && Vector2.DistanceSquared(monster.WorldPosition, targetEntity.WorldPosition) < 5000.0f * 5000.0f)
                    {
                        break;
                    }
                }
            }

            if (monstersDead)
            {
                Finished();
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Load a previously saved campaign map from XML
        /// </summary>
        private Map(CampaignMode campaign, XElement element) : this()
        {
            Seed = element.GetAttributeString("seed", "a");
            Rand.SetSyncedSeed(ToolBox.StringToInt(Seed));
            foreach (XElement subElement in element.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "location":
                    int i = subElement.GetAttributeInt("i", 0);
                    while (Locations.Count <= i)
                    {
                        Locations.Add(null);
                    }
                    Locations[i] = new Location(subElement);
                    break;
                }
            }
            System.Diagnostics.Debug.Assert(!Locations.Contains(null));
            for (int i = 0; i < Locations.Count; i++)
            {
                Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, $"location.{i}", -100, 100, Rand.Range(-10, 10, Rand.RandSync.Server));
            }

            foreach (XElement subElement in element.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "connection":
                    Point locationIndices = subElement.GetAttributePoint("locations", new Point(0, 1));
                    var   connection      = new LocationConnection(Locations[locationIndices.X], Locations[locationIndices.Y])
                    {
                        Passed     = subElement.GetAttributeBool("passed", false),
                        Difficulty = subElement.GetAttributeFloat("difficulty", 0.0f)
                    };
                    Locations[locationIndices.X].Connections.Add(connection);
                    Locations[locationIndices.Y].Connections.Add(connection);
                    connection.LevelData = new LevelData(subElement.Element("Level"));
                    string biomeId = subElement.GetAttributeString("biome", "");
                    connection.Biome =
                        LevelGenerationParams.GetBiomes().FirstOrDefault(b => b.Identifier == biomeId) ??
                        LevelGenerationParams.GetBiomes().FirstOrDefault(b => b.OldIdentifier == biomeId) ??
                        LevelGenerationParams.GetBiomes().First();
                    Connections.Add(connection);
                    break;
                }
            }

            int startLocationindex = element.GetAttributeInt("startlocation", -1);

            if (startLocationindex > 0 && startLocationindex < Locations.Count)
            {
                StartLocation = Locations[startLocationindex];
            }
            else
            {
                DebugConsole.AddWarning($"Error while loading the map. Start location index out of bounds (index: {startLocationindex}, location count: {Locations.Count}).");
                foreach (Location location in Locations)
                {
                    if (!location.Type.HasOutpost)
                    {
                        continue;
                    }
                    if (StartLocation == null || location.MapPosition.X < StartLocation.MapPosition.X)
                    {
                        StartLocation = location;
                    }
                }
            }
            int endLocationindex = element.GetAttributeInt("endlocation", -1);

            if (endLocationindex > 0 && endLocationindex < Locations.Count)
            {
                EndLocation = Locations[endLocationindex];
            }
            else
            {
                DebugConsole.AddWarning($"Error while loading the map. End location index out of bounds (index: {endLocationindex}, location count: {Locations.Count}).");
                foreach (Location location in Locations)
                {
                    if (EndLocation == null || location.MapPosition.X > EndLocation.MapPosition.X)
                    {
                        EndLocation = location;
                    }
                }
            }

            InitProjectSpecific();
        }
Esempio n. 25
0
        private void CreateCharacterElement(CharacterInfo characterInfo, GUIListBox listBox)
        {
            GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, GUI.IntScale(45)), listBox.Content.RectTransform), style: "ListBoxElement")
            {
                CanBeFocused = false,
                UserData     = characterInfo,
                Color        = (Character.Controlled?.Info == characterInfo) ? TabMenu.OwnCharacterBGColor : Color.Transparent
            };

            var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
            {
                AbsoluteSpacing = 2,
                Stretch         = true
            };

            new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => characterInfo.DrawJobIcon(sb, component.Rect))
            {
                ToolTip       = characterInfo.Job.Name ?? "",
                HoverColor    = Color.White,
                SelectedColor = Color.White
            };

            GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
                                                               ToolBox.LimitString(characterInfo.Name, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: characterInfo.Job.Prefab.UIColor);

            string statusText  = TextManager.Get("StatusOK");
            Color  statusColor = GUI.Style.Green;

            Character character = characterInfo.Character;

            if (character == null || character.IsDead)
            {
                if (character == null && characterInfo.IsNewHire && characterInfo.CauseOfDeath == null)
                {
                    statusText  = TextManager.Get("CampaignCrew.NewHire");
                    statusColor = GUI.Style.Blue;
                }
                else if (characterInfo.CauseOfDeath == null)
                {
                    statusText  = TextManager.Get("CauseOfDeathDescription.Unknown");
                    statusColor = Color.DarkRed;
                }
                else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null)
                {
                    string errorMsg = "Character \"" + characterInfo.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
                    DebugConsole.ThrowError(errorMsg);
                    GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
                    statusText  = TextManager.Get("CauseOfDeathDescription.Unknown");
                    statusColor = GUI.Style.Red;
                }
                else
                {
                    statusText = characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction ?
                                 characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription :
                                 TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString());
                    statusColor = Color.DarkRed;
                }
            }
            else
            {
                if (character.IsUnconscious)
                {
                    statusText  = TextManager.Get("Unconscious");
                    statusColor = Color.DarkOrange;
                }
                else if (character.Vitality / character.MaxVitality < 0.8f)
                {
                    statusText  = TextManager.Get("Injured");
                    statusColor = Color.DarkOrange;
                }
            }

            GUITextBlock statusBlock = new GUITextBlock(new RectTransform(new Point(statusColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
                                                        ToolBox.LimitString(statusText, GUI.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: statusColor);
        }
Esempio n. 26
0
        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);
            }
        }
Esempio n. 27
0
        private void QuickStart()
        {
            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.Identifier == "devsandbox"),
                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;
                }
                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;
            }
        }
Esempio n. 28
0
 public static Mission LoadRandom(Location[] locations, string seed, bool requireCorrectLocationType, MissionType missionType, bool isSinglePlayer = false)
 {
     return(LoadRandom(locations, new MTRandom(ToolBox.StringToInt(seed)), requireCorrectLocationType, missionType, isSinglePlayer));
 }
Esempio n. 29
0
            protected List <Tuple <string, Tuple <Client, Character> > > AssignTraitors(GameServer server, TraitorManager traitorManager, Character.TeamType team)
            {
                List <Character> characters = FindCharacters();

#if !ALLOW_SOLO_TRAITOR
                if (characters.Count < 2)
                {
                    return(null);
                }
#endif
                var roleCandidates = new Dictionary <string, HashSet <Tuple <Client, Character> > >();
                foreach (var role in Roles)
                {
                    roleCandidates.Add(role.Key, new HashSet <Tuple <Client, Character> >(FindTraitorCandidates(server, team, role.Value)));
                    if (roleCandidates[role.Key].Count <= 0)
                    {
                        return(null);
                    }
                }
                var candidateRoleCounts = new Dictionary <Tuple <Client, Character>, int>();
                foreach (var candidateEntry in roleCandidates)
                {
                    foreach (var candidate in candidateEntry.Value)
                    {
                        candidateRoleCounts[candidate] = candidateRoleCounts.TryGetValue(candidate, out var count) ? count + 1 : 1;
                    }
                }
                var unassignedRoles = new List <string>(roleCandidates.Keys);
                unassignedRoles.Sort((a, b) => roleCandidates[a].Count - roleCandidates[b].Count);
                var assignedCandidates = new List <Tuple <string, Tuple <Client, Character> > >();
                while (unassignedRoles.Count > 0)
                {
                    var currentRole         = unassignedRoles[0];
                    var availableCandidates = roleCandidates[currentRole].ToList();
                    if (availableCandidates.Count <= 0)
                    {
                        break;
                    }
                    unassignedRoles.RemoveAt(0);
                    availableCandidates.Sort((a, b) => candidateRoleCounts[b] - candidateRoleCounts[a]);
                    unassignedRoles.Sort((a, b) => roleCandidates[a].Count - roleCandidates[b].Count);

                    int numCandidates = 1;
                    for (int i = 1; i < availableCandidates.Count && candidateRoleCounts[availableCandidates[i]] == candidateRoleCounts[availableCandidates[0]]; ++i)
                    {
                        ++numCandidates;
                    }

                    var selected = ToolBox.SelectWeightedRandom(availableCandidates, availableCandidates.Select(c => Math.Max(c.Item1.RoundsSincePlayedAsTraitor, 0.1f)).ToList(), TraitorManager.Random);
                    assignedCandidates.Add(Tuple.Create(currentRole, selected));
                    foreach (var candidate in roleCandidates.Values)
                    {
                        candidate.Remove(selected);
                    }
                }
                if (unassignedRoles.Count > 0)
                {
                    return(null);
                }
                return(assignedCandidates);
            }
        public void PlaceNestObjects(Level level, Level.Cave cave, Vector2 nestPosition, float nestRadius, int objectAmount)
        {
            Rand.SetSyncedSeed(ToolBox.StringToInt(level.Seed));

            var availablePrefabs = new List <LevelObjectPrefab>(LevelObjectPrefab.List.FindAll(p => p.SpawnPos.HasFlag(LevelObjectPrefab.SpawnPosType.NestWall)));
            Dictionary <LevelObjectPrefab, List <SpawnPosition> > suitableSpawnPositions = new Dictionary <LevelObjectPrefab, List <SpawnPosition> >();
            Dictionary <LevelObjectPrefab, List <float> >         spawnPositionWeights   = new Dictionary <LevelObjectPrefab, List <float> >();

            List <SpawnPosition> availableSpawnPositions = new List <SpawnPosition>();
            var caveCells = cave.Tunnels.SelectMany(t => t.Cells);
            List <VoronoiCell> caveWallCells = new List <VoronoiCell>();

            foreach (var edge in caveCells.SelectMany(c => c.Edges))
            {
                if (!edge.NextToCave)
                {
                    continue;
                }
                if (MathUtils.LineSegmentToPointDistanceSquared(edge.Point1.ToPoint(), edge.Point2.ToPoint(), nestPosition.ToPoint()) > nestRadius * nestRadius)
                {
                    continue;
                }
                if (edge.Cell1?.CellType == CellType.Solid)
                {
                    caveWallCells.Add(edge.Cell1);
                }
                if (edge.Cell2?.CellType == CellType.Solid)
                {
                    caveWallCells.Add(edge.Cell2);
                }
            }
            availableSpawnPositions.AddRange(GetAvailableSpawnPositions(caveWallCells.Distinct(), LevelObjectPrefab.SpawnPosType.CaveWall));

            for (int i = 0; i < objectAmount; i++)
            {
                //get a random prefab and find a place to spawn it
                LevelObjectPrefab prefab = GetRandomPrefab(cave.CaveGenerationParams, availablePrefabs, requireCaveSpecificOverride: false);
                if (prefab == null)
                {
                    continue;
                }
                if (!suitableSpawnPositions.ContainsKey(prefab))
                {
                    suitableSpawnPositions.Add(prefab,
                                               availableSpawnPositions.Where(sp =>
                                                                             sp.Length >= prefab.MinSurfaceWidth &&
                                                                             (sp.Alignment == Alignment.Any || prefab.Alignment.HasFlag(sp.Alignment))).ToList());
                    spawnPositionWeights.Add(prefab,
                                             suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
                }
                SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
                if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None)
                {
                    continue;
                }
                PlaceObject(prefab, spawnPosition, level);
                if (objects.Count(o => o.Prefab == prefab) >= prefab.MaxCount)
                {
                    availablePrefabs.Remove(prefab);
                }
            }
        }