sami test

This commit is contained in:
2026-04-02 20:00:21 +02:00
parent f004205069
commit 1e3c2b176d
2 changed files with 83 additions and 13 deletions

View File

@@ -10,6 +10,7 @@
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Orientation="Horizontal" Spacing="8">
<Button x:Name="StartButton" Content="Start Bot" Width="120"/>
<Button x:Name="StopButton" Content="Stop Bot" Width="120" IsEnabled="False"/>
<CheckBox x:Name="MultiplayerCheckBox" Content="Multiplayer" VerticalAlignment="Center"/>
<TextBlock Text="API Key:" VerticalAlignment="Center"/>
<TextBox x:Name="ApiKeyBox" Width="360" Watermark="GUID player token"/>
<TextBlock x:Name="StatusText" VerticalAlignment="Center" Text="Idle"/>

View File

@@ -32,6 +32,7 @@ public partial class MainWindow : Window
};
private readonly string _configuredApiKey = Program.Configuration["APIKEY"] ?? string.Empty;
private readonly bool _multiplayerModeDefault = bool.TryParse(Program.Configuration["MULTIPLAYER"], out var multiplayer) && multiplayer;
private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(8) };
private readonly DigitalDojoApiClient _client;
private readonly ObservableCollection<string> _logEntries = [];
@@ -85,6 +86,7 @@ public partial class MainWindow : Window
BuildKnowledgeGrid();
ApiKeyBox.Text = _configuredApiKey;
MultiplayerCheckBox.IsChecked = _multiplayerModeDefault;
LogList.ItemsSource = _logEntries;
StartButton.Click += async (_, _) => await StartBotAsync();
@@ -122,6 +124,7 @@ public partial class MainWindow : Window
StartButton.IsEnabled = false;
StopButton.IsEnabled = true;
ApiKeyBox.IsEnabled = false;
MultiplayerCheckBox.IsEnabled = false;
ResetKnowledgeState();
@@ -185,6 +188,7 @@ public partial class MainWindow : Window
StartButton.IsEnabled = true;
StopButton.IsEnabled = false;
ApiKeyBox.IsEnabled = true;
MultiplayerCheckBox.IsEnabled = true;
SetStatus("Stopped.");
}
@@ -211,6 +215,13 @@ public partial class MainWindow : Window
return false;
}
if (IsMultiplayerMode)
{
// In multiplayer, the lobby controls game creation/start.
AppendLog("Multiplayer mode enabled; waiting for lobby game start (no create call).");
return true;
}
try
{
var created = await _client.CreateAsync(_playerToken, ct);
@@ -501,6 +512,12 @@ public partial class MainWindow : Window
// Teleport closer to enemy for aggressive positioning
var moveTowardX = targetX > 0 ? targetX - 1 : targetX + 1;
var moveTowardY = targetY > 0 ? targetY - 1 : targetY + 1;
var teleportDirection = DirectionFromVector(moveTowardX, moveTowardY);
if (IsDirectionUnsafeForHighSpeedMove(teleportDirection))
{
moveTowardX = targetX;
moveTowardY = targetY;
}
return new BotDecision(
"teleport-aggro",
@@ -509,16 +526,26 @@ public partial class MainWindow : Window
{
var response = await _client.TeleportAsync(_playerToken, moveTowardX, moveTowardY, ct);
MarkUsed(BotAction.Teleport);
if (response.Executed)
if (response.Executed && !response.LandedInWall)
{
_x = moveTowardX;
_y = moveTowardY;
}
if (response.LandedInWall)
{
var dir = DirectionFromVector(moveTowardX, moveTowardY);
_blockedDirectionTicks.TryGetValue(dir, out var blocked);
_blockedDirectionTicks[dir] = Math.Max(blocked, 14);
_survivalTicks = Math.Max(_survivalTicks, 10);
_sessionLogger?.LogEvent("teleport-wall", $"x={moveTowardX};y={moveTowardY}");
}
return response.Executed;
});
}
if (Ready(BotAction.Dash) && TryGetAggressiveDashDirection(predictedEnemy, bestSight, out var dashDirection, out var dashReason))
if (Ready(BotAction.Dash) && TryGetAggressiveDashDirection(predictedEnemy, bestSight.Key, bestSight.Value, out var dashDirection, out var dashReason))
{
return new BotDecision(
"dash-aggro",
@@ -529,7 +556,19 @@ public partial class MainWindow : Window
MarkUsed(BotAction.Dash);
if (response.Executed)
{
ApplyMovement(dashDirection, Math.Max(response.BlocksDashed, 1));
var movedBlocks = Math.Max(response.BlocksDashed, 0);
if (movedBlocks > 0)
{
ApplyMovement(dashDirection, movedBlocks);
}
if (response.DamageTaken > 0)
{
_blockedDirectionTicks.TryGetValue(dashDirection, out var blocked);
_blockedDirectionTicks[dashDirection] = Math.Max(blocked, 12);
_survivalTicks = Math.Max(_survivalTicks, 8);
_sessionLogger?.LogEvent("dash-self-damage", $"dir={dashDirection};damage={response.DamageTaken};blocks={response.BlocksDashed}");
}
}
return response.Executed;
@@ -581,7 +620,20 @@ public partial class MainWindow : Window
MarkUsed(BotAction.Dash);
if (response.Executed)
{
ApplyMovement(retreatDirection, Math.Max(response.BlocksDashed, 1));
var movedBlocks = Math.Max(response.BlocksDashed, 0);
if (movedBlocks > 0)
{
ApplyMovement(retreatDirection, movedBlocks);
}
if (response.DamageTaken > 0)
{
_blockedDirectionTicks.TryGetValue(retreatDirection, out var blocked);
_blockedDirectionTicks[retreatDirection] = Math.Max(blocked, 12);
_survivalTicks = Math.Max(_survivalTicks, 10);
_sessionLogger?.LogEvent("dash-self-damage", $"dir={retreatDirection};damage={response.DamageTaken};blocks={response.BlocksDashed}");
}
_escapeDirection = retreatDirection;
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
}
@@ -1025,7 +1077,8 @@ public partial class MainWindow : Window
private bool TryGetAggressiveDashDirection(
(int X, int Y)? predictedEnemy,
KeyValuePair<Direction, PeekEntitiesAsyncResponse>? bestSight,
Direction? sightDirection,
PeekEntitiesAsyncResponse? sightResponse,
out Direction direction,
out string reason)
{
@@ -1033,20 +1086,24 @@ public partial class MainWindow : Window
{
var target = predictedEnemy ?? _nearestEnemy.Value;
var dist = Math.Abs(target.X) + Math.Abs(target.Y);
if (dist >= 2 && dist <= 6)
if (dist >= 2 && dist <= 4)
{
direction = DirectionFromVector(target.X, target.Y);
reason = $"Aggressive gap-close toward enemy at {direction} (predicted distance {dist}).";
return true;
var candidate = DirectionFromVector(target.X, target.Y);
if (!IsDirectionUnsafeForHighSpeedMove(candidate))
{
direction = candidate;
reason = $"Aggressive gap-close toward enemy at {direction} (predicted distance {dist}).";
return true;
}
}
}
if (bestSight.HasValue && bestSight.Value.Value.Executed && bestSight.Value.Value.PlayersInSight > 0)
if (sightDirection.HasValue && sightResponse is not null && sightResponse.Executed && sightResponse.PlayersInSight > 0)
{
var dist = bestSight.Value.Value.SightedPlayerDistance ?? 99;
if (dist >= 2 && dist <= 5)
var dist = sightResponse.SightedPlayerDistance ?? 99;
if (dist >= 2 && dist <= 4 && !IsDirectionUnsafeForHighSpeedMove(sightDirection.Value))
{
direction = bestSight.Value.Key;
direction = sightDirection.Value;
reason = $"Enemy visible at {direction} ({dist} dist); dash to force close-range combat.";
return true;
}
@@ -1057,6 +1114,16 @@ public partial class MainWindow : Window
return false;
}
private bool IsDirectionUnsafeForHighSpeedMove(Direction direction)
{
if (_blockedDirectionTicks.TryGetValue(direction, out var blocked) && blocked > 0)
{
return true;
}
return DeathHeatFor(direction) >= 4.0;
}
private void MarkVisit(int x, int y, double amount)
{
var key = (x, y);
@@ -1209,6 +1276,8 @@ public partial class MainWindow : Window
Dispatcher.UIThread.Post(() => StatusText.Text = text);
}
private bool IsMultiplayerMode => MultiplayerCheckBox.IsChecked == true;
private void AppendLog(string message)
{
Dispatcher.UIThread.Post(() =>