Вольная модификация игрового бота 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, который сильно расширил функциональность бота и написал к нему графический интерфейс. К сожалению, исходного кода интерфейса он не предоставил, поэтому, чтобы не пересоздавать его, – при модифицировании исходных файлов бота необходимо подстраиваться под этот интерфейс.
Созданы специализированные боты для игровых платформ вроде 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)); } }
А вот как это будет выглядеть в игре:
Заключение
Игровой бот - это мощная система для создания игр в Battle.net и Локальной сети. Она позволяет сделать игровой процесс более удобным и приятным. Имея мощную систему управления игровым процессом, предоставляя много возможностей управления им. Благодаря тому, что бот распространяется с открытым исходным кодом, - на нем возможно воплотить любые смелые и не очень идеи.