こんにちは。ますたーです。
今回は、レジェンズアルセウスのガチグマライド(道具掘り)を自動化しました。
リングマやストライクの進化に使う「ピートブロック」「くろのきせき」を完全放置で集めることができます。
なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。
導入記事:【Arduino自動化01】Arduino開発環境の導入
※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。
概要
天冠の山麓で、ガチグマでの宝掘り(宝探し)を自動で行います。実績値として、12時間放置で「ピートブロック」13個、「つきのいし」12個、「くろのきせき」9個が手に入りました。特に「ピートブロック」はガチグマライドでしか手に入らないので、ぜひともお役立てください。
目次です。今回はガチグマ宝探しの解説記事っぽくなりました。
ソースコードだけほしいという方は→ソースコードまで読み飛ばす。
ガチグマの進化のために「ピートブロック」がほしい!
まずは、レジェンズアルセウスで追加された進化アイテム「ピートブロック」について紹介です。
ピートブロックは「リングマ」が「ガチグマ」に進化するために使うアイテムです。満月の日にリングマに「ピートブロック」を与えることで進化するという、稀有な進化条件を持ちます。肝心の「ピートブロック」は、+ボタンで呼び出せるライドポケモンの「ガチグマ」による「宝探し」でのみ入手できます*1。
ピートブロックは天冠の山麓で掘り出せる
ガチグマは、近くにあるお宝の匂いを感知し、その方向をプレイヤーに教えてくれます。今までのシリーズで言う、ダウジングマシンですね。
天冠の山麓では、ガチグマライドで低確率ながら、ピートブロックを掘り起こすことができます。他にも「つきのいし」「くろのきせき」などの進化アイテムもランダムで掘り出すことができます。確率は、それぞれ約5%です*2。
なお、掘り起こせる場所(ポイント)は、コトブキムラから天冠の山麓に向かうたびにランダムに決まるため、根気よく探す必要があります。
宝を掘り出せる場所はランダム5パターン
ガチグマライドは、コトブキムラから出入りする度に、宝探しで掘り出せるアイテムの種類はもちろん、掘り出せる場所もランダムで変わることが挙げられます。すなわち、アイテムを掘り出した場所を覚えておいて、コトブキムラに一度帰ってからその場所にもう一度向かっても、同じ場所で掘り出せない場合がある、ということです。
そこで、場所も完全にランダムなのかを検証すべく「コトブキムラに戻る」「山頂ベースすぐの宝を掘る」という一連の動作を242試行繰り返しました。結果、筆者にて検証を行い、おそらく5パターンでランダムに変わっていることが確認できました。
したがって、コトブキムラから出入りした後、これら5パターンを見て回れば、宝掘りを見逃さずに済みます。
天冠の山麓で掘り出せるアイテムは12種類!
さて、宝掘りができる位置が5パターンでランダムになることは前述の通りですが、アイテムとしては何が拾えるのか、という点も要確認です。
筆者にて12時間(233試行)で掘り出したアイテムを集計したところ、下記12種類となりました。括弧内の数字はアイテムの個数です。
- たまいし(280個)
- てつのかけら(260個)
- どろだんご(260個)
- そらいろたまいし(200個)
- くろいろたまいし(200個)
- ごりごりミネラル(165個)
- スイートトリュフ(81個)
- ほしのかけら(20個)
- ピートブロック(13個)
- つきのいし(12個)
- くろのきせき(9個)
- たいようのいし(7個)
興味深いことに、ガチグマが掘り出す確率が最も高いのは「どろだんご」でしたが、集めたアイテムの個数が多くなったのは「たまいし」でした。設定確率と比して、1回あたりに拾ってくる個数により体感できる入手効率が大きく異なるといえます。また、今回の目玉である「ピートブロック」は13個も入手することができました。すなわち、単純計算で1時間あたり1個入手できることになります。
他にも、「くろのきせき」や「たいようのいし」「つきのいし」などの貴重な進化アイテムも複数入手できました。ガチグマライドによるピートブロック集めは、副次的にも「美味しい」と言えます。
自動化の準備
さて、おまたせしました。自動化の準備です。
本自動化では、ガチグマに乗り降りするので、ライドポケモンのカーソルをガチグマに合わせた状態にしておいてください。事前の準備としてはそのくらいです。また、場所は「天冠の山麓」マップ内なら、基本的には不問です。
注意すべき点は「-ボタン」でマップを開いてXボタンから移動(ファストトラベル)を行うので、ポケモンに索敵されていない状態でArduino Leonardoを差し込む、ということです(マップから移動ができなくなるため)。
今回は「天冠の山麓」でのガチグマライドの自動化です。
天冠の山麓の内部で、ライドポケモンの選択カーソルがガチグマに合っている状態でArduinoを挿せば自動で「山頂ベース」まで移動してガチグマに乗って収集を始めてくれます。5箇所を巡って確認し終わったら自動でコトブキムラに戻って周回してくれます。
#include <SwitchControlLibrary.h>
#define HOLDTIME (95)
const int SANROKU = 0;
const int SANCHU = 1;
const int SANCHO = 2;
const int GEIGETSU= 3;
const int HOMBU = 0;
const int OMOTEMON = 1;
const int YAGAI = 2;
const int NOUJO = 3;
const int KUNRENJO = 4;
const int KOTOBUKI = 1;
const int KOKUYO = 2;
const int GUREN = 3;
const int GUNJO = 4;
const int TENGAN = 5;
const int JUMPAKU = 6;
const int INISHIE = 7;
bool isFirstLoop = true;
void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void TiltLeftStick(int direction_deg, double power,unsigned long int holdtime, unsigned long int delaytime);
void Die(void);
void JumpTo(int destination){
int i=0;
PushKey("-", HOLDTIME, 1200);
PushKey("X", HOLDTIME, 1000);
for(i=0; i<destination; i++)PushKey("down", HOLDTIME, 250);
PushKey("A", HOLDTIME, 3300);
return;
}
void Turn(int degree){
TiltLeftStick( degree, 0.3, 140, 300);
PushKey("ZL", HOLDTIME, 1000);
return;
}
void Dash(double second){
TiltLeftStick( 0, 1.0, second*1000UL, 300);
return;
}
void Dash(double second, double second_interruptA){
TiltLeftStick( 0, 1.0, 0, second_interruptA*1000UL);
PushKey("A", HOLDTIME, (second - second_interruptA)*1000UL );
TiltLeftStick( 0, 0.0, 0, 300);
return;
}
void PokeThrow(int delaytime=300, int holdingballtime = 250){
SwitchControlLibrary().PressButtonZR(); delay(holdingballtime);
SwitchControlLibrary().ReleaseButtonZR(); delay(delaytime);
return;
}
void RidePoke(void){
PushKey("+", HOLDTIME, 1200);
return;
}
void Dig(void){
PushKey("Y", HOLDTIME, 400);
return;
}
void DashBack(void){
TiltLeftStick( 180, 1.0, 3500, 300);
PushKey("B", HOLDTIME, 300);
return;
}
void BackToJubilifeVillage(void){
JumpTo(SANCHO);
TiltLeftStick( 48, 1.0, 900, 300);
PushKey("A", HOLDTIME, 900);
PushKey("A", HOLDTIME, 700);
PushKey("A", HOLDTIME, 700);
PushKey("down", HOLDTIME, 350);
PushKey("A", HOLDTIME, 1200);
PushKey("A", HOLDTIME, 12000);
return;
}
void GotoCoronetHighlands(void){
int i=0;
JumpTo(OMOTEMON);
TiltLeftStick( 23, 1.0, 2000, 500);
PushKey("A", HOLDTIME, 1200);
if(isFirstLoop){
TiltLeftStick( 0, 1.0, 1700, 500);
for(i=0; i<TENGAN; i++)PushKey("down", HOLDTIME, 250);
}
PushKey("A", HOLDTIME, 600);
for(i=0; i<SANCHO ; i++)PushKey("down", HOLDTIME, 250);
PushKey("A", HOLDTIME, 12000);
return;
}
void setup() {
for(int i=0; i < 5 ; i++)PushKey("B", HOLDTIME, 700);
}
void loop() {
if(isFirstLoop)JumpTo(SANCHO);
Turn(169);
Dash(15.8, 9.63);
RidePoke();
Dig();
DashBack();
JumpTo(SANCHO);
Turn(177);
Dash(16.9);
RidePoke();
Dig();
TiltLeftStick( 180, 1.0, 1600, 300);
Dig();
DashBack();
JumpTo(SANCHO);
Turn(189);
Dash(18.4, 16.64);
RidePoke();
Dig();
DashBack();
JumpTo(SANCHO);
Turn(202);
Dash(15.2);
RidePoke();
Dig();
TiltLeftStick( 180, 1.0, 13000, 2800);
BackToJubilifeVillage();
GotoCoronetHighlands();
isFirstLoop = false;
}
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,unsigned long int holdtime, unsigned long 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 Die(void){
for(;;)delay(100);
}
あとがき
お久しぶりですね!!(20日ぶり)
今回は、レジェンズアルセウスの自動化にチャレンジしてみました。今回は自動化の第1弾として「ガチグマライドによる宝探し」を題材にしてみました。
もともと「ピートブロック」など、入手方法が限られており、かつ、その確率も低く設定されているこれらについては、手動では「周回作業」としての側面が拭えず、これを自動化した次第です。結果として、シンプルながらも非常にパワフルな自動化になったのではないか、と考えます。
また、世の中的にも、ガチグマライドを攻略・解説した記事はほとんど無く、詳しい掘り出しポイント・確率についても自分で調べて、結構やりがいがありました(笑)
個人的に、やっぱり自動化のソースコードだけじゃなく、こういう雑談的な基礎研究的な部分も入れていきたいなと思ってしまいます(凝り性ですかね)。
このブログも、マイペースながらも、自分が「楽しい」と思えたことを交えてこれからも更新していけたらと思いますので、引き続きよろしくお願いいたします。
*
それにしても、レジェンズアルセウスは本当に神ゲーですね。総じて「ポケモンの世界そのもの」を体感できる素晴らしいゲームで、ついつい時間を忘れて没頭して楽しんでしまいます。
私自身、もともとオープンワールド系のゲームは馴染みがなく、楽しめるかが不安だったのですが、まさかこれほどハマるとは、自分でも予想できなかったです。
第9世代(ポケモンSV)もまさかのオープンワールド形式とのことでしたし、これが2022年度内に発売される、というのは本当に驚きと喜びと期待でいっぱいです。
スマホ用ゲーム「ポケモンマスターズEX」も2.5周年を迎えてますます勢いづいて来ましたし、BDSPではシェイミ・アルセウスイベントの解禁も来ましたし、本当にポケモンをこうして楽しめることを嬉しく思います。
これからも引き続きポケモンと永く遊んでいけたらと思いますし、その折、本ブログも更新していけたらと思います。
これからもどうぞよろしくお願いいたします。
ではではc⌒っ.ω.)っ
導入記事:【Arduino自動化01】Arduino開発環境の導入
ポケモン剣盾の記事:ポケモン剣盾Arduino自動化 カテゴリーの記事一覧
ポケモンBDSPの記事:ダイパリメイクArduino自動化 カテゴリーの記事一覧
YouTubeチャンネル:ますたーの忘備録 - YouTube
---