/// <summary> /// When new village is found by the bot, it should firstly check barracks, then stable and then workshop, /// to see which troops are researched /// </summary> public override async Task <TaskRes> Execute(Account acc) { var wb = acc.Wb.Driver; // If we have Plus account, just check that. if (acc.AccInfo.PlusAccount) { await VersionHelper.Navigate(acc, "/dorf3.php?s=5&su=2", "/village/statistics/troops?su=2"); OverviewParser.UpdateTroopsLevels(acc.Wb.Html, ref acc); // We have updated all villages at the same time. No need to continue. acc.Tasks.RemoveAll(x => x.GetType() == typeof(UpdateTroops)); return(TaskRes.Executed); } var smithy = Vill.Build.Buildings.FirstOrDefault(x => x.Type == Classificator.BuildingEnum.Smithy); if (smithy != null) { await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/build.php?id={smithy.Id}"); Vill.Troops.Levels = TroopsParser.GetTroopLevels(acc.Wb.Html); TroopsHelper.UpdateResearchedTroops(Vill); return(TaskRes.Executed); } for (int i = 0; i < 3; i++) { //var building = GetBuilding(i); //await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/build.php?id={building.Id}"); // TODO: parse content } return(TaskRes.Executed); }
/// <summary> /// When new village is found by the bot, it should firstly check barracks, then stable and then workshop, /// to see which troops are researched /// </summary> public override async Task <TaskRes> Execute(HtmlDocument htmlDoc, ChromeDriver wb, Files.Models.AccModels.Account acc) { // If we have Plus account, just check that. if (acc.AccInfo.PlusAccount) { await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/dorf3.php?s=5&su=2"); OverviewParser.UpdateTroopsLevels(htmlDoc, ref acc); // We have updated all villages at the same time. No need to continue. acc.Tasks.RemoveAll(x => x.GetType() == typeof(UpdateTroops)); return(TaskRes.Executed); } var smithy = vill.Build.Buildings.FirstOrDefault(x => x.Type == Classificator.BuildingEnum.Smithy); if (smithy != null) { await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/build.php?id={smithy.Id}"); vill.Troops.Levels = TroopsParser.GetTroopLevels(htmlDoc); UpdateResearchedTroops(vill); return(TaskRes.Executed); } for (int i = 0; i < 3; i++) { //var building = GetBuilding(i); //await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/build.php?id={building.Id}"); // TODO: parse content } return(TaskRes.Executed); }
// Copied from UpdateTroops BotTask public async Task UpdateTroopsResearchedAndLevels(Account acc) { if (acc.AccInfo.PlusAccount) { // From overview we get all researched troops and their levels switch (acc.AccInfo.ServerVersion) { case Classificator.ServerVersionEnum.T4_4: await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/dorf3.php?s=5&su=2"); break; case Classificator.ServerVersionEnum.T4_5: await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/village/statistics/troops?su=2"); break; } OverviewParser.UpdateTroopsLevels(acc.Wb.Html, ref acc); // We have updated all villages at the same time. No need to continue. acc.Tasks.RemoveAll(x => x.GetType() == typeof(UpdateTroops)); return; } var smithy = Vill.Build.Buildings.FirstOrDefault(x => x.Type == Classificator.BuildingEnum.Smithy); if (smithy != null) { // If smithy exists, we get all researched troops and their levels await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/build.php?id={smithy.Id}"); Vill.Troops.Levels = TroopsParser.GetTroopLevels(acc.Wb.Html); TroopsHelper.UpdateResearchedTroops(Vill); return; } }
public void UpdateCurrentlyTraining(HtmlDocument htmlDoc, Account acc) { var ct = TroopsParser.GetTroopsCurrentlyTraining(htmlDoc); switch (building) { case Classificator.BuildingEnum.Barracks: Vill.Troops.CurrentlyTraining.Barracks = ct; break; case Classificator.BuildingEnum.Stable: Vill.Troops.CurrentlyTraining.Stable = ct; break; case Classificator.BuildingEnum.GreatBarracks: Vill.Troops.CurrentlyTraining.GB = ct; break; case Classificator.BuildingEnum.GreatStable: Vill.Troops.CurrentlyTraining.GS = ct; break; case Classificator.BuildingEnum.Workshop: Vill.Troops.CurrentlyTraining.Workshop = ct; break; } }
//If Troop == null, just update the troop levels public override async Task <TaskRes> Execute(Account acc) { await base.Execute(acc); // Navigate to dorf2 if (!await VillageHelper.EnterBuilding(acc, Vill, Classificator.BuildingEnum.Academy)) { return(TaskRes.Executed); } var troop = Vill.Troops.ToResearch.FirstOrDefault(); if (troop == TroopsEnum.None) { return(TaskRes.Executed); //We have researched all troops that were on the list } var troopNode = acc.Wb.Html.DocumentNode.Descendants("img").FirstOrDefault(x => x.HasClass("u" + (int)troop)); if (troopNode == null) { acc.Wb.Log($"Researching {troop} was not possible! Bot assumes you already have it researched"); Vill.Troops.Researched.Add(troop); return(TaskRes.Retry); } while (!troopNode.HasClass("research")) { troopNode = troopNode.ParentNode; } var button = troopNode.Descendants("button").FirstOrDefault(x => x.HasClass("green")); if (button == null) { RepeatTask(Vill, troop, DateTime.Now); } (TimeSpan dur, Resources cost) = TroopsParser.AcademyResearchCost(acc.Wb.Html, troop); // Check if we have enough resources to research the troop if (!ResourcesHelper.IsEnoughRes(Vill, cost.ToArray())) { ResourcesHelper.NotEnoughRes(acc, Vill, cost, this); return(TaskRes.Executed); } await DriverHelper.ClickById(acc, button.Id); var executeNext = DateTime.Now.Add(dur).AddMilliseconds(10 * AccountHelper.Delay()); if (Vill.Settings.AutoImprove) { TaskExecutor.AddTask(acc, new ImproveTroop() { Vill = this.Vill, ExecuteAt = DateTime.Now.Add(dur) }); } RepeatTask(Vill, troop, executeNext); return(TaskRes.Executed); }
//If Troop == null, just update the troop levels public override async Task <TaskRes> Execute(HtmlDocument htmlDoc, ChromeDriver wb, Files.Models.AccModels.Account acc) { var academy = vill.Build.Buildings.FirstOrDefault(x => x.Type == Classificator.BuildingEnum.Academy); if (academy == null) { return(TaskRes.Executed); } await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/build.php?id={academy.Id}"); var troop = vill.Troops.ToResearch.FirstOrDefault(); if (troop == TroopsEnum.None) { return(TaskRes.Executed); //We have researched all troops that were on the list } var troopNode = htmlDoc.DocumentNode.Descendants("img").FirstOrDefault(x => x.HasClass("u" + (int)troop)); if (troopNode == null) { this.ErrorMessage = $"Researching {troop} was not possible! Bot assumes you already have it researched"; vill.Troops.Researched.Add(troop); return(TaskRes.Retry); } while (!troopNode.HasClass("research")) { troopNode = troopNode.ParentNode; } var button = troopNode.Descendants("button").FirstOrDefault(x => x.HasClass("green")); if (button == null) { RepeatTask(vill, troop, DateTime.Now); } (TimeSpan dur, Resources cost) = TroopsParser.AcademyResearchCost(htmlDoc, troop); var nextExecute = ResourcesHelper.EnoughResourcesOrTransit(acc, vill, cost); if (nextExecute < DateTime.Now.AddMilliseconds(1)) //We have enough resources, click Research button { wb.ExecuteScript($"document.getElementById('{button.Id}').click()"); var executeNext = DateTime.Now.Add(dur).AddMilliseconds(10 * AccountHelper.Delay()); TaskExecutor.AddTask(acc, new ImproveTroop() { vill = this.vill, ExecuteAt = DateTime.Now.Add(dur) } ); RepeatTask(vill, troop, executeNext); return(TaskRes.Executed); } else //Retry same task after resources get produced/transited { this.NextExecute = nextExecute; return(TaskRes.Executed); } }
/// <summary> /// Sends HTTP request to the server and gets number of animals inside the oasis /// </summary> public static int[] GetOasisAnimals(Account acc, Coordinates oasis) { var htmlDoc = new HtmlAgilityPack.HtmlDocument(); string html = ""; switch (acc.AccInfo.ServerVersion) { case Classificator.ServerVersionEnum.T4_4: var ajaxToken = DriverHelper.GetJsObj <string>(acc, "ajaxToken"); var req = new RestSharp.RestRequest { Resource = "/ajax.php?cmd=viewTileDetails", Method = Method.POST, }; req.AddParameter("cmd", "viewTileDetails"); req.AddParameter("x", oasis.x.ToString()); req.AddParameter("y", oasis.y.ToString()); req.AddParameter("ajaxToken", ajaxToken); var resString = HttpHelper.SendPostReq(acc, req); var root = JsonConvert.DeserializeObject <TileDetailsT4_4>(resString); if (root.response.error) { throw new Exception("Unable to get T4.4 tile details!\n" + root.response.error); } html = WebUtility.HtmlDecode(root.response.data.html); break; case Classificator.ServerVersionEnum.T4_5: var bearerToken = DriverHelper.GetBearerToken(acc); var reqMapInfo = new RestSharp.RestRequest { Resource = "/api/v1/ajax/viewTileDetails", Method = Method.POST, RequestFormat = DataFormat.Json }; reqMapInfo.AddHeader("authorization", $"Bearer {bearerToken}"); reqMapInfo.AddHeader("content-type", "application/json; charset=UTF-8"); reqMapInfo.AddJsonBody(oasis); var tileDetails = HttpHelper.SendPostReq(acc, reqMapInfo); var tile = JsonConvert.DeserializeObject <TileDetailsT4_5>(tileDetails); html = WebUtility.HtmlDecode(tile.html); break; } htmlDoc.LoadHtml(html); return(TroopsParser.GetOasisAnimals(htmlDoc)); }
public async Task UpdateTroopsTraining(Account acc) { foreach (var trainingBuilding in trainingBuildings) { if (!await VillageHelper.EnterBuilding(acc, Vill, trainingBuilding)) { continue; } // Mark troops that user can train in building as researched TroopsHelper.UpdateTroopsResearched(Vill, acc.Wb.Html); var ct = TroopsParser.GetTroopsCurrentlyTraining(acc.Wb.Html); switch (trainingBuilding) { case Classificator.BuildingEnum.Barracks: Vill.Troops.CurrentlyTraining.Barracks = ct; break; case Classificator.BuildingEnum.Stable: Vill.Troops.CurrentlyTraining.Stable = ct; break; case Classificator.BuildingEnum.GreatBarracks: Vill.Troops.CurrentlyTraining.GB = ct; break; case Classificator.BuildingEnum.GreatStable: Vill.Troops.CurrentlyTraining.GS = ct; break; case Classificator.BuildingEnum.Workshop: Vill.Troops.CurrentlyTraining.Workshop = ct; break; } await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/dorf2.php"); await Task.Delay(AccountHelper.Delay()); } }
public override async Task <TaskRes> Execute(Account acc) { var building = Vill.Build.Buildings .FirstOrDefault(x => x.Type == Classificator.BuildingEnum.Residence || x.Type == Classificator.BuildingEnum.Palace || x.Type == Classificator.BuildingEnum.CommandCenter ); if (!await VillageHelper.EnterBuilding(acc, building, "&s=1")) { return(TaskRes.Executed); } var settler = TroopsData.TribeSettler(acc.AccInfo.Tribe); var troopNode = acc.Wb.Html.DocumentNode.Descendants("img").FirstOrDefault(x => x.HasClass("u" + (int)settler)); if (troopNode == null) { acc.Wb.Log("No new settler can be trained, probably because 3 settlers are already (being) trained"); SendSettlersTask(acc); return(TaskRes.Executed); } while (!troopNode.HasClass("details")) { troopNode = troopNode.ParentNode; } var div = troopNode.Descendants("div"); Vill.Troops.Settlers = (int)Parser.RemoveNonNumeric(div.FirstOrDefault(x => x.HasClass("tit")).Descendants("span").FirstOrDefault().InnerText); string innertext = ""; switch (acc.AccInfo.ServerVersion) { case Classificator.ServerVersionEnum.T4_4: innertext = troopNode.ChildNodes.First(x => x.Name == "a").InnerText; break; case Classificator.ServerVersionEnum.T4_5: // no expansion slot if (div.FirstOrDefault(x => x.HasClass("noExpansionSlot")) != null) { if (Vill.Troops.Settlers >= 3) { if (acc.NewVillages.AutoSettleNewVillages) { TaskExecutor.AddTaskIfNotExists(acc, new SendSettlers() { ExecuteAt = DateTime.Now.AddHours(-3), Vill = this.Vill, // For high speed servers, you want to train settlers asap Priority = 1000 < acc.AccInfo.ServerSpeed ? TaskPriority.High : TaskPriority.Medium, }); } acc.Wb.Log("Have enoung settlers"); } else { acc.Wb.Log("Don't have enough expansion slot or settlers are training."); } return(TaskRes.Executed); } innertext = div.FirstOrDefault(x => x.HasClass("cta")).Descendants("a").FirstOrDefault().InnerText; break; } var maxNum = Parser.RemoveNonNumeric(innertext); Vill.Troops.Settlers = (int)TroopsParser.ParseAvailable(troopNode); var costNode = troopNode.Descendants("div").FirstOrDefault(x => x.HasClass("resourceWrapper")); var cost = ResourceParser.GetResourceCost(costNode); if (!ResourcesHelper.IsEnoughRes(Vill, cost.ToArray())) { ResourcesHelper.NotEnoughRes(acc, Vill, cost, this); return(TaskRes.Executed); } acc.Wb.Driver.ExecuteScript($"document.getElementsByName('t10')[0].value='{maxNum}'"); await Task.Delay(AccountHelper.Delay()); // Click Train button await TbsCore.Helpers.DriverHelper.ExecuteScript(acc, "document.getElementById('s1').click()"); Vill.Troops.Settlers += (int)maxNum; if (Vill.Troops.Settlers < 3) { // random train next settlers after 30 - 60 mins var ran = new Random(); this.NextExecute = DateTime.Now.AddMinutes(ran.Next(30, 60)); } else { if (acc.NewVillages.AutoSettleNewVillages) { SendSettlersTask(acc); } } return(TaskRes.Executed); }
public static DateTime TrainingDuration(HtmlAgilityPack.HtmlDocument html) { var training = TroopsParser.GetTroopsCurrentlyTraining(html); return(training.Count == 0 ? DateTime.MinValue : training.Last().FinishTraining); }
public override async Task <TaskRes> Execute(HtmlDocument htmlDoc, ChromeDriver wb, Files.Models.AccModels.Account acc) { if (vill == null) { vill = acc.Villages.First(x => x.Active); } var smithy = vill.Build.Buildings.FirstOrDefault(x => x.Type == Classificator.BuildingEnum.Smithy); if (smithy == null) { return(TaskRes.Executed); } await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/build.php?id={smithy.Id}"); var levels = TroopsParser.GetTroopLevels(htmlDoc); if (levels == null) { this.ErrorMessage = "There was an error at getting Smithy troop levels"; return(TaskRes.Executed); } vill.Troops.Levels = levels; UpdateResearchedTroops(vill); var currentlyImproving = TroopsParser.GetImprovingTroops(htmlDoc); var troop = TroopToImprove(vill, currentlyImproving); if (troop == Classificator.TroopsEnum.None) { return(TaskRes.Executed); } //If we have plus account we can improve 2 troops at the same time int maxImproving = acc.AccInfo.PlusAccount ? 2 : 1; if (currentlyImproving.Count() >= maxImproving) { this.NextExecute = DateTime.Now.Add(currentlyImproving.Last().Time); return(TaskRes.Executed); } //call NextImprove() after enough res OR when this improvement finishes. var cost = vill.Troops.Levels.FirstOrDefault(x => x.Troop == troop); var nextExecute = ResourcesHelper.EnoughResourcesOrTransit(acc, vill, cost.UpgradeCost); if (nextExecute < DateTime.Now.AddMilliseconds(1)) //We have enough resources, click Improve button { //Click on the button var troopNode = htmlDoc.DocumentNode.Descendants("img").FirstOrDefault(x => x.HasClass("u" + (int)troop)); while (!troopNode.HasClass("research")) { troopNode = troopNode.ParentNode; } var button = troopNode.Descendants("button").FirstOrDefault(x => x.HasClass("green")); if (button == null) { this.ErrorMessage = $"Could not find Upgrade button to improve {troop}"; this.NextExecute = DateTime.Now.AddMinutes(1); return(TaskRes.Retry); } wb.ExecuteScript($"document.getElementById('{button.Id}').click()"); // If we have plus account and there is currently no other troop to improve, go ahead and improve the unit again this.NextExecute = (currentlyImproving.Count() == 0 && maxImproving == 2) ? DateTime.MinValue : DateTime.Now.Add(cost.TimeCost).AddMilliseconds(5 * AccountHelper.Delay()); return(TaskRes.Executed); } else //Retry same task after resources get produced/transited { this.NextExecute = nextExecute; return(TaskRes.Executed); } }
public override async Task <TaskRes> Execute(Account acc) { building = TroopsHelper.GetTroopBuilding(Troop, Great); // Switch hero helmet. If hero will be switched, this TrainTroops task // will be executed right after the hero helmet switch if (HeroHelper.SwitchHelmet(acc, this.Vill, building, this)) { return(TaskRes.Executed); } await base.Execute(acc); if (!await VillageHelper.EnterBuilding(acc, Vill, building)) { return(TaskRes.Executed); } if (this.UpdateOnly || this.Troop == TroopsEnum.None) { return(TaskRes.Executed); } (TimeSpan dur, Resources cost) = TroopsParser.GetTrainCost(acc.Wb.Html, this.Troop); var troopNode = acc.Wb.Html.DocumentNode.Descendants("img").FirstOrDefault(x => x.HasClass("u" + (int)Troop)); if (troopNode == null) { acc.Wb.Log($"Bot tried to train {Troop} in {Vill.Name}, but couldn't find it in {building}! Are you sure you have {Troop} researched?"); return(TaskRes.Executed); } while (!troopNode.HasClass("details")) { troopNode = troopNode.ParentNode; } var inputName = troopNode.Descendants("input").FirstOrDefault().GetAttributeValue("name", ""); long maxNum = 0; switch (acc.AccInfo.ServerVersion) { case ServerVersionEnum.T4_4: maxNum = Parser.RemoveNonNumeric( troopNode.ChildNodes .FirstOrDefault(x => x.Name == "a")?.InnerText ?? "0" ); break; case ServerVersionEnum.T4_5: maxNum = Parser.RemoveNonNumeric( troopNode.ChildNodes .First(x => x.HasClass("cta")) .ChildNodes .First(x => x.Name == "a") .InnerText); break; } if (!HighSpeedServer) { var trainNum = TroopsHelper.TroopsToFill(acc, Vill, this.Troop, this.Great); // Don't train too many troops, just fill up the training building if (maxNum > trainNum) { maxNum = trainNum; } } if (maxNum < 0) { // We have already enough troops in training. return(TaskRes.Executed); } acc.Wb.Driver.ExecuteScript($"document.getElementsByName('{inputName}')[0].value='{maxNum}'"); await Task.Delay(100); await DriverHelper.ExecuteScript(acc, "document.getElementsByName('s1')[0].click()"); UpdateCurrentlyTraining(acc.Wb.Html, acc); if (!HighSpeedServer) { RepeatTrainingCycle(acc.Wb.Html, acc); } return(TaskRes.Executed); }
public override async Task <TaskRes> Execute(Account acc) { var building = Vill.Build.Buildings .FirstOrDefault(x => x.Type == Classificator.BuildingEnum.Residence || x.Type == Classificator.BuildingEnum.Palace || x.Type == Classificator.BuildingEnum.CommandCenter ); if (!await VillageHelper.EnterBuilding(acc, Vill, building, "&s=1")) { return(TaskRes.Executed); } var settler = TroopsData.TribeSettler(acc.AccInfo.Tribe); var troopNode = acc.Wb.Html.DocumentNode.Descendants("img").FirstOrDefault(x => x.HasClass("u" + (int)settler)); if (troopNode == null) { acc.Wb.Log("No new settler can be trained, probably because 3 settlers are already (being) trained"); SendSettlersTask(acc); return(TaskRes.Executed); } while (!troopNode.HasClass("details")) { troopNode = troopNode.ParentNode; } var maxNum = Parser.RemoveNonNumeric(troopNode.ChildNodes.First(x => x.Name == "a").InnerText); var available = TroopsParser.ParseAvailable(troopNode); var costNode = acc.Wb.Html.DocumentNode.Descendants("div").FirstOrDefault(x => x.HasClass("resourceWrapper")); var cost = ResourceParser.GetResourceCost(costNode); if (!ResourcesHelper.IsEnoughRes(Vill, cost.ToArray())) { ResourcesHelper.NotEnoughRes(acc, Vill, cost, this); return(TaskRes.Executed); } acc.Wb.Driver.ExecuteScript($"document.getElementsByName('t10')[0].value='{maxNum}'"); await Task.Delay(AccountHelper.Delay()); // Click Train button await TbsCore.Helpers.DriverHelper.ExecuteScript(acc, "document.getElementById('s1').click()"); Vill.Troops.Settlers = (int)available + (int)maxNum; var training = TroopsHelper.TrainingDuration(acc.Wb.Html); if (training < DateTime.Now) { training = DateTime.Now; } if (Vill.Troops.Settlers < 3) { //In 1 minute, do the same task (to get total of 3 settlers) this.NextExecute = training.AddSeconds(3); } else { if (acc.NewVillages.AutoSettleNewVillages) { SendSettlersTask(acc); } } return(TaskRes.Executed); }
public override async Task <TaskRes> Execute(HtmlDocument htmlDoc, ChromeDriver wb, Files.Models.AccModels.Account acc) { building = TroopsHelper.GetTroopBuilding(Troop, Great); var buildId = vill.Build.Buildings.FirstOrDefault(x => x.Type == building); if (buildId == null) { //update dorf, no buildingId found? TaskExecutor.AddTask(acc, new UpdateDorf2() { ExecuteAt = DateTime.Now, vill = vill }); Console.WriteLine($"There is no {building} in this village!"); return(TaskRes.Executed); } await acc.Wb.Navigate($"{acc.AccInfo.ServerUrl}/build.php?id={buildId.Id}"); //after finishing task, update currently training this.PostTaskCheck.Add(UpdateCurrentlyTraining); if (!HighSpeedServer) { this.PostTaskCheck.Add(RepeatTrainingCycle); } if (this.UpdateOnly || this.Troop == TroopsEnum.None) { return(TaskRes.Executed); } (TimeSpan dur, Resources cost) = TroopsParser.GetTrainCost(htmlDoc, this.Troop); var troopNode = htmlDoc.DocumentNode.Descendants("img").FirstOrDefault(x => x.HasClass("u" + (int)Troop)); while (!troopNode.HasClass("details")) { troopNode = troopNode.ParentNode; } var inputName = troopNode.Descendants("input").FirstOrDefault().GetAttributeValue("name", ""); var maxNum = Parser.RemoveNonNumeric(troopNode.ChildNodes.FirstOrDefault(x => x.Name == "a").InnerText); if (!HighSpeedServer) { var trainNum = TroopsHelper.TroopsToFill(acc, vill, this.Troop, this.Great); // Don't train too many troops, just fill up the training building if (maxNum > trainNum) { maxNum = trainNum; } } if (maxNum < 0) { // We have already enough troops in training. return(TaskRes.Executed); } wb.ExecuteScript($"document.getElementsByName('{inputName}')[0].value='{maxNum}'"); await Task.Delay(100); wb.ExecuteScript("document.getElementsByName('s1')[0].click()"); //Train button return(TaskRes.Executed); }
public override async Task <TaskRes> Execute(Account acc) { await base.Execute(acc); // Navigate to dorf2 if (Vill == null) { Vill = acc.Villages.First(x => x.Active); } if (!await VillageHelper.EnterBuilding(acc, Vill, Classificator.BuildingEnum.Smithy)) { return(TaskRes.Executed); } var levels = TroopsParser.GetTroopLevels(acc.Wb.Html); if (levels == null) { acc.Wb.Log("There was an error at getting Smithy troop levels"); return(TaskRes.Executed); } Vill.Troops.Levels = levels; TroopsHelper.UpdateResearchedTroops(Vill); var currentlyImproving = TroopsParser.GetImprovingTroops(acc.Wb.Html); var troop = TroopToImprove(Vill, currentlyImproving); if (troop == Classificator.TroopsEnum.None) { return(TaskRes.Executed); } //If we have plus account we can improve 2 troops at the same time int maxImproving = acc.AccInfo.PlusAccount ? 2 : 1; if (maxImproving <= currentlyImproving.Count()) { this.NextExecute = DateTime.Now.Add(currentlyImproving.Last().Time); return(TaskRes.Executed); } //call NextImprove() after enough res OR when this improvement finishes. var cost = Vill.Troops.Levels.FirstOrDefault(x => x.Troop == troop); // Check if we have enough resources to improve the troop if (!ResourcesHelper.IsEnoughRes(Vill, cost.UpgradeCost.ToArray())) { ResourcesHelper.NotEnoughRes(acc, Vill, cost.UpgradeCost, this); return(TaskRes.Executed); } //Click on the button var troopNode = acc.Wb.Html.DocumentNode.Descendants("img").FirstOrDefault(x => x.HasClass("u" + (int)troop)); while (!troopNode.HasClass("research")) { troopNode = troopNode.ParentNode; } var button = troopNode.Descendants("button").FirstOrDefault(x => x.HasClass("green")); if (button == null) { acc.Wb.Log($"Could not find Upgrade button to improve {troop}"); this.NextExecute = DateTime.Now.AddMinutes(1); return(TaskRes.Retry); } acc.Wb.Driver.ExecuteScript($"document.getElementById('{button.Id}').click()"); // If we have plus account and there is currently no other troop to improve, go ahead and improve the unit again this.NextExecute = (currentlyImproving.Count() == 0 && maxImproving == 2) ? DateTime.MinValue : DateTime.Now.Add(cost.TimeCost).AddMilliseconds(5 * AccountHelper.Delay()); return(TaskRes.Executed); }