diff --git a/Source/automap.cpp b/Source/automap.cpp index 30c6a0a94..d5f53e7e1 100644 --- a/Source/automap.cpp +++ b/Source/automap.cpp @@ -41,6 +41,8 @@ enum MapColors : uint8_t { MapColorsDim = (PAL16_YELLOW + 8), /** color for items on automap */ MapColorsItem = (PAL8_BLUE + 1), + /** color for activated pentragram on automap */ + MapColorsPentagramOpen = (PAL8_RED + 2), /** color for cave lava on automap */ MapColorsLava = (PAL8_ORANGE + 2), /** color for cave water on automap */ @@ -110,6 +112,8 @@ struct AutomapTile { VerticalBridgeLava, VerticalDiamond, HorizontalDiamond, + PentagramClosed, + PentagramOpen, }; Types type; @@ -785,6 +789,82 @@ void DrawCaveRightCorner(const Surface &out, Point center, uint8_t colorDim) DrawMapLineNE(out, center + AmOffset(AmWidthOffset::HalfTileRight, AmHeightOffset::None), AmLine(AmLineLength::HalfTile), colorDim); } +void DrawMapEllipse(const Surface &out, Point from, int radius, uint8_t colorIndex) +{ + const int a = radius; + const int b = radius / 2; + + int x = 0; + int y = b; + + // Offset ellipse so the center of the ellipse is the center of our megatile on the x plane + from.x -= radius; + + // Initial point + out.SetPixel({ from.x, from.y + b }, colorIndex); + out.SetPixel({ from.x, from.y - b }, colorIndex); + + // Initialize the parameters + int p1 = (b * b) - (a * a * b) + (a * a) / 4; + + // Region 1 + while ((b * b * x) < (a * a * y)) { + x++; + if (p1 < 0) { + p1 += (2 * b * b * x) + (b * b); + } else { + y--; + p1 += (2 * b * b * x) - (2 * a * a * y) + (b * b); + } + + out.SetPixel({ from.x + x, from.y + y }, colorIndex); + out.SetPixel({ from.x - x, from.y + y }, colorIndex); + out.SetPixel({ from.x + x, from.y - y }, colorIndex); + out.SetPixel({ from.x - x, from.y - y }, colorIndex); + } + + // Initialize the second parameter for Region 2 + int p2 = (b * b * ((x + 1) * (x + 1))) + (a * a * ((y - 1) * (y - 1))) - (a * a * b * b); + + // Region 2 + while (y > 0) { + y--; + if (p2 > 0) { + p2 += (-2 * a * a * y) + (a * a); + } else { + x++; + p2 += (2 * b * b * x) - (2 * a * a * y) + (a * a); + } + + out.SetPixel({ from.x + x, from.y + y }, colorIndex); + out.SetPixel({ from.x - x, from.y + y }, colorIndex); + out.SetPixel({ from.x + x, from.y - y }, colorIndex); + out.SetPixel({ from.x - x, from.y - y }, colorIndex); + } +} + +void DrawMapStar(const Surface &out, Point from, int radius, uint8_t color) +{ + const int scaleFactor = 128; + Point anchors[5]; + + // Offset star so the center of the star is the center of our megatile on the x plane + from.x -= radius; + + anchors[0] = { from.x - (121 * radius / scaleFactor), from.y + (19 * radius / scaleFactor) }; // Left Point + anchors[1] = { from.x + (121 * radius / scaleFactor), from.y + (19 * radius / scaleFactor) }; // Right Point + anchors[2] = { from.x, from.y + (64 * radius / scaleFactor) }; // Bottom Point + anchors[3] = { from.x - (75 * radius / scaleFactor), from.y - (51 * radius / scaleFactor) }; // Top Left Point + anchors[4] = { from.x + (75 * radius / scaleFactor), from.y - (51 * radius / scaleFactor) }; // Top Right Point + + // Draw lines between the anchors to form a star + DrawMapFreeLine(out, anchors[3], anchors[1], color); // Connect Top Left -> Right + DrawMapFreeLine(out, anchors[1], anchors[0], color); // Connect Right -> Left + DrawMapFreeLine(out, anchors[0], anchors[4], color); // Connect Left -> Top Right + DrawMapFreeLine(out, anchors[4], anchors[2], color); // Connect Top Right -> Bottom + DrawMapFreeLine(out, anchors[2], anchors[3], color); // Connect Bottom -> Top Left +} + /** * @brief Check if a given tile has the provided AutomapTile flag */ @@ -1099,6 +1179,20 @@ void DrawAutomapTile(const Surface &out, Point center, Point map) case AutomapTile::Types::VerticalBridgeLava: DrawLavaRiver(out, center, lavaColor, true); break; + case AutomapTile::Types::PentagramClosed: + // Functions are called twice to integrate shadow. Shadows are not drawn inside these functions to avoid shadows being drawn on top of normal pixels. + DrawMapEllipse(out, center + Displacement { 0, 1 }, AmLine(AmLineLength::OctupleTile), 0); // shadow + DrawMapStar(out, center + Displacement { 0, 1 }, AmLine(AmLineLength::OctupleTile), 0); // shadow + DrawMapEllipse(out, center, AmLine(AmLineLength::OctupleTile), colorDim); + DrawMapStar(out, center, AmLine(AmLineLength::OctupleTile), colorDim); + break; + case AutomapTile::Types::PentagramOpen: + // Functions are called twice to integrate shadow. Shadows are not drawn inside these functions to avoid shadows being drawn on top of normal pixels. + DrawMapEllipse(out, center + Displacement { 0, 1 }, AmLine(AmLineLength::OctupleTile), 0); // shadow + DrawMapStar(out, center + Displacement { 0, 1 }, AmLine(AmLineLength::OctupleTile), 0); // shadow + DrawMapEllipse(out, center, AmLine(AmLineLength::OctupleTile), MapColorsPentagramOpen); + DrawMapStar(out, center, AmLine(AmLineLength::OctupleTile), MapColorsPentagramOpen); + break; } } @@ -1441,6 +1535,8 @@ void InitAutomap() case DTYPE_HELL: tileTypes[51] = { AutomapTile::Types::VerticalDiamond }; tileTypes[55] = { AutomapTile::Types::HorizontalDiamond }; + tileTypes[102] = { AutomapTile::Types::PentagramClosed }; + tileTypes[111] = { AutomapTile::Types::PentagramOpen }; break; default: break; diff --git a/Source/automap.h b/Source/automap.h index cdc3335d0..1a9cd26e7 100644 --- a/Source/automap.h +++ b/Source/automap.h @@ -75,6 +75,7 @@ enum class AmLineLength : uint8_t { FullTile = 8, FullAndHalfTile = 12, DoubleTile = 16, + OctupleTile = 64, }; inline Displacement AmOffset(AmWidthOffset x, AmHeightOffset y) diff --git a/Source/engine/render/automap_render.cpp b/Source/engine/render/automap_render.cpp index 9dc5de048..26214ab6a 100644 --- a/Source/engine/render/automap_render.cpp +++ b/Source/engine/render/automap_render.cpp @@ -94,4 +94,34 @@ void DrawMapLineSteepSW(const Surface &out, Point from, int width, std::uint8_t DrawMapLineSteep(out, from, width, colorIndex); } +/** + * @brief Draws a line from first point to second point, unrestricted to the standard automap angles. Doesn't include shadow. + */ +void DrawMapFreeLine(const Surface &out, Point from, Point to, uint8_t colorIndex) +{ + int dx = std::abs(to.x - from.x); + int dy = std::abs(to.y - from.y); + int sx = from.x < to.x ? 1 : -1; + int sy = from.y < to.y ? 1 : -1; + int err = dx - dy; + + while (true) { + out.SetPixel(from, colorIndex); + + if (from.x == to.x && from.y == to.y) { + break; + } + + int e2 = 2 * err; + if (e2 > -dy) { + err -= dy; + from.x += sx; + } + if (e2 < dx) { + err += dx; + from.y += sy; + } + } +} + } // namespace devilution diff --git a/Source/engine/render/automap_render.hpp b/Source/engine/render/automap_render.hpp index df342eac7..1025ce809 100644 --- a/Source/engine/render/automap_render.hpp +++ b/Source/engine/render/automap_render.hpp @@ -88,5 +88,6 @@ void DrawMapLineSteepNW(const Surface &out, Point from, int width, std::uint8_t * The end point is at `{ from.x - (width + 1), from.y + 2 * width }`. */ void DrawMapLineSteepSW(const Surface &out, Point from, int width, std::uint8_t colorIndex); +void DrawMapFreeLine(const Surface &out, Point from, Point to, uint8_t colorIndex); } // namespace devilution