今回のPHPポケモンでは「状態異常」を導入します。バトルシステムにも関係してくる部分ですが、それ以外にも影響を与える部分が多く、且つ非常に判定がややこしく、作り込む必要があったため1つずつ片付けていきます。
状態異常の実装
ポケモンの除隊異常に該当するものは以下の7通りです。
- やけど
- こおり
- まひ
- どく
- もうどく
- ねむり
- ひんし
状態異常にかかれば、ステータス横に表示され、バトル終了後も残り続けます。中にはターンで解除されるものや、回復処理をさせなければ永久に残り続けるものまであり、その判定は非常にやっかいです。
また、状態異常は原則として1つしかかかりません。どく状態になれば、まひ状態にはならず、それが上書きされることもありません。最初にかかった状態異常が優先されるということです。但し、ひんしは「HPが0」という少し他とは違った判定になるため、HPが0になれば他の状態異常に関係なくひんし状態になります。
では、状態異常の格納用としてポケモンにsaというプロパティを用意しましょう。
ポケモンクラス(/Classes/Pokemon.php)
/**
* 状態異常
* SaBurn やけど
* SaFreeze こおり
* SaParalysis まひ
* SaPoison どく
* SaBadPoison もうどく
* SaSleep ねむり
* SaFainting ひんし
* @var array [sa1_class_name(string) => turn(integer)]
*/
protected $sa1 = [];
それぞれにクラス名を振っていますが、クラス名の重複を避けてSaという接頭語を使用しています。オートローダーを使った際に、どく状態(Poison)とどくタイプ(Poison)のバッティングを防ぐためです。
saのプロパティにはクラス名をキー、ターン数を値にした配列で格納します。中にはターンが経過することによって解除されたり、ダメージ量が増えるものがあるからです。
「もうどく」の判定
ひんしの他にも、「もうどく」が少し別処理が施されます。初代、第2世代ではもうどくはポケモンを入れ替えることで「どく」に戻りましたが、今回は最新世代を参考に「もうどく」は継続する仕様で作成をします。
但し、「もうどく」はバトルが終了すれば「どく」に戻ります。こちらはゲーム再現として実装予定です。
「まひ」の実装
それでは、「まひ」の状態異常を実装します。
技やポケモン、タイプよりは情報量も少なくなりますが、それぞれ個別の処理が予定されるので、こちらもクラスとして作成します。
クラス作成
まひのクラスと、状態異常の親クラスは以下の通りです。
状態異常:まひ(/Classes/StatusAilment/SaParalysis.php)
<?php
require_once(__DIR__.'/../StatusAilment.php');
// まひ
class SaParalysis extends StatusAilment
{
/**
* 正式名称
* @var string
*/
protected $name = 'まひ';
/**
* 状態異常にかかった際のメッセージ
* @var string
*/
protected $sicked_msg = '相手の::pokemonは、まひして技が出にくくなった';
/**
* すでにこの状態異常にかかっている際のメッセージ
* @var string
*/
protected $sicked_already_msg = '::pokemonは、既に麻痺している';
/**
* ターンチェック時に表示されるメッセージ
* @var string
*/
protected $turn_msg = '::pokemonは、体が痺れて動けない';
}
状態異常(/Classes/StatusAilment.php)
<?php
// 状態異常
abstract class StatusAilment
{
/**
* インスタンス作成時に実行される処理
*
* @return void
*/
public function __construct()
{
//
}
/**
* 名称の取得
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* 状態異常にかかった際のメッセージを取得
*
* @param string $pokemon
* @return string
*/
public function getSickedMessage($pokemon)
{
return str_replace('::pokemon', $pokemon, $this->sicked_msg);
}
/**
* 状態異常にかかった際のメッセージを取得
*
* @param string $pokemon
* @return string
*/
public function getSickedAlreadyMessage($pokemon)
{
return str_replace('::pokemon', $pokemon, $this->sicked_already_msg);
}
/**
* 状態異常にかかった際のメッセージを取得
*
* @param string $pokemon
* @return string
*/
public function getTurnMessage($pokemon)
{
return str_replace('::pokemon', $pokemon, $this->turn_msg);
}
}
今回は表記として必要になるメッセージ格納用のプロパティだけを設定しました。メッセージの中にはポケモンの名称など状況に合わせた固有名詞が含まれるため、get時にstr_replaceで置き換えられるように::pokemonという表記で当てはめました。
状態異常もオートローダーを使った読み込みを想定しているため、オートローダーの対象フォルダにStatusAilmentを追加しておいてください。
状態異常にする
次に、ポケモンを状態異常にするためのメソッドを、ポケモンに対して作成します。まずはGet格納用トレイトに以下のメソッドを追加しましょう。
Get格納用トレイト(/Traits/Pokemon/GetTrait.php)
/**
* 現在の状態異常を取得する
* @return string
*/
public function getSa()
{
if(empty($this->sa)){
return '';
}else{
return array_key_first($this->sa);
}
}
/**
* 現在の状態異常(Sa)の名称を取得する
* @return string
*/
public function getSaName()
{
if(empty($this->sa)){
return '';
}
$sa = $this->getInstance(array_key_first($this->sa));
if($sa){
return $sa->getName();
}
}
まずは現在の状態異常を取得するためのメソッドです。1つ目のgetSaでは、かかっている状態異常のクラス名(キー)を取得しています。正常であればsa内は空になるのでそのまま空文字を返却します。もし存在している場合は、array_key_firstを使って配列最初のキーを取得します。状態異常は重複しないため、一つしか存在していないことが前提条件としてあるためです。
array_key_first(PHP.net)
合わせて、現在の状態異常の名称を取得するためのメソッド(getSaName)も作成しました。こちらは画面上で現在の状態異常を表示するために使用します。
次に、状態異常をセットするためのメソッドをSet格納トレイトに追加しましょう。
Set格納トレイト(/Traits/Pokemon/SetTrait.php)
/**
* ランク(バトルステータス)をセットする
* @param string $class
* @param integer $turn|0
* @param string $param
* @return string
*/
public function setSa($class, $turn=0)
{
$sa_list = [
'SaBurn', 'SaFreeze', 'SaParalysis', 'SaPoison', 'SaBadPoison', 'SaSleep', 'SaFainting',
];
// クラスチェック
if(!in_array($class, $sa_list, true) || !class_exists($class)){
// 不正なクラス
return '指定された状態異常は存在しません';
}
// インスタンス化
$sa = new $class;
if(isset($this->sa[$class])){
return $sa->getSickedAlreadyMessage($this->getName());
}
if(empty($this->sa)){
// 状態異常をセット
$this->sa[$class] = $turn;
return $sa->getSickedMessage($this->getName());
}
}
状態異常の数は限られているため、念のために状態異常の一覧配列を用意してin_arrayで検証しています。空であれば登録、空でなく同じ状態異常に既にかかっていれば、sicked_already_msgのプロパティに格納された値を返却します。
次に、まひの状態異常にする技として「でんじは」の追加効果を作成しましょう。
まひ(/Classes/Move/ ThunderWave.php)
/**
* 追加効果
*
* @param array $args
* @return void
*/
public function effects(...$args)
{
/**
* @param Pokemon $atk 攻撃ポケモン
* @param Pokemon $def 防護ポケモン
*/
list($atk, $def) = $args;
// 相手をまひ状態にする
$msg = $def->setSa('SaParalysis');
// メッセージをセット
$this->setMessage($msg);
}
これで相手ポケモンをまひ状態にすることが出来ます。さらに、状態異常をバトル終了後も引き継がれるよう引き継ぎの値に追加しておきましょう。
ポケモン(/Classes/Pokemon.php)
/**
* 進化時の能力引き継ぎ処理
*
* @param object $before 進化前
* @return void
*/
protected function takeOverAbility($before)
{
if(is_object($before)){
$this->nickname = $before->nickname; # ニックネーム
$this->level = $before->level; # レベル
$this->ev = $before->ev; # 努力値
$this->iv = $before->iv; # 個体値
$this->exp = $before->exp; # 経験値
$this->move = $before->move; # 技
$this->sa = $before->sa; # 状態異常
}elseif(is_array($before)){
$this->nickname = $before['nickname']; # ニックネーム
$this->level = $before['level']; # レベル
$this->ev = $before['ev']; # 努力値
$this->iv = $before['iv']; # 個体値
$this->exp = $before['exp']; # 経験値
$this->move = $before['move']; # 技
$this->sa = $before['sa']; # 状態異常
}
}
それでは、実行結果を見てみましょう。
※名前とレベルの下に現在の状態異常(getSa)を出力させています
でんじはを使うことで麻痺状態になることが確認できました。引き継ぎ処理をしているので、再度でんじはを使えばその旨のアラートも正常に出力されていることがわかります。
ステータスへの反映
最後にステータス(実数値)への状態異常の反映を行います。バトル中であれば、実数値に補正がかかるため、それをステータス取得用のメソッド(getStats)に追加しましょう。
Get格納トレイト(/Traits/Pokemon/GetTrait.php)
/**
* ステータスの取得
*
* @param string|null
* @return array|integer
*/
public function getStats($param=null, $m=false)
{
// ポケモンのステータス(実数値)を計算して返却
foreach($this->base_stats as $key => $val){
/**
* ステータスの計算式(小数点以下は切り捨て)
* HP:(種族値×2+個体値+努力値÷4)×レベル÷100+レベル+10
* HP以外:(種族値×2+個体値+努力値÷4)×レベル÷100+5
*/
if($key === 'HP'){
$correction = $this->level + 10;
}else{
$correction = 5;
}
$stats[$key] = (int)(($val * 2 + $this->iv[$key] + $this->ev[$key] / 4) * $this->level / 100 + $correction);
}
if(is_null($param)){
// 指定がなければ全ステータスを返却
return $stats;
}
if($m){
// 状態異常補正を計算した値を返却
switch ($param) {
// すばやさ
case 'Speed':
if($this->getSa() === 'SaParalysis'){
// すばやさ半減
return $stats[$param] / 2;
}
// 補正不要
default:
return $stats[$param];
}
}
return $stats[$param];
}
状況によっては、補正がかかっていないステータスが必要になる場合も考えられるため、引数で補正の有無を判定しています。全ステータスを要求された際は、基本的に補正が不要な場面が多いため、処理を省いています。
switchを使用して、もし素早さが要求された場合には麻痺状態かどうかをチェックして半減処理を行なっています。
まとめ
いかがだったでしょうか。
今回のPHPポケモンは「状態異常の実装〜まひ〜」についてご紹介しました。
状態異常の処理はバトルに大きく影響し、更にそれぞれ異なるタイミングや影響が出るため、複雑な部分の一つです。しかし、作り上げればバトル要素としてはより戦略的かつ楽しみの一つとなるでしょう。
現在プログラミング学習に取り組んでいる人は、ぜひ参考にしてみてくださいね。