チャージ中の回避技
以前は「ロケットずつき」や「ソーラービーム」をサンプルとしてチャージ技を実装しましたが、今回は少し特別な効果をもったチャージ技を実装します。それが「そらをとぶ」と「あなをほる」です。これらは初代ポケモンでも重宝される技であり、チャージ中に相手からの攻撃を回避することができます。
前回のチャージ技の実装については以下の記事をご参考ください。
そらをとぶ
そらをとぶ(ポケモンwiki)
まずは「そらをとぶ」から実装します。技クラスは以下の通りです。
そらをとぶ(/Classes/Move/Fly.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Move.php');
// そらをとぶ
class Fly extends Move
{
/**
* 正式名称
* @var string
*/
protected $name = 'そらをとぶ';
/**
* 説明文
* @var string
*/
protected $description = '1ターン目で空に舞い上がり、2ターン目に攻撃する。空を飛んでいる間はほとんどの技を受けない。';
/**
* タイプ
* @var string
*/
protected $type = 'Flying';
/**
* 分類
* @var string(physical:物理|special:特殊|status:変化)
*/
protected $species = 'physical';
/**
* 威力
* @var integer
*/
protected $power = 90;
/**
* 命中率
* @var integer
*/
protected $accuracy = 95;
/**
* 使用回数
* @var integer
*/
protected $pp = 15;
/**
* 優先度
* @var integer
*/
protected $priority = 0;
/**
* チャージ技
* @var boolean
*/
protected $charge_flg = true;
/**
* チャージ中に回避できない技
* @var array
*/
protected $cant_escape_move = ['Thunder', 'Gust'];
/**
* チャージ
*
* @param object $atk
* @return boolean (true:準備ターン, false:攻撃ターン)
*/
public function charge($atk)
{
/**
* @param Pokemon $atk 攻撃ポケモン
*/
// チャージ前後の分岐
if($atk->checkChargeMove(get_class())){
// チャージ完了
$atk->releaseSc('ScCharge');
return false;
}else{
// チャージ開始
// 自身をチャージ状態にする
$msg = $atk->setSc('ScCharge', 1, get_class());
$atk->setMessage($msg);
return true;
}
}
}
以前作成したチャージ技と同様に実装していきます。追加要素として、チャージ中に回避できない技をまとめておくプロパティ(cant_escape_move)を配列形式でセットしています。こちらは後ほど説明します。
あなをほる
あなをほる(ポケモンwiki)
「そらをとぶ」と同じ要領で「あなをほる」の技も作成していきましょう。
あなをほる(/Classes/Move/Dig.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Move.php');
// あなをほる
class Dig extends Move
{
/**
* 正式名称
* @var string
*/
protected $name = 'あなをほる';
/**
* 説明文
* @var string
*/
protected $description = '1ターン目で地中に潜り、2ターン目に攻撃する。地中に潜っている間はほとんどの技を受けない。';
/**
* タイプ
* @var string
*/
protected $type = 'Ground';
/**
* 分類
* @var string(physical:物理|special:特殊|status:変化)
*/
protected $species = 'physical';
/**
* 威力
* @var integer
*/
protected $power = 80;
/**
* 命中率
* @var integer
*/
protected $accuracy = 100;
/**
* 使用回数
* @var integer
*/
protected $pp = 10;
/**
* 優先度
* @var integer
*/
protected $priority = 0;
/**
* チャージ技
* @var boolean
*/
protected $charge_flg = true;
/**
* チャージ中に回避できない技
* @var array
*/
protected $cant_escape_move = ['Earthquake'];
/**
* チャージ
*
* @param object $atk
* @return boolean (true:準備ターン, false:攻撃ターン)
*/
public function charge($atk)
{
/**
* @param Pokemon $atk 攻撃ポケモン
*/
// チャージ前後の分岐
if($atk->checkChargeMove(get_class())){
// チャージ完了
$atk->releaseSc('ScCharge');
return false;
}else{
// チャージ開始
// 自身をチャージ状態にする
$msg = $atk->setSc('ScCharge', 1, get_class());
$atk->setMessage($msg);
return true;
}
}
}
あなをほるにも、チャージ中に攻撃を回避できない例外技があるため、プロパティを用意してまとめておきます。
例外技
では、2つの技クラスに新しく用意したプロパティ(cant_escape_move)ともう1点例外処理について説明します。
回避できない技
今回実装する「そらをとぶ」と「あなをほる」ですが、チャージ中すべての技を回避できるわけではありません。それぞれに例外となる技が存在しており、相手がその技を使用してくればチャージ状態で合ったとしてもダメージを受けてしまいます。
チャージ中に回避できない技
そらをとぶ状態
かみなり、かぜおこし
あなをほる状態
じしん
※初代技のみ
初代技の中でもそれぞれに回避不可能な技があります。なので、これらを判定するためにクラス名をcant_escape_moveプロパティに格納しました。
威力倍化技
2点目の例外が、「威力が変動する技」についてです。例えば「かみなり」であれば、相手が「そらをとぶ」のチャージ中に使用することで技威力が倍の220になります。ですが、これは「そらをとぶ」ではなく「かみなり」の技に記述を追加する必要がありますので、新しくメソッドを作成して威力取得処理を修正しましょう。
かみなり(/Classes/Move/Thunder.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Move.php');
// かみなり
class Thunder extends Move
{
/**
* 正式名称
* @var string
*/
protected $name = 'かみなり';
/**
* 説明文
* @var string
*/
protected $description = '30%の確立で相手をまひ状態にする。';
/**
* タイプ
* @var string
*/
protected $type = 'Electric';
/**
* 分類
* @var string(physical:物理|special:特殊|status:変化)
*/
protected $species = 'special';
/**
* 威力
* @var integer
*/
protected $power = 110;
/**
* 命中率
* @var integer
*/
protected $accuracy = 70;
/**
* 使用回数
* @var integer
*/
protected $pp = 10;
/**
* 優先度
* @var integer
*/
protected $priority = 0;
/**
* 威力補正値の取得
*
* @param mixed
* @return integer
*/
public function powerCorrection(...$args)
{
/**
* @param Pokemon:object $atk 攻撃ポケモン
* @param Pokemon:object $def 防御ポケモン
*/
list($atk, $def) = $args;
// もし相手がそらをとぶチャージ中なら威力2倍
if($def->getChargeMove() === 'Fly'){
return 2;
}
// 通常補正値
return 1;
}
/**
* 追加効果
*
* @param array $args
* @return void
*/
public function effects(...$args)
{
/**
* @param Pokemon $atk 攻撃ポケモン
* @param Pokemon $def 防御ポケモン
*/
list($atk, $def) = $args;
// 相手が状態異常にかかっていない
// 30%の確率
if($def->getSa() || 30 < random_int(0, 100)){
return;
}
// 相手をまひ状態にする
$msg = $def->setSa('SaParalysis');
// メッセージをセット
$this->setMessage($msg);
}
}
powerCorrectionというメソッドを作成して、相手の状態に合わせて威力補正値を取得しています。他の技は通常このメソッドは不要ですが、変化がない(1倍)を返却しなければいけないので、親クラスにデフォルト値を返却するためのメソッドを作成しておきましょう。
技クラス(/Classes/Move.php)
<?php
$root_path = __DIR__.'/..';
require_once($root_path.'/App/Traits/InstanceTrait.php');
require_once($root_path.'/App/Traits/ResponseTrait.php');
// 技
abstract class Move
{
use InstanceTrait;
use ResponseTrait;
--省略
/**
* チャージ中に回避できない技
* @var array
*/
protected $cant_escape_move = [];
--省略
/**
* 威力補正値の取得
*
* @param mixed
* @return integer
*/
public function powerCorrection(...$args)
{
return 1;
}
--省略
/**
* チャージ中に回避できない技を取得(チャージ技の場合)
* @return array
*/
public function getCantEscapeMove()
{
return $this->cant_escape_move;
}
}
※回避不可の技を取得するためのメソッドと空プロパティも合わせて親クラスへ用意しています
では補正値計算を含めた威力の算出を、ダメージ計算前に追加しましょう。
攻撃用トレイト(/App/Traits/Service/Battle/ServiceBattleAttackTrait.php)
/**
* 攻撃判定成功時の処理
*
* @param object $atk_pokemon
* @param object $def_pokemon
* @param object $move
* @return void
*/
private function attackSuccess($atk_pokemon, $def_pokemon, $move)
{
if($move->getFixedDamageFlg()){
/**
* 固定ダメージ技
*/
$damage = (int)$move->getFixedDamage($atk_pokemon, $def_pokemon);
}else{
/**
* 通常技
*/
// ローカル変数として補正値を用意
$m = 1;
// 必要ステータスの取得
$stats = $this->getStats($move->getSpecies(), $atk_pokemon, $def_pokemon);
// ダメージ計算(物理,特殊技)
if($move->getSpecies() !== 'status'){
// 急所判定
$critical = $this->checkCritical($move->getCritical());
if($critical){
// 補正値を乗算
$m *= $critical;
$this->setMessage('急所に当たった!');
}
// 乱数補正値の計算
$m *= $this->calRandNum();
// タイプ一致補正の計算
$this->calMatchType($move->getType(), $atk_pokemon->getTypes());
// 技威力の取得(威力補正込み)
$power = $move->getPower() * $move->powerCorrection($atk_pokemon, $def_pokemon);
if(get_class($move) === 'Thunder'){
var_export($power);
}
// ダメージ計算
$damage = (int)$this->calDamage(
$atk_pokemon->getLevel(), # 攻撃ポケモンのレベル
$stats['a'], # 攻撃ポケモンの攻撃値
$stats['d'], # 防御ポケモンの防御値
$power, # 技の威力
$this->m * $m, # 補正値(プロパティ*ローカル)
);
ダメージ計算前に$powerという変数に、威力と補正値を乗算した値を格納して、それをダメージ計算の引数として渡しています。これで威力補正値込みでのダメージ計算を行うことができます。
回避判定
では、作成した回避判定を実装しましょう。こちらは攻撃用トレイトのcheckHitメソッド内に分岐を追加します。
攻撃用トレイト(/App/Traits/Service/Battle/ServiceBattleAttackTrait.php)
/**
* 命中判定
*
* @param object $atk
* @param object $def
* @param object $move
* @return boolean
*/
private function checkHit($atk, $def, $move)
{
// ふきとばし・ほえるのチェック
if(in_array(get_class($move), ['Whirlwind', 'Roar'], true)){
if($atk->getLevel() < $def->getLevel()){
$this->setMessage($def->getPrefixName().'は平気な顔をしている');
return false;
}
}
// 相手のチャージ状態による判定チェック
$charge_move_class = $def->getChargeMove();
if(in_array($charge_move_class, ['Fly', 'Dig'], true)){
$charge_move = new $charge_move_class;
// 攻撃技が回避できない技リストになければ失敗
if(!in_array(get_class($move), $charge_move->getCantEscapeMove(), true)){
$this->setMessage($move->getFailedMessage($atk->getPrefixName()));
return false;
}
}
もし防御ポケモンのチャージ状態が「そらをとぶ」か「あなをほる」であれば、回避不可技に現在使用している技が存在しているかどうかを確認しています。もしあれば、そのまま通常通り命中判定を行いますが、なければ攻撃が外れることになるためfalseを返却します。
それでは実際に確認してみましょう。
「なきごえ」は命中率100%の技ですが、あなをほる状態なので無事回避することができました。
次に「そらをとぶ」と「かみなり」の検証を行います。技を「かみなり」1択にしたライチュウを野生ポケモンとして固定します。
「そらをとぶ」状態にも関わらず、「かみなり」が当たりました。威力はvar_exportで出力してチェックしたところ、そらをとぶの前は110、そらをとぶ中には220という数値が出力されていたので、威力補正についても問題なく反映されています。
※まひになっている状態でまひにかかった旨のメッセージが出ているのは、HPと違ってステータス変化に対して動的な処理を行なっていないからです
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「そらをとぶ」と「あなをほる」の実装方法をご紹介しました。
現在プレイページを公開中ですので、気になる人はぜひ遊んでみてくださいね。