ДонНТУ   Портал магистров

Вольная модификация игрового бота Warcraft 3 с открытым исходным кодом.

Об игре

Warcraft 3 изначально разрабатывался компанией Blizzard как игра в жанре стратегии и вышел в далеком 2002 году, являясь продолжением культовой игры конца 90х - Warcraft2. Стандартный пак игры включал в себя несколько кампаний, в которых игрок мог полностью погрузиться во вселенную Warcraft ( к тому же превосходно отрисованную, на тот момент так точно) и научиться грамотно использовать интерфейс игры, получить навыки для будущих сражений с другими игроками онлайн. Мультиплеер включал в себя несколько карт-локаций, в которых один или несколько игроков могли воевать друг с другом

Более того, разработчики предоставили игрокам возможность на базе игрового движка разрабатывать свои карты,причем изначально редактор карт включал настолько большое число возможностей, что игроки могли отойти от стандартного шаблона и делать уже не карты-сражения ( так называемые melee), но и воплотить абсолютно любую идею на движке Warcraft! Для этого, помимо упрощенного редактора скриптов, с помощью которых можно реализовать логику задуманной карты, но и специально созданный язык программирования - Jass, который окончательно снес барьеры. Дальнейшее развитие редактора подстегнули уже сами картостроители. Появились редакторы с новыми возможностями, выпущенные не в Blizzard, созданы парсеры, типа cJass, используя который, не нужно перестраиваться на специфический синтаксис, а использовать привычный для c-подобных языков, сформировались сообщества создателей карт, например обширное русскоязычное, ну и конечно же, было создано множество великолепных карт, например общеизвестная среди людей мужского пола младше 25 лет Dota Allstars :). Для меня это интересная тема, но индивидуальный раздел посвящен не этому. Я как-то пытался создать собственную карту, но я не хотел делать плохо, а на "хорошо" не хватило терпения. Так что написав четверть кода я остановился, зато это был полезный опыт)

Появление ботов

Возможность играть друг с другом в мультиплеерные карты была реализована Blizzard через систему BattleNet - специальный игровой сервер. Рассмотрим же систему пользовательских карт, которая непосредственно связана с тем, о чем я хочу рассказать. Изначально обычный игрок мог лишь создавать игру, присоединяться к игре и , конечно же, получать удовольствие, играя в выбранную карту. Хост (создающий игру) выбирает карту из имеющихся у него, после чего создается лобби ("прихожая" - место с чатом, где хост ждет, пока присоединится необходимое количество игроков, после чего запускает игру).

Но что делать со случайно попавшим к тебе из доты школьником, который зашел, чтобы лишь перечислить знакомое ему количество матерных слов в адрес хоста (хост - создатель карты), как бы избавиться от него? Что делать с игроком с высоким пингом, который портит игру остальным, может быть лучше и не пускать таких изначально при создании карты в лобби? Как научить многих играть в любимую карту, не создавать же с утра до ночи?. Также не все игроки способны хостить игры, а только имеющие "белый" ip, который виден из сети, было бы не плохо поделиться с другом возможностью создавать карты? Ну и просто, как выделится среди других хостов? Может быть, с помощью отдельных программ для каждой мелкой функции, но как же получить всё в одном? Эти и другие возможности появились с появлением бота с символичным названием Ghost - программы, которые полностью эмулируют процесс создания карты и это только малая его часть. Бот также имеет возможность подключиться к нескольким серверам и объединить игроков из них в одной игре, тем самым набрав очень быстро необходимое количество игроков. Скажу спасибо MrJag, он по сути спас Warcraft, создав своего бота, именно благодаря ему люди до сих пор играют в интересные нестандартные карты (например, известная карточная игра "Мафия" на движке варкрафт), а не только в доту. Я и сам тоже иногда погружаюсь в этот мир, но не так часто, как когда-то.

Модификации бота

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

Рисунок 1 – интерфейс игрового бота.

Созданы специализированные боты для игровых платформ вроде Garena, всё еще развиваются интернет-сообщества, посвященные боту. Пока это происходит - Warcraft 3 живет.

Локализация команд бота

Как вообще происходит процесс хостинга ( создание игровой карты)? Бот запускается как отдельное от Warcraft 3 приложения и используя соответствующие протоколы подключается к серверу ничем не отличаясь для него от обычного игрока. Бот имеет систему команд, которые изначально по умолчанию были указаны в исходном коде и не было возможности их поменять, не изменяя исходник.

				if( Command == "pub" || Command == "p" )
				{
					//логика команды
				}

Поэтому в некоторых модификациях бота, в том числе и в моей, реализован вынос команд в отдельный файл. Соответственно стало возможным менять команды и локализовывать их. ( Один из многих реализованных мной способов выделиться среди других хостов :) ). При локализации, однако, встречается уже упоминаемая мной выше проблема взаимодействия с интерфейсом. Дело в том, что команды боту можно подавать как непосредственно из самой игры, так и из GUI из операционной системы. Warcraft 3 и бот, соответственно, поддерживает кодировку UTF8, тогда как интерфейс был написан под Windows с поддержкой исключительно ASCII. Причем передача боту команды из оболочки происходит без какой либо конвертации через порт взаимодействия с GUI. Соответственно из-за разницы кодировок правильно будет передаваться только команда, написанная на латинице. Чтобы обойти эту проблему и не переписывать весь интерфейс - мной был изменен исходный код следующим образом:

				if( m_GHost->CheckCommand(Command,"9956"))
				{	 	
					//логика команды
				}

Соответственно в операторе условия поступившая команда сравнивается с её представлением в обоих кодировках. Локализация команды хранится в отдельном файле. И имеет вид для данного случая: lang_9956 = команда. При этом функция CheckCommand имеет вид:

					bool CGHost :: CheckCommand( string Command, string lang_numb)
					{
						lang_numb = "lang_" + lang_numb;
						string GCommand = m_Language->m_CFG->GetString(lang_numb.c_str(),lang_numb.c_str());
						vector<string> alliases;
						CutWords(GCommand," ",alliases);
						string CommandUtf8;
						for (unsigned int i=0;i<alliases.size();i++)
						{
							CommandUtf8 = unicode_to_utf8(ansi_to_unicode(Command.c_str()));
							if ( Command==alliases[i] || CommandUtf8==alliases[i])
								return true;
						}	
						return false;
					}

Как видно, в теле функции производится конвертация команды в UTF8 и сравнение её со списком команд. К тому же функция поддерживает синонимы команд, которые также можно задавать в файле локализации. String GetString(...) - стандартная функция бота, получает строку локализации из файла.

Информация о карте

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

Среди простейших возможностей использования конфигурационного файла – это возможность создать какое-то понятное и осмысленное описание карты, которое будет печататься боту в личный чат тому игроку, который её запросит соответствующей командой. Для этого в конфигурационном файле создается отдельное поле и загружается в память, в поле объекта класса Map – класс, который отвечает за хранение информации о выбранной карте и методов работы с ней.

				String m_Info = CFG->GetString("map_Info", string());
				m_InfoOpt = Delim(m_Info,100); //вектор, поле класса Map.

Функция Delim(String str,int lim) осуществляет разбиение входной строки на несколько, не превышающих lim символов. Это необходимо, т.к. одно сообщение от бота в личный чат не может быть больше 100 символов, поэтому если информация занимает больше - она будет отправлена за несколько сообщений, идущих подряд.

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

				if (!m_GameLoading && !m_GameLoaded)
				{
					// Печать сообщения о наличии инфо через 8 секунд после входа игрока
					if (!m_InfoOpt.empty() && !(*i)->f_InfoSended && (GetTime( ) - (*i)->GetJoinTime( )>= 8))
					{
						(*i)->f_InfoSended=true;
						SendChat(*i,m_GHost->m_Language->AboutInfo( ));
					}
				}

Этот код отрабатывает в периодичной функции, которая обрабатывает информацию о текущей игре в лобби, в цикле обработки информации об игроках Здесь i- итератор на элемент вектора игроков.

Тогда сам код команды !инфо будет иметь следующий вид:

				if ( m_GHost->CheckCommand(Command,"8947") )
				{	
					if (!m_InfoOpt.empty())
					{
						for( vector :: iterator i = m_InfoOpt.begin( ); i !=m_InfoOpt.end( ); i++ )
							SendChat( player, (*i));
					}
				}

А вот как это будет выглядеть в игре:

Рисунок 2 – Лобби игры.

Заключение

Игровой бот - это мощная система для создания игр в Battle.net и Локальной сети. Она позволяет сделать игровой процесс более удобным и приятным. Имея мощную систему управления игровым процессом, предоставляя много возможностей управления им. Благодаря тому, что бот распространяется с открытым исходным кодом, - на нем возможно воплотить любые смелые и не очень идеи.