1年後、VKontakteの友達が楽しんでいるものを見ることができると決めました。 従来の大量の政治、子猫やその他のわいせつ物の写真に加えて、私はAngry Petsブラウザへのリンクを見つけました。 私はブラウザをプレイしたことがないので、どんな種類の獣なのかを見ることにしました。 最もかわいい写真(かわいい猫、ペンギン、リスがお互いの顔を打ちます)、肛門を寄付する(お金が収入を8倍にします)、プロット、戦略、絶望、マニュアル、その他の通常のアメニティが欠けています。
ゲームは、建物を建てる、10分待つ、ユニットを建てる、10分待つ、被害者を見つける、攻撃するユニットを送る、10分待つ、被害者を見つける、攻撃するユニットを送る、10分待つ、という単純な操作で構成されています。 ...(高レベルでの10分間は指数関数的に増加します。加速のため-有料です。)
そのようなゲームをどうするか? そうです、ボットを書いてください。 正直なところ、 これをプレイしないでください。
タスクを設定します。
- ボットは、リスト上のスケジュールされた都市を攻撃できる必要があります。
- ボットは、攻撃するユニットを尋ねられます。
- ボットはすぐに燃えてはいけません。 :)
ボットがすぐに燃えないように、まず、長い間オンラインになっていない農場の
ボットの作成者が喜ぶように、サイト上のスクリプトは難読化されていません。 パッケージ化されたスクリプトはjQueryとその他のみです。 そして、はい、jQueryがあるので、文明のすべての利点を使用します。
ゲーム内のほとんどのアクションは、AJAXリクエストにつながります。 アイテムをクリックすると、リクエストはなくなり、ほぼ全画面または別のウィンドウが表示されます。 デバッガーでリンクを調べると、次のようになっていることがわかります。
<a href="/10193192/city/view/10009466" data-link-handled="1" onclick="Main.goToUrl(this);return false;"></a>
Main.goToUrlメソッドは、文字列またはリンク要素を受け入れます。 ほとんどのゲームリンクの先頭には、プレーヤープロファイル識別子が付いたプレフィックスがあります。 保存してください。
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(); },
まあ、純粋にwaitForAjaxの均一性のために、AJAXを待つのではなく、単に遅延を作る必要がある場合にwaitForActionを追加します。
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 () {
特定の単位を選択するか(利用可能な数量は最大入力属性にあります)、すべてを選択し(別のボタン)、最も重要なこと:「攻撃」をクリックします。
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ページをクリックすると、Popapレイヤーが閉じます。気にすることはできません。
実際には、それだけです。 誰が濡れているかを見るために、攻撃された都市の美しいリストのみを固定できます。
完全なコード:
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-クリックの遅延、ランダム値-ランダムに追加される遅延の範囲
- ゲームに入ります。
- デバッグコンソールからコードを実行します。
- すべてが正しい場合、攻撃された都市の識別子のリストが左側に表示され、スクリプトは最初の都市を攻撃し始めます。 現在の都市は大胆です。
一般的に、ゲームの所有者の慢さは私を楽しませる。 オズベリンの形での「サブスクリプション料金」(それよりもさらに憂鬱にプレーするために)は180ルーブル/月です(このゲームにはないすべてを持っているWoWは、わずか2倍の費用がかかります)。 リソースは最大120ルーブル/日(1日!)で購入でき、リソースの抽出速度が8倍になります(ウォレットの競合、非支払いは一般に森に行きます)。 加速器への寄付を
そして結局のところ、人々は支払います。 私は間抜けです。