public void Action() { BuildingQueue Q = this; var CV = UpCall.TD.Villages[VillageID]; if(Q.NextExec >= DateTime.Now) return; Q.NextExec = DateTime.Now.AddSeconds(60); int Bid = UpCall.testPossibleNow(VillageID, Q); // -1表示目前无法建造 if(Bid == -1) { Q.MarkDeleted = true; UpCall.DebugLog("Delete Queue [" + Q.Title + "] because it's impossible to build it.", DebugLevel.W); return; } // 0表示建造该建筑先要造某种别的建筑 if(Bid != 0) { UpCall.DebugLog("Queue [" + Q.Title + "] needs Bid=" + Bid.ToString() + " to be extended.", DebugLevel.I); Q = new BuildingQueue() { UpCall = UpCall, Bid = Bid, Gid = CV.Buildings[Bid].Gid }; UpCall.DebugLog("Create Queue [" + Q.Title + "] because it needs to be extended.", DebugLevel.I); } int bid = Q.Bid; int gid = Q.Gid; string result; result = UpCall.PageQuery(VillageID, "dorf1.php"); if(result == null) return; List<int> nMilitaries = new List<int> {13, 14, 19, 20, 21, 22, 29, 30, 31, 32, 33, 36, 37}; List<int> nResources = new List<int> {5, 6, 7, 8, 9}; string url = "build.php?id=" + bid.ToString(); if (nMilitaries.Contains(gid)) { url += "&category=2"; } else if (nResources.Contains(gid)) { url += "&category=3"; } else if (gid == 17) { url += "&t=0"; } result = UpCall.PageQuery(VillageID, url); if(result == null) return; // m用来解析新建建筑,n用来解析建筑升级 Match m, n; m = Regex.Match(result, "(dorf(\\d)\\.php\\?a=" + gid + "&id=" + bid + "&c=[^\']*?)';\\sreturn"); n = Regex.Match(result, "(dorf(\\d)\\.php\\?a=" + bid + "&c=[^\']*?)';\\sreturn"); if(!m.Success && !n.Success) { // check reason /* * <span class="c">已经有建筑在建造中</span> * <div class="c">资源不足</div> * <p class="c">伐木场建造完成</p> * <span class="c">建造所需资源超过仓库容量上限,请先升级你的仓库</span> * <span class="c">粮食产量不足: 需要先建造一个农场</span> * */ int RomaNeedCrop = -1; // 仓库容量不足的话,先造仓库 if(gid != 10 && UpCall.GidLang.ContainsKey(10) && Regex.Match(result, "<span class=\"(c|none)\">[^<]*?" + UpCall.GetGidLang(10) + "[^<]*?</span>", RegexOptions.IgnoreCase).Success) { gid = 10; bid = findBuilding(VillageID, gid); } // 粮食产量不足的话,先造农场 else if (gid != 11 && UpCall.GidLang.ContainsKey(11) && Regex.Match(result, "<span class=\"(c|none)\">[^<]*?" + UpCall.GetGidLang(11) + "[^<]*?</span>", RegexOptions.IgnoreCase).Success) { gid = 11; bid = findBuilding(VillageID, gid); } else if (gid != 4 && UpCall.GidLang.ContainsKey(4) && Regex.Match(result, "<span class=\"(c|none)\">[^<]*?" + UpCall.GetGidLang(4) + "[^<]*?</span>", RegexOptions.IgnoreCase).Success) { if (UpCall.TD.isRomans && CV.InBuilding[0] != null && Q.Bid > 18) { if (CV.InBuilding[0].Gid != 4) RomaNeedCrop = 1; else if (CV.InBuilding[0].Gid == 4) { RomaNeedCrop = 0; return; } UpCall.DebugLog("Roma NEED Crop rule", DebugLevel.W); Q.NextExec = CV.InBuilding[0].FinishTime.AddSeconds(30); } gid = 4; bid = findBuilding(VillageID, gid); } else if (result.Contains("<p class=\"(c|none)\">")) { UpCall.DebugLog("Unexpected status! Report it on the forum! " + Q.Title, DebugLevel.W); Q.MarkDeleted = true; UpCall.CallStatusUpdate(this, new Travian.StatusChanged() { ChangedData = Travian.ChangedType.Queue, VillageID = VillageID }); return; } else if (UpCall.GidLang.ContainsKey(gid) && Regex.Match(result, "<span class=\"(c|none)\">[^<]*?" + UpCall.GetGidLang(gid) + "[^<]*?</span>", RegexOptions.IgnoreCase).Success) return; else if (result.Contains("<span class=\"(c|none)\">")) { //Q.Delay = rand.Next(500, 1000); // Delay shouldn't happen. Q.NextExec = DateTime.Now.AddSeconds(rand.Next(150, 300)); UpCall.DebugLog("Data not refreshed? Add delay for " + Q.Title, DebugLevel.I); return; } else { UpCall.PageQuery(VillageID, "dorf1.php"); UpCall.PageQuery(VillageID, "dorf2.php"); UpCall.DebugLog("Unknown status! And cause a queue been deleted! " + Q.Title, DebugLevel.W); //Q.MarkDeleted = true; //UpCall.CallStatusUpdate(this, new Travian.StatusChanged() { ChangedData = Travian.ChangedType.Queue, VillageID = VillageID }); Q.NextExec = DateTime.Now.AddSeconds(rand.Next(150, 300)); return; } // 检查资源是否足够 int timecost; if(CV.Buildings.ContainsKey(bid)) timecost = CV.TimeCost(Buildings.Cost(gid, CV.Buildings[bid].Level + 1)); else timecost = CV.TimeCost(Buildings.Cost(gid, 1)); if(CV.InBuilding[UpCall.TD.isRomans && bid > 18 ? 1 : 0] != null) timecost = Math.Max(timecost, Convert.ToInt32(DateTime.Now.Subtract(CV.InBuilding[UpCall.TD.isRomans && bid > 18 ? 1 : 0].FinishTime).TotalSeconds)); if(timecost > 0 || RomaNeedCrop == 1) { UpCall.DebugLog("Need to build but resource not enough so add into queue: " + Q.Title, DebugLevel.I); CV.Queue.Insert(0, new BuildingQueue() { UpCall = UpCall, VillageID = VillageID, Bid = bid, Gid = gid }); UpCall.CallStatusUpdate(this, new Travian.StatusChanged() { ChangedData = Travian.ChangedType.Queue, VillageID = VillageID }); return; } result = UpCall.PageQuery(VillageID, "build.php?id=" + bid.ToString()); if(result == null) return; m = Regex.Match(result, "(dorf(\\d)\\.php\\?a=" + gid + "&id=" + bid + "&c=[^\']*?)'"); n = Regex.Match(result, "(dorf(\\d)\\.php\\?a=" + bid + "&c=[^\']*?)'"); if(!m.Success && !n.Success) { UpCall.DebugLog("Unknown error on building " + Q.Title, DebugLevel.E); Q.MarkDeleted = true; UpCall.CallStatusUpdate(this, new Travian.StatusChanged() { ChangedData = Travian.ChangedType.Queue, VillageID = VillageID }); return; } } // New building int qtype = bid < 19 && bid > 0 ? 0 : 1; if(CV.Buildings.ContainsKey(bid)) CV.RB[UpCall.TD.isRomans ? qtype : 0] = new TInBuilding() { ABid = bid, Gid = gid, Level = CV.Buildings[bid].Level }; else CV.RB[UpCall.TD.isRomans ? qtype : 0] = new TInBuilding() { ABid = bid, Gid = gid, Level = 1 }; // 执行建造操作 string uri; if(m.Success) { uri = m.Groups[1].Value.Replace("amp;", ""); UpCall.PageQuery(VillageID, uri); } else { uri = n.Groups[1].Value.Replace("amp;", ""); UpCall.PageQuery(VillageID, uri); } UpCall.BuildCount(); if(Q.Bid == bid) UpCall.DebugLog("Build " + Q.Title, DebugLevel.I); else UpCall.DebugLog("Build (other) " + Q.Title, DebugLevel.I); if(Q.Bid == bid) { if(Q.TargetLevel == 0 || Q.TargetLevel <= CV.Buildings[bid].Level) { Q.MarkDeleted = true; UpCall.CallStatusUpdate(this, new Travian.StatusChanged() { ChangedData = Travian.ChangedType.Queue, VillageID = VillageID }); } } UpCall.CallStatusUpdate(this, new Travian.StatusChanged() { ChangedData = Travian.ChangedType.Buildings, VillageID = VillageID }); }