Как стать автором
Обновить

Боты для браузерных игр на AutoIT

Время на прочтение 6 мин
Количество просмотров 98K

Вместо предисловия

Сегодня я получил ссылочку на статью на хабре о технологии создания «макроса-бота для браузерной игры». Там же было написано с сожалением, что AutoIT мало представлен на хабре. Со штуками, описанными в статье я баловался год-два назад. В последнее время использую библиотеку IE.au3, которая позволяет творить с браузерными игрушками просто чудеса.Собственно информацией об этом и хотел бы поделиться. Только сразу предупреждаю — речь идет только работе под MS-Internet Explorer. Фанатам других браузеров скажу сразу — можно тоже самое делать наверное под любым браузером, только нужно искать соответствующую библиотеку и как они работают я сказать не могу. Скажу только о библиотеке IE.au3 — она входит в комплект стандартной установки AutoIT-а, достаточно хорошо протестирована, снабжена комментариями и примерами, описанные в ней функции удобно подсвечиваются и предлагаются к завершению при наборе с соответствующими подсказками, как стандартные функции пакета (или как там назвать этот самый AutoIT).

Выбор жертвы

В качестве примера работы AutoIT-а с браузерными играми предлагаю игру «Моя деревня» (оригинальное название игры “My Free Farm”) — http://www.mojaderewnja.ru/.Игра реально напрашивается на автоматизацию, потому что заставляет выполнять слишком много рутинных действий. Например, если Вы не будите платить в проект около 180 рублей ежемесячно, то посадку и поливку растений Вам нужно будет делать вручную. А это обычно 120 кликов по полю, только чтобы посадить растения, затем 120 кликов чтобы полить. Полей может быть не один и не два, а до десятка. А некоторые растения растут минут 10, так что такие кликанья либо отбивают желание играть либо заставляют платить за казуальную игрушку ежемесячно сумму, за которую можно иметь месяц скромного интернета или хорошее кабельное телевидение. Так что автоматизировать «Мою деревню» — это просто то, что нам нужно.Выглядит поле для обтыкивания так:
image

Вариант №1 — примитивный вариант

Ищем на экране куда тыкать, и тыкаем «мышей» куда надо. Сразу скажу – это вариант неправильный, но для общей эрудиции я приведу текст скрипта с пояснениями.Кусок №1: ищем на экране «точку отсчета», за которую можно будет зацепиться и от неё считать местоположение квадратиков куда будем обтыкивать поле.
Func GetTopLeftCorner($window)
 Global $x = 0, $y = 0
 WinActivate($window, "")
 If WinActive($window) Then
  $size = WinGetPos("[active]")
  For $i = 1 To $size[3]
   If CheckRGB(PixelGetColor($x + $i, $y + $i), Dec("402215"), Dec("5A352A")) Then
    If CheckRGB(PixelGetColor($x + $i - 259, $y + $i), Dec("331A0D"), Dec("624232")) Then
     For $j = $i To 1 Step -1
      If not CheckRGB(PixelGetColor($i + 1, $j), Dec("000000"), Dec("3A301D")) Then
       $x = $i
       $y = $j
       ExitLoop(2)
      EndIf
     Next
     ExitLoop
    EndIf
   EndIf
  Next
 EndIf
EndFunc
Функция проверяет цвета точек, пробегая по диагонали, ищет левый край окна игры в браузере. Затем просматривает цвета точек, пробегая вверх, ищет верхнюю границу окна игры. Найденную точку я буду считать «точкой отсчета». Расстояние от неё до каждой клетки на поле игры фиксированное и легко вычисляется по индексу.Результат работы функции возвращается в глобальных переменных $x и $y, которые соответствуют координатам точки по горизонтали и вертикали соответственно.При вызове функции в качестве параметра нужно указать заголовок окна программы. Его можно задать вручную, определив предварительно с помощью утилиты AutoIt Window Info, которая устанавливается вместе с AutoIt-ом.Приведенный выше скрипт использует самодельную функцию CheckRGB:
Func CheckRGB($color, $min, $max)
 Local $rgb[3][3]
 $res = True
 $rgb[2][0] = BitAND($min, Dec("FF0000")) / Dec("10000")
 $rgb[1][0] = BitAND($min, Dec("00FF00")) / Dec("100")
 $rgb[0][0] = BitAND($min, Dec("0000FF"))
 $rgb[2][1] = BitAND($color, Dec("FF0000")) / Dec("10000")
 $rgb[1][1] = BitAND($color, Dec("00FF00")) / Dec("100")
 $rgb[0][1] = BitAND($color, Dec("0000FF"))
 $rgb[2][2] = BitAND($max, Dec("FF0000")) / Dec("10000")
 $rgb[1][2] = BitAND($max, Dec("00FF00")) / Dec("100")
 $rgb[0][2] = BitAND($max, Dec("0000FF"))
 For $i = 0 To 2
  If $rgb[$i][0] > $rgb[$i][1] Or $rgb[$i][1] > $rgb[$i][2] Then
   $res = False
   ExitLoop
  EndIf
 Next
 Return $res
EndFunc
— Функция проверяет цвет точки, передаваемой в качестве первого параметра $color на то, чтобы она находилась в цветовом диапазоне от $min до $max, с учетом трех составляющих цвета точки (RGB). Возвращает, соответственно True или False.

Непосредственно процедура обтыкивания всех клеток на поле выглядит так:
For $i = 1 To 12
 For $j = 1 To 10
  MouseClick("left", $x + ($i * 40) + 103, $y + ($j * 40) + 172, 1, 1)
  Sleep(25)
 Next
Next
Тут все понятно. 10 и 12 в заголовках цикла это размер поля в клетках. Константы в параметрах MouseClick вычислены с помощью той же утилиты AutoIt Window Info, относительно определенной ранее «точки отсчета». Значение задержки в Sleep можно менять по своему желанию – это будет влиять на скорость обтыкивания, но слишком быстрое может приводить к ошибкам выполнения скрипта игры.

Преимущество этого метода – он работает в любом браузере. Везде где можно открыть окно игры так, чтобы была видна вся пашня.Недостаток – окно игры должно быть всегда открыто, нужно подбирать скорость обтыкивания и во время работы скрипта нельзя трогать мышь (иначе тыкнет не там где надо).

Вариант №2 — правильный вариант

Мы не используем указатель мыши вообще. Вместо этого, мы тыкаем на нужном объекте, загруженном в браузере IE по его ID. (ID этих клеток можно посмотреть в HTML коде загруженной страницы, они имеют названия f1-f120 соотвественно).
Local $i, $j, $n
Local $oIE = _IEAttach($gamewindowname)
For $i = 1 To 12
 For $j = 0 To 9
  $obj = _IEGetObjById($oIE, "f" & (12 * $j + $i))
  If $obj <> 0 Then $obj.click()
 Next
Next


Вариант №3 — самый правильный вариант

Недостатком предыдущего варианта является то, что когда нам нужно обтыкать поле, нам нужно переключиться из игры и запустить скрипт. Это неудобно. По-настоящему удобный скрипт не должен заставлять выполнять дополнительные действия в целях экономии на других рутинных операциях. Поэтому, я просто заменяю стандартное действие в игре «посадить одну семачку» на «засадить все поле выбранными семенами». Выглядит этот так:
$obj = _IEGetObjById($oIE, "anpflanzen")
If $obj <> 0  Then _
 $obj.outerHTML = "… тут кусок HTML кода, который для удобства привожу отдельно “
Вот этот кусок HTML-кода для вставки в предыдущий фрагмент:
<SPAN id=anpflanzen class=link onclick="
 selectMode(0,true,selected);
 var i, j, s, n = 0;
 for (i = 1; i < 13; i = i + rackElement[selected].x)
  for (j = 0; j < 10; j = j + rackElement[selected].y) {
   s = 12 * j + i; cache_me(" & $zone & ", s, garten_prod[s], garten_kategorie[s], n++);}">

<IMG onmouseover="this.src='http://mff.wavecdn.de/mff/garden_menue_seed.gif'; showDiv('tooltipseed')" onmouseout="this.src='http://mff.wavecdn.de/mff/leer.gif'; hideDiv('tooltipseed')" src="http://mff.wavecdn.de/mff/leer.gif" width=53 height=68>
<DIV style="DISPLAY: none" id=tooltipseed class=blackbox onmouseover="showDiv('tooltipseed')" onmouseout="hideDiv('tooltipseed')" src="http://mff.wavecdn.de/mff/leer.gif">посадить всё</DIV></SPAN>
Сам код и скрипты на JavaScript позаимствованы из оригинального HTML кода игры и подгружаемого вместе с ней файла скриптов, и немного переделаны с полива на посадку.
Теги:
Хабы:
+26
Комментарии 38
Комментарии Комментарии 38

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн