ますたーです。こんにちは。
今回は、「5番道路」の橋の上でひたすら努力値振りに使える「ハネ」系アイテムの自動回収を行う記事です。
なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。
導入記事:【Arduino自動化01】Arduino開発環境の導入
※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。
概要
本記事では、ランクマバグ状態※を利用した、羽系アイテムの自動回収を実装します。
※便宜上「ランクマバグ」と表記しますが、当ブログではランクマッチを使用しません。通信切断・初手降参の推奨もしません。
NintendoSwitch Ver.11.0アップデート対応済です。
★2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済です。
★2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済です。
では、目次です。
ソースコードだけほしい方は読み飛ばしてください⇒読み飛ばす
羽集めで端数の努力値振りも簡単に
今回の記事で集める「たいりょくのハネ」「ちりょくのハネ」などのいわゆる「ハネ系アイテム」は、 ポケモンの基礎ポイント(努力値)を1増やすことができます。
ポケモンの育成をする上で努力値振りという作業をしますが、極振り(252振り)以外の端数で努力値を扱う場合には、10単位でしか努力値が増やせない各種ドーピングアイテム(タウリン・ブロムヘキシンなど)では対応できないため、1単位で努力値を増やせる「○○のハネ」は大変重宝します。
日付変更+マップ切り替えで無限に羽が集まる
「○○のハネ」はドロップアイテムとしてガラル地方の様々な場所に隠しアイテムとして落ちています。
これらの場所で拾える羽系アイテムは、1日経過で「同じ場所」に復活するため、これらの拾えるポイントを事前に覚えておけば、毎日これらのポイントを周回することでコツコツと集めることができます(例えば「5ばんどうろ」の橋の上や「エンジンシティはずれ」の橋の上、ヨロイじまの海上など)。
条件についてより厳密には、日付の切り替え+マップ切り替え(そらとぶタクシー含む)の条件2つを満たすと復活するため、巣穴が近くにある場合には、いわゆる「日付バグ」との併用で無限に回収し続けることができます。
手動でやる場合は、ヨロイじまの「ワークアウトのうみ」の岩(一礼野原の駅を出て目の前に見える海上の岩)がおすすめです。岩場を1周するだけで羽が集められ、ポケモンの巣穴もあるため日付変更ペナルティの回避もできます。前述の通り羽の落ちている場所は常に一定なので、場所を覚えれば効率的に回収できます。
ランクマバグで効率的な日付変更が可能に
前回の記事でも紹介しましたが、ランクマッチ1戦の直後や、YY通信のカジュアルバトルで機内モードに変更した際に、日付変更ペナルティが解除されるバグ(通称:ランクマバグ)があります。これを活用することで、短い時間で場所を選ばず効率的に日付変更ができるようになります。
なお、ランクマッチを使用しない方法での「ランクマバグ状態」移行は下記手順でできます。画像は過去記事の使いまわしです。あしからず。
- YY通信で「通信対戦」を行う(ローカル通信)
- もう一台のSwitch・剣盾を使ってその通信対戦に応じる
- 戦闘が始まったらHomeボタン長押し→「機内モード」をONに変更する
- エラーが発生するのでそれを閉じて、「にげる」選択
- フィールド画面に戻ってくる(ランクマバグ状態に移行完了)
羽集めの自動化は「5番道路」が最適
前述の通り、羽を集めるには、大きく「日付変更+マップ切り替え」と「羽を拾う動作」の2つを繰り返す必要があります。自動化する上で、この「日付変更+マップ切り替え」が結構な曲者です。
上記でおすすめした「ワークアウトのうみ」では、近くに「そらとぶタクシー」で移動できるポイントがあるため都合が良いのですが、海上に位置するため、道中、ポケモンに遭遇する可能性が高いです。具体的には、サメハダーに襲われたりタマンタが跳ねてきたり、他にもキャモメが空を飛んでいたりなどで不意な戦闘が発生するため、一定の動きでプログラミングしてしまうと、ループが途切れてしまいます。
そこで、羽集めの自動化には、「そらとぶタクシー」で近くにアクセスできて、ポケモンとの遭遇がほぼ発生しない「5番道路」を活用します。
「そらとぶタクシー」でこれらが選択できるよう、あらかじめ「5番道路」のキャンプ場と「預り屋さん」に足を運んでおきましょう。
ちなみに、5番道路を活用することで「DLCが不要」 という副次的なメリットもあります。剣盾ビギナーの方にはそういう意味でもおすすめと言えます。
自動化プログラムの使い方
今回のプログラム(ソースコードは後述の通り)は、上記の通り5番道路で羽集めを自動で行うものです。できるだけ効率化を図るため、下記条件で動くようにしました。
この状態でArduinoを挿すと、「日付変更⇒そらとぶタクシーで預り屋に移動⇒10枚の羽を拾う」をひたすらループしてくれます。
- ランクマバグ状態であること
- そらとぶタクシーで「5ばんどうろ」「あずかりやさん」が選択可能なこと
- 「話の速さ」が「はやい」になっていること
- Xボタンでメニューを開いた時に「タウンマップ」にカーソルが合うこと
- 5番道路で自転車に乗っていること
ランクマバグ状態・5番道路で自転車に乗ってArduinoを挿すだけの簡単仕様です。
2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済(詳細はこちら)
2022/10/23追記:NintendoSwitch Ver.15.0アップデート対応済
※Switch Liteをご利用の方は「#define SWITCH_VER (15)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。ただし、未検証です。
#include <SwitchControlLibrary.h>
#define HOLDTIME (95)
#define SWITCH_VER (15)
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() {
NextDayInCheatMode();
PushKey("X", HOLDTIME, 700);
PushKey("A", HOLDTIME, 2700);
TiltLeftStick( 45, 1.0, 50, 170);
PushKey("A", HOLDTIME, 650);
PushKey("A", HOLDTIME, 3500);
TiltLeftStick( 93, 1.0, 3000, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 72, 1.0, 1950, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 103, 1.0, 1460, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 105, 1.0, 1250, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 59, 1.0, 750, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 100, 1.0, 2690, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 63, 1.0, 1620, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 120, 1.0, 1950, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 69, 1.0, 1800, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
TiltLeftStick( 125, 1.0, 900, 500);
PushKey("A", HOLDTIME, 100);
PushKey("B", HOLDTIME, 100);
PushKey("B", HOLDTIME, 300);
delay(1000);
}
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;
}
void NextDayInCheatMode(){
PushKey("Home", HOLDTIME, 1000);
PushKey("down", HOLDTIME, 105);
PushKey("right", HOLDTIME, 105);
PushKey("right", HOLDTIME, 105);
PushKey("right", HOLDTIME, 105);
PushKey("right", HOLDTIME, 105);
PushKey("right", HOLDTIME, 105);
PushKey("A", HOLDTIME, 1500);
PushKey("down", 1500, 105);
PushKey("right", HOLDTIME, 105);
#if (SWITCH_VER >= 15)
PushKey("down", 750, 55);
#elif (SWITCH_VER >= 13)
PushKey("down", 780, 55);
#else
for(int i=0; i<4; i++){
PushKey("down", HOLDTIME, 55);
}
#endif
PushKey("A", HOLDTIME, 500);
PushKey("down", HOLDTIME, 105);
PushKey("down", HOLDTIME, 105);
PushKey("A", HOLDTIME, 500);
PushKey("right", HOLDTIME, 105);
PushKey("right", HOLDTIME, 105);
PushKey("up", HOLDTIME, 105);
PushKey("A", HOLDTIME, 105);
PushKey("A", HOLDTIME, 105);
PushKey("A", HOLDTIME, 105);
PushKey("A", HOLDTIME, 105);
PushKey("Home", HOLDTIME, 2000);
PushKey("A", HOLDTIME, 1000);
return;
}
日付変更処理部分を関数にしたので、loop()の中が多少読みやすくなりました。
あとがき
今回の記事では、対応する努力値を「1」だけ増やすことができる、いわゆる「羽系アイテム」の自動回収について紹介しました。
前回の「【Arduino自動化10】きのみ・ぼんぐり自動回収」を使えば、対応する努力値を「10」下げられるので、これらを併用することで、努力値調整がかなり簡便に行えるようになりました。
さらに、技レコードやミント、各種カプセルなどは、それぞれ「ワット(【Arduino自動化03】ワット稼ぎ・自動回収)」、「バトルポイント(【Arduino自動化08】バトルタワー自動周回【BP稼ぎ】)」や「マックスこうせき(【Arduino自動化06】完全放置「マックスこうせき」集め)」で引き換えられるため、今までのものも含めて育成環境の整備がしっかりとできるようになってきたかな、と感じています。
アイテムなどの回収作業をArduinoで自動化でき、さらに副次的に、育成論の検討や対戦に時間を割けるようになるのは、まさに一石二鳥なのではないかと思います。皆様のプレイスタイルに応じてうまくご活用いただければ幸いです。
ではではc⌒っ.ω.)っ
前記事:【Arduino自動化10】きのみ・ぼんぐり自動回収
導入記事:【Arduino自動化01】Arduino開発環境の導入
次の記事:【Arduino自動化12】全自動タマゴ受け取り&孵化