/// <summary> /// Returns the state of the game. /// <para>In lobby: GameState.InLobby</para> /// <para>Waiting for players: GameState.Waiting</para> /// <para>Ingame: GameState.Ingame</para> /// <para>Commending players: GameState.Ending_Commend</para> /// </summary> /// <returns>Returns the state of the game.</returns> public GameState GetGameState() { using (LockHandler.Passive) { UpdateScreen(); // Check if in lobby if (Capture.CompareColor(Points.LOBBY_START_GAME, Colors.LOBBY_START_GAME, Fades.LOBBY_START_GAME)) // Get "START GAME" color { return(GameState.InLobby); } // Check if waiting if (Capture.CompareColor(Points.LOBBY_START_GAMEMODE, Colors.LOBBY_CHANGE, Fades.LOBBY_CHANGE)) // Check if "START GAMEMODE" button exists. { return(GameState.Waiting); } if (Capture.CompareColor(Points.ENDING_COMMEND_DEFEAT, Colors.ENDING_COMMEND_DEFEAT, Fades.ENDING_COMMEND_DEFEAT)) // Check if commending by testing red color of defeat at top left corner { return(GameState.Ending_Commend); } if (Capture.CompareColor(Points.LOBBY_BACK_TO_LOBBY, Colors.LOBBY_CHANGE, Fades.LOBBY_CHANGE)) // Check if ingame by checking if "START GAMEMODE" button does not exist and the "BACK TO LOBBY" button does. { return(GameState.Ingame); } return(GameState.Unknown); } }
/// <summary> /// Obtains the markup of an AI's difficulty. /// </summary> /// <param name="scalar">Garanteed index of difficulty. (0 = easy, 1 = medium, 2 = hard)</param> /// <param name="saveAt">Location to save markup at.</param> public void GetAIDifficultyMarkup(int scalar, string saveAt) { using (cg.LockHandler.Passive) { cg.UpdateScreen(); int[] scales = new int[] { 33, 49, 34 }; DirectBitmap tmp = Capture.Clone(401, 244, scales[scalar], 17); for (int x = 0; x < tmp.Width; x++) { for (int y = 0; y < tmp.Height; y++) { if (tmp.CompareColor(x, y, Colors.WHITE, 30)) { tmp.SetPixel(x, y, Color.Black); } else { tmp.SetPixel(x, y, Color.White); } } } tmp.Save(saveAt); tmp.Dispose(); } }
private static bool WaitForMainMenu(ScreenshotMethod screenshotMethod, IntPtr hwnd, DirectBitmap bmp, int maxTime) { Stopwatch elapsed = new Stopwatch(); elapsed.Start(); while (elapsed.ElapsedMilliseconds < maxTime || maxTime == -1) { Screenshot(screenshotMethod, hwnd, ref bmp); if (bmp.CompareColor(Points.MAIN_MENU_OVERWATCH_WATERMARK, Colors.WHITE, 10)) { Thread.Sleep(2000); return(true); } Thread.Sleep(500); } return(false); }
// Checks if an executed command should be added to the list of commands, then adds it. private string AddExecutedCommand(int y, int namelength, int[] seed, string command #if DEBUG , List <LetterResult> letterInfos #endif ) { #region Command Cleanup ListenTo ltd = null; int nameSeperator = command.IndexOf(']') + 2; if (nameSeperator == 1 || nameSeperator > command.Length) { return(command); } command = command.Substring(nameSeperator) .Trim(); string firstWord = command.Split(' ')[0]; #if DEBUG letterInfos.RemoveRange(0, nameSeperator); cg.DebugMenu?.ShowScan(letterInfos); #endif lock (ListenToAccessLock) foreach (ListenTo listenData in ListenTo) { if (listenData.Command == firstWord) { ltd = listenData; break; } } if (ltd == null || !ltd.Listen) { return(command); } #endregion #region Chat Identity // Store executor noise data in a bitmap. var executorscan = new Rectangle(0, y - 4, namelength, 6); DirectBitmap executor = Capture.Clone(executorscan); // Set name pixels to black and everything else to white for (int xi = 0; xi < executor.Width; xi++) { for (int yi = 0; yi < executor.Height; yi++) { if (executor.CompareColor(xi, yi, seed, Chat.ChatFade)) { executor.SetPixel(xi, yi, Color.Black); } else { executor.SetPixel(xi, yi, Color.White); } } } ChatIdentity ci = new ChatIdentity(executor); #endregion #region Profile and Friend Check bool isFriend = false; string name = null; PlayerIdentity pi = null; // If it was not found, pi is still null. Register the profile if _registerPlayerProfiles is true. if (ltd.GetNameAndProfile || ltd.CheckIfFriend) { Point openMenuAt = new Point(56, y); // Open the chat cg.Chat.OpenChat(); // Open the career profile cg.RightClick(openMenuAt, Timing.OPTION_MENU); // If the Send Friend Request option exists, they are not a friend. isFriend = !(bool)cg.Interact.MenuOptionScan(openMenuAt, OptionScanFlags.ReturnFound, null, Markups.SEND_FRIEND_REQUEST); if (ltd.GetNameAndProfile) { using (cg.LockHandler.Interactive) { // By default, the career profile option is selected and we can just press enter to open it. cg.KeyPress(Keys.Enter); // Wait for the career profile to load. WaitForCareerProfileToLoad(); // Get the player name name = cg.GetPlayerName(); // Take a screenshot of the career profile. DirectBitmap careerProfileSnapshot = Capture.Clone(Rectangles.LOBBY_CAREER_PROFILE); // Register the player identity. pi = new PlayerIdentity(careerProfileSnapshot); // Go back to the lobby. cg.GoBack(1); //cg.//ResetMouse(); // If opening the career profile failed, the state of the chat could be incorrect, // like being wrongly opened or wrongly closed because of when enter was pressed earlier. // This will fix it. cg.Chat.OpenChat(); if (!cg.OpenChatIsDefault) { cg.KeyPress(Keys.Enter); } } } else { cg.Interact.CloseOptionMenu(); } } #endregion CommandData commandData = new CommandData(command, GetChannelFromSeed(seed), ci, isFriend, name, pi); if (ltd.Callback != null) { ltd.Callback.Invoke(commandData); } else { commandData.ChatIdentity.Dispose(); commandData.PlayerIdentity?.Dispose(); } return(command); }
/// <summary> /// Creates a new Overwatch process by logging into an account. Since this requires your username and password, I recommend using <see cref="StartOverwatch(OverwatchInfoAuto)"/> instead. /// </summary> /// <param name="processInfo">Parameters for creating the process.</param> /// <returns>The created Overwatch process.</returns> public static Process StartOverwatch(OverwatchInfoManual processInfo) { if (processInfo == null) { throw new ArgumentNullException(nameof(processInfo)); } int maxWaitTime = 5000; if (!File.Exists(processInfo.OverwatchExecutableFilePath)) { throw new FileNotFoundException(string.Format("Overwatch's executable at {0} was not found. " + "Change OverwatchProcessInfo.OverwatchExecutableFilePath to the location of the Overwatch executable.", processInfo.OverwatchExecutableFilePath)); } if (!File.Exists(processInfo.OverwatchSettingsFilePath)) { throw new FileNotFoundException(string.Format("Overwatch's settings at {0} was not found. " + "Change OverwatchProcessInfo.OverwatchSettingsFilePath to the location of Overwatch's settings.", processInfo.OverwatchSettingsFilePath)); } // Set the video settings. var initialSettings = ChangeVideoSettings(processInfo.OverwatchSettingsFilePath, VideoSettings.Item1, VideoSettings.Item2); Process OWProcess = new Process(); OWProcess.StartInfo.FileName = processInfo.OverwatchExecutableFilePath; OWProcess.StartInfo.Arguments = "-Displaymode 0"; OWProcess.Start(); // Wait for the window to start WaitForVisibleProcessWindow(OWProcess); // Show the window SetupWindow(OWProcess.MainWindowHandle, processInfo.ScreenshotMethod); Stopwatch elapsed = new Stopwatch(); DirectBitmap bmp = null; elapsed.Start(); while (true) { Screenshot(processInfo.ScreenshotMethod, OWProcess.MainWindowHandle, ref bmp); if (elapsed.ElapsedMilliseconds >= maxWaitTime) { bmp.Dispose(); ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException("Failed to start Overwatch.")); } // If the text input for the log in info is found, break out of the loop. if (bmp.CompareColor(407, 384, new int[] { 168, 168, 170 }, 10)) { break; } // If the log in button is yellow, there is not a connection. else if (bmp.CompareColor(Points.PRE_MAIN_MENU_LOGIN, Colors.CONFIRM, Fades.CONFIRM)) { ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException("Could not log in; no internet connection.")); } Thread.Sleep(500); } elapsed.Reset(); Thread.Sleep(100); // At this point login info is ready to be inputed TextInput(OWProcess.MainWindowHandle, processInfo.Username); KeyPress(OWProcess.MainWindowHandle, Keys.Tab); TextInput(OWProcess.MainWindowHandle, processInfo.Password); // Log in Thread.Sleep(50); Screenshot(processInfo.ScreenshotMethod, OWProcess.MainWindowHandle, ref bmp); if (bmp.CompareColor(Points.PRE_MAIN_MENU_LOGIN, Colors.CONFIRM, Fades.CONFIRM)) { KeyPress(OWProcess.MainWindowHandle, Keys.Enter); } else { ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException("Could not log in with the input username or password.")); } Thread.Sleep(500); elapsed.Start(); while (true) { if (elapsed.ElapsedMilliseconds >= maxWaitTime) { ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException("Failed to start Overwatch.")); } Screenshot(processInfo.ScreenshotMethod, OWProcess.MainWindowHandle, ref bmp); if (bmp.CompareColor(469, 437, Colors.CONFIRM, Fades.CONFIRM) == false) { break; } Thread.Sleep(500); } elapsed.Reset(); Thread.Sleep(500); Screenshot(processInfo.ScreenshotMethod, OWProcess.MainWindowHandle, ref bmp); // Check if login failed // s0 will equal true and s1 will equal false if the login failed. s0 and s1 will equal true if an authenticator is required. bool s0 = bmp.CompareColor(518, 482, Colors.CONFIRM, Fades.CONFIRM); // "Cancel" button bool s1 = bmp.CompareColor(605, 475, Colors.CONFIRM, Fades.CONFIRM); // "Authenticate" button. if (s0 && !s1) { ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException("Could not log in with the input username or password.")); } // Enter authenticator code if it is required if (s0 && s1) { if (String.IsNullOrEmpty(processInfo.Authenticator)) { ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException("Authenticator is required")); } TextInput(OWProcess.MainWindowHandle, processInfo.Authenticator); Thread.Sleep(10); KeyPress(OWProcess.MainWindowHandle, Keys.Enter); Thread.Sleep(500); elapsed.Start(); while (true) { if (elapsed.ElapsedMilliseconds >= maxWaitTime) { ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException("Failed to start Overwatch.")); } Screenshot(processInfo.ScreenshotMethod, OWProcess.MainWindowHandle, ref bmp); if (bmp.CompareColor(469, 437, Colors.CONFIRM, Fades.CONFIRM) == false) { break; } Thread.Sleep(500); } Thread.Sleep(500); Screenshot(processInfo.ScreenshotMethod, OWProcess.MainWindowHandle, ref bmp); if (bmp.CompareColor(518, 482, Colors.CONFIRM, Fades.CONFIRM)) { ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException(string.Format("Authenticator number \"{0}\" is invalid.", processInfo.Authenticator))); } } if (!WaitForMainMenu(processInfo.ScreenshotMethod, OWProcess.MainWindowHandle, bmp, maxWaitTime)) { ProcessCreateError(initialSettings, processInfo, OWProcess, bmp, new OverwatchStartFailedException("Failed to start Overwatch.")); } if (processInfo.AutomaticallyCreateCustomGame) { CreateCustomGame(OWProcess.MainWindowHandle); } // Reset the contrast to its initial value RestoreVideoSettings(processInfo.OverwatchSettingsFilePath, initialSettings); return(OWProcess); }
/// <summary> /// Scans for an option at the specified point. /// </summary> /// <param name="scanLocation">The location to scan at.</param> /// <param name="flags">The flags for scanning.</param> /// <param name="saveMarkupsToFolder">The location to save the markup of the scanned options. Set to null to ignore.</param> /// <param name="markup">The markup to scan for. Set to null to ignore.</param> /// <returns><para>Returns a bool determining if the option is found if <paramref name="markup"/> is not null and <paramref name="flags"/> has the <see cref="OptionScanFlags.ReturnFound"/> flag.</para> /// <para>Returns the location of the option if <paramref name="markup"/> is not null and <paramref name="flags"/> has the <see cref="OptionScanFlags.ReturnLocation"/> flag.</para></returns> public object MenuOptionScan(Point scanLocation, OptionScanFlags flags, string saveMarkupsToFolder, DirectBitmap markup) { if (saveMarkupsToFolder != null) { saveMarkupsToFolder = System.IO.Path.GetDirectoryName(saveMarkupsToFolder) + System.IO.Path.DirectorySeparatorChar; } using (cg.LockHandler.SemiInteractive) { if (scanLocation == Point.Empty) { if (flags.HasFlag(OptionScanFlags.ReturnFound)) { return(false); } else if (flags.HasFlag(OptionScanFlags.ReturnLocation)) { return(Point.Empty); } else { return(null); } } if (flags.HasFlag(OptionScanFlags.OpenMenu)) { cg.RightClick(scanLocation); } int xStart = scanLocation.X + 14, // X position to start scanning. yStart = 0, // Y position to start scanning. optionWidth = 79, // The width of the option. optionHeight = 6, // The height of the option. yIncrement = 1; // Pixel distance between options. int[] textcolor = new int[] { 169, 169, 169 }; int fade = 80; bool menuPointsDown = MenuPointsDown(scanLocation); if (menuPointsDown) // The menu points down. { yStart = scanLocation.Y + 12; } else // The menu points up. { yStart = scanLocation.Y - 18; yIncrement = -yIncrement; } cg.UpdateScreen(); var options = new List <Tuple <Point, int> >(); int optionIndex = 0; for (int y = yStart; optionHeight < y && y < cg.Capture.Height - optionHeight; y += yIncrement) { bool oob = false; while (!(oob = optionHeight > y || y > cg.Capture.Height - optionHeight) && !Capture.CompareColor(xStart, y + (menuPointsDown ? 1 : -optionHeight), textcolor, fade + 20)) { y += yIncrement; } // If the y is out of range of the bitmap, stop scanning the options. if (oob || !Capture.CompareColor(xStart - 8, y, new int[] { 67, 67, 68 }, 30)) { break; } int percent = 0; if (markup != null) { int success = 0; int total = 0; for (int xi = 0; xi < markup.Width; xi++) { for (int yi = 0; yi < markup.Height; yi++) { total++; bool bmpPixelIsBlack = Capture.CompareColor(xStart + xi, y + yi, new int[] { 170, 170, 170 }, 80); bool markupPixelIsBlack = markup.GetPixel(xi, yi) == Color.FromArgb(0, 0, 0); if (bmpPixelIsBlack == markupPixelIsBlack) { success++; } } } percent = (int)(Convert.ToDouble(success) / Convert.ToDouble(total) * 100); } // Get bitmap of option if (saveMarkupsToFolder != null) { DirectBitmap work = Capture.Clone(xStart, y, optionWidth, optionHeight); for (int xi = 0; xi < work.Width; xi++) { for (int yi = 0; yi < work.Height; yi++) { if (work.CompareColor(xi, yi, textcolor, fade)) { work.SetPixel(xi, yi, Color.Black); } else { work.SetPixel(xi, yi, Color.White); } } } work.Save($@"{saveMarkupsToFolder}Option Markup-{optionIndex}.png"); work.Dispose(); } #if DEBUG if (cg.DebugMenu != null) { Console.WriteLine($"{optionIndex} - {percent}%"); } #endif options.Add(new Tuple <Point, int>(new Point(xStart, y), percent)); optionIndex++; } Point optionLocation = Point.Empty; if (markup != null && options.Count > 0) { optionLocation = options.Where(o => o.Item2 > 75).OrderByDescending(o => o.Item2).FirstOrDefault()?.Item1 ?? Point.Empty; } if (flags.HasFlag(OptionScanFlags.Click)) { SelectMenuOption(optionLocation); } // Close the menu. if (flags.HasFlag(OptionScanFlags.CloseMenu) || (flags.HasFlag(OptionScanFlags.CloseIfNotFound) && optionLocation == Point.Empty)) { CloseOptionMenu(); } if (flags.HasFlag(OptionScanFlags.ReturnFound)) { return(optionLocation != Point.Empty); } else if (flags.HasFlag(OptionScanFlags.ReturnLocation)) { return(optionLocation); } return(null); } }