「拡張HP規格」と「攻撃属性規格」


 以前から私が提唱していた「攻撃属性規格」「拡張HP規格」ですが、添野さんの方から、 システムでHPの拡張を行う予定であることが発表されました。 発表によるとHPに小数点以下2桁の精度を持たせ、かつ当然ながら互換性の保証されるとのこと。 つまり「拡張HP規格」は完全に用なしになったということです。
 まぁ、それは非常に喜ばしいことなんですけど、 今までの調査の結果をすべて闇に葬るのは面白くないので、ここで発表してしまおう、と思い立ったわけです。

 なにかしら参考になるところがあると思いますので目を通してやってください。

拡張HP規格

 現行のシステムでは体力の最大値が88であることは周知の事実だと思います。 この値は、とくに移植キャラ製作者にとって悩みの種です。 移植元のゲームではHPの最大値が128以上のものが多く、 SFXVI用に値を補正すると微妙に差が出てきてしまいます。 特に削りダメージの問題は深刻で、ヒット数の多い必殺技はガードさせても相当量のダメージになってしまいます。
 そこからHP精度の拡張の必要性が生まれてきたといえるでしょう。

 現在、拡張HP規格では32倍の精度を持たせることとしています。 つまり最大値は88*32=2816ということになります。

 どうあがいてもシステムで定められているHPの最大値を変更することは出来ません。 ですから、キャラクタ個別にHPの値を用意し管理する必要があります。
 体力の変化が生じた場合はまず、この値に変更を加え、 その結果をシステムHPに反映させるというのが拡張HP規格の基本です。

 次の用語を以降で使用します。
基本HP:システムで管理しているキャラクタの体力値
拡張HP:キャラクタ個別に管理する体力値
同期:基本HPの値を拡張HPに反映させる、あるいはその逆の処理


 話を簡単にするために、とりあえず拡張HP規格対応キャラ同士の場合だけ考えていきます。

 上記により体力変化の発生するタイミングを全て監視してやる必要があります。

 HPが減少する可能性は3パターンあります。
  1. 相手の攻撃でHPが減少した
  2. 自分でHPを減少させた
  3. 自殺コマンドが入力された
 いずれの場合も例外なく自分の「VCT_受ダメージ量調整処理」ベクタを通過します。 ですからこのベクタ内で拡張HP用の処理を行うようにすればいいわけです。

 HPが増加する可能性は3パターンあります。
  1. 自分でHPを増加させた
  2. 相手からHPを増加させられた
  3. トレーニングモードによる自動回復
これらのうち、1は特に問題ありません。回復のタイミングは自分でわかるわけですから。 2は体力回復のリクエスト関数を用意し、それを使ってもらうことにすれば解決です。 そして3。こればかりは手の打ちようがありません。毎サイクル、基本HPを監視し、 拡張HPより値が大きくなったとき、HPの増加が発生したとみなすしかないでしょう。

 さて、これですべての体力変化イベントをフックすることが出来ました。 次に必要なことは拡張HPに対応した体力変化量を受け渡す方法です。
 もっとも簡単な方法はCBでヒット情報を拡張HPに対応した値で作成するというものです。 これで通常の攻撃はすべて拡張HP対応値になります。 投げなど直接変化値を指定する必要のあるものは、そこに拡張HP対応値を指定してやります。


 互換性を無視すればたったこれだけで済むんですよね。しかし、互換性は無視出来ません。 これをどうやって解決するかは以降で延べることにします。

 ここまでで述べた手法で拡張HP非対応キャラと対戦するとどうなるでしょうか。

 まず、自分の攻撃が相手にヒットした場合、各攻撃力値は基本HPの32倍の値になっているので、 そのほとんどが即死レベルの攻撃となってしまいます。 ですから、非対応キャラと対戦する場合は、非対応キャラ用の攻撃力値を受け渡すようにするか、 攻撃力値を32で割った値を受け渡すかする必要があります。
 また、逆に相手の攻撃を受けた場合は、ごく微量のダメージにしかなりません。 この場合は受けるダメージを32倍してやる必要があります。


 さて、対戦相手が拡張HP規格に対応しているかどうかは簡単に調べられます。 キャラクタ間通信関数を利用すればいいのです。

  Cmd_拡張HP = Icc取得_項目( p2 , "CMD_拡張HP" ) ?
                 Icc取得_数値( p2 ) :
                 OFF;

この処理を「OPT_登場」で実行し、 変数Cmd_拡張HPに0以外の値が格納されれば拡張HP対応キャラであるということになります。


 まず、「VCT_与ダメージ量調整処理」ベクタ内部で規格対応キャラかどうか判定し、 非対応であればベクタの第3引数から得られる攻撃力値を32で割ってやればよさそうです。
 次に「VCT_受ダメージ量調整処理」ベクタ内部で、 非対応キャラの攻撃力値を32倍してやれば受けるダメージの問題も解決しそうです。
 相手に体力を回復された場合は、前述の「トレーニングモードの対応」方法でなんとかなります。

 この時点での規格を「拡張HP規格α版」ということにします。 α版に対応したキャラは実は2作発表されています。まず一つ目はKYOSKE氏作「K_LUKS」です。 そしてα版に若干の改良を加えたものが拙作「セーラームーン」に搭載されています。

 規格対応キャラの稼動実績もあり、一見完璧なように見えます。 が、そう簡単にはいかないものです。これではだめなのです。

 では何がいけないのでしょうか?

 ここまで説明してきた方法では、拡張HP対応攻撃力値はヒット情報に格納されます。 そして、対戦相手のヒット情報を参照することが許されています。 つまり、拡張HP対応攻撃力を、非対応キャラが参照することがあるわけです。 これによってどんな影響があるかは不明ですが、互換性を考えれば、無視するわけにはいきません。

 単純に、ヒット情報に拡張HP対応攻撃力を持たせることは出来なくなりました。 ではどうすればよいのでしょうか?いくつか方法は考えられると思いますが、ここでは二つ挙げてみます。

1.ヒットIDを二つ用意する
 たとえば立ちキックのヒット情報としてヒットID50に基本HP対応の攻撃力値を用意し、 ヒットID51に拡張HP対応の攻撃力値を用意します。 立ちキックの動作関数内では攻撃設定_ヒット情報()の引数としてID50を指定します。
 攻撃がヒットし、VCT_与ダメージ量調整処理が呼び出されたら、相手が規格に対応しているかどうか調べます。 対応していれば現在のIDに1を足した51番のヒット情報から値を拾うようにします。

2.外部にデータを持たせる
 ヒット情報には基本HP対応値のみ用意します。 そして、それぞれのヒットIDに対応した拡張HP対応値を拡張ヒット情報として用意します。
 攻撃がヒットし、VCT_与ダメージ量調整処理が呼び出されたら、 現在指定されているヒットIDを調べ、そのIDに対応した値を拡張ヒット情報から取得します。

 1は特殊なツールを用意する必要がないぶん簡単ですが、ヒットIDの使用数が倍増するというのが欠点です。 また、エディタ上では順番に並んでいてもヒットIDが連番になるという保証はありません。
 2は専用のエディタを用意するなどの手間がかかりますが、その分自由度が高いといえます。

 さて、どちらの場合にも共通な処理が必要となります。 それは「現在指定されているヒットIDを取得する」処理です。 この情報はワークエリアなどを参照しても得ることが出来ません。
 これを実現しようとした場合、真っ先に思い付くのは、 攻撃設定_ヒット情報()の実行と同時にグローバル変数にIDを格納するという方法です。 しかし、これには穴があります。飛び道具などを使用している場合、 攻撃のヒットする順番とグローバル変数にIDを設定する順番が同じになる保証はありません。 別の方法を考える必要があります。

 攻撃取得_被ヒット情報()という関数があります。 これは最後に自分が受けた攻撃のヒット情報を指すアドレスを返します。 この値は基本的にヒットIDと一対一で対応しています。 ですから、この値を利用すればヒットIDを知ることが出来ます。
 VCT_与ダメージ量調整処理で、相手の被ヒット情報を参照し、 そこからヒットIDを取得することが可能なのです。

 しかし、これでも完璧ではありません。 投げ技などで相手にダメージを与えた場合、被ヒット情報は変化しません。 そもそも投げ技などで使う状態設定_残り体力()ではヒットIDを必要としていません。
 この場合は被ヒット情報を無理矢理書き換えることで対処します。 適当なヒットIDに投げ技用のヒット情報を設定し、そのアドレスを被ヒット情報とするのです。

 ここまで規格を煮詰めた時点で、もはや一分の隙もない、と思い拡張ヒット情報エディタの作成を開始しました。 一応、公開できるレベルまで完成しています。そして、ライブラリの作成も開始しました。 こちらも完成目前のレベルまで達しています。 これで楽しい拡張HP生活が楽しめる(α版対応キャラを作成したとき、 攻撃力設定のあまりの自由度の高さに感動したという経験があります)。

 が、そんなに甘くはなかったのです。

 ちなみに、この時点での規格内容を「拡張HP規格β版」と呼ぶことにします。

 β版に足りないのは何か?これはシステムの仕様に関わってきます。

 自分の体力を減らそうとしたとき、以下のような順序で処理が行われます。
  1. p1が状態設定_残り体力()あるいはゲージ増減_体力()を実行する
  2. p2のVCT_与ダメージ量調整処理が呼び出される
  3. p1のVCT_受ダメージ量調整処理が呼び出される
  4. システムがp1の体力を減らす
ここでは2に注目してください。体力の減少を命じたのはp1であったにも関わらず、 p2のVCT_与ダメージベクタが呼び出されています。これによってどんな現象が発生するのでしょうか?

 p1が規格非対応、p2が規格対応キャラだったと仮定します。 するとp2の与ダメージベクタではp1が最後に受けたヒットIDから攻撃力を取得します。

 逆の場合を検証してみます。1で指定した値がp2の与ダメージベクタで加工され、 p1の受ダメージベクタに渡されます。 規格非対応キャラの攻撃力は32倍するような処理を組み込んでいますから、 結局、最初に指定した値の32倍の値が得られることになります。

 規格対応キャラが自分の体力を減らす分にはフラグを立てるなどして対処できますがそうでない場合の対処法はありません。 添野さんにこのことを報告し、仕様変更をお願いしたのですが、互換性の問題もあり即答は出来ないとのこと。 まあ当然ですけどね。

 結局、添野さん自らシステムの拡張を行うということになり、 拡張HP規格の必要性がなくなったのです。

 余談ですが、システムで用意されている自殺コマンドの正体は10000ポイントのダメージを与えることだったのです。 この場合も自分にダメージを与えるのと同じ不具合が発生します。

 しかし、この攻撃は自殺コマンドである、と推測することが可能ですので、回避策は存在します。

 まず、VCT_与ダメージの第3引数で得られる攻撃力が10000であれば自殺コマンドであるとみなせます。 こちらは簡単です。
 VCT_受ダメージの第3引数で得られる攻撃力がある程度大きい場合、 それを自殺コマンドとみなすことが出来ます。この、ある程度、というのが問題なのですが、 対戦相手が規格対応キャラなら10000、非対応キャラの場合は100以上が該当すると見ていいのではないでしょうか。

 ただし、自殺コマンドの仕様が将来において変更される可能性がないとは言い切れませんので、あくまで参考程度に。

 こうして一応の決着がついたかに見えました。 添野さんの都合により、システムのバージョンアップは夏以降ということなのでしばらく何も出来ません。

 ちょうどその頃、AT互換機を購入、さらにToHeartにハマり、 ホストがうちに移転するなどとあわただしく、しばらくキャラ制作が出来ない状況になりました。

 が、やはりキャラ制作をしないでいるのはつまらない。 システムのバージョンアップは待てない、ということで拡張HP規格を再び練り直すことにしました。

 β版までは、攻撃力の受け渡しをVCT_与ダメージ、VCT_受ダメージベクタの第3引数を利用していました。 これを止めれば規格非対応キャラに拡張HP対応値および、それを加工した値は一切流出しないことになります。 VCT_与ダメージの第3引数の値を全く変更せずそのままにしておくことで前述の穴は埋まることになります。

 では規格対応キャラ同士での受け渡しはどうするのか。

 答えは簡単です。リクエスト関数を使って受け渡しをすればいいのです。 散々悩んだ割には、あっけなく解決したように見えます。 本当にこれで穴は全て埋まったのか、と心配しつつもテストでは問題なく動いているようです。

 この規格をγ版とします。

 今のところγ版においての問題点は認められていません。 このまま何事もなく済めばいいのですが。

攻撃属性規格

 もともと攻撃属性規格が先にありきだったのですがいつの間にやら立場が逆転してしまいました。 しかし、こちらもかなりいろいろなことが出来そうな規格なのです。

 格闘ゲームにおいて、炎には耐性があるが冷気には弱い、 といった攻撃の属性ごとに耐性が異なるシステムを採用したのはウォーザード(CAPCOM)が最初だったと記憶しています。
 RPGではごく普遍的に取り入れられている属性攻撃ですが、格闘ゲームにはなぜ少ないのでしょうか。
 とにかく、ゲームのルールを拡張するということは可能性をひろげることになります。 いくら画面演出が派手になろうと、ゲームの本質的に出来ることがひろがらなければ行き詰まりは目に見えています。

 見た目の変化より質の変化こそが必要、とSFXVIの未来を心配しつつ考えたのがこの規格なのです。 ちょっと大袈裟ですけど。

 攻撃属性規格を組み込むことでどのような利点があるのでしょうか。
  1. 炎に弱い、冷気に耐性があるなど、キャラに個性を持たせることが出来る
  2. 属性攻撃を使い分けるという戦略性がひろがる
  3. 防御力無視属性で、指定した値のダメージを確実に与えることが出来る
  4. 乱舞系の技で、最後の攻撃以外では止めをさせない、ということも簡単
 逆に問題点は、何といっても「好んで弱点を付加したがる人がいるのか?」ということでしょう。

 攻撃属性規格は「ダメージを受けた攻撃の属性を知ることが出来る」というものです。 つまり、「VCT_受ダメージ量調整処理」内部でのみ属性の取得が可能であるということになります。
 残念ながら、今相手が出している攻撃の属性を知ることは出来ません。 これは飛び道具が画面上に存在している場合、正しい属性が取得できなくなるためです。

 攻撃属性は、ヒット情報を拡張する形で組み込むのが楽です。 ヒット情報の拡張といえば拡張HP規格ですでに実現されてますから特に難しいことはありません。
 これでヒットIDそれぞれに対して個別に属性を設定することが出来ます。

 属性の受け渡し方法は以下のように規定します。
  1. 攻撃側はVCT_与ダメージにおいて、現在のヒットIDを取得し、 そのIDに対応した攻撃属性をグローバル変数に代入する
  2. 受け側はVCT_受ダメージにおいて、上記グローバル変数を参照するためのリクエスト関数を実行する

 受け渡し方法の次は、受け渡す内容ですね。これは32ビットの符号なし整数を使用します。 つまり、unsigned int もしくは unsigned long になります。
 ビットごとに属性を持たせ、ビットのON/OFFで、属性の有無を指定します。

 各ビットの意味ですが、これはまだ確定していません。 属性の要素として最低限必要なものと候補にあがっているものを列挙しておきます。

1.必須
炎、防御力無視、不殺
2.候補
冷気、電撃、大地、水、風、毒、光、闇
実体、飛び道具、手、足、武器


 ここまでの内容を「攻撃属性規格α版」とします。 拡張HP規格と比較すると非常に単純なつくりになっています。とくに穴もないように見えます。

 しかしα版ではVCT_受ダメージ内でのみ属性の取得が可能であるため、 たとえば「武器攻撃だけを対象とする当て身投げ」といった技に利用することが出来ません。 そこでβ版仕様を定めます。

 前述の通り、飛び道具が存在する以上、VCT_受ダメージ以外で属性の取得をすることが出来ません。 そこで、思い切って飛び道具を無視します。 そうすることで攻撃設定_ヒット情報()が実行されたサイクルで属性の取得が可能になります。

1.攻撃側は、攻撃設定_ヒット情報()、攻撃設定_空中ヒット情報()の実行と同時にグローバル変数に攻撃属性を代入する(α版のグローバル変数とは別に変数を用意する)
2.受け側は、任意の場面で(OPT_サイクル2が望ましい)攻撃取得_ヒット情報( p2 )を実行し、戻り値が0以外なら、リクエスト関数で属性値を取得することが出来る

 ここで注意していただきたいのですが、β版の仕様はα版に追加する形で実装されることになります。 ですから、VCT_受ダメージではα版の仕様通り、飛び道具でもなんでも属性を取得できます。 VCT_受ダメージ以外の場面で属性を取得するときのみ飛び道具が無視されるのです。

 両規格とも、現段階で実現の見通しが立ってきました。 しかし、システムのバージョンアップによりどのような展開を見せるのか不明なため正式に発表するのはためらわれるというのが実状です。

 それでも興味があるという人がいるのであれば、なんとか発表したいと思っています。 意見、感想をお待ちしています。

ひとつ前にもどるSFXVI Worldにもどるトップページにもどる