AFK Macro

Idle Mafia Macro/Source/src/Animals.cs

Animals.cs

The animal: feed, train, shop · 484 lines · 26 KB

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text.RegularExpressions;
namespace IdleMafiaBot
{
sealed class AnimalsWindow
{
public OcrLine Title, Owned, Shop, Training;
public Point Close;
public List<OcrLine> Lines = new List<OcrLine>();
public Rectangle Area;
public int H;
}
sealed class AnimalCard
{
public string Name = "", Kind = "";
public int Level = -1, Hunger = -1, Food = -1, Premium = -1;
public bool None;
public OcrLine Feed;
public OcrLine FeedPremium;
public override string ToString()
{
return (Name.Length > 0 ? Name : "the animal") + (Kind.Length > 0 ? " (" + Kind + ")" : "") + (Level > 0 ? " level " + Level : "")
+ ", hunger " + (Hunger >= 0 ? Hunger + "%" : "?") + ", food " + (Food >= 0 ? Food.ToString() : "?");
}
}
sealed class AnimalBuy
{
public string Name;
public bool Crate, SoldOut;
public double Price = -1;
public string Left = "";
public OcrLine Buy, Open;
public bool BuyLit, OpenLit;
public override string ToString() { return Name + " " + (SoldOut ? "sold out" : Price > 0 ? SafehouseInfo.Money(Price) : "price not read") + (Left.Length > 0 ? " (" + Left.ToLowerInvariant() + ")" : ""); }
}
sealed partial class Game
{
static readonly string AnimalsKey = Parse.Key("ANIMALS");
static int SmallNum(string s)
{
return Parse.FirstInt(Regex.Replace(s ?? "", "[OoIl]", m => m.Value == "O" || m.Value == "o" ? "0" : "1"));
}
static readonly string OwnedKey = Parse.Key("OWNED"), ShopTabKey = Parse.Key("ANIMAL SHOP"), TrainingTabKey = Parse.Key("ANIMAL TRAINING");
public AnimalsWindow ReadAnimalsWindow(Frame f)
{
var area = BigPopupArea(f);
int wide = f.Width * 46 / 100;
if (wide > area.Width / 2) area = new Rectangle(f.Width / 2 - wide, area.Y, 2 * wide, area.Height);
int scale = PopupScale(f);
var lines = Ocr.Read(f, area, scale, Prep.None);
var titles = lines.Where(l => Parse.Key(l.Text) == AnimalsKey).OrderBy(l => l.Box.Y).ToList();
if (titles.Count == 0)
{
var tabs = lines.Where(l => { string k = Parse.Key(l.Text); return k == OwnedKey || k == ShopTabKey || k == TrainingTabKey; }).OrderBy(l => l.Box.X).ToList();
var one = tabs.FirstOrDefault(t => tabs.Any(o => Parse.Key(o.Text) != Parse.Key(t.Text) && Math.Abs(o.CenterY - t.CenterY) <= t.Box.Height));
if (one != null)
titles.Add(new OcrLine { Text = "ANIMALS", Box = new Rectangle(one.Box.X, one.Box.Y - 5 * one.Box.Height, 10 * one.Box.Height, 3 * one.Box.Height) });
}
foreach (var title in titles)
{
int h = Math.Max(8, title.Box.Height);
Func<string, OcrLine> tab = key => lines.FirstOrDefault(l => Parse.Key(l.Text) == key && l.Box.Y > title.Box.Bottom && l.Box.Y < title.Box.Bottom + 4 * h);
var w = new AnimalsWindow { Title = title, Owned = tab(OwnedKey), Shop = tab(ShopTabKey), Training = tab(TrainingTabKey), Lines = lines, Area = area };
if ((w.Owned != null ? 1 : 0) + (w.Shop != null ? 1 : 0) + (w.Training != null ? 1 : 0) < 2) continue;
w.H = Math.Max(8, (w.Owned ?? w.Shop ?? w.Training).Box.Height);
var x = lines.Where(l => Regex.IsMatch(l.Text.Trim(), "^[xX×]$") && l.Box.X > title.Box.Right && Math.Abs(l.CenterY - title.CenterY) <= 1.5 * h)
.OrderByDescending(l => l.Box.X).FirstOrDefault();
w.Close = x != null ? new Point(x.CenterX, x.CenterY) : SkillWindowX(f, title, area);
return w;
}
return null;
}
public bool OpenAnimals()
{
using (var f = Capture()) if (ReadAnimalsWindow(f) != null) return true;
if (!OpenTab(Tab.Safehouse)) return false;
ScrollPage(0.5, 15);
Wait(900);
bool pressed = false;
for (int attempt = 0; attempt < 2; attempt++)
{
Point button;
using (var f = Capture()) button = FindAnimalsButton(f);
if (button.IsEmpty) { Wait(1200); continue; }
pressed = true;
Press("ANIMALS", button.X, button.Y, 1200);
for (int look = 0; look < 4; look++)
{
using (var f = Capture()) if (ReadAnimalsWindow(f) != null) return true;
Wait(700);
}
}
NoteFailure(pressed ? "the Animals window didn't open" : "the ANIMALS button didn't read");
Snapshot("animals not opened", 60);
return false;
}
Point FindAnimalsButton(Frame f)
{
var v = ViewOf(f);
int left = v != null && v.Problem == null ? v.PagePoint(0, 0).X : f.Width * 15 / 100;
var page = new Rectangle(left, 0, f.Width - left, f.Height);
int top = f.Height * 35 / 100;
var line = Ocr.Read(f, page, 2, Prep.None).FirstOrDefault(l => Parse.Key(l.Text).EndsWith(AnimalsKey) && Parse.Key(l.Text).Length <= AnimalsKey.Length + 4 && l.CenterY > top);
if (line != null) return new Point(line.CenterX, line.CenterY);
var lower = Rectangle.FromLTRB(left, top, f.Width, f.Height * 80 / 100);
foreach (var t in new[] { Tuple.Create(2, Prep.None), Tuple.Create(1, Prep.None), Tuple.Create(1, Prep.Contrast), Tuple.Create(3, Prep.None), Tuple.Create(2, Prep.Contrast) })
{
var word = Ocr.ReadWords(f, lower, t.Item1, t.Item2).FirstOrDefault(w => { string k = Parse.Key(w.Text); return k.Length >= 6 && k.Length <= AnimalsKey.Length + 2 && (k.EndsWith(AnimalsKey) || View.Distance(k, AnimalsKey) <= 1); });
if (word != null) return new Point(word.Box.X + word.Box.Width / 2, word.Box.Y + word.Box.Height / 2);
}
return Point.Empty;
}
public bool CloseAnimals()
{
int blind = 0;
for (int attempt = 0; attempt < 6; attempt++)
{
AnimalsWindow w;
using (var f = Capture()) w = ReadAnimalsWindow(f);
if (w == null) return true;
if (w.Close.IsEmpty)
{
if (++blind > 3) break;
if (!CloseTerritoryToasts()) Wait(1500);
continue;
}
Click(w.Close.X, w.Close.Y, 900);
}
using (var f = Capture()) if (ReadAnimalsWindow(f) == null) return true;
Snapshot("animals not closed", 60);
return false;
}
public bool AnimalsTab(string which)
{
string key = which == "shop" ? ShopTabKey : which == "training" ? TrainingTabKey : OwnedKey;
for (int attempt = 0; attempt < 3; attempt++)
{
AnimalsWindow w;
using (var f = Capture()) w = ReadAnimalsWindow(f);
if (w == null) return false;
var tab = key == ShopTabKey ? w.Shop : key == TrainingTabKey ? w.Training : w.Owned;
if (tab == null || Parse.Key(tab.Text) != key) { Wait(800); continue; }
NotDisconnected();
if (OnlyNavigate) RefuseInCheck(tab.Text);
Click(tab.CenterX, tab.CenterY, 1100);
using (var f = Capture())
{
var now = ReadAnimalsWindow(f);
if (now == null) return false;
bool shows = key == ShopTabKey ? now.Lines.Any(l => Parse.Has(l.Text, "ANIMAL CRATES") || Parse.Has(l.Text, "ANIMAL FOOD"))
: key == TrainingTabKey ? now.Lines.Any(l => Parse.Has(l.Text, "TRAINING SESSION") || Parse.Has(l.Text, "ENERGY COST"))
: now.Lines.Any(l => Parse.Has(l.Text, "HUNGER"));
if (shows) return true;
}
Wait(800);
}
return false;
}
public AnimalCard ReadAnimalCard(Frame f, AnimalsWindow w)
{
var c = new AnimalCard();
var lines = w.Lines;
c.None = lines.Any(l => Parse.Has(l.Text, "NO ACTIVE ANIMAL") || Parse.Has(l.Text, "NO ANIMALS YET"));
var hunger = lines.FirstOrDefault(l => Parse.Key(l.Text).StartsWith(Parse.Key("HUNGER")) && !Parse.Has(l.Text, "HUNGER USED") && l.Box.Y > w.Title.Box.Bottom + 4 * w.H);
if (hunger != null) c.None = false;
if (c.None && !lines.Any(l => Parse.Has(l.Text, "NO ACTIVE ANIMAL"))
&& lines.Any(l => { string k = Parse.Key(l.Text); return k.StartsWith(Parse.Key("FEED")) || k == Parse.Key("RENAME") || k == Parse.Key("REMOVE") || k.Contains(Parse.Key("PREMIUM FOOD")) || k.Contains(Parse.Key("ACTIVE ANIMAL")); }))
c.None = false;
var kind = lines.FirstOrDefault(l => Regex.IsMatch(l.Text, @"\b(COMMON|UNCOMMON|RARE|EPIC|LEGENDARY|MYTHIC|SECRET|FORBIDDEN|EXOTIC)\b", RegexOptions.IgnoreCase)
&& hunger != null && l.Box.Bottom < hunger.Box.Y && l.Box.Y > hunger.Box.Y - 12 * w.H);
if (kind != null)
{
c.Kind = kind.Text.Trim();
var name = lines.Where(l => l.Box.Bottom <= kind.Box.Y + 2 && l.Box.Y > kind.Box.Y - 4 * w.H && Math.Abs(l.CenterX - kind.CenterX) < kind.Box.Width)
.OrderByDescending(l => l.Box.Y).FirstOrDefault();
if (name != null) c.Name = name.Text.Trim().Trim('"', '\'', '“', '”');
}
var level = lines.FirstOrDefault(l => Regex.IsMatch(l.Text.Trim(), @"^LEVEL\s*[0-9OIl]{1,2}$", RegexOptions.IgnoreCase));
if (level != null) c.Level = SmallNum(Regex.Replace(level.Text, @"(?i)level", ""));
if (hunger != null)
{
c.Hunger = HungerPercent(f, w, hunger, kind);
foreach (var l in lines.Where(l => l.Box.Y > hunger.Box.Bottom && l.Box.Y < hunger.Box.Bottom + 5 * w.H))
{
var t = l.Text.ToUpperInvariant();
var premium = Regex.Match(t, @"PREMIUM\s*F[O0]{2}D\s*([0-9OIl]{1,4})");
if (premium.Success) c.Premium = SmallNum(premium.Groups[1].Value);
var food = Regex.Match(Regex.Replace(t, @"PREMIUM\s*F[O0]{2}D\s*[0-9OIl]{0,4}", ""), @"F[O0]{2}D\s*([0-9OIl]{1,4})");
if (food.Success) c.Food = SmallNum(food.Groups[1].Value);
}
c.Feed = lines.Where(l => Parse.Key(l.Text).StartsWith(Parse.Key("FEED")) && l.Box.Y > hunger.Box.Bottom && l.Box.Y < hunger.Box.Bottom + 8 * w.H
&& !Parse.Key(l.Text).Contains(Parse.Key("50"))).OrderBy(l => l.Box.X).FirstOrDefault();
if (c.Feed != null)
c.FeedPremium = lines.Where(l => Parse.Key(l.Text).StartsWith(Parse.Key("FEED")) && l.Box.X > c.Feed.Box.Right && Math.Abs(l.CenterY - c.Feed.CenterY) <= c.Feed.Box.Height)
.OrderBy(l => l.Box.X).FirstOrDefault();
}
return c;
}
int HungerPercent(Frame f, AnimalsWindow w, OcrLine hunger, OcrLine centre)
{
int h = Math.Max(8, hunger.Box.Height);
int right = centre != null ? 2 * centre.CenterX - hunger.Box.X : hunger.Box.X + 22 * h;
Func<OcrLine, int> pct = l =>
{
var m = Regex.Match(l.Text.Trim(), @"^([0-9OIl]{1,3})\s*(%|o/o|0/0)$", RegexOptions.IgnoreCase);
return m.Success ? SmallNum(m.Groups[1].Value) : -1;
};
var own = w.Lines.FirstOrDefault(l => l != hunger && Math.Abs(l.CenterY - hunger.CenterY) <= 0.7 * h && l.Box.X > hunger.Box.Right && pct(l) >= 0);
if (own != null && pct(own) <= 100) return pct(own);
var row = Rectangle.FromLTRB(hunger.Box.Right + h, hunger.Box.Y - h / 2, Math.Min(f.Width, right + h), hunger.Box.Bottom + h / 2);
foreach (int s in new[] { 3, 4 })
foreach (var prep in new[] { Prep.None, Prep.DarkText })
{
var hit = Ocr.Read(f, row, s, prep).Select(pct).FirstOrDefault(v => v >= 0 && v <= 100);
if (hit > 0 || Ocr.Read(f, row, s, prep).Any(l => pct(l) == 0)) return hit;
}
int y0 = hunger.Box.Bottom + h / 3, y1 = hunger.Box.Bottom + 2 * h;
for (int y = y0; y <= y1 && y < f.Height; y++)
{
int green = 0, x = hunger.Box.X;
for (; x < right && x < f.Width; x++)
{
var c = f.Pixel(x, y);
if (c.G >= 120 && c.G - c.R >= 40 && c.G - c.B >= 40 || EventOrange(c) || c.R >= 150 && c.R - c.G >= 60 && c.R - c.B >= 60) green++;
else if (green > 0) break;
}
if (green >= h) return Math.Max(0, Math.Min(100, (int)Math.Round(100.0 * green / Math.Max(1, right - hunger.Box.X))));
}
return w.Lines.Any(l => Parse.Has(l.Text, "HUNGRY")) ? 0 : -1;
}
public void PressFeed(AnimalCard c)
{
if (c.Feed == null || !Parse.Key(c.Feed.Text).StartsWith(Parse.Key("FEED")) || Parse.Key(c.Feed.Text).Contains(Parse.Key("50")))
throw new NeverPressException(c.Feed == null ? "" : c.Feed.Text, "not the animal's FEED 10%");
Press(c.Feed, 1200);
}
public void PressFeedPremium(AnimalCard c)
{
if (c.FeedPremium == null || c.Premium <= 0 || !Parse.Key(c.FeedPremium.Text).StartsWith(Parse.Key("FEED")))
throw new NeverPressException(c.FeedPremium == null ? "" : c.FeedPremium.Text, "not the animal's FEED 50% with premium food owned");
Press(c.FeedPremium, 1200);
}
public bool ReadTraining(AnimalsWindow w, out OcrLine train, out int energy, out int hungerUsed, out string rest)
{
train = null; energy = hungerUsed = -1; rest = "";
var lines = w.Lines;
var session = lines.FirstOrDefault(l => Parse.Has(l.Text, "TRAINING SESSION"));
Func<string, int> under = label =>
{
var lab = lines.FirstOrDefault(l => Parse.Has(l.Text, label));
if (lab == null) return -1;
int lh = Math.Max(8, lab.Box.Height);
var v = lines.Where(l => l != lab && l.Box.Y > lab.Box.Bottom && l.Box.Y < lab.Box.Bottom + 6 * lh && Math.Abs(l.CenterX - lab.CenterX) < 3 * lh).OrderBy(l => l.Box.Y).FirstOrDefault();
if (v == null) return -1;
var m = Regex.Match(v.Text.Trim(), @"^\+?([0-9OIl]{1,3})\s*(%|o/o|0/0)?$", RegexOptions.IgnoreCase);
return m.Success ? SmallNum(m.Groups[1].Value) : -1;
};
energy = under("ENERGY COST");
hungerUsed = under("HUNGER USED");
bool ready = lines.Any(l => Parse.Has(l.Text, "READY TO TRAIN"));
var timer = lines.FirstOrDefault(l => l.Box.Y > (session != null ? session.Box.Bottom : w.Title.Box.Bottom) && Regex.IsMatch(l.Text, @"\b\d{1,2}\s?[:.]\s?\d{2}\b") && !Parse.Has(l.Text, "ENERGY"));
if (timer != null) rest = timer.Text.Trim();
if (session != null)
train = lines.FirstOrDefault(l => IsTrainButton(l.Text) && l.Box.Y > session.Box.Bottom && l.Box.X > session.Box.X - 2 * w.H);
return ready;
}
static bool IsTrainButton(string text)
{
string k = Parse.Key(text), train = Parse.Key("TRAIN");
return k == train || k.EndsWith(train) && k.Length <= train.Length + 2;
}
public OcrLine FindAnimalTrain(Frame f, AnimalsWindow w)
{
var ready = w.Lines.FirstOrDefault(l => Parse.Has(l.Text, "READY TO TRAIN"));
if (ready == null) return null;
var box = Rectangle.FromLTRB(ready.Box.X - 3 * w.H, ready.Box.Bottom, ready.Box.Right + 3 * w.H, ready.Box.Bottom + 12 * w.H);
box.Intersect(w.Area);
foreach (var t in new[] { Tuple.Create(1, Prep.None), Tuple.Create(2, Prep.None), Tuple.Create(1, Prep.Contrast), Tuple.Create(2, Prep.Contrast), Tuple.Create(1, Prep.DarkText), Tuple.Create(2, Prep.DarkText), Tuple.Create(3, Prep.None) })
{
var word = Ocr.ReadWords(f, box, t.Item1, t.Item2).FirstOrDefault(l => IsTrainButton(l.Text));
if (word != null) return word;
}
return null;
}
public void PressAnimalTrain(OcrLine train, AnimalsWindow w)
{
var session = w.Lines.FirstOrDefault(l => Parse.Has(l.Text, "TRAINING SESSION"));
if (train == null || !IsTrainButton(train.Text) || session == null || train.Box.Y <= session.Box.Bottom || !w.Area.Contains(train.Box))
throw new NeverPressException(train == null ? "" : train.Text, "not the animal's TRAIN");
NotDisconnected();
if (OnlyNavigate) RefuseInCheck(train.Text);
Click(train.CenterX, train.CenterY, 1500);
}
static readonly string BuyKey = Parse.Key("BUY"), OpenKey = Parse.Key("OPEN");
public List<AnimalBuy> ReadAnimalShop(Frame f, AnimalsWindow w)
{
var list = AnimalShopFrom(f, w.Lines, w.H);
if (AnimalShopWhole(list, w.Lines)) return list;
int scale = PopupScale(f);
var merged = w.Lines.ToList();
foreach (var t in new[] { Tuple.Create(scale + 1, Prep.None), Tuple.Create(scale, Prep.Contrast), Tuple.Create(scale + 1, Prep.Contrast), Tuple.Create(Math.Max(1, scale - 1), Prep.None) })
{
var more = Ocr.Read(f, w.Area, t.Item1, t.Item2);
merged.AddRange(more.Where(m => !merged.Any(l => l.Box.IntersectsWith(m.Box))));
foreach (var b in AnimalShopFrom(f, merged, w.H))
{
int i = list.FindIndex(x => Parse.Key(x.Name) == Parse.Key(b.Name));
if (i < 0) list.Add(b);
else if (list[i].Buy == null && b.Buy != null) list[i] = b;
}
if (AnimalShopWhole(list, merged)) break;
}
return list;
}
static bool AnimalShopWhole(List<AnimalBuy> list, List<OcrLine> lines)
{
int crates = lines.Count(l => Parse.Key(l.Text).EndsWith(Parse.Key("ANIMAL CRATE")) && !Parse.Has(l.Text, "EXOTIC"));
return list.Count(b => b.Crate && b.Buy != null) >= Math.Max(2, crates) && list.Any(b => !b.Crate && b.Buy != null);
}
static List<AnimalBuy> AnimalShopFrom(Frame f, List<OcrLine> lines, int h)
{
var list = new List<AnimalBuy>();
foreach (var name in lines.Where(l => Parse.Key(l.Text).EndsWith(Parse.Key("ANIMAL CRATE")) && !Parse.Has(l.Text, "EXOTIC")))
{
int half = 9 * h;
Func<OcrLine, bool> inCard = l => Math.Abs(l.CenterX - name.CenterX) <= half && l.Box.Y > name.Box.Bottom;
var b = new AnimalBuy { Name = name.Text.Trim(), Crate = true };
var priceLine = lines.Where(l => inCard(l) && l.Box.Y < name.Box.Bottom + 6 * h && (Parse.Has(l.Text, "SOLD OUT") || l.Text.Contains("$")))
.OrderBy(l => l.Box.Y).FirstOrDefault()
?? PriceAgain(f, new Rectangle(name.CenterX - 5 * h, name.Box.Bottom + 3 * h, 10 * h, 3 * h));
if (priceLine == null) continue;
if (Regex.IsMatch(priceLine.Text, @"R\s?\$")) continue;
b.SoldOut = Parse.Has(priceLine.Text, "SOLD OUT");
if (!b.SoldOut) b.Price = LastMoney(priceLine.Text);
var left = lines.FirstOrDefault(l => inCard(l) && l.Box.Y > priceLine.Box.Bottom && l.Box.Y < priceLine.Box.Bottom + 2 * h && Parse.Has(l.Text, "LEFT TODAY"));
if (left != null) b.Left = left.Text.Trim();
var foot = lines.Where(l => inCard(l) && l.Box.Y > priceLine.Box.Bottom && l.Box.Y < priceLine.Box.Bottom + 6 * h).ToList();
b.Buy = foot.FirstOrDefault(l => Parse.Key(l.Text) == BuyKey && l.CenterX > name.CenterX);
b.Open = foot.FirstOrDefault(l => Parse.Key(l.Text) == OpenKey && l.CenterX < name.CenterX);
if (b.Buy != null) b.BuyLit = Lit(f, b.Buy);
if (b.Open != null) b.OpenLit = Lit(f, b.Open);
list.Add(b);
}
foreach (var name in lines.Where(l => Parse.Key(l.Text) == Parse.Key("ANIMAL FOOD")))
{
if (!lines.Any(l => Parse.Has(l.Text, "FILLS") && l.Box.Y > name.Box.Bottom && l.Box.Y < name.Box.Bottom + 2 * h && Math.Abs(l.Box.X - name.Box.X) < 2 * h)) continue;
var priceLine = lines.Where(l => l.Box.X > name.Box.Right + 4 * h && Math.Abs(l.CenterY - name.CenterY) <= h && (Parse.Has(l.Text, "SOLD OUT") || l.Text.Contains("$")))
.OrderBy(l => l.Box.X).FirstOrDefault();
if (priceLine == null)
{
var under = lines.Where(l => Parse.Key(l.Text) == BuyKey && l.Box.X > name.Box.Right + 4 * h && l.Box.Y > name.Box.Bottom && l.Box.Y < name.Box.Bottom + 4 * h)
.OrderBy(l => l.Box.Y).FirstOrDefault();
if (under != null) priceLine = PriceAgain(f, new Rectangle(under.CenterX - 6 * h, name.Box.Y - h, 12 * h, name.Box.Height + 2 * h));
}
if (priceLine == null || Regex.IsMatch(priceLine.Text, @"R\s?\$")) continue;
var b = new AnimalBuy { Name = "Animal Food", SoldOut = Parse.Has(priceLine.Text, "SOLD OUT") };
if (!b.SoldOut) b.Price = LastMoney(priceLine.Text);
b.Buy = lines.FirstOrDefault(l => Parse.Key(l.Text) == BuyKey && l.Box.Y > priceLine.Box.Bottom && l.Box.Y < priceLine.Box.Bottom + 4 * h
&& Math.Abs(l.CenterX - priceLine.CenterX) < 6 * h);
if (b.Buy != null) b.BuyLit = Lit(f, b.Buy);
list.Add(b);
break;
}
return list;
}
static OcrLine PriceAgain(Frame f, Rectangle box)
{
box.Intersect(new Rectangle(0, 0, f.Width, f.Height));
if (box.Width < 8 || box.Height < 4) return null;
foreach (var t in new[] { Tuple.Create(3, Prep.None), Tuple.Create(4, Prep.None), Tuple.Create(3, Prep.Contrast), Tuple.Create(2, Prep.None), Tuple.Create(4, Prep.Contrast) })
{
string s = Ocr.ReadText(f, box, t.Item1, t.Item2) ?? "";
if (Parse.Has(s, "SOLD OUT") || Regex.IsMatch(s, @"\$\s*[0-9][0-9,]*(\.[0-9]+)?\s*[KMBT](?![A-Za-z])|\$\s*[0-9][0-9,]*(?![0-9.,A-Za-z])") && LastMoney(s) > 0)
return new OcrLine { Text = s.Trim(), Box = box };
}
return null;
}
static bool Lit(Frame f, OcrLine button)
{
int h = Math.Max(6, button.Box.Height);
var box = Rectangle.FromLTRB(button.Box.X - h, button.Box.Y - h, button.Box.Right + h, button.Box.Bottom + h);
box.Intersect(new Rectangle(0, 0, f.Width, f.Height));
int gold = 0, all = 0;
for (int y = box.Top; y < box.Bottom; y += 2)
for (int x = box.Left; x < box.Right; x += 2)
{
all++;
if (GoldIsh(f, x, y)) gold++;
}
return gold * 100 >= 3 * Math.Max(1, all);
}
public void PressAnimalBuy(AnimalBuy b, AnimalsWindow w)
{
if (b == null || b.Buy == null || Parse.Key(b.Buy.Text) != BuyKey || b.SoldOut || b.Price <= 0 || !w.Area.Contains(b.Buy.Box))
throw new NeverPressException(b == null || b.Buy == null ? "" : b.Buy.Text, "not an animal shop cash BUY");
NotDisconnected();
if (OnlyNavigate) RefuseInCheck(b.Buy.Text);
Click(b.Buy.CenterX, b.Buy.CenterY, 1500);
}
public void PressAnimalOpen(AnimalBuy b, AnimalsWindow w)
{
if (b == null || !b.Crate || b.Open == null || Parse.Key(b.Open.Text) != OpenKey || !w.Area.Contains(b.Open.Box))
throw new NeverPressException(b == null || b.Open == null ? "" : b.Open.Text, "not an animal crate's OPEN");
NotDisconnected();
if (OnlyNavigate) RefuseInCheck(b.Open.Text);
Click(b.Open.CenterX, b.Open.CenterY, 2500);
}
public bool AfterAnimalOpen()
{
var calm = new[] { "CLOSE", "OK", "OKAY", "CONTINUE", "COLLECT", "CLAIM", "NICE", "AWESOME", "TAP TO CONTINUE", "TAP TO CLOSE", "TAP ANYWHERE" }.Select(Parse.Key).ToList();
for (int look = 0; look < 6; look++)
{
Wait(1200);
using (var f = Capture())
{
var w = ReadAnimalsWindow(f);
var lines = Ocr.Read(f, PopupArea(f), PopupScale(f), Prep.None);
if (w != null && lines.Any(l => Parse.Has(l.Text, "ANIMAL CRATES"))) return true;
if (look == 0) Snapshot("animal crate opened", 0, true, false);
var button = lines.FirstOrDefault(l => calm.Contains(Parse.Key(l.Text)));
if (button != null && NeverPress.Why(button.Text) == null) { Press(button, 1200); continue; }
}
}
using (var f = Capture()) if (ReadAnimalsWindow(f) != null) return true;
Snapshot("animal crate window not closed", 60);
return false;
}
}
}