【Arduino自動化17】ふしぎなおくりもの受け取り【あいことば自動入力】

ますたーです。こんにちは。

今回の記事では「ふしぎなおくりもの」での『あいことば』(シリアルコード)による受け取りを自動化します。

 

Arduino自動化記事はこれで第17回。これからもよろしくお願いします。

 

なお、Arduino Leonardo自動化の導入・機材構成については導入記事を参考にしてください。

導入記事:【Arduino自動化01】Arduino開発環境の導入

※本ブログに初めてお越しの方は「本ブログについて」もぜひ、ご覧ください。

 

概要

「ふしぎなおくりもの」の「シリアルコードで受け取る」を自動で行います。

f:id:tangential_star:20210226230616g:plain
f:id:tangential_star:20210226225427p:plain
シリアルコード(あいことば)の入力から受け取りまでを全部自動で行ってくれる

f:id:tangential_star:20210226234312g:plain

幻のポケモンゲットチャレンジ」など、10個以上の『あいことば』もまとめて入力できる
(注)「幻のポケモンゲットチャレンジ」はすでに終了しています

 

では、もくじです。

今回も余談が多めなので、ソースコードだけ欲しい方は⇒読み飛ばす

 

2021年2月27日は「赤・緑」発売から25周年の「ポケモンデー」

いきなり余談をはさみますが、ポケモンの最初の作品「赤・緑」が発売されたのは、今からちょうど25年前の、1996年2月27日でした。つまり、本日2021年2月27日は「ポケモン赤・緑発売25周年」となります。おめでとうございます!!

実は、昨年2020年には、株式会社ポケモンにより、2月27日を「ポケモンデー」として、記念日として制定(日本記念日協会が認定)されています。つまりは、今年の2月27日は発売25周年「ポケモンデー」となるわけですね。

f:id:tangential_star:20210226232259j:plain
f:id:tangential_star:20210226232303j:plain
「Pokémon Day」のロゴとポケモン一般社団法人 日本記念日協会のHPより引用)

 

「うたうを覚えたピカチュウ」を受け取ろう

明日2021年2月28日(日)には、ポケモン25周年を記念したバーチャルコンサートが開催されます。これを記念して、2021年2月27日現在、ポケモン剣盾では、「うたう」を覚えた特別なピカチュウがプレゼントされています(期日:3月25日(木)23時59分まで)。

f:id:tangential_star:20210226233517j:plain
f:id:tangential_star:20210226233513j:plain
Post Malone氏によるポケモン25周年記念コンサートの開催案内と、配信されるピカチュウ
ポケモン公式サイトの記事(2021.2.19掲載)より画像引用)
f:id:tangential_star:20210227000103p:plain
f:id:tangential_star:20210227000107p:plain
「うたう」を覚えていて、夢特性ひらいしん」のピカチュウ

プレゼント方法は、剣盾「ふしぎなおくりもの」の「あいことば」を使った配信です。

ちなみに、今回のピカチュウを受け取るための「あいことば」は「P25MUS1C」です。まさに「ポケモン25周年コンサート」を表すあいことばですね。

 

準備(プログラムの使い方など)

ここからが本題です。

「あいことば」をプログラムに書き込もう

今回のArduino自動化では、「あいことば」の入力から受け取りまでを自動で行います。入力する『あいことば』を予め準備しておきましょう。

プログラム上では、serial_code[][32]に書き込みます。

具体的には、今回のあいことばが「P25MUS1C」なので、これを半角のダブルクオートで囲み、最後に半角のカンマをつけて記入してください(例⇒ "P25MUS1C", )。「"P25M US1C",」のように、区切りの半角スペースを挟んでもしっかり動きます。

char serial_code[][32] = {
   "P25MUS1C", // ポケモン25周年記念ピカチュウのコマンド
    "" // ←この行は残してください(ループの判定に使うため)
};

余談ですが、剣盾のキーボードでは「Z(ゼット)」「I(アイ)」「O(オー)」はそれぞれ数字の「2」「1」「0」と間違えやすいため使われません。

このプログラムでは上記表記ミスにも対応できるように作ったつもりです。例えば、誤って「P25 MUSIC」などと記入しても動くはずなので、各人が読みやすい方法で記入してください。

f:id:tangential_star:20210227011924g:plain

プログラムに書き込むことで、「P25MUS1C」の入力が自動で行える

ちなみに、キャンペーンによっては、1つのキャンペーン中に複数(10程度)の『あいことば』が発行される場合があります(例えば、いずれもすでに期間は終了していますが「幻のポケモンゲットチャレンジ」「サトピカゲットキャンペーン」など)。このプログラムでは複数の「あいことば」の入力にも対応可能ですので、『あいことば』を複数serial_code[][32]の中に記入することで全部続けて入力できます。

 

// 例:「サトピカゲットキャンペーン」の『あいことば』
char
serial_code[][32] = { "P1KACHUGET", "P1KAADVANCE", "V0LTTACKLEP1KA", "P1KABESTW1SH", "KAL0SP1KA", "ULTRAP1KA", "K1NP1KA1855", "1CH00SEY0U", "" // ←この行は残してください(ループの判定に使うため) };

1つのシリアルならいざ知らず、複数のシリアルコード(あいことば)を入力する場合には、特にサブロムを持っている人などは重宝すると思います。

YY通信でオンライン接続し、カーソルを「ふしぎなおくりもの」に合わせる

次に、ゲーム本編での準備ですが、まず、YY通信で「インターネットに接続」をしてください。フィールド画面でYボタン⇒+ボタンで接続できるはずです。そして、Xボタンでメニューを開いた時に「ふしぎなおくりもの」にカーソルが合うようにしたら、Bを押してフィールド画面にもどってください。以上、わずか2ステップで準備完了です。

あとは、フィールド画面でArduinoを挿すだけ。簡単ですね。

f:id:tangential_star:20210227011003p:plain
f:id:tangential_star:20210227011009p:plain
準備は「インターネット接続」「カーソルを『ふしぎなおくりもの』に合わせる」だけ

 

ソースコード

プログラムにはポケモン25周年コンサート記念の「うたうピカチュウ」のシリアルコード(P25MUS1C)が入力されています。必要に応じて書き換えて使用ください。

なお、予めインターネットに接続した状態で、メニュー開いた際に「ふしぎなおくりもの」にカーソルが合う状態で、Arduinoを挿すだけで動きます。

 

/* 
 *  自動でふしぎなおくりもののシリアルコードを入力して受け取ってくれるやつ。
 *  
 *  Xボタンでメニューを開いた時に「ふしぎなおくりもの」にカーソルが合うこと。
 *  YY通信がオンラインになっている状態(予めインターネット接続するため)でArduino差し込むだけ!
 *  (c) 2021 ますたーの忘備録
 *  https://tangential-star.hatenablog.jp/
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95) // 1回のキー入力の長押し時間

// ★ここに受け取りたい文字列を入力(半角・ダブルクオートで囲み、最後は半角カンマ,で改行)
char serial_code[][32] = {
   "P25MUS1C", // ポケモン25周年記念ピカチュウのコマンド
    "" // ←この行は残してください(ループの判定に使うため)
};


void PushRL(int delay_time_ms);
int PushKey(char* keyname, int holdtime, int delaytime);
void NextDayInCheatMode(void);

void input_serial(char*);

void setup() {
  // コントローラーとして認識されるためにRLを7回ほどカチャカチャする
  for(int i=0;i<7;i++)PushRL(300);
  delay(1000);
}

void loop() {
  int i=0;
  PushKey("X", HOLDTIME, 500);  // メニューを開いて
  PushKey("A", HOLDTIME, 1500); // ふしぎなおくりものを選択
  PushKey("A", HOLDTIME, 500);  // ふしぎなおくりものを受け取る

  // シリアルコード列が終わるまで受け取り続ける
  for(i=0; strcmp(serial_code[i],"") != 0 ;i++){
    
    PushKey("down", HOLDTIME, 120);
    PushKey("down", HOLDTIME, 120);
    PushKey("A", HOLDTIME, 1100);  // 警告画面が出る
    PushKey("A", HOLDTIME, 1500);  // Aを押さないと進まない

    // キーボード起動
    input_serial(serial_code[i]);  // シリアルを入力

    PushKey("+", HOLDTIME, 7000);  // +で確定⇒ギフトを探しています…

    PushKey("A", HOLDTIME, 5000);  // Aで受け取り⇒本当は21秒待機

    // 失敗した場合のケア(もう一度入力しますか?)
    PushKey("Down", HOLDTIME, 16000);

    PushKey("A", HOLDTIME, 1000);    // ▼
    
  }

  PushKey("B", HOLDTIME, 500);  
  PushKey("B", HOLDTIME, 500);  
  PushKey("B", HOLDTIME, 500);  
  PushKey("B", HOLDTIME, 500);  
  PushKey("B", HOLDTIME, 500);  
  for(;;) delay(100); // プログラム終了

}

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){
  // ホームボタン・方向キーはRight, Left, Up, Down, Homeなど2文字以上で入力。
  // その他ボタン入力は1文字(A,B,X,Y,R,L,+,-)ZR・ZLにも対応
  // 同時押しは非対応
  
  if(strlen(keyname)==1){
    switch(keyname[0]){
      case 'A': case 'a': // A
        SwitchControlLibrary().PressButtonA(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonA(); delay(delaytime);
      break;
      case 'B': case 'b': // B
        SwitchControlLibrary().PressButtonB(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonB(); delay(delaytime);
      break;
      case 'X': case 'x': // X
        SwitchControlLibrary().PressButtonX(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonX(); delay(delaytime);
      break;
      case 'Y': case 'y': // Y
        SwitchControlLibrary().PressButtonY(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonY(); delay(delaytime);
      break;
      case 'L': case 'l': // L
        SwitchControlLibrary().PressButtonL(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonL(); delay(delaytime);
      break;
      case 'R': case 'r': // R
        SwitchControlLibrary().PressButtonR(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonR(); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      break;
      case '+': case 'p': case 'P': // Plus
        SwitchControlLibrary().PressButtonPlus(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonPlus(); delay(delaytime);
      break;
      case '-': case 'm': case 'M': // Minus
        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': // ZR/ZL
        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': // right
        SwitchControlLibrary().MoveHat(2); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'l': case 'L': // left
        SwitchControlLibrary().MoveHat(6); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'u': case 'U': // up
        SwitchControlLibrary().MoveHat(0); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'd': case 'D': // down
        SwitchControlLibrary().MoveHat(4); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().MoveHat(8); delay(delaytime);
      break;
      case 'H': case 'h': // Home
        SwitchControlLibrary().PressButtonHome(); delay(holdtime);
        if(holdtime>0)SwitchControlLibrary().ReleaseButtonHome(); delay(delaytime);
      default:
      break;  
    }
  }else{
    return -1;
  }
  return strlen(keyname);
}
void NextDayInCheatMode(){
  // ★日付変更
  // Homeボタンを押して設定の画面へ移動
  PushKey("Home", HOLDTIME, 1000);

  // Home画面で「設定」を選ぶ
  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); // 1.5秒「↓」長押し
  PushKey("right", HOLDTIME, 105); 

  for(int i=0; i<4; i++){
    PushKey("down", HOLDTIME, 55);
  }
  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;
}

void input_serial(char *str){
  char keyboard[4][15]={
    "1234567890@",
    "QWERTYUIOP=",
    "ASDFGHJKL&;",
    "ZXCVBNM*#!?"
  };
  int cur_x=0, cur_y=0; // 現在カーソル位置
  int x,y; // 目標キーボード位置
  int i=0;
  char *p;

  // ★すべて大文字に変換
  toupper(str);

  // ★剣盾のキーボードはZ,I,Oは不使用(それぞれ2,1,0に置き換え)
  for(i=0; str[i]!='\0' ;i++ ){
    switch(str[i]){
      case 'Z':
        str[i]= '2';
        break;
      case 'I':
        str[i]= '1';
        break;
      case 'O':
        str[i]= '0';
        break;
      default:
        break;
    }
  } 

  // ★入力する文字列strを1文字ずつ処理
  for(i=0; str[i] != '\0' ; i++ ){

    // 空白文字は読み飛ばし(例:"P25M US1"みたいなやつ)
    if(str[i] == ' ' ) continue;

    // キーボードから該当文字を検索(x,yを決定)
    for(x=0; x < 4 ; x++){
       p = strchr(keyboard[x], str[i]);
       if( p == NULL){ continue;
       }else{
         for(y=0; keyboard[x][y] != *p ; y++);
         break;
       }
    }
    delay(100);
    // y(左右位置)
    if(cur_y != y){
      for( ; cur_y < y ; cur_y++) PushKey("Right", HOLDTIME, 150);
      for( ; cur_y > y ; cur_y--) PushKey("Left", HOLDTIME, 150);
    }
    // x(上下位置)
    if(cur_x != x){
      for( ; cur_x < x ; cur_x++) PushKey("DOWN", HOLDTIME, 150);
      for( ; cur_x > x ; cur_x--) PushKey("UP", HOLDTIME, 150);
    }
    // 入力
    PushKey("A", HOLDTIME, 150);
  }
  

  return;
}

f:id:tangential_star:20210227012752g:plain

動作確認(再掲)。自動でふしぎなおくりものを開き、受け取ってくれる


あとがき

今回は、ポケモン25周年ということで、記念して配布されている「うたうを覚えた特別なピカチュウ」をArduinoで受け取りました。

Arduino自動化の記事と言いつつ、まずはポケモンのファンとして、心の底から25周年をお祝いします

自身が初めて出会ったポケモン作品が「金・銀」で、そこから遡る形で「赤・緑」も遊び、今に至るまでにポケモン本編作品についてはほぼすべてを遊んできました。どの作品にも思い入れがありますが、これだけシリーズを通してのめり込めたゲームは「ポケモン」だけです。自分の人生はポケモンとともにあった、と言っても過言で無い気もします。

そして、その遊び方も、「図鑑集め」「コンテスト制覇」「リボン集め」「育成・対戦」「ポケモンとの触れ合い」「色違い厳選」など、ずっと飽きることなく、たくさん広がりました。そして、ポケモン剣盾では、新たな遊び方として「Arduino自動化」が加わったような形です。

私にとってポケモンは、かけがえの無いゲームで、遊びごたえもキャラクタ性も、シナリオも全部が全部、大好きなのです。この25周年という節目の日に、こうやってブログで気持ちをしたためることができるのも、本当に光栄ですし、これからのポケモンの作品も楽しみで仕方がありません。

そういう意味では、ちょうど今日未明に新作「ブリリアントダイヤモンド」「シャイニングパール」のティザームービーも公開されましたが、今から発売日(2021年冬)が待ち遠しくてしょうがないです。25年分のワクワク、しっかりと温めておきたいです。

なにはともあれ、改めてポケモン25周年、おめでとうございます。

 

さて、話がだいぶ逸れました。

皆様のポケモンライフが、あるいはArduino自動化ライフが、このブログにより一助となれば幸いです。ではではc⌒っ.ω.)っ

 

前記事:【Arduino自動化16】自動ミラクル交換(ID集めほか)

導入記事:【Arduino自動化01】Arduino開発環境の導入