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

Создание простого бота для WoW: продолжение

Время на прочтение 6 мин
Количество просмотров 33K
Это продолжение предыдущей статьи:
Создание простого бота для онлайн-игры world of warcraft

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



В той статье мы создали бота, который умеет самостоятельно приходить к NPC-аукционеру. Теперь нам необходимо реализовать дальнейшие наши действия. Сначала я немного расскажу как происходит торговля на аукционе. Я лично торгую символами, но аддоны, которые я использую, также позволяют автоматизировать торговлю любыми крафтовыми предметами. Я использую TradeSkill Master, это аддон от авторов auction profit masterа, который раньше назывался quick auctions. Смысл в чем: у меня лежит на аукционе около 400-500 моих предметов. Кроме меня на сервере есть еще 4-5 человек, которые торгуют тем же товаром в таких же объемах. Моя задача — все время держать цену на товар ниже чем у них. Это позволяет делать аддон: он автоматически сканирует аукцион, если находит что кто-то выставил предмет по цене ниже моей он снимает мой лот с торгов. Предмет отправляется на почту. Соответсвенно его потом нужно забрать с почты и выложить по цене ниже чем у конкурентов. Цену назначает также аддон.

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

Торговля


Здесь уже идет чистый AutoIt, с небольшим добавлением макросов.
Нам понадобится один макрос, который будет брать в цель аукционера — это
/ц Аукционист Дрезмит

Назначаем этот макрос, например, на кнопку «9». Дальше нам необходимо начать с ним торговлю. Тут тоже все просто: в настройках назначения клавиш, раздел «функции использования целей» надо назначить кнопку «взаимодействовать с целью», я ее назначил на "\" например.
После открытия аукциона необходимо запустить процесс выставления товаров из сумок на аукцион. В моем аддоне это желается простым кликом по кнопке, в других аддонах может потребоваться два клика — не принципиально, все равно функция получается тривиальной:
Func StartPostingAuc()
	Send("9") ; берем аукциониста в цель
	Sleep(300)
	Send("\") ; открываем аукцион
	Sleep(2000); на всякий случай вдруг проблема с пингом или еще что - лучше подождать
	MouseClick("left", 1278, 155) ; кликаем на кнопку "начать постинг"
	Sleep(2000)
	$state = "posting"  ; постинг
EndFunc


Собственно сама функция постинга тоже довольно проста. После нажатия на кнопку у нас появляется такое окно:

В нем внизу идет прогрессбар, а наверху появляется кнопка, по клику на ней наш товар выставляется на аукцион.
Соответственно наша задача кликать по кнопке пока есть прогресс-бар, как только прогресс-бар заканчивается — переходим к следующему шагу — отмене товаров, цену на которые перебили
Func PostingAuc()
	$borderPixelColor = PixelGetColor(937,527); наличие прогрессбара определеяем по его рамке - пока она есть, есть и прогресс-бар
	While $borderPixelColor = 6249826 and $state = "posting" ; пока есть прогресс-бар - кликаем
		MouseClick("left", 1026, 210)
		Sleep(500);		
		$borderPixelColor = PixelGetColor(937,527);
	Wend
	if $state = "posting" then ; если закончили выставлять - переходим к следующему шагу - отмене
		$state = "startcancel"
	EndIf
EndFunc


Отмена ничем принципиально не отличается от постинга, такое же точно окно с прогрессбаром и одной кнопкой. Соответственно функции точно такие же, просто кликаем. Вот собственно и весь процесс торговли.

Перемещение к почтовому ящику


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

Единственная разница: когда идешь в сторону почтового ящика в стенах есть выступающие элементы, в которые я иногда врезался, поэтому при создании семафора я этот момент учел и сделал чтобы при приближении к стене от отодвигался от нее вправо. В принципе это было сделано просто добавлением еще одной ветки в if:
    elseif(mailPosX < 0.2000 and mailPosY > 0.896) then
      PlayerMailGoForvard:SetTexture(1,0,0);
      PlayerMailGoBack:SetTexture(1,0,0);
      PlayerMailGoLeft:SetTexture(1,0,0);
      PlayerMailGoRight:SetTexture(0,1,0);
      PlayerOnMail:SetTexture(1,0,0); 

Т.е. x < 0.2 это пока не выйду из здания, y > 0.896 — приближаюсь к стене, надо отойти. Как только вышел из здания стены уже нет, отходить не надо.

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

Итак, мы пришли к почтовому ящику, камера направлена вниз. Видим примерно такую картину:

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

Эти проблемы означают следующее: мы не можем захардкодить точку, по которой надо кликать, чтобы открыть почтовый ящик, как мы поступаем в случае с другими кнопками.
Но с учетом нашего алгоритма похода к почтовому ящику мы считаем что скорее всего он будет где-то в левой трети экрана.
Соответсвенно напишем функцию, которая будет кликать сначала в то место, где чаще всего находится почтовый ящик, и если она его не находит — кликать по левой трети экрана пока не найдет.
За 9 часов тестирования эта функция только 2 раза не смогла найти почтовый ящик, и то по моей вине: путь до ящика был плохо прописан, персонаж падал с уступа на котором он стоял и ящика на экране вообще не было. Проблема была решена прописыванием в семафор условия, при котором персонаж должен отойти немного назад чтобы не упасть.
    elseif (mailposX > 0.203) then
      PlayerMailGoForvard:SetTexture(1,0,0);
      PlayerMailGoBack:SetTexture(0,1,0);
      PlayerMailGoLeft:SetTexture(1,0,0);
      PlayerMailGoRight:SetTexture(1,0,0);
      PlayerOnMail:SetTexture(1,0,0); 

ПОчтовый ящик в открытом состоянии (слева вверху виден кусок обновленного семафора, более компактного):


Собственно открытие почтового ящика мы будем определять по появлению красной кнопки «получить все». Функция для autoit у меня получилась такая:
Func OpenMail()	
	$x1 = 392 ; позиция, в которой почтовый ящик находится наиболее часто
	$y1 = 382
	While not (PixelGetColor(237,515) = 6226176) ; пока не появится красная кнопка - обходим заданную область поиска
		MouseClick("right", $x1, $y1);	
		$y1 = $y1 + 20
		if $y1 > 620 Then
			$x1 = $x1 + 10
			$y1 = 54			
			if $x1 > 650 and $y1 > 620 Then
				$x1 = 194
				$y1 = 54
			EndIf
		EndIf
		Sleep(200)
	Wend
	MouseClick("left", 237,515)4 когда нашли кнопку - кликаем по ней
	Sleep(1000)
	MouseClick("left", 237,535); убираем с нее мышку
	$state = "givingmails"; переходим к получению писем
EndFunc

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

Получение писем


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

Казалось бы все, бот написан. Но тут то меня и поджидали самые большие проблемы: узнать о том, что все письма получены, оказалось не такой тривиальной задачей, как выглядело сначала. Вообще есть два способа узнать что все письма получены:
1. кнопка снова стала красной. самый простой вариант, к сожалению — самый редкий.
2. сумки заполнились — при этом кнопка не становится красной и бот мог бы вечно стоять и ждать возле почты. Чтобы решить эту проблему бот автоматически открывает последнюю сумку при запуске и следит чтобы последняя ячейка в ней была пустой. Как только цвет последней ячейки сумки меняется — значит сумки заполнены, пора идти на аукцион
3. иногда trade skill master глючит и некоторые пустые письма не удаляются с почты. В этом случае кнопка тоже никогда не становится красной, даже если писем на почте уже нет. В этом случае проблема решается просто: я взял последний слот почты, и смотрю меняется он или нет: при получении писем они постоянно сдвигаются вверх и слот меняется. Когда все письма получены он перестает меняться. Если он не меняется в течении 20 секунд — значит пора идти выставлять товар.

Итого функция получилась такая:
Func GiveMails()
	if PixelGetColor(237,515) = 6226176 or $i = 25 or not (PixelGetColor(1665, 868) = 2761500)  then ; проверяем на соответствие одному из трех условий
		$state = "goingtoauc"
		$i = 0
	EndIf
	if PixelGetColor(52,470) = $prevcolor then ; сохраняем состояние слота и ведем подсчет секунд, сколько времени цвет не менялся
		$i = $i+1
	else 
		$i = 0
	EndIf
	$prevcolor = PixelGetColor(52,470)
	Sleep(1000)
EndFunc


Все, мы успешно получили письма, возвращаемся к аукционеру!


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

В качестве заключения хочу сказать что разработка ботов для онлайн-игр это как логическая игра:
Как заставить его забрать все письма? Каким образом обойти ту или иную особенность? Как лучше реализовать ту или иную функцию? Выходные считаю проведенными с толком, хорошая разминка для мозгов :)
Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+63
Комментарии 49
Комментарии Комментарии 49

Публикации

Истории

Работа

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

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