From ba42b6896e09211aeee6563b000b947595e275f2 Mon Sep 17 00:00:00 2001 From: Squid Coder Date: Wed, 12 Feb 2025 17:25:25 -0600 Subject: [PATCH 1/7] Draw a mimicry of DF's selection rectangle and tooltip --- GUI.cpp | 84 +++++++++++++++++++++++++++++++++++++++++++++----- MapLoading.cpp | 12 ++++---- 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/GUI.cpp b/GUI.cpp index 59b2d053..da7b9234 100644 --- a/GUI.cpp +++ b/GUI.cpp @@ -511,20 +511,87 @@ namespace { auto& ssConfig = stonesenseState.ssConfig; Crd3D& selection = segment->segState.dfSelection; - if ((selection.x != -30000 && ssConfig.config.follow_DFcursor)) { - drawCursorAt(segment, selection, uiColor(3)); + if (selection.x >= 0) { + drawCursorAt(segment, selection, uiColor(4)); } else { return; } } - void drawDebugCursor(WorldSegment* segment) + void drawMainCursor(WorldSegment* segment) { Crd3D& cursor = segment->segState.dfCursor; - drawCursorAt(segment, cursor, uiColor(2)); + drawCursorAt(segment, cursor, uiColor(3)); } + void drawRulerTooltip(WorldSegment* segment) { + auto& font = stonesenseState.font; + auto fontHeight = al_get_font_line_height(font); + + Crd3D p1 = segment->segState.dfCursor; + Crd3D p2 = segment->segState.dfSelection; + Crd3D ruler = { + std::abs(p1.x - p2.x) + 1, + std::abs(p1.y - p2.y) + 1, + std::abs(p1.z - p2.z) + 1 + }; + if (p2.x >= 0) { + 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(1), + 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) { + Crd3D p1 = segment->segState.dfCursor; + Crd3D p2 = segment->segState.dfSelection; + if (p1.x >= 0 && p2.x >= 0) { + 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(2); + 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; @@ -896,6 +963,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); @@ -921,10 +993,6 @@ void paintboard() al_hold_bitmap_drawing(true); draw_textf_border(font, uiColor(1), 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 e97788f2..6bdb898f 100644 --- a/MapLoading.cpp +++ b/MapLoading.cpp @@ -946,12 +946,12 @@ void read_segment( void *arg) auto& ssState = stonesenseState.ssState; //read cursor - if (stonesenseState.ssConfig.config.follow_DFcursor) { - DFHack::Gui::getCursorCoords(ssState.dfCursor.x, ssState.dfCursor.y, ssState.dfCursor.z); - ssState.dfSelection.x = df::global::selection_rect->start_x; - ssState.dfSelection.y = df::global::selection_rect->start_y; - ssState.dfSelection.z = df::global::selection_rect->start_z; - } + df::coord mouseTemp = DFHack::Gui::getMousePos(); + ssState.dfCursor = { mouseTemp.x, mouseTemp.y, mouseTemp.z }; + DFHack::Gui::getDesignationCoords( + ssState.dfSelection.x, + ssState.dfSelection.y, + ssState.dfSelection.z); if (firstLoad || stonesenseState.ssConfig.config.track_mode != Config::TRACKING_NONE) { firstLoad = 0; From e31ed40e21ec96ca2c8d8ef1cb07e90431d5cb5a Mon Sep 17 00:00:00 2001 From: Squid Coder Date: Wed, 12 Feb 2025 17:30:24 -0600 Subject: [PATCH 2/7] Update changelog.txt --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index ecd1bf15..02cac5db 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 From 515d6a684dc697eea62cdab0f6fde3278b8b8cdb Mon Sep 17 00:00:00 2001 From: Squid Coder Date: Wed, 12 Feb 2025 17:51:52 -0600 Subject: [PATCH 3/7] remove unused var --- GUI.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/GUI.cpp b/GUI.cpp index da7b9234..fde92618 100644 --- a/GUI.cpp +++ b/GUI.cpp @@ -509,7 +509,6 @@ namespace void drawSelectionCursor(WorldSegment* segment) { - auto& ssConfig = stonesenseState.ssConfig; Crd3D& selection = segment->segState.dfSelection; if (selection.x >= 0) { drawCursorAt(segment, selection, uiColor(4)); From 733c2e33cbcf09a0140b15573c92a196f420eccf Mon Sep 17 00:00:00 2001 From: Squid Coder Date: Sun, 2 Mar 2025 19:37:06 -0600 Subject: [PATCH 4/7] Update to use the new uicolor syntax --- GUI.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GUI.cpp b/GUI.cpp index fde92618..85d0caeb 100644 --- a/GUI.cpp +++ b/GUI.cpp @@ -509,9 +509,9 @@ namespace void drawSelectionCursor(WorldSegment* segment) { - Crd3D& selection = segment->segState.dfSelection; - if (selection.x >= 0) { - drawCursorAt(segment, selection, uiColor(4)); + auto selection = segment->segState.dfSelection; + if (selection) { + drawCursorAt(segment, *selection, uiColor(dfColors::lgreen)); } else { return; @@ -577,7 +577,7 @@ namespace auto fadePercent = ((std::max(p1.z, p2.z) - z) * 100) / maxFadeDistance; // Closer = lower fade // Blend between base color and fade color - auto baseColor = uiColor(2); + auto baseColor = uiColor(dfColors::yellow); ALLEGRO_COLOR finalColor = partialBlend(baseColor, fadeColor, fadePercent); Crd3D point = { x, y, z }; From 913d21a831fa4329a98f64a8ea2507f4d96ed313 Mon Sep 17 00:00:00 2001 From: Squid Coder Date: Sun, 2 Mar 2025 19:42:59 -0600 Subject: [PATCH 5/7] use auto not crd3d --- GUI.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/GUI.cpp b/GUI.cpp index 39d32568..4492dce3 100644 --- a/GUI.cpp +++ b/GUI.cpp @@ -544,19 +544,19 @@ namespace auto& font = stonesenseState.font; auto fontHeight = al_get_font_line_height(font); - Crd3D p1 = segment->segState.dfCursor; - Crd3D p2 = segment->segState.dfSelection; - Crd3D ruler = { + auto p1 = segment->segState.dfCursor; + auto p2 = segment->segState.dfSelection; + auto ruler = { std::abs(p1.x - p2.x) + 1, std::abs(p1.y - p2.y) + 1, std::abs(p1.z - p2.z) + 1 }; if (p2.x >= 0) { df::coord mouseCoord = DFHack::Gui::getMousePos(); - Crd3D mousePos = { mouseCoord.x, mouseCoord.y, mouseCoord.z }; + auto 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); + auto mousePoint = LocalTileToScreen(mousePos.x, mousePos.y, mousePos.z); draw_text_border( font, uiColor(1), mousePoint.x + al_get_text_width(font, "-----"), @@ -569,8 +569,8 @@ namespace } void drawVolume(WorldSegment* segment) { - Crd3D p1 = segment->segState.dfCursor; - Crd3D p2 = segment->segState.dfSelection; + auto p1 = segment->segState.dfCursor; + auto p2 = segment->segState.dfSelection; if (p1.x >= 0 && p2.x >= 0) { 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); From d35f2a4ed3ec02723d5abc7997745bd5fbecec7f Mon Sep 17 00:00:00 2001 From: Squid Coder Date: Sun, 2 Mar 2025 19:55:47 -0600 Subject: [PATCH 6/7] Fix it fr now --- GUI.cpp | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/GUI.cpp b/GUI.cpp index 4492dce3..140067c8 100644 --- a/GUI.cpp +++ b/GUI.cpp @@ -533,8 +533,7 @@ namespace } } - void drawMainCursor(WorldSegment* segment) - { + void drawMainCursor(WorldSegment* segment) { auto& cursor = segment->segState.dfCursor; if (cursor) drawCursorAt(segment, *cursor, uiColor(dfColors::yellow)); @@ -544,37 +543,37 @@ namespace auto& font = stonesenseState.font; auto fontHeight = al_get_font_line_height(font); - auto p1 = segment->segState.dfCursor; - auto p2 = segment->segState.dfSelection; - auto ruler = { - std::abs(p1.x - p2.x) + 1, - std::abs(p1.y - p2.y) + 1, - std::abs(p1.z - p2.z) + 1 + 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.x >= 0) { + if (p2) { df::coord mouseCoord = DFHack::Gui::getMousePos(); - auto mousePos = { mouseCoord.x, mouseCoord.y, mouseCoord.z }; + Crd3D mousePos = { mouseCoord.x, mouseCoord.y, mouseCoord.z }; segment->CorrectTileForSegmentOffset(mousePos.x, mousePos.y, mousePos.z); segment->CorrectTileForSegmentRotation(mousePos.x, mousePos.y, mousePos.z); - auto mousePoint = LocalTileToScreen(mousePos.x, mousePos.y, mousePos.z); + Crd2D mousePoint = LocalTileToScreen(mousePos.x, mousePos.y, mousePos.z); draw_text_border( font, uiColor(1), 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()); + std::to_string(ruler->x) + "x" + + std::to_string(ruler->y) + "x" + + std::to_string(ruler->z)).c_str()); } } void drawVolume(WorldSegment* segment) { - auto p1 = segment->segState.dfCursor; - auto p2 = segment->segState.dfSelection; - if (p1.x >= 0 && p2.x >= 0) { - 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); + 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 @@ -590,7 +589,7 @@ namespace // 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 + 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); From 9c12ac890842edfe6fd9fde877c877b0ed6d626e Mon Sep 17 00:00:00 2001 From: Squid Coder Date: Mon, 3 Mar 2025 14:40:32 -0600 Subject: [PATCH 7/7] Various fixes Missed the ruler text and main cursor colors. also finally fixed the invalid cursor bug i had --- GUI.cpp | 6 +++--- MapLoading.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/GUI.cpp b/GUI.cpp index 140067c8..9d8944d8 100644 --- a/GUI.cpp +++ b/GUI.cpp @@ -536,7 +536,7 @@ namespace 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) { @@ -557,8 +557,8 @@ namespace segment->CorrectTileForSegmentRotation(mousePos.x, mousePos.y, mousePos.z); Crd2D mousePoint = LocalTileToScreen(mousePos.x, mousePos.y, mousePos.z); draw_text_border( - font, uiColor(1), - mousePoint.x + al_get_text_width(font, "-----"), + font, uiColor(dfColors::white), + mousePoint.x + al_get_text_width(font, "------"), mousePoint.y + fontHeight, ALLEGRO_ALIGN_LEFT, ( std::to_string(ruler->x) + "x" + 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;