【Twitter】ランパの台詞botを作成してみる その3

というわけで、今回は「ランパの台詞bot」制作その3です!
少しずつ作っていた台詞集ですが、ゲーム開始からエンディングまでの台詞を集め終わりました!

前回同様、改良点や苦労した点を載せていきます。
ちょっと長めの記事ですが、今回でほぼ完成までいけた・・・かと思います!

前回の記事は↓になります!

【Twitter】ランパの台詞botを作成してみる その2

ツイートした台詞を一定期間再ツイートしないようにする

かなりレパートリーは豊富になりましたが、それでも短期間に連続してツイートしてしまうことがあります。
以下は1月19日のツイートです。

種類が豊富なのに短期間で同じ台詞を言わせるのはいただけないです。
そんなわけで、1回ツイートした台詞は少し期間を空け、連続でツイートしないようにします。

これを実現するにはサーバ側でデータを取っておくか、過去のツイートを取得して判定するしかありみあせん。
幸い、WordPress 用に MySQL が入っているので、それを使ってサーバ側で判定してみます。
当初「台詞をデータベースで管理する」ことは想定していなかったので、台詞ごとにシーケンシャルなIDなんていいものはありません。
当然ながら一意に識別できるコードなんてものもありません。

そこで使用するのがハッシュ値を計算する md5() です!
これで台詞をハッシュ値に変換し、識別しやすい形に置き換えて保存します。
普通に台詞を格納するのも手ですが、最大130文字近くになる台詞がある上、マルチバイト文字をそのまま入れて比較・・・というのは避けたかったためです。

下準備として、データベースとテーブルを作成しておきます。
端末上から直接作ってしまいましょう。

CREATE DATABASE twitter_bot;

use twitter_bot;

CREATE TABLE rampa_tweet_history (
    id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
    message TEXT NOT NULL,
    create_date DATETIME NOT NULL
);

データベース名やテーブル名は適当です。
id は不要かもしれませんが、一応作っておきます。
create_date は一定期間以上経過した台詞を弾くために必要です。

前回作成したPHPファイルを修正していきます。
それなりに長くなりましたが、以下がソースになります!

<?php

require_once("twitteroauth-master/autoload.php");
require_once('twitteroauth-master/src/TwitterOAuth.php');

use Abraham\TwitterOAuth\TwitterOAuth;

/**
 * ランパの台詞集から台詞を抽出・ツイートするクラス
 */
class TwitterRampaBot {

    private $customer_key;
    private $customer_secret;
    private $access_token;
    private $access_token_secret;

    private $db_user = 'db_user';
    private $db_password = 'db_password';
    private $interval_spec = 'P3D';

    const file_path = 'rampa_serifu.txt';
    const max_tweet_len = 140;

    /**
     * コンストラクタ
     */
    public function __construct()
    {
        $this->customer_key = "customer_key";
        $this->customer_secret = "customer_secret";
        $this->access_token = "access_token";
        $this->access_token_secret = "access_token_secret";

        mb_internal_encoding('UTF-8');
    }

    /**
     * つぶやきを送信する
     */
    public function tweet()
    {
        $message = $this->getTweetWord();

        // 文字数チェック
        if (self::max_tweet_len < mb_strlen($message)) {
            trigger_error('ツイート可能な文字数を超えています。', E_USER_ERROR);
            exit;
        }

        // サーバにつぶやきを送信
        $connection = new TwitterOAuth($this->customer_key, $this->customer_secret, $this->access_token, $this->access_token_secret);
        $connection->post("statuses/update", array("status" => $message));
    }

    /**
     * ツイート用の文字列を取得・整形する
     *
     * @return string
     */
    private function getTweetWord()
    {
        // テキストファイルから文字列読み込み
        $input_lines = file(self::file_path);
        $words = array();

        // データベース接続
        try {
            $dsn = 'mysql:host=localhost;dbname=twitter_bot;charset=utf8';
            $pdo = new PDO($dsn, $this->db_user, $this->db_password);
        } catch (\Exception $e) {
            trigger_error('データベースへの接続に失敗しました。', E_USER_ERROR);
            exit;
        }

        // 先頭 # の行を取得するまでループ
        while (true) {
            $line_num = rand(0, count($input_lines));

            // 先頭が # で始まる行を抽出
            if (isset($input_lines[$line_num]) && preg_match('/^\# .*$/', $input_lines[$line_num])) {
                $words = array();

                // # 以降を場面として取得
                $scene = $this->excludeLineFeed($input_lines[$line_num]);
                $scene = str_replace('# ', '', $scene);

                // 複数行の台詞を全て取得するまでループ
                for ($i = $line_num + 1; ; $i++) {
                    // 文字列か空or改行コードのみの場合は終了
                    if (empty($input_lines[$i]) || preg_match('/^' . PHP_EOL . '$/', $input_lines[$i])) {
                        break;
                    }

                    $words[] = $this->excludeLineFeed($input_lines[$i]);
                }

                // 台詞と発言場面を設定
                $message = '';
                foreach ($words as $word) {
                    $message .= $word . PHP_EOL;
                }
                $message .= '【' . $scene . '】';

                // 台詞が一定期間内にツイートされているかチェック
                if (!$this->checkMessage($pdo, $message)) {
                    continue;
                }

                // ツイートする台詞を保存
                $this->insertMessage($pdo, $message);

                break;
            }
        }

        $pdo = null;

        return $message;
    }

    /**
     * 台詞がデータベース内に保存されているかチェックする
     *
     * @param PDO $pdo
     * @param string $message
     */
    private function checkMessage(PDO $pdo, $message)
    {
        $sql = 'SELECT count(id) FROM rampa_tweet_history WHERE message = :message AND create_date > :create_date';
        $date = new DateTime();
        $date->sub(new DateInterval($this->interval_spec));

        $pdo_stat = $pdo->prepare($sql);
        $pdo_stat->bindParam(':message', md5($message));
        $pdo_stat->bindParam(':create_date', $date->format('Y-m-d H:i:s'));
        $pdo_stat->execute();

        // ツイートされていた場合は台詞を再取得
        if (0 < $pdo_stat->fetchColumn()) {
            return false;
        }

        return true;
    }

    /**
     * 台詞をデータベースへ挿入する
     *
     * @param PDO $pdo
     * @param string $message
     */
    private function insertMessage(PDO $pdo, $message)
    {
        $sql = 'INSERT INTO rampa_tweet_history (message, create_date) VALUES (:message, :create_date)';
        $date = new DateTime();

        $pdo_stat = $pdo->prepare($sql);
        $pdo_stat->bindParam(':message', md5($message));
        $pdo_stat->bindParam(':create_date', $date->format('Y-m-d H:i:s'));
        $pdo_stat->execute();
    }

    /**
     * 指定した文字列から改行コードを除外する
     *
     * @param string $str
     * @return string
     */
    private function excludeLineFeed($str)
    {
        return str_replace(PHP_EOL, '', $str);
    }
}

$twitterRampaBot = new TwitterRampaBot();
$twitterRampaBot->tweet();

exit;

?>

※ツイートの取得や送信部分は前回の記事をご参照下さい。

MySQL への接続には PDO_MySQL を使用しました。
明確な理由はありませんが、ガチガチに書くわけでもないので、PDO が手っ取り早いかなーと。
仕事ではDB関連はフレームワークに任せてしまうので、別の意味で苦戦していたりもします。

ポイントは checkMessage() 内の処理です。
一定期間は interval_spec で定義し、P3D を設定しておきます。
これを DateTime::sub() で指定することで、「現在時間から3日前の日時」になります。
このあたりの指定方法は公式マニュアルに書いてあります。
http://php.net/manual/ja/dateinterval.construct.php

「データベース内に台詞が存在するか」だけ欲しいので、実行する SQL は「SELECT COUNT(id)」です。
execute() 実行後、fetchColumn() を実行することでレコード数を取得することができます。
あとは if で評価して真偽を返し、false であれば continue で再度台詞を取得します。true であれば台詞をハッシュ化してデータベースに保存します。

作りたての状態で実行すると、データベース接続が出来なかったり、日付型の比較でしくじったりするので、事前にテストを行うことをおすすめします。
端末上から直接PHPファイルを指定して実行すればOKです。
その場合、「サーバにつぶやきを送信」の部分をコメントアウトし、echo や var_dump() を使用しましょう。
テスト用として別ファイルで作ってしまうと安全です。

乱数の生成方法の変更

そもそもPHPの rand() はいろいろと問題があるようで、これを使用していること自体がまずいみたいです。
より良い乱数生成と数倍の速度を持つという mt_rand() で置き換えます。
使い方は変わらないようなので、本当に置き換えるだけ!

$line_num = mt_rand(0, count($input_lines));

「より良い乱数」になったかどうかはまだ分かりません。
ただ rand() では特定の台詞のみ偏って選出されたりしたので、そのあたりの改善が期待できる・・・かもしれません。

上で記載した「一定期間内にツイートした台詞は除外」機能と合わせれば、少なくとも同じ台詞が続いてしまうことは避けらます。
データベースやPHPのモジュールにもよりますが、気になっている方は試してみてはいかがでしょうか。

苦労したこと

前回に引き続き、bot製作に関して苦労したことを紹介します。

抜けが無く収集できているか心配になる

抜けがないように収集したつもりですが、やはり不安な部分もあります。
例えばランパの変身が可能なエリアで、且つ該当の変身をまだ取得していない場合に特殊な台詞があります。

今のボクのチカラじゃここではへんしんできないみたいだ・・・
ぼうけんしてフシギな石を見つけたら、またへんしんできるようになるかも・・・?
気になるところがあるかもしれないけれど、ひとまず今は先にすすんで、あとでここにもどってみようよ

今のボクのチカラじゃここではへんしんできないみたいだ・・・
ぼうけんしてフシギな石を見つけたら、またへんしんできるようになるかも・・・?
ひとまず今はちがうみちをすすんでみて・・・あとでここにもどってみようよ、スタフィー

この際、場所によって微妙に台詞が違ったりします。
自分は後半で気付きましたが、もしかしたら前半の隠しエリアなどにも設定されているかもしれません。
その場合、ストーリーを最初からやり直すことになりかねません。

手動で収集・入力することに限界を感じる瞬間ですが、メインとなるストーリー上のイベントはすべて搭載しているので、台詞botとしては妥協ラインかなーとも思います。
裏を返せばそれだけの台詞パターンがある位、ゲーム自体の作りが丁寧ということですね。
攻略本で変身するエリアだけを確認する等、漏れがないような施策を考えていきたいところです。

かなり長い台詞がある

例として、以下はステージ8-3後半の会話です。
途中キョロスケが1~2回話す以外、ほぼランパのみが喋り続けます。

す、スタフィー・・・なかまが・・・なかまが・・・

みんなっ、しっかりっ!!へんじをしてーーー!!
ダメだ・・・みんなチカラをダイールにすいとられてうごけないみたい・・・

ダイール・・・何てことを・・・
ゆるさない!ゆるさないぞーぉおお!!!
何があっても・・・みんなをもとの元気なすがたにもどすんだ!!!

ボクをダイールからまもるために、みんなはぎせいになった・・・
みんなは・・・なかまは・・・かぞくどうぜんなんだ
ボクには・・・パパもママもいないから・・・みんながかぞくなんだ!

・・・うん、ボクが生まれてすぐ・・・パパもママもしんじゃったんだって
すごく小さかったからよくわからなかったけど
さみしくないようにって、みんながやさしくしてくれた

ボク、こうやってスタフィーたちとであえてわかったんだ
スタフィーも王子、ボクも王子、おなじ王子なのに、スタフィーはいつもボクをたすけてくれた
このままじゃいけないんだ!スタフィーのように、強くやさしく・・・みんなをまもれる王子にならなきゃ!

ねぇ、スタフィー ボクやるよ!
ダイールをたおして・・・なかま・・・かぞくをとりもどすんだ!!!
ぜったいこのままでおわらせるわけにはいかない!さあ!行こう!

台詞自体はランパの過去や成長、決意が見て取れる大変よろしいものです。
ただし、bot的には「ツイート可能な文字数は140まで」という制限に引っ掛かります。
仕方ないので文としての意味合いが切れない程度に分けていますが、それでも140文字以内に収まるか怪しくなる台詞もあります。
上の例で言えば、「ボク、こうやってスタフィーたちと~」から3行で129文字です。

この例に限らず、稀に非常に長い台詞があります。(7-4など)
こればかりはどうしようもないので、やはり文としての意味合いを保ちつつ分けています。
一部強引な分け方をしていますが、「こんな台詞がある」というbotであり、所謂「名言集」ではないので・・・と言い訳しておきます。

余談ですが、その割にはエンディングは超あっさりで、ダイール撃破後にランパが発した明確な台詞は以下の2つのみです。

スタフィー!だいじょうぶ?

スタフィー!ほんとうにありがとう
またあそびにきてね

後者はスタッフロール後の一番最後の台詞で、「また遊んでね!」的な意味合いが含まれていると思われるため、実質1つのみです。
まあエンディングなのでナレーションベースということもありますが、ちょっと驚きました。

「ランパのあつめもの」の存在を忘れる

キョロスケ様のかばんメニューに「あつめもの」があります。
このメニュー、ストーリーの進行具合に応じてランパのコメントがあります。

DSC_0306

が、このメニュー自体の存在をステージ5まで忘れていました。
更新タイミングは(たぶん)ステージクリア時とエンディング後なので、ステージ5からメモっていけばやり直す範囲も抑えられますが、完全にノーマークだったので精神的ダメージが大きかったです。

ちなみに「今日のゲスト」の各台詞と、クリア後にあつめものを見た際の「ランパのにちじょう」シリーズはすべて回収しました。

DSC_0326

ただし、「ランパのにちじょう (海)」だけ異常に出現率が低く逃しそうになりました。
内容は上画像の通りですが、さらっとすごいことを言っているので意図的に低確率なのかもしれません。
隕石を弾き返すほどの回転をランパが習得できるとは思えませんが・・・。

「キョロスケ様のキャラ診断」なるフラッシュがある

公式サイトに「キョロスケ様のキャラ診断」なるものがあります。
公式自体見たことがなかったので、海外のフォーラムで初めて知ったりもします。

現在でも公式サイトにリンクがありますが、画面下部にひっそりと表示されているだけです。
気合でランパっぽくなるような選択肢を選びます。

starfy_sindan_rampa2

やはりというか、キャラクター毎のコメントがあります。
ゲーム外の台詞ですが、「ゲーム内の」と限定して作っているわけでもないので、とりあえず台詞集に追加しておきました。
ちなみにハマグリ曰く、「真面目で素直な優等生タイプ」らしいです。

まとめ

そんなわけで、ランパの台詞bot作成(ほぼ)完了です!
プレイしていると、キャラクターやストーリーが懐かしく感じて、意外とハマってしまったりします。

現在の台詞パターンは193種類です!
1アクションゲームとしてみると相当な量ではないでしょうか。
あとは上述した「あつめもの」をステージ1~4分入れれば完成かと思います!

【Twitter】ランパの台詞botを作成してみる その2

というわけで、今回は「ランパの台詞botを作る」第2弾です。
前回の記事はコチラ!

【Twitter】ランパの台詞botを作成してみる その1

今回は台詞集から出力するテキストを抜き出し、ツイートするところまでやってみます!
ついでに作っている上で苦労していることも紹介します。

台詞の入力

とりあえず「オープニング~ステージ3-2」までと、その他回収できた台詞を書き出してみました!

20170116_02

見直してみると結構喋りますね。
ステージ3-2まででも3000文字近くあります。
ハマグリほどではありませんが、主人公が喋らないのでその影響もあるようです。
一方で全く喋らない(≒登場しない)ステージもそれなりにあるので、各ステージ満遍なく喋るというよりは、1ステージでの回数が多いといった印象です。

それにしても、3点リーダーが尋常でなく多いです。

DSC_0281

恐らく会話ウィンドウ的な都合があるのだと思いますが、それを差し置いても多いです。
実際にツイートさせる時は適度に削除しないと見にくくなってしまいます。

ゲーム自体の対象年齢故にひらがなも多いですが、簡単な漢字とカタカナは含まれているので、そこまで読みにくくはないと思います。
ただ句読点が一切ない上、上記の3点リーダーを削除してツイートする兼ね合いもあるため、適度に句読点は入れています。
それ以外は原文ママで問題ないと思われます。

twitterアイコンの作成

デフォルトのたまごアイコンでは味気ないので、アイコン用にランパを描いてみました。
ステージ選択のアイコンを元にしました。

20170116_rampa_icon1

うーん・・・また何とも言えない出来ですが、まあ及第点でしょう。
まあアイコンなんて小さいものなので、割と大雑把なくらいがちょうどよかったりします。

個人ページの背景は・・・後回しにします(ぁ
今の自分のイラスト力では描ける気がしないので・・・。

bot用PHPファイルの修正

前回ほぼコピペだったPHPファイルを修正します。
自分は手続き型っぽく書くのが嫌いなので、意味もなくクラスをインスタンス化するようにしました。
ツイートする部分は同じですが、ランパの台詞の抽出と整形部分を大きく変えています。

ツイートの際の理想の形式は「ランパの台詞 (改行)【発言した場面】」です。
また、台詞が複数行になることもあるので、その点も考慮する必要があります。

<?php

require_once("twitteroauth-master/autoload.php");
require_once('twitteroauth-master/src/TwitterOAuth.php');

use Abraham\TwitterOAuth\TwitterOAuth;

/**
 * ランパの台詞集から台詞を抽出・ツイートするクラス
 */
class TwitterRampaBot {

    private $customer_key;
    private $customer_secret;
    private $access_token;
    private $access_token_secret;

    const file_path = 'rampa_serifu.txt';
    const max_tweet_len = 140;

    /**
     * コンストラクタ
     */
    public function __construct() {
        $this->customer_key = "customer_key";
        $this->customer_secret = "customer_secret";
        $this->access_token = "access_token";
        $this->access_token_secret = "access_token_secret";

        mb_internal_encoding('UTF-8');
    }

    /**
     * つぶやきを送信する
     */
    public function tweet() {
        $message = $this->getTweetWord();

        // 文字数チェック
        if (self::max_tweet_len < mb_strlen($message)) {
            trigger_error('ツイート可能な文字数を超えています。', E_USER_ERROR);
            exit;
        }

        // サーバにつぶやきを送信
        $connection = new TwitterOAuth($this->customer_key, $this->customer_secret, $this->access_token, $this->access_token_secret);
        $connection->post("statuses/update", array("status" => $message));
    }

    /**
     * ツイート用の文字列を取得・整形する
     *
     * @return string
     */
    private function getTweetWord() {
        // テキストファイルから文字列読み込み
        $input_lines = file(self::file_path);
        $words = array();

        // 先頭 # の行を取得するまでループ
        while(true) {
            $line_num = rand(0, count($input_lines));

            // 先頭が # で始まる行を抽出
            if (preg_match('/^\# .*$/', $input_lines[$line_num])) {
                // # 以降を場面として取得
                $scene = $this->excludeLineFeed($input_lines[$line_num]);
                $scene = str_replace('# ', '', $scene);

                // 複数行の台詞を全て取得するまでループ
                for ($i = $line_num + 1; ; $i++) {
                    // 文字列か空or改行コードのみの場合は終了
                    if (empty($input_lines[$i]) || preg_match('/^' . PHP_EOL . '$/', $input_lines[$i])) {
                        break;
                    }

                    $words[] = $this->excludeLineFeed($input_lines[$i]);
                }
                break;
            }
        }

        // 台詞と発言場面を設定
        $message = '';
        foreach ($words as $word) {
            $message .= $word . PHP_EOL;
        }

        $message .= '【' . $scene . '】';

        return $message;
    }

    /**
     * 指定した文字列から改行コードを除外する
     *
     * @param string $str
     * @return string
     */
    private function excludeLineFeed($str) {
        return str_replace(PHP_EOL, '', $str);
    }
}

$twitterRampaBot = new TwitterRampaBot();
$twitterRampaBot->tweet();

exit;

?>

GitHub から落とした「TwitterOAuth」を使用していますが、バージョンによってやり方に差があるようです。
自分も他サイトのコピペでは全然動きませんでした。

あれこれ考えた結果、ファイルから取得した後、正規表現で取捨選択するのが最も手っ取り早かったです。
テキストファイルから抽出した文字列から、以下の条件で抽出します。
・# から始まる行を発言場面として抽出
・#以下から次の空白行 (実際は改行コード) までを台詞として抽出
・空白行は抽出しない

台詞集となるテキストファイルもそれに則って書いていきます。
サンプルとして、いくつか台詞を記載します。

# ステージ1-3
・・・どうしてこんなところに・・・
それに何でたたかっていたんだ・・・
うう・・・思い出そうとするとアタマがイタイ・・・
もしかして・・・ボクのきおく・・・

# ステージ1-4
あ・・・うん!!
スタフィーのボクをたすけたいって思う気もちが
ボクのへんしんのチカラ、『ドランパ』を思い出させてくれたんだ・・・

# ステージ2-2
あ、そうだ!ボクとチカラをあわせて下からゴォォォーってやってみる?
ドランパで、上ボタンをおしながらゴォォォーってできるよ
ためしてみて!

注意点として、Linux 上から動作させる関係上、改行コードは「LF」にしておく必要があります。
サクラエディタであれば保存時に指定できます。

かなり効率の悪い処理ですが、何度も実行するような処理ではないので、速度はあまり気にしません。
他にもいろいろ考えましたが、.ini は設定ファイルの趣が強く、このためだけに yaml や json のパーサを入れるのも嫌なので、とりあえずこの形でいってみようと思います!

苦労している点

プレイ日記に片足突っ込みつつ、製作している上で苦戦していることを紹介します。

データが消える

ある意味最大の壁です。
本体がダメなのか、ソフトが古いためか、プレイ中に接触不良→次回起動時にデータ消失ということがあります。
特にカートリッジを抜いておくと、次回起動時に差しても高確率で認識しません。

スロットからカートリッジを出さなければ順調なので、差しっぱなしにすることでカバーしていますが、当分の間3DSがスタフィー専用機となることを意味します。
最近3DSはほとんど起動していないので、あまり実害はないと思われますが、MHXX発売までには完成させたいところです。

ステージクリア後にオートセーブ

カートリッジ故にセーブは高速で、普通にプレイする分には問題ありません。
ただ、ランパの台詞を取り逃してしまったり、間違えていた場合、ステージをクリアするまでにリセットしないとアウトです。
ストーリーが進んでしまうと読み直すことができないので、漏れなくニューゲームとなります。
後半のステージでこれをやってしまうと悲惨なので、最も注意すべき人的エラーですね。

会話後に再度会話をすると内容が異なる

ステージの所々に会話イベントがありますが、会話後に再度キャラクターと会話すると、内容が異なる場合があります。
ゲーム的には素晴らしい作り込みですが、台詞をまとめる上では注意が必要です。

DSC_0283

しかも再会話時の台詞は長いものが多いです。
これも上記のオートセーブと同じく、気付かずにストーリーを進めてセーブされると、最初からやり直す羽目になりかねません。

まとめ

そんなわけで、ランパbotの作成日記その2でした!
まだ途中までしか作っていませんが、アカウントを作ってしまった上、完成がいつになるか分からないので、今のレパートリーで試運転してみようと思います。
cron で1日2回、12時間置きにツイートさせるように設定しています。

ひとまず問題なく稼働しているみたいです。
あとはランパの台詞を逃すことなく追加していけば完成すると思われます!

【Twitter】ランパの台詞botを作成してみる その1

【2017/01/16】
サンプルソースを修正しました。

というわけで、今回はタイトル通り、Twitterのbot作成に挑戦してみます!
作るのは伝説のスタフィーに登場するキャラクター「ランパ」の台詞集です!

ranpa31

上のような、宇宙服を着たウサギのようなキャラです。
(自分が描いたイラストなので実物とは異なります)
「ランパ星」というまんまな星の王子で、いろいろな動物に変身することができます。
「キャラクターとしての魅力は?」と言われれば・・・回答が難しいところですが、自分は「見た目」と「至って普通な性格」と返します。
主人公であるスタフィーとの変身形態の1つにアザラシがあるので、むしろそっちに惹かれたりしていましたが・・・。

DSC_0278

そんなランパの台詞集、誰も作っていなかったので、ネタとしてのポストは空いています。
前からbotを作ってみたかったのもあるので、どんな感じなのかやってみました!

Twitterアカウントの作成

まずはbot用のTwitterアカウントを作成します。
マイアカウントでログインしっぱなしなので一度ログアウトし、新しくアカウントを作成します。

新規アカウントのためにはメールアドレスが必要ですが、bot専用のアカウントを作るのも嫌なので、Gmailのエイリアス機能を使用します。
[アドレス]+[任意文字列]@gmail.com でメールを自動的に転送してくれるらしいです。
細かいことはぐぐればたくさんでるので割愛します。

shot2ss20161223224502738

「ランパ」とだけ打つと、歯の矯正手術とかそっち系のばかりヒットするため、頭にスタフィーと入れておきます。
ちなみにランパのスペルは「Rampa」らしいです。
海外版では「bunston」と全く別名だったりしますが、とりあえずランパで行きます!

shot2ss20161223224725777

電話番号認証の後、ユーザIDを入力します。
まあ日本の方ならアカウント名見れば分かると思うので、シンプルにいきます。

あとはおすすめされる通知設定やフォローを全て拒否して完了です。

「Twitter Developers」でアプリケーションの作成

Twitter連携用のアプリケーションを作成します。

https://dev.twitter.com/

サイト上の「My Apps」をクリックし、次画面の右上からログインしましょう。

shot2ss20161223231237770

アプリ名、アプリの詳細、サイトURLを入力します。
割と適当でも大丈夫です。
サイトを持っていない場合は適当なURL(example.comとか)でも良いらしいです。

作成時に電話番号認証が行われていない場合、エラーとなって先に進めません。
しかも電話番号はアカウント間で共有することが出来ないそうです。
面倒ですが、メインアカウントの電話番号で一時的に認証してしまいました。

完了後にアプリケーションの詳細画面が表示されるので、「Application Settings」のあたりを撮っておきます。
上タブの「Keys and Access Tokens」の情報と、画面下の「Create My Access Token」クリック後の情報もメモしておきます。

実行用PHPファイルの作成と自動実行設定

GitHub上で公開されている「TwitterOauth」というPHPで作るのが一般的らしいです。
ほぼ他の参考サイトのコピペです。

<?php
require_once("twitteroauth-master/autoload.php");
require_once('twitteroauth-master/src/TwitterOAuth.php');

use Abraham\TwitterOAuth\TwitterOAuth;

$customer_key = "customer_key";
$customer_secret = "customer_secret";
$access_token = "access_token";
$access_token_secret = "access_token_secret";

$filelist = file('rampa_serifu.txt');
if(shuffle($filelist) ){
    $message = $filelist[0];
}

$connection = new TwitterOAuth($customer_key, $customer_secret, $access_token, $access_token_secret);
$connection->post("statuses/update", array("status" => $message));
?>

file() でテキストファイルの中身を取得し、無作為に1行抽出しているようです。
TwitterOAuth のパスや各種キーは環境に応じて設定して下さい。

実際は後述の台詞集入力で手間取っているため、まだ動かしていません。
またツイート時に「どこで発言したか」も入れたいので、単純にテキストファイルから取ってくるだけではきついかなーとも思います。
行く行くは正規表現であれこれして出力する感じでしょうか。

台詞集の入力

あとはランパの台詞を読み込ませるだけなのですが・・・。
ランパが登場するのは「伝説のスタフィー たいけつ!ダイール海賊団」という作品になりますが、もう発売から10年近く経つゲーム故、台詞をまとめてあるサイトなんてどこにもありません。
もちろんROM解析する知識・技術もなければ、それを行うための機材もありません。

ただ、ソフト自体は今でもとってあります。DSもあります。
つまりこういうことです!

DSC_0277

素でゲームを最初からエンディングまでプレイし、ランパの発言を残すことなく記録していくしかないでしょう。
クリアデータがありますが、一度クリアしたステージのストーリーを再度見ることは出来ません。
また、マリオやカービィと違ってステージ中にも会話が入るので、そういった意味でもプレイしないと厳しいです。

必要なのは「ランパが落ちてくるところからダイール撃破まで」のステージ1~8で、9~10は(確か)一言も喋らないので除きます。
隠しステージの攻略が必要かどうかは微妙なところです。
(うる覚えですが、ドランパに関することでランパが何か喋った気がします)
その他サブ要素(今日のゲストとメモ)で幾つか台詞があった気がしますが、既存のクリアデータで回収できます。

・・・と思いきや、セーブ中にソフトの接触不良→再起動時にデータ真っ白というアクシデント!
サブ要素をメモった後だったのが幸いですが、(ほぼ)コンプリートしたデータが消し飛んでしまいました。
元々最初からやり直す予定だったので、新規で始めますが・・・。

DSC_0279

DSC_0280

何かステージがところどころおかしいです。
水中なのに地上扱いになっていたり、壁のブロックが消えていたりします。
使用している3DSのカートリッジスロットの認識が悪いので、本体を入れ替えてからプレイしないと危険な気がします・・・。
ちょっとやり方を考える必要がありそうです。

というトラブルがあったことを踏まえると、実際の完成はかなり先の話になってしまいそうです。
こういう「台詞bot」って割とよく見かけますが、どうやって作っているのでしょうか。
やはり気合で入力するしかないのでしょうか・・・。

一気にやるのは無理があるので、暇なときにやっていくようにします。
ゲーム的な難易度は低めなので、「詰まる」という意味での障害はないと思われます。

まとめ

というわけで、Twitterでランパの台詞botを「形だけ」作ってみました!
botだけなら自作でも簡単に作れてしまうようです。
むしろゲーム内のランパの台詞をかき集める作業の方が大変かもしれません・・・。
気が向いたらときに少しずつ作っていくしかなさそうです。

余談

海外では「starfy wiki」というシリーズ全体のwikiがあります。
スタフィーシリーズは5作目まで海外で発売されていなかったにも関わらずです。
過去シリーズはおろか、過去に発売されたグッズやROM内の没データまで、内容量も凄まじいです。
英語のサイトですが、スタフィー好きな方は読んでみると面白いかもしれません。

http://starfywiki.org/wiki/Main_Page