AFK Macro

Idle Mafia Macro/Source/src/BotAnimals.cs

BotAnimals.cs

When the animal gets its turn · 318 lines · 15 KB

using System;
using System.Collections.Generic;
using System.Linq;
namespace IdleMafiaBot
{
sealed partial class Bot
{
DateTime nextAnimals, nextAnimalShop;
int animalFails;
bool AnimalCratesOpen() { return S.Crates && !CratesHeld(DateTime.UtcNow); }
bool AnimalShopOn() { return S.AnimalBuyFood || S.AnimalBuyCrates || AnimalCratesOpen(); }
bool AnimalsDue(DateTime now)
{
return S.Animals && (S.AnimalFeed || S.AnimalTrain || AnimalShopOn()) && now >= nextAnimals && Can(Tab.Safehouse) && !TutorialOn;
}
void DoAnimals(Header h)
{
var now = DateTime.UtcNow;
nextAnimals = now.AddMinutes(20);
bool shopNow = AnimalShopOn() && now >= nextAnimalShop;
double bankedBefore = -1;
if (shopNow && CanWithdraw())
using (var f = game.Capture()) { var hd = game.ReadHeader(f); bankedBefore = hd != null ? hd.Banked : -1; }
if (!game.OpenAnimals())
{
if (++animalFails >= 2) nextAnimals = S.LastLevel >= 10 ? now.AddMinutes(30) : now.AddHours(3);
return;
}
animalFails = 0;
bool took = false;
double spent = -1;
try
{
AnimalCard card = null;
for (int look = 0; look < 3 && (card == null || card.Hunger < 0); look++)
{
if (look > 0) game.Wait(800);
using (var f = game.Capture())
{
var w = game.ReadAnimalsWindow(f);
if (w != null) card = game.ReadAnimalCard(f, w);
}
}
if (card != null && card.None)
{
SayOnce("no animal", "Animals: no animal yet - pick the free one in the game's ANIMALS window; the bot looks again in 3 hours");
nextAnimals = now.AddHours(3);
return;
}
if (card == null || card.Hunger < 0)
{
bool hasOne = S.LastLevel >= 10;
SayOnce("animal card", "Animals: the active animal's card didn't read (no animal yet? the game gives one from level 10) - the bot looks again in " + (hasOne ? "30 minutes" : "3 hours"));
game.Snapshot("animal card not read", 180);
nextAnimals = hasOne ? now.AddMinutes(30) : now.AddHours(3);
return;
}
Info("animal", card.Name.Length > 0 ? card.Name + (card.Level > 0 ? ", level " + card.Level : "") + ", hunger " + card.Hunger + "%" : "");
if (S.AnimalFeed) card = FeedAnimal(card);
if (S.AnimalTrain) TrainAnimal(h, card);
if (shopNow) took = AnimalShop(h, bankedBefore, out spent);
}
finally
{
game.CloseAnimals();
if (took) DepositBack(spent);
}
}
AnimalCard FeedPremium(AnimalCard card)
{
if (card.Hunger < 0 || card.Hunger > 50 || card.Premium <= 0 || !game.AnimalsTab("owned")) return card;
int from = card.Hunger, fed = 0;
for (int i = 0; i < 2; i++)
{
using (var f = game.Capture())
{
var w = game.ReadAnimalsWindow(f);
if (w == null) break;
card = game.ReadAnimalCard(f, w);
}
if (card.Hunger < 0 || card.Hunger > 50 || card.Premium <= 0 || card.FeedPremium == null) break;
int before = card.Hunger, left = card.Premium;
game.PressFeedPremium(card);
game.Snapshot("animal fed premium", 0, true, false);
AnimalCard after = null;
for (int look = 0; look < 4 && (after == null || (after.Hunger <= before && after.Premium == left)); look++)
{
if (look > 0) game.Wait(500);
using (var f = game.Capture())
{
var w = game.ReadAnimalsWindow(f);
if (w != null) after = game.ReadAnimalCard(f, w);
}
}
if (after == null || (after.Hunger <= before && after.Premium == left))
{
Log("Animals: FEED 50% pressed, but the hunger (" + before + "%) and the premium food (" + left + ") didn't change");
game.Snapshot("animal premium feed did nothing", 60);
break;
}
card = after;
fed++;
}
if (fed > 0) Log("Animals: fed " + (card.Name.Length > 0 ? card.Name : "the animal") + " " + fed + " Premium Animal Food (hunger " + from + "% -> " + card.Hunger + "%, " + (card.Premium >= 0 ? card.Premium + " left" : "left not read") + ")");
return card;
}
AnimalCard FeedAnimal(AnimalCard card)
{
if (S.AnimalPremium) card = FeedPremium(card);
if (card.Hunger >= 50) return card;
if (card.Food == 0) { SayOnce("animal no food " + DateTime.UtcNow.DayOfYear, "Animals: " + card.Name + " is hungry (" + card.Hunger + "%) and there's no Animal Food left"); return card; }
if (!game.AnimalsTab("owned")) return card;
int fed = 0, from = card.Hunger;
for (int i = 0; i < 8 && card.Hunger >= 0 && card.Hunger < 80 && card.Food != 0; i++)
{
using (var f = game.Capture())
{
var w = game.ReadAnimalsWindow(f);
if (w == null) break;
card = game.ReadAnimalCard(f, w);
}
if (card.Feed == null) { game.Snapshot("animal feed not found", 60); break; }
if (card.Hunger >= 80) break;
int hungerBefore = card.Hunger, foodBefore = card.Food;
game.PressFeed(card);
if (fed == 0) game.Snapshot("animal fed", 0, true, false);
AnimalCard after = null;
for (int look = 0; look < 4 && (after == null || (after.Hunger <= hungerBefore && after.Food == foodBefore)); look++)
{
if (look > 0) game.Wait(500);
using (var f = game.Capture())
{
var w = game.ReadAnimalsWindow(f);
if (w != null) after = game.ReadAnimalCard(f, w);
}
}
if (after == null || (after.Hunger <= hungerBefore && after.Food == foodBefore))
{
Log("Animals: FEED 10% pressed, but the hunger (" + hungerBefore + "%) and the food (" + foodBefore + ") didn't change");
game.Snapshot("animal feed did nothing", 60);
break;
}
card = after;
fed++;
}
if (fed > 0) Log("Animals: fed " + (card.Name.Length > 0 ? card.Name : "the animal") + " " + fed + " Animal Food (hunger " + from + "% -> " + card.Hunger + "%, " + (card.Food >= 0 ? card.Food + " food left" : "food left not read") + ")");
return card;
}
void TrainAnimal(Header h, AnimalCard card)
{
if (!game.AnimalsTab("training")) { game.Snapshot("animal training tab not opened", 60); return; }
OcrLine train; int energy, used; string rest; bool ready;
AnimalsWindow w;
using (var f = game.Capture()) w = game.ReadAnimalsWindow(f);
if (w == null) return;
ready = game.ReadTraining(w, out train, out energy, out used, out rest);
if (!ready)
{
var m = System.Text.RegularExpressions.Regex.Match(rest ?? "", @"(\d{1,2})\s?[:.]\s?(\d{2})");
int secs = m.Success ? int.Parse(m.Groups[1].Value) * 60 + int.Parse(m.Groups[2].Value) : -1;
if (secs > 0) nextAnimals = DateTime.UtcNow.AddSeconds(Math.Min(secs + 20, 20 * 60 + 20));
return;
}
if (energy <= 0) energy = 10;
if (used < 0) used = 5;
if (card.Hunger >= 0 && card.Hunger - used < 30) { SayOnce("animal train hunger " + DateTime.UtcNow.DayOfYear, "Animals: training waits - the hunger (" + card.Hunger + "%) would drop under 30%"); return; }
int e = h != null ? h.Energy : -1;
using (var f = game.Capture()) { var now = game.ReadHeader(f); if (now != null && now.Energy >= 0) e = now.Energy; }
if (e < energy) { nextAnimals = DateTime.UtcNow.AddMinutes(10); return; }
if (train == null) using (var f = game.Capture()) train = game.FindAnimalTrain(f, w);
if (train == null)
{
SayOnce("animal train " + DateTime.UtcNow.DayOfYear, "Animals: the animal is ready, but TRAIN didn't read (the window read: " + string.Join(" | ", w.Lines.Where(l => l.Box.Y > w.Title.Box.Bottom + 15 * w.H && l.Box.X > w.Area.X + w.Area.Width / 3).Select(l => l.Text)) + ")");
game.Snapshot("animal train not found", 60);
return;
}
game.PressAnimalTrain(train, w);
game.Snapshot("animal trained", 0, true, false);
bool still = true;
for (int look = 0; look < 3 && still; look++)
{
if (look > 0) game.Wait(1000);
using (var f = game.Capture())
{
var after = game.ReadAnimalsWindow(f);
OcrLine t2; int e2, u2; string r2;
still = after != null && game.ReadTraining(after, out t2, out e2, out u2, out r2);
}
}
if (still)
{
Log("Animals: TRAIN pressed, but the animal still shows ready to train");
game.Snapshot("animal train did nothing", 60);
nextAnimals = DateTime.UtcNow.AddMinutes(5);
return;
}
Log("Animals: trained " + (card.Name.Length > 0 ? card.Name : "the animal") + " (" + energy + " energy, " + used + "% hunger)");
nextAnimals = DateTime.UtcNow.AddMinutes(20).AddSeconds(20);
}
bool AnimalShop(Header h, double bankedBefore, out double spent)
{
nextAnimalShop = DateTime.UtcNow.AddHours(1);
spent = 0;
bool took = false;
double tookFloor = 0;
var bought = new List<string>();
var skipped = new HashSet<string>();
for (int round = 0; round < 12; round++)
{
if (!game.AnimalsTab("shop")) { game.Snapshot("animal shop tab not opened", 60); break; }
List<AnimalBuy> buys;
AnimalsWindow w;
double cash, banked;
using (var f = game.Capture())
{
w = game.ReadAnimalsWindow(f);
if (w == null) break;
buys = game.ReadAnimalShop(f, w);
var hd = game.ReadHeader(f);
cash = hd != null ? hd.Cash : -1;
banked = hd != null && CanWithdraw() ? hd.Banked : -1;
}
if (round == 0 && buys.Count == 0) { game.Snapshot("animal shop not read", 60); break; }
double keep = ShopKeep(true);
var want = buys.Where(b => !skipped.Contains(b.Name) && !b.SoldOut && b.Price > 0 && b.Price <= S.AnimalMaxPrice
&& (b.Crate ? S.AnimalBuyCrates : S.AnimalBuyFood)).OrderBy(b => b.Crate ? 1 : 0).ThenBy(b => b.Price).FirstOrDefault();
if (want == null)
{
var open = AnimalCratesOpen() ? buys.FirstOrDefault(b => b.Crate && b.Open != null && b.OpenLit && !skipped.Contains("open " + b.Name)) : null;
if (open == null) break;
game.PressAnimalOpen(open, w);
if (!game.AfterAnimalOpen()) { Log("Animals: opened a " + open.Name + ", but what it showed didn't close - crates wait 6 hours"); nextAnimalShop = DateTime.UtcNow.AddHours(6); break; }
Log("Animals: opened a " + open.Name);
Count.Rewards++;
skipped.Add("open " + open.Name);
continue;
}
if (cash < 0) break;
if (banked < 0 && !took) banked = bankedBefore;
double free = banked >= 0 || !took ? FreeCash(cash, banked, keep) : cash - tookFloor;
if (free < want.Price) { skipped.Add(want.Name); continue; }
if (cash < want.Price)
{
if (took || !CanWithdraw() || BankFee() != 0) { skipped.Add(want.Name); continue; }
game.CloseAnimals();
if (WithdrawKeeping(want.Price, false, want.Price, keep, out tookFloor)) took = true;
else skipped.Add(want.Name);
if (!game.OpenAnimals()) break;
continue;
}
if (!want.BuyLit) { skipped.Add(want.Name); continue; }
game.PressAnimalBuy(want, w);
game.Snapshot("animal shop bought", 0, true, false);
AnimalBuy again = null;
double cashAfter = -1;
bool shop = false;
for (int look = 0; look < 3 && !shop; look++)
{
if (look > 0) game.Wait(900);
using (var f = game.Capture())
{
var w2 = game.ReadAnimalsWindow(f);
if (w2 == null) continue;
var list = game.ReadAnimalShop(f, w2);
shop = list.Count > 0;
again = list.FirstOrDefault(b => b.Name == want.Name);
var hd = game.ReadHeader(f);
cashAfter = hd != null ? hd.Cash : -1;
}
}
if (!shop)
{
Log("Animals: BUY pressed on " + want.Name + ", then a window the bot doesn't know - the animal shop waits 6 hours");
game.Snapshot("animal shop after buy", 60);
nextAnimalShop = DateTime.UtcNow.AddHours(6);
break;
}
bool moved = again == null || again.SoldOut || Math.Abs(again.Price - want.Price) > 0.5 || again.Left != want.Left || (cashAfter >= 0 && cashAfter < cash - want.Price * 0.5);
if (!moved)
{
Log("Animals: BUY pressed on " + want.Name + " for " + M(want.Price) + ", but nothing changed");
game.Snapshot("animal buy did nothing", 60);
skipped.Add(want.Name);
continue;
}
bought.Add(want.Name + " for " + M(want.Price));
if (took) spent += want.Price;
}
if (bought.Count > 0) Log("Animals: bought " + string.Join(", ", bought));
return took;
}
}
}