before mutliplayer
This commit is contained in:
@@ -66,6 +66,8 @@ public partial class MainWindow : Window
|
||||
private DateTimeOffset _lastStatsAt = DateTimeOffset.MinValue;
|
||||
private DateTimeOffset _lastStatusAt = DateTimeOffset.MinValue;
|
||||
private (int X, int Y)? _nearestEnemy;
|
||||
private (int X, int Y)? _lastObservedEnemyRelative;
|
||||
private (int X, int Y)? _enemyVelocityEstimate;
|
||||
private Direction _lastMoveDirection = Direction.North;
|
||||
private Direction _escapeDirection = Direction.North;
|
||||
private int _recentDamageTicks;
|
||||
@@ -402,11 +404,20 @@ public partial class MainWindow : Window
|
||||
{
|
||||
var scan = await _client.ScanAsync(_playerToken, ct);
|
||||
MarkUsed(BotAction.Scan);
|
||||
var previousEnemy = _nearestEnemy;
|
||||
var sx = scan.DifferenceToNearestPlayer?.X;
|
||||
var sy = scan.DifferenceToNearestPlayer?.Y;
|
||||
_nearestEnemy = sx.HasValue && sy.HasValue ? (sx.Value, sy.Value) : null;
|
||||
if (_nearestEnemy.HasValue)
|
||||
{
|
||||
if (previousEnemy.HasValue)
|
||||
{
|
||||
_enemyVelocityEstimate = (
|
||||
_nearestEnemy.Value.X - previousEnemy.Value.X,
|
||||
_nearestEnemy.Value.Y - previousEnemy.Value.Y);
|
||||
}
|
||||
|
||||
_lastObservedEnemyRelative = _nearestEnemy;
|
||||
AddHeat(_x + _nearestEnemy.Value.X, _y + _nearestEnemy.Value.Y, 5.5);
|
||||
}
|
||||
}
|
||||
@@ -461,6 +472,26 @@ public partial class MainWindow : Window
|
||||
|
||||
var underPressure = hpRatio < PressureHpThreshold(profile) || _recentDamageTicks > 0 || closeThreats >= PressureThreatThreshold(profile) || _survivalTicks > 0 || _pressureStreak >= 2;
|
||||
_lastUnderPressure = underPressure;
|
||||
var predictedEnemy = PredictEnemyRelative();
|
||||
|
||||
var bestSight = _lastPeek
|
||||
.Where(x => x.Value.Executed && x.Value.PlayersInSight > 0)
|
||||
.OrderBy(x => x.Value.SightedPlayerDistance ?? int.MaxValue)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (Ready(BotAction.Hit) && immediateDir.HasValue && closeThreats >= 1)
|
||||
{
|
||||
var dir = immediateDir.Value;
|
||||
return new BotDecision(
|
||||
"hit-lock",
|
||||
$"Enemy committed in close range at {dir}; preemptive melee pressure.",
|
||||
async ct =>
|
||||
{
|
||||
var response = await _client.HitAsync(_playerToken, (int)dir, ct);
|
||||
MarkUsed(BotAction.Hit);
|
||||
return response.Executed;
|
||||
});
|
||||
}
|
||||
|
||||
// Teleport if we can and enemies are nearby - aggressive repositioning for kills
|
||||
if (Ready(BotAction.Teleport) && closeThreats >= 1 && _nearestEnemy.HasValue)
|
||||
@@ -487,10 +518,28 @@ public partial class MainWindow : Window
|
||||
});
|
||||
}
|
||||
|
||||
if (Ready(BotAction.Dash) && TryGetAggressiveDashDirection(predictedEnemy, bestSight, out var dashDirection, out var dashReason))
|
||||
{
|
||||
return new BotDecision(
|
||||
"dash-aggro",
|
||||
dashReason,
|
||||
async ct =>
|
||||
{
|
||||
var response = await _client.DashAsync(_playerToken, (int)dashDirection, ct);
|
||||
MarkUsed(BotAction.Dash);
|
||||
if (response.Executed)
|
||||
{
|
||||
ApplyMovement(dashDirection, Math.Max(response.BlocksDashed, 1));
|
||||
}
|
||||
|
||||
return response.Executed;
|
||||
});
|
||||
}
|
||||
|
||||
var specialThreatThreshold = SpecialThreatThreshold(profile);
|
||||
var specialHpFloor = SpecialHpFloor(profile);
|
||||
|
||||
if (Ready(BotAction.Special) && closeThreats >= specialThreatThreshold)
|
||||
if (Ready(BotAction.Special) && closeThreats >= specialThreatThreshold && (hpRatio >= specialHpFloor || closeThreats > specialThreatThreshold))
|
||||
{
|
||||
return new BotDecision(
|
||||
"specialattack",
|
||||
@@ -575,22 +624,14 @@ public partial class MainWindow : Window
|
||||
});
|
||||
}
|
||||
|
||||
var bestSight = _lastPeek
|
||||
.Where(x => x.Value.Executed && x.Value.PlayersInSight > 0)
|
||||
.OrderBy(x => x.Value.SightedPlayerDistance ?? int.MaxValue)
|
||||
.FirstOrDefault();
|
||||
|
||||
// More aggressive shooting
|
||||
if (bestSight.Value is not null && Ready(BotAction.Shoot))
|
||||
if (Ready(BotAction.Shoot) && TryGetPredictiveShotDirection(bestSight.Key, bestSight.Value, predictedEnemy, out var shotDirection, out var shotReason))
|
||||
{
|
||||
var dir = bestSight.Key;
|
||||
var dist = bestSight.Value.SightedPlayerDistance ?? 99;
|
||||
return new BotDecision(
|
||||
"shoot",
|
||||
$"Enemy at {dir} ({dist} dist); ranged kill.",
|
||||
shotReason,
|
||||
async ct =>
|
||||
{
|
||||
var response = await _client.ShootAsync(_playerToken, (int)dir, ct);
|
||||
var response = await _client.ShootAsync(_playerToken, (int)shotDirection, ct);
|
||||
MarkUsed(BotAction.Shoot);
|
||||
return response.Executed;
|
||||
});
|
||||
@@ -641,7 +682,6 @@ public partial class MainWindow : Window
|
||||
foreach (var dir in scored.Keys.ToArray())
|
||||
{
|
||||
var score = 0.0;
|
||||
// Always chase aggressively - ignore radar safety
|
||||
score += scored[dir] * 0.5;
|
||||
|
||||
if (_lastPeek.TryGetValue(dir, out var peek) && peek.Executed)
|
||||
@@ -656,8 +696,8 @@ public partial class MainWindow : Window
|
||||
|
||||
if (_nearestEnemy.HasValue)
|
||||
{
|
||||
var targetDir = DirectionFromVector(_nearestEnemy.Value.X, _nearestEnemy.Value.Y);
|
||||
// Always move toward nearest enemy
|
||||
var targetVector = PredictEnemyRelative() ?? _nearestEnemy.Value;
|
||||
var targetDir = DirectionFromVector(targetVector.X, targetVector.Y);
|
||||
if (dir == targetDir)
|
||||
{
|
||||
score += 12.0;
|
||||
@@ -927,6 +967,96 @@ public partial class MainWindow : Window
|
||||
_ => hpRatio < 0.02,
|
||||
};
|
||||
|
||||
private (int X, int Y)? PredictEnemyRelative()
|
||||
{
|
||||
if (!_nearestEnemy.HasValue)
|
||||
{
|
||||
return _lastObservedEnemyRelative;
|
||||
}
|
||||
|
||||
if (_enemyVelocityEstimate is null)
|
||||
{
|
||||
return _nearestEnemy;
|
||||
}
|
||||
|
||||
return (
|
||||
_nearestEnemy.Value.X + _enemyVelocityEstimate.Value.X,
|
||||
_nearestEnemy.Value.Y + _enemyVelocityEstimate.Value.Y);
|
||||
}
|
||||
|
||||
private bool TryGetPredictiveShotDirection(
|
||||
Direction? sightDirection,
|
||||
PeekEntitiesAsyncResponse? sightResponse,
|
||||
(int X, int Y)? predictedEnemy,
|
||||
out Direction direction,
|
||||
out string reason)
|
||||
{
|
||||
if (sightDirection is null || sightResponse is null)
|
||||
{
|
||||
if (predictedEnemy.HasValue)
|
||||
{
|
||||
direction = DirectionFromVector(predictedEnemy.Value.X, predictedEnemy.Value.Y);
|
||||
reason = $"Predicted enemy lane -> {direction}; taking lead shot.";
|
||||
return true;
|
||||
}
|
||||
|
||||
direction = Direction.North;
|
||||
reason = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
var currentDir = sightDirection.Value;
|
||||
var dist = sightResponse.SightedPlayerDistance ?? 99;
|
||||
if (predictedEnemy.HasValue && dist >= 2)
|
||||
{
|
||||
var predictedDir = DirectionFromVector(predictedEnemy.Value.X, predictedEnemy.Value.Y);
|
||||
if (predictedDir != currentDir)
|
||||
{
|
||||
direction = predictedDir;
|
||||
reason = $"Enemy moving toward {predictedDir}; lead shot instead of static line {currentDir}.";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
direction = currentDir;
|
||||
reason = $"Enemy at {currentDir} ({dist} dist); ranged kill.";
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetAggressiveDashDirection(
|
||||
(int X, int Y)? predictedEnemy,
|
||||
KeyValuePair<Direction, PeekEntitiesAsyncResponse>? bestSight,
|
||||
out Direction direction,
|
||||
out string reason)
|
||||
{
|
||||
if (_nearestEnemy.HasValue)
|
||||
{
|
||||
var target = predictedEnemy ?? _nearestEnemy.Value;
|
||||
var dist = Math.Abs(target.X) + Math.Abs(target.Y);
|
||||
if (dist >= 2 && dist <= 6)
|
||||
{
|
||||
direction = DirectionFromVector(target.X, target.Y);
|
||||
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)
|
||||
{
|
||||
var dist = bestSight.Value.Value.SightedPlayerDistance ?? 99;
|
||||
if (dist >= 2 && dist <= 5)
|
||||
{
|
||||
direction = bestSight.Value.Key;
|
||||
reason = $"Enemy visible at {direction} ({dist} dist); dash to force close-range combat.";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
direction = Direction.North;
|
||||
reason = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void MarkVisit(int x, int y, double amount)
|
||||
{
|
||||
var key = (x, y);
|
||||
|
||||
288
DDApp/DDApplication/multiplayer.txt
Normal file
288
DDApp/DDApplication/multiplayer.txt
Normal file
@@ -0,0 +1,288 @@
|
||||
Digital Dojo <https://dd.countit.at/> Menü //
|
||||
|
||||
* //Coden lernen<https://dd.countit.at/programmieren-lernen>
|
||||
o //Programmier-Roadmap <https://dd.countit.at/programmieren-lernen>
|
||||
o //Programmierschule <https://dd.countit.at/programmierschule>
|
||||
o //Übungsräume <https://dd.countit.at/dojos>
|
||||
o //Katas <https://dd.countit.at/katas>
|
||||
o //Tutorials <https://dd.countit.at/tutorials>
|
||||
* //Dojo Game<https://dd.countit.at/dojo-game/multiplayer-modus>
|
||||
o //Besiege unseren Bot <https://dd.countit.at/dojo-game>
|
||||
o //Spieleinstieg <https://dd.countit.at/dojo-game/spieleinstieg>
|
||||
o //Levels & Bots <https://dd.countit.at/dojo-game/levels>
|
||||
o //Leaderboard <https://dd.countit.at/dojo-game/leaderboard>
|
||||
o //Multiplayer Modus <https://dd.countit.at/dojo-game/
|
||||
multiplayer-modus>
|
||||
o //Tipps <https://dd.countit.at/dojo-game/tipps>
|
||||
* //Programmier-Challenge <https://dd.countit.at/programmierwettbewerb>
|
||||
* //Bewerben <https://dd.countit.at/bewerben>
|
||||
* //Feedback <https://dd.countit.at/feedback>
|
||||
* // <#>
|
||||
Ausloggen
|
||||
|
||||
/
|
||||
|
||||
/
|
||||
/
|
||||
|
||||
/
|
||||
|
||||
//Teilen //Facebook <https://www.facebook.com/sharer/sharer.php?
|
||||
u=https%3A%2F%2Fdd.countit.at%2Fdojo-game%2Fmultiplayer-modus> //
|
||||
Instagram <https://www.instagram.com/count_it_group/> //LinkedIn
|
||||
<https://www.linkedin.com/shareArticle?
|
||||
mini=true&url=https%3A%2F%2Fdd.countit.at%2Fdojo-game%2Fmultiplayer-
|
||||
modus&title=&summary=&source=> //E-Mail <mailto:m.mustermann@countit.at?
|
||||
subject=Lese-
|
||||
Tipp%3A%20Dojo%20Game%20%7C%20Multiplayer%20Modus&body=Hey%2C%0D%0A%0D%0Aich%20habe%20auf%20https%3A%2F%2Fkarriere.countit.at%20einen%20Beitrag%20gefunden%2C%20der%20dich%20interessieren%20k%C3%B6nnte%3A%0D%0A%22Dojo%20Game%20%7C%20Multiplayer%20Modus%22%0D%0ASchau%20ihn%20dir%20mal%20an%3A%20https%3A%2F%2Fkarriere.countit.at%2Fdojo-game%2Fmultiplayer-modus%3Fkaid%3Dsharemail%0D%0A%0D%0ABeste%20Gr%C3%BC%C3%9Fe>
|
||||
|
||||
|
||||
Der Multiplayer Modus
|
||||
|
||||
|
||||
Dojo Game
|
||||
|
||||
|
||||
//Multiplayer Modus
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Der Mutiplayer Modus basiert auf einem *Lobby System*. Erstelle eine
|
||||
Lobby, lade Freunde ein oder spiele mit anderen Usern! Alle
|
||||
Möglichkeiten stehen dir offen.
|
||||
|
||||
Desto mehr Spieler in einer Lobby sind, mit welchen du zuvor noch nicht
|
||||
viel gespielt hast, desto mehr Punkte werden dir für eine gute
|
||||
Platzierung gutgeschrieben. Der Mehrspieler Modus funktioniert mit den
|
||||
selben API-Aufrufen <https://dd.countit.at/dojo-game/spieleinstieg#api>
|
||||
wie der Singleplayer - es werden lediglich Bots durch Spieler ersetzt.
|
||||
Du kannst daher deinen Einzelspieler Code auch für Mehrspieler Matches
|
||||
verwenden.
|
||||
|
||||
|
||||
*Viel Spaß!*
|
||||
|
||||
|
||||
// Lobby Manager
|
||||
|
||||
------------------------------------------------------------------------
|
||||
Lobby-Key
|
||||
|
||||
/
|
||||
|
||||
/
|
||||
//
|
||||
|
||||
//Starten <https://dd.countit.at/lobby/start>
|
||||
//Verlassen <https://dd.countit.at/lobby/leave>
|
||||
//Schließen <https://dd.countit.at/lobby/close>
|
||||
// tikaiz1 ADMIN
|
||||
// Bot
|
||||
// Bot
|
||||
// Bot
|
||||
// Bot
|
||||
// Bot
|
||||
|
||||
|
||||
// Dein derzeitiger Spielstand
|
||||
|
||||
|
||||
Deine Tötungen: *21*
|
||||
|
||||
Deine Tode: *43*
|
||||
|
||||
Dein Leben: *(7/10)*
|
||||
|
||||
|
||||
// Server Status
|
||||
|
||||
Server - Adresse: game-dd.countit.at
|
||||
|
||||
Port: 80 (optional)
|
||||
|
||||
Status: Online
|
||||
|
||||
|
||||
//Wichtige Informationen
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
//Der Start
|
||||
|
||||
Um eine Lobby zu starten, müssen mindestens die minimale Anzahl an
|
||||
Spielern in einer Lobby sein - standardmäßig sind dies 2. Wir das Spiel
|
||||
dann gestartet, wird die Lobby aus der Liste entfernt, da diese dann
|
||||
nicht mehr benötigt wird. Spielern wird die eigene Lobby nach dem Start
|
||||
nicht mehr angezeigt.
|
||||
|
||||
|
||||
//Dein Algorithmus
|
||||
|
||||
Dein Algorithmus kann schon laufen bevor deine Lobby gestartet wurde.
|
||||
Dein Code wird, sobald eine Verbindung zu einem Spiel hergestellt wurde,
|
||||
automatisch Befehle ausführen.
|
||||
*Vorsicht:* Du darfst deinen Singleplayer Code nicht 1:1 übernehmen.
|
||||
Wenn du ein Lobby Game spielst, darfst du zuvor keine Singleplayer Game
|
||||
Instanz erstellen.
|
||||
|
||||
|
||||
//Dein Spieler
|
||||
|
||||
Dein Spieler ist im Multiplayer mit den selben Stärken und Fähigkeiten
|
||||
ausgestattet wie im Singleplayer. In diesem Modus sind alle Spieler
|
||||
gleich stark - es gibt keine unterschiedlichen Klassen, denn es geht
|
||||
darum, wer den besten Code hat.
|
||||
|
||||
|
||||
//Rangliste
|
||||
|
||||
Unsere Rangliste wird durch Kills und an der Vielzahl der verschiedenen
|
||||
Gegner in einem Match berechnet. Spielst du gegen neue Gegner oder
|
||||
andere Spieler, mit welchen du noch nicht all zu viel gespielt hast,
|
||||
bekommst du mehr Punkte als wenn du beispielsweise immer mit denselben 3
|
||||
Freunden spielst.
|
||||
|
||||
|
||||
//Public/Private Lobby
|
||||
|
||||
Eine öffentliche Lobby ist für jeden Nutzer zugänglich und kann mit
|
||||
jedem Spieler gespielt werden. Eine geschlossene und private Lobby ist
|
||||
nur für jene Spieler zugänglich, welche von einem bereits in der Lobby
|
||||
vorhandenen Spieler den Lobby-Key o.a. Lobby-ID erhalten haben. Beim
|
||||
Eintreten in eine private Lobby wird nach diesem Key verlangt.
|
||||
|
||||
|
||||
//Lobby Admin
|
||||
|
||||
Standardmäßig ist der Ersteller einer Lobby der Admin für die derzeitige
|
||||
Sitzung. Verlässt dieser Nutzer die Lobby, wird durch ein Zufallsprinzip
|
||||
ein neuer Admin ausgewählt. Das Spiel kann nur vom Lobby-Admin
|
||||
geschlossen oder gestartet werden.
|
||||
|
||||
|
||||
//Update Changelog
|
||||
|
||||
Es sind seit dem neuesten Update nur 2 Spieler notwendig, um eine Lobby
|
||||
zu starten. Zusätzlich wurde die Interkation mit dem User durch
|
||||
verbesserte Nachrichten und Übersetzungen optimiert.
|
||||
|
||||
|
||||
Übung macht den Meister!
|
||||
|
||||
Du möchtest deine Skills noch ein wenig trainieren? Dann führe ein paar
|
||||
Katas aus!
|
||||
|
||||
Katas //
|
||||
<https://dd.countit.at/katas>
|
||||
/
|
||||
|
||||
/
|
||||
|
||||
|
||||
Dojo - virtueller Übungsraum
|
||||
|
||||
Löse die Dojo-Aufgaben und werde Programmier-Profi!
|
||||
|
||||
Zu den Dojos // <https://dd.countit.at/dojos>
|
||||
/
|
||||
|
||||
/
|
||||
|
||||
|
||||
Ultimative Coding-Roadmap
|
||||
|
||||
Unsere Roadmap weist dir den Weg zum Coding-Profi!
|
||||
|
||||
Mehr erfahren // <https://dd.countit.at/programmieren-lernen>
|
||||
/
|
||||
|
||||
/
|
||||
|
||||
|
||||
Bewerbung bei COUNT IT
|
||||
|
||||
Starte deine Karriere als Softwareentwickler*in bei COUNT IT.
|
||||
|
||||
Zum Formular! // <https://dd.countit.at/bewerben>
|
||||
|
||||
|
||||
Über Digital Dojo
|
||||
|
||||
Das Digital Dojo ist der virtuelle Übungsraum von COUNT IT.
|
||||
|
||||
Angehende Programmierer*innen, Code-Neulinge, Wiedereinsteiger*innen und
|
||||
Fortgeschrittene finden hier das nötige Rüstzeug für ihre Karriere.
|
||||
|
||||
Du möchtest deine Lehre bei COUNT IT starten? Dann bist du hier richtig
|
||||
- besiege deine Gegner im Dojo Game und sichere dir deine Lehrstelle!
|
||||
|
||||
Inspire your career.
|
||||
|
||||
|
||||
Navigation
|
||||
|
||||
Programmieren lernen <https://dd.countit.at/programmieren-lernen> News
|
||||
<https://dd.countit.at/news>
|
||||
Programmierschule <https://dd.countit.at/programmierschule> Partner
|
||||
<https://dd.countit.at/partner>
|
||||
Programmier-Challenge <https://dd.countit.at/programmierwettbewerb>
|
||||
Dojo Game <https://dd.countit.at/dojo-game>
|
||||
|
||||
|
||||
Datenschutz <https://www.countit.at/datenschutz> Karriere @ COUNT IT
|
||||
<https://karriere.countit.at/>
|
||||
Impressum <https://www.countit.at/impressum> COUNT IT
|
||||
Softwarehouse <https://it.countit.at/>
|
||||
|
||||
|
||||
Newsletter abonnieren
|
||||
|
||||
Der COUNT IT Newsletter liefert viermal jährlich interessante
|
||||
Neuigkeiten über das Unternehmen. Gleich anfordern!
|
||||
|
||||
E-Mail-Adresse
|
||||
Senden
|
||||
|
||||
// <https://de-de.facebook.com/COUNTITGroup/> // <https://
|
||||
www.instagram.com/count_it_group/> // <https://de.linkedin.com/company/
|
||||
count-it-group>
|
||||
|
||||
//
|
||||
|
||||
COUNT IT Group verwendet Cookies, um die Website bestmöglich an die
|
||||
Bedürfnisse der User anpassen zu können.
|
||||
|
||||
* Google
|
||||
* Microsoft
|
||||
* Ahrefs
|
||||
* Statistik
|
||||
|
||||
Akzeptieren
|
||||
Individuelle EinstellungenIndividuelle Einstellungen ausblenden |
|
||||
Datenschutzerklärung <https://www.countit.at/datenschutz>
|
||||
|
||||
Google
|
||||
|
||||
Google Analytics und Optimize aggregiert Daten über unsere Besucher und
|
||||
ihr Verhalten auf unserer Website. Wir nutzen diese Informationen zur
|
||||
Verbesserung unserer Seite.
|
||||
|
||||
Microsoft
|
||||
|
||||
Microsoft aggregiert Daten über unsere Besucher und ihr Verhalten auf
|
||||
unserer Website. Wir nutzen diese Informationen zur Verbesserung unserer
|
||||
Seite.
|
||||
|
||||
Ahrefs
|
||||
|
||||
Ahrefs aggregiert Daten über unsere Besucher und ihr Verhalten auf
|
||||
unserer Website. Wir nutzen diese Informationen zur Verbesserung unserer
|
||||
Seite.
|
||||
|
||||
Statistik
|
||||
|
||||
Es werden grundlegend notwendige, anonymisierte Userdaten aufgezeichnet,
|
||||
welche nur von uns für Auswertungen verwendet werden!
|
||||
|
||||
Cookie Entscheidung speichern
|
||||
Reference in New Issue
Block a user