This commit is contained in:
Boki 2026-02-21 15:56:52 -05:00
parent 64a6ab694b
commit 109b1b4059
6 changed files with 33 additions and 13 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 MiB

After

Width:  |  Height:  |  Size: 7.5 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 MiB

After

Width:  |  Height:  |  Size: 6.3 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 KiB

After

Width:  |  Height:  |  Size: 354 KiB

Before After
Before After

View file

@ -368,6 +368,7 @@ public class BossRunExecutor : GameExecutor
// Walk to well and click the closest match to screen center // Walk to well and click the closest match to screen center
Log.Information("Phase {Phase} done, walking to well", phase); Log.Information("Phase {Phase} done, walking to well", phase);
await WalkToWorldPosition(wellWorldX, wellWorldY); await WalkToWorldPosition(wellWorldX, wellWorldY);
await Helpers.Sleep(1000);
await ClickClosestTemplateToCenter(CathedralWellTemplate); await ClickClosestTemplateToCenter(CathedralWellTemplate);
await Helpers.Sleep(200); await Helpers.Sleep(200);
@ -378,11 +379,14 @@ public class BossRunExecutor : GameExecutor
// 4th fight - no well after // 4th fight - no well after
if (_stopped) return; if (_stopped) return;
Log.Information("=== Boss phase 4/4 ==="); Log.Information("=== Boss phase 4/4 ===");
await AttackBossUntilGone(); var phase4BossPos = await AttackBossUntilGone();
if (_stopped) return; if (_stopped) return;
// Walk to ring area and return it // Walk toward where the boss died (ring spawns there)
await WalkToWorldPosition(-440, -330); 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; if (_stopped) return;
Log.Information("Looking for Return the Ring..."); Log.Information("Looking for Return the Ring...");
@ -438,13 +442,13 @@ public class BossRunExecutor : GameExecutor
var topRegion = new Region(750, 16, 1068, 96); var topRegion = new Region(750, 16, 1068, 96);
// Check all three healthbar templates — boss is alive if ANY matches // 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; 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; 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; if (m3.Count > 0) return true;
return false; return false;
@ -452,10 +456,18 @@ public class BossRunExecutor : GameExecutor
/// <summary> /// <summary>
/// Check for the "Resurrect at Checkpoint" button — means we died. /// 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. /// If found, click it, wait for respawn, and return true.
/// </summary> /// </summary>
private long _lastDeathCheckMs;
private readonly Stopwatch _deathCheckSw = Stopwatch.StartNew();
private async Task<bool> CheckDeath() private async Task<bool> CheckDeath()
{ {
var now = _deathCheckSw.ElapsedMilliseconds;
if (now - _lastDeathCheckMs < 2000) return false;
_lastDeathCheckMs = now;
var match = await _screen.TemplateMatch(ResurrectTemplate); var match = await _screen.TemplateMatch(ResurrectTemplate);
if (match == null) return false; if (match == null) return false;
@ -475,16 +487,23 @@ public class BossRunExecutor : GameExecutor
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
var atkX = 1280; var atkX = 1280;
var atkY = 720; var atkY = 720;
var lastCheckMs = 0L;
while (sw.ElapsedMilliseconds < timeoutMs) while (sw.ElapsedMilliseconds < timeoutMs)
{ {
if (_stopped) return false; 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); lastCheckMs = sw.ElapsedMilliseconds;
return true; 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 // Attack toward YOLO-detected boss if available, otherwise last known position

View file

@ -17,7 +17,7 @@ public interface IScreenReader : IDisposable
Task Snapshot(); Task Snapshot();
Task<DiffOcrResponse> DiffOcr(string? savePath = null, Region? region = null); Task<DiffOcrResponse> DiffOcr(string? savePath = null, Region? region = null);
Task<TemplateMatchResult?> TemplateMatch(string templatePath, Region? region = null); Task<TemplateMatchResult?> TemplateMatch(string templatePath, Region? region = null);
Task<List<TemplateMatchResult>> TemplateMatchAll(string templatePath, Region? region = null, double threshold = 0.7); Task<List<TemplateMatchResult>> TemplateMatchAll(string templatePath, Region? region = null, double threshold = 0.7, bool silent = false);
Task<OcrResponse> NameplateDiffOcr(System.Drawing.Bitmap reference, System.Drawing.Bitmap current); Task<OcrResponse> NameplateDiffOcr(System.Drawing.Bitmap reference, System.Drawing.Bitmap current);
void SetLootBaseline(System.Drawing.Bitmap frame); void SetLootBaseline(System.Drawing.Bitmap frame);
List<LootLabel> DetectLootLabels(System.Drawing.Bitmap reference, System.Drawing.Bitmap current); List<LootLabel> DetectLootLabels(System.Drawing.Bitmap reference, System.Drawing.Bitmap current);

View file

@ -177,10 +177,11 @@ public class ScreenReader : IScreenReader
return Task.FromResult(result); return Task.FromResult(result);
} }
public Task<List<TemplateMatchResult>> TemplateMatchAll(string templatePath, Region? region = null, double threshold = 0.7) public Task<List<TemplateMatchResult>> TemplateMatchAll(string templatePath, Region? region = null, double threshold = 0.7, bool silent = false)
{ {
var results = _templateMatch.MatchAll(templatePath, region, threshold); 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); return Task.FromResult(results);
} }