AFK Macro

Idle Mafia Macro/Source/src/Respect.cs

Respect.cs

Respect from fights · 311 lines · 15 KB

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
namespace IdleMafiaBot
{
sealed partial class Game
{
static readonly Regex RespectChip = new Regex(@"Respect\s*[:.]?\s*([0-9OoIlS][0-9OoIlS,. ]{0,9})\s*$", RegexOptions.IgnoreCase);
internal static int FightRespectIn(List<OcrLine> lines, Rectangle area)
{
foreach (var l in lines.Where(x => x.CenterX > area.Left + area.Width / 2 && x.CenterY < area.Top + area.Height / 3))
{
var m = RespectChip.Match(l.Text);
int v;
if (m.Success && int.TryParse(Parse.Digits(m.Groups[1].Value), out v) && v >= 0) return v;
}
return -1;
}
public int FightRespect(Frame f, Prep prep)
{
var area = PageArea(f);
return FightRespectIn(Ocr.Read(f, area, PageScale(f), prep), area);
}
internal OcrLine CollectionWithdrawBeside(Frame f, OcrLine deposit)
{
var area = PageArea(f);
int h = Math.Max(8, deposit.Box.Height);
foreach (var prep in new[] { Prep.None, Prep.DarkText, Prep.WhiteText })
{
var hit = Ocr.Read(f, area, PageScale(f), prep).FirstOrDefault(l => Parse.Key(l.Text) == "WITHDRAWAII" && l.Box.X >= deposit.Box.Right
&& l.Box.X - deposit.Box.Right < Math.Max(12 * h, 5 * deposit.Box.Width) && Math.Abs(l.CenterY - deposit.CenterY) < 2 * h);
if (hit != null) return hit;
}
return null;
}
public sealed class WithdrawResult { public CollectionState Before, After; public bool Out; }
internal static OcrLine CollectionWithdrawConfirm(List<OcrLine> lines)
{
if (!lines.Any(l => Parse.Has(l.Text, "RETURN ALL") || Parse.Has(l.Text, "COLLECTION TO"))) return null;
var cancel = lines.FirstOrDefault(l => Parse.Key(l.Text) == "CANCEI");
if (cancel == null) return null;
int h = Math.Max(8, cancel.Box.Height);
return lines.FirstOrDefault(l => Parse.Key(l.Text) == "WITHDRAWAII" && l.Box.Right < cancel.Box.X && Math.Abs(l.CenterY - cancel.CenterY) <= h);
}
public WithdrawResult WithdrawCollection()
{
if (!OpenTab(Tab.Collection)) return null;
var r = new WithdrawResult();
OcrLine button = null;
for (int look = 0; look < 3 && button == null; look++)
{
if (look > 0) Wait(1200);
using (var f = Capture())
{
var deposit = FindCollectionDeposit(f, out r.Before);
if (deposit != null) button = CollectionWithdrawBeside(f, deposit);
}
}
if (r.Before != null && r.Before.Deposited == 0 && r.Before.Attack <= 0)
{
log("Collection: nothing in it to withdraw (" + r.Before + ")");
r.After = r.Before;
r.Out = true;
return r;
}
if (button == null)
{
log("Collection: WITHDRAW ALL not found - nothing pressed (" + collectionSeen + ")");
Snapshot("collection withdraw not found", 60);
return null;
}
CheckForPurchaseWindow();
NotDisconnected();
if (OnlyNavigate) RefuseInCheck(button.Text);
Click(button.CenterX, button.CenterY, 1200);
Snapshot("collection withdraw pressed", 0, true);
for (int look = 0; look < 4; look++)
{
using (var f = Capture())
{
var popup = Ocr.Read(f, PopupArea(f), PopupScale(f), Prep.None);
CheckForPurchasePrompt(popup);
var yes = CollectionWithdrawConfirm(popup);
if (yes != null) { Snapshot("collection withdraw window", 0, true); Click(yes.CenterX, yes.CenterY, 1500); continue; }
FindCollectionDeposit(f, out r.After);
}
if (r.After != null && (r.After.Attack >= 0 && r.Before.Attack > r.After.Attack || r.After.Deposited >= 0 && r.Before.Deposited > r.After.Deposited)) { r.Out = true; break; }
Wait(800);
}
return r;
}
internal string LowestFlaggedCity(Frame f)
{
var flagged = FlaggedCities(f);
return Districts.Cities.FirstOrDefault(flagged.Contains);
}
public bool LowestFamilyDistrict(out string city, out int number, out string name)
{
city = name = null; number = -1;
if (!OpenTab(Tab.Territory)) return false;
CloseStrayDistrict();
OcrLine cityBox, districtBox;
cityBox = districtBox = null;
for (int look = 0; look < 6 && cityBox == null; look++)
{
if (look > 0) Wait(1000);
using (var f = Capture()) if (!TerritoryBar(f, out cityBox, out districtBox)) cityBox = null;
}
if (cityBox == null) { log("Territory: the page's city and district drop-downs didn't read"); Snapshot("respect cycle territory not read", 60); return false; }
Click(cityBox.CenterX, cityBox.CenterY, 900);
using (var f = Capture()) city = LowestFlaggedCity(f);
Click(cityBox.CenterX, cityBox.CenterY, 600);
if (city == null) return false;
if (!SelectCity(city, out cityBox, out districtBox) || !MyFamilyOn()) return false;
Click(districtBox.CenterX, districtBox.CenterY, 900);
int h = Math.Max(8, cityBox.Box.Height), bottom = districtBox.Box.Bottom, left = districtBox.Box.X;
var rows = new List<Tuple<int, OcrLine, string>>();
using (var f = Capture())
foreach (var l in Ocr.Read(f, PageArea(f), PageScale(f) + 1, Prep.None).Where(l => l.Box.Y > bottom && l.Box.X < left + 8 * h))
{
int no;
string nm;
if (ListedDistrict(l.Text, city, out no, out nm)) rows.Add(Tuple.Create(no, l, nm));
}
Click(districtBox.CenterX, districtBox.CenterY, 600);
var first = ListColumn(rows).FirstOrDefault();
if (first == null) return false;
number = first.Item1; name = first.Item3;
return true;
}
}
sealed partial class Bot
{
bool Lowering { get { return S.RespectState.Length > 0; } }
internal static bool RespectUnfinished(string state) { return state == "0|0" || state.EndsWith("|s"); }
int lastRespect = -1, respectOnce = -1, depositTries;
DateTime respectWait = DateTime.MinValue, stationAgain = DateTime.MinValue;
int ReadRespect()
{
int a, b;
using (var f = game.Capture()) { a = game.FightRespect(f, Prep.None); b = game.FightRespect(f, Prep.WhiteText); }
int v = a >= 0 && a == b ? a : -1;
if (v < 0)
{
int one = a >= 0 && b < 0 ? a : b >= 0 && a < 0 ? b : -1;
if (one >= 0 && (one == respectOnce || (lastRespect >= 0 && Math.Abs(one - lastRespect) <= 300))) v = one;
respectOnce = one;
}
if (v >= 0) lastRespect = v;
return v;
}
bool RespectTurn()
{
if (DateTime.UtcNow < respectWait) return false;
int r = ReadRespect();
if (r < 0) { SayOnce("respect unread " + DateTime.UtcNow.ToString("yyyyMMddHH"), "Respect cycle: couldn't read your respect on the Fight page"); return false; }
SayOnce("respect read " + DateTime.UtcNow.ToString("yyyyMMddHH"), "Respect cycle: respect is " + r.ToString("N0", CultureInfo.InvariantCulture) + ", limits " + S.RespectLow.ToString("N0", CultureInfo.InvariantCulture) + " to " + S.RespectHighNow.ToString("N0", CultureInfo.InvariantCulture) + (Lowering ? " - lowering" : ""));
if (!Lowering) return r >= S.RespectHighNow && StartLowering(r);
if (r > S.RespectLow && RespectUnfinished(S.RespectState)) return StartLowering(r);
if (r > S.RespectLow && S.RespectState.Split('|').Length > 1 && S.RespectState.Split('|')[1] != "1" && DateTime.UtcNow >= stationAgain)
{
stationAgain = DateTime.UtcNow.AddMinutes(15);
Log("Respect cycle: the crew isn't garrisoned yet - trying again");
if (StationCrewLowest(false))
{
S.RespectState = S.RespectState.Split('|')[0] + "|1";
SaveSettings();
}
return true;
}
if (r > S.RespectLow) return false;
RespectBack("respect is " + r.ToString("N0", CultureInfo.InvariantCulture));
return true;
}
bool StartLowering(int respect)
{
bool again = Lowering;
var p = S.RespectState.Split('|');
bool taken = p[0] == "1", stationed = p.Length > 1 && p[1] == "1";
Log("Respect cycle: respect is " + respect.ToString("N0", CultureInfo.InvariantCulture) + (again ? " - finishing the start that was cut off, " : " - ") + "garrisoning the crew and taking out the collection, down to " + S.RespectLow.ToString("N0", CultureInfo.InvariantCulture));
if (!again)
{
S.RespectState = "0|0|s";
SaveSettings();
if (S.Bank && Can(Tab.Bank)) DoBank();
}
if (!stationed)
{
stationed = StationCrewLowest(again);
S.RespectState = "0|" + (stationed ? "1" : "0") + "|s";
SaveSettings();
}
if (!taken)
{
var w = game.WithdrawCollection();
taken = w != null || again;
if (w != null && !w.Out) { Log("Respect cycle: WITHDRAW ALL pressed, but the collection's totals didn't drop (" + w.Before + ")"); game.Snapshot("collection withdraw no change", 60); }
}
S.RespectState = (taken ? "1" : "0") + "|" + (stationed ? "1" : "0");
if (!taken && !stationed)
{
S.RespectState = "";
respectWait = DateTime.UtcNow.AddMinutes(30);
Log("Respect cycle: couldn't garrison or take out the collection - tried again in 30 minutes");
}
SaveSettings();
return true;
}
internal static List<Tuple<string, int, string>> GarrisonPicks(string list, List<string> unknown = null)
{
var got = new List<Tuple<string, int, string>>();
foreach (var e in NeverAttackEntries(list))
{
string c, n;
int no;
if (Game.MatchDistrict(e, out c, out no, out n)) { if (!got.Any(t => t.Item3 == n)) got.Add(Tuple.Create(c, no, n)); }
else if (unknown != null) unknown.Add(e);
if (got.Count == 5) break;
}
return got;
}
bool StationCrewLowest(bool again)
{
string city = null, name = null;
int no = -1;
game.CloseDistrict();
var picks = GarrisonPicks(S.GarrisonPicks);
if (picks.Count > 0)
{
bool opened = false;
foreach (var p in picks)
{
if (game.OpenDistrict(p.Item1, p.Item2, p.Item3)) { city = p.Item1; no = p.Item2; name = p.Item3; opened = true; break; }
if (!game.LastDistrictGone) { game.Snapshot("respect cycle district not opened", 60); return false; }
SayOnce("garrison pick gone " + p.Item3 + " " + DateTime.UtcNow.ToString("yyyyMMddHH"), "Respect cycle: " + p.Item3 + " isn't your family's any more - the next pick");
}
if (!opened)
{
SayOnce("garrison picks gone " + DateTime.UtcNow.ToString("yyyyMMddHH"), "Respect cycle: none of your picked districts is your family's any more - the crew stays with you until you pick a new one");
return false;
}
}
else
{
if (!game.LowestFamilyDistrict(out city, out no, out name))
{
Log("Respect cycle: no district of your family found - the crew stays with you");
return false;
}
if (!game.OpenDistrict(city, no, name)) { game.Snapshot("respect cycle district not opened", 60); return false; }
}
int n = game.StationAllHere();
game.CloseDistrict();
Log("Respect cycle: " + (n > 0 ? "stationed " + n + " henchmen at " + name + " (" + city + ")" : "no henchmen stationed at " + name));
SnapshotOnce("respect cycle crew stationed");
return n > 0 || again;
}
void RespectBack(string why)
{
Log("Respect cycle: " + why + " - putting the collection back and recalling the crew");
var p = S.RespectState.Split('|');
bool taken = p[0] == "1", stationed = p.Length > 1 && p[1] == "1";
if (taken)
{
var d = game.DepositCollection();
bool seen = d != null && (d.Toast != null || (d.After != null && d.Before != null && d.After.Attack > d.Before.Attack));
if (d != null) Log("Respect cycle: DEPOSIT ALL pressed" + (d.Toast != null ? " - \"" + d.Toast.Trim() + "\"" : seen ? "" : ", nothing showed it took"));
if (seen || (d != null && ++depositTries >= 3)) { taken = false; depositTries = 0; }
}
int recalled = game.OpenTab(Tab.Crew) ? game.RecallEveryone() : -1;
if (recalled > 0) Log("Respect cycle: recalled " + recalled + " henchmen");
stationed = recalled < 0;
S.RespectState = taken || stationed ? (taken ? "1" : "0") + "|" + (stationed ? "1" : "0") : "";
SaveSettings();
if (Lowering) { respectWait = DateTime.UtcNow.AddMinutes(2); Log("Respect cycle: not everything went back - tried again in 2 minutes"); }
else { nextCrew = nextEquip = DateTime.UtcNow; Log("Respect cycle: done, back to normal fights"); }
}
}
}