public async Task Run(GameContext context, BaseWorkerWindow vm, Action <string> statusUpdater, CancellationToken cancellationToken) { await Task.CompletedTask; var wall = new WallBattle(context); if (!wall.IsScreenActive()) { throw new InvalidOperationException("You're not in the wall combat"); } var lastOneMirror = DateTime.UtcNow; var strange = 0; while (true) { cancellationToken.ThrowIfCancellationRequested(); statusUpdater("Waiting for heroes to die..."); await wall.Deactivation(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); if (!wall.IsFailureDialogActive()) { if (strange++ > 50) { throw new Exception("Desynchronized from battle"); } continue; } strange = 0; if ((DateTime.UtcNow - lastOneMirror).TotalMinutes > ResetInterval) { statusUpdater("Respawning..."); lastOneMirror = DateTime.UtcNow; await wall.PressUse1Mirror(cancellationToken); } else { statusUpdater("Respawning..."); await wall.PressUse2Mirrors(cancellationToken); } context.MoveCursor(10, 10); } }
public async Task Run(GameContext context, BaseWorkerWindow vm, Action <string> statusUpdater, CancellationToken cancellationToken) { await Task.CompletedTask; var maps = new TreasureMaps(context); var rewards = new RewardsDialog(context); while (true) { cancellationToken.ThrowIfCancellationRequested(); if (!maps.IsScreenActive()) { throw new InvalidOperationException("You're not at the treasure maps screen"); } statusUpdater("Looting..."); await maps.PressLootButton(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); statusUpdater("Getting rewards..."); await rewards.Activation(cancellationToken); await rewards.PressOkButton(cancellationToken); } }
public async Task Run(GameContext context, BaseWorkerWindow vm, Action <string> statusUpdater, CancellationToken cancellationToken) { using (NDC.Push("Arena Worker")) { await Task.CompletedTask; var lobby = new ArenaLobby(context); var matcher = new ArenaMatcher(context); var prepareBattle = new PrepareBattle(context); var lastScore = 0L; var lastCombatScore = 0L; Opponent lastOpponent = null; var combatResults = new List <CombatLogItem>(); var strategies = new List <IArenaStrategy>(); if (!string.IsNullOrEmpty(WorstEnemy)) { strategies.Add(new WorstEnemyArenaStrategy(WorstEnemy, WorstEnemyOnly, WorstEnemyMaxDist)); } if (UseHistory) { strategies.Add(new HistoryArenaStrategy()); } if (UseScore) { strategies.Add(new PowerArenaStrategy()); strategies.Add(new ScoreFallbackArenaStrategy()); } if (strategies.Any()) { strategies.Add(new PowerArenaStrategy()); } var clog = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "logs", "combat.jlog"); if (!Directory.Exists(Path.GetDirectoryName(clog))) { Directory.CreateDirectory(Path.GetDirectoryName(clog)); } if (File.Exists(clog)) { try { combatResults.AddRange(JsonConvert.DeserializeObject <CombatLogItem[]>(File.ReadAllText(clog))); } catch { } } Logger.Info("Created screens, entering main loop."); while (true) { cancellationToken.ThrowIfCancellationRequested(); if (!lobby.IsScreenActive()) { Logger.Fatal("Lobby screen not detected! Bailing out."); throw new InvalidOperationException("Not on the arena lobby screen"); } if (lobby.CurrentScore > MaxScore) { Logger.InfoFormat("Score limit reached (current {0} > max {1}). Bailing out.", lobby.CurrentScore, MaxScore); return; } lastCombatScore = lobby.CurrentScore - lastScore; if (lastScore != 0 && lobby.CurrentScore != 0 && lastOpponent != null) { combatResults.Add( new CombatLogItem { Date = DateTime.UtcNow, Name = lastOpponent.Name, Power = lastOpponent.Power, ScoreChange = lastCombatScore } ); File.WriteAllText(clog, JsonConvert.SerializeObject(combatResults, Formatting.Indented)); } var combatLookup = combatResults.ToLookup(x => x.Name); lastScore = lobby.CurrentScore; cancellationToken.ThrowIfCancellationRequested(); Logger.Info("Switching to matcher screen."); while (true) { do { await lobby.PressBattleButton(cancellationToken); } while (lobby.IsScreenActive()); var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); try { await matcher.Activation(CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancellationToken).Token); break; } catch (TaskCanceledException) { if (lobby.IsScreenActive()) { continue; } throw; } } if (matcher.TicketsLeft == 0) { await Task.Delay(500, cancellationToken); Logger.Info("Recapture matcher screen due to possible erratic tickets reading."); matcher.IsScreenActive(); } if (matcher.TicketsLeft <= MinTickets) { Logger.InfoFormat("Tickets limit reached (current {0} < min {1}). Bailing out.", matcher.TicketsLeft, MinTickets); return; } Logger.Info("Enabling fast battle."); statusUpdater($"My power {matcher.MyPower.Pretty()}, score {lobby.CurrentScore}. {matcher.TicketsLeft} tickets left."); while (!cancellationToken.IsCancellationRequested) { cancellationToken.ThrowIfCancellationRequested(); Logger.InfoFormat("Matcher screen found opponents {0}; {1}; {2}.", matcher.Opponents[0], matcher.Opponents[1], matcher.Opponents[2]); var opponentsWithHistory = matcher.Opponents.Select( x => { var logs = combatLookup[x.Name].Where(l => Math.Abs(1.0 - (double)l.Power / x.Power) < .1).ToArray(); return(new OpponentWithHistory(x, logs.Length > 0 ? logs.Average(l => l.ScoreChange) : 0)); } ).ToArray(); var engaged = false; foreach (var strategy in strategies) { var result = strategy.SelectOpponent(opponentsWithHistory, matcher.MyPower, lobby.CurrentScore); if (result.Item1 != null) { lastOpponent = result.Item1; matcher.Refresh(); await matcher.ToggleFastBattle(true, cancellationToken); await matcher.EngageOpponent(result.Item1, cancellationToken); engaged = true; break; } if (!result.Item2) { break; } } if (engaged) { break; } Logger.Info("Refreshing matcher as no valid opponents found."); cancellationToken.ThrowIfCancellationRequested(); await matcher.GetNewOpponents(cancellationToken); //await Task.Delay(100, cancellationToken); if (!matcher.IsScreenActive()) { Logger.Fatal("Matcher screen not detected after refresh! Bailing out."); throw new InvalidOperationException("Not on the arena matcher screen"); } } cancellationToken.ThrowIfCancellationRequested(); if (!prepareBattle.IsScreenActive()) { Logger.Fatal("Prepare for battle screen not detected! Bailing out."); throw new InvalidOperationException("Not on the prepare battle screen"); } cancellationToken.ThrowIfCancellationRequested(); Logger.Info("Into the battle!"); await prepareBattle.Engage(cancellationToken); cancellationToken.ThrowIfCancellationRequested(); var ts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); try { await matcher.Activation(CancellationTokenSource.CreateLinkedTokenSource(ts.Token, cancellationToken).Token); } catch (TaskCanceledException) { if (lobby.IsScreenActive()) { continue; } } Logger.Info("Trying to close matcher."); while (true) { cancellationToken.ThrowIfCancellationRequested(); if (matcher.IsScreenActive()) { await matcher.Close(cancellationToken); if (lobby.IsScreenActive()) { Logger.Info("Ok, we're back to lobby."); break; } await Task.Delay(200, cancellationToken); } else if (lobby.IsScreenActive()) { continue; } else { Logger.Fatal("Matcher screen not detected while trying to close it! Bailing out."); throw new InvalidOperationException("Not on the arena matcher screen"); } } await Task.Delay(300, cancellationToken); } } }
public async Task Run(GameContext context, BaseWorkerWindow vm, Action <string> statusUpdater, CancellationToken cancellationToken) { using (NDC.Push("Mapper Worker")) { await Task.Delay(1); var map = new WorldMap(context); var stride = (int)Math.Ceiling(484D / SubScanBounds.Width); var scans = (int)Math.Ceiling(484D / SubScanBounds.Height); var linear = Phase; ProcessedTiles = RecognizedTiles = FailedTiles = 0; TotalTiles = 484 * 484 / Period; TileInfo[][] mapData = null; var clog = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "logs", "map.json"); var ilog = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "logs", "tiles"); var jss = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; if (!Directory.Exists(Path.GetDirectoryName(clog))) { Directory.CreateDirectory(clog); } if (!Directory.Exists(ilog)) { Directory.CreateDirectory(ilog); } if (File.Exists(clog)) { try { mapData = JsonConvert.DeserializeObject <TileInfo[][]>(File.ReadAllText(clog), jss); } catch { } } if (mapData == null || mapData.Length != 492) { mapData = new TileInfo[492][]; } for (var i = 0; i < mapData.Length; i++) { if (mapData[i] == null || mapData[i].Length != 492) { mapData[i] = new TileInfo[492]; } } while (!cancellationToken.IsCancellationRequested) { if (linear > stride * scans) { break; } var cx = 8 + (linear % stride) * SubScanBounds.Width - SubScanBounds.X; var cy = 8 + (linear / stride) * SubScanBounds.Height - SubScanBounds.Y; statusUpdater($"Mapping at {cx},{cy} ({linear})"); if (!map.IsScreenActive()) { await Task.Delay(500, cancellationToken); if (!map.IsScreenActive()) { Logger.Fatal("World map screen not detected! Bailing out."); throw new InvalidOperationException("Not on the world map screen"); } } var needTiles = 0; for (var xx = SubScanBounds.Left; xx < SubScanBounds.Right; xx++) { for (var yy = SubScanBounds.Top; yy < SubScanBounds.Bottom; yy++) { if (xx + cx < 8 || xx + cx > 492 || yy + cy < 8 || yy + cy > 492) { continue; } ProcessedTiles++; if (mapData[cx + xx][cy + yy] == null) { needTiles++; } } } cancellationToken.ThrowIfCancellationRequested(); if (needTiles > 0) { statusUpdater($"Mapping {needTiles} tiles at {cx},{cy} ({linear})"); await map.GoTo(cx, cy, cancellationToken); for (var xx = SubScanBounds.Left; xx < SubScanBounds.Right; xx++) { for (var yy = SubScanBounds.Top; yy < SubScanBounds.Bottom; yy++) { if (xx + cx < 8 || xx + cx > 492 || yy + cy < 8 || yy + cy > 492) { continue; } mapData[cx + xx][cy + yy] = await map.SelectTile(xx, yy, Path.Combine(ilog, $"tile{cx + xx},{cy + yy}"), cancellationToken); if (mapData[cx + xx][cy + yy] != null) { mapData[cx + xx][cy + yy].CenterPoint = new Point(cx + xx, cy + yy); RecognizedTiles++; } else { FailedTiles++; } } } File.WriteAllText(clog, JsonConvert.SerializeObject(mapData, jss)); } linear += Period; } } }
public async Task Run(GameContext context, BaseWorkerWindow vm, Action <string> statusUpdater, CancellationToken cancellationToken) { await Task.CompletedTask; var tavern = new Tavern(context); //var rewards = new RewardsDialog(context); var claimed = false; do { claimed = false; cancellationToken.ThrowIfCancellationRequested(); if (!tavern.IsScreenActive()) { throw new InvalidOperationException("You're not at the tavern screen"); } statusUpdater($"{tavern.StandardCards} standard cards, {tavern.HeroicCards} heroic cards, {tavern.EventPoints} event points."); if (tavern.StandardCards > 0 && ClaimStandard) { if (tavern.StandardCards >= 10) { await tavern.PressClaimStandard10Button(cancellationToken); } else { await tavern.PressClaimStandard1Button(cancellationToken); } while (!tavern.IsScreenActive()) { await tavern.PressCloseButton(cancellationToken); } claimed = true; } if (tavern.HeroicCards > 0 && ClaimHeroic) { if (tavern.HeroicCards >= 10) { await tavern.PressClaimHeroic10Button(cancellationToken); } else { await tavern.PressClaimHeroic1Button(cancellationToken); } while (!tavern.IsScreenActive()) { await tavern.PressCloseButton(cancellationToken); } claimed = true; } if (tavern.EventPoints > 10 && ClaimEvent) { if (tavern.EventPoints >= 100) { await tavern.PressClaimEvent10Button(cancellationToken); } else { await tavern.PressClaimEvent1Button(cancellationToken); } while (!tavern.IsScreenActive()) { await tavern.PressCloseButton(cancellationToken); } claimed = true; } } while (claimed); }