【Arduino自動化03】ワット稼ぎ・自動回収

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

3つ目の記事では、n番煎じ感は否めませんが、日付バグによるワット自動回収Arduino Leonardoで自動化していきます。DLC含め大量のワットを消費する機会が増えたので、重宝すると思います。

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

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

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

 

概要

本記事では、日付バグの併用による巣穴の2,000Wの無限回収を実装します。
2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済です。
2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済です。

f:id:tangential_star:20201108131008g:plain

Arduino Leonardoを挿すだけで無限にワット回収ができる。

 

今回の目次です。かなりシンプルです。

 

作ったきっかけ

DLC第1弾「鎧の孤島」でのミツバへのワット貢ぎイベントや、前の記事でも取り上げた、DLC第2弾「冠の雪原」のワットショップの高額目玉商品など、シナリオに直結しない部分で使うワット数が増えたため、気軽に使えるワット回収スクリプトが欲しいと思ったので作りました。

また、先駆者の作成ソースコードは、プログラミング負荷軽減のため、仕様が制限されていて「1月1日に日付変更してから使うこと」「31日ある月で使うこと」「年を更新するタイプ」など、私の「気軽に使いたい」ニーズに応えるものではなかったので作りました。

 ※気軽に使いたい=巣穴に「ねがいのかたまり」入れてArduino挿すだけ!

 

使い方

至ってシンプルで、巣穴に「ねがいのかたまり」を投げ入れ、柱を立てたらそのままAを押して「みんなで挑戦」を押す手前の状態でArduino LeonardoをSwitchに挿すだけで使えます。

なお、挿して3~5秒ほど、何度かHomeボタンが押されるような挙動は仕様です。

挿してから数秒後、5秒ほどなんの操作もしていない時間がありますが、このタイミングでHome画面(Switchでゲームを選ぶ画面)になっていればOKです。もし、なっていなければ手動で1度Homeボタンを押しておいてください。

事前準備

正しく動作するための条件は下記の通りです。

  •  ポケモン剣盾側の設定
    • 巣穴に手動で柱を立てておく(近くに草むらなどが無い場所が良い)
  • NintendoSwitch側の設定
    • Switch設定「時刻と時刻」の「インターネットで時間をあわせる」をOFF
    • インターネットには接続しない

 

書いたプログラム

処理フロー

  1. みんなで挑戦を押す
  2. Homeボタンを押して「設定」へ
  3. 日付を1日進める
  4. Homeでゲームに復帰し、募集終了
  5. ワットを回収し、1へ戻る(ループ)

ソースコード

2020/12/5追記:NintendoSwitch Ver.11.0アップデート対応済(変更点はこちら

2021/9/20追記:NintendoSwitch Ver.13.0アップデート対応済(詳細はこちら
※Switch Liteをご利用の方は「#define SWITCH_VER (13)」を「#define SWITCH_VER (12)」に書き換えてご利用ください。

/* ★NintendoSwitchのファームウェアVer11に対応版(2020/12/1)★
 * ★NintendoSwitchのファームウェアVer13に対応版(2021/9/20)★
 * ★自動ワット稼ぎ★
巣穴に「ねがいのかたまり」を投げ入れてA。
「みんなで挑戦」の手前でArduinoをSwitchに挿すだけ。
*/

#include <SwitchControlLibrary.h>

#define HOLDTIME (95)
#define INTERVAL (105)

#define SWITCH_VER (13)
// 2021/9/20、SwitchのVer13アップデートに伴う追記
// Switchのバージョンを整数で入力(例:12.2.1⇒12, 13.0.0⇒13)

void PushHome(int delay_time_ms);
void PushA(int delay_time_ms);
void PushB(int delay_time_ms);
void move_for(char* Direction); // ex: "right" "left" "up" "down"
void move_for(char* Direction, int delay_time_ms);
void move_for(char* Direction, int hold_time_ms, int delay_time_ms);

void setup() {
  
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(1000);
  PushHome(5000); // 5秒待つ
  PushHome(1000);

  delay(100);
}

void loop() {

  // 開始 みんなで挑戦の直前から。
  PushA(4000); // 通信待機中・・・
  
  // Homeボタンを押して設定の画面へ移動
  PushHome(1000);

  // Home画面で「設定」を選ぶ
  move_for("down");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  move_for("right");
  PushA(1500);

  // 設定画面で「日付と時刻」を開く
  move_for("down", 1500, (int)INTERVAL/4); // 「↓」長押し
  move_for("right");

#if (SWITCH_VER >= 13)
  // Switchのアプデで「ドックの更新」項目が追加されたので
  // 日付変更をする場合には「↓」キー長押しが必要に。
  move_for("down", (int)780, (int)INTERVAL/2); 
#else
  // ver12まで(13アプデ前)は、1ページに収まるのでそのままでOK
  for(int i=0; i<4; i++){
    move_for("down", (int)HOLDTIME/2, (int)INTERVAL/2);
  }
#endif
  PushA(500);

  // 時間設定(現在の日付と時刻を選ぶ)
  move_for("down");
  move_for("down");
  PushA(500);

  // 時刻設定(日付の部分のみ回していく
  // 時間の変更
  move_for("right");
  move_for("right");
  move_for("up");
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushA(INTERVAL);
  PushHome(2000);
  PushA(1000);
  // ↑ここまでで設定画面おわり。

  // 募集終了処理
  PushB(500);  // 「募集終了」を選択
  PushA(1000); // 「はい」
  PushA(4500); // 「はい」

  // ★フィールド画面に戻ってくる(watt回収)
  // There's energy pouring out from the den! [Enter]
  PushA(500);  // 1回目は「A」
  // You gained 2,000W! [Quit]
  PushB(2500);  // 2回目は「B」(日付が1日に戻った時との共通処理のため遅めに)
  // [Enter]
  PushA(1500);  // 3回目は「A」(募集画面に入る)

}

void PushHome(int delay_time_ms){
  SwitchControlLibrary().PressButtonHome();
  delay(210);
  SwitchControlLibrary().ReleaseButtonHome();
  delay(delay_time_ms);
  return;
}

void PushA(int delay_time_ms){
  SwitchControlLibrary().PressButtonA();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonA();
  delay(delay_time_ms);
  return;
}
void PushB(int delay_time_ms){
  SwitchControlLibrary().PressButtonB();
  delay(HOLDTIME);
  SwitchControlLibrary().ReleaseButtonB();
  delay(delay_time_ms);
  return;
}

void move_for(char* Direction){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(INTERVAL);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int delay_time){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(HOLDTIME);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time);
    break;

    default:
    break;  
  }
  
}

void move_for(char* Direction, int hold_time_ms, int delay_time_ms){
  // ex: "right" "left" "up" "down"
  
  switch(Direction[0]){
    case 'r':
    case 'R':
    SwitchControlLibrary().MoveHat(2); // right
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'l':
    case 'L':
    SwitchControlLibrary().MoveHat(6); // left
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'u':
    case 'U':
    SwitchControlLibrary().MoveHat(0); // up
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    case 'd':  
    case 'D':
    SwitchControlLibrary().MoveHat(4); // down
    delay(hold_time_ms);
    SwitchControlLibrary().MoveHat(8); // center
    delay(delay_time_ms);
    break;

    default:
    break;  
  }

}

 

f:id:tangential_star:20201108131008g:plain

動作例(再掲)


あとがき

今回は自動でワット回収ができるプログラムを紹介しました。

実は、このプログラムのみは、日本語版・英語版・中国語版(繁体字)で動作を確認済です。ソースコードのコメント行でゲーム中のセリフを英語で書いているのは、英語版の文字送り速度に合わせてDelay()の数値を調整したからなのです。
余談ですが、文字送り速度はゲーム中の設定から「早い 普通 遅い」と選べますが、同じ「早い」でも英語の「Fast」とは文字の送られる時間が違います(日本語や中国語のほうが短いです)。

理由は明白で、我々漢字圏の人は2バイト文字なので単純計算で英語版の文字送りの2倍速になるんですね(流石に2倍はないかもですが)。

日本語版でしかデバッグしていないArduinoでの自動化プログラムを英語版で使うと「あれ、なんで動作がズレるんだ?」となりますが、意外な落とし穴が文字送り速度に隠れているんですね(体験談)。

ちなみに、本ブログでは原則として日本語版でのみ動作確認したものしか載せません。ただ、もしかしたら、プログラム中の定数「INTERVAL」や「HOLDTIME」を増やすとうまく動くかもしれません。

 

余談が長くなってしまいました。

ではではc⌒っ.ω.)っ

 

前の記事:

【Arduino自動化02】雪中渓谷のワットショップの目玉商品を全自動回収【カンムリ雪原】

次の記事:

【Arduino自動化04】パッチルドン自動受け取り(中国語・英語対応)