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
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
/// <summary>
/// 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.
/// </summary>
private long _lastDeathCheckMs;
private readonly Stopwatch _deathCheckSw = Stopwatch.StartNew();
private async Task<bool> 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,10 +487,16 @@ 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;
// Only check healthbar + death every ~500ms to avoid blocking combat
if (sw.ElapsedMilliseconds - lastCheckMs > 500)
{
lastCheckMs = sw.ElapsedMilliseconds;
if (await CheckDeath()) continue;
if (await IsBossAlive())
@ -486,6 +504,7 @@ public class BossRunExecutor : GameExecutor
Log.Information("Boss healthbar detected after {Ms}ms", sw.ElapsedMilliseconds);
return true;
}
}
// Attack toward YOLO-detected boss if available, otherwise last known position
var snapshot = _bossDetector.Latest;

View file

@ -17,7 +17,7 @@ public interface IScreenReader : IDisposable
Task Snapshot();
Task<DiffOcrResponse> DiffOcr(string? savePath = null, 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);
void SetLootBaseline(System.Drawing.Bitmap frame);
List<LootLabel> DetectLootLabels(System.Drawing.Bitmap reference, System.Drawing.Bitmap current);

View file

@ -177,9 +177,10 @@ public class ScreenReader : IScreenReader
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);
if (!silent)
Log.Information("TemplateMatchAll: {Count} matches for {Template}", results.Count, Path.GetFileName(templatePath));
return Task.FromResult(results);
}