かなしばりとは
最近は技のアップデートをおろそかにしていたので、久々の追加実装です。へんしんという再現が面倒な技は乗り越えましたが、他の技も仕様がややこしいため、覚えるポケモンが用意できたタイミングに基本的に増やしていきたいのですが、バトルシステムを作り上げていく関係上、どうしても見逃せない部分が出てきてしまうため、渋々実装していくといった感じです。
そこで、今回実装するのは「かなしばり」です。
かなしばり(ポケモンwiki)
世代によって効果が異なっていますが、今回は最新世代を参考にするので「最後に使った技を4ターン封じる」を採用します。かなしばりの状態変化は重複しないので、複数の技を封じることはできません。
では、技クラスと状態変化クラスを合わせて見ていきましょう。
かなしばり:技(/Classes/Move/MoveDisable.php)
<?php
$root_path = __DIR__.'/../..';
require_once($root_path.'/Classes/Move.php');
// かなしばり
class MoveDisable extends Move
{
/**
* 正式名称
* @var string
*/
public const NAME = 'かなしばり';
/**
* 説明文
* @var string
*/
public const DESCRIPTION = '直前に相手が使ったわざを4ターン使えなくする。';
/**
* タイプ
* @var string
*/
public const TYPE = 'TypeNormal';
/**
* 分類
* @var string::physical:物理|special:特殊|status:変化
*/
public const SPECIES = 'status';
/**
* 威力
* @var integer
*/
public const POWER = null;
/**
* 命中率
* @var integer
*/
public const ACCURACY = 100;
/**
* 使用回数
* @var integer
*/
public const PP = 20;
/**
* 対象
* @var string
*/
public const TARGET = 'enemy';
/**
* 追加効果
* @param args:array
* @return void
*/
public static function effects(...$args)
{
/**
* @param atk:object::Pokemon 攻撃ポケモン
* @param def:object::Pokemon 防御ポケモン
*/
list($atk, $def) = $args;
// 相手をかなしばり状態にする
$last = battle_state()->getLastMove($def->getPosition());
$move = array_filter($def->getMove(), function($move) use($last){
// 最後に使用した技が存在しているか確認
return $move['class'] === $last;
});
// 判定(既にかかっている場合は状態変化のセット時に判定)
if(
empty($move) ||
empty($last)
){
// 縛れる技が無いので失敗
$message = ScDisable::getSickedAlreadyMessage($def->getPrefixName());
}else{
// かなしばり発動(もし既にかかっていれば失敗)
$message = $def->setSc('ScDisable', 4, $last);
}
// メッセージの返却
return [
'message' => $message
];
}
}
かなしばりの状態変化を格納する際には、第3引数に対象技を判定するための技クラスをセットしています。当初は技番号で判定しようと考えていましたが、メッセージの出力などの関係上、クラス名の方が使い勝手が良かったのでこちらを採用しました。
続いて、かなしばりの状態変化クラスについてです。
かなしばり:状態変化(/Classes/StateChange/ScDisable.php)
<?php
require_once(root_path('Classes').'StateChange.php');
/**
* かなしばり
*/
class ScDisable extends StateChange
{
/**
* 正式名称
* @var string
*/
public const NAME = 'かなしばり';
/**
* 状態変化にかかった際のメッセージ
* @var string
*/
public const SICKED_MSG = '::pokemonは、かなしばりで、::moveが使えなくなった';
/**
* すでにこの状態変化にかかっている際のメッセージ
* @var string
*/
public const SICKED_ALREADY_MSG = 'しかし、上手く決まらなかった';
/**
* 行動失敗
* @var string
*/
public const FAILED_MSG = '::pokemonは、かなしばりで、::moveが出せない!';
/**
* 回復時に表示されるメッセージ
* @var string
*/
public const RECOVERY_MSG = '::pokemonは、かなしばりから開放された';
/**
* 状態変化にかかった際のメッセージを取得
* @param pokemon:string
* @param move:string
* @return string
*/
public static function getSickedMessage(string $pokemon, $move='')
{
return str_replace(
['::pokemon', '::move'],
[$pokemon, $move::NAME],
static::SICKED_MSG
);
}
/**
* 行動失敗時のメッセージを取得
* @param pokemon:string
* @param move:mixed
* @return string
*/
public static function getFailedMessage(string $pokemon, $move='')
{
return str_replace(
['::pokemon', '::move'],
[$pokemon, $move::NAME],
static::FAILED_MSG
);
}
}
かなしばりにかかった際と失敗時のメッセージの出力は、技名を置き換えしたかったため、親クラスとは別で用意しました。複数同じパターンが必要になりそうであれば、親クラスで統一させるための判定を追加予定です。
技の使用不可判定
ここで「かなしばり」の効果について簡単にまとめておきます。
かなしばりを先手で使用して技を封じられた際に、相手がその技を入力していれば発動失敗となります。技選択時にもし封じられていれば、その技は入力不可となり別の技を選択する必要があります。
また、あばれるなどの技固定がされている際にかなしばり状態になれば、その技は失敗となり暴れる状態は解除されます。混乱状態にはなりません。
ただ、状況によってまだ未定な部分も多く複雑かつ独自の判定が入る技になるので、こちらは作りながら調整していく予定です。
では実際に、状態変化判定の部分に「かなしばり」を追加、更に技選択が出来ないように制限を追加しましょう。
バトルサービスチェック関係トレイト(/App/Traits/Service/Battle/ServiceBattleCheckTrait.php)
/**
* アタック前の状態変化チェック
* @param pokemon:object::Pokemon
* @param move:string
* @return boolean
*/
protected function checkBeforeSc(object $pokemon, string $move)
{
-- 省略
/**
* かなしばり
*/
if(
$pokemon->isSc('ScDisable') &&
$move === $pokemon->getScOther('ScDisable')
){
// 行動失敗メッセージを格納
response()->setMessage(
ScDisable::getFailedMessage($pokemon->getPrefixName(), $move)
);
// あばれる状態で金縛りを受けた場合は、失敗後に解除※こんらん状態にはならない
if(
$pokemon->isSc('ScThrash') &&
$pokemon->getScOther('ScThrash') === $move
){
$pokemon->initSc('ScThrash');
}
// チャージ状態で金縛りを受けた場合は、失敗後に解除
if(
$pokemon->isSc('ScCharge') &&
$pokemon->getScOther('ScCharge') === $move
){
$pokemon->initSc('ScCharge');
}
return false;
}
-- 省略
状態変化では「ひるみ」「反動」「こんらん」がバトル前に検証されます。ひるみと反動については優先的に判定を行い、こんらんの前にかなしばりの判定を追加しました。
この辺りも実際の仕様は確認しつつ、合わせながら変更予定ですので、細かな流れがわかる方はぜひお問い合わせお待ちしています。
では、技選択画面での制限についてです。現在技選択画面ではPPが0のみ選択不可としていますが、ここにかなしばりの判定を追加して選択不可状態にしましょう。
技選択モーダル(/Resources/Partials/Battle/Modals/move.php)
<table class="table table-bordered table-hover table-sm mb-0" id="move-table">
<thead class="thead-light">
<tr>
<th scope="col" style="width:40%">使える技</th>
<th scope="col" style="width:25%">タイプ</th>
<th scope="col" style="width:25%">PP</th>
<th scope="col" style="width:10%"></th>
</tr>
</thead>
<tbody>
<?php foreach(friend()->getBattleMove() as $key => $move): ?>
<?php if(empty($move['remaining']) || $move['class'] === friend()->getScOther('ScDisable')): ?>
<tr class="bg-light text-secondary"
style="cursor:not-allowed;">
<?php else: ?>
<tr class="move-table-row" data-key="<?=$key?>">
<?php endif; ?>
<th scope="row" data-move="name"><?=$move['class']::NAME?></th>
<td data-move="type"><?=$move['class']::getTypeName()?></td>
<td data-move="pp">
<?php if(empty($move['remaining'])):?>
<span class="text-danger"><?=$move['remaining']?></span>
<?php else: ?>
<?=$move['remaining']?>
<?php endif; ?>
/<?=$move['class']::getPp($move['correction'])?>
</td>
<td tabIndex="0"
class="text-center"
data-move="details"
data-toggle="popover"
data-trigger="focus"
data-html="true"
data-content="<?=$move['class']::DESCRIPTION?>"
title='<small>
命中:<?=$move['class']::ACCURACY ?? '-'?>
威力:<?=$move['class']::POWER ?? '-'?>
分類:<?=transJp($move['class']::SPECIES, 'move')?>
</small>'><i class="fas fa-info-circle text-php-dark"></i></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php if(friend()->isSc('ScDisable')): ?>
<p class="text-danger small mt-2">「<?=constant(friend()->getScOther('ScDisable').'::NAME')?>」は、かなしばり状態のため使えません</p>
<?php endif; ?>
レイアウトに少し迷いましたが、かなしばりの文言をテーブル下へ追加することで対応しました。では、実際に相手からのかなしばりを受けて動作確認をしてみましょう。
かなしばり状態になった際の挙動が確認できましたね。これで実装完了です。
敵AIの判定
相手ポケモンに対してかなしばりを使った際にも、技選択が出来なくする必要があります。そのため、AIによる技選択でかなしばりにかかっている技を対象外とする判定を追加しておきましょう。
// PPが残っている && かなしばり状態ではない技を選択
$move_list = array_filter($move_list, function($move){
return $move['remaining'] &&
$move['class'] !== enemy()->getScOther('ScDisable');
});
残PPが残っており、且つかなしばり状態の技ではないものをarray_filterで返していますAIの技選択はこれで選択を不可にすることができます。
へんしん状態も考慮し、バトル中の技一覧は別メソッドを使って取得しているので、こちらを使ってリストそのものを返す時点で使用できる技かどうかを返すのも方法の1つです。現状は見直す点が多いので、次の全体見直しのタイミングで綺麗に整えていく予定です。
まとめ
いかがだったでしょうか。
今回のPHPポケモンでは「かなしばり」の実装方法をご紹介しました。
現在プログラミング学習に取り組んでいる方や、ゲームづくりに興味がある方は、ぜひ参考にしてみてくださいね。