This commit is contained in:
2026-04-02 20:51:21 +02:00
parent 1e3c2b176d
commit 49156bcda4
2 changed files with 236 additions and 21 deletions

View File

@@ -11,6 +11,19 @@
<Button x:Name="StartButton" Content="Start Bot" Width="120"/> <Button x:Name="StartButton" Content="Start Bot" Width="120"/>
<Button x:Name="StopButton" Content="Stop Bot" Width="120" IsEnabled="False"/> <Button x:Name="StopButton" Content="Stop Bot" Width="120" IsEnabled="False"/>
<CheckBox x:Name="MultiplayerCheckBox" Content="Multiplayer" VerticalAlignment="Center"/> <CheckBox x:Name="MultiplayerCheckBox" Content="Multiplayer" VerticalAlignment="Center"/>
<TextBlock Text="Aggro:" VerticalAlignment="Center"/>
<ComboBox x:Name="AggressivenessProfileBox" Width="150" SelectedIndex="2">
<ComboBoxItem Content="Conservative"/>
<ComboBoxItem Content="Balanced"/>
<ComboBoxItem Content="Aggressive"/>
<ComboBoxItem Content="Extreme"/>
</ComboBox>
<TextBlock Text="Mode Profile:" VerticalAlignment="Center"/>
<ComboBox x:Name="ModeOptimizationProfileBox" Width="200" SelectedIndex="0">
<ComboBoxItem Content="Auto"/>
<ComboBoxItem Content="Singleplayer Optimized"/>
<ComboBoxItem Content="Multiplayer Optimized"/>
</ComboBox>
<TextBlock Text="API Key:" VerticalAlignment="Center"/> <TextBlock Text="API Key:" VerticalAlignment="Center"/>
<TextBox x:Name="ApiKeyBox" Width="360" Watermark="GUID player token"/> <TextBox x:Name="ApiKeyBox" Width="360" Watermark="GUID player token"/>
<TextBlock x:Name="StatusText" VerticalAlignment="Center" Text="Idle"/> <TextBlock x:Name="StatusText" VerticalAlignment="Center" Text="Idle"/>

View File

@@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Controls.Primitives;
using Avalonia.Threading; using Avalonia.Threading;
namespace DDApplication; namespace DDApplication;
@@ -77,6 +78,9 @@ public partial class MainWindow : Window
private bool _lastUnderPressure; private bool _lastUnderPressure;
private int _pressureStreak; private int _pressureStreak;
private LevelProfile _currentLevelProfile = LevelProfile.Unknown; private LevelProfile _currentLevelProfile = LevelProfile.Unknown;
private bool _isMultiplayerMode;
private AggressivenessProfile _selectedAggressiveness = AggressivenessProfile.Aggressive;
private ModeOptimizationProfile _selectedModeOptimization = ModeOptimizationProfile.Auto;
public MainWindow() public MainWindow()
{ {
@@ -87,6 +91,20 @@ public partial class MainWindow : Window
ApiKeyBox.Text = _configuredApiKey; ApiKeyBox.Text = _configuredApiKey;
MultiplayerCheckBox.IsChecked = _multiplayerModeDefault; MultiplayerCheckBox.IsChecked = _multiplayerModeDefault;
AggressivenessProfileBox.SelectedIndex = 2;
ModeOptimizationProfileBox.SelectedIndex = 0;
SyncProfileSelectionState();
MultiplayerCheckBox.PropertyChanged += (_, e) =>
{
if (e.Property == ToggleButton.IsCheckedProperty)
{
SyncProfileSelectionState();
}
};
AggressivenessProfileBox.SelectionChanged += (_, _) => SyncProfileSelectionState();
ModeOptimizationProfileBox.SelectionChanged += (_, _) => SyncProfileSelectionState();
LogList.ItemsSource = _logEntries; LogList.ItemsSource = _logEntries;
StartButton.Click += async (_, _) => await StartBotAsync(); StartButton.Click += async (_, _) => await StartBotAsync();
@@ -125,6 +143,8 @@ public partial class MainWindow : Window
StopButton.IsEnabled = true; StopButton.IsEnabled = true;
ApiKeyBox.IsEnabled = false; ApiKeyBox.IsEnabled = false;
MultiplayerCheckBox.IsEnabled = false; MultiplayerCheckBox.IsEnabled = false;
AggressivenessProfileBox.IsEnabled = false;
ModeOptimizationProfileBox.IsEnabled = false;
ResetKnowledgeState(); ResetKnowledgeState();
@@ -189,6 +209,8 @@ public partial class MainWindow : Window
StopButton.IsEnabled = false; StopButton.IsEnabled = false;
ApiKeyBox.IsEnabled = true; ApiKeyBox.IsEnabled = true;
MultiplayerCheckBox.IsEnabled = true; MultiplayerCheckBox.IsEnabled = true;
AggressivenessProfileBox.IsEnabled = true;
ModeOptimizationProfileBox.IsEnabled = true;
SetStatus("Stopped."); SetStatus("Stopped.");
} }
@@ -481,7 +503,7 @@ public partial class MainWindow : Window
_pressureStreak = Math.Max(_pressureStreak - 1, 0); _pressureStreak = Math.Max(_pressureStreak - 1, 0);
} }
var underPressure = hpRatio < PressureHpThreshold(profile) || _recentDamageTicks > 0 || closeThreats >= PressureThreatThreshold(profile) || _survivalTicks > 0 || _pressureStreak >= 2; var underPressure = hpRatio < PressureHpThresholdAdjusted(profile) || _recentDamageTicks > 0 || closeThreats >= PressureThreatThresholdAdjusted(profile) || _survivalTicks > 0 || _pressureStreak >= 2;
_lastUnderPressure = underPressure; _lastUnderPressure = underPressure;
var predictedEnemy = PredictEnemyRelative(); var predictedEnemy = PredictEnemyRelative();
@@ -575,8 +597,8 @@ public partial class MainWindow : Window
}); });
} }
var specialThreatThreshold = SpecialThreatThreshold(profile); var specialThreatThreshold = SpecialThreatThresholdAdjusted(profile);
var specialHpFloor = SpecialHpFloor(profile); var specialHpFloor = SpecialHpFloorAdjusted(profile);
if (Ready(BotAction.Special) && closeThreats >= specialThreatThreshold && (hpRatio >= specialHpFloor || closeThreats > specialThreatThreshold)) if (Ready(BotAction.Special) && closeThreats >= specialThreatThreshold && (hpRatio >= specialHpFloor || closeThreats > specialThreatThreshold))
{ {
@@ -609,7 +631,7 @@ public partial class MainWindow : Window
{ {
var retreatDirection = Opposite(immediateDir.Value); var retreatDirection = Opposite(immediateDir.Value);
if (Ready(BotAction.Dash) && (hpRatio < DashHpThreshold(profile) || _pressureStreak >= 3 || _survivalTicks > 0)) if (Ready(BotAction.Dash) && (hpRatio < DashHpThresholdAdjusted(profile) || _pressureStreak >= 3 || _survivalTicks > 0))
{ {
return new BotDecision( return new BotDecision(
"dash-retreat", "dash-retreat",
@@ -1001,23 +1023,143 @@ public partial class MainWindow : Window
_ => 2, _ => 2,
}; };
private bool ShouldUseImmediateHit(LevelProfile profile, double hpRatio, int closeThreats, bool underPressure) => profile switch private bool ShouldUseImmediateHit(LevelProfile profile, double hpRatio, int closeThreats, bool underPressure)
{ {
LevelProfile.Default => hpRatio >= 0.05, var hpFloor = SelectedAggressiveness switch
LevelProfile.BiggerMap => hpRatio >= 0.05, {
LevelProfile.MoreBots => hpRatio >= 0.05, AggressivenessProfile.Conservative => 0.30,
LevelProfile.NewBots => hpRatio >= 0.05, AggressivenessProfile.Balanced => 0.16,
_ => hpRatio >= 0.05, AggressivenessProfile.Aggressive => 0.05,
}; AggressivenessProfile.Extreme => 0.01,
_ => 0.05,
};
private bool ShouldRetreatOnImmediate(LevelProfile profile, double hpRatio, int closeThreats) => profile switch if (IsMultiplayerOptimized)
{
hpFloor = Math.Max(hpFloor, 0.18);
}
return hpRatio >= hpFloor || (!underPressure && closeThreats <= 1);
}
private bool ShouldRetreatOnImmediate(LevelProfile profile, double hpRatio, int closeThreats)
{ {
LevelProfile.Default => hpRatio < 0.02, var hpRetreat = SelectedAggressiveness switch
LevelProfile.BiggerMap => hpRatio < 0.02, {
LevelProfile.MoreBots => hpRatio < 0.02, AggressivenessProfile.Conservative => 0.30,
LevelProfile.NewBots => hpRatio < 0.02, AggressivenessProfile.Balanced => 0.18,
_ => hpRatio < 0.02, AggressivenessProfile.Aggressive => 0.02,
}; AggressivenessProfile.Extreme => 0.01,
_ => 0.02,
};
if (IsMultiplayerOptimized)
{
hpRetreat = Math.Max(hpRetreat, 0.20);
}
return hpRatio < hpRetreat || (IsMultiplayerOptimized && closeThreats >= 3);
}
private double PressureHpThresholdAdjusted(LevelProfile profile)
{
var value = PressureHpThreshold(profile);
value += SelectedAggressiveness switch
{
AggressivenessProfile.Conservative => 0.20,
AggressivenessProfile.Balanced => 0.08,
AggressivenessProfile.Aggressive => 0.00,
AggressivenessProfile.Extreme => -0.05,
_ => 0.00,
};
if (IsMultiplayerOptimized)
{
value += 0.08;
}
return Math.Clamp(value, 0.01, 0.95);
}
private int PressureThreatThresholdAdjusted(LevelProfile profile)
{
var value = PressureThreatThreshold(profile);
value += SelectedAggressiveness switch
{
AggressivenessProfile.Conservative => -2,
AggressivenessProfile.Balanced => -1,
AggressivenessProfile.Aggressive => 0,
AggressivenessProfile.Extreme => 1,
_ => 0,
};
if (IsMultiplayerOptimized)
{
value -= 1;
}
return Math.Clamp(value, 1, 8);
}
private int SpecialThreatThresholdAdjusted(LevelProfile profile)
{
var value = SpecialThreatThreshold(profile);
value += SelectedAggressiveness switch
{
AggressivenessProfile.Conservative => 1,
AggressivenessProfile.Balanced => 0,
AggressivenessProfile.Aggressive => 0,
AggressivenessProfile.Extreme => -1,
_ => 0,
};
if (IsMultiplayerOptimized)
{
value += 1;
}
return Math.Clamp(value, 1, 6);
}
private double SpecialHpFloorAdjusted(LevelProfile profile)
{
var value = SpecialHpFloor(profile);
value += SelectedAggressiveness switch
{
AggressivenessProfile.Conservative => 0.20,
AggressivenessProfile.Balanced => 0.10,
AggressivenessProfile.Aggressive => 0.00,
AggressivenessProfile.Extreme => -0.05,
_ => 0.00,
};
if (IsMultiplayerOptimized)
{
value += 0.10;
}
return Math.Clamp(value, 0.01, 0.95);
}
private double DashHpThresholdAdjusted(LevelProfile profile)
{
var value = DashHpThreshold(profile);
value += SelectedAggressiveness switch
{
AggressivenessProfile.Conservative => 0.18,
AggressivenessProfile.Balanced => 0.10,
AggressivenessProfile.Aggressive => 0.00,
AggressivenessProfile.Extreme => -0.03,
_ => 0.00,
};
if (IsMultiplayerOptimized)
{
value += 0.10;
}
return Math.Clamp(value, 0.01, 0.95);
}
private (int X, int Y)? PredictEnemyRelative() private (int X, int Y)? PredictEnemyRelative()
{ {
@@ -1121,7 +1263,21 @@ public partial class MainWindow : Window
return true; return true;
} }
return DeathHeatFor(direction) >= 4.0; var deathHeatLimit = SelectedAggressiveness switch
{
AggressivenessProfile.Conservative => 2.5,
AggressivenessProfile.Balanced => 3.2,
AggressivenessProfile.Aggressive => 4.0,
AggressivenessProfile.Extreme => 5.0,
_ => 4.0,
};
if (IsMultiplayerOptimized)
{
deathHeatLimit -= 0.6;
}
return DeathHeatFor(direction) >= deathHeatLimit;
} }
private void MarkVisit(int x, int y, double amount) private void MarkVisit(int x, int y, double amount)
@@ -1235,7 +1391,7 @@ public partial class MainWindow : Window
$"Level: {_levelName} | Kills: {_kills} | Deaths: {_deaths} | K/D: {kdr} | " + $"Level: {_levelName} | Kills: {_kills} | Deaths: {_deaths} | K/D: {kdr} | " +
$"HP: {_currentHealth.ToString("0.0", CultureInfo.InvariantCulture)}/{_maxHealth.ToString("0.0", CultureInfo.InvariantCulture)} ({hpPercent.ToString("0", CultureInfo.InvariantCulture)}%) | " + $"HP: {_currentHealth.ToString("0.0", CultureInfo.InvariantCulture)}/{_maxHealth.ToString("0.0", CultureInfo.InvariantCulture)} ({hpPercent.ToString("0", CultureInfo.InvariantCulture)}%) | " +
$"Progress: {_progress.ToString("0.0", CultureInfo.InvariantCulture)}% | Remaining: {_remainingTime.ToString("0.00", CultureInfo.InvariantCulture)} min | " + $"Progress: {_progress.ToString("0.0", CultureInfo.InvariantCulture)}% | Remaining: {_remainingTime.ToString("0.00", CultureInfo.InvariantCulture)} min | " +
$"Pos (estimated): ({_x}, {_y}) | Profile: {_currentLevelProfile} | SurvivalMode: {(_survivalTicks > 0 ? "ON" : "OFF")}"; $"Pos (estimated): ({_x}, {_y}) | Profile: {_currentLevelProfile} | Aggro: {SelectedAggressiveness} | Mode: {SelectedModeOptimization} | SurvivalMode: {(_survivalTicks > 0 ? "ON" : "OFF")}";
var nearest = _nearestEnemy.HasValue ? $"({_nearestEnemy.Value.X}, {_nearestEnemy.Value.Y})" : "none"; var nearest = _nearestEnemy.HasValue ? $"({_nearestEnemy.Value.X}, {_nearestEnemy.Value.Y})" : "none";
var radar = _lastRadar.Count == 0 var radar = _lastRadar.Count == 0
@@ -1276,7 +1432,38 @@ public partial class MainWindow : Window
Dispatcher.UIThread.Post(() => StatusText.Text = text); Dispatcher.UIThread.Post(() => StatusText.Text = text);
} }
private bool IsMultiplayerMode => MultiplayerCheckBox.IsChecked == true; private bool IsMultiplayerMode => _isMultiplayerMode;
private AggressivenessProfile SelectedAggressiveness => _selectedAggressiveness;
private ModeOptimizationProfile SelectedModeOptimization => _selectedModeOptimization;
private bool IsMultiplayerOptimized => SelectedModeOptimization switch
{
ModeOptimizationProfile.SingleplayerOptimized => false,
ModeOptimizationProfile.MultiplayerOptimized => true,
_ => _isMultiplayerMode,
};
private void SyncProfileSelectionState()
{
_isMultiplayerMode = MultiplayerCheckBox.IsChecked == true;
_selectedAggressiveness = AggressivenessProfileBox.SelectedIndex switch
{
0 => AggressivenessProfile.Conservative,
1 => AggressivenessProfile.Balanced,
2 => AggressivenessProfile.Aggressive,
3 => AggressivenessProfile.Extreme,
_ => AggressivenessProfile.Aggressive,
};
_selectedModeOptimization = ModeOptimizationProfileBox.SelectedIndex switch
{
1 => ModeOptimizationProfile.SingleplayerOptimized,
2 => ModeOptimizationProfile.MultiplayerOptimized,
_ => ModeOptimizationProfile.Auto,
};
}
private void AppendLog(string message) private void AppendLog(string message)
{ {
@@ -1382,6 +1569,21 @@ public partial class MainWindow : Window
NewBots, NewBots,
} }
private enum AggressivenessProfile
{
Conservative,
Balanced,
Aggressive,
Extreme,
}
private enum ModeOptimizationProfile
{
Auto,
SingleplayerOptimized,
MultiplayerOptimized,
}
private enum Direction private enum Direction
{ {
North = 0, North = 0,