LINE-Botでポケモンのサファリゾーンを作ってポケモ◯ゲットだぜ！(Callback側はPHP+Redis)

# やりたいこと
Botを使ってECの商品検索など作ったのですが、ちょっと違うテイストをやってみたくなったのでチャレンジです。
今回はケンタロス欲しさに頑張ったサファリゾーンの石やエサを投げてサファリボールで捕まえるタイプをLineのボットで遊べるようにします。


イメージは
話しかけるとポケモンが出現して
1と話しかけると石を投げる。
２と話しかけるとエサを投げる。
３と話しかけるとサファリボール投げて判定。
って感じです。
あとは毎ターン逃げる判定。

そんな大層なものではありません。



# 環境とアカウントセットアップ
記載は省きます。
サーバーはConohaVPS+OnamaeドメインでLetsEncryptを導入済みです。
LINE Botの登録も綺麗にまとめていらっしゃる方が多いので、参考にさせていただきました。
[LINE BOT API Trialでできる全ての事を試してみた](http://qiita.com/betchi/items/8e5417dbf20a62f2239d)

# ポケモン関連で参考にさせていただいたサイト
- http://wiki.xn--rckteqa2e.com/wiki/%E6%8D%95%E7%8D%B2%E5%87%A6%E7%90%86
- http://pikap.blog.jp/archives/56002339.html

赤・緑の時代の人間なので、最近の話が全くわかっていません。
当時はこんなに細かくパラメータなど考えてプレイしていないので、この歳になってポケモンの実装をWikiで調べる。


# 作成したBOT

スクリーンショット撮影中・・




## サファリゾーン（対戦画面）の再現で最低限必要なデータ

サファリボールの時は「スーパーボール」扱いになるというサイトもありましたが、石やエサで補正されるので、これらが必要です。

必要なパラメータ
- 捕獲率
- 現在の捕獲率
- エサポイント
- エサの回数
- 石ポイント
- 石の回数
- 素早さ


## データ

必要な要素のあるポケモンを準備

```php:callback_poke.php
$pokemons = [];
$pokemons[] = array( "id" => 32 , "name" => "ニドラン♂" , "voice" => "ギャラーララー"   , "get" => 235 , "now_get" => 235 , "speed" => 50  , "food" => 0 , "stone" => 0 , "count_food" => 0 , "count_stone" => 0 );
$pokemons[] = array( "id" => 128 , "name" => "ケンタロス" , "voice" => "ギャラーララー" , "get" => 45  , "now_get" => 235 , "speed" => 110 , "food" => 0 , "stone" => 0 , "count_food" => 0 , "count_stone" => 0 );
```

CallBackが呼び出されると、LineのユーザID？を元にlocalhostのRedisからプレイ中の対戦ポケモンデータを取得します。
いない場合、ランダム（あとで確率を埋めたい）でpokemonsから取得

```php:callback_poke.php
$user_id 	= $content->from;
$poke = $redis->get( $user_id );
```

はじめてのアクセスやコンテニューの場合、ポケモンの出現音をメッセージで表示してredisにデフォルトのステータスのポケモンをLineのユーザID？をKeyに保存します。

```php:callback_poke.php
$message[] = "トュルトュルトュルトュルトュルトュルトュル♪・テン♪・テン♪・テン♪・ッテッテテデン..\r\n\r\n".$pokemon["name"]."が現れた！\r\n\r\n".$pokemon["voice"]."\r\n";
$redis->set( $user_id , json_encode( $pokemon ) );
```

ボットへのメッセージ情報はstdinで受け取ります。
angularjsのpostを受け取る時と同じ感じです。

```php:callback_poke.php

$request = file_get_contents("php://input");
$json = json_decode($request);
$content = $json->result[0]->content;
```

すでにゲームを始めてる場合、redisからポケモン情報を取得して
受け取ったLineのメッセージの本分をみて処理を分岐します。
エラートラップは記載してません。

```php:callback_poke.php

$poke = json_decode( $poke , true );
$mode = intval( $content->text );
if( $mode == 1 ){
	$message[] = "いしをなげた!";
..補正処理
}else if( $mode == 2 ){
	$message[] = "えさをなげた!";
..補正処理
}else if( $mode == 3 ){
	$message[] = "サファリボールをなげた!";
..捕獲判定
}

if( !isGameComplete )
//捕まえていなければターン終了処理

//ターン終了時、どちらかのカウンタが1以上であれば、1減少する。
//怒りカウンタが0に戻ると、捕捉率は元の値にリセットされる。
if( $poke["stone"] > 0 || $poke["food"] > 0 ){
	if( $poke["stone"] > 0 ){
	　	$poke["stone"] = $poke["stone"] - 1;
	}
	if( $poke["food"] > 0 ){
		$poke["food"] = $poke["food"] - 1;
	}
}


// 0~255の乱数を発生させ、それがSより小さければポケモンは逃げる。ただし、Sは、
// エサカウンタが1以上のとき、ポケモンのすばやさの半分（小数点以下切り捨て）
// どちらのカウンタも0のとき、ポケモンのすばやさの2倍
// 怒りカウンタが1以上のとき、ポケモンのすばやさの4倍
// である。また、ポケモンのすばやさが128以上のとき、乱数やカウンタに関わらず逃げる。
$r = mt_rand(0,255);
if( $poke["food"] >= 1 ){
	$s = floor( $poke["speed"] / 2 );
}else if( $poke["stone"] >= 1 ){
	$s = floor( $poke["speed"] * 4 );
}else if( $poke["stone"] == 0 && $poke["food"] == 0 ){
	$s = floor( $poke["speed"] * 2 );
}
if( $s > 128 || $s > $r ){
	$message[] = "やせいの".$poke["name"]."は逃げだした。";
	$command   = "\r\n\r\n----------操作メニュー----------\r\n0 -> コンテニュー";
	//逃げた場合、消去
	$redis->delete( $user_id );
}else{
	//次のメッセージに備えて保存
	$redis->set( $user_id , json_encode( $poke ) );
}
```

あとはメッセージを返却する際に操作メニューを追加します。

```php:callback_poke.php
$command   = "\r\n\r\n----------操作メニュー----------\r\n1 -> いしをなげる\r\n2 -> エサをなげる\r\n3 -> サファリボール";
$message   = [];

間に上の補正や判定処理

$post['content']['text'] = implode( "\r\n\r\n" ,$message) .$command;

この下でcurlで
$ch = curl_init("https://trialbot-api.line.me/v1/events");
を呼ぶ
```


## 課題
- validation
- サファリボールの判定をもうちょっとちゃんと調べる必要がある。
- 逃げる判定あってるかな？ニドランでさえマッハで逃げていく。。。
とまだまだアップデートが必要