/// <summary> /// Used by BotTasks to insert resources/coordinates into the page. /// </summary> /// <param name="acc">Account</param> /// <param name="resources">Target resources</param> /// <param name="coordinates">Target coordinates</param> /// <returns>Time it will take for transit to complete</returns> public static async Task <TimeSpan> MarketSendResource(Account acc, long[] resources, Village targetVillage, BotTask botTask) { var times = 1; if (acc.AccInfo.GoldClub ?? false) { times = 3; } else if (acc.AccInfo.PlusAccount) { times = 2; } // No resources to send if (resources.Sum() == 0) { return(TimeSpan.Zero); } var sendRes = resources.Select(x => x / times).ToArray(); //round the resources that we want to send, so it looks less like a bot (var merchantsCapacity, var merchantsNum) = MarketHelper.ParseMerchantsInfo(acc.Wb.Html); // We don't have any merchants. if (merchantsNum == 0) { //Parse currently ongoing transits var transits = MarketParser.ParseTransits(acc.Wb.Html); var activeVill = acc.Villages.FirstOrDefault(x => x.Active); // Could also just pass that in params var nextTry = SoonestAvailableMerchants(acc, activeVill, targetVillage, transits); if (nextTry != DateTime.MaxValue) { nextTry = nextTry.AddSeconds(5); } botTask.NextExecute = nextTry; // Just return something, will get overwritten anyways. return(new TimeSpan((int)(nextTry - DateTime.Now).TotalHours + 1, 0, 0)); } var maxRes = merchantsCapacity * times; var allRes = resources.Sum(); if (allRes > maxRes) { // We don't have enough merchants to transit all the resources. Divide all resources by some divider. var resDivider = (float)allRes / maxRes; float[] resFloat = sendRes.Select(x => x / resDivider).ToArray(); sendRes = resFloat.Select(x => (long)Math.Floor(x)).ToArray(); } var wb = acc.Wb.Driver; for (int i = 0; i < 4; i++) { // To avoid exception devide by zero if (50 <= sendRes[i]) { //round the number to about -1%, for rounder numbers var digits = Math.Ceiling(Math.Log10(sendRes[i])); var remainder = sendRes[i] % (long)Math.Pow(10, digits - 2); sendRes[i] -= remainder; await DriverHelper.WriteById(acc, "r" + (i + 1), sendRes[i]); } await Task.Delay(AccountHelper.Delay() / 5); } // Input coordinates await DriverHelper.WriteCoordinates(acc, targetVillage.Coordinates); //Select x2/x3 if (times != 1) { wb.ExecuteScript($"document.getElementById('x2').value='{times}'"); await Task.Delay(AccountHelper.Delay() / 5); } await DriverHelper.ClickById(acc, "enabledButton"); var durNode = acc.Wb.Html.GetElementbyId("target_validate"); if (durNode == null && acc.Wb.Html.GetElementbyId("prepareError") != null) { // Error "Abuse! You have not enough resources." is displayed. } //get duration of transit var dur = durNode.Descendants("td").ToList()[3].InnerText.Replace("\t", "").Replace("\n", ""); // Will NOT trigger a page reload! Thus we should await some time before continuing. await DriverHelper.ClickById(acc, "enabledButton"); targetVillage.Market.LastTransit = DateTime.Now; var duration = TimeParser.ParseDuration(dur); return(TimeSpan.FromTicks(duration.Ticks * (times * 2 - 1))); }
/// <summary> /// Used by BotTasks to insert resources/coordinates into the page. /// </summary> /// <param name="acc">Account</param> /// <param name="resources">Target resources</param> /// <param name="coordinates">Target coordinates</param> /// <returns>Time it will take for transit to complete</returns> public static async Task <TimeSpan> MarketSendResource(Account acc, long[] resources, Village targetVillage, BotTask botTask) { var times = 1; if (acc.AccInfo.GoldClub ?? false) { times = 3; } else if (acc.AccInfo.PlusAccount) { times = 2; } var sendRes = resources.Select(x => x / times).ToArray(); //round the resources that we want to send, so it looks less like a bot //TODO: check if we have enough merchants (var merchantsCapacity, var merchantsNum) = MarketHelper.ParseMerchantsInfo(acc.Wb.Html); // We don't have any merchants. if (merchantsNum == 0) { //Parse currently ongoing transits var transits = MarketParser.ParseTransits(acc.Wb.Html); var activeVill = acc.Villages.FirstOrDefault(x => x.Active); // Could also just pass that in params var nextTry = SoonestAvailableMerchants(acc, activeVill, targetVillage, transits); botTask.NextExecute = nextTry.AddSeconds(5); // Just return something, will get overwritten anyways. return(new TimeSpan((int)(nextTry - DateTime.Now).TotalHours + 1, 0, 0)); } var maxRes = merchantsCapacity * times; var allRes = resources.Sum(); if (allRes > maxRes) { // We don't have enough merchants to transit all the resources. Divide all resources by some divider. var resDivider = (float)allRes / maxRes; float[] resFloat = sendRes.Select(x => x / resDivider).ToArray(); sendRes = resFloat.Select(x => (long)Math.Floor(x)).ToArray(); } var wb = acc.Wb.Driver; for (int i = 0; i < 4; i++) { // To avoid exception devide by zero if (sendRes[i] != 0) { //round the number to about -1%, for rounder numbers var digits = Math.Ceiling(Math.Log10(sendRes[i])); var remainder = sendRes[i] % (long)Math.Pow(10, digits - 2); sendRes[i] -= remainder; } wb.ExecuteScript($"document.getElementById('r{i + 1}').value='{sendRes[i]}'"); await Task.Delay(AccountHelper.Delay() / 5); } wb.ExecuteScript($"document.getElementById('xCoordInput').value='{targetVillage.Coordinates.x}'"); await Task.Delay(AccountHelper.Delay() / 5); wb.ExecuteScript($"document.getElementById('yCoordInput').value='{targetVillage.Coordinates.y}'"); await Task.Delay(AccountHelper.Delay() / 5); //Select x2/x3 if (times != 1) { wb.ExecuteScript($"document.getElementById('x2').value='{times}'"); await Task.Delay(AccountHelper.Delay() / 5); } // Some bot protection here I guess. Just remove the class of the DOM. var script = @" var button = document.getElementById('enabledButton'); button.click(); "; wb.ExecuteScript(script); //Prepare //update htmlDoc, parse duration, TODO: maybe some other method to wait until the page is loaded? HtmlNode durNode = null; do { await Task.Delay(AccountHelper.Delay()); HtmlDocument html2 = new HtmlDocument(); html2.LoadHtml(wb.PageSource); durNode = html2.GetElementbyId("target_validate"); }while (durNode == null); //get duration of transit var dur = durNode.Descendants("td").ToList()[3].InnerText.Replace("\t", "").Replace("\n", ""); // Will NOT trigger a page reload! Thus we should await some time before continuing. wb.ExecuteScript("document.getElementById('enabledButton').click()"); //SendRes await Task.Delay(AccountHelper.Delay() * 2); var duration = TimeParser.ParseDuration(dur); return(TimeSpan.FromTicks(duration.Ticks * (times * 2 - 1))); }