Торговый бот для Diablo 3
15 мая 2012 года вышел очередной шедевр компании Blizzard. Игра из легендарной серии – Diablo 3. Сегодня не будем говорить о самом процессе игры, а поговорим о написании бота. В начале июня 2012 ко мне обратился один мой знакомый с просьбой написать бота для Аукциона. В то время можно было делать неплохие деньги, выискивая вещи по заниженной цене и продавая их.
Изначально я хотел анализировать сетевые пакеты, но быстро понял что идея не выгорит. Установил Delphi, попробовал сделать примитивный кликер в этой среде. Но всё было очень сложно… И тут я вспомнил о программе для автоматизации действий пользователя — AutoIT. Главное, что она умела из коробки: перемещать курсор, кликать, вводить значения… Оставалось научить её распознавать образы с экрана…
Для распознавания образов уже был готов модуль: ImageSearch
.
Почти весь бот построен на вызове функции _ImageSearchArea
, которая ищет в указанной области картинку-шаблон. Пример использования функции:
Local $x, $y $pattern = "img\game\Disconnect.bmp" $result = _ImageSearchArea($pattern, 1, 330, 250, 490, 270, $x, $y, 100) |
Если картинка-образец найдена, то $result будет равен 1, а в $x и $y будут координаты совпадения.
Для удобства работы конечного пользователя было решено вынести настройки в файл конфигурации. Для работы с конфигами есть функция IniRead
. Пример: из файла config.ini
, секции config получить значение параметра ItemsCount
, иначе установить значение 1.
$ItemsCount = IniRead("config.ini", "config", "CanBuyout", "0") |
И сам файл:
[config] ItemsConfig="items.ini" CanBuyout="1" Check2Page="1" CheckManyItems="3" SleepAfterSearch="2" SleepBeforTtansaction="3" Rrepeat="1" |
Для задания параметров покупки вещей использовалась подобная схема. В конфиге задавались все значения искомых предметов, которые и забивались в фильтр
[config] ItemsCount="42" [item1] Class="dh" Type="4" Item="12" lvl1="47" lvl2="60" Qual="6" Stat1="aspd" Val1="7" Stat2="crit_chanse" Val2="3" Stat3="dex" Val3="100" BuyOut="2500000" [item2] Class="dh" Type="4" Item="12" lvl1="47" lvl2="60" Qual="6" Stat1="aspd" Val1="7" Stat2="crit_chanse" Val2="2" Stat3="dex" Val3="70" BuyOut="750000" |
Загрузка данных из конфига предметов осуществлялась в цикле:
; Инициализируем глобальные переменные Global $ItemNum Global $iClass, $iType, $iItem, $ilvl1, $ilvl2, $iQual, $iStat1, $iVal1, $iStat2, $iVal2, $iStat3, $iVal3, $iBuyOut ; бесконечный цикл While 1 = 1 ; перебираем все предметы от первого, до последнего (обычный цикл for) For $ItemNum = 1 To $ItemsCount Step 1 initItem() ; функция для инициализации параметров предмета ; операции по проверке и покупке Next WEnd Func initItem() $config_item = "item" & $ItemNum; $iClass = IniRead($ItemsConfig, $config_item, "Class", "") $iType = IniRead($ItemsConfig, $config_item, "Type", "") ; аналогично заполняются остальные 11 элементов конфига EndFunc |
Заполнение значений в форму поиска аукциона.
Для каждого элемента поиска я создал отдельную функцию. Разберем на примере выбора класса героя.
Func pClass($class) Local $x = 0, $y = 0 $img = "img\class\" & $class & ".bmp" $img_w = "img\class\" & $class & "_w.bmp" ; проверяем, что у нас уже выбрано If Not _ImageSearchArea($img_w, 1, 80, 180, 200, 200, $x, $y, 100) Then ; Раскрываем выпадающий список MouseClick("left", 110, 195, 1, 3) RandSleep() ; Ищем название класса If _ImageSearchArea($img, 1, 75, 200, 220, 480, $x, $y, 100) Then ; Если нашли - щелкаем по нему MouseClick("left", $x, $y, 1, 3) Else FileWrite($file, $img & ": not found " & @CRLF) EndIf EndIf RandSleep() EndFunc |
По своей сути получившийся бот – это комбинация приведенных методов: пытаемся найти… нашли? – кликнули.
При разработке, большую часть времени я потратил на отладку координат и подготовку картинок-шаблонов.
ps. Бот успешно работал на протяжении месяца и принес неплохие барыши своему заказчику.