Вместо предисловия
Сегодня я получил ссылочку на статью на хабре о технологии создания «макроса-бота для браузерной игры». Там же было написано с сожалением, что AutoIT мало представлен на хабре. Со штуками, описанными в статье я баловался год-два назад. В последнее время использую библиотеку IE.au3, которая позволяет творить с браузерными игрушками просто чудеса.Собственно информацией об этом и хотел бы поделиться. Только сразу предупреждаю — речь идет только работе под MS-Internet Explorer. Фанатам других браузеров скажу сразу — можно тоже самое делать наверное под любым браузером, только нужно искать соответствующую библиотеку и как они работают я сказать не могу. Скажу только о библиотеке IE.au3 — она входит в комплект стандартной установки AutoIT-а, достаточно хорошо протестирована, снабжена комментариями и примерами, описанные в ней функции удобно подсвечиваются и предлагаются к завершению при наборе с соответствующими подсказками, как стандартные функции пакета (или как там назвать этот самый AutoIT).Выбор жертвы
В качестве примера работы AutoIT-а с браузерными играми предлагаю игру «Моя деревня» (оригинальное название игры “My Free Farm”) — http://www.mojaderewnja.ru/.Игра реально напрашивается на автоматизацию, потому что заставляет выполнять слишком много рутинных действий. Например, если Вы не будите платить в проект около 180 рублей ежемесячно, то посадку и поливку растений Вам нужно будет делать вручную. А это обычно 120 кликов по полю, только чтобы посадить растения, затем 120 кликов чтобы полить. Полей может быть не один и не два, а до десятка. А некоторые растения растут минут 10, так что такие кликанья либо отбивают желание играть либо заставляют платить за казуальную игрушку ежемесячно сумму, за которую можно иметь месяц скромного интернета или хорошее кабельное телевидение. Так что автоматизировать «Мою деревню» — это просто то, что нам нужно.Выглядит поле для обтыкивания так:
Вариант №1 — примитивный вариант
Ищем на экране куда тыкать, и тыкаем «мышей» куда надо. Сразу скажу – это вариант неправильный, но для общей эрудиции я приведу текст скрипта с пояснениями.Кусок №1: ищем на экране «точку отсчета», за которую можно будет зацепиться и от неё считать местоположение квадратиков куда будем обтыкивать поле.Func GetTopLeftCorner($window)Функция проверяет цвета точек, пробегая по диагонали, ищет левый край окна игры в браузере. Затем просматривает цвета точек, пробегая вверх, ищет верхнюю границу окна игры. Найденную точку я буду считать «точкой отсчета». Расстояние от неё до каждой клетки на поле игры фиксированное и легко вычисляется по индексу.Результат работы функции возвращается в глобальных переменных $x и $y, которые соответствуют координатам точки по горизонтали и вертикали соответственно.При вызове функции в качестве параметра нужно указать заголовок окна программы. Его можно задать вручную, определив предварительно с помощью утилиты AutoIt Window Info, которая устанавливается вместе с AutoIt-ом.Приведенный выше скрипт использует самодельную функцию CheckRGB:
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
Func CheckRGB($color, $min, $max)— Функция проверяет цвет точки, передаваемой в качестве первого параметра $color на то, чтобы она находилась в цветовом диапазоне от $min до $max, с учетом трех составляющих цвета точки (RGB). Возвращает, соответственно True или False.
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
Непосредственно процедура обтыкивания всех клеток на поле выглядит так:
For $i = 1 To 12Тут все понятно. 10 и 12 в заголовках цикла это размер поля в клетках. Константы в параметрах MouseClick вычислены с помощью той же утилиты AutoIt Window Info, относительно определенной ранее «точки отсчета». Значение задержки в Sleep можно менять по своему желанию – это будет влиять на скорость обтыкивания, но слишком быстрое может приводить к ошибкам выполнения скрипта игры.
For $j = 1 To 10
MouseClick("left", $x + ($i * 40) + 103, $y + ($j * 40) + 172, 1, 1)
Sleep(25)
Next
Next
Преимущество этого метода – он работает в любом браузере. Везде где можно открыть окно игры так, чтобы была видна вся пашня.Недостаток – окно игры должно быть всегда открыто, нужно подбирать скорость обтыкивания и во время работы скрипта нельзя трогать мышь (иначе тыкнет не там где надо).
Вариант №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")Вот этот кусок HTML-кода для вставки в предыдущий фрагмент:
If $obj <> 0 Then _
$obj.outerHTML = "… тут кусок HTML кода, который для удобства привожу отдельно “
<SPAN id=anpflanzen class=link onclick="Сам код и скрипты на JavaScript позаимствованы из оригинального HTML кода игры и подгружаемого вместе с ней файла скриптов, и немного переделаны с полива на посадку.
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>