diff --git a/debug_loot_capture.png b/debug_loot_capture.png index 8fac337..1fb1a3e 100644 Binary files a/debug_loot_capture.png and b/debug_loot_capture.png differ diff --git a/debug_loot_detected.png b/debug_loot_detected.png index 15f766c..3199c9e 100644 Binary files a/debug_loot_detected.png and b/debug_loot_detected.png differ diff --git a/debug_loot_edges.png b/debug_loot_edges.png index 2639463..cc4da60 100644 Binary files a/debug_loot_edges.png and b/debug_loot_edges.png differ diff --git a/src/Poe2Trade.Bot/BossRunExecutor.cs b/src/Poe2Trade.Bot/BossRunExecutor.cs index f97b103..c78b804 100644 --- a/src/Poe2Trade.Bot/BossRunExecutor.cs +++ b/src/Poe2Trade.Bot/BossRunExecutor.cs @@ -368,6 +368,7 @@ public class BossRunExecutor : GameExecutor // Walk to well and click the closest match to screen center Log.Information("Phase {Phase} done, walking to well", phase); await WalkToWorldPosition(wellWorldX, wellWorldY); + await Helpers.Sleep(1000); await ClickClosestTemplateToCenter(CathedralWellTemplate); await Helpers.Sleep(200); @@ -378,11 +379,14 @@ public class BossRunExecutor : GameExecutor // 4th fight - no well after if (_stopped) return; Log.Information("=== Boss phase 4/4 ==="); - await AttackBossUntilGone(); + var phase4BossPos = await AttackBossUntilGone(); if (_stopped) return; - // Walk to ring area and return it - await WalkToWorldPosition(-440, -330); + // Walk toward where the boss died (ring spawns there) + var ringX = phase4BossPos?.X ?? fightWorldX; + var ringY = phase4BossPos?.Y ?? fightWorldY; + Log.Information("Walking to ring area ({X:F0},{Y:F0})", ringX, ringY); + await WalkToWorldPosition(ringX, ringY); if (_stopped) return; Log.Information("Looking for Return the Ring..."); @@ -438,13 +442,13 @@ public class BossRunExecutor : GameExecutor var topRegion = new Region(750, 16, 1068, 96); // Check all three healthbar templates — boss is alive if ANY matches - var m1 = await _screen.TemplateMatchAll(BossHealthbarTemplate, topRegion, threshold: 0.5); + var m1 = await _screen.TemplateMatchAll(BossHealthbarTemplate, topRegion, threshold: 0.5, silent: true); if (m1.Count > 0) return true; - var m2 = await _screen.TemplateMatchAll(BossHealthbarTemplate2, topRegion, threshold: 0.5); + var m2 = await _screen.TemplateMatchAll(BossHealthbarTemplate2, topRegion, threshold: 0.5, silent: true); if (m2.Count > 0) return true; - var m3 = await _screen.TemplateMatchAll(BossHealthbarTemplate3, topRegion, threshold: 0.5); + var m3 = await _screen.TemplateMatchAll(BossHealthbarTemplate3, topRegion, threshold: 0.5, silent: true); if (m3.Count > 0) return true; return false; @@ -452,10 +456,18 @@ public class BossRunExecutor : GameExecutor /// /// Check for the "Resurrect at Checkpoint" button — means we died. + /// Self-throttled: only actually checks every 2s to avoid slowing combat. /// If found, click it, wait for respawn, and return true. /// + private long _lastDeathCheckMs; + private readonly Stopwatch _deathCheckSw = Stopwatch.StartNew(); + private async Task CheckDeath() { + var now = _deathCheckSw.ElapsedMilliseconds; + if (now - _lastDeathCheckMs < 2000) return false; + _lastDeathCheckMs = now; + var match = await _screen.TemplateMatch(ResurrectTemplate); if (match == null) return false; @@ -475,16 +487,23 @@ public class BossRunExecutor : GameExecutor var sw = Stopwatch.StartNew(); var atkX = 1280; var atkY = 720; + var lastCheckMs = 0L; while (sw.ElapsedMilliseconds < timeoutMs) { if (_stopped) return false; - if (await CheckDeath()) continue; - if (await IsBossAlive()) + // Only check healthbar + death every ~500ms to avoid blocking combat + if (sw.ElapsedMilliseconds - lastCheckMs > 500) { - Log.Information("Boss healthbar detected after {Ms}ms", sw.ElapsedMilliseconds); - return true; + lastCheckMs = sw.ElapsedMilliseconds; + if (await CheckDeath()) continue; + + if (await IsBossAlive()) + { + Log.Information("Boss healthbar detected after {Ms}ms", sw.ElapsedMilliseconds); + return true; + } } // Attack toward YOLO-detected boss if available, otherwise last known position diff --git a/src/Poe2Trade.Screen/IScreenReader.cs b/src/Poe2Trade.Screen/IScreenReader.cs index 76a3c6e..a5e371a 100644 --- a/src/Poe2Trade.Screen/IScreenReader.cs +++ b/src/Poe2Trade.Screen/IScreenReader.cs @@ -17,7 +17,7 @@ public interface IScreenReader : IDisposable Task Snapshot(); Task DiffOcr(string? savePath = null, Region? region = null); Task TemplateMatch(string templatePath, Region? region = null); - Task> TemplateMatchAll(string templatePath, Region? region = null, double threshold = 0.7); + Task> TemplateMatchAll(string templatePath, Region? region = null, double threshold = 0.7, bool silent = false); Task NameplateDiffOcr(System.Drawing.Bitmap reference, System.Drawing.Bitmap current); void SetLootBaseline(System.Drawing.Bitmap frame); List DetectLootLabels(System.Drawing.Bitmap reference, System.Drawing.Bitmap current); diff --git a/src/Poe2Trade.Screen/ScreenReader.cs b/src/Poe2Trade.Screen/ScreenReader.cs index 1647133..b4c64ef 100644 --- a/src/Poe2Trade.Screen/ScreenReader.cs +++ b/src/Poe2Trade.Screen/ScreenReader.cs @@ -177,10 +177,11 @@ public class ScreenReader : IScreenReader return Task.FromResult(result); } - public Task> TemplateMatchAll(string templatePath, Region? region = null, double threshold = 0.7) + public Task> TemplateMatchAll(string templatePath, Region? region = null, double threshold = 0.7, bool silent = false) { var results = _templateMatch.MatchAll(templatePath, region, threshold); - Log.Information("TemplateMatchAll: {Count} matches for {Template}", results.Count, Path.GetFileName(templatePath)); + if (!silent) + Log.Information("TemplateMatchAll: {Count} matches for {Template}", results.Count, Path.GetFileName(templatePath)); return Task.FromResult(results); }