/// <summary> /// Instantiates level data using the properties of the connection (seed, size, difficulty) /// </summary> public LevelData(LocationConnection locationConnection) { Seed = locationConnection.Locations[0].BaseName + locationConnection.Locations[1].BaseName; Biome = locationConnection.Biome; Type = LevelType.LocationConnection; GenerationParams = LevelGenerationParams.GetRandom(Seed, LevelType.LocationConnection, Biome); Difficulty = locationConnection.Difficulty; float sizeFactor = MathUtils.InverseLerp( MapGenerationParams.Instance.SmallLevelConnectionLength, MapGenerationParams.Instance.LargeLevelConnectionLength, locationConnection.Length); int width = (int)MathHelper.Lerp(GenerationParams.MinWidth, GenerationParams.MaxWidth, sizeFactor); Size = new Point( (int)MathUtils.Round(width, Level.GridCellSize), (int)MathUtils.Round(GenerationParams.Height, Level.GridCellSize)); var rand = new MTRandom(ToolBox.StringToInt(Seed)); InitialDepth = (int)MathHelper.Lerp(GenerationParams.InitialDepthMin, GenerationParams.InitialDepthMax, (float)rand.NextDouble()); HasBeaconStation = rand.NextDouble() < locationConnection.Locations.Select(l => l.Type.BeaconStationChance).Max(); IsBeaconActive = false; }
/// <summary> /// Instantiates level data using the properties of the connection (seed, size, difficulty) /// </summary> public LevelData(LocationConnection locationConnection) { Seed = locationConnection.Locations[0].BaseName + locationConnection.Locations[1].BaseName; Biome = locationConnection.Biome; Type = LevelType.LocationConnection; GenerationParams = LevelGenerationParams.GetRandom(Seed, LevelType.LocationConnection, Biome); Difficulty = locationConnection.Difficulty; float sizeFactor = MathUtils.InverseLerp( MapGenerationParams.Instance.SmallLevelConnectionLength, MapGenerationParams.Instance.LargeLevelConnectionLength, locationConnection.Length); int width = (int)MathHelper.Lerp(GenerationParams.MinWidth, GenerationParams.MaxWidth, sizeFactor); Size = new Point( (int)MathUtils.Round(width, Level.GridCellSize), (int)MathUtils.Round(GenerationParams.Height, Level.GridCellSize)); var rand = new MTRandom(ToolBox.StringToInt(Seed)); InitialDepth = (int)MathHelper.Lerp(GenerationParams.InitialDepthMin, GenerationParams.InitialDepthMax, (float)rand.NextDouble()); //minimum difficulty of the level before hunting grounds can appear float huntingGroundsDifficultyThreshold = 25; //probability of hunting grounds appearing in 100% difficulty levels float maxHuntingGroundsProbability = 0.3f; HasHuntingGrounds = OriginallyHadHuntingGrounds = rand.NextDouble() < MathUtils.InverseLerp(huntingGroundsDifficultyThreshold, 100.0f, Difficulty) * maxHuntingGroundsProbability; HasBeaconStation = !HasHuntingGrounds && rand.NextDouble() < locationConnection.Locations.Select(l => l.Type.BeaconStationChance).Max(); IsBeaconActive = false; }
public void SelectLocation(Location location, LocationConnection connection) { GUIComponent locationPanel = bottomPanel[(int)PanelTab.Map].GetChild("selectedlocation"); if (locationPanel != null) { bottomPanel[(int)PanelTab.Map].RemoveChild(locationPanel); } locationPanel = new GUIFrame(new Rectangle(0, 0, 250, 190), Color.Transparent, Alignment.TopRight, null, bottomPanel[(int)PanelTab.Map]); locationPanel.UserData = "selectedlocation"; if (location == null) { return; } new GUITextBlock(new Rectangle(0, 0, 250, 0), location.Name, "", Alignment.TopLeft, Alignment.TopCenter, locationPanel, true, GUI.LargeFont); if (GameMain.GameSession.Map.SelectedConnection != null && GameMain.GameSession.Map.SelectedConnection.Mission != null) { var mission = GameMain.GameSession.Map.SelectedConnection.Mission; new GUITextBlock(new Rectangle(0, 80, 0, 20), "Mission: " + mission.Name, "", locationPanel); new GUITextBlock(new Rectangle(0, 100, 0, 20), "Reward: " + mission.Reward + " credits", "", locationPanel); new GUITextBlock(new Rectangle(0, 130, 0, 0), mission.Description, "", locationPanel, true); } startButton.Enabled = true; selectedLevel = connection.Level; }
private void AssignBiomes() { List <LocationConnection> biomeSeeds = new List <LocationConnection>(); List <Biome> centerBiomes = LevelGenerationParams.GetBiomes().FindAll(b => b.Placement.HasFlag(Biome.MapPlacement.Center)); if (centerBiomes.Count > 0) { Vector2 mapCenter = new Vector2(locations.Sum(l => l.MapPosition.X), locations.Sum(l => l.MapPosition.Y)) / locations.Count; foreach (Biome centerBiome in centerBiomes) { LocationConnection closestConnection = null; float closestDist = float.PositiveInfinity; foreach (LocationConnection connection in connections) { if (connection.Biome != null) { continue; } float dist = Vector2.Distance(connection.CenterPos, mapCenter); if (closestConnection == null || dist < closestDist) { closestConnection = connection; closestDist = dist; } } closestConnection.Biome = centerBiome; biomeSeeds.Add(closestConnection); } } List <Biome> edgeBiomes = LevelGenerationParams.GetBiomes().FindAll(b => b.Placement.HasFlag(Biome.MapPlacement.Edge)); if (edgeBiomes.Count > 0) { List <LocationConnection> edges = GetMapEdges(); foreach (LocationConnection edge in edges) { edge.Biome = edgeBiomes[Rand.Range(0, edgeBiomes.Count, Rand.RandSync.Server)]; } } List <Biome> randomBiomes = LevelGenerationParams.GetBiomes().FindAll(b => b.Placement.HasFlag(Biome.MapPlacement.Random)); foreach (Biome biome in randomBiomes) { LocationConnection seed = connections[0]; while (seed.Biome != null) { seed = connections[Rand.Range(0, connections.Count, Rand.RandSync.Server)]; } seed.Biome = biome; biomeSeeds.Add(seed); } ExpandBiomes(biomeSeeds); }
private void ConnectSecondaryNodes(SecondaryNode node1, SecondaryNode node2) { LocationConnection newConnection = new LocationConnection(node1, node2); connections.Add(newConnection); node1.connections.Add(newConnection); node2.connections.Add(newConnection); }
private void ConnectPrimaryNodes(PrimaryNode node1, PrimaryNode node2) { LocationConnection newConnection = new LocationConnection(node1, node2); connections.Add(newConnection); node1.connections.Add(newConnection); node2.connections.Add(newConnection); }
private void NotifyUnlock(LocationConnection connection) { foreach (Client client in GameMain.Server.ConnectedClients) { IWriteMessage outmsg = new WriteOnlyMessage(); outmsg.Write((byte)ServerPacketHeader.EVENTACTION); outmsg.Write((byte)EventManager.NetworkEventType.UNLOCKPATH); outmsg.Write((UInt16)GameMain.GameSession.Map.Connections.IndexOf(connection)); GameMain.Server.ServerPeer.Send(outmsg, client.Connection, DeliveryMethod.Reliable); } }
//DEBUG /*foreach (GraphEdge edge in graphEdges) * { * Location newLocation1; * Location newLocation2; * * if ((edge.node1 != null && edge.node2 != null) && (edge.node1.group == edge.node2.group)) * { * if (primaryNodes.Any(n => n.mapPosition == edge.node1.mapPosition) && primaryNodes.Any(n => n.mapPosition == edge.node2.mapPosition)) * { * if (!locations.Any(l => l.MapPosition == edge.node1.mapPosition)) * { * newLocation1 = Location.CreateRandom(edge.node1.mapPosition); * locations.Add(newLocation1); * } * else * newLocation1 = locations.Find(l => l.MapPosition == edge.node1.mapPosition); * if (!locations.Any(l => l.MapPosition == edge.node2.mapPosition)) * { * newLocation2 = Location.CreateRandom(edge.node2.mapPosition); * locations.Add(newLocation2); * } * else * newLocation2 = locations.Find(l => l.MapPosition == edge.node2.mapPosition); * * //connections.Add(new LocationConnection(newLocation1, newLocation2)); * ConnectLocations(newLocation1, newLocation2); * } * } * }*/ private LocationConnection ConnectLocations(Location location1, Location location2) { LocationConnection newConnection = new LocationConnection(location1, location2); connections.Add(newConnection); location1.Connections.Add(newConnection); location2.Connections.Add(newConnection); newConnection.primaryNodes = new PrimaryNode[2]; return(newConnection); }
public void SelectLocation(Location location) { if (!locations.Contains(location)) { DebugConsole.ThrowError("Failed to select a location. " + location.Name + " not found in the map."); return; } selectedLocation = location; selectedConnection = connections.Find(c => c.Locations.Contains(currentLocation) && c.Locations.Contains(selectedLocation)); OnLocationSelected?.Invoke(selectedLocation, selectedConnection); }
/// <summary> /// Instantiates level data using the properties of the connection (seed, size, difficulty) /// </summary> public LevelData(LocationConnection locationConnection) { Seed = locationConnection.Locations[0].BaseName + locationConnection.Locations[1].BaseName; Biome = locationConnection.Biome; Type = LevelType.LocationConnection; GenerationParams = LevelGenerationParams.GetRandom(Seed, LevelType.LocationConnection, Biome); Difficulty = locationConnection.Difficulty; float sizeFactor = MathUtils.InverseLerp( MapGenerationParams.Instance.SmallLevelConnectionLength, MapGenerationParams.Instance.LargeLevelConnectionLength, locationConnection.Length); int width = (int)MathHelper.Lerp(GenerationParams.MinWidth, GenerationParams.MaxWidth, sizeFactor); Size = new Point( (int)MathUtils.Round(width, Level.GridCellSize), (int)MathUtils.Round(GenerationParams.Height, Level.GridCellSize)); }
public void Update(float deltaTime, Rectangle rect, float scale = 1.0f) { Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); Vector2 offset = -currentLocation.MapPosition; float maxDist = 20.0f; float closestDist = 0.0f; highlightedLocation = null; for (int i = 0; i < locations.Count; i++) { Location location = locations[i]; Vector2 pos = rectCenter + (location.MapPosition + offset) * scale; if (!rect.Contains(pos)) { continue; } float dist = Vector2.Distance(PlayerInput.MousePosition, pos); if (dist < maxDist && (highlightedLocation == null || dist < closestDist)) { closestDist = dist; highlightedLocation = location; } } foreach (LocationConnection connection in connections) { if (highlightedLocation != currentLocation && connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation)) { if (PlayerInput.LeftButtonClicked() && selectedLocation != highlightedLocation && highlightedLocation != null) { selectedConnection = connection; selectedLocation = highlightedLocation; GameMain.LobbyScreen.SelectLocation(highlightedLocation, connection); } } } }
public void SelectLocation(Location location, LocationConnection connection) { locationInfoContainer.ClearChildren(); if (location == null) { return; } var titleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), locationInfoContainer.RectTransform, Anchor.TopCenter), location.Name, font: GUI.LargeFont); Sprite portrait = location.Type.Background; new GUIImage(new RectTransform( new Point(locationInfoContainer.Rect.Width, (int)(portrait.size.Y * (locationInfoContainer.Rect.Width / portrait.size.X))), locationInfoContainer.RectTransform), portrait, scaleToFit: true); if (GameMain.GameSession.Map.SelectedConnection != null && GameMain.GameSession.Map.SelectedConnection.Mission != null) { var mission = GameMain.GameSession.Map.SelectedConnection.Mission; new GUITextBlock( new RectTransform(new Vector2(1.0f, 0.05f), locationInfoContainer.RectTransform, Anchor.TopCenter), TextManager.Get("Mission") + ": " + mission.Name); new GUITextBlock( new RectTransform(new Vector2(1.0f, 0.05f), locationInfoContainer.RectTransform, Anchor.TopCenter), TextManager.Get("Reward").Replace("[reward]", mission.Reward.ToString())); new GUITextBlock( new RectTransform(new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform, Anchor.TopCenter), mission.Description, wrap: true); } if (startButton != null) { startButton.Enabled = true; } selectedLevel = connection?.Level; OnLocationSelected?.Invoke(location, connection); }
public void SelectLocation(int index) { if (index == -1) { selectedLocation = null; selectedConnection = null; OnLocationSelected?.Invoke(null, null); return; } if (index < 0 || index >= locations.Count) { DebugConsole.ThrowError("Location index out of bounds"); return; } selectedLocation = locations[index]; selectedConnection = connections.Find(c => c.Locations.Contains(currentLocation) && c.Locations.Contains(selectedLocation)); OnLocationSelected?.Invoke(selectedLocation, selectedConnection); }
public void SelectLocation(Location location, LocationConnection connection) { GUIComponent locationPanel = tabs[(int)Tab.Map].GetChild("selectedlocation"); if (locationPanel != null) tabs[(int)Tab.Map].RemoveChild(locationPanel); locationPanel = new GUIFrame(new Rectangle(0, 0, 250, 190), Color.Transparent, Alignment.TopRight, null, tabs[(int)Tab.Map]); locationPanel.UserData = "selectedlocation"; if (location == null) return; GUITextBlock titleText; if (GameMain.Server != null || GameMain.Client != null) { titleText = new GUITextBlock(new Rectangle(0, 10, 250, 0), location.Name, "", Alignment.TopLeft, Alignment.TopCenter, locationPanel, true, GUI.LargeFont); } else { titleText = new GUITextBlock(new Rectangle(0, 0, 250, 0), location.Name, "", Alignment.TopLeft, Alignment.TopCenter, locationPanel, true, GUI.LargeFont); } if (GameMain.GameSession.Map.SelectedConnection != null && GameMain.GameSession.Map.SelectedConnection.Mission != null) { var mission = GameMain.GameSession.Map.SelectedConnection.Mission; new GUITextBlock(new Rectangle(0, titleText.Rect.Height + 20, 0, 20), TextManager.Get("Mission") + ": " + mission.Name, "", locationPanel); new GUITextBlock(new Rectangle(0, titleText.Rect.Height + 40, 0, 20), TextManager.Get("Reward") + ": " + mission.Reward + " " + TextManager.Get("Credits"), "", locationPanel); new GUITextBlock(new Rectangle(0, titleText.Rect.Height + 70, 0, 0), mission.Description, "", Alignment.TopLeft, Alignment.TopLeft, locationPanel, true, GUI.SmallFont); } if (startButton != null) startButton.Enabled = true; selectedLevel = connection.Level; OnLocationSelected?.Invoke(location, connection); }
public void SelectLocation(Location location, LocationConnection connection) { missionTickBoxes.Clear(); missionRewardTexts.Clear(); locationInfoPanel.ClearChildren(); //don't select the map panel if we're looking at some other tab if (selectedTab == CampaignMode.InteractionType.Map) { SelectTab(CampaignMode.InteractionType.Map); locationInfoPanel.Visible = location != null; } Location prevSelectedLocation = selectedLocation; float prevMissionListScroll = missionList?.BarScroll ?? 0.0f; selectedLocation = location; if (location == null) { return; } int padding = GUI.IntScale(20); var content = new GUILayoutGroup(new RectTransform(locationInfoPanel.Rect.Size - new Point(padding * 2), locationInfoPanel.RectTransform, Anchor.Center), childAnchor: Anchor.TopRight) { Stretch = true, RelativeSpacing = 0.02f, }; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), location.Name, font: GUI.LargeFont) { AutoScaleHorizontal = true }; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), location.Type.Name, font: GUI.SubHeadingFont); Sprite portrait = location.Type.GetPortrait(location.PortraitId); portrait.EnsureLazyLoaded(); var portraitContainer = new GUICustomComponent(new RectTransform(new Vector2(1.0f, 0.3f), content.RectTransform), onDraw: (sb, customComponent) => { portrait.Draw(sb, customComponent.Rect.Center.ToVector2(), Color.Gray, portrait.size / 2, scale: Math.Max(customComponent.Rect.Width / portrait.size.X, customComponent.Rect.Height / portrait.size.Y)); }) { HideElementsOutsideFrame = true }; var textContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), portraitContainer.RectTransform, Anchor.Center)) { RelativeSpacing = 0.05f }; if (connection?.LevelData != null) { var biomeLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform), TextManager.Get("Biome", fallBackTag: "location"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft); new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), biomeLabel.RectTransform), connection.Biome.DisplayName, textAlignment: Alignment.CenterRight); var difficultyLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform), TextManager.Get("LevelDifficulty"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft); new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), difficultyLabel.RectTransform), ((int)connection.LevelData.Difficulty) + " %", textAlignment: Alignment.CenterRight); if (connection.LevelData.HasBeaconStation) { var beaconStationContent = new GUILayoutGroup(new RectTransform(biomeLabel.RectTransform.NonScaledSize, textContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft); string style = connection.LevelData.IsBeaconActive ? "BeaconStationActive" : "BeaconStationInactive"; var icon = new GUIImage(new RectTransform(new Point((int)(beaconStationContent.Rect.Height * 1.2f)), beaconStationContent.RectTransform), style, scaleToFit: true) { Color = MapGenerationParams.Instance.IndicatorColor, HoverColor = Color.Lerp(MapGenerationParams.Instance.IndicatorColor, Color.White, 0.5f), ToolTip = TextManager.Get(connection.LevelData.IsBeaconActive ? "BeaconStationActiveTooltip" : "BeaconStationInactiveTooltip") }; new GUITextBlock(new RectTransform(Vector2.One, beaconStationContent.RectTransform), TextManager.Get("submarinetype.beaconstation", fallBackTag: "beaconstationsonarlabel"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft) { Padding = Vector4.Zero, ToolTip = icon.ToolTip }; } if (connection.LevelData.HasHuntingGrounds) { var huntingGroundsContent = new GUILayoutGroup(new RectTransform(biomeLabel.RectTransform.NonScaledSize, textContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft); var icon = new GUIImage(new RectTransform(new Point((int)(huntingGroundsContent.Rect.Height * 1.5f)), huntingGroundsContent.RectTransform), "HuntingGrounds", scaleToFit: true) { Color = MapGenerationParams.Instance.IndicatorColor, HoverColor = Color.Lerp(MapGenerationParams.Instance.IndicatorColor, Color.White, 0.5f), ToolTip = TextManager.Get("HuntingGroundsTooltip") }; new GUITextBlock(new RectTransform(Vector2.One, huntingGroundsContent.RectTransform), TextManager.Get("missionname.huntinggrounds"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft) { Padding = Vector4.Zero, ToolTip = icon.ToolTip }; } } missionList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), content.RectTransform)) { Spacing = (int)(5 * GUI.yScale) }; missionList.OnSelected = (GUIComponent selected, object userdata) => { var tickBox = selected.FindChild(c => c is GUITickBox, recursive: true) as GUITickBox; if (GUI.MouseOn == tickBox) { return(false); } if (tickBox != null) { if (Campaign.AllowedToManageCampaign() && tickBox.Enabled) { tickBox.Selected = !tickBox.Selected; } } return(true); }; SelectedLevel = connection?.LevelData; Location currentDisplayLocation = Campaign.GetCurrentDisplayLocation(); if (connection != null && connection.Locations.Contains(currentDisplayLocation)) { List <Mission> availableMissions = currentDisplayLocation.GetMissionsInConnection(connection).ToList(); if (!availableMissions.Contains(null)) { availableMissions.Insert(0, null); } missionList.Content.ClearChildren(); foreach (Mission mission in availableMissions) { var missionPanel = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), missionList.Content.RectTransform), style: null) { UserData = mission }; var missionTextContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), missionPanel.RectTransform, Anchor.Center)) { Stretch = true, CanBeFocused = true, AbsoluteSpacing = GUI.IntScale(5) }; var missionName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission?.Name ?? TextManager.Get("NoMission"), font: GUI.SubHeadingFont, wrap: true); // missionName.RectTransform.MinSize = new Point(0, (int)(missionName.Rect.Height * 1.5f)); if (mission != null) { var tickBox = new GUITickBox(new RectTransform(Vector2.One * 0.9f, missionName.RectTransform, anchor: Anchor.CenterLeft, scaleBasis: ScaleBasis.Smallest) { AbsoluteOffset = new Point((int)missionName.Padding.X, 0) }, label: string.Empty) { UserData = mission, Selected = Campaign.Map.CurrentLocation?.SelectedMissions.Contains(mission) ?? false }; tickBox.RectTransform.MinSize = new Point(tickBox.Rect.Height, 0); tickBox.RectTransform.IsFixedSize = true; tickBox.Enabled = Campaign.AllowedToManageCampaign(); tickBox.OnSelected += (GUITickBox tb) => { if (!Campaign.AllowedToManageCampaign()) { return(false); } if (tb.Selected) { Campaign.Map.CurrentLocation.SelectMission(mission); } else { Campaign.Map.CurrentLocation.DeselectMission(mission); } foreach (GUITextBlock rewardText in missionRewardTexts) { Mission otherMission = rewardText.UserData as Mission; rewardText.SetRichText(otherMission.GetMissionRewardText(Submarine.MainSub)); } UpdateMaxMissions(connection.OtherLocation(currentDisplayLocation)); if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending && Campaign.AllowedToManageCampaign()) { GameMain.Client?.SendCampaignState(); } return(true); }; missionTickBoxes.Add(tickBox); GUILayoutGroup difficultyIndicatorGroup = null; if (mission.Difficulty.HasValue) { difficultyIndicatorGroup = new GUILayoutGroup(new RectTransform(Vector2.One * 0.9f, missionName.RectTransform, anchor: Anchor.CenterRight, scaleBasis: ScaleBasis.Smallest) { AbsoluteOffset = new Point((int)missionName.Padding.Z, 0) }, isHorizontal: true, childAnchor: Anchor.CenterRight) { AbsoluteSpacing = 1, UserData = "difficulty" }; var difficultyColor = mission.GetDifficultyColor(); for (int i = 0; i < mission.Difficulty; i++) { new GUIImage(new RectTransform(Vector2.One, difficultyIndicatorGroup.RectTransform, scaleBasis: ScaleBasis.Smallest) { IsFixedSize = true }, "DifficultyIndicator", scaleToFit: true) { Color = difficultyColor, SelectedColor = difficultyColor, HoverColor = difficultyColor }; } } float extraPadding = 0;// 0.8f * tickBox.Rect.Width; float extraZPadding = difficultyIndicatorGroup != null ? mission.Difficulty.Value * (difficultyIndicatorGroup.Children.First().Rect.Width + difficultyIndicatorGroup.AbsoluteSpacing) : 0; missionName.Padding = new Vector4(missionName.Padding.X + tickBox.Rect.Width * 1.2f + extraPadding, missionName.Padding.Y, missionName.Padding.Z + extraZPadding + extraPadding, missionName.Padding.W); missionName.CalculateHeightFromText(); //spacing new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform) { MinSize = new Point(0, GUI.IntScale(10)) }, style: null); var rewardText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission.GetMissionRewardText(Submarine.MainSub), wrap: true, parseRichText: true) { UserData = mission }; missionRewardTexts.Add(rewardText); string reputationText = mission.GetReputationRewardText(mission.Locations[0]); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), reputationText, wrap: true, parseRichText: true); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission.Description, wrap: true, parseRichText: true); } missionPanel.RectTransform.MinSize = new Point(0, (int)(missionTextContent.Children.Sum(c => c.Rect.Height + missionTextContent.AbsoluteSpacing) / missionTextContent.RectTransform.RelativeSize.Y) + GUI.IntScale(0)); foreach (GUIComponent child in missionTextContent.Children) { if (child is GUITextBlock textBlock) { textBlock.Color = textBlock.SelectedColor = textBlock.HoverColor = Color.Transparent; textBlock.SelectedTextColor = textBlock.HoverTextColor = textBlock.TextColor; } } missionPanel.OnAddedToGUIUpdateList = (c) => { missionTextContent.Children.ForEach(child => child.State = c.State); if (missionTextContent.FindChild("difficulty", recursive: true) is GUILayoutGroup group) { group.State = c.State; } }; if (mission != availableMissions.Last()) { new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), missionList.Content.RectTransform), style: "HorizontalLine") { CanBeFocused = false }; } } if (prevSelectedLocation == selectedLocation) { missionList.BarScroll = prevMissionListScroll; missionList.UpdateDimensions(); missionList.UpdateScrollBarSize(); } } var destination = connection.OtherLocation(currentDisplayLocation); UpdateMaxMissions(destination); var buttonArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), content.RectTransform), isHorizontal: true); new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), buttonArea.RectTransform), "", font: GUI.Style.SubHeadingFont) { TextGetter = () => { return(TextManager.AddPunctuation(':', TextManager.Get("Missions"), $"{Campaign.NumberOfMissionsAtLocation(destination)}/{Campaign.Settings.MaxMissionCount}")); } }; StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform), TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge") { OnClicked = (GUIButton btn, object obj) => { if (missionList.Content.FindChild(c => c is GUITickBox tickBox && tickBox.Selected, recursive: true) == null && missionList.Content.Children.Any(c => c.UserData is Mission)) { var noMissionVerification = new GUIMessageBox(string.Empty, TextManager.Get("nomissionprompt"), new string[] { TextManager.Get("yes"), TextManager.Get("no") }); noMissionVerification.Buttons[0].OnClicked = (btn, userdata) => { StartRound?.Invoke(); noMissionVerification.Close(); return(true); }; noMissionVerification.Buttons[1].OnClicked = noMissionVerification.Close; }
private void Generate() { connections.Clear(); Locations.Clear(); GenerateNoiseMap(generationParams.NoiseOctaves, generationParams.NoisePersistence); List <Vector2> sites = new List <Vector2>(); float mapRadius = size / 2; Vector2 mapCenter = new Vector2(mapRadius, mapRadius); float locationRadius = mapRadius * generationParams.LocationRadius; for (float x = mapCenter.X - locationRadius; x < mapCenter.X + locationRadius; x += generationParams.VoronoiSiteInterval) { for (float y = mapCenter.Y - locationRadius; y < mapCenter.Y + locationRadius; y += generationParams.VoronoiSiteInterval) { float noiseVal = Noise[(int)(x / size * generationParams.NoiseResolution), (int)(y / size * generationParams.NoiseResolution)]; if (Rand.Range(generationParams.VoronoiSitePlacementMinVal, 1.0f, Rand.RandSync.Server) < noiseVal * generationParams.VoronoiSitePlacementProbability) { sites.Add(new Vector2(x, y)); } } } Voronoi voronoi = new Voronoi(0.5f); List <GraphEdge> edges = voronoi.MakeVoronoiGraph(sites, size, size); float zoneRadius = size / 2 / generationParams.DifficultyZones; sites.Clear(); foreach (GraphEdge edge in edges) { if (edge.Point1 == edge.Point2) { continue; } if (Vector2.DistanceSquared(edge.Point1, mapCenter) >= locationRadius * locationRadius || Vector2.DistanceSquared(edge.Point2, mapCenter) >= locationRadius * locationRadius) { continue; } Location[] newLocations = new Location[2]; newLocations[0] = Locations.Find(l => l.MapPosition == edge.Point1 || l.MapPosition == edge.Point2); newLocations[1] = Locations.Find(l => l != newLocations[0] && (l.MapPosition == edge.Point1 || l.MapPosition == edge.Point2)); for (int i = 0; i < 2; i++) { if (newLocations[i] != null) { continue; } Vector2[] points = new Vector2[] { edge.Point1, edge.Point2 }; int positionIndex = Rand.Int(1, Rand.RandSync.Server); Vector2 position = points[positionIndex]; if (newLocations[1 - i] != null && newLocations[1 - i].MapPosition == position) { position = points[1 - positionIndex]; } int zone = MathHelper.Clamp(generationParams.DifficultyZones - (int)Math.Floor(Vector2.Distance(position, mapCenter) / zoneRadius), 1, generationParams.DifficultyZones); newLocations[i] = Location.CreateRandom(position, zone, Rand.GetRNG(Rand.RandSync.Server)); Locations.Add(newLocations[i]); } var newConnection = new LocationConnection(newLocations[0], newLocations[1]); float centerDist = Vector2.Distance(newConnection.CenterPos, mapCenter); newConnection.Difficulty = MathHelper.Clamp(((1.0f - centerDist / mapRadius) * 100) + Rand.Range(-10.0f, 10.0f, Rand.RandSync.Server), 0, 100); connections.Add(newConnection); } //remove connections that are too short float minConnectionDistanceSqr = generationParams.MinConnectionDistance * generationParams.MinConnectionDistance; for (int i = connections.Count - 1; i >= 0; i--) { LocationConnection connection = connections[i]; if (Vector2.DistanceSquared(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minConnectionDistanceSqr) { continue; } //locations.Remove(connection.Locations[0]); connections.Remove(connection); foreach (LocationConnection connection2 in connections) { if (connection2.Locations[0] == connection.Locations[0]) { connection2.Locations[0] = connection.Locations[1]; } if (connection2.Locations[1] == connection.Locations[0]) { connection2.Locations[1] = connection.Locations[1]; } } } HashSet <Location> connectedLocations = new HashSet <Location>(); foreach (LocationConnection connection in connections) { connection.Locations[0].Connections.Add(connection); connection.Locations[1].Connections.Add(connection); connectedLocations.Add(connection.Locations[0]); connectedLocations.Add(connection.Locations[1]); } //remove orphans Locations.RemoveAll(c => !connectedLocations.Contains(c)); //remove locations that are too close to each other float minLocationDistanceSqr = generationParams.MinLocationDistance * generationParams.MinLocationDistance; for (int i = Locations.Count - 1; i >= 0; i--) { for (int j = Locations.Count - 1; j > i; j--) { float dist = Vector2.DistanceSquared(Locations[i].MapPosition, Locations[j].MapPosition); if (dist > minLocationDistanceSqr) { continue; } //move connections from Locations[j] to Locations[i] foreach (LocationConnection connection in Locations[j].Connections) { if (connection.Locations[0] == Locations[j]) { connection.Locations[0] = Locations[i]; } else { connection.Locations[1] = Locations[i]; } Locations[i].Connections.Add(connection); } Locations.RemoveAt(j); } } for (int i = connections.Count - 1; i >= 0; i--) { i = Math.Min(i, connections.Count - 1); LocationConnection connection = connections[i]; for (int n = Math.Min(i - 1, connections.Count - 1); n >= 0; n--) { if (connection.Locations.Contains(connections[n].Locations[0]) && connection.Locations.Contains(connections[n].Locations[1])) { connections.RemoveAt(n); } } } foreach (LocationConnection connection in connections) { float centerDist = Vector2.Distance(connection.CenterPos, mapCenter); connection.Difficulty = MathHelper.Clamp(((1.0f - centerDist / mapRadius) * 100) + Rand.Range(-10.0f, 10.0f, Rand.RandSync.Server), 0, 100); } AssignBiomes(); GenerateNoiseMapProjSpecific(); }
private void DrawConnection(SpriteBatch spriteBatch, LocationConnection connection, Rectangle viewArea, Vector2 viewOffset, Color?overrideColor = null) { Color connectionColor; if (GameMain.DebugDraw) { float sizeFactor = MathUtils.InverseLerp( generationParams.SmallLevelConnectionLength, generationParams.LargeLevelConnectionLength, connection.Length); connectionColor = ToolBox.GradientLerp(sizeFactor, Color.LightGreen, GUI.Style.Orange, GUI.Style.Red); } else if (overrideColor.HasValue) { connectionColor = overrideColor.Value; } else { connectionColor = connection.Passed ? generationParams.ConnectionColor : generationParams.UnvisitedConnectionColor; } int width = (int)(generationParams.LocationConnectionWidth * zoom); if (Level.Loaded?.LevelData == connection.LevelData) { connectionColor = generationParams.HighlightedConnectionColor; width = (int)(width * 1.5f); } if (SelectedLocation != CurrentDisplayLocation && (connection.Locations.Contains(SelectedLocation) && connection.Locations.Contains(CurrentDisplayLocation))) { connectionColor = generationParams.HighlightedConnectionColor; width *= 2; } else if (HighlightedLocation != CurrentDisplayLocation && (connection.Locations.Contains(HighlightedLocation) && connection.Locations.Contains(CurrentDisplayLocation))) { connectionColor = generationParams.HighlightedConnectionColor; width *= 2; } Vector2 rectCenter = viewArea.Center.ToVector2(); int startIndex = connection.CrackSegments.Count > 2 ? 1 : 0; int endIndex = connection.CrackSegments.Count > 2 ? connection.CrackSegments.Count - 1 : connection.CrackSegments.Count; for (int i = startIndex; i < endIndex; i++) { var segment = connection.CrackSegments[i]; Vector2 start = rectCenter + (segment[0] + viewOffset) * zoom; Vector2 end = rectCenter + (segment[1] + viewOffset) * zoom; if (!viewArea.Contains(start) && !viewArea.Contains(end)) { continue; } else { if (MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(viewArea.X, viewArea.Y + viewArea.Height, viewArea.Width, viewArea.Height), out Vector2 intersection)) { if (!viewArea.Contains(start)) { start = intersection; } else { end = intersection; } } } float a = 1.0f; if (!connection.Locations[0].Discovered && !connection.Locations[1].Discovered) { if (IsInFogOfWar(connection.Locations[0])) { a = (float)i / connection.CrackSegments.Count; } else if (IsInFogOfWar(connection.Locations[1])) { a = 1.0f - (float)i / connection.CrackSegments.Count; } } float dist = Vector2.Distance(start, end); var connectionSprite = connection.Passed ? generationParams.PassedConnectionSprite : generationParams.ConnectionSprite; spriteBatch.Draw(connectionSprite.Texture, new Rectangle((int)start.X, (int)start.Y, (int)(dist - 1 * zoom), width), connectionSprite.SourceRect, connectionColor * a, MathUtils.VectorToAngle(end - start), new Vector2(0, connectionSprite.size.Y / 2), SpriteEffects.None, 0.01f); } if (GameMain.DebugDraw && zoom > 1.0f && generationParams.ShowLevelTypeNames) { Vector2 center = rectCenter + (connection.CenterPos + viewOffset) * zoom; if (viewArea.Contains(center) && connection.Biome != null) { GUI.DrawString(spriteBatch, center, connection.Biome.Identifier + " (" + connection.Difficulty + ")", Color.White); } } }
private void DrawConnection(SpriteBatch spriteBatch, LocationConnection connection, Rectangle viewArea, Vector2 viewOffset, Color?overrideColor = null) { Color connectionColor; if (GameMain.DebugDraw) { float sizeFactor = MathUtils.InverseLerp( generationParams.SmallLevelConnectionLength, generationParams.LargeLevelConnectionLength, connection.Length); connectionColor = ToolBox.GradientLerp(sizeFactor, Color.LightGreen, GUI.Style.Orange, GUI.Style.Red); } else if (overrideColor.HasValue) { connectionColor = overrideColor.Value; } else { connectionColor = connection.Passed ? generationParams.ConnectionColor : generationParams.UnvisitedConnectionColor; } int width = (int)(generationParams.LocationConnectionWidth * zoom); if (Level.Loaded?.LevelData == connection.LevelData) { connectionColor = generationParams.HighlightedConnectionColor; width = (int)(width * 1.5f); } if (SelectedLocation != CurrentDisplayLocation && (connection.Locations.Contains(SelectedLocation) && connection.Locations.Contains(CurrentDisplayLocation))) { connectionColor = generationParams.HighlightedConnectionColor; width *= 2; } else if (HighlightedLocation != CurrentDisplayLocation && (connection.Locations.Contains(HighlightedLocation) && connection.Locations.Contains(CurrentDisplayLocation))) { connectionColor = generationParams.HighlightedConnectionColor; width *= 2; } Vector2 rectCenter = viewArea.Center.ToVector2(); int startIndex = connection.CrackSegments.Count > 2 ? 1 : 0; int endIndex = connection.CrackSegments.Count > 2 ? connection.CrackSegments.Count - 1 : connection.CrackSegments.Count; Vector2?connectionStart = null; Vector2?connectionEnd = null; for (int i = startIndex; i < endIndex; i++) { var segment = connection.CrackSegments[i]; Vector2 start = rectCenter + (segment[0] + viewOffset) * zoom; if (!connectionStart.HasValue) { connectionStart = start; } Vector2 end = rectCenter + (segment[1] + viewOffset) * zoom; connectionEnd = end; if (!viewArea.Contains(start) && !viewArea.Contains(end)) { continue; } else { if (MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(viewArea.X, viewArea.Y + viewArea.Height, viewArea.Width, viewArea.Height), out Vector2 intersection)) { if (!viewArea.Contains(start)) { start = intersection; } else { end = intersection; } } } float a = 1.0f; if (!connection.Locations[0].Discovered && !connection.Locations[1].Discovered) { if (IsInFogOfWar(connection.Locations[0])) { a = (float)i / connection.CrackSegments.Count; } else if (IsInFogOfWar(connection.Locations[1])) { a = 1.0f - (float)i / connection.CrackSegments.Count; } } float dist = Vector2.Distance(start, end); var connectionSprite = connection.Passed ? generationParams.PassedConnectionSprite : generationParams.ConnectionSprite; spriteBatch.Draw(connectionSprite.Texture, new Rectangle((int)start.X, (int)start.Y, (int)(dist - 1 * zoom), width), connectionSprite.SourceRect, connectionColor * a, MathUtils.VectorToAngle(end - start), new Vector2(0, connectionSprite.size.Y / 2), SpriteEffects.None, 0.01f); } if (connectionStart.HasValue && connectionEnd.HasValue) { GUIComponentStyle crushDepthWarningIconStyle = null; string tooltip = null; var subCrushDepth = Submarine.MainSub?.RealWorldCrushDepth ?? Level.DefaultRealWorldCrushDepth; if (GameMain.GameSession?.Campaign?.UpgradeManager != null) { var hullUpgradePrefab = UpgradePrefab.Find("increasewallhealth"); if (hullUpgradePrefab != null) { int pendingLevel = GameMain.GameSession.Campaign.UpgradeManager.GetUpgradeLevel(hullUpgradePrefab, hullUpgradePrefab.UpgradeCategories.First()); int currentLevel = GameMain.GameSession.Campaign.UpgradeManager.GetRealUpgradeLevel(hullUpgradePrefab, hullUpgradePrefab.UpgradeCategories.First()); if (pendingLevel > currentLevel) { string updateValueStr = hullUpgradePrefab.SourceElement?.Element("Structure")?.GetAttributeString("crushdepth", null); if (!string.IsNullOrEmpty(updateValueStr)) { subCrushDepth = PropertyReference.CalculateUpgrade(subCrushDepth, pendingLevel - currentLevel, updateValueStr); } } } } if (connection.LevelData.InitialDepth * Physics.DisplayToRealWorldRatio > subCrushDepth) { crushDepthWarningIconStyle = GUI.Style.GetComponentStyle("CrushDepthWarningHighIcon"); tooltip = "crushdepthwarninghigh"; } else if ((connection.LevelData.InitialDepth + connection.LevelData.Size.Y) * Physics.DisplayToRealWorldRatio > subCrushDepth) { crushDepthWarningIconStyle = GUI.Style.GetComponentStyle("CrushDepthWarningLowIcon"); tooltip = "crushdepthwarninglow"; } if (crushDepthWarningIconStyle != null) { Vector2 iconPos = (connectionStart.Value + connectionEnd.Value) / 2; float iconSize = 32.0f * GUI.Scale; bool mouseOn = HighlightedLocation == null && Vector2.DistanceSquared(iconPos, PlayerInput.MousePosition) < iconSize * iconSize; Sprite crushDepthWarningIcon = crushDepthWarningIconStyle.GetDefaultSprite(); crushDepthWarningIcon.Draw(spriteBatch, iconPos, mouseOn ? crushDepthWarningIconStyle.HoverColor : crushDepthWarningIconStyle.Color, scale: iconSize / crushDepthWarningIcon.size.X); if (mouseOn) { connectionTooltip = new Pair <Rectangle, string>( new Rectangle(iconPos.ToPoint(), new Point((int)iconSize)), TextManager.Get(tooltip) .Replace("[initialdepth]", ((int)(connection.LevelData.InitialDepth * Physics.DisplayToRealWorldRatio)).ToString()) .Replace("[submarinecrushdepth]", ((int)subCrushDepth).ToString())); } } } if (GameMain.DebugDraw && zoom > 1.0f && generationParams.ShowLevelTypeNames) { Vector2 center = rectCenter + (connection.CenterPos + viewOffset) * zoom; if (viewArea.Contains(center) && connection.Biome != null) { GUI.DrawString(spriteBatch, center, connection.Biome.Identifier + " (" + connection.Difficulty + ")", Color.White); } } }
private void GenerateLocations() { Voronoi voronoi = new Voronoi(0.5f); List <Vector2> sites = new List <Vector2>(); for (int i = 0; i < 100; i++) { sites.Add(new Vector2(Rand.Range(0.0f, size, Rand.RandSync.Server), Rand.Range(0.0f, size, Rand.RandSync.Server))); } List <GraphEdge> edges = voronoi.MakeVoronoiGraph(sites, size, size); sites.Clear(); foreach (GraphEdge edge in edges) { if (edge.point1 == edge.point2) { continue; } //remove points from the edge of the map if (edge.point1.X == 0 || edge.point1.X == size) { continue; } if (edge.point1.Y == 0 || edge.point1.Y == size) { continue; } if (edge.point2.X == 0 || edge.point2.X == size) { continue; } if (edge.point2.Y == 0 || edge.point2.Y == size) { continue; } Location[] newLocations = new Location[2]; newLocations[0] = locations.Find(l => l.MapPosition == edge.point1 || l.MapPosition == edge.point2); newLocations[1] = locations.Find(l => l != newLocations[0] && (l.MapPosition == edge.point1 || l.MapPosition == edge.point2)); for (int i = 0; i < 2; i++) { if (newLocations[i] != null) { continue; } Vector2[] points = new Vector2[] { edge.point1, edge.point2 }; int positionIndex = Rand.Int(1, Rand.RandSync.Server); Vector2 position = points[positionIndex]; if (newLocations[1 - i] != null && newLocations[1 - i].MapPosition == position) { position = points[1 - positionIndex]; } newLocations[i] = Location.CreateRandom(position); locations.Add(newLocations[i]); } //int seed = (newLocations[0].GetHashCode() | newLocations[1].GetHashCode()); connections.Add(new LocationConnection(newLocations[0], newLocations[1])); } //remove connections that are too short float minDistance = 50.0f; for (int i = connections.Count - 1; i >= 0; i--) { LocationConnection connection = connections[i]; if (Vector2.Distance(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minDistance) { continue; } locations.Remove(connection.Locations[0]); connections.Remove(connection); foreach (LocationConnection connection2 in connections) { if (connection2.Locations[0] == connection.Locations[0]) { connection2.Locations[0] = connection.Locations[1]; } if (connection2.Locations[1] == connection.Locations[0]) { connection2.Locations[1] = connection.Locations[1]; } } } foreach (LocationConnection connection in connections) { connection.Locations[0].Connections.Add(connection); connection.Locations[1].Connections.Add(connection); } for (int i = connections.Count - 1; i >= 0; i--) { i = Math.Min(i, connections.Count - 1); LocationConnection connection = connections[i]; for (int n = Math.Min(i - 1, connections.Count - 1); n >= 0; n--) { if (connection.Locations.Contains(connections[n].Locations[0]) && connection.Locations.Contains(connections[n].Locations[1])) { connections.RemoveAt(n); } } } foreach (LocationConnection connection in connections) { Vector2 start = connection.Locations[0].MapPosition; Vector2 end = connection.Locations[1].MapPosition; int generations = (int)(Math.Sqrt(Vector2.Distance(start, end) / 10.0f)); connection.CrackSegments = MathUtils.GenerateJaggedLine(start, end, generations, 5.0f); } AssignBiomes(); }
private void GenerateConnections() { foreach (GraphEdge edge in graphEdges) { if (edge.point1 == edge.point2 || edge.isInternal) { continue; } Location[] newLocations = new Location[2]; newLocations[0] = locations.Find(l => l.MapPosition == edge.point1 || l.MapPosition == edge.point2); newLocations[1] = locations.Find(l => l != newLocations[0] && (l.MapPosition == edge.point1 || l.MapPosition == edge.point2)); for (int i = 0; i < 2; i++) { if (newLocations[i] != null) { continue; } Vector2[] points = new Vector2[] { edge.point1, edge.point2 }; int positionIndex = Rand.Int(1, false); Vector2 position = points[positionIndex]; if (newLocations[1 - i] != null && newLocations[1 - i].MapPosition == position) { position = points[1 - positionIndex]; } newLocations[i] = Location.CreateRandom(position); // DEBUG //newLocations[i].Discovered = true; locations.Add(newLocations[i]); } LocationConnection newConnection = ConnectLocations(newLocations[0], newLocations[1]); newConnection.primaryNodes[0] = edge.node1; newConnection.primaryNodes[1] = edge.node2; newConnection.secondaryNodes = edge.secondaryNodes.ToArray(); /*if (!edge.isInternal && edge.node1 != null && edge.node2 != null && edge.cell1 != null && edge.cell2 != null) * { * Location newLocation1; * Location newLocation2; * * newLocation1 = Location.CreateRandom(edge.node1.mapPosition); * newLocation2 = Location.CreateRandom(edge.node2.mapPosition); * * if (!locations.Any(l => l.MapPosition == edge.node1.mapPosition)) * locations.Add(newLocation1); * else * newLocation2 = locations.Find(l => l.MapPosition == edge.node1.mapPosition); * if (!locations.Any(l => l.MapPosition == edge.node2.mapPosition)) * locations.Add(newLocation2); * else * newLocation2 = locations.Find(l => l.MapPosition == edge.node2.mapPosition); * * ConnectLocations(newLocation1, newLocation2); * }*/ } foreach (SecondaryNode node in secondaryNodes) { if (!node.isOnEdge) { Location nodeLocation = Location.CreateRandom(node.mapPosition); locations.Add(nodeLocation); foreach (SecondaryNode subNode in node.attachedNodes) { LocationConnection newConnection = ConnectLocations(nodeLocation, Location.CreateRandom(subNode.mapPosition)); subNode.connections.Add(newConnection); } } } }
public static Level CreateRandom(LocationConnection locationConnection) { string seed = locationConnection.Locations[0].Name + locationConnection.Locations[1].Name; return(new Level(seed, locationConnection.Difficulty, LevelGenerationParams.GetRandom(seed, locationConnection.Biome))); }
//static because we may need to instantiate the campaign if it hasn't been done yet public static void ClientRead(IReadMessage msg) { bool isFirstRound = msg.ReadBoolean(); byte campaignID = msg.ReadByte(); UInt16 updateID = msg.ReadUInt16(); UInt16 saveID = msg.ReadUInt16(); string mapSeed = msg.ReadString(); UInt16 currentLocIndex = msg.ReadUInt16(); UInt16 selectedLocIndex = msg.ReadUInt16(); byte selectedMissionIndex = msg.ReadByte(); bool allowDebugTeleport = msg.ReadBoolean(); float? reputation = null; if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); } Dictionary <string, float> factionReps = new Dictionary <string, float>(); byte factionsCount = msg.ReadByte(); for (int i = 0; i < factionsCount; i++) { factionReps.Add(msg.ReadString(), msg.ReadSingle()); } bool forceMapUI = msg.ReadBoolean(); int money = msg.ReadInt32(); bool purchasedHullRepairs = msg.ReadBoolean(); bool purchasedItemRepairs = msg.ReadBoolean(); bool purchasedLostShuttles = msg.ReadBoolean(); byte missionCount = msg.ReadByte(); List <Pair <string, byte> > availableMissions = new List <Pair <string, byte> >(); for (int i = 0; i < missionCount; i++) { string missionIdentifier = msg.ReadString(); byte connectionIndex = msg.ReadByte(); availableMissions.Add(new Pair <string, byte>(missionIdentifier, connectionIndex)); } UInt16?storeBalance = null; if (msg.ReadBoolean()) { storeBalance = msg.ReadUInt16(); } UInt16 buyCrateItemCount = msg.ReadUInt16(); List <PurchasedItem> buyCrateItems = new List <PurchasedItem>(); for (int i = 0; i < buyCrateItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 purchasedItemCount = msg.ReadUInt16(); List <PurchasedItem> purchasedItems = new List <PurchasedItem>(); for (int i = 0; i < purchasedItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 soldItemCount = msg.ReadUInt16(); List <SoldItem> soldItems = new List <SoldItem>(); for (int i = 0; i < soldItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); UInt16 id = msg.ReadUInt16(); bool removed = msg.ReadBoolean(); byte sellerId = msg.ReadByte(); soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId)); } ushort pendingUpgradeCount = msg.ReadUInt16(); List <PurchasedUpgrade> pendingUpgrades = new List <PurchasedUpgrade>(); for (int i = 0; i < pendingUpgradeCount; i++) { string upgradeIdentifier = msg.ReadString(); UpgradePrefab prefab = UpgradePrefab.Find(upgradeIdentifier); string categoryIdentifier = msg.ReadString(); UpgradeCategory category = UpgradeCategory.Find(categoryIdentifier); int upgradeLevel = msg.ReadByte(); if (prefab == null || category == null) { continue; } pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel)); } bool hasCharacterData = msg.ReadBoolean(); CharacterInfo myCharacterInfo = null; if (hasCharacterData) { myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg); } if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaignID != campaign.CampaignID) { string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer); GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, mapSeed); campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode; campaign.CampaignID = campaignID; GameMain.NetLobbyScreen.ToggleCampaignMode(true); } //server has a newer save file if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID)) { campaign.PendingSaveID = saveID; } if (NetIdUtils.IdMoreRecent(updateID, campaign.lastUpdateID)) { campaign.SuppressStateSending = true; campaign.IsFirstRound = isFirstRound; //we need to have the latest save file to display location/mission/store if (campaign.LastSaveID == saveID) { campaign.ForceMapUI = forceMapUI; UpgradeStore.WaitForServerUpdate = false; campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex); campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex); campaign.Map.SelectMission(selectedMissionIndex); campaign.Map.AllowDebugTeleport = allowDebugTeleport; campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems); campaign.CargoManager.SetPurchasedItems(purchasedItems); campaign.CargoManager.SetSoldItems(soldItems); if (storeBalance.HasValue) { campaign.Map.CurrentLocation.StoreCurrentBalance = storeBalance.Value; } campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades); campaign.UpgradeManager.PurchasedUpgrades.Clear(); foreach (var(identifier, rep) in factionReps) { Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase)); if (faction?.Reputation != null) { faction.Reputation.Value = rep; } else { DebugConsole.ThrowError($"Received an update for a faction that doesn't exist \"{identifier}\"."); } } if (reputation.HasValue) { campaign.Map.CurrentLocation.Reputation.Value = reputation.Value; campaign?.CampaignUI?.UpgradeStore?.RefreshAll(); } foreach (var availableMission in availableMissions) { MissionPrefab missionPrefab = MissionPrefab.List.Find(mp => mp.Identifier == availableMission.First); if (missionPrefab == null) { DebugConsole.ThrowError($"Error when receiving campaign data from the server: mission prefab \"{availableMission.First}\" not found."); continue; } if (availableMission.Second < 0 || availableMission.Second >= campaign.Map.CurrentLocation.Connections.Count) { DebugConsole.ThrowError($"Error when receiving campaign data from the server: connection index for mission \"{availableMission.First}\" out of range (index: {availableMission.Second}, current location: {campaign.Map.CurrentLocation.Name}, connections: {campaign.Map.CurrentLocation.Connections.Count})."); continue; } LocationConnection connection = campaign.Map.CurrentLocation.Connections[availableMission.Second]; campaign.Map.CurrentLocation.UnlockMission(missionPrefab, connection); } GameMain.NetLobbyScreen.ToggleCampaignMode(true); } bool shouldRefresh = campaign.Money != money || campaign.PurchasedHullRepairs != purchasedHullRepairs || campaign.PurchasedItemRepairs != purchasedItemRepairs || campaign.PurchasedLostShuttles != purchasedLostShuttles; campaign.Money = money; campaign.PurchasedHullRepairs = purchasedHullRepairs; campaign.PurchasedItemRepairs = purchasedItemRepairs; campaign.PurchasedLostShuttles = purchasedLostShuttles; if (shouldRefresh) { campaign?.CampaignUI?.UpgradeStore?.RefreshAll(); } if (myCharacterInfo != null) { GameMain.Client.CharacterInfo = myCharacterInfo; GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo); } else { GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null); } campaign.lastUpdateID = updateID; campaign.SuppressStateSending = false; } }
public void ServerWrite(IWriteMessage msg, Client c) { System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue); Reputation reputation = Map?.CurrentLocation?.Reputation; msg.Write(IsFirstRound); msg.Write(CampaignID); msg.Write(lastUpdateID); msg.Write(lastSaveID); msg.Write(map.Seed); msg.Write(map.CurrentLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.CurrentLocationIndex); msg.Write(map.SelectedLocationIndex == -1 ? UInt16.MaxValue : (UInt16)map.SelectedLocationIndex); var selectedMissionIndices = map.GetSelectedMissionIndices(); msg.Write((byte)selectedMissionIndices.Count()); foreach (int selectedMissionIndex in selectedMissionIndices) { msg.Write((byte)selectedMissionIndex); } msg.Write(map.AllowDebugTeleport); msg.Write(reputation != null); if (reputation != null) { msg.Write(reputation.Value); } // hopefully we'll never have more than 128 factions msg.Write((byte)Factions.Count); foreach (Faction faction in Factions) { msg.Write(faction.Prefab.Identifier); msg.Write(faction.Reputation.Value); } msg.Write(ForceMapUI); msg.Write(Money); msg.Write(PurchasedHullRepairs); msg.Write(PurchasedItemRepairs); msg.Write(PurchasedLostShuttles); if (map.CurrentLocation != null) { msg.Write((byte)map.CurrentLocation?.AvailableMissions.Count()); foreach (Mission mission in map.CurrentLocation.AvailableMissions) { msg.Write(mission.Prefab.Identifier); if (mission.Locations[0] == mission.Locations[1]) { msg.Write((byte)255); } else { Location missionDestination = mission.Locations[0] == map.CurrentLocation ? mission.Locations[1] : mission.Locations[0]; LocationConnection connection = map.CurrentLocation.Connections.Find(c => c.OtherLocation(map.CurrentLocation) == missionDestination); msg.Write((byte)map.CurrentLocation.Connections.IndexOf(connection)); } } // Store balance msg.Write(true); msg.Write((UInt16)map.CurrentLocation.StoreCurrentBalance); } else { msg.Write((byte)0); // Store balance msg.Write(false); } msg.Write((UInt16)CargoManager.ItemsInBuyCrate.Count); foreach (PurchasedItem pi in CargoManager.ItemsInBuyCrate) { msg.Write(pi.ItemPrefab.Identifier); msg.WriteRangedInteger(pi.Quantity, 0, 100); } msg.Write((UInt16)CargoManager.PurchasedItems.Count); foreach (PurchasedItem pi in CargoManager.PurchasedItems) { msg.Write(pi.ItemPrefab.Identifier); msg.WriteRangedInteger(pi.Quantity, 0, 100); } msg.Write((UInt16)CargoManager.SoldItems.Count); foreach (SoldItem si in CargoManager.SoldItems) { msg.Write(si.ItemPrefab.Identifier); msg.Write((UInt16)si.ID); msg.Write(si.Removed); msg.Write(si.SellerID); } msg.Write((ushort)UpgradeManager.PendingUpgrades.Count); foreach (var(prefab, category, level) in UpgradeManager.PendingUpgrades) { msg.Write(prefab.Identifier); msg.Write(category.Identifier); msg.Write((byte)level); } msg.Write((ushort)UpgradeManager.PurchasedItemSwaps.Count); foreach (var itemSwap in UpgradeManager.PurchasedItemSwaps) { msg.Write(itemSwap.ItemToRemove.ID); msg.Write(itemSwap.ItemToInstall?.Identifier ?? string.Empty); } var characterData = GetClientCharacterData(c); if (characterData?.CharacterInfo == null) { msg.Write(false); } else { msg.Write(true); characterData.CharacterInfo.ServerWrite(msg); } }
public void SelectLocation(Location location, LocationConnection locationConnection) { }
/// <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)); if (locationIndices.X == locationIndices.Y) { continue; } 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(); }
private void CreateEndLocation() { float zoneWidth = Width / generationParams.DifficultyZones; Vector2 endPos = new Vector2(Width - zoneWidth / 2, Height / 2); float closestDist = float.MaxValue; EndLocation = Locations.First(); foreach (Location location in Locations) { float dist = Vector2.DistanceSquared(endPos, location.MapPosition); if (location.Biome.IsEndBiome && dist < closestDist) { EndLocation = location; closestDist = dist; } } Location previousToEndLocation = null; foreach (Location location in Locations) { if (!location.Biome.IsEndBiome && (previousToEndLocation == null || location.MapPosition.X > previousToEndLocation.MapPosition.X)) { previousToEndLocation = location; } } if (EndLocation == null || previousToEndLocation == null) { return; } //remove all locations from the end biome except the end location for (int i = Locations.Count - 1; i >= 0; i--) { if (Locations[i].Biome.IsEndBiome && Locations[i] != EndLocation) { for (int j = Locations[i].Connections.Count - 1; j >= 0; j--) { if (j >= Locations[i].Connections.Count) { continue; } var connection = Locations[i].Connections[j]; var otherLocation = connection.OtherLocation(Locations[i]); Locations[i].Connections.RemoveAt(j); otherLocation?.Connections.Remove(connection); Connections.Remove(connection); } Locations.RemoveAt(i); } } //removed all connections from the second-to-last location, need to reconnect it if (!previousToEndLocation.Connections.Any()) { Location connectTo = Locations.First(); foreach (Location location in Locations) { if (!location.Biome.IsEndBiome && location != previousToEndLocation && location.MapPosition.X > connectTo.MapPosition.X) { connectTo = location; } } var newConnection = new LocationConnection(previousToEndLocation, connectTo) { Biome = EndLocation.Biome, Difficulty = 100.0f }; Connections.Add(newConnection); previousToEndLocation.Connections.Add(newConnection); connectTo.Connections.Add(newConnection); } var endConnection = new LocationConnection(previousToEndLocation, EndLocation) { Biome = EndLocation.Biome, Difficulty = 100.0f }; Connections.Add(endConnection); previousToEndLocation.Connections.Add(endConnection); EndLocation.Connections.Add(endConnection); }
private void Generate() { Connections.Clear(); Locations.Clear(); List <Vector2> voronoiSites = new List <Vector2>(); for (float x = 10.0f; x < Width - 10.0f; x += generationParams.VoronoiSiteInterval.X) { for (float y = 10.0f; y < Height - 10.0f; y += generationParams.VoronoiSiteInterval.Y) { voronoiSites.Add(new Vector2( x + generationParams.VoronoiSiteVariance.X * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server), y + generationParams.VoronoiSiteVariance.Y * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server))); } } Voronoi voronoi = new Voronoi(0.5f); List <GraphEdge> edges = voronoi.MakeVoronoiGraph(voronoiSites, Width, Height); float zoneWidth = Width / generationParams.DifficultyZones; Vector2 margin = new Vector2( Math.Min(10, Width * 0.1f), Math.Min(10, Height * 0.2f)); float startX = margin.X, endX = Width - margin.X; float startY = margin.Y, endY = Height - margin.Y; if (!edges.Any()) { throw new Exception($"Generating a campaign map failed (no edges in the voronoi graph). Width: {Width}, height: {Height}, margin: {margin}"); } voronoiSites.Clear(); foreach (GraphEdge edge in edges) { if (edge.Point1 == edge.Point2) { continue; } if (edge.Point1.X < margin.X || edge.Point1.X > Width - margin.X || edge.Point1.Y < startY || edge.Point1.Y > endY) { continue; } if (edge.Point2.X < margin.X || edge.Point2.X > Width - margin.X || edge.Point2.Y < startY || edge.Point2.Y > endY) { continue; } Location[] newLocations = new Location[2]; newLocations[0] = Locations.Find(l => l.MapPosition == edge.Point1 || l.MapPosition == edge.Point2); newLocations[1] = Locations.Find(l => l != newLocations[0] && (l.MapPosition == edge.Point1 || l.MapPosition == edge.Point2)); for (int i = 0; i < 2; i++) { if (newLocations[i] != null) { continue; } Vector2[] points = new Vector2[] { edge.Point1, edge.Point2 }; int positionIndex = Rand.Int(1, Rand.RandSync.Server); Vector2 position = points[positionIndex]; if (newLocations[1 - i] != null && newLocations[1 - i].MapPosition == position) { position = points[1 - positionIndex]; } int zone = MathHelper.Clamp((int)Math.Floor(position.X / zoneWidth) + 1, 1, generationParams.DifficultyZones); newLocations[i] = Location.CreateRandom(position, zone, Rand.GetRNG(Rand.RandSync.Server), requireOutpost: false, Locations); Locations.Add(newLocations[i]); } var newConnection = new LocationConnection(newLocations[0], newLocations[1]); Connections.Add(newConnection); } //remove connections that are too short float minConnectionDistanceSqr = generationParams.MinConnectionDistance * generationParams.MinConnectionDistance; for (int i = Connections.Count - 1; i >= 0; i--) { LocationConnection connection = Connections[i]; if (Vector2.DistanceSquared(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minConnectionDistanceSqr) { continue; } //locations.Remove(connection.Locations[0]); Connections.Remove(connection); foreach (LocationConnection connection2 in Connections) { if (connection2.Locations[0] == connection.Locations[0]) { connection2.Locations[0] = connection.Locations[1]; } if (connection2.Locations[1] == connection.Locations[0]) { connection2.Locations[1] = connection.Locations[1]; } } } HashSet <Location> connectedLocations = new HashSet <Location>(); foreach (LocationConnection connection in Connections) { connection.Locations[0].Connections.Add(connection); connection.Locations[1].Connections.Add(connection); connectedLocations.Add(connection.Locations[0]); connectedLocations.Add(connection.Locations[1]); } //remove orphans Locations.RemoveAll(c => !connectedLocations.Contains(c)); //remove locations that are too close to each other float minLocationDistanceSqr = generationParams.MinLocationDistance * generationParams.MinLocationDistance; for (int i = Locations.Count - 1; i >= 0; i--) { for (int j = Locations.Count - 1; j > i; j--) { float dist = Vector2.DistanceSquared(Locations[i].MapPosition, Locations[j].MapPosition); if (dist > minLocationDistanceSqr) { continue; } //move connections from Locations[j] to Locations[i] foreach (LocationConnection connection in Locations[j].Connections) { if (connection.Locations[0] == Locations[j]) { connection.Locations[0] = Locations[i]; } else { connection.Locations[1] = Locations[i]; } if (connection.Locations[0] != connection.Locations[1]) { Locations[i].Connections.Add(connection); } else { Connections.Remove(connection); } } Locations[i].Connections.RemoveAll(c => c.OtherLocation(Locations[i]) == Locations[j]); Locations.RemoveAt(j); } } for (int i = Connections.Count - 1; i >= 0; i--) { i = Math.Min(i, Connections.Count - 1); LocationConnection connection = Connections[i]; for (int n = Math.Min(i - 1, Connections.Count - 1); n >= 0; n--) { if (connection.Locations.Contains(Connections[n].Locations[0]) && connection.Locations.Contains(Connections[n].Locations[1])) { Connections.RemoveAt(n); } } } foreach (Location location in Locations) { for (int i = location.Connections.Count - 1; i >= 0; i--) { if (!Connections.Contains(location.Connections[i])) { location.Connections.RemoveAt(i); } } } foreach (LocationConnection connection in Connections) { connection.Difficulty = MathHelper.Clamp((connection.CenterPos.X / Width * 100) + Rand.Range(-10.0f, 0.0f, Rand.RandSync.Server), 1.2f, 100.0f); } AssignBiomes(); CreateEndLocation(); foreach (Location location in Locations) { location.LevelData = new LevelData(location); } foreach (LocationConnection connection in Connections) { connection.LevelData = new LevelData(connection); } }
public void SelectLocation(Location location, LocationConnection connection) { selectedLocationInfo.ClearChildren(); missionPanel.Visible = location != null; if (location == null) { return; } var container = selectedLocationInfo; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), container.RectTransform), location.Name, font: GUI.LargeFont) { AutoScale = true }; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), container.RectTransform), location.Type.Name); Sprite portrait = location.Type.GetPortrait(location.PortraitId); new GUIImage(new RectTransform(new Vector2(1.0f, 0.6f), container.RectTransform), portrait, scaleToFit: true); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), container.RectTransform), TextManager.Get("SelectMission"), font: GUI.LargeFont) { AutoScale = true }; var missionFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.3f), container.RectTransform), style: "InnerFrame"); var missionContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), missionFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.02f, Stretch = true }; SelectedLevel = connection?.Level; if (connection != null) { Point maxTickBoxSize = new Point(int.MaxValue, missionContent.Rect.Height / 4); List <Mission> availableMissions = Campaign.Map.CurrentLocation.GetMissionsInConnection(connection).ToList(); if (!availableMissions.Contains(null)) { availableMissions.Add(null); } Mission selectedMission = Campaign.Map.CurrentLocation.SelectedMission != null && availableMissions.Contains(Campaign.Map.CurrentLocation.SelectedMission) ? Campaign.Map.CurrentLocation.SelectedMission : null; missionTickBoxes.Clear(); foreach (Mission mission in availableMissions) { var tickBox = new GUITickBox(new RectTransform(new Vector2(0.1f, 0.1f), missionContent.RectTransform) { MaxSize = maxTickBoxSize }, mission?.Name ?? TextManager.Get("NoMission")) { UserData = mission, Enabled = GameMain.Client == null || GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign), Selected = mission == selectedMission, OnSelected = (tb) => { if (!tb.Selected) { return(false); } RefreshMissionTab(tb.UserData as Mission); Campaign.Map.OnMissionSelected?.Invoke(connection, mission); if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending && GameMain.Client != null && GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign)) { GameMain.Client?.SendCampaignState(); } return(true); } }; missionTickBoxes.Add(tickBox); } RefreshMissionTab(selectedMission); StartButton = new GUIButton(new RectTransform(new Vector2(0.3f, 0.7f), missionContent.RectTransform, Anchor.CenterRight), TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge") { IgnoreLayoutGroups = true, OnClicked = (GUIButton btn, object obj) => { StartRound?.Invoke(); return(true); }, Enabled = true }; if (GameMain.Client != null) { StartButton.Visible = !GameMain.Client.GameStarted && (GameMain.Client.HasPermission(Networking.ClientPermissions.ManageRound) || GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign)); } } OnLocationSelected?.Invoke(location, connection); }
public void SelectLocation(Location location, LocationConnection connection) { locationInfoPanel.ClearChildren(); //don't select the map panel if we're looking at some other tab if (selectedTab == CampaignMode.InteractionType.Map) { SelectTab(CampaignMode.InteractionType.Map); locationInfoPanel.Visible = location != null; } Location prevSelectedLocation = selectedLocation; float prevMissionListScroll = missionList?.BarScroll ?? 0.0f; selectedLocation = location; if (location == null) { return; } int padding = GUI.IntScale(20); var content = new GUILayoutGroup(new RectTransform(locationInfoPanel.Rect.Size - new Point(padding * 2), locationInfoPanel.RectTransform, Anchor.Center), childAnchor: Anchor.TopRight) { Stretch = true, RelativeSpacing = 0.02f, }; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), location.Name, font: GUI.LargeFont) { AutoScaleHorizontal = true }; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), location.Type.Name, font: GUI.SubHeadingFont); Sprite portrait = location.Type.GetPortrait(location.PortraitId); portrait.EnsureLazyLoaded(); var portraitContainer = new GUICustomComponent(new RectTransform(new Vector2(1.0f, 0.3f), content.RectTransform), onDraw: (sb, customComponent) => { portrait.Draw(sb, customComponent.Rect.Center.ToVector2(), Color.Gray, portrait.size / 2, scale: Math.Max(customComponent.Rect.Width / portrait.size.X, customComponent.Rect.Height / portrait.size.Y)); }) { HideElementsOutsideFrame = true }; var textContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), portraitContainer.RectTransform, Anchor.Center)) { RelativeSpacing = 0.05f }; if (connection?.LevelData != null) { var biomeLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform), TextManager.Get("Biome", fallBackTag: "location"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft); new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), biomeLabel.RectTransform), connection.Biome.DisplayName, textAlignment: Alignment.CenterRight); var difficultyLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform), TextManager.Get("LevelDifficulty"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft); new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), difficultyLabel.RectTransform), ((int)connection.LevelData.Difficulty) + " %", textAlignment: Alignment.CenterRight); } missionList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), content.RectTransform)) { Spacing = (int)(5 * GUI.yScale) }; SelectedLevel = connection?.LevelData; Location currentDisplayLocation = Campaign.CurrentDisplayLocation; if (connection != null && connection.Locations.Contains(currentDisplayLocation)) { List <Mission> availableMissions = currentDisplayLocation.GetMissionsInConnection(connection).ToList(); if (!availableMissions.Contains(null)) { availableMissions.Insert(0, null); } Mission selectedMission = currentDisplayLocation.SelectedMission != null && availableMissions.Contains(currentDisplayLocation.SelectedMission) ? currentDisplayLocation.SelectedMission : null; missionList.Content.ClearChildren(); foreach (Mission mission in availableMissions) { var missionPanel = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), missionList.Content.RectTransform), style: null) { UserData = mission }; var missionTextContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), missionPanel.RectTransform, Anchor.Center)) { Stretch = true, CanBeFocused = true }; var missionName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission?.Name ?? TextManager.Get("NoMission"), font: GUI.SubHeadingFont, wrap: true); if (mission != null) { if (MapGenerationParams.Instance?.MissionIcon != null) { var icon = new GUIImage(new RectTransform(Vector2.One * 0.9f, missionName.RectTransform, anchor: Anchor.CenterLeft, scaleBasis: ScaleBasis.Smallest) { AbsoluteOffset = new Point((int)missionName.Padding.X, 0) }, MapGenerationParams.Instance.MissionIcon, scaleToFit: true) { Color = MapGenerationParams.Instance.IndicatorColor * 0.5f, SelectedColor = MapGenerationParams.Instance.IndicatorColor, HoverColor = Color.Lerp(MapGenerationParams.Instance.IndicatorColor, Color.White, 0.5f) }; missionName.Padding = new Vector4(missionName.Padding.X + icon.Rect.Width * 1.5f, missionName.Padding.Y, missionName.Padding.Z, missionName.Padding.W); } new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), TextManager.GetWithVariable("missionreward", "[reward]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", mission.Reward)), wrap: true); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission.Description, wrap: true); } missionPanel.RectTransform.MinSize = new Point(0, (int)(missionTextContent.Children.Sum(c => c.Rect.Height) / missionTextContent.RectTransform.RelativeSize.Y) + GUI.IntScale(20)); foreach (GUIComponent child in missionTextContent.Children) { var textBlock = child as GUITextBlock; textBlock.Color = textBlock.SelectedColor = textBlock.HoverColor = Color.Transparent; textBlock.HoverTextColor = textBlock.TextColor; textBlock.TextColor *= 0.5f; } missionPanel.OnAddedToGUIUpdateList = (c) => { missionTextContent.Children.ForEach(child => child.State = c.State); }; if (mission != availableMissions.Last()) { new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), missionList.Content.RectTransform), style: "HorizontalLine") { CanBeFocused = false }; } } missionList.Select(selectedMission); if (prevSelectedLocation == selectedLocation) { missionList.BarScroll = prevMissionListScroll; } if (Campaign.AllowedToManageCampaign()) { missionList.OnSelected = (component, userdata) => { Mission mission = userdata as Mission; if (Campaign.Map.CurrentLocation.SelectedMission == mission) { return(false); } Campaign.Map.CurrentLocation.SelectedMission = mission; //RefreshMissionInfo(mission); if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending && Campaign.AllowedToManageCampaign()) { GameMain.Client?.SendCampaignState(); } return(true); }; } } StartButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.1f), content.RectTransform), TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge") { OnClicked = (GUIButton btn, object obj) => { StartRound?.Invoke(); return(true); }, Enabled = true, Visible = Campaign.AllowedToEndRound() }; if (Level.Loaded != null && connection.LevelData == Level.Loaded.LevelData && currentDisplayLocation == Campaign.Map?.CurrentLocation) { StartButton.Visible = false; missionList.Enabled = false; } }