Создание несложного бота для WoW, программирование маршрутов / Хабр

Введение

Прочитал недавно

, в котором автор рассказал о своём боте для торговли на аукционе в игре World of Warcraft. Его персонаж бегал челноком на небольшие расстояния и выполнял конкретные действия, строго заданные в управляющей программе. Воспользовавшись его идеями, я решил пойти немного дальше: пусть персонаж будет способен бегать по маршруту длительностью хотя бы пять минут, при этом должна быть возможность записывать маршрут и выполняемые действия извне, не прибегая к изменению самой программы управления. Описанное мной является развитием

, тем не менее я постарался, чтобы его чтение не было обязательным.


В посте я опишу

  1. Процесс создания тривиального аддона для пользовательского интерфейса WoW на языке Lua
  2. Процесс управления персонажем на языке AutoIt
  3. Программа управления (ро)ботом с командами, понятными непрограммисту

HubSpot

У конструктора чат-ботов HubSpot предусмотрена интеграция с платформами для создания сайтов WordPress и Tilda Publishing. Также поддерживается работа с MailChimp, Bitrix24, Google Analytics и облаком iCloud.

Конструктор HubSpot предлагает отличные возможности для самостоятельного создания чат-бота. В комплекте идут CRM-система, инструменты для работы с клиентами и контентом, сервисы автоматизации продаж и маркетинга в интернет-магазине.

Тарифные планы:

  1. Бесплатный. Доступны элементарные функции конструктора, которые позволяют создать чат-бот и успешно его запустить.
  2. Starter – $45 в месяц. Убираются логотипы HubSpot, добавляются основные функции автоматизации процессов продаж.
  3. Professional – $450 в месяц. Появляются инструменты командной работы, телефонная поддержка, профессиональные инструменты автоматизации.
  4. Enterprise – $1200 в месяц. Пакет создан для больших проектов с персональным обучением до 10 человек и продвинутыми возможностями.

. DialogFlow

Компания Google также не осталась в стороне от рынка чат-ботов, поэтому создала собственный облачный конструктор DialogFlow. На платформе можно создать ботов практически для любых мессенджеров: Google Assistant, Skype, Slack, Telegram и прочих.

DialogFlow поддерживает более 30 языков, а также может распознавать устную речь. Несмотря на широкие возможности, этот конструктор прост в использовании. Создать чат-бота может буквально каждый человек.

Конструктор создан исключительно для общения и не имеет инструментов для активных продаж. Однако, в отличие от конкурентов, он может распознавать устную речь. То есть на основе DialogFlow можно создать даже телефонного чат-бота.

На платформе также реализована возможность подключения живого человека в любой диалог.

Базовая функциональность бота абсолютно бесплатная. Но, например, за каждый запрос на распознавание устной речи придется заплатить. Как таковых тарифных планов у DialogFlow не существует, пользователь платит только за использование облачных ресурсов Google. Сервисы могут оплачиваться поминутно или поштучно.

Каждому новому клиенту при подключении к платному тарифу предоставляется $600, которые можно потратить на подключение и тестирование желаемых функций.

Bluetooth-модуль, датчики и индикатор


Помимо контроллера и колесной платформы нам подарили еще много полезных штук:

  1. Модуль Bluetooth Bee, совместимый с платформой и очень простой в использовании. К контроллеру он подключается через UART, а операционные системы видят его как COM-порт. Наверное, самый простой способ подключить что-то к ПК/смартфону без проводов;
  2. Текстовый экран 8х2. Очень удобно, если робот может показывать какие-то статусные сообщения, тем более, что этот дисплей поддерживает еще и русский алфавит;
  3. Два аналоговых датчика линии для постройки line-tracer’а. В комплекте с ними есть обычные трехжильные кабели для подключения;
  4. Инфракрасный дальномер 10-80см с креплением. На выходе у него напряжение, величина которого зависит от измеренного расстояния;
  5. Два инфракрасных датчика препятствий. На его выходе либо ноль, либо единица в зависимости от выставленного порога срабатывания и измеренного расстояния.

Strela

Платформа

— это Arduino-совместимая плата, полностью подготовленная для строительства роботов. Она разработана компанией Амперка и совмещает в себе практически все, что может понадобиться для быстрой постройки робота. Построена на основе контроллера Atmega32u4 и работать с ней надо, как с Arduino Leonardo. Приехала она нам вот в такой коробочке:

Вообще, Амперка внимательно относится к упаковке. Все их продукты аккуратно упакованы в специально разработанные коробочки. Ориентируются они в первую очередь на довольно юную аудиторию и, я думаю, ребятам приятно получать свои покупки в таком виде, а не завернутые в пупырчатую пленку.

В коробке сама плата:

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

Сама плата с лицевой…

… и с обратной стороны:

Вот основные характеристики платы:Питание

  1. Входное напряжение: 7-24В. От этого же напряжения питается драйвер двигателя;
  2. Встроенный импульсный стабилизатор на 5В, 3А. Сама плата потребляет очень мало, то есть все это можно использовать для питания подключаемых элементов (датчиков, сервоприводов и т.д.);
  3. Линейный стабилизатор на 3,3В для питания модулей связи;
  4. Питание от USB. На Стреле установлен компаратор, который при отключении основного питания автоматически переключается на питание от USB-порта. Нагрузочная способность по 5-ти вольтовому каналу при этом упадет до 500мА, а силовые выходы на двигатели перестанут работать.

Периферия, установленная на плате

  1. Драйвер двигателей L298P;
  2. Пьезоизлучатель без встроенного генератора. Может быть использован для воспроизведения произвольной мелодии
  3. Переключатель RESET. То есть именно переключатель. Он, по сути, служит выключателем платы. Можно отключить плату если поставить внешний тумблер на питание, а можно просто «выключить» микроконтроллер переключателем RESET;
  4. Четыре пользовательских кнопки без фиксации;
  5. Четыре пользовательских светодиода;
  6. Десять индикаторных светодиодов состояния двигателей, питания и линий передачи.

Разъемы для подключения внешних элементов

  1. Две клеммные колодки для подключения двух моторов постоянного тока по 2А, либо одного мощного на 4А, либо одного шагового двигателя;
  2. 12 стандартных трехконтактных PLS-разъемов (GND, 5V, SIG). К ним можно подключать разнообразные датчики, сервоприводы и т.д. Восемь из них могут работать, как аналоговые входы и 4 как PWM-выходы;
  3. Разъем для установки модулей связи. Вся необходимая обвязка уже есть на плате — остается только установить нужный модуль формата XBee;
  4. Разъем для подключения ИК-приемника для управления с пульта по оптическому каналу;
  5. Разъем для подключения жидкокристаллических дисплеев;
  6. Интерфейсы TWI/I2C, SPI, UART.

Надеюсь, читатель простит меня за вольный пересказ. Все характеристики можно найти в

На сегодняшний день роботостроители чаще всего используют модульный принцип. То есть им приходится покупать по отдельности практически все эти функции, а потом соединять их вместе.

Примерно так бы выглядел наш робот, сделанный на шилдах:

Strela включает в себя несколько устройств, которые обычно покупают отдельно — Arduino, шилд с драйвером двигателей, преобразователь напряжения и breadboard для прототипирования. Это основная идея платы и у нее есть две стороны.С одной стороны, если попробовать все эти функции купить в виде раздельных шилдов, то получится намного дороже и больше по размеру.

С другой стороны, если есть конкретный проект, который задуман на Arduino и известны все составляющие системы заранее, то скорее всего можно будет обойтись одним-двумя шилдами и получить выигрыш и в стоимости и в размерах.Мне кажется, что использование платформы будет оправдано в рамках кружка робототехники.

Можно будет постоянно переставлять ее на разных роботов, быстро добавлять функции и т.д. В видеообзоре от Амперки они вообще построили робота, в котором реализовали одновременно чуть-ли не весь функционал. Также Стрела может заинтересовать людей, сведущих в программировании, которым в их проекте понадобилась относительно несложная аппаратная часть.

Подводя итоги этой части, хочется перечислить плюсы и минусы платы. Итак, вот то, что я считаю достоинствами:


А вот то, что лично мне не понравилось:

Вот

эта плата стоит сейчас. Трудно сказать много это или мало. Вполне может оказаться, что при строительстве робота с нуля это дешевле, чем собрать на шилдах. По моему опыту, цена честная. Именно столько и стоит электроника, если разрабатывать ее в России, продавать официально и организовывать масштабную техническую поддержку.

Вперед или назад?


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

(ax, ay)

и смотрит под углом

и ему надо попасть в

(bx, by)

, ему бежать вперед или назад? Для начала слегка перефразируем задачу: пусть персонаж стоит в

(0, 0)

, смотрит в

, а надо ему в

(dx, dy)Создание несложного бота для WoW, программирование маршрутов / Хабр


Если решать задачу в лоб, то надо бы вычислить косинус угла между векторами. Если он положительный, то угол острый и бежать вперед. Если отрицательный — тупой, надо пятиться. Косинус можно вычислять по

Но для этого нам придется вычислять длины каждого из векторов, извлекать корни, очень громоздко.

Есть так же формула скалярного произведения
Создание несложного бота для WoW, программирование маршрутов / Хабр
Которое, как известно, в декартовой системе координат может быть вычислено по формуле
Создание несложного бота для WoW, программирование маршрутов / Хабр
Таким образом, вычислив скалярное произведение и посмотрев на его знак, мы сможем определить, бежать нам вперед или назад. А в нашем случае вычислять мы его будем по формуле Создание несложного бота для WoW, программирование маршрутов / Хабр. Более того, это же самое скалярное произведение показывает нам, сколько именно надо бежать вперед или назад по своему геометрическому определению (проекция одного вектора на другой, помноженная на длину второго).
image

Где создать чат-бота без программирования?

Лучший конструктор чат-ботов можно определить только на практике. Но процесс можно ускорить, если выбирать по конкретным критериям.

Изучите сайт. Если информация кажется неструктурированной, что-то непонятно, не хватает иллюстраций — работать с конструктором тоже может оказаться сложно.

Посмотрите отзывы. Загляните в сервисы отзывов, соцсети конструкторов и видеообзоры. Почитайте, что пишут действующие пользователи. Для надежности можно даже пробить компанию в реестре юридических лиц.

Проверьте функционал. Необязательно сразу платить за конструктор — попробуйте создать бота на бесплатном тарифе. В процессе поймете, достаточно ли удобен инструмент, работает ли с нужной соцсетью или мессенджером. Или лучше попробовать другой вариант.

Оцените техподдержку. Здорово, если у сервиса качественная служба поддержки и к ней можно оперативно обратиться — написать в мессенджер или позвонить. Так будет проще освоить конструктор. О том, как работает поддержка, в том числе можно узнать из отзывов.

Читайте также:  Вдохновитесь трехэтажными загородными домами: идеальное сочетание элегантности и комфорта

Узнайте об интеграциях. Пользователей, с которыми взаимодействует чат-бот, важно собирать в базу: для опросов, email-рассылок или ретаргетинга. Поэтому нужно изучить возможность передачи таких данных.

В подборке я собрала конструкторы, которые поддерживают сразу несколько каналов. Например, можно сделать бота сразу и для ВКонтакте, и для Telegram, и для сайта. Еще у всех сервисов есть понятный визуальный интерфейс, статистика в личном кабинете, бесплатный тариф.

Есть поддержка платформыКонструкторы чат-ботов
ВКонтактеUnibots, BotKits, Aimylogic, Salebot, Botmother, MyBotan, Leadtex
TelegramUnibots, Flow XO, ManyChat, BotKits, Aimylogic, Salebot, Botmother, MyBotan, Leadtex
ViberBotKits, Aimylogic, Salebot, Botmother, Leadtex
Instagram*ManyChat, Aimylogic, Salebot, Botmother, MyBotan
Facebook*Flow XO, ManyChat, BotKits, Aimylogic, Salebot, Botmother
WhatsAppFlow XO, ManyChat, Aimylogic, Salebot, Botmother, Leadtex
Веб-чат для сайтаUnibots, Flow XO, Aimylogic

Движение и позиционирование

Просто записать нажатие и отпускание клавиш, позицию и щелчки мыши не получится. Точнее записать-то получится, только при проигрывании будет происходить совсем не то, что вы ожидали, по следующим причинам:

  1. Вам требуется воспроизвести первоначальное положение персонажа и направление его взгляда. Если вы перед автоматическим забегом повернетесь слегка в другую сторону, вы побежите кривовато и рано или поздно упретесь в стенку
  2. Если вы записали точные координаты и угол, то поставить персонажа туда же вам также не удастся. Реагирует на кнопки он как бульдозер и поворачивается так же. А даже ошибка в 1 градус через 100 метров выльется в Создание несложного бота для WoW, программирование маршрутов / Хабр метра (ширина дверного проема)
  3. Время нажатия и отпускания кнопок тоже далеко от идеала. Это похоже на передвижение по квартире с закрытыми глазами. Вроде бы шесть шагов вперед и строго направо, но на деле вместо туалета мы оказываемся в ванной. Попробуйте также открыть дверь с закрытыми глазами, не щупая ручку

Вот по этим причинам нам необходимо позиционироваться в мире при помощи координат. При этом сверять позицию и вносить коррективы необходимо регулярно, каждые 100 миллисекунд.

move 40.644 20.417 1.537
move 40.526 20.411 1.537
move 40.246 20.408 1.592
move 39.974 20.414 1.592
move 39.691 20.411 1.537
move 39.417 20.388 1.510


Это отрывок из списка команд робота по перемещению. Указаны координаты

xy

и угол поворота в пространстве в радианах.

Запись координат

Ну и, конечно же, наш

Recorder

должен в фоне записывать передвижение персонажа

$hfile = FileOpen("output.txt", 1)
$prev = ""
While true WinWaitActive($hwnd) local $pos = GetPos() $command = StringFormat("move %.3f %.3f %.3f", $pos[0], $pos[1], $pos[2]); if $pos[0] $pos[1] > 0 And $command <> $prev Then FileWriteLine($hfile, $command) EndIf $prev = $command Sleep(100)
WEnd 


Вы можете спросить, зачем так часто (10 раз в секунду) записывать координаты? Дело в том, что на нашем маршруте навалено препятствий: ящиков, углов, дверных проемов, фонарных столбов,

граблей

. А персонаж просто «магнитится» к ним. Если где-то, пробегая мимо, он может застрять, он обязательно сделает это. Даже если вы длительное время бежите по прямой, вспомните, азимут движения был задан не идеально, поэтому, возможно, вы давно бежите, упираясь лбом в стенку.

Полный исходный код Recorder’а

#include <Color.au3>
Global $WinName = "World of Warcraft"
Opt("PixelCoordMode", 2) ;Отсчет координат пикселей от левого верхнего угла клиентской части окна
Opt("MouseCoordMode", 2) ;Отсчет координат мыши от левого верхнего угла клиентской части окна
$paused = false
HotKeySet("{F11}", "Pause")
HotKeySet("{F10}", "Kill")
local $keys = StringSplit("` [ ] 1 2 3 4 5 6 7 8 9 0 !1 !2 !3 !4 !5 !6 !7 !8 !9 !0 1 2 3 4 5 6 7 8 9 0 f {SPACE} {TAB} {ESC} {PAUSE} {DELETE} {BACKSPACE}", " ", 2)
for $i = 0 to UBound($keys)-1 HotKeySet($keys[$i], "OnHotKey")
Next
$hwnd = WinGetHandle($WinName)
$hfile = FileOpen("output.txt", 1)
$prev = ""
While true WinWaitActive($hwnd) local $pos = GetPos() $command = StringFormat("move %.3f %.3f %.3f", $pos[0], $pos[1], $pos[2]); if $pos[0] $pos[1] > 0 And $command <> $prev Then FileWriteLine($hfile, $command) EndIf $prev = $command Sleep(100)
WEnd
Func Pause()	$Paused = NOT $Paused	While $Paused	Sleep(100)	WEnd
EndFunc
Func Kill() FileClose($hfile) Exit
EndFunc
Func GetPitch() $pixel2 = _ColorGetRGB(PixelGetColor(10, 0, $hwnd)); Return ($pixel2[2]/255.0-0.5)*4
EndFunc
Func GetPos() $pixel1 = _ColorGetRGB(PixelGetColor(0, 0, $hwnd)); $pixel2 = _ColorGetRGB(PixelGetColor(10, 0, $hwnd)); local $result[3] = [ ($pixel1[0] $pixel1[1]/255.0)/255*100, ($pixel2[0] $pixel2[1]/255.0)/255*100, $pixel1[2]*7.0/255 ] return $result
EndFunc
Func OnHotKey() ;ToolTip(@HotKeyPressed) HotKeySet(@HotKeyPressed) Send(@HotKeyPressed) HotKeySet(@HotKeyPressed, "OnHotKey") Switch @HotKeyPressed Case "[" FileWriteLine($hfile, "mouse left " & MouseGetPos(0) & " " & MouseGetPos(1)) Case "]" FileWriteLine($hfile, "mouse right " & MouseGetPos(0) & " " & MouseGetPos(1)) Case "{PAUSE}" FileWriteLine($hfile, "pause 1000") Case "{BACKSPACE}" FileWriteLine($hfile, StringFormat("pitch %.2f", GetPitch())) Case Else FileWriteLine($hfile, "key " & @HotKeyPressed) EndSwitch
EndFunc

Как добавить лайки и сделать отложенный постинг в telegram-канал

Сделайте созданного бота админом вашего канала:

Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр

Первое, что вы увидите — сообщение с описанием возможностей этого бота.

Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр

Мы выбрали «Опубликовать». Вот, что получилось:

Создание несложного бота для WoW, программирование маршрутов / Хабр

Как сделать опрос в telegram

Для того, чтобы сделать опрос в Телеграм, находим бота @vote:

Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр

По окончанию, отправляем боту сигнал о завершении настроек в виде команды /done

Создание несложного бота для WoW, программирование маршрутов / Хабр

Еще один способ добавить реакции к посту

Telegram бот @like

Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр

Пост готов.

Несколько полезных команд для вашего бота

Создание несложного бота для WoW, программирование маршрутов / Хабр

Как сделать опрос в telegram

Для того, чтобы сделать опрос в Телеграм, находим бота @vote:

Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр

По окончанию, отправляем боту сигнал о завершении настроек в виде команды /done

Создание несложного бота для WoW, программирование маршрутов / Хабр

Еще один способ добавить реакции к посту

Telegram бот @like

Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр
Создание несложного бота для WoW, программирование маршрутов / Хабр

Пост готов.

Несколько полезных команд для вашего бота

Создание несложного бота для WoW, программирование маршрутов / Хабр

Как  сделать своего чат-бота для учебы без знаний в  программировании

Добрый день, дорогие друзья. Данный пост ни в коем случае не реклама сервиса или каких-то услуг в нём, а просто рассказ о том как я немного облегчил себе жизнь при помощи чат-бота в VK.

В процессе учёбы у меня очень часто возникала необходимость пользоваться одними и теми-же учебными материалами в электронном виде (учебники, методички, лабораторные работы и т.д.). И всё время была проблема как их хранить, чтобы и места не занимали и были под рукой и чтобы в случае чего можно было получить доступ в определённой группе материалов без необходимости пролистывать огромные списки файлов.

После нескольких недель попыток использования различных облачных хранилищ, в голову пришла идея сделать чат бота для вк, поскольку в основном все сидят там и переключатся на какие-то сторонние приложения не очень удобно.

И в результате всего 20 минут абсолютно без знания языков программирования и специальных навыков удалось создать бота в сообществе группы, который умеет:

— выдавать необходимые материалы по предмету по ключевому запросу ( напишите «физиология» он вам отправит материалы по предмету «Физиология человека» и т.д. )

— отправлять актуальное расписание
— отправлять случайный ответ в форме (да/нет)  на запрос «идти ли сегодня на пары?»

и т.д.

1) Необходимо авторизоваться на сайте (лучше сразу зайти через VK, чтобы сайт получил доступ к группам в которых вы имеете права администратора).

2) Вам необходимо создать стартовый шаблон для бота, нажмите на большую синюю кнопку » » и выберите в меню пункт «стартовый шаблон» и «добавить»

3) Cтартовый шаблон подключен, теперь необходимо привязать его к какому-либо сообществу.

4) Далее на главной панели у нас появится плитка с добавленным ботом. Переходим в её настройки и видим основное меню настройки бота.

5) В этом меню вы можете настроить основные функции бота (приветствие на подписку/отписку и т.д), а так-же реакцию на неизвестные команды, однако нас это не интересует и мы переходим во вкладку «Сценарий» , чтобы создать свои команды для использования.

6) В этой вкладке мы может создавать и редактировать команды для бота и создавать свои сценарии. Для того, чтобы создать команду нажимаем на большую красную синюю кнопку.

7) В первом пустом поле мы пишем команду или команды (через запятую) и выбираем тип того, как будет интерпретироваться ввод (только по ключевому слово, или отдельной фразе), а во втором поле мы добавляем ответ, который нам пришлёт бот.

8) Готовый сценарий выглядит так. В настройках можно добавить возможность прикрепления различных документов и фотографий, а так-же различные команды вроде (часы работы, время, дата, имя пользователя и т.д.)

9) Теперь пишем в сообщения группы необходимую нам команду, и бот ответит нам согласно сценарию.

10) Получается очень удобно, сообщение с информацией можно тут-же переслать коллегам или одногруппникам сразу в VK. При помощи бота, можно оптимизировать свою работу с файлами, расписаниями и т.д.

Спасибо большое за то, что дочитали мой пост.

P.S. Я не программист, конечно же наверное есть способы сделать всё намного проще и удобнее, но я просто поделился своим опытом, надеюсь он кому-то будет полезен.

Коллекционирование

Люди, далекие от индустрии игр, могут без ущерба пропустить этот раздел. В игре WoW есть такой аспект — коллекционирование. Как и в нумизматике/филателии, чем больше у вас, например, верховых животных, тем вам приятнее. Точно так же важен процесс получения.

Какие-то драконы требуют для получения выполнения десятка задач («ачивок»), какие-то — войти в лучшие 2% игроков в мире по навыку управления персонажем (сражения на арене), что-то можно просто купить за игровую валюту, что-то — за реальные деньги в магазине. Подробности можно почитать в

, речь не об этом. Так вот, некоторые из коллекционируемых предметов падают в подземелье с шансом около 0,5%. Если шанс выпадения дается игроку лишь раз в день (иногда в неделю), вам потребуется время, соизмеримое с годом, для забегов. И все ради того мгновения получения заветного выстраданного предмета. Чем больше вы потратили времени и сил на «

» предмета, тем приятнее вам его в итоге получить. По моему опыту радость очень мимолетна.

Логирование клавиш


Читал я где-то, что автор языка

AutoIt

не хотел, чтобы такой простой и мощный язык использовался злоумышленниками для написания вредоносных программ. Поэтому он убрал возможность создать обработчик нажатия для всех клавиш сразу, чтобы хотя бы

не клепали.

Что я могу сказать. AutoIt весьма активно используется для написания вредоносов, а перехват нажатия нужных клавиш мы будем делать так:

local $keys = StringSplit("` [ ] 1 2 3 4 5 6 7 8 9 0 !1 !2 !3 !4 !5 !6 !7 !8 !9 !0 1 2 3 4 5 6 7 8 9 0 f {SPACE} {TAB} {ESC} {PAUSE} {DELETE} {BACKSPACE}", " ", 2)
for $i = 0 to UBound($keys)-1 HotKeySet($keys[$i], "OnHotKey")
Next
Func OnHotKey() ;ToolTip(@HotKeyPressed) HotKeySet(@HotKeyPressed) Send(@HotKeyPressed) HotKeySet(@HotKeyPressed, "OnHotKey") Switch @HotKeyPressed Case "[" FileWriteLine($hfile, "mouse left " & MouseGetPos(0) & " " & MouseGetPos(1)) Case "]" FileWriteLine($hfile, "mouse right " & MouseGetPos(0) & " " & MouseGetPos(1)) Case "{PAUSE}" FileWriteLine($hfile, "pause 1000") Case "{BACKSPACE}" FileWriteLine($hfile, StringFormat("pitch %.2f", GetPitch())) Case Else FileWriteLine($hfile, "key " & @HotKeyPressed) EndSwitch
EndFunc


Таким образом, нам не нужно изобретать свою систему наименования клавиш для сохранения их в файл, достаточно использовать

Читайте также:  Тишина и спокойствие: обеспечьте идеальную звукоизоляцию с помощью звукоизоляции потолка

Если нам понадобится перехватить что-то еще (а при игре мы заранее знаем, что мы будем давить и какими заклинаниями пользоваться), мы просто добавим их в длинный список в начале.

Перехватив нажатие клавиши, нам надо послать его дальше в приложение, для этого мы временно убираем свой обработчик

HotKeySet(@HotKeyPressed)
Send(@HotKeyPressed)
HotKeySet(@HotKeyPressed, "OnHotKey")


Такой подход рекомендуется в справке, но на практике при нажатии на комбинации с

Alt

и другие ощутимо глючит. Я не стал разбираться, а просто избегал использования таких комбинаций.

Логирование мыши

AutoIt

нет штатного способа перехвата нажатий кнопок мыши. Есть сторонний модуль с

. Или вы можете повесить свой

SetWindowsHookEx (WH_MOUSE_LL)

. Познавательный пример использования

WinAPI Callback

-функций на

AutoIt

. Но я не использовал такой подход по двум причинам:

  1. Передвижение персонажа сопряжено с большим количеством нажатий мыши, которые логировать не надо. Плюс, возможны случайные нажатия. Пришлось бы писать логику по отделению мух от котлет.
  2. Использование Hook’ов повышает шансы привлечения к вам внимания «спецслужб». Об этом подробнее в разделе «Противодействие ботам».


Поэтому, как вы уже заметили, я всего лишь использовал кнопки »

[

» и »

]

» и давил их по мере необходимости. Главное, не забывать нажимать их.

Манифест и gui

. В папке

World of WarcraftInterfaceAddOns

создаете папку

HelloWorld

. В нее кладете

HelloWorld.toc

с содержимым

## Interface: 50001
## Title: Hello, World!
## Notes: My first AddOn
HelloWorld.lua


Если бы я хотел понарисовать формочек и кнопочек (а для этого обычно и нужны аддоны), последней строчкой я бы вписал еще

HelloWorld.xml

с описанием этих кнопочек. В дизайне и написании такого GUI-аддона хорошо помогает

. Мощный инструмент на базе MS Visual Studio.

Но так как я минималист, рисовать мы в этот раз не будем. Кроме того, это даст мне возможность показать, что создавать формы можно динамически из самого скрипта без использования дизайнера. Рассмотрим же HelloWorld.lua. Редактировал я его в Notepad .

Чтобы игра подключила изменения в HelloWorld.toc, надо перезапустить ее целиком. А вот изменения в HelloWorld.lua можно подхватить, написав в консоли команду /reload. Поэтому процесс программирования и отладки не такой болезненный.

Модули

Таким образом, у нас вырисовываются части

программно-аппаратного комплекса

бота:

  1. Мы напишем addon для интерфейса WoW, который будет определять позицию персонажа, азимут, наклон. Правилами игры аддоны ничуть не запрещены, указанная информация доступна через игровое API внутри аддона. Он будет рисовать это все на экране. Сам аддон пишется на языке Lua, потому что так решили разработчики игры.
  2. В аддоне можно определять кое-что, можно рисовать, но вот заставить персонажа двигаться нельзя. Еще в аддоне нельзя писать в файл, спрашивать у игры, где стены, где враги, да и много чего еще нельзя. Поэтому нам нужно написать внешнее управляющее приложение. Я не стал оригинальничать и использовал AutoIt. Это действительно быстро и удобно, хоть и немного дико для меня, привыкшего программировать на строго типизированных языках.
  3. Записанные действия и координаты мы будем хранить в текстовом файле построчно. Их можно и нужно редактировать вручную. Добавлять костыли, удалять мусор. Скажу сразу, это самое сложное.

Обработчик событий

Система работы с GUI в аддоне похожа на работу Windows со своими сообщениями и их обработкой.

local EventFrame = CreateFrame("Frame")
function EventFrame:OnEvent(event, ...)	print("HelloWorld:", event)	self[event](self, ...)
end
EventFrame:SetScript("OnEvent", EventFrame.OnEvent)
EventFrame:RegisterEvent("PLAYER_LOGIN")
function EventFrame:PLAYER_LOGIN() -- Инициализация тут
end
function EventFrame:OnUpdate() -- Полезные действия тут
end
EventFrame:SetScript("OnUpdate", EventFrame.OnUpdate)


Мы создаем фрейм типа »

Frame

» и подключаемся на действия »

OnEvent

» и »

OnUpdate

» командами

EventFrame:SetScript("OnEvent", EventFrame.OnEvent)
EventFrame:SetScript("OnUpdate", EventFrame.OnUpdate)


Обработчик

OnUpdate

будет вызываться после каждого кадра — то, что нам нужно для обновления координат. А

OnEvent

будет вызываться при других желаемых событиях. Из него будем дергать соответствующие функции:

self[event](self, ...)

Что еще удобнее в Lua, это то, что вот такой конструкцией можно вызвать уникальные обработчики вида

function EventFrame:PLAYER_LOGIN() 


Здесь

PLAYER_LOGIN

— это событие, которое рассылается во все фреймы при входе в мир и перезапуске пользовательского интерфейса. Другие события:

PLAYER_LEAVE_COMBATQUEST_FINISHEDPLAYER_EQUIPMENT_CHANGEDPLAYER_DEAD

, — и еще очень много. С полным списком можно ознакомиться

. Зарегистрируем то событие, которое мы хотим обрабатывать, командой

EventFrame:RegisterEvent("PLAYER_LOGIN")

Остановка


Теперь мы готовы давить кнопки бега

Func Move($want) while true StartMoving() local $pos = GetPos() local $dir = GetDirection($pos[0], $pos[1], $want[0], $want[1], $pos[2]) ;ToolTip(StringFormat("(%.2f,%.2f,%.2f) to (%.2f,%.2f, %.2f): (%.2f,%.2f)", $pos[0], $pos[1], $pos[2], $want[0], $want[1], $want[2], $dir[0], $dir[1])) if abs($dir[0]) < 0.1 And abs($dir[1]) < 0.1 then ExitLoop if abs($dir[0]) >= abs($dir[1]) Then Send("{a up}{d up}") if $dir[0] <=0 Then	Send("{w down}{s up}") ; forward Else	Send("{s down}{w up}") ; backward EndIf Else Send("{s up}") if $dir[1] < 0 Then	Send("{d down}{a up}") ; right Else	Send("{a down}{d up}") ; left EndIf EndIf wend Send("{s up}{a up}{d up}")
EndFunc

Обратите внимание, мы идем в том направлении, в котором идти дальше всего, и заканчиваем путь, когда мы почти у цели. Это позволяет персонажу «не мельтешить». Кнопка движения вперед не отпускается по достижении точки назначения. Поэтому поворачиваться на требуемый угол нам надо сравнительно быстро.

Код, отвечающий за проигрывание файлов команд, не представляет из себя ничего интересного, и при желании вы можете ознакомиться с ним самостоятельно.

Полный исходный код Player’а

#include <Color.au3>
Global $WinName = "World of Warcraft"
Opt("PixelCoordMode", 2) ;Отсчет координат пикселей от левого верхнего угла клиентской части окна
Opt("MouseCoordMode", 2) ;Отсчет координат мыши от левого верхнего угла клиентской части окна
$paused = false
$moving = false
HotKeySet("{F11}", "Pause")
HotKeySet("{F10}", "Kill")
;WinActivate($WinName)
$hwnd = WinGetHandle($WinName)
WinWaitActive($hwnd)
PlayFile("outdoor.txt", 0)
PlayFile("indoor.txt", 0)
PlayFile("outdoor.txt", 0)
PlayFile("indoor.txt", 0)
PlayFile("outdoor.txt", 0)
PlayFile("indoor.txt", 0)
PlayFile("outdoor.txt", 0)
PlayFile("indoor.txt", 0)
PlayFile("outdoor.txt", 0)
PlayFile("indoor.txt", 0)
Func PlayLine($line) local $command = StringSplit($line, " ", 2) ;ToolTip(StringFormat("%s %s %s", $command[0], $command[1], $command[2])) Switch $command[0] Case "move" local $want[3] = [ number($command[1]), number($command[2]), number($command[3]) ] Move($want) Turn($want) Case "pause" StopMoving() Sleep($command[1]) Case "key" If $command[1] = "{SPACE}" Then	Send("{SPACE down}")	Sleep(300)	Send("{SPACE up}") Else	StopMoving()	if UBound($command) > 2 Then Send($command[1] & " " & $command[2])	Else Send($command[1])	EndIf	Sleep(1500) EndIf Case "mouse" StopMoving() MouseClick($command[1], $command[2], $command[3]) Sleep(500) Case "pitch" SetPitch($command[1]) EndSwitch
EndFunc
Func PlayFile($filename, $skip = 0) $hfile = FileOpen($filename, 0) For $i = 1 to $skip $line = FileReadLine($hfile) Next while True $line = FileReadLine($hfile) if @error = -1 Then ExitLoop PlayLine($line) wend FileClose($hfile) StopMoving()
EndFunc
Func Sign($x)	if ($x < 0) then	return -1	else	return 1	EndIf
EndFunc
Func ScalarMult($a, $b, $x, $y)	return $a*$x $b*$y
EndFunc
Func VectorMult($a, $b, $x, $y)	return $a*$y - $b*$x
EndFunc
Func StartMoving()	if $moving then return	$moving = true;	WinWaitActive($hwnd)	MouseMove(@DesktopWidth/2, @DesktopHeight/2, 0)	MouseDown("right")	Sleep(300)
EndFunc
Func StopMoving()	$moving = false	Send("{w up}{s up}{a up}{d up}")	MouseUp("right")	Sleep(300)
EndFunc
Func GetPitch() StartMoving() $pixel2 = _ColorGetRGB(PixelGetColor(10, 0, $hwnd)); Return ($pixel2[2]/255.0-0.5)*4
EndFunc
Func GetPos() StartMoving() $pixel1 = _ColorGetRGB(PixelGetColor(0, 0, $hwnd)); $pixel2 = _ColorGetRGB(PixelGetColor(10, 0, $hwnd)); local $result[3] = [ ($pixel1[0] $pixel1[1]/255.0)/255*100, ($pixel2[0] $pixel2[1]/255.0)/255*100, $pixel1[2]*7.0/255 ] return $result
EndFunc
Func GetDirection($x, $y, $wx, $wy, $angle) $dx = $x - $wx $dy = $y - $wy local $result[2] = [ ScalarMult(-sin($angle), -cos($angle), $dx, $dy), VectorMult(-sin($angle), -cos($angle), $dx, $dy) ] Return $result
EndFunc
Func Move($want) while true local $pos = GetPos() local $dir = GetDirection($pos[0], $pos[1], $want[0], $want[1], $pos[2]) ToolTip(StringFormat("(%.2f,%.2f,%.2f) to (%.2f,%.2f, %.2f): (%.2f,%.2f)", $pos[0], $pos[1], $pos[2], $want[0], $want[1], $want[2], $dir[0], $dir[1])) if abs($dir[0]) < 0.1 And abs($dir[1]) < 0.1 then ExitLoop if abs($dir[0]) >= abs($dir[1]) Then Send("{a up}{d up}") if $dir[0] <=0 Then	Send("{w down}{s up}") ; forward Else	Send("{s down}{w up}") ; backward EndIf Else Send("{s up}") if $dir[1] < 0 Then	Send("{d down}{a up}") ; right Else	Send("{a down}{d up}") ; left EndIf EndIf wend Send("{s up}{a up}{d up}")
EndFunc
Func Turn($want)	while true	local $current = GetPos()	$sin = sin($current[2] - $want[2])	;ToolTip(StringFormat("(%.2f,%.2f,%.2f) to (%.2f,%.2f,%.2f)", $current[0], $current[1], $sin, $want[0], $want[1], $want[2]))	if abs($sin) < 0.05 then return	MouseMove(MouseGetPos(0) 50*$sin, MouseGetPos(1), 1) wend
EndFunc
Func SetPitch($want)	while true	$current = GetPitch()	$sin = sin($current - $want)	;ToolTip(StringFormat("pitch %.2f to %.2f: %.2f", $current, $want, $sin))	if abs($sin) < 0.05 then return	MouseMove(MouseGetPos(0), MouseGetPos(1) 50*$sin, 1)	wend
EndFunc
Func Pause()	$paused = not $paused	if $paused then StopMoving()	While $Paused	Sleep(1000)	WEnd
EndFunc
Func Kill()	StopMoving()	Exit
EndFunc

Поворот и наклон

Поворот и наклон при помощи нажатия на кнопки дает точность порядка 30 градусов, что неприемлемо для нашей задачи. Поэтому мы будем использовать для этого вторую возможность: движение мыши с зажатой правой кнопкой. Алгоритм следующий:

  1. Зажмем правую кнопку мыши
  2. Игра сама поместит курсор на центр экрана и будет удерживать его там. Это позволит пользователю не упереться в итоге курсором в край экрана при повороте
  3. Сдвигаем курсор налево или направо на определенное число пикселей
  4. Направление персонажа смещается налево или направо. Причем, чем быстрее вы двигаете курсор, тем быстрее вертится персонаж


Как нам попроще определить, в какую сторону выгоднее поворачиваться, если у нас есть два угла: текущий и требуемый?

Создание несложного бота для WoW, программирование маршрутов / Хабр

Можно посмотреть на разницу углов, если она положительна — направо. Но рассмотрим случай: текущий угол — 30 градусов, требуемый — 330 градусов. Разница отрицательна, но нам все равно направо. А еще углы могут быть отрицательными. Чтобы не приходилось выписывать все эти условия, просто воспользуемся синусом разницы углов и будем смотреть только на его знак.

Переменные $want и $current содержат (x, y, azimuth)

Func Turn($want)	while true	$current = GetPos()	$sin = sin($current[2] - $want[2])	;ToolTip(StringFormat("(%.2f,%.2f,%.2f) to (%.2f,%.2f,%.2f)", $current[0], $current[1], $sin, $want[0], $want[1], $want[2]))	if abs($sin) < 0.05 then return	MouseMove(MouseGetPos(0) 50*$sin, MouseGetPos(1), 1) wend
EndFunc


Синус же позволяет нам регулировать скорость поворота. Чем меньше угол, тем аккуратнее будет двигаться наш курсор и тем точнее мы повернемся. И наоборот, на большие углы нам хочется поворачиваться побыстрее.

Функция изменения наклона к горизонту полностью аналогична, только сдвигать курсор надо по вертикали.

В приведенном примере кода, есть логическая ошибка, которая может привести к неправильному поведению бота. Предлагаю любопытному читателю самому ее найти.

Получение координат

Напомню, что в аддоне мы клали в цветовые компоненты пикселей числа с плавающей запятой, а приезжают они к нам уже в виде целых байтов:

#include <Color.au3>
Opt("PixelCoordMode", 2) ;Отсчет координат пикселей от левого верхнего угла клиентской части окна
Opt("MouseCoordMode", 2) ;Отсчет координат мыши от левого верхнего угла клиентской части окна
$WinName = "World of Warcraft"
$hwnd = WinGetHandle($WinName)
Func GetPitch() $pixel2 = _ColorGetRGB(PixelGetColor(10, 0, $hwnd)); Return ($pixel2[2]/255.0-0.5)*4
EndFunc
Func GetPos() $pixel1 = _ColorGetRGB(PixelGetColor(0, 0, $hwnd)); $pixel2 = _ColorGetRGB(PixelGetColor(10, 0, $hwnd)); $result[3] = [ ($pixel1[0] $pixel1[1]/255.0)/255*100, ($pixel2[0] $pixel2[1]/255.0)/255*100, $pixel1[2]*7.0/255 ] return $result
EndFunc 


Считав данные, мы производим с ними обратные преобразования. Функции возвращают массивы и массивы записываются в переменные абсолютно прозрачно для программиста.

Читайте также:  Сарай для нутрий своими руками фото

Предыстория

Я преподаю специальные дисциплины в радиотехническом колледже и в свободное время занимаюсь со студентами проектной деятельностью. Это нельзя назвать кружком в привычном понимании этого слова. У меня просто есть группа молодых людей, которые индивидуально или в очень маленьких группах работают над тем что им нравится.

На основном месте работы я профессионально занимаюсь разработкой электроники и имею большой опыт работы над настоящими железными проектами. Я могу высказать свои впечатления не только как учитель, но и как инженер.Когда мне предложили попробовать использовать в своей работе Стрелу и поделиться полученным опытом я, кончено, сразу согласился.

Итак, перейдем к описанию комплектующих.

Противодействие ботам

Создание несложного бота для WoW, программирование маршрутов / Хабр


Люди, далекие от

, спросят: «А зачем вообще противодействовать ботам? Ведь автоматизация везде приветствуется.» А вот и нет. Если все

, то и возможности должны быть равными. Иначе ущемленная часть обижается и перестает играть. Если в игре доступны, например, макросы, то они должны быть понятны и не программистам. Поэтому разработчик игры запрещает использование средств автоматизации на уровне лицензионного соглашения и следит.

Я нередко встречал возгласы, что Blizzard (это разработчик WoW) плохо следит, и боты повсюду. Во-первых, сам я так не считаю, думаю, их доля преувеличена. А во-вторых, давайте обсудим, что же есть в арсенале разработчика. Как не только распознать бота, но еще и иметь подтверждающие факты. Ведь на основе подозрений невежливо банить игрока.

Например, гейм-мастер (внутриигровая поддержка) способен наблюдать за игроком и видеть его глазами. Но даже, увидев явно «нечеловеческое» поведение, как то: длительное вращение на месте, попытки пройти сквозь стену, беспрерывная игра в течение суток (обычно сбор ресурсов), игнорирование попыток общения других игроков, — все это не дает гарантий использования ботов. Быть может, игрок просто заснул на клавиатуре, очень целеустремлен, или просто не хочет общаться, когда «работает».

Поэтому у Blizzard есть Warden. ПО по сути напоминает облачный антивирус:

  1. фоновые программы анализируются
  2. их метаданные отправляются в облако
  3. чит-аналитики принимают решение, что такой-то процесс нечестно взаимодействует с игрой
  4. к пользователям, использовавшим эти программы, применяются санкции

Есть

, что игроков банили за запуск игры из-под

Blizzard

возможность бана за использование программируемых клавиатур и мышек.

Давайте подумаем, что же надо делать, чтобы как можно быстрее привлечь к себе внимание и попасть под подозрение:

  1. Нужно читать, а главное, писать в память процесса игры
  2. Нужно инжектить туда свои модули
  3. Ваше ПО для получения преимуществ в игре должно быть как можно более популярным
  4. Вам надо использовать руткит-технологии и полиморфизм для обхода систем защиты

И вот тогда рано или поздно придет ban-wave для всех пользователей этого ПО.

Что же касается посылки нажатия клавиш и языка

AutoIt

, то по всей видимости, его запущенный интерпретатор слишком распространен среди игроков и используется также для «мирных» целей. В итоге отличить ботоводов от офисных автоматизаторов труда

Blizzard

не могут, ну, или не хотят.

Рисование


Так как для рисования тоже нужны фреймы, создадим их

local HelloWorld1 = CreateFrame("Frame", nil, UIParent)
local HelloWorld2 = CreateFrame("Frame", nil, UIParent)
function EventFrame:PLAYER_LOGIN()	HelloWorld1:SetFrameStrata("BACKGROUND")	HelloWorld1:SetWidth(10)	HelloWorld1:SetHeight(10)	HelloWorld1.texture = HelloWorld1:CreateTexture(nil,"BACKGROUND")	HelloWorld1.texture:SetAllPoints(HelloWorld1)	HelloWorld1:SetPoint("TOPLEFT",0,0)	HelloWorld1:Show()	HelloWorld2:SetFrameStrata("BACKGROUND")	HelloWorld2:SetWidth(10)	HelloWorld2:SetHeight(10)	HelloWorld2.texture = HelloWorld2:CreateTexture(nil,"BACKGROUND")	HelloWorld2.texture:SetAllPoints(HelloWorld2)	HelloWorld2:SetPoint("TOPLEFT",10,0)	HelloWorld2:Show()
end

Думаю, тут все понятно и без комментариев. Подробности по каждому методу

сами.

Сериализация

У нас есть две координаты и два угла. Все — числа с плавающей запятой. Компоненты цветов пикселей в аддоне тоже числа с плавающей запятой, но от

0.01.0

. Кроме того, известно, что сохранится компонента цвета в одном байте. Поначалу я каждую координату сохранял в одну компоненту цвета. В итоге точность позиционирования в локации составляла

1/255

от размера карты. Получалось как в

GPS

: вроде координаты есть, но вести машину на автомате (управление компьютером без человека) по дороге по навигатору не выйдет. Так что пришлось давать два байта. Как повыгоднее сохранить одно дробное число в два байта? Я сделал так

local x1, x2 = math.modf(x*255)


Функция

modf

возвращает целую и дробную часть числа через запятую. Здесь используется

— еще одна полезная фишечка Lua.

При таком подходе я использую полную мощность каждого из двух байтов, в которые сохраняется координата. Ну а азимут и наклон не так требовательны к точности, лишь бы укладывались в отрезок 0.0-1.0. Получается вот так:

local math = getfenv(0).math
function EventFrame:OnUpdate()	local facing = GetPlayerFacing();	local pitch = GetUnitPitch("player");	local x, y = GetPlayerMapPosition("player");	local x1, x2 = math.modf(x*255)	local y1, y2 = math.modf(y*255)	HelloWorld1.texture:SetTexture(x1/255, x2, facing/7)	HelloWorld2.texture:SetTexture(y1/255, y2, pitch/4 0.5)
end

Теперь при перемещении по миру в левом верхнем углу два квадратика 10 на 10 будут хаотично менять свой цвет.

Полный текст HelloWorld.lua

local math = getfenv(0).math
SLASH_HELLO_WORLD1 = '/helloworld';
local EventFrame = CreateFrame("Frame")
local HelloWorld1 = CreateFrame("Frame", nil, UIParent)
local HelloWorld2 = CreateFrame("Frame", nil, UIParent)
function EventFrame:OnEvent(event, ...)	print("HelloWorld:", event)	self[event](self, ...)
end
EventFrame:SetScript("OnEvent", EventFrame.OnEvent)
EventFrame:RegisterEvent("PLAYER_LOGIN")
function EventFrame:PLAYER_LOGIN()	HelloWorld1:SetFrameStrata("BACKGROUND")	HelloWorld1:SetWidth(10)	HelloWorld1:SetHeight(10)	HelloWorld1.texture = HelloWorld1:CreateTexture(nil,"BACKGROUND")	HelloWorld1.texture:SetAllPoints(HelloWorld1)	HelloWorld1:SetPoint("TOPLEFT",0,0)	HelloWorld1:Show()	HelloWorld2:SetFrameStrata("BACKGROUND")	HelloWorld2:SetWidth(10)	HelloWorld2:SetHeight(10)	HelloWorld2.texture = HelloWorld2:CreateTexture(nil,"BACKGROUND")	HelloWorld2.texture:SetAllPoints(HelloWorld2)	HelloWorld2:SetPoint("TOPLEFT",10,0)	HelloWorld2:Show()
end
function EventFrame:OnUpdate()	local facing = GetPlayerFacing();	local pitch = GetUnitPitch("player");	local x, y = GetPlayerMapPosition("player");	local x1, x2 = math.modf(x*255)	local y1, y2 = math.modf(y*255)	HelloWorld1.texture:SetTexture(x1/255, x2, facing/7)	HelloWorld2.texture:SetTexture(y1/255, y2, pitch/4 0.5)
end
EventFrame:SetScript("OnUpdate", EventFrame.OnUpdate)
function SlashCmdList.HELLO_WORLD(msg, editbox)	local facing = GetPlayerFacing();	local pitch = GetUnitPitch("player");	local x, y = GetPlayerMapPosition("player");	print(format("HelloWorld %.2f %.2f %.2f %.2f", x*100, y*100, facing, pitch));
end

Слеш-команды

Кстати, об отладке. Советую сразу добавить

SLASH_HELLO_WORLD1 = '/helloworld';
function SlashCmdList.HELLO_WORLD(msg, editbox)	local facing = GetPlayerFacing();	local pitch = GetUnitPitch("player");	local x, y = GetPlayerMapPosition("player");	print(format("HelloWorld %.2f %.2f %.2f %.2f", x*100, y*100, facing, pitch));
end


Для этого определим переменную вида

SLASH_ИМЯn

. Где

ИМЯ

уникально для всех аддонов, а

n

либо пусто, либо порядковое число с 1. И добавим функцию с именем

ИМЯ

в некий объект. Может показаться странным для программиста на C , что мы эту функцию-обработчик нигде явно не регистрируем. Да и со строковой переменной связываем чисто по имени переменной. Но вот такая она, мощь и магия Lua.

Теперь команда в WoW-консоли /helloworld выполнит требуемые вам действия: позволит вывести отладочную информацию, а для простейших аддонов, собственно, произведет все то, ради чего вы их писали.

Ну и тут же я показал WoW API, которое достает требуемую информацию.

Управление (ро)ботом

Создание несложного бота для WoW, программирование маршрутов / Хабр

Вот, казалось бы, и все. Пробежим по маршруту, запишем координаты, нажатия клавиш и клики, и включим воспроизведение. Но не тут-то было. Здесь начинается самое сложное.

В подземелье живут мобы, которые хоть и не представляют угрозы для жизни нашего персонажа, но норовят оглушить, кинуть «молчанку», отбежать в сторонку как раз тогда, когда вы бы хотели их убить, и бросаются на амбразуру в тот момент, когда вы думали взять в цель совсем другого моба.

Иногда ваша цель забегает за спину, иногда — умирает за один удар, хотя должна жить три. В общем, их хаотичное поведение вносит заметный элемент случайности в наш маршрут, и в итоге персонаж может оказаться у запертой двери в самом конце маршрута просто потому, что не смог убить кого-то в самом начале.

Да, можно было написать внутриигровые макросы, которые бы брали в цель нужного моба, и тем самым избавиться от некоторых проблем, но мне хотелось оставить бота как можно более универсальным.

Двери-решетки. На них нужно кликнуть, чтобы открыть. А так как они решетки, то кликнуть вы можете случайно аккуратно в дырку. И персонаж будет биться лбом об дверь в попытке пробежать дальше.

Таким образом, записав маршрут, вы открываете его в блокноте и отлаживаете. Вы наблюдаете за персонажем и при проблемах или возможных проблемах «вбиваете костыли» в маршрут: вставляете дополнительное заклинание для верности (вдруг моб выживет), добегаете до той точки, в которой моб будет точно виден и досягаем независимо от его желания прогуляться.

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

Я понял, каково это, запускать марсоход, программировать робот-пылесос, идти в полной темноте по квартире или учить роботов играть в футбол. Надо все делать надежно, с запасом. На марсе ямы будут везде, а еще будут нависающие скалы и пещеры. В квартире роботу-пылесосу будут противостоять провода и тапочки повсюду, а еще будет кот, который захочет поиграть. В полной темноте будут углы, ножки стульев, и даже упавшие на пол ножи. Только на ощупь!

Признаюсь, выполнил я заявленную в прошлой части лишь программу минимум. Бот все еще может не выполнить задачу с вероятностью 1%. Так что оставлять его без контроля на ночь нельзя, застрянет.

Заключение первой части


Повторим, о чем шла речь

  1. Мы посчитали вероятность получения предмета за большое число попыток
  2. Обозначили задачу, выработали подход к решению, разбили на модули
  3. Мы рассмотрели код простейшего аддона для WoW на языке Lua

    Теперь вы готовы к написанию своего аддона.

А если вы разрабатываете нечто и хотите дать возможность себе или пользователям принимать участие, гибко подстраивать ПО под себя с использованием вашего API (например, писать искусственный интеллект противников, дать возможность брокерам размещать позиции, основываясь на котировках, дать возможность администраторам выполнять свои действия по результатам инвентаризации систем пользователей и т.п.), то знайте, Lua очень гибок и очень легко встраивается. Обдумайте такую возможность.

Ну, а в следующей части мы поговорим о

  1. написании Recorder’а клавиш и координат на языке AutoIt
  2. написании Player’a инструкций для бота
  3. математике 2D, как ориентироваться в декартовой системе координат без теоремы косинусов
  4. управлении роботом при недостаточном количестве датчиков
  5. мерах противодействия ботам

Изменение от 14.08


Добавил

на вторую часть.