/// <summary> /// Verifies that the pop-up is roughly the expected size /// </summary> /// <returns></returns> protected virtual void GetPopupHeight(Bitmap screen) { int yOffset; for (int row = 0; row < MAX_ROWS; row++) { yOffset = RowOffset(row); Color background = screen.GetPixel(XClick, YClick + yOffset); RGBHSBRange rightClickColor = RGBHSBRangeFactory.RightClickPopup(); if (rightClickColor.ColorInRange(background)) { Height = TITLE_HEIGHT + ((row + 1) * ROW_HEIGHT); } } }
/// <summary> /// Determines if the bank screen is currently visible /// </summary> /// <returns>true if the bank is open</returns> public bool BankIsOpen() { const double minTitleMatch = 0.05; double titleMatch; int left = Left + 162; int right = Left + 325; int top = Top + 8; int bottom = Top + 25; Color[,] screen; screen = ScreenScraper.GetRGB(ScreenScraper.CaptureWindow()); screen = ImageProcessing.ScreenPiece(screen, left, right, top, bottom); titleMatch = ImageProcessing.FractionalMatch(screen, RGBHSBRangeFactory.BankTitle()); return(titleMatch > minTitleMatch); }
/// <summary> /// Determines if the character is currently running. /// Assumes the character is running if a stamina potion is active because we cannot differentiate. /// </summary> /// <returns>true for running, false for walking</returns> public bool CharacterIsRunning(bool readWindow = false) { if (readWindow && !ReadWindow()) { return(false); } Point runOrb = RunOrbSamplePoint(); Color runColor = Screen[runOrb.X, runOrb.Y]; RGBHSBRange normalRunEnergyFoot = RGBHSBRangeFactory.RunEnergyFoot(); RGBHSBRange staminaRunEnergyFoot = RGBHSBRangeFactory.RunEnergyFootStamina(); bool normalRun = normalRunEnergyFoot.ColorInRange(runColor); bool staminaRun = staminaRunEnergyFoot.ColorInRange(runColor); return(normalRun || staminaRun); }
/// <summary> /// Finds the closest bank booth in the Port Phasmatys bank /// </summary> /// <returns>True if the bank booths are found</returns> internal bool LocateBankBoothPhasmatys(out Blob bankBooth) { bankBooth = null; const int numberOfBankBooths = 6; const double minBoothWidthToHeightRatio = 2.3667; //ex 2.6667 const double maxBoothWidthToHeightRatio = 3.1333; //ex 2.8333 int left = Screen.Center.X - Screen.ArtifactLength(0.5); int right = Screen.Center.X + Screen.ArtifactLength(0.3); int top = Screen.Center.Y - Screen.ArtifactLength(0.15); int bottom = Screen.Center.Y + Screen.ArtifactLength(0.2); Screen.ReadWindow(); Point offset; bool[,] bankBooths = Vision.ColorFilterPiece(RGBHSBRangeFactory.BankBoothPhasmatys(), left, right, top, bottom, out offset); List <Blob> boothBlobs = new List <Blob>(); List <Blob> possibleBoothBlobs = ImageProcessing.FindBlobs(bankBooths, false, MinBankBoothSize, MaxBankBoothSize); //list of blobs from biggest to smallest possibleBoothBlobs.Sort(new BlobProximityComparer(Screen.Center)); double widthToHeightRatio, rectangularity; //Remove blobs that aren't bank booths foreach (Blob possibleBooth in possibleBoothBlobs) { widthToHeightRatio = (possibleBooth.Width / (double)possibleBooth.Height); rectangularity = Geometry.Rectangularity(possibleBooth); if (Numerical.WithinBounds(widthToHeightRatio, minBoothWidthToHeightRatio, maxBoothWidthToHeightRatio) && rectangularity > 0.75) { boothBlobs.Add(possibleBooth); } } if (boothBlobs.Count != numberOfBankBooths) { return(false); //We either failed to locate all of the booths or identified something that was not actually a booth. } //Reduce the blob list to the bank booths boothBlobs.Sort(new BlobHorizontalComparer()); //sort from left to right boothBlobs.RemoveAt(3); //remove the unusable booths without tellers boothBlobs.RemoveAt(0); bankBooth = Blob.ClosestBlob(new Point(Screen.Center.X - left, Screen.Center.Y - top), boothBlobs); bankBooth.ShiftPixels(offset.X, offset.Y); return(true); }
/// <summary> /// Determines if a bank slot is occupied by an empty placeholder /// </summary> /// <param name="screen">image of the entire game screen</param> /// <returns></returns> public bool SlotIsEmpty(int x, int y, Color[,] screen) { Rectangle counterOffset = new Rectangle(-16, -17, 8, 11); Point slotLocation = ItemSlotLocation(x, y).Value; int left = slotLocation.X + counterOffset.X; int right = slotLocation.X + counterOffset.X + counterOffset.Width; int top = slotLocation.Y + counterOffset.Y; int bottom = slotLocation.Y + counterOffset.Y + counterOffset.Height; if (screen == null) { screen = ScreenScraper.GetRGB(ScreenScraper.CaptureWindow()); } screen = ImageProcessing.ScreenPiece(screen, left, right, top, bottom); double slotCounterMatch = ImageProcessing.FractionalMatch(screen, RGBHSBRangeFactory.BankSlotPlaceholderZero()); return(slotCounterMatch > 0.1); }
/// <summary> /// Determines if the chat box is currently open /// </summary> /// <returns></returns> protected bool ChatBoxIsOpen(bool readWindow = false) { if (readWindow) { Screen.ReadWindow(); } int left = 11; int right = left + 30; int top = Screen.Height - 43; int bottom = top + 13; Color[,] chatName = Vision.ScreenPiece(left, right, top, bottom); double textMatch = ImageProcessing.FractionalMatch(chatName, RGBHSBRangeFactory.Black()); double backgroundMatch = ImageProcessing.FractionalMatch(chatName, RGBHSBRangeFactory.ChatBoxBackground()); return(textMatch > 0.05 && backgroundMatch > 0.5); }
/// <summary> /// Estimates the target's fraction of its maximum hitpoints using OSBuddy's target hitpoints indicator /// </summary> /// <returns></returns> protected double TargetHitpointFraction() { if (!InCombat()) { return(double.MaxValue); } Screen.UpdateScreenshot(); Color[,] targetHitpoints = Vision.ScreenPiece(TARGET_HP_LEFT, TARGET_HP_RIGHT, TARGET_HP_TOP, TARGET_HP_BOTTOM); RGBHSBRange greenHPBar = RGBHSBRangeFactory.OSBuddyEnemyHitpointsGreen(); bool[,] greenHP = Vision.ColorFilter(targetHitpoints, greenHPBar); double greenWidth = ImageProcessing.BiggestBlob(greenHP).Width; RGBHSBRange redHPBar = RGBHSBRangeFactory.OSBuddyEnemyHitpointsRed(); bool[,] redHP = Vision.ColorFilter(targetHitpoints, redHPBar); double redWidth = ImageProcessing.BiggestBlob(redHP).Width; return(greenWidth / Numerical.NonZero(greenWidth + redWidth)); }
/// <summary> /// Determines an appropriate value to use for building floor color range /// </summary> protected bool ScanForBuildingFloor() { List <RGBHSBRange> colorRanges = new List <RGBHSBRange>() { RGBHSBRangeFactory.PhasmatysBuildingFloorDark(), RGBHSBRangeFactory.PhasmatysBuildingFloorLight() }; Blob bankIcon, bankFloor, furnaceIcon, furnaceFloor; Point offset; foreach (RGBHSBRange colorRange in colorRanges) { if (BankLocation(out bankIcon, out bankFloor, out offset, colorRange) && (bankFloor != null) && BankFloorSizeCheck(bankFloor.Size) && FurnaceLocation(out furnaceIcon, out furnaceFloor, out offset, colorRange) && (furnaceFloor != null) && FurnaceFloorSizeCheck(furnaceFloor.Size)) { BuildingFloor = colorRange; return(true); } } return(false); }
/// <summary> /// Determines whether the player is in combat using OSBuddy's target hitpoints indicator /// </summary> /// <returns></returns> protected bool InCombat() { const double minBackground = 0.1; RGBHSBRange background = RGBHSBRangeFactory.OSBuddyEnemyHitpointsBackground(); Screen.UpdateScreenshot(); bool[,] targetBackground = Vision.ColorFilterPiece(background, TARGET_HP_LEFT, TARGET_HP_RIGHT, TARGET_HP_TOP, TARGET_HP_BOTTOM); double backgroundMatch = ImageProcessing.FractionalMatch(targetBackground); if (backgroundMatch >= minBackground) { return(true); } else { oldHitpoints = new KeyValuePair <DateTime, double>(DateTime.Now, double.MaxValue); return(false); } }
/// <summary> /// Checks the area where the center of the bottom row of the popup is expected to be /// </summary> /// <param name="screen">the full game screen</param> /// <returns>true if the expected bottom row is found</returns> protected bool PopupIsCorrectHeight(Color[,] screen, CheckHeight checkHeight) { if (checkHeight == CheckHeight.None) { return(true); //No height checking needed } int left = XClick - MIN_WIDTH / 2; int right = XClick + MIN_WIDTH / 2; int top = Bottom - ROW_HEIGHT; double lastRow = ImageProcessing.FractionalMatchPiece(screen, RGBHSBRangeFactory.RightClickPopup(), left, right, top, Bottom); switch (checkHeight) { case CheckHeight.Half: return(lastRow > 0.5); case CheckHeight.Full: double belowPopup = ImageProcessing.FractionalMatchPiece(screen, RGBHSBRangeFactory.RightClickPopup(), left, right, top + ROW_HEIGHT, Bottom + ROW_HEIGHT); return(lastRow > 0.5 && belowPopup < 0.25); } return(false); //Should never reach here. }
/// <summary> /// Tries each found tree from closest to farthest away until an actual tree is confirmed /// </summary> /// <returns>true if a tree is found and chopped, false if no tree is confirmed found</returns> protected bool ChopTree() { Point click; foreach (Blob tree in Trees) { if (StopFlag) { return(false); } click = tree.Center; click = Probability.GaussianCircle(click, 3); Mouse.Move(click.X, click.Y); if (Vision.WaitForMouseOverText(RGBHSBRangeFactory.MouseoverTextStationaryObject(), 1000)) { LeftClick(click.X, click.Y, 0, 0); FailedTreeSearches = 0; return(true); } } return(false); }
/// <summary> /// Mouses over an alleged NPC. Left-clicks if the NPC text appears. /// </summary> /// <param name="ObjectsToCheck">alleged NPC</param /// <param name="click">set to false to skip clicking on the NPC</param> /// <param name="randomization">maximum number of pixels from the center of the blob that it is safe to click</param> /// <returns>true if a matching NPC is found and clicked on</returns> internal bool MouseOverDroppedItem(Blob item, bool click = true, int randomization = 5, int maxWait = 1000) { return(MouseOver(item.Center, RGBHSBRangeFactory.MouseoverTextDroppedItem(), click, randomization, maxWait)); }
/// <summary> /// Determines if house options is open /// </summary> /// <returns>true if the world switcher is open</returns> protected bool HouseOptionsIsOpen() { Inventory.OpenOptions(false); Screen.ReadWindow(); int left = Screen.Width - 169; int right = left + 100; int top = Screen.Height - 296; int bottom = top + 20; Color[,] houseOptionsTitle = Vision.ScreenPiece(left, right, top, bottom); double houseOptionsMatch = ImageProcessing.FractionalMatch(houseOptionsTitle, RGBHSBRangeFactory.BankTitle()); const double houseOptionsMinimumMatch = 0.05; return(houseOptionsMatch > houseOptionsMinimumMatch); }
private void GetReferenceColors() { TeaStallRoof = RGBHSBRangeFactory.TeaStallRoof(); MouseOverText = RGBHSBRangeFactory.MouseoverTextStationaryObject(); }
/// <summary> /// Determines if the given inventory slot contains any item /// </summary> /// <param name="x">slots away from the leftmost column (0-3) or screen x coordinate</param> /// <param name="y">slots away from the topmost column (0-6) or screen y coordinate</param> /// <param name="readScreen">set to true to reread the game screen before checking</param> /// <param name="safeTab">set to true to switch to the inventory tab even if it already thinks that it is selected</param> /// <returns>true if the slot is empty</returns> public bool SlotIsEmpty(int xSlot, int ySlot, bool readScreen = false, bool safeTab = false) { return(SlotMatchesColorFilter(xSlot, ySlot, RGBHSBRangeFactory.EmptyInventorySlot(), 0.95, readScreen, safeTab)); }
/// <summary> /// Locates a bank booth with the counter color from the Varrock west bank /// </summary> /// <param name="bankBooth"></param> /// <returns>true if a bank booth is found</returns> internal bool LocateBankBoothVarrock(out Blob bankBooth) { return(LocateBankBooth(RGBHSBRangeFactory.BankBoothVarrockWest(), out bankBooth)); }
/// <summary> /// Finds the next slot that a new picked up item would go into. /// </summary> /// <param name="safeTab">set to false to rely on the Inventory's record of whether it is already on the inventory tab</param> /// <param name="emptySlotNumber">Set to a number higher than 1 to find the second, third, etc empty slot.</param> /// <returns>The first empty inventory slot scanning left to right then top to bottom. Returns null if inventory is full.</returns> public Point?FirstEmptySlot(bool safeTab = false, int emptySlotNumber = 1) { return(FirstColorMatchingSlot(RGBHSBRangeFactory.EmptyInventorySlot(), 0.99, safeTab, emptySlotNumber)); }
/// <summary> /// Mouses over an alleged stationary object. Left-clicks if the stationary object text appears. /// </summary> /// <param name="stationaryObject">alleged stationary object</param> /// <param name="click">set to false to skip clicking on the stationary object</param> /// <param name="randomization">maximum number of pixels from the center of the blob that it is safe to click</param> /// <returns>true if a matching stationary object is found and clicked on</returns> internal bool MouseOverStationaryObject(Blob stationaryObject, bool click = true, int randomization = 5, int maxWait = 1000) { return(MouseOver(stationaryObject.Center, RGBHSBRangeFactory.MouseoverTextStationaryObject(), click, randomization, maxWait)); }
/// <summary> /// Mouses over an alleged NPC. Left-clicks if the NPC text appears. /// </summary> /// <param name="ObjectsToCheck">alleged NPC</param /// <param name="click">set to false to skip clicking on the NPC</param> /// <param name="randomization">maximum number of pixels from the center of the blob that it is safe to click</param> /// <returns>true if a matching NPC is found and clicked on</returns> internal bool MouseOverNPC(Blob npc, bool click = true, int randomization = 5, int maxWait = 1000) { return(MouseOver(npc.Center, RGBHSBRangeFactory.MouseoverTextNPC(), click, randomization, maxWait)); }
/// <summary> /// Determines if the world switcher is open /// </summary> /// <returns>true if the world switcher is open</returns> public bool WorldSwitcherIsOpen() { int left = Width - 200; int right = left + 150; int top = Height - 297; int bottom = top + 20; Color[,] currentWorldTitle = ImageProcessing.ScreenPiece(Value, left, right, top, bottom); double worldTextMatch = ImageProcessing.FractionalMatch(currentWorldTitle, RGBHSBRangeFactory.BankTitle()); const double worldTextMinimumMatch = 0.05; return(worldTextMatch > worldTextMinimumMatch); }
/// <summary> /// Determines if the client is logged out /// </summary> /// <returns>true if we are verifiably logged out</returns> public bool IsLoggedOut(bool readWindow = false) { if (readWindow && !ReadWindow()) { RunParams.LoggedIn = false; return(false); } Color color; Point loginOffset = LoginScreenOffset(); int height = Height; int top = loginOffset.Y; int centerX = Center.X + loginOffset.X; int checkRow = Math.Min(Math.Max(0, height - 1), loginOffset.Y + ScreenScraper.LOGIN_WINDOW_HEIGHT + 1); //1 pixel below where the bottom of the login window should be int xOffset = (ScreenScraper.LOGIN_WINDOW_WIDTH / 2) + 2; int blackPixels = 0; int totalPixels = 0; for (int x = centerX - xOffset; x < centerX + xOffset; x++) { //check bottom of login box color = Value[x, checkRow]; blackPixels += ImageProcessing.ColorsAreEqual(color, Color.Black) ? 1 : 0; totalPixels++; } for (int y = top; y < checkRow; y++) //check sides { //check left of login box color = Value[centerX - xOffset, y]; blackPixels += ImageProcessing.ColorsAreEqual(color, Color.Black) ? 1 : 0; totalPixels++; //check right of login box color = Value[centerX + xOffset, y]; blackPixels += ImageProcessing.ColorsAreEqual(color, Color.Black) ? 1 : 0; totalPixels++; } //assume we are logged out if a majority off the border pixels are perfectly black if ((blackPixels / ((double)totalPixels)) < 0.25) { return(false); } //Check for "Welcome to RuneScape" yellow text. We are probably logged out at this point. int topWelcome = top + 241; int bottomWelcome = topWelcome + 13; int leftWelcome = Center.X - 75; int rightWelcome = leftWelcome + 146; bool[,] welcomeText = ImageProcessing.ColorFilterPiece(Value, RGBHSBRangeFactory.Yellow(), leftWelcome, rightWelcome, topWelcome, bottomWelcome); double welcomeMatch = ImageProcessing.FractionalMatch(welcomeText); if (!Numerical.WithinRange(welcomeMatch, 0.23275, 0.01)) //ex 0.23275 { //Check for the "Enter your username/email & password." text. leftWelcome = Center.X - 140; rightWelcome = leftWelcome + 280; topWelcome = top + 206; bottomWelcome = topWelcome + 10; welcomeText = ImageProcessing.ColorFilterPiece(Value, RGBHSBRangeFactory.Yellow(), leftWelcome, rightWelcome, topWelcome, bottomWelcome); welcomeMatch = ImageProcessing.FractionalMatch(welcomeText); if (!Numerical.WithinRange(welcomeMatch, 0.25234, 0.01)) //ex. 0.2523 { return(false); //Could not find the welcome text or the enter text. } } RunParams.LoggedIn = false; return(true); }