This commit is contained in:
Boki 2026-02-22 11:38:24 -05:00
parent 011269acab
commit bb8f50116a
5 changed files with 98 additions and 89 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 MiB

After

Width:  |  Height:  |  Size: 7.2 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 MiB

After

Width:  |  Height:  |  Size: 6.2 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 KiB

After

Width:  |  Height:  |  Size: 332 KiB

Before After
Before After

View file

@ -58,6 +58,8 @@ public class BossRunExecutor : GameExecutor
public override void Stop()
{
base.Stop();
_nav.Frozen = false;
FightPosition = null;
Log.Information("Boss run executor stop requested");
}
@ -358,106 +360,113 @@ public class BossRunExecutor : GameExecutor
FightPosition = (fightWorldX, fightWorldY);
await WalkToWorldPosition(fightWorldX, fightWorldY, cancelWhen: IsBossAlive);
_nav.Frozen = true; // Lock canvas — position tracking only
if (_stopped) { _nav.Frozen = false; return; }
// 3x fight-then-well loop
for (var phase = 1; phase <= 3; phase++)
try
{
if (_stopped) return;
var preWp = _nav.WorldPosition;
Log.Information("=== Boss phase {Phase}/4 === fightArea=({FX:F0},{FY:F0}) charPos=({CX:F1},{CY:F1})",
phase, fightWorldX, fightWorldY, preWp.X, preWp.Y);
var lastBossPos = await AttackBossUntilGone(fightWorldX, fightWorldY);
if (_stopped) return;
// Update fight area to where the boss was last seen
var postWp = _nav.WorldPosition;
Log.Information("Phase {Phase} ended: charPos=({CX:F1},{CY:F1}) lastBossPos={Boss}",
phase, postWp.X, postWp.Y,
lastBossPos != null ? $"({lastBossPos.Value.X:F1},{lastBossPos.Value.Y:F1})" : "null");
if (lastBossPos != null)
// 3x fight-then-well loop
for (var phase = 1; phase <= 3; phase++)
{
fightWorldX = lastBossPos.Value.X;
fightWorldY = lastBossPos.Value.Y;
FightPosition = (fightWorldX, fightWorldY);
Log.Information("Fight area updated to ({X:F0},{Y:F0})", fightWorldX, fightWorldY);
if (_stopped) return;
var preWp = _nav.WorldPosition;
Log.Information("=== Boss phase {Phase}/4 === fightArea=({FX:F0},{FY:F0}) charPos=({CX:F1},{CY:F1})",
phase, fightWorldX, fightWorldY, preWp.X, preWp.Y);
var lastBossPos = await AttackBossUntilGone(fightWorldX, fightWorldY);
if (_stopped) return;
// Update fight area to where the boss was last seen
var postWp = _nav.WorldPosition;
Log.Information("Phase {Phase} ended: charPos=({CX:F1},{CY:F1}) lastBossPos={Boss}",
phase, postWp.X, postWp.Y,
lastBossPos != null ? $"({lastBossPos.Value.X:F1},{lastBossPos.Value.Y:F1})" : "null");
if (lastBossPos != null)
{
fightWorldX = lastBossPos.Value.X;
fightWorldY = lastBossPos.Value.Y;
FightPosition = (fightWorldX, fightWorldY);
Log.Information("Fight area updated to ({X:F0},{Y:F0})", fightWorldX, fightWorldY);
}
// Wait for death animation before looking for well
await Sleep(3000);
// 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 Sleep(500);
await ClickClosestTemplateToCenter(CathedralWellTemplate);
await Sleep(200);
// Walk back to fight position for next phase
await WalkToWorldPosition(fightWorldX, fightWorldY, cancelWhen: IsBossAlive);
}
// Wait for death animation before looking for well
await Sleep(3000);
// 4th fight - no well after
if (_stopped) return;
{
var p4wp = _nav.WorldPosition;
Log.Information("=== Boss phase 4/4 === fightArea=({FX:F0},{FY:F0}) charPos=({CX:F1},{CY:F1})",
fightWorldX, fightWorldY, p4wp.X, p4wp.Y);
}
var finalBossPos = await AttackBossUntilGone(fightWorldX, fightWorldY);
if (_stopped) return;
// 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 Sleep(500);
await ClickClosestTemplateToCenter(CathedralWellTemplate);
await Sleep(200);
// Update fight area from phase 4 if we got detections
{
var p4postWp = _nav.WorldPosition;
Log.Information("Phase 4 ended: charPos=({CX:F1},{CY:F1}) finalBossPos={Boss}",
p4postWp.X, p4postWp.Y,
finalBossPos != null ? $"({finalBossPos.Value.X:F1},{finalBossPos.Value.Y:F1})" : "null");
}
if (finalBossPos != null)
{
fightWorldX = finalBossPos.Value.X;
fightWorldY = finalBossPos.Value.Y;
FightPosition = (fightWorldX, fightWorldY);
}
Log.Information("Ring phase: using fightArea=({FX:F0},{FY:F0})", fightWorldX, fightWorldY);
// Walk back to fight position for next phase
await WalkToWorldPosition(fightWorldX, fightWorldY, cancelWhen: IsBossAlive);
// Walk to known ring position and look for the template
await WalkToWorldPosition(-440, -330);
await Sleep(1000);
if (_stopped) return;
Log.Information("Looking for Return the Ring...");
var ring = await _screen.TemplateMatch(ReturnTheRingTemplate);
if (ring == null)
{
ring = await _screen.TemplateMatch(ReturnTheRingTemplate);
}
if (ring != null)
{
Log.Information("Found Return the Ring at ({X},{Y}), clicking", ring.X, ring.Y);
await _game.LeftClickAt(ring.X, ring.Y);
await Sleep(500);
}
else
{
Log.Error("Could not find Return the Ring template");
}
if (_stopped) return;
// Walk back to fight area — fightWorldX/Y carries position from all phases
Log.Information("Walking to fight position ({X:F0},{Y:F0})", fightWorldX, fightWorldY);
await WalkToWorldPosition(fightWorldX, fightWorldY);
await Sleep(300);
Log.Information("Attacking at ring fight position");
await AttackBossUntilGone(fightWorldX, fightWorldY);
if (_stopped) return;
StopBossDetection();
Log.Information("Fight complete");
}
// 4th fight - no well after
if (_stopped) return;
finally
{
var p4wp = _nav.WorldPosition;
Log.Information("=== Boss phase 4/4 === fightArea=({FX:F0},{FY:F0}) charPos=({CX:F1},{CY:F1})",
fightWorldX, fightWorldY, p4wp.X, p4wp.Y);
_nav.Frozen = false;
FightPosition = null;
}
var finalBossPos = await AttackBossUntilGone(fightWorldX, fightWorldY);
if (_stopped) return;
// Update fight area from phase 4 if we got detections
{
var p4postWp = _nav.WorldPosition;
Log.Information("Phase 4 ended: charPos=({CX:F1},{CY:F1}) finalBossPos={Boss}",
p4postWp.X, p4postWp.Y,
finalBossPos != null ? $"({finalBossPos.Value.X:F1},{finalBossPos.Value.Y:F1})" : "null");
}
if (finalBossPos != null)
{
fightWorldX = finalBossPos.Value.X;
fightWorldY = finalBossPos.Value.Y;
FightPosition = (fightWorldX, fightWorldY);
}
Log.Information("Ring phase: using fightArea=({FX:F0},{FY:F0})", fightWorldX, fightWorldY);
// Walk to known ring position and look for the template
await WalkToWorldPosition(-440, -330);
await Sleep(1000);
if (_stopped) return;
Log.Information("Looking for Return the Ring...");
var ring = await _screen.TemplateMatch(ReturnTheRingTemplate);
if (ring == null)
{
ring = await _screen.TemplateMatch(ReturnTheRingTemplate);
}
if (ring != null)
{
Log.Information("Found Return the Ring at ({X},{Y}), clicking", ring.X, ring.Y);
await _game.LeftClickAt(ring.X, ring.Y);
await Sleep(500);
}
else
{
Log.Error("Could not find Return the Ring template");
}
if (_stopped) return;
// Walk back to fight area — fightWorldX/Y carries position from all phases
Log.Information("Walking to fight position ({X:F0},{Y:F0})", fightWorldX, fightWorldY);
await WalkToWorldPosition(fightWorldX, fightWorldY);
await Sleep(300);
Log.Information("Attacking at ring fight position");
await AttackBossUntilGone(fightWorldX, fightWorldY);
if (_stopped) return;
StopBossDetection();
_nav.Frozen = false;
FightPosition = null;
Log.Information("Fight complete");
}
/// <summary>

View file

@ -87,7 +87,7 @@ internal sealed class D2dEnemyBoxLayer : ID2dOverlayLayer, IDisposable
if (state.FightPosition is var (fx, fy))
{
const double worldToScreen = 835.0 / 97.0; // inverse of screenToWorld
const int screenCx = 1280, screenCy = 720;
const int screenCx = 1280, screenCy = 660; // player character screen position
var wp = state.NavPosition;
var sx = (float)(screenCx + (fx - wp.X) * worldToScreen);
var sy = (float)(screenCy + (fy - wp.Y) * worldToScreen);