Предупреждение : Бот невероятно простой.
Вряд ли вы узнаете что-то новое.
Статья просто для развлечения.
Я решил, что через год смогу посмотреть, чем занимаются друзья ВКонтакте в свое удовольствие.
Помимо традиционных тонн политической литературы, картинок с котятами и прочей нецензурной лексикой я нашел ссылку на браузер Злые домашние животные .
Я никогда не играл в браузерные игры, поэтому решил посмотреть, что это за зверь.
Выяснилось следующее: картинки самые милые (милые котики, пингвины и белки бьют друг друга по морде), донат самый анальный (за деньги доход умножается в 8 раз), сюжет, стратегия, беззаботность , мануал и прочие привычные приятности отсутствуют.
Игра, чуть менее чем полностью, состоит из следующих простых операций: построить здание, подождать 10 минут, построить юнитов, подождать 10 минут, найти жертву, отправить юнитов в атаку, подождать 10 минут, найти жертву, отправить юнитов чтобы атаковать, подождите 10 минут. (10 минут на высоких уровнях увеличиваются в геометрической прогрессии.
За ускорение взимается отдельная плата.
) Что делать с такой игрой? Правильно, написать бота.
Не играй Этот , честно.
Поставим задачу:
У бота можно спросить, какими юнитами атаковать.
Бот не должен сразу стрелять.
:) Чтобы бот не сгорел сразу, во-первых, в качестве жертв за избиение фермерских малышей выбираем игроков, которые давно не были в сети, чтобы они не жаловались на нас в нужное место; во-вторых, мы моделируем действия пользователя, а не отправляем голые AJAX-запросы; в-третьих, делаем задержку между действиями не нулевой, а случайной.
К радости авторов ботов, скрипты на сайте не обфусцированы.
Единственные упакованные скрипты — это jQuery и ему подобные.
И да, есть jQuery, поэтому мы пользуемся всеми благами цивилизации.
Большинство действий в игре приводят к запросам AJAX. Щелкаешь по элементу, запрос уходит и появляется либо почти полный экран, либо отдельное окно.
Исследуя ссылки в отладчике, мы видим, что они имеют вид
где метод Main.goToUrl принимает либо строки, либо элементы ссылки.<a href="/10193192/city/view/10009466" data-link-handled="1" onclick="Main.goToUrl(this);return false;"></a>
Большинство ссылок на игры имеют префикс идентификатора профиля игрока.
Давайте сохраним его.
profilePath: window.location.pathname.match(/^\/\d+\//)[0],
Как дождаться завершения запроса AJAX? В jQuery есть хорошая функция $.
ajaxSuccess, в которую вы можете передать обратный вызов, который вызывается после каждого успешного запроса.
В него сохраняются событие, объект XMLHttpRequest и аргументы вызова $.
ajax. Соответственно, когда мы получаем указанный URL, мы вызываем наш обратный вызов.
ajaxCallbacks: {},
run: function ()
{
.
$('html').
ajaxSuccess(Bot.ajaxSuccess); .
}, ajaxSuccess: function (e, xhr, settings) { var ajaxUrl = null, ajaxCallback = null; $.
each(Bot.ajaxCallbacks, function (url, callback)
{
var fullUrl = Bot.profilePath + url;
if (settings.url.substr(0, fullUrl.length) == fullUrl) {
ajaxUrl = url;
ajaxCallback = callback;
}
});
if (ajaxCallback) {
Bot.ajaxCallbacks[ajaxUrl] = null;
setTimeout(ajaxCallback, Bot.getClickDelay());
}
},
waitForAjax: function (pageUrl, gotoPage, success)
{
Bot.ajaxCallbacks[pageUrl] = success;
gotoPage();
},
Ну чисто для единообразия мы добавляем waitForAction к waitForAjax, когда нужно не ждать AJAX, а просто сделать задержку.
waitForAction: function (action, success)
{
action();
setTimeout(success, Bot.getClickDelay());
},
Как часто занимается фермерством простой неавтоматизированный смертный? Нажимает кнопку почты, заходит в логи, выбирает недавно атакованный город, нажимает "Атака", выбирает юниты, нажимает "Удар в лицо".
Так что повторим эту операцию по кругу.
Конечно, в логах не всегда будет нужный город на нужной странице, но писать сложную логику перелистывания без особой мотивации — откровенное лень.
Выбираем жертву и генерируем ссылки.
attackNext: function ()
{
if (Bot.targetCities.length == 0)
return;
if (!Bot.targetCities[Bot.currentTargetCity])
Bot.currentTargetCity = 0;
var targetCity = Bot.targetCities[Bot.currentTargetCity++],
targetCityUrl = 'city/view/' + targetCity,
attackCityUrl = 'attack/' + targetCity;
Переходите по ссылкам и нажимайте кнопки.
Bot.waitForAjax('pm/inbox', function ()
{
Main.goToUrl(Bot.profilePath + 'pm/inbox');
}, function ()
{
Bot.waitForAjax('pm/logs', function ()
{
Main.goToUrl(Bot.profilePath + 'pm/logs');
}, function ()
{
Bot.waitForAjax(targetCityUrl, function ()
{
Main.goToUrl(Bot.profilePath + targetCityUrl);
}, function ()
{
Bot.waitForAjax(attackCityUrl, function ()
{
$('button[onclick^="Attack.showAttackAlert"]').
click();
}, function ()
{
Либо выбираем конкретные юниты (доступное количество есть во входном атрибуте max), либо выбираем все (отдельная кнопка), а потом самое главное: нажимаем «Атака».
Bot.waitForAction(function ()
{
var count = 0;
$.
each(Bot.attackUnits, function (unitType, unitNum) { var ctl = $('input[name="units[' + unitType + ']"]'); ctl.val(Math.min(ctl.attr('max'), unitNum)).
change(); count++; }); if (count == 0) { $('span[onclick^="Attack.ChooseEveryone"]').
click(); } }, function () { $('button[type=submit]').
click();
setTimeout(Bot.attackNext, Bot.getAttackInterval());
})
Слои всплывающих окон закрываются самостоятельно при навигации по страницам AJAX, поэтому вам не придется беспокоиться.
Собственно, это все.
Можно прикрепить только красивый список атакованных городов, чтобы увидеть, кого мы убиваем.
Полный код: window.Bot = {
attackInterval: /*5.5*/8 * 60 * 1000, // 8 min
attackIntervalRandom: 1.2 * 60 * 1000, // 1.2 min
clickDelay: 3 * 1000, // 3 sec
clickDelayRandom: 4 * 1000, // 4 sec
targetCities: [
//12345678
],
attackUnits: {
//101: 99
},
profilePath: window.location.pathname.match(/^\/\d+\//)[0],
currentTargetCity: 0,
ajaxCallbacks: {},
run: function ()
{
var box = '<div style="position: absolute; background: #fff; padding: 10px; border-radius: 10px; left: 20px; top: 20px; z-index: 666666">';
$.
each(Bot.targetCities, function (_, cityId) { box += '<a class="bot-target-city" data-link-handled="1" onclick="Main.goToUrl(this);return false;"' + ' id="bot-target-city-' + cityId + '"' + ' href="' + Bot.profilePath + 'city/view/' + cityId + '">' + cityId + '</a><br>'; }); box += '</div>'; $('body').
append(box); $('html').
ajaxSuccess(Bot.ajaxSuccess); Bot.attackNext(); }, ajaxSuccess: function (e, xhr, settings) { var ajaxUrl = null, ajaxCallback = null; $.
each(Bot.ajaxCallbacks, function (url, callback) { var fullUrl = Bot.profilePath + url; if (settings.url.substr(0, fullUrl.length) == fullUrl) { ajaxUrl = url; ajaxCallback = callback; } }); if (ajaxCallback) { Bot.ajaxCallbacks[ajaxUrl] = null; setTimeout(ajaxCallback, Bot.getClickDelay()); } else { console.log('Not recognized ' + settings.url); } }, waitForAjax: function (pageUrl, gotoPage, success) { Bot.ajaxCallbacks[pageUrl] = success; gotoPage(); }, waitForAction: function (action, success) { action(); setTimeout(success, Bot.getClickDelay()); }, getAttackInterval: function () { return parseInt(Bot.attackInterval + Math.random() * Bot.attackIntervalRandom); }, getClickDelay: function () { return parseInt(Bot.clickDelay + Math.random() * Bot.clickDelayRandom); }, attackNext: function () { if (Bot.targetCities.length == 0) return; if (!Bot.targetCities[Bot.currentTargetCity]) Bot.currentTargetCity = 0; var targetCity = Bot.targetCities[Bot.currentTargetCity++], targetCityUrl = 'city/view/' + targetCity, attackCityUrl = 'attack/' + targetCity; $('a.bot-target-city').
css({ fontWeight: 'normal' }); $('a#bot-target-city-' + targetCity).
css({ fontWeight: 'bold' }); Bot.waitForAjax('pm/inbox', function () { Main.goToUrl(Bot.profilePath + 'pm/inbox'); }, function () { Bot.waitForAjax('pm/logs', function () { Main.goToUrl(Bot.profilePath + 'pm/logs'); }, function () { Bot.waitForAjax(targetCityUrl, function () { Main.goToUrl(Bot.profilePath + targetCityUrl); }, function () { Bot.waitForAjax(attackCityUrl, function () { $('button[onclick^="Attack.showAttackAlert"]').
click(); }, function () { Bot.waitForAction(function () { var count = 0; $.
each(Bot.attackUnits, function (unitType, unitNum) { var ctl = $('input[name="units[' + unitType + ']"]'); ctl.val(Math.min(ctl.attr('max'), unitNum)).
change(); count++; }); if (count == 0) { $('span[onclick^="Attack.ChooseEveryone"]').
click(); } }, function () { $('button[type=submit]').
click();
setTimeout(Bot.attackNext, Bot.getAttackInterval());
})
});
});
});
});
}
};
Bot.run();
Инструкции по использованию: В коде заполните массив targetCities идентификаторами атакуемых городов.
При просмотре страницы города идентификатором является цифра в самом конце.
В коде заполняем объект AttackUnits попарно: тип юнита — количество юнитов.
Идентификаторы типа любезно предоставлен разработчиками (101 пример — кот «боец»).
Настройте задержки по своим возможностям: AttackInterval — интервал между атаками, clickDelay — задержка на клики, Randomvalue — диапазон случайно добавляемой задержки.
Войдите в игру.
Запустите код из консоли отладки.
Если все правильно, то слева появится список идентификаторов атакованных городов, и скрипт начнет атаковать первый город. Текущий город выделен жирным шрифтом.
Вообще меня забавляет наглость владельцев игры.
«Абонентская плата» в виде Озверина (без которого играть еще скучнее) составляет 180 руб/мес (WoW, в котором есть все, чего нет в этой игре, стоит всего в 2 раза дороже).
Ресурсы можно приобрести на сумму до 120 рублей/день (день!), увеличивая скорость добычи ресурсов в 8 раз (конкуренция кошельков, неплательщики вообще идут к черту).
Простор для вымогательства пожертвований на ускорители, детали для ракет, бонусы за атаки, выполнение квестов (ага, заплатил 300 рублей - квест выполнил) и прочие мелочи вообще безграничны.
Обмен ресурсами, вступление в клан и т.п.
- только за деньги.
Платят за «выбор игроков» — это монеты стоимостью 1500 рублей.
И все это прикрывается железным аргументом: «Часть доходов идет в WWF! Вы спасаете милых пушистых зверюшек! Если вы будете возмущаться, мы вас забаним!» И люди платят. Я волнуюсь.
Теги: #angry pets #браузерная игра #бот #браузерная игра #браузер #бот #глупость #Разработка игр
-
Шаблоны Grasp: Создатель
19 Oct, 24 -
Президент Reddit Подал В Отставку
19 Oct, 24