/// <summary> /// Moves away any character that is inside the bounding box of the sub (but not inside the sub) /// </summary> /// <param name="subTranslation">The translation that was applied to the sub before doing the displacement /// (used for determining where to push the characters)</param> private void DisplaceCharacters(Vector2 subTranslation) { Rectangle worldBorders = Borders; worldBorders.Location += MathUtils.ToPoint(ConvertUnits.ToDisplayUnits(Body.SimPosition)); Vector2 translateDir = Vector2.Normalize(subTranslation); if (!MathUtils.IsValid(translateDir)) { translateDir = Vector2.UnitY; } foreach (Character c in Character.CharacterList) { if (c.AnimController.CurrentHull != null && c.AnimController.CanEnterSubmarine) { continue; } foreach (Limb limb in c.AnimController.Limbs) { if (limb.IsSevered) { continue; } //if the character isn't inside the bounding box, continue if (!Submarine.RectContains(worldBorders, limb.WorldPosition)) { continue; } //cast a line from the position of the character to the same direction as the translation of the sub //and see where it intersects with the bounding box if (!MathUtils.GetLineRectangleIntersection(limb.WorldPosition, limb.WorldPosition + translateDir * 100000.0f, worldBorders, out Vector2 intersection)) { //should never happen when casting a line out from inside the bounding box Debug.Assert(false); continue; } //"+ translatedir" in order to move the character slightly away from the wall c.AnimController.SetPosition(ConvertUnits.ToSimUnits(c.WorldPosition + (intersection - limb.WorldPosition)) + translateDir); return; } } }
public void Draw(SpriteBatch spriteBatch, GUICustomComponent mapContainer) { Rectangle rect = mapContainer.Rect; Vector2 viewSize = new Vector2(rect.Width / zoom, rect.Height / zoom); float edgeBuffer = size * (BackgroundScale - 1.0f) / 2; drawOffset.X = MathHelper.Clamp(drawOffset.X, -size - edgeBuffer + viewSize.X / 2.0f, edgeBuffer - viewSize.X / 2.0f); drawOffset.Y = MathHelper.Clamp(drawOffset.Y, -size - edgeBuffer + viewSize.Y / 2.0f, edgeBuffer - viewSize.Y / 2.0f); drawOffsetNoise = new Vector2( (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.1f % 255, Timing.TotalTime * 0.1f % 255, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.2f % 255, Timing.TotalTime * 0.2f % 255, 0.5f) - 0.5f) * 10.0f; Vector2 viewOffset = drawOffset + drawOffsetNoise; Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); Rectangle prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle; spriteBatch.End(); spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, rect); spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable); for (int x = 0; x < mapTiles.GetLength(0); x++) { for (int y = 0; y < mapTiles.GetLength(1); y++) { Vector2 mapPos = new Vector2( x * generationParams.TileSpriteSpacing.X + ((y % 2 == 0) ? 0.0f : generationParams.TileSpriteSpacing.X * 0.5f), y * generationParams.TileSpriteSpacing.Y); mapPos.X -= size / 2 * (BackgroundScale - 1.0f); mapPos.Y -= size / 2 * (BackgroundScale - 1.0f); Vector2 scale = new Vector2( generationParams.TileSpriteSize.X / mapTiles[x, y].Sprite.size.X, generationParams.TileSpriteSize.Y / mapTiles[x, y].Sprite.size.Y); mapTiles[x, y].Sprite.Draw(spriteBatch, rectCenter + (mapPos + viewOffset) * zoom, Color.White, origin: new Vector2(256.0f, 256.0f), rotate: 0, scale: scale * zoom, spriteEffect: mapTiles[x, y].SpriteEffect); } } #if DEBUG if (generationParams.ShowNoiseMap) { GUI.DrawRectangle(spriteBatch, rectCenter + (borders.Location.ToVector2() + viewOffset) * zoom, borders.Size.ToVector2() * zoom, Color.White, true); } #endif Vector2 topLeft = rectCenter + viewOffset * zoom; topLeft.X = (int)topLeft.X; topLeft.Y = (int)topLeft.Y; Vector2 bottomRight = rectCenter + (viewOffset + new Vector2(size, size)) * zoom; bottomRight.X = (int)bottomRight.X; bottomRight.Y = (int)bottomRight.Y; spriteBatch.Draw(noiseTexture, destinationRectangle: new Rectangle((int)topLeft.X, (int)topLeft.Y, (int)(bottomRight.X - topLeft.X), (int)(bottomRight.Y - topLeft.Y)), sourceRectangle: null, color: Color.White); if (topLeft.X > rect.X) { GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Y, (int)(topLeft.X - rect.X), rect.Height), Color.Black * 0.8f, true); } if (topLeft.Y > rect.Y) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, rect.Y, (int)(bottomRight.X - topLeft.X), (int)(topLeft.Y - rect.Y)), Color.Black * 0.8f, true); } if (bottomRight.X < rect.Right) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)bottomRight.X, rect.Y, (int)(rect.Right - bottomRight.X), rect.Height), Color.Black * 0.8f, true); } if (bottomRight.Y < rect.Bottom) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, (int)bottomRight.Y, (int)(bottomRight.X - topLeft.X), (int)(rect.Bottom - bottomRight.Y)), Color.Black * 0.8f, true); } var sourceRect = rect; float rawNoiseScale = 1.0f + Noise[(int)(Timing.TotalTime * 100 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 100 % Noise.GetLength(1) - 1)]; cameraNoiseStrength = Noise[(int)(Timing.TotalTime * 10 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 10 % Noise.GetLength(1) - 1)]; rawNoiseSprite.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(), startOffset: new Point(Rand.Range(0, rawNoiseSprite.SourceRect.Width), Rand.Range(0, rawNoiseSprite.SourceRect.Height)), color: Color.White * cameraNoiseStrength * 0.5f, textureScale: Vector2.One * rawNoiseScale); rawNoiseSprite.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(), startOffset: new Point(Rand.Range(0, rawNoiseSprite.SourceRect.Width), Rand.Range(0, rawNoiseSprite.SourceRect.Height)), color: new Color(20, 20, 20, 100), textureScale: Vector2.One * rawNoiseScale * 2); if (generationParams.ShowLocations) { foreach (LocationConnection connection in connections) { Color connectionColor; if (GameMain.DebugDraw) { float sizeFactor = MathUtils.InverseLerp( MapGenerationParams.Instance.SmallLevelConnectionLength, MapGenerationParams.Instance.LargeLevelConnectionLength, connection.Length); connectionColor = ToolBox.GradientLerp(sizeFactor, Color.LightGreen, Color.Orange, Color.Red); } else { connectionColor = ToolBox.GradientLerp(connection.Difficulty / 100.0f, MapGenerationParams.Instance.LowDifficultyColor, MapGenerationParams.Instance.MediumDifficultyColor, MapGenerationParams.Instance.HighDifficultyColor); } int width = (int)(3 * zoom); if (SelectedLocation != CurrentLocation && (connection.Locations.Contains(SelectedLocation) && connection.Locations.Contains(CurrentLocation))) { connectionColor = Color.Gold; width *= 2; } else if (highlightedLocation != CurrentLocation && (connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(CurrentLocation))) { connectionColor = Color.Lerp(connectionColor, Color.White, 0.5f); width *= 2; } else if (!connection.Passed) { //crackColor *= 0.5f; } for (int i = 0; i < connection.CrackSegments.Count; i++) { var segment = connection.CrackSegments[i]; Vector2 start = rectCenter + (segment[0] + viewOffset) * zoom; Vector2 end = rectCenter + (segment[1] + viewOffset) * zoom; if (!rect.Contains(start) && !rect.Contains(end)) { continue; } else { if (MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(rect.X, rect.Y + rect.Height, rect.Width, rect.Height), out Vector2 intersection)) { if (!rect.Contains(start)) { start = intersection; } else { end = intersection; } } } float distFromPlayer = Vector2.Distance(CurrentLocation.MapPosition, (segment[0] + segment[1]) / 2.0f); float dist = Vector2.Distance(start, end); float a = GameMain.DebugDraw ? 1.0f : (200.0f - distFromPlayer) / 200.0f; spriteBatch.Draw(generationParams.ConnectionSprite.Texture, new Rectangle((int)start.X, (int)start.Y, (int)(dist - 1 * zoom), width), null, connectionColor * MathHelper.Clamp(a, 0.1f, 0.5f), MathUtils.VectorToAngle(end - start), new Vector2(0, 16), SpriteEffects.None, 0.01f); } if (GameMain.DebugDraw && zoom > 1.0f && generationParams.ShowLevelTypeNames) { Vector2 center = rectCenter + (connection.CenterPos + viewOffset) * zoom; if (rect.Contains(center)) { GUI.DrawString(spriteBatch, center, connection.Biome.Name + " (" + connection.Difficulty + ")", Color.White); } } } rect.Inflate(8, 8); GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8); GUI.DrawRectangle(spriteBatch, rect, Color.LightGray); for (int i = 0; i < Locations.Count; i++) { Location location = Locations[i]; Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; Rectangle drawRect = location.Type.Sprite.SourceRect; drawRect.X = (int)pos.X - drawRect.Width / 2; drawRect.Y = (int)pos.Y - drawRect.Width / 2; if (!rect.Intersects(drawRect)) { continue; } Color color = location.Type.SpriteColor; if (location.Connections.Find(c => c.Locations.Contains(CurrentLocation)) == null) { color *= 0.5f; } float iconScale = location == CurrentLocation ? 1.2f : 1.0f; if (location == highlightedLocation) { iconScale *= 1.1f; color = Color.Lerp(color, Color.White, 0.5f); } float distFromPlayer = Vector2.Distance(CurrentLocation.MapPosition, location.MapPosition); color *= MathHelper.Clamp((1000.0f - distFromPlayer) / 500.0f, 0.1f, 1.0f); location.Type.Sprite.Draw(spriteBatch, pos, color, scale: MapGenerationParams.Instance.LocationIconSize / location.Type.Sprite.size.X * iconScale * zoom); MapGenerationParams.Instance.LocationIndicator.Draw(spriteBatch, pos, color, scale: MapGenerationParams.Instance.LocationIconSize / MapGenerationParams.Instance.LocationIndicator.size.X * iconScale * zoom * 1.4f); } //PLACEHOLDER until the stuff at the center of the map is implemented float centerIconSize = 50.0f; Vector2 centerPos = rectCenter + (new Vector2(size / 2) + viewOffset) * zoom; bool mouseOn = Vector2.Distance(PlayerInput.MousePosition, centerPos) < centerIconSize * zoom; var centerLocationType = LocationType.List.Last(); Color centerColor = centerLocationType.SpriteColor * (mouseOn ? 1.0f : 0.6f); centerLocationType.Sprite.Draw(spriteBatch, centerPos, centerColor, scale: centerIconSize / centerLocationType.Sprite.size.X * zoom); MapGenerationParams.Instance.LocationIndicator.Draw(spriteBatch, centerPos, centerColor, scale: centerIconSize / MapGenerationParams.Instance.LocationIndicator.size.X * zoom * 1.2f); if (mouseOn && PlayerInput.LeftButtonClicked() && !messageBoxOpen) { if (TextManager.ContainsTag("centerarealockedheader") && TextManager.ContainsTag("centerarealockedtext")) { var messageBox = new GUIMessageBox( TextManager.Get("centerarealockedheader"), TextManager.Get("centerarealockedtext")); messageBoxOpen = true; CoroutineManager.StartCoroutine(WaitForMessageBoxClosed(messageBox)); } else { //if the message cannot be shown in the selected language, //show the campaign roadmap (which mentions the center location not being reachable) var messageBox = new GUIMessageBox(TextManager.Get("CampaignRoadMapTitle"), TextManager.Get("CampaignRoadMapText")); messageBoxOpen = true; CoroutineManager.StartCoroutine(WaitForMessageBoxClosed(messageBox)); } } } DrawDecorativeHUD(spriteBatch, rect); for (int i = 0; i < 2; i++) { Location location = (i == 0) ? highlightedLocation : CurrentLocation; if (location == null) { continue; } Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; pos.X += 25 * zoom; pos.Y -= 5 * zoom; Vector2 size = GUI.LargeFont.MeasureString(location.Name); GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0].Draw( spriteBatch, new Rectangle((int)pos.X - 30, (int)pos.Y, (int)size.X + 60, (int)(size.Y + 25 * GUI.Scale)), Color.Black * hudOpenState * 0.7f); GUI.DrawString(spriteBatch, pos, location.Name, Color.White * hudOpenState * 1.5f, font: GUI.LargeFont); GUI.DrawString(spriteBatch, pos + Vector2.UnitY * 25 * GUI.Scale, location.Type.Name, Color.White * hudOpenState * 1.5f); } GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect; spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred); }
public void Draw(SpriteBatch spriteBatch, Rectangle rect, float scale = 1.0f) { Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); Vector2 offset = -currentLocation.MapPosition; iceTexture.DrawTiled(spriteBatch, new Vector2(rect.X, rect.Y), new Vector2(rect.Width, rect.Height), Vector2.Zero, Color.White * 0.8f); foreach (LocationConnection connection in connections) { Color crackColor = Color.White * Math.Max(connection.Difficulty / 100.0f, 1.5f); if (selectedLocation != currentLocation && (connection.Locations.Contains(selectedLocation) && connection.Locations.Contains(currentLocation))) { crackColor = Color.Red; } else if (highlightedLocation != currentLocation && (connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation))) { crackColor = Color.Red * 0.5f; } else if (!connection.Passed) { crackColor *= 0.2f; } for (int i = 0; i < connection.CrackSegments.Count; i++) { var segment = connection.CrackSegments[i]; Vector2 start = rectCenter + (segment[0] + offset) * scale; Vector2 end = rectCenter + (segment[1] + offset) * scale; if (!rect.Contains(start) && !rect.Contains(end)) { continue; } else { Vector2?intersection = MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(rect.X, rect.Y + rect.Height, rect.Width, rect.Height)); if (intersection != null) { if (!rect.Contains(start)) { start = (Vector2)intersection; } else { end = (Vector2)intersection; } } } float dist = Vector2.Distance(start, end); int width = (int)(MathHelper.Clamp(connection.Difficulty, 2.0f, 20.0f) * scale); spriteBatch.Draw(iceCrack, new Rectangle((int)start.X, (int)start.Y, (int)dist + 2, width), new Rectangle(0, 0, iceCrack.Width, 60), crackColor, MathUtils.VectorToAngle(end - start), new Vector2(0, 30), SpriteEffects.None, 0.01f); } } rect.Inflate(8, 8); GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8); GUI.DrawRectangle(spriteBatch, rect, Color.LightGray); for (int i = 0; i < locations.Count; i++) { Location location = locations[i]; Vector2 pos = rectCenter + (location.MapPosition + offset) * scale; Rectangle drawRect = location.Type.Sprite.SourceRect; Rectangle sourceRect = drawRect; drawRect.X = (int)pos.X - drawRect.Width / 2; drawRect.Y = (int)pos.Y - drawRect.Width / 2; if (!rect.Intersects(drawRect)) { continue; } Color color = location.Connections.Find(c => c.Locations.Contains(currentLocation)) == null ? Color.White : Color.Green; color *= (location.Discovered) ? 0.8f : 0.2f; if (location == currentLocation) { color = Color.Orange; } if (drawRect.X < rect.X) { sourceRect.X += rect.X - drawRect.X; sourceRect.Width -= sourceRect.X; drawRect.X = rect.X; } else if (drawRect.Right > rect.Right) { sourceRect.Width -= (drawRect.Right - rect.Right); } if (drawRect.Y < rect.Y) { sourceRect.Y += rect.Y - drawRect.Y; sourceRect.Height -= sourceRect.Y; drawRect.Y = rect.Y; } else if (drawRect.Bottom > rect.Bottom) { sourceRect.Height -= drawRect.Bottom - rect.Bottom; } drawRect.Width = sourceRect.Width; drawRect.Height = sourceRect.Height; spriteBatch.Draw(location.Type.Sprite.Texture, drawRect, sourceRect, color); } for (int i = 0; i < 3; i++) { Location location = (i == 0) ? highlightedLocation : selectedLocation; if (i == 2) { location = currentLocation; } if (location == null) { continue; } Vector2 pos = rectCenter + (location.MapPosition + offset) * scale; pos.X = (int)(pos.X + location.Type.Sprite.SourceRect.Width * 0.6f); pos.Y = (int)(pos.Y - 10); GUI.DrawString(spriteBatch, pos, location.Name, Color.White, Color.Black * 0.8f, 3); } }
private void GenerateRuin(List <VoronoiCell> mainPath) { Vector2 ruinSize = new Vector2(Rand.Range(5000.0f, 8000.0f, Rand.RandSync.Server), Rand.Range(5000.0f, 8000.0f, Rand.RandSync.Server)); float ruinRadius = Math.Max(ruinSize.X, ruinSize.Y) * 0.5f; Vector2 ruinPos = cells[Rand.Int(cells.Count, Rand.RandSync.Server)].Center; //50% chance of placing the ruins at a cave if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) < 0.5f) { TryGetInterestingPosition(true, PositionType.Cave, 0.0f, out ruinPos); } ruinPos.Y = Math.Min(ruinPos.Y, borders.Y + borders.Height - ruinSize.Y / 2); ruinPos.Y = Math.Max(ruinPos.Y, SeaFloorTopPos + ruinSize.Y / 2.0f); int iter = 0; while (mainPath.Any(p => Vector2.Distance(ruinPos, p.Center) < ruinRadius * 2.0f)) { Vector2 weighedPathPos = ruinPos; iter++; foreach (VoronoiCell pathCell in mainPath) { float dist = Vector2.Distance(pathCell.Center, ruinPos); if (dist > 10000.0f) { continue; } Vector2 moveAmount = Vector2.Normalize(ruinPos - pathCell.Center) * 100000.0f / dist; weighedPathPos += moveAmount; weighedPathPos.Y = Math.Min(borders.Y + borders.Height - ruinSize.Y / 2, weighedPathPos.Y); } ruinPos = weighedPathPos; if (iter > 10000) { break; } } VoronoiCell closestPathCell = null; float closestDist = 0.0f; foreach (VoronoiCell pathCell in mainPath) { float dist = Vector2.Distance(pathCell.Center, ruinPos); if (closestPathCell == null || dist < closestDist) { closestPathCell = pathCell; closestDist = dist; } } var ruin = new Ruin(closestPathCell, cells, new Rectangle(MathUtils.ToPoint(ruinPos - ruinSize * 0.5f), MathUtils.ToPoint(ruinSize))); ruins.Add(ruin); ruin.RuinShapes.Sort((shape1, shape2) => shape2.DistanceFromEntrance.CompareTo(shape1.DistanceFromEntrance)); for (int i = 0; i < 4; i++) { positionsOfInterest.Add(new InterestingPosition(ruin.RuinShapes[i].Rect.Center.ToVector2(), PositionType.Ruin)); } foreach (RuinShape ruinShape in ruin.RuinShapes) { var tooClose = GetTooCloseCells(ruinShape.Rect.Center.ToVector2(), Math.Max(ruinShape.Rect.Width, ruinShape.Rect.Height)); foreach (VoronoiCell cell in tooClose) { if (cell.CellType == CellType.Empty) { continue; } foreach (GraphEdge e in cell.edges) { Rectangle rect = ruinShape.Rect; rect.Y += rect.Height; if (ruinShape.Rect.Contains(e.point1) || ruinShape.Rect.Contains(e.point2) || MathUtils.GetLineRectangleIntersection(e.point1, e.point2, rect) != null) { cell.CellType = CellType.Removed; int x = (int)Math.Floor(cell.Center.X / GridCellSize); int y = (int)Math.Floor(cell.Center.Y / GridCellSize); cellGrid[x, y].Remove(cell); cells.Remove(cell); break; } } } } }
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); } } }
public void Draw(SpriteBatch spriteBatch, GUICustomComponent mapContainer) { Rectangle rect = mapContainer.Rect; Vector2 viewSize = new Vector2(rect.Width / zoom, rect.Height / zoom); float edgeBuffer = size * (BackgroundScale - 1.0f) / 2; drawOffset.X = MathHelper.Clamp(drawOffset.X, -size - edgeBuffer + viewSize.X / 2.0f, edgeBuffer - viewSize.X / 2.0f); drawOffset.Y = MathHelper.Clamp(drawOffset.Y, -size - edgeBuffer + viewSize.Y / 2.0f, edgeBuffer - viewSize.Y / 2.0f); drawOffsetNoise = new Vector2( (float)PerlinNoise.Perlin(Timing.TotalTime * 0.1f % 255, Timing.TotalTime * 0.1f % 255, 0) - 0.5f, (float)PerlinNoise.Perlin(Timing.TotalTime * 0.2f % 255, Timing.TotalTime * 0.2f % 255, 0.5f) - 0.5f) * 10.0f; Vector2 viewOffset = drawOffset + drawOffsetNoise; Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); Rectangle prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle; spriteBatch.End(); spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, rect); spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable); for (int x = 0; x < mapTiles.GetLength(0); x++) { for (int y = 0; y < mapTiles.GetLength(1); y++) { Vector2 mapPos = new Vector2( x * generationParams.TileSpriteSpacing.X + ((y % 2 == 0) ? 0.0f : generationParams.TileSpriteSpacing.X * 0.5f), y * generationParams.TileSpriteSpacing.Y); mapPos.X -= size / 2 * (BackgroundScale - 1.0f); mapPos.Y -= size / 2 * (BackgroundScale - 1.0f); Vector2 scale = new Vector2( generationParams.TileSpriteSize.X / mapTiles[x, y].Sprite.size.X, generationParams.TileSpriteSize.Y / mapTiles[x, y].Sprite.size.Y); mapTiles[x, y].Sprite.Draw(spriteBatch, rectCenter + (mapPos + viewOffset) * zoom, Color.White, origin: new Vector2(256.0f, 256.0f), rotate: 0, scale: scale * zoom, spriteEffect: mapTiles[x, y].SpriteEffect); } } #if DEBUG if (generationParams.ShowNoiseMap) { GUI.DrawRectangle(spriteBatch, rectCenter + (borders.Location.ToVector2() + viewOffset) * zoom, borders.Size.ToVector2() * zoom, Color.White, true); } #endif Vector2 topLeft = rectCenter + viewOffset * zoom; topLeft.X = (int)topLeft.X; topLeft.Y = (int)topLeft.Y; Vector2 bottomRight = rectCenter + (viewOffset + new Vector2(size, size)) * zoom; bottomRight.X = (int)bottomRight.X; bottomRight.Y = (int)bottomRight.Y; spriteBatch.Draw(noiseTexture, destinationRectangle: new Rectangle((int)topLeft.X, (int)topLeft.Y, (int)(bottomRight.X - topLeft.X), (int)(bottomRight.Y - topLeft.Y)), sourceRectangle: null, color: Color.White); if (topLeft.X > rect.X) { GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Y, (int)(topLeft.X - rect.X), rect.Height), Color.Black * 0.8f, true); } if (topLeft.Y > rect.Y) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, rect.Y, (int)(bottomRight.X - topLeft.X), (int)(topLeft.Y - rect.Y)), Color.Black * 0.8f, true); } if (bottomRight.X < rect.Right) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)bottomRight.X, rect.Y, (int)(rect.Right - bottomRight.X), rect.Height), Color.Black * 0.8f, true); } if (bottomRight.Y < rect.Bottom) { GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, (int)bottomRight.Y, (int)(bottomRight.X - topLeft.X), (int)(rect.Bottom - bottomRight.Y)), Color.Black * 0.8f, true); } var sourceRect = rect; float rawNoiseScale = 1.0f + Noise[(int)(Timing.TotalTime * 100 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 100 % Noise.GetLength(1) - 1)]; cameraNoiseStrength = Noise[(int)(Timing.TotalTime * 10 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 10 % Noise.GetLength(1) - 1)]; rawNoiseSprite.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(), startOffset: new Point(Rand.Range(0, rawNoiseSprite.SourceRect.Width), Rand.Range(0, rawNoiseSprite.SourceRect.Height)), color: Color.White * cameraNoiseStrength * 0.5f, textureScale: Vector2.One * rawNoiseScale); if (generationParams.ShowLocations) { foreach (LocationConnection connection in connections) { Color connectionColor; if (GameMain.DebugDraw) { float sizeFactor = MathUtils.InverseLerp( MapGenerationParams.Instance.SmallLevelConnectionLength, MapGenerationParams.Instance.LargeLevelConnectionLength, connection.Length); connectionColor = ToolBox.GradientLerp(sizeFactor, Color.LightGreen, Color.Orange, Color.Red); } else { connectionColor = ToolBox.GradientLerp(connection.Difficulty / 100.0f, MapGenerationParams.Instance.LowDifficultyColor, MapGenerationParams.Instance.MediumDifficultyColor, MapGenerationParams.Instance.HighDifficultyColor); } int width = (int)(3 * zoom); if (selectedLocation != currentLocation && (connection.Locations.Contains(selectedLocation) && connection.Locations.Contains(currentLocation))) { connectionColor = Color.Gold; } else if (highlightedLocation != currentLocation && (connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation))) { connectionColor = Color.Lerp(connectionColor, Color.White, 0.5f); width *= 2; } else if (!connection.Passed) { //crackColor *= 0.5f; } for (int i = 0; i < connection.CrackSegments.Count; i++) { var segment = connection.CrackSegments[i]; Vector2 start = rectCenter + (segment[0] + viewOffset) * zoom; Vector2 end = rectCenter + (segment[1] + viewOffset) * zoom; if (!rect.Contains(start) && !rect.Contains(end)) { continue; } else { Vector2?intersection = MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(rect.X, rect.Y + rect.Height, rect.Width, rect.Height)); if (intersection != null) { if (!rect.Contains(start)) { start = (Vector2)intersection; } else { end = (Vector2)intersection; } } } float distFromPlayer = Vector2.Distance(currentLocation.MapPosition, (segment[0] + segment[1]) / 2.0f); float dist = Vector2.Distance(start, end); float a = GameMain.DebugDraw ? 1.0f : (200.0f - distFromPlayer) / 200.0f; spriteBatch.Draw(generationParams.ConnectionSprite.Texture, new Rectangle((int)start.X, (int)start.Y, (int)(dist - 1 * zoom), width), null, connectionColor * MathHelper.Clamp(a, 0.1f, 0.5f), MathUtils.VectorToAngle(end - start), new Vector2(0, 16), SpriteEffects.None, 0.01f); } if (GameMain.DebugDraw && zoom > 1.0f && generationParams.ShowLevelTypeNames) { Vector2 center = rectCenter + (connection.CenterPos + viewOffset) * zoom; if (rect.Contains(center)) { GUI.DrawString(spriteBatch, center, connection.Biome.Name + " (" + connection.Difficulty + ")", Color.White); } } } rect.Inflate(8, 8); GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8); GUI.DrawRectangle(spriteBatch, rect, Color.LightGray); for (int i = 0; i < locations.Count; i++) { Location location = locations[i]; Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; float iconScale = MapGenerationParams.Instance.LocationIconSize / location.Type.Sprite.size.X; Rectangle drawRect = location.Type.Sprite.SourceRect; drawRect.X = (int)pos.X - drawRect.Width / 2; drawRect.Y = (int)pos.Y - drawRect.Width / 2; if (!rect.Intersects(drawRect)) { continue; } Color color = location.Type.SpriteColor; if (location.Connections.Find(c => c.Locations.Contains(currentLocation)) == null) { color *= 0.5f; } //color *= (location.Discovered) ? 0.8f : 0.5f; //if (location != currentLocation) color *= 1.0f; if (location == highlightedLocation) { iconScale *= 1.1f; color = Color.Lerp(color, Color.White, 0.5f); } location.Type.Sprite.Draw(spriteBatch, pos, color, scale: iconScale * zoom); } } DrawDecorativeHUD(spriteBatch, rect); for (int i = 0; i < 3; i++) { Location location = (i == 0) ? highlightedLocation : selectedLocation; if (i == 2) { location = currentLocation; } if (location == null) { continue; } Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom; //pos.X = (int)(pos.X + location.Type.Sprite.SourceRect.Width * 0.6f); pos.Y = (int)(pos.Y + 15 * zoom); GUI.DrawString(spriteBatch, pos - GUI.Font.MeasureString(location.Name) * 0.5f, location.Name, Color.White * hudOpenState, Color.Black * 0.8f * hudOpenState, 3); GUI.DrawString(spriteBatch, pos + Vector2.UnitY * 25 - GUI.Font.MeasureString(location.Type.DisplayName) * 0.5f, location.Type.DisplayName, Color.White * hudOpenState, Color.Black * 0.8f * hudOpenState, 3); } GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect; spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred); }