ますたーです。こんにちは。
今回は、「バトルタワー」自動周回で、BPを稼ぐArduino Leonardo自動化の記事です。
なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。
導入記事:【Arduino自動化01】Arduino開発環境の導入
※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。
概要
本記事では、シュートシティの「バトルタワー」自動周回を実装します。
目次です。
経緯
バトルタワー周回という「いまさら」感が強いタイミングでの記事化となりますが、実は、当ブログのアクセス状況を確認すると、ダイマックスアドベンチャーの自動周回記事が(アクセス数も検索流入も)大変盛況なのです。
どうやら、従来のマクロ対応コントローラーでできることをマイコン(本ブログだとArduino Leonardo)に対応させたいという需要は一定数あるらしく、それならこのブログでも取り上げる価値があるかな?と思ったので記事化しました。
BP(バトルポイント)は、お金やワットとは引き換えられないもの(いじっぱりミントなど)も多いため、そういう意味でも需要はあると思います。
この記事のスタンス
本記事では、下記の前々回・前回(第6回・第7回)の記事に引き続き、マクロ対応コントローラーの代替用の雛形をベースにArduino Leonardo用にプログラムを書いていきます。例のごとく、入力するコマンド列が予め分かっているものを活用します。
なお、本ブログで扱うコマンド列は、私が考案したものではありません。ダイマックスアドベンチャーの記事でも紹介した、あずき氏によるものです。当該ブログ記事を下記にて引用します。合わせてご参考ください。
azukiss.hatenablog.com
バトルタワー自動周回のやりかた
バトルタワーの自動周回には、以下の条件を満たしている必要があります。
- バトルタワー「シングルバトル」ランクが「マスターボール級」であること
- 自動周回用のパーティーを準備していること
1のマスターランク到達は前提ですが、今作では禁止伝説級のポケモンが使用できるのでゴリ押しで攻略可能です。1時間ほどでマスターランクに到達できると思います。
2の自動周回用パーティーですが、
- AS極振り ザシアン@くちたけん/わざ:アイアンヘッド
- AS極振り ウオノラゴン@こだわりスカーフ/わざ:エラがみ
- CS極振り ムゲンダイナ@こだわりメガネ/わざ:ダイマックスほう
の3匹を準備してください。なお、それぞれのPPは最大値まで増やしておきましょう。
自前で準備が難しければレンタルチーム(要Nintendo Online加入)でも可能です(参考チームID:0000 0000 5MJ4 0K)。
コマンド列ですが、原則としてAボタン連打で攻略していき、ポケモン入れ替えなどのために「↑」や「B」を押す、というイメージです。下記を御覧ください。
自動周回のコマンド入力列(あずき氏のブログ記事より引用・一部改変)
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
A |
A |
A |
A |
↑ |
A |
A |
↑ |
9 |
10 |
11 |
12 |
13 |
14 |
15,16 |
A |
A |
A |
A |
B |
↑ |
R,R(連打) |
※指定が無い部分のキー入力間隔は約1.5秒
要するに、この16コマンドをひたすら繰り返すことで、バトルタワーを延々と攻略してBPを稼いでくれるということです。すごいですね。
自動化コマンドの実装
前回の記事で紹介した雛形・関数の要領で、前述の16コマンドを入力していきます。雛形は下記テキストボックスからコピペも可能です。今回はスティック入力が無いので、「PushKey("入力キー", 長押しミリ秒, 待機ミリ秒 ); 」を16行並べるだけです。
Arduino Leonardo自動化用 プログラム雛形
前述のコマンド列を関数に当てはめると下記の様になります。この雛形の中に下記「loop(){」と「}」の間16行を埋め込むだけでプログラムになります。
こちらは説明用に抜粋したプログラムの一部です。プログラム全文は⇒コチラをクリックして読み飛ばす
#define HOLDTIME (95)
void loop() {
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("UP", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("UP", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("B", HOLDTIME, 1500);
PushKey("UP", HOLDTIME, 1500);
PushKey("R", HOLDTIME, 150 );
PushKey("R", HOLDTIME, 150 );
}
なお、今回は15個目のRと16個目のRの間を連打するので、それぞれの待機時間を150ミリ秒(充分短い時間)にしています。なお、この間が極端に短すぎる(例えば10ミリ秒などに設定する)と、Switch側がボタンの押下状態を認識できずコマンドミスすることがあるようです。注意しましょう。
プログラムの使い方
前述の通り、攻略用3匹のみのパーティーを準備の上、シュートシティの上側にあるバトルタワーへ行き、受付の前でArduino Leonardoを差し込むだけです。
なお、初回は「手持ち」にカーソルが合っていると思いますので、上記のレンタルチームを活用している人は、手動でそちらにカーソルをあわせておいてください。
雛形は前回の記事と同一です。
#include <SwitchControlLibrary.h>
#define HOLDTIME (95)
void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void TiltLeftStick(int direction_deg, double power, int holdtime, int delaytime);
void setup() {
for(int i=0;i<7;i++)PushRL(300);
delay(1000);
}
void loop() {
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("UP", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("UP", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("A", HOLDTIME, 1500);
PushKey("B", HOLDTIME, 1500);
PushKey("UP", HOLDTIME, 1500);
PushKey("R", HOLDTIME, 150 );
PushKey("R", HOLDTIME, 150 );
}
void PushRL(int delay_time_ms){
SwitchControlLibrary().PressButtonR();
SwitchControlLibrary().PressButtonL();
delay(HOLDTIME);
SwitchControlLibrary().ReleaseButtonR();
SwitchControlLibrary().ReleaseButtonL();
delay(delay_time_ms);
return;
}
int PushKey(char* keyname, int holdtime, int delaytime){
if(strlen(keyname)==1){
switch(keyname[0]){
case 'A': case 'a':
SwitchControlLibrary().PressButtonA(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonA(); delay(delaytime);
break;
case 'B': case 'b':
SwitchControlLibrary().PressButtonB(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonB(); delay(delaytime);
break;
case 'X': case 'x':
SwitchControlLibrary().PressButtonX(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonX(); delay(delaytime);
break;
case 'Y': case 'y':
SwitchControlLibrary().PressButtonY(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonY(); delay(delaytime);
break;
case 'L': case 'l':
SwitchControlLibrary().PressButtonL(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonL(); delay(delaytime);
break;
case 'R': case 'r':
SwitchControlLibrary().PressButtonR(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonR(); delay(delaytime);
break;
case 'H': case 'h':
SwitchControlLibrary().PressButtonHome(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
break;
case '+': case 'p': case 'P':
SwitchControlLibrary().PressButtonPlus(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonPlus(); delay(delaytime);
break;
case '-': case 'm': case 'M':
SwitchControlLibrary().PressButtonMinus(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonMinus(); delay(delaytime);
break;
default:
break;
}
}else if(strlen(keyname)>=2){
switch(keyname[0]){
case 'z': case 'Z':
if(keyname[1]=='R'||keyname[1]=='r'){
SwitchControlLibrary().PressButtonZR(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonZR(); delay(delaytime);
}
if(keyname[1]=='L'||keyname[1]=='l'){
SwitchControlLibrary().PressButtonZL(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonZL(); delay(delaytime);
}
break;
case 'r': case 'R':
SwitchControlLibrary().MoveHat(2); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
break;
case 'l': case 'L':
SwitchControlLibrary().MoveHat(6); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
break;
case 'u': case 'U':
SwitchControlLibrary().MoveHat(0); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
break;
case 'd': case 'D':
SwitchControlLibrary().MoveHat(4); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
break;
case 'H': case 'h':
SwitchControlLibrary().PressButtonHome(); delay(holdtime);
if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
default:
break;
}
}else{
return -1;
}
return strlen(keyname);
}
void TiltLeftStick(int direction_deg, double power, int holdtime, int delaytime){
double rad = (double)direction_deg*PI/180.0;
int x, y;
x = (double)128*sin(rad)*power;
y = (double)-128*cos(rad)*power;
x += 128; y += 128;
if(x >= 255) x=255; if(x <= 0) x=0;
if(y >= 255) y=255; if(y <= 0) y=0;
SwitchControlLibrary().MoveLeftStick(x,y);
if(holdtime> 0){
delay(holdtime);
SwitchControlLibrary().MoveLeftStick(128,128);
}
if(delaytime>0) delay(delaytime);
return;
}
あとがき
本記事では、Arduino Leonardoを使ったバトルタワー自動周回(BP稼ぎ)について紹介をしました。
パーティーをいくつも作っていると「こだわりメガネ」「こだわりスカーフ」が足りなくなったり、不意の事故で「きあいのタスキ」「ふうせん」などを野生戦で消費してしまったりしますよね。ほかにも、育成用に欠かせない「ようきミント」「いじっぱりミント」なども不足しがちです。このあたりの道具が引き換えられるのはありがたいですね。
今回のバトルタワー然り、前回のトーナメント然り、前々回のダイマックスアドベンチャー然り、ポケモンには対人戦の準備に関わる「周回」が切っても切り離せないですね。無論、こういったエンドレスに遊べるコンテンツを通してやりこみや対人戦前の調整をするのが目的になるのでしょうが、アイテム回収を目的にすると少しツライものがあります。この観点において、マクロ対応コントローラーやマイコンは、各人のゲームとの関わり方の選択肢を増やしてくれるので、うまく活用していきたいものですね。
本記事が皆様のポケモン自動化ライフの一助となることを願っています。
ではではc⌒っ.ω.)っ
前回記事:
【Arduino自動化07】トーナメント自動周回【マクロコン代替】
前々回記事:
【Arduino自動化06】完全放置「マックスこうせき」集め【ダイマックスアドベンチャー】
次の記事:
【Arduino自動化09】ポケモンキャンプでカレー自動調理【カレーのあかし】
導入記事:
【Arduino自動化01】Arduino開発環境の導入