diff --git a/GUI.cpp b/GUI.cpp index 6675ae40..9d8944d8 100644 --- a/GUI.cpp +++ b/GUI.cpp @@ -524,9 +524,8 @@ namespace void drawSelectionCursor(WorldSegment* segment) { - auto& ssConfig = stonesenseState.ssConfig; auto selection = segment->segState.dfSelection; - if (selection && ssConfig.config.follow_DFcursor) { + if (selection) { drawCursorAt(segment, *selection, uiColor(dfColors::lgreen)); } else { @@ -534,13 +533,79 @@ namespace } } - void drawDebugCursor(WorldSegment* segment) - { + void drawMainCursor(WorldSegment* segment) { auto& cursor = segment->segState.dfCursor; if (cursor) - drawCursorAt(segment, *cursor, uiColor(dfColors::yellow)); + drawCursorAt(segment, *cursor, uiColor(dfColors::lblue)); } + void drawRulerTooltip(WorldSegment* segment) { + auto& font = stonesenseState.font; + auto fontHeight = al_get_font_line_height(font); + + OptCrd3D p1 = segment->segState.dfCursor; + OptCrd3D p2 = segment->segState.dfSelection; + OptCrd3D ruler = { + std::abs(p1->x - p2->x) + 1, + std::abs(p1->y - p2->y) + 1, + std::abs(p1->z - p2->z) + 1 + }; + if (p2) { + df::coord mouseCoord = DFHack::Gui::getMousePos(); + Crd3D mousePos = { mouseCoord.x, mouseCoord.y, mouseCoord.z }; + segment->CorrectTileForSegmentOffset(mousePos.x, mousePos.y, mousePos.z); + segment->CorrectTileForSegmentRotation(mousePos.x, mousePos.y, mousePos.z); + Crd2D mousePoint = LocalTileToScreen(mousePos.x, mousePos.y, mousePos.z); + draw_text_border( + font, uiColor(dfColors::white), + mousePoint.x + al_get_text_width(font, "------"), + mousePoint.y + fontHeight, ALLEGRO_ALIGN_LEFT, + ( + std::to_string(ruler->x) + "x" + + std::to_string(ruler->y) + "x" + + std::to_string(ruler->z)).c_str()); + } + } + + void drawVolume(WorldSegment* segment) { + OptCrd3D p1 = segment->segState.dfCursor; + OptCrd3D p2 = segment->segState.dfSelection; + if (p1 && p2) { + int minX = std::min(p1->x, p2->x), maxX = std::max(p1->x, p2->x); + int minY = std::min(p1->y, p2->y), maxY = std::max(p1->y, p2->y); + int minZ = std::min(p1->z, p2->z), maxZ = std::max(p1->z, p2->z); + + ALLEGRO_COLOR fadeColor = al_map_rgba(0, 0, 0, 0); // Fully transparent black + + for (int x = minX; x <= maxX; ++x) { + for (int y = minY; y <= maxY; ++y) { + for (int z = minZ; z <= maxZ; ++z) { + int edgeCount = 0; + if (x == minX || x == maxX) edgeCount++; + if (y == minY || y == maxY) edgeCount++; + if (z == minZ || z == maxZ) edgeCount++; + + if (edgeCount >= 2) { // Only draw points on edges + // Compute fade effect based on distance from the highest Z point + int maxFadeDistance = std::max(10, (maxZ - minZ)); + + auto fadePercent = ((std::max(p1->z, p2->z) - z) * 100) / maxFadeDistance; // Closer = lower fade + + // Blend between base color and fade color + auto baseColor = uiColor(dfColors::yellow); + ALLEGRO_COLOR finalColor = partialBlend(baseColor, fadeColor, fadePercent); + + Crd3D point = { x, y, z }; + drawCursorAt(segment, point, finalColor); + } + } + } + } + drawRulerTooltip(segment); + } + } + + void drawAdvmodeMenuTalk(const ALLEGRO_FONT* font, int x, int y) { //df::adventure * menu = df::global::adventure; @@ -919,6 +984,11 @@ void paintboard() stonesenseState.stoneSenseTimers.frame_total.update(donetime - stonesenseState.stoneSenseTimers.prev_frame_time); stonesenseState.stoneSenseTimers.prev_frame_time = donetime; + + drawVolume(segment); + drawSelectionCursor(segment); + drawMainCursor(segment); + if (ssConfig.show_announcements) { al_hold_bitmap_drawing(true); draw_announcements(font, ssState.ScreenW, ssState.ScreenH - 10 - al_get_font_line_height(font), ALLEGRO_ALIGN_RIGHT, df::global::world->status.announcements); @@ -944,10 +1014,6 @@ void paintboard() al_hold_bitmap_drawing(true); draw_textf_border(font, uiColor(dfColors::white), 10,fontHeight, 0, "%i,%i,%i, r%i, z%i", ssState.Position.x,ssState.Position.y,ssState.Position.z, ssState.Rotation, ssConfig.zoom); - drawSelectionCursor(segment); - - drawDebugCursor(segment); - drawAdvmodeMenuTalk(font, 5, ssState.ScreenH - 5); if(ssConfig.config.debug_mode) { diff --git a/MapLoading.cpp b/MapLoading.cpp index ce2ad862..a1a4c94c 100644 --- a/MapLoading.cpp +++ b/MapLoading.cpp @@ -946,10 +946,11 @@ void read_segment( void *arg) auto& ssState = stonesenseState.ssState; //read cursor - if (stonesenseState.ssConfig.config.follow_DFcursor) { - ssState.dfCursor = DFHack::Gui::getCursorPos(); - ssState.dfSelection = OptCrd3D { df::global::selection_rect->start_x, df::global::selection_rect->start_y, df::global::selection_rect->start_z }; + df::coord mouseTemp = DFHack::Gui::getMousePos(); + if (mouseTemp.isValid()) { + ssState.dfCursor = { mouseTemp.x, mouseTemp.y, mouseTemp.z }; } + ssState.dfSelection = OptCrd3D { df::global::selection_rect->start_x, df::global::selection_rect->start_y, df::global::selection_rect->start_z }; if (firstLoad || stonesenseState.ssConfig.config.track_mode != Config::TRACKING_NONE) { firstLoad = 0; diff --git a/docs/changelog.txt b/docs/changelog.txt index db5c34e4..41d5e218 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,6 +38,7 @@ Template for new versions: # Future ## New Features +- `stonesense`: Stonesense now shows a selection rectangle much like DF does and also a cursor following DF's mouse position ## Fixes - `stonesense`: megashots no longer leave stonesense unresponsive