private async Task SwipeDown(AndroidConnector android)
        {
            await Task.Delay(250);

            await android.Swipe(1160, 860, 1160, -350, 1000);

            await Task.Delay(250);

            await android.Tap(530, 845); // against overlay

            await Task.Delay(500);
        }
        private async Task <bool> NextPage(AndroidConnector android)
        {
            using (var image = Image.Load <Rgba32>("shopitems.png"))
            {
                var maxPageImage = image.Clone(ctx => ctx.Crop(new Rectangle(763, 956, 39, 52)));
                int maxPage      = -1;
                //TODO: cache these
                foreach (var file in Directory.GetFiles("data/pagenumbers/total"))
                {
                    using (var pageImage = Image.Load <Rgba32>(file))
                        if (IsSame(pageImage, maxPageImage))
                        {
                            maxPage = int.Parse(Path.GetFileNameWithoutExtension(file), CultureInfo.InvariantCulture);
                        }
                }

                if (maxPage == -1)
                {
                    maxPageImage.Save($"unknown/maxpage{Directory.GetFiles("unknown").Length}.png");
                }

                var curPageImage = image.Clone(ctx => ctx.Crop(new Rectangle(700, 962, 63, 44)));
                int curPage      = -1;
                //TODO: cache these
                foreach (var file in Directory.GetFiles("data/pagenumbers/current"))
                {
                    using (var pageImage = Image.Load <Rgba32>(file))
                        if (IsSame(pageImage, curPageImage))
                        {
                            curPage = int.Parse(Path.GetFileNameWithoutExtension(file), CultureInfo.InvariantCulture);
                        }
                }
                if (curPage == -1)
                {
                    curPageImage.Save($"unknown/curpage{Directory.GetFiles("unknown").Length}.png");
                }


                if (curPage < maxPage)
                {
                    await android.Tap(944, 982);

                    await Task.Delay(500); // wait for next page to load

                    return(false);
                }
            }


            return(true);
        }
        public async Task <bool> IsExchangeOpen(AndroidConnector android)
        {
            await android.Screenshot("isExchangeOpen.png");

            using (var image = Image.Load <Rgba32>("isExchangeOpen.png"))
            {
                using (var cmp = Image.Load <Rgba32>("data/search.png"))
                    if (ImageDistance(image.Clone(ctx => ctx.Crop(new Rectangle(223, 200, 268, 63))), cmp) < 10)
                    {
                        return(true);
                    }
                using (var cmp = Image.Load <Rgba32>("data/search2.png"))
                    if (ImageDistance(image.Clone(ctx => ctx.Crop(new Rectangle(1356, 235, 117, 55))), cmp) < 10)
                    {
                        return(true);
                    }
                return(false);
            }
        }
        static void Main(string[] args)
        {
            string hostname = "10.10.0.32:1234";

            if (args.Length > 0)
            {
                hostname = args[0];
            }


            Application.Init();
            var top = Application.Top;

            top.Add(log      = new LogWindow());
            top.Add(status   = new StatusWindow());
            top.Add(controls = new ControlsWindow());



            var menu = new MenuBar(new MenuBarItem[] {
                new MenuBarItem("_File", new MenuItem [] {
                    new MenuItem("_New", "", null),
                    new MenuItem("_Close", "", null),
                    new MenuItem("_Quit", "", null)
                }),
                new MenuBarItem("_Edit", new MenuItem [] {
                    new MenuItem("_Copy", "", null),
                    new MenuItem("C_ut", "", null),
                    new MenuItem("_Paste", "", null)
                })
            });

            top.Add(menu);

            androidConnection = new AndroidConnector(hostname);
            using (scanner = new Scanner())
            {
                Task.Run(RunScanner);
                Application.Run();
            }
        }
        public async Task <List <ScanResultEquip> > ScanEquip(AndroidConnector android, ScanInfo scanInfo)
        {
            List <ScanResultEquip> result = new List <ScanResultEquip>();


            if (scanInfo.RealName.Contains("[1]"))
            {
                scanInfo.Slots = 1;
            }
            if (scanInfo.RealName.Contains("[2]"))
            {
                scanInfo.Slots = 2;
            }

            if (scanInfo.SearchName.Contains("["))
            {
                scanInfo.SearchName = scanInfo.SearchName.Substring(0, scanInfo.SearchName.IndexOf("[")).Trim();
            }
            scanInfo.Equip = true;

            Program.status.SetSubStatus("Opening search window");
            await CloseSearch(android);
            await ClickSearchButton(android);
            await ClickSearchBox(android);

            await android.Text(scanInfo.SearchName);

            await ClickSearchWindowSearchButton(android); //to close text input
            await ClickSearchWindowSearchButton(android);

            Program.status.SetSubStatus("Scanning search result");
            await android.Screenshot("searchresult.png");

            using (var image = Image.Load <Rgba32>("searchresult.png"))
                using (var cmp = Image.Load <Rgba32>("data/bigerror.png"))
                    if (ImageDistance(image.Clone(c => c.Crop(new Rectangle(650, 150, 700, 200))), cmp) < 100)
                    {
                        Program.Restart = true;
                        return(null);
                    }


            List <int> indices = FindSearchResult("searchresult.png", scanInfo);

            if (indices.Count == 1 && indices[0] == -1)
            {
                await android.Swipe(1100, 863, 1100, 355, 200);

                await Task.Delay(500);

                await android.Screenshot("searchresult.png");

                indices = FindSearchResult("searchresult.png", scanInfo);
            }

            await Task.Delay(500);

            if (indices.Count == 0)
            {
                //TODO: do something with item0.png - item9.png
                Program.status.SetSubStatus("- Error, could not find item");
                await CloseSearch(android);

                return(new List <ScanResultEquip>()
                {
                    ScanResult.BuildError <ScanResultEquip>(scanInfo)
                });
            }
            if (indices[0] != scanInfo.SearchIndex)
            {
                if (scanInfo.SearchIndex != -1)
                {
                    Program.log.Log(scanInfo.RealName, "Warning, search index not correct");
                }
                scanInfo.SearchIndex = indices[0];
            }


            for (int i = 0; i < indices.Count; i++)
            {
                await ClickSearchWindowIndex(android, indices[i]);

                await Task.Delay(2500);

                Program.status.SetSubStatus("Checking for sales");
                await android.Screenshot("shopitems.png");

                using (var image = Image.Load <Rgba32>("shopitems.png"))
                    image.Clone(ctx => ctx.Crop(new Rectangle(975, 505, 368, 64))).Save($"nosale.png");

                bool onSale = true;
                if (GetTextFromImage("nosale.png").ToLower().Contains("currently"))
                {
                    onSale = false;
                    Program.log.Log(scanInfo.RealName, "Currently not for sale");
                    if (i + 1 >= indices.Count)
                    {
                        return new List <ScanResultEquip>()
                               {
                                   new ScanResultEquip()
                                   {
                                       Found    = false,
                                       ScanInfo = scanInfo
                                   }
                               }
                    }
                    ;
                }

                if (onSale)
                {
                    var images  = new List <Image <Rgba32> >();
                    int subPage = 0;
                    while (!Program.CancelScan)
                    {
                        Program.log.Log(scanInfo.RealName, "Scanning page " + subPage);

                        int  foundResults = images.Count;
                        bool done         = await ScanPage(images, android, scanInfo, result);

                        if (foundResults == images.Count)
                        {
                            Program.log.Log(scanInfo.RealName, "No new items found in last sweep, done");
                            break;
                        }
                        if (subPage % 2 == 0)
                        {
                            await SwipeDown(android);
                        }
                        else
                        if (await NextPage(android))
                        {
                            break;
                        }

                        await android.Screenshot("shopitems.png");

                        subPage++;
                    }
                    Program.status.SetSubStatus("done scanning");

                    foreach (var img in images)
                    {
                        img.Dispose();
                    }


                    return(result);
                }
                //this should not happen
                scanInfo.Message = "";
                Console.WriteLine("Item does not match, or not found on exchange with multiple items, trying to rescan it");
                await CloseSearch(android);
                await ClickSearchButton(android);
                await ClickSearchBox(android);

                await android.Text(scanInfo.SearchName);
                await ClickSearchWindowSearchButton(android); //to close text input
                await ClickSearchWindowSearchButton(android);
            }

            return(null);
        }
        public async Task RestartRo(AndroidConnector android)
        {
            Program.status.SetSubStatus("Stopping RO");
            await android.StopRo();

            await Task.Delay(1000);

            Program.status.SetSubStatus("Starting RO");
            await android.StartRo();

            await Task.Delay(30000);

            Program.status.SetSubStatus("Scanning if logged in");
            //TODO: check for google/facebook popup
            for (int i = 0; i < 25; i++)
            {
                await android.Screenshot("login.png");

                using (var image = Image.Load <Rgba32>("login.png"))
                    image.Clone(ctx => ctx.Crop(new Rectangle(855, 585, 215, 55))).Save($"servername.png");
                string servername = GetTextFromImage("servername.png");
                Console.WriteLine(servername);
                if (servername.ToLower() == "eternal love")
                {
                    break;
                }
                await Task.Delay(5000);

                if (i == 24)
                {
                    Program.status.SetSubStatus("Unable to login");
                    return;
                }
            }
            Program.status.SetSubStatus("Tapping Login");
            await android.Tap(500, 500);        //login tap

            await Task.Delay(10000);

            for (int i = 0; i < 25; i++)
            {
                await android.Screenshot("charselect.png");

                using (var image = Image.Load <Rgba32>("charselect.png"))
                    using (var cmp = Image.Load <Rgba32>("data/startbutton.png"))
                        if (IsSame(image.Clone(ctx => ctx.Crop(new Rectangle(1518, 943, 243, 67))), cmp))
                        {
                            break;
                        }
                await Task.Delay(2000);

                if (i == 24)
                {
                    Program.status.SetSubStatus("Unable to select character");
                    return;
                }
            }
            Program.status.SetSubStatus("Selecting char");
            await android.Tap(1624, 975);       //select char button

            await Task.Delay(30000);

            Program.status.SetSubStatus("Closing stupid ninja popup");
            await android.Tap(1893, 50);       //

            await Task.Delay(1000);

            Program.status.SetSubStatus("Closing event popup");
            await android.Tap(1400, 133);       //close event popup

            await android.Tap(1495, 111);       //close anotherpopup
        }
        public async Task <ScanResultEquip> ParseResultWindowEquip(string fileName, ScanInfo scanInfo, AndroidConnector android)
        {
            ScanResultEquip exchangeInfo = new ScanResultEquip()
            {
                Found    = true,
                ScanInfo = scanInfo
            };

            using (var image = Image.Load <Rgba32>(fileName))
            {
                image.Clone(ctx => ctx.Crop(new Rectangle(996, 159, 549, 66))).Save($"itemname.png");
                string itemName = GetTextFromImage("itemname.png");
                if (itemName.ToLower() != scanInfo.RealName.ToLower())
                {
                    scanInfo.Message = $"Something is wrong, names do NOT match. Expected {scanInfo.RealName.ToLower()} but got {itemName.ToLower()}";
                    return(ScanResult.BuildError <ScanResultEquip>(scanInfo));
                }

                exchangeInfo.Price    = int.Parse(GetPriceEquip(image), CultureInfo.InvariantCulture);
                exchangeInfo.SnapTime = GetSnapTime(image);

                int i = 0;
                //scan for multiple items
                bool enchanted   = false;
                bool foundRefine = false;
                while (!Program.CancelScan)
                {
                    using (var image2 = Image.Load <Rgba32>(fileName))
                        image2.Clone(ctx => ctx.Crop(new Rectangle(383, 261, 553, 453))).Save($"enchant{i}.png");
                    string hasEnchant = GetTextFromImage($"enchant{i}.png");
                    Console.WriteLine($"- Text Read: \n\n{hasEnchant}\n\n");
                    if (hasEnchant.ToLower().Contains("refine ") && !foundRefine && !enchanted && hasEnchant.ToLower().IndexOf("refine ") != hasEnchant.ToLower().IndexOf("refine +6 effective"))
                    {
                        string refine = hasEnchant.ToLower();
                        refine = refine.Replace("\r\n", "\n");
                        while (refine.Contains("\n\n"))
                        {
                            refine = refine.Replace("\n\n", "\n");
                        }
                        refine = refine.Substring(refine.IndexOf("\nrefine ") + 8).Trim();
                        if (refine.IndexOf("\n") > 0)
                        {
                            refine = refine.Substring(0, refine.IndexOf("\n")).Trim();
                        }
                        Console.WriteLine(refine);
                        int refineLevel = 0;
                        if (refine.Contains("/"))
                        {
                            try
                            {
                                refineLevel = int.Parse(refine.Substring(0, refine.IndexOf("/")));
                                foundRefine = true;
                            }
                            catch (FormatException e)
                            {
                                scanInfo.Message = "Something is wrong, error parsing refine level: " + refine;
                                Console.WriteLine(e);
                                return(ScanResult.BuildError <ScanResultEquip>(scanInfo));
                            }
                        }
                        if (refine.Contains("atk+"))
                        {
                            int atk = int.Parse(refine.Substring(refine.IndexOf("atk+") + 4));
                            foundRefine = true;
                            //TODO: check if atk matches refineLevel
                        }
                        exchangeInfo.RefinementLevel = refineLevel;
                    }


                    if (hasEnchant.ToLower().Contains("enchanted"))
                    {
                        enchanted = true;
                    }
                    if (hasEnchant.ToLower().Contains("equipment upgrade"))
                    {
                        if (enchanted)
                        {
                            MemoryStream ms          = new MemoryStream();
                            var          jpegEncoder = new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder {
                                Quality = 10
                            };
                            using (var image2 = Image.Load <Rgba32>($"enchant{i}.png"))
                                image2.Clone(ctx => ctx.Resize(new ResizeOptions {
                                    Size = image2.Size() / 2
                                })).SaveAsJpeg(ms, jpegEncoder);

                            exchangeInfo.EnchantmentImage = System.Convert.ToBase64String(ms.GetBuffer());
                            if (!hasEnchant.ToLower().Contains("enchanted"))
                            {
                                Console.WriteLine("Scrolled too far");
                                exchangeInfo.Enchantments = new List <string>()
                                {
                                    "scrolled too far"
                                };
                                break;
                            }
                            hasEnchant = hasEnchant.ToLower();
                            hasEnchant = hasEnchant.Replace("\r\n", "\n");
                            while (hasEnchant.Contains("\n\n"))
                            {
                                hasEnchant = hasEnchant.Replace("\n\n", "\n");
                            }
                            hasEnchant = hasEnchant.Substring(hasEnchant.IndexOf("enchanted attribute:") + 20).Trim();
                            hasEnchant = hasEnchant.Substring(0, hasEnchant.IndexOf("equipment upgrade")).Trim();

                            hasEnchant = hasEnchant.Replace("mapr ", "maxhp ");
                            exchangeInfo.Enchantments = hasEnchant.Split("\n", 4).ToList();
                        }
                        break;
                    }
                    if (hasEnchant.ToLower().Contains("exchange price"))
                    {
                        Console.WriteLine("Scrolled wayyyyyy too far");
                        break;
                    }


                    await android.Swipe(555, 500, 555, 300, 500);

                    await Task.Delay(100);

                    await android.Tap(1500, 960);

                    await android.Screenshot(fileName);

                    i++;
                }
                exchangeInfo.Found = true;
            }
            return(exchangeInfo);
        }
        public ScanResultItem ParseResultWindowRareItem(string fileName, ScanInfo scanInfo, AndroidConnector android)
        {
            ScanResultItem exchangeInfo = new ScanResultItem()
            {
                Found    = true,
                ScanInfo = scanInfo
            };

            using (var image = Image.Load <Rgba32>(fileName))
            {
                image.Clone(ctx => ctx.Crop(new Rectangle(996, 159, 549, 66))).Save($"itemname.png");
                string itemName = GetTextFromImage("itemname.png");
                if (
                    (!scanInfo.RealName.Contains("★") && itemName.ToLower() != scanInfo.RealName.ToLower()) ||
                    (scanInfo.RealName.Contains("★") && !itemName.Contains("*") &&
                     itemName.ToLower() != "andrei card" &&
                     itemName.ToLower() != "zipper beartcard" &&
                     itemName.ToLower() != "archer skeletontcard"
                    )
                    )
                {
                    if (scanInfo.RealName.Contains("★"))
                    {
                        Console.WriteLine("Star card not found");
                    }
                    scanInfo.Message = "Something is wrong, names do NOT match";
                    return(ScanResult.BuildError <ScanResultItem>(scanInfo));
                }


                exchangeInfo.Price = int.Parse(GetPrice(image), CultureInfo.InvariantCulture);

                string amount = GetAmount(image);
                if (amount == "")
                {
                    scanInfo.Message = "Could not find the right amount";
                    return(ScanResult.BuildError <ScanResultItem>(scanInfo));
                }
                exchangeInfo.Amount   = int.Parse(amount, CultureInfo.InvariantCulture);
                exchangeInfo.SnapTime = GetSnapTime(image);


                exchangeInfo.Found = true;
            }
            return(exchangeInfo);
        }
        public async Task <ScanResultItem> ScanRareItem(AndroidConnector android, ScanInfo scanInfo)
        {
            Console.WriteLine("- Opening search window");
            await CloseSearch(android);
            await ClickSearchButton(android);
            await ClickSearchBox(android);

            string itemName = scanInfo.SearchName;

            if (itemName.Contains("★"))
            {
                itemName = itemName.Substring(0, itemName.IndexOf("★")).Trim();
            }

            await android.Text(itemName);

            await ClickSearchWindowSearchButton(android); //to close text input
            await ClickSearchWindowSearchButton(android);

            Console.WriteLine("- Scanning search result");
            await android.Screenshot("searchresult.png");

            List <int> indices = FindSearchResult("searchresult.png", scanInfo);

            if (indices.Count == 0)
            {
                //TODO: do something with item0.png - item9.png
                Console.WriteLine("- Error, could not find item");
                await CloseSearch(android);

                return(ScanResult.BuildError <ScanResultItem>(scanInfo));
            }
            if (indices[0] != scanInfo.SearchIndex)
            {
                if (scanInfo.SearchIndex != -1)
                {
                    Console.WriteLine("- Warning, search index not correct");
                }
                scanInfo.SearchIndex = indices[0];
            }


            for (int i = 0; i < indices.Count; i++)
            {
                await ClickSearchWindowIndex(android, indices[i]);

                await Task.Delay(1500); // the UI needs some time to load the card

                Console.WriteLine("- Checking if any items are on sale");
                await android.Screenshot("shopitems.png");

                using (var image = Image.Load <Rgba32>("shopitems.png"))
                    image.Clone(ctx => ctx.Crop(new Rectangle(975, 505, 368, 64))).Save($"nosale.png");


                bool nosale = false;
                if (GetTextFromImage("nosale.png").ToLower().Contains("currently"))
                {
                    nosale = true;
                    Console.WriteLine("- No items currently on sale");
                    if (i + 1 >= indices.Count)
                    {
                        return new ScanResultItem()
                               {
                                   Found    = false,
                                   ScanInfo = scanInfo
                               }
                    }
                    ;
                }

                if (!nosale)
                {
                    await ClickShopItem(android, 0); // these items should only give 1 item result
                    await ClickShopBuyButton(android);

                    await Task.Delay(1500); // the UI needs some time to load the card

                    Console.WriteLine("- Scanning item");
                    await android.Screenshot("shopresult.png");
                    await ClickShopCloseItem(android);

                    ScanResultItem priceInfo = ParseResultWindowRareItem("shopresult.png", scanInfo, android);
                    if (!priceInfo.Error || i + 1 >= indices.Count)
                    {
                        priceInfo.Error = false;

                        return(priceInfo);
                    }
                }
                scanInfo.Message = "";
                Console.WriteLine("Item does not match, or not found on exchange with multiple items, trying to rescan it");
                await CloseSearch(android);
                await ClickSearchButton(android);
                await ClickSearchBox(android);

                await android.Text(itemName);
                await ClickSearchWindowSearchButton(android); //to close text input
                await ClickSearchWindowSearchButton(android);
            }

            return(null);
        }
    }
 private async Task ClickShopItem(AndroidConnector android, int index, int offsety = 0)
 {
     await android.Tap(800 + (index % 2) * 600, offsety + 302 + 180 *(index / 2));
 }
 private async Task ClickSearchWindowIndex(AndroidConnector android, int index)
 {
     await android.Tap(SearchResultPositions[index].X + 155, SearchResultPositions[index].Y + 44);
 }
 private async Task ClickSearchWindowSearchButton(AndroidConnector android)
 {
     await android.Tap(1400, 260);
 }
 private async Task ClickSearchBox(AndroidConnector android)
 {
     await android.Tap(800, 270);
 }
 private async Task CloseSearch(AndroidConnector android)
 {
     await android.Tap(1467, 187);
 }
 private async Task ClickSearchButton(AndroidConnector android)
 {
     await android.Tap(300, 200);
 }
        private async Task <bool> ScanPage(List <Image <Rgba32> > images, AndroidConnector android, ScanInfo scanInfo, List <ScanResultEquip> result)
        {
            string codename = scanInfo.RealName.ToLower();

            codename = codename.Replace(" ", "_");
            codename = codename.Replace("[1]", "1s");
            codename = codename.Replace("[2]", "2s");


            using (var image = Image.Load <Rgba32>("shopitems.png"))
            {
                //first, look for the top blue line of the item box (RGB(171, 210, 243) if not scrolled half a pixel)
                int starty = FindFirstResult(image);
                Program.log.Log(scanInfo.RealName, $"Item list starting at {starty}");
                await ClickShopItem(android, 0, starty - 230);

                //go through all 8 pictures
                for (int ii = 0; ii < 8; ii++)
                {
                    int newstarty = FindFirstResult(image);
                    if (newstarty != starty)
                    {
                        Program.log.Log(scanInfo.RealName, $"Scrolled a bit, adjusting");
                        starty = newstarty;
                    }
                    if (starty + 180 * (ii / 2) + 132 > 902)
                    {
                        continue;
                    }

                    //make a capture of the item, so we don't scan items twice
                    var subImage = image.Clone(ctx => ctx.Crop(new Rectangle(595 + 600 * (ii % 2), starty + 180 * (ii / 2), 400, 132)));

                    if (TestIfScanned(subImage, images))
                    {
                        Program.log.Log(scanInfo.RealName, $"Item {ii} already scanned, skipping");
                        continue;
                    }
                    images.Add(subImage);
                    subImage.Save($"unknown/unknown{Directory.GetFiles("unknown").Length}.png");

                    //click it as visualisation
                    await ClickShopItem(android, ii, starty - 230);

                    //check if item has multiple on sale. If it does, we don't have to scan it because it won't have an enchantment
                    var rect = new Rectangle(694 + 600 * (ii % 2), starty + 103 + 180 * (ii / 2), 33, 28);
                    using (var amountImage = image.Clone(ctx => ctx.Crop(rect)))
                    {
                        //image.Clone(ctx => ctx.Crop(rect)).Save($"unknown/unknown{Directory.GetFiles("unknown").Length}.png");
                        if (!File.Exists($"data/equip_br/{codename}.png"))
                        {
                            if (!Directory.Exists($"data/equip_br/{codename}"))
                            {
                                Directory.CreateDirectory($"data/equip_br/{codename}");
                            }
                            amountImage.Save($"data/equip_br/{codename}/{Directory.GetFiles($"data/equip_br/{codename}/").Length}.png");
                        }
                        else
                        {
                            using (var noamount = Image.Load <Rgba32>($"data/equip_br/{codename}.png"))
                            {
                                int dist = ImageDistance(amountImage, noamount);
                                if (dist > 100)
                                {
                                    Program.log.Log(scanInfo.RealName, $"Item {ii} has an amount, not scanning. Distance {dist}");
                                    Console.WriteLine($"- Item {ii} has an amount, not scanning! Distance {dist}");
                                    continue;
                                }
                            }
                        }
                    }

                    //scan item for price and enchantments
                    await Task.Delay(100);

                    Console.WriteLine($"- Scanning item {ii}");
                    await ClickShopBuyButton(android);

                    await Task.Delay(1000);

                    Console.WriteLine("- Scanning item");
                    await android.Screenshot("shopresult.png");

                    ScanResultEquip priceInfo = await ParseResultWindowEquip("shopresult.png", scanInfo, android);

                    result.Add(priceInfo);
                    await Task.Delay(100);
                    await ClickShopCloseItem(android);

                    if (priceInfo.Error) //if error, last one is found
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
 private async Task ClickShopBuyButton(AndroidConnector android)
 {
     await android.Tap(1600, 984);
 }
 private async Task ClickShopCloseItem(AndroidConnector android)
 {
     await android.Tap(525, 900);
 }
        public async Task OpenExchange(AndroidConnector android, int map)
        {
            await android.Tap(1800, 160);       //open minimap

            await Task.Delay(500);

            await android.Screenshot("minimap.png");

            using (var image = Image.Load <Rgba32>("minimap.png"))
                image.Clone(ctx => ctx.Crop(new Rectangle(1309, 175, 523, 60))).Save($"mapname.png");
            string mapname = GetTextFromImage("mapname.png").ToLower();
            await android.Tap(1325, 861);       //click world button

            await Task.Delay(1500);

            if (mapname == "prontera south gate")
            {
                await android.Tap(1100, 700);       //click map

                await Task.Delay(1500);

                await android.Tap(700, 665);       //click big cat man
            }
            else if (mapname == "prontera")
            {
                await android.Tap(1100, 600);       //click map

                await Task.Delay(1500);

                await android.Tap(700, 831);       //click big cat man
            }
            else if (mapname == "morroc")
            {
                await android.Tap(1000, 800);       //click map

                await Task.Delay(1500);

                await android.Tap(700, 782);       //click big cat man
            }
            else if (mapname == "geffen")
            {
                await android.Tap(900, 600);       //click map

                await Task.Delay(1500);

                await android.Tap(700, 718);       //click big cat man            }
            }
            else if (mapname == "payon")
            {
                await android.Tap(1300, 800);       //click map

                await Task.Delay(1500);

                await android.Tap(700, 716);       //click big cat man
            }
            else if (mapname == "izlude island")
            {
                await android.Tap(1200, 700);       //click map

                await Task.Delay(1500);

                await android.Tap(700, 432);        //click big cat man
            }
            else
            {
                Program.status.SetSubStatus("Player is at unknown map: " + mapname);
            }


            Program.status.SetSubStatus("Waiting for exchange popup");
            await Task.Delay(1000);

            //wait for buy button to appear
            while (true)
            {
                await android.Screenshot("exchange.png");

                using (var image = Image.Load <Rgba32>("exchange.png"))
                    using (var cmp = Image.Load <Rgba32>("data/exchange.png"))
                        if (IsSame(image.Clone(ctx => ctx.Crop(new Rectangle(1525, 683, 329, 54))), cmp))
                        {
                            break;
                        }
                await Task.Delay(2000);
            }
            Program.status.SetSubStatus("Exchange opened, done");
            await android.Tap(1660, 705);
        }