GOREとにゃんこの桃源郷

主観的にCDのレビューやら、日記やら、色々と。
ゴアとかメタルとかロックとか

RPGツクールMZ - その7

2023-09-29 | RPGツクールMZ,VXace,VX,2000,95,1~5

 「MOG_BattleHud」の表情パターンを増やしています。例えば睡眠の状態を追加。
_bhud_face_data = [0,0,0,1] ⇒これの要素2(左から3つ目)が現在の表情(つまり準備している画像の左から何番目か)を示しています。
「update_face_animation」に条件文を追加するだけで、簡単に表情を増やせます。※直接記載しないか、またはバックアップを取っておくことをお勧めします。
 ただし、優先順に条件が設定されていることに注意が必要です。例えば初めに戦闘不能かを判断しており、戦闘不能であればその後一切のアニメーションはスキップされます。これは、デフォルトでは戦闘不能アクターに攻撃等の行動を実行できないためです。記載方法が間違っていると、睡眠中に攻撃を受けると被ダメージの表情になったり、行動した時の表情が次の行動後まで残ったりします。
「updateFaceEffects」には呼吸エフェクトが適用されるかが設定されています。デフォルトでは待機(インデックス0)と被ダメ&瀕死(インデックス3)が呼吸在りになっています。そのほかの回復(インデックス1)等が設定されていないのは、アニメーションのフレーム数が消化されると待機の表情に戻る、一時的な表情であるからです。
「Game_Action」の「apply」も大事です。被ダメ、回復の際の表情設定がされています。自分は睡眠状態の時にダメージや回復で一瞬起きるのも変だなと思ったので、!target.isStateAffected(睡眠のステートID)等の条件で括りましたが、凝るなら睡眠中の被ダメ、睡眠中の回復みたいに更に表情を追加するのもありかなと思いました。
「prepare」に関しては行動時(インデックス2)が設定されています。ズームする時の表情です。これは変更するとしたら攻撃スキルの時はより攻撃的な表情だったり周りにオーラっぽい光をまとわせた画像を追加するのはどうでしょうか。試していませんがGameActionクラスなのでitem.isSkill().requiredWtypeId1 !== 0とかいけますかね。必要武器を設定しているから攻撃スキルみたいな作り方であれば。

 その他の案としては、フロントビュー限定になりますが最初から被ステートを取得しておいてoverlayをもとに分岐させるようにするのが良さそうだと思いました。これはサイドビュー用の設定項目なのでフロントビューであれば余っているはずで、且つデータベース上で10種類くらい設定可能なので利便性が高そうに思います。このパターンならデータベースを並び替えたり、追加/更新してもプラグインを書き換える必要がありません。
 なんかでもまぁ、色々出来るからこそ何処まで追求するのか、制作ってどんなものでも、沼となるか否かも自分次第ですよね。音楽にも通じますが、個人的には追及した結果から引き算で調整していける人はセンスあるなと思います。最初からスカスカなのとは全く話が違って、あくまで要素を潤沢に準備した上で客観視点で切り捨てていける。せっかく作ったのだから活かす方法を考えるかのも良いですが、何でもそうしていると大体ごちゃっとした自己満作品になりがちだなと。Necrocannibalistic Vomitriumなんてドラムボーカルとベースだけで20年も活動し続けてますし、余計なものを削ぎ落すって意味では必聴なのでは?


RPGツクールMZ - その6

2023-09-25 | RPGツクールMZ,VXace,VX,2000,95,1~5

 細々(ほそぼそ)と細々(こまごま)した改変(あらた かわり)を細(ぽそ)く長(おさ)く行(△□〇ー)っている。アクターコマンドの攻撃だけ、武器名称を表示させる都合上、長くしたかったので下画像のようにした。隠れたインデックス1(スタートの武器欄は0)を作成して、疑似的にコマンド数を調節している。インデックス1はダミーコマンドとして設定しつつも、テキストは空欄""、widthは0にした。また、インデックス0(武器欄)のみrect(矩形)を他インデックスの2倍に設定。


Window_ActorCommand.prototype.makeCommandList = function() {
    if (this._actor) {
        this.addAttackCommand(); 
        this.addDummyCommand();//これを追加
        this.addSkillCommands();
        this.addGuardCommand();
        this.addItemCommand();
    }
Window_ActorCommand.prototype.addDummyCommand = function() {
    this.addCommand("", "Dummy", "");//ハンドラはNUUNさまのCommandIconに対応するため設定。
};
Window_ActorCommand.prototype.itemRect = function(index) {
    const maxCols = this.maxCols();
 let itemWidth;//項目の幅をインデックス毎に設定。
 if(index === 0){
  itemWidth = this.itemWidth() * 2;
 }
 else if(index === 1){
  itemWidth = 0;
 }
 else{
  itemWidth = this.itemWidth();
 }
    //const itemWidth = index === 0 ? this.itemWidth() * 2 : this.itemWidth();
    const itemHeight = this.itemHeight();
    const colSpacing = this.colSpacing();
    const rowSpacing = this.rowSpacing();
    const col = index % maxCols;
    const row = Math.floor(index / maxCols);
    const x = col * itemWidth + colSpacing / 2 - this.scrollBaseX();
    const y = row * itemHeight + rowSpacing / 2 - this.scrollBaseY();
    const width = itemWidth - colSpacing;
    const height = itemHeight - rowSpacing;
    return new Rectangle(x, y, width, height);
};



 その後に必要となるのが、カーソルの設定になる。このままだと見た目には何も無いダミー項目にカーソルが移動するので、アクターコマンドのクラスにカーソル移動メソッドを定義して設定していく。

例えばWindow_ActorCommand.prototype.cursorDownに、次のような条件文を加えたりする。ちなみにカーソルに関するメソッドはWindow_Selectableクラスにある。
if(index === 0){
  this.smoothSelect(2);
 }

 結果的に想定通りの挙動が出来たので満足。ただ無理やりな方法なのでメンバー毎にコマンドが異なるゲームには使えない。あとはこの先、変なバグとか出ないことを祈るのみ。

 ところで画像から察しが付くと思うが、みんな大好きMoghunterBattleHudを利用している。コマンド位置の自動調整で、幅を大きくすると画面外にはみ出てしまうため、下記に手を加えてみた。同じような悩みを持って夜もおちおち眠れないし同年代と比較して圧倒的に禿げてきたという人は参考にされたし。「update Position S」のメソッドに条件文を追加するだけ。


this.yp = $gameTemp._bhud_position_active[1];//元々の処理
    if(this.xp + this.width < Graphics.width){//追加
     this.org[0] = $gameTemp._bhud_position_active[0] + Moghunter.bhud_com_x - this._fx;
    }
    else{
     this.org[0] = Graphics.width - this.width;
    }


RPGツクールMZ - その5

2023-09-16 | RPGツクールMZ,VXace,VX,2000,95,1~5

 わくわくするようなプラグイン素材の数々、ゼロから書けない自分にとっては宝石箱のようなもの。彦摩呂だってツクラーだったらそんなこと言いそう。トリアコンタンさまの「説明テンプレートプラグイン」を利用して、自分向けに利便性を高める改変を施した。 
 といっても、「function createDescription」の前後に配列と条件文を追加しただけ。スキルレベル的な問題が大きな壁としてうんにゃらかんにゃらでそれくらいの改変しか出来ない。


 
    const paramProps = ['mhp', 'mmp', 'atk', 'def', 'mat', 'mdf', 'agi', 'luk', 'hit', 'eva', 'cri', 'cev', 'mev', 'mrf', 'cnt' ];//既存に追加能力値の略称を追加
const paramNaming = ['HP', 'MP', '攻撃', '防御', '魔力', '魔防', '素早さ', '運', '命中', '回避', '会心', '会心回避', '魔法回避', '魔法反射', '反撃率'];//ネーミング用、色変更をプラグインパラメータ側で行うため。

//能力値取得のelese内にスイッチ分岐して、変化のある能力だけを説明欄に記載させる。
const paramIndex = paramProps.indexOf(propName);
    switch(paramProps[paramIndex]){
     case 'mhp':
     case 'mmp':
     case 'atk':
     case 'def':
     case 'mat':
     case 'mdf':
     case 'agi':
     case 'luk':
      if(data.params[paramIndex] > 0){
       return '+' + data.params[paramIndex] + ' ';
      }
      else if(data.params[paramIndex] < 0){
       return data.params[paramIndex] + ' ';//マイナス符号は勝手に付くらしい。
      }
      else{
       return '';//増減しない値は非表示。
      }
      break;
     case 'hit':
     case 'eva':
     case 'cri':
     case 'cev':
     case 'mev':
     case 'mrf':
     case 'cnt':
      const rate = data.traits.reduce((r, pm) => pm.code === 22 && pm.dataId === (paramIndex - 8) ? r + (pm.value * 100) : r, 0);
      if(rate > 0){
       return '+' + rate + '% ';
      }
      else if(rate < 0){
       return rate + '% '; 
      }
      else{
       return '';
      }
      break;
    }
    const nameIndex = paramNaming.indexOf(propName);
    switch(paramNaming[nameIndex]){
     case 'HP' :
     case 'MP' :
     case '攻撃' :
     case '防御' :
     case '魔力' :
     case '魔防' :
     case '素早さ' :
     case '運' :
      return data.params[nameIndex] !== 0 ? paramNaming[nameIndex] + ' ' : '';
      break;
     case '命中' :
     case '回避' :
     case '会心' :
     case '会心回避' :
     case '魔法回避' :
     case '魔法反射' :
     case '反撃率' :
      const rate = data.traits.reduce((r, pm) => pm.code === 22 && pm.dataId === (nameIndex - 8) ? r + (pm.value * 100) : r, 0);
      return rate !== 0 ? paramNaming[nameIndex] : '';
      break
    }
 

 そもそも装備品用の改変なので、スキルでは一切役に立たない。これを設定するあたり、プラグインパラメータの説明テンプレートは結構可読性が減少。
\C[23]【${wtypeId}】\C[3]${攻撃}\c[0]${atk}\C[3]${防御}\c[0]${def}\C[3]${魔力}\c[0]${mat}\C[3]${魔防}\c[0]${mdf}\C[3]${素早さ}\c[0]${agi}\C[3]${運}\c[0]${luk}\C[3]${HP}\c[0]${mhp}\C[3]${MP}\c[0]${mmp}\C[3]${命中}\c[0]${hit}${回避}\c[0]${eva}\C[3]${会心}\c[0]${cri}\C[3]${会心回避}\c[0]${cev}\C[3]${魔法回避}\c[0]${mev}\C[3]${魔法反射}\c[0]${mrf}\C[3]${反撃率}\c[0]${cnt}
${description}」
 けれど、能力変化の有無を勝手に判別して、無い場合には「攻撃」という項目自体も表示されなくなるので、ヘルプと実態の設定ミスが大きく減少するはず。日本の出生数くらい減少するはず。もっと言えば物価高騰に於いて所得据え置きの現状から相対的な収入減少を示唆している。
 
 こういう適当に設定したパラメータから、自動的に値0以外のものだけを取得する。
<style type="text/css"></style> <style type="text/css"></style>

RPGツクールMZ - その4

2023-09-10 | RPGツクールMZ,VXace,VX,2000,95,1~5

 やっとステータス画面が完成した。VXAceの時のようにdraw_guageが用意されていないので、水平線は諦めるしかないかと思ったが、BitmapクラスにgradientFillRectなるものがあったので事なきを得た。この画面はスキルリスト画面を参考に作成した。コマンドの選択肢にマウスカーソルを載せるだけで画面の中が書き換わる構成にした。初めは3画面準備して、show(),hide()で切り替える想定だったが、よくよくスキルリスト画面とスキル画面、対応するシーンをトレースしたところ、マウスオーバーで可能だと分かり方針転換した。update(秒間50~60程度だったろうか)の際にカーソル選択を監視すればいいらしい。

 属性とか沢山ある。何故多いのかと言うと、作る規模が分からないから、足りなくなるより先に準備しておく性分なので、使わなければカットするのは簡単。増やす事こそ難しい。表示スペースの問題も出てくるし、減らすほうが断然楽だと思うが、アイコンが足りないのは事実なので、配布されている素材を改変したり、それなりに作業は発生する。

 ステートも40種類くらい表示させているものの、効果未設定もあるので使うか分からない。そんなこともあるので、プラグインのパラメータに配列で格納しているから、後で不要になったものを削除してもパーツが上に、あるいは左に詰まっていくだけのはず。

 だがあと装備画面が手つかずの状態だと思うと気が滅入ることもあるが、いいプラグインがあれば頼ることにしたい。いいプラグインとは、自分のプロジェクトと競合しないものを指す。最悪競合しても、一から自作するのとトラブルシュートのどちらが楽かはよく考えて選択するつもりだ。


gradientFillRect (x, y, width, height, color1, color2, vertical)
 カラー1からカラー2にかけてグラデーションの矩形を作成してくれる。verticalは縦グラデーションの指定、その分描画パワーが必要になるはずなので今回は使っていない。

//----------------------------------------------------------------------------- // ColorManager
ColorManager.stLineColor1 = function() {
 return this.textColor(12);
};
ColorManager.stLineColor2 = function() {
 return this.textColor(14);
};
//-----------------------------------------------------------------------------

 カラーマネージャにグラデーション専用色を設定しておくと楽。カラーパレットは下記ファイルの右下にある32色を左上から右に向かって数える。
./img/system/window.png


RPGツクールMZ - その3

2023-09-08 | RPGツクールMZ,VXace,VX,2000,95,1~5

 ステータス画面を改装中。アクターを表示するSimpleStatusは理想の形に出来た。ゲージ描画の仕組みに悪戦苦闘した。特にHP、MP、TPをそれぞれ別の幅で描画することで2段で表示させたいという要望があった。あと状態異常のアイコンが9個表示できるように幅を取っている。意識的にやらなければそんな異常事態にならないと思うが、小さいことに拘ることがツクールの神髄と信じてやまない。
 メニューステータスはTP表示せず、HP、MPも現在値だけにしている。項目としてのステータス画面はなるべく詳細な情報を載せたいという思いからこの構成に。おそらく大雑把な人からすると感覚的に分かる情報だけで事足りるので、数値的なものを意識する人こそステータス画面を表示させる、つまりはメニューから選択するのではなかろうか。けどTPは戦闘中から引継ぎしないので、ステータス画面では必ず最大値だけ表示されるようにした。


 さて、先に述べたゲージ描画について、何に躓いていたか下記に残そうと思おう今の僕は。


これが成功例。mpゲージ、tpゲージ等、ステータスタイプによってそれぞれ幅を指定している。timeは戦闘中しか使わないので省いて構わないけどデフォルトの値が分かるように残している。けどステータスタイプが入らないパターンって何だろう。その場合256にしちゃってるから、この再定義項目についてはこの画面からしか参照されないようにしたいと思う。
Sprite_Gauge.prototype.bitmapWidth = function() {
 if(this._statusType === "mp"){
  return 180;
 }
 else if(this._statusType === "tp"){
  return 77;
 }
 else if(this._statusType === "time"){
  return 128;
 }
 return 256;
};


こっちが失敗例。成功例の場合もそうだが、何故か"hp"を指定するとどう書いても上手くいかなかった。他のプラグインと競合しただけかもしれない。
Sprite_Gauge.prototype.bitmapWidth = function() {
 switch (this._statusType) {
            case "hp":
                return 256;
            case "mp":
                return 180;
            case "tp":
                return 77;
            case "time":
                return 128;
    }
 return 128;
};


RPGツクールMZ - その2

2023-09-06 | RPGツクールMZ,VXace,VX,2000,95,1~5

 続きまして、ステートのメモ欄に「sealItem」と書かれているステートに感染すると、アイテムコマンドが封印されるという仕組みを作った。感染中のステート配列から、メモが記載されているステートだけのフィルタリング結果が0件であればアイテム使用可能、1件以上あると使用不可になる。
 各スキルコマンドや防御コマンドの封印はデフォルトで設定できるから、考えてるのは攻撃コマンドくらい。攻撃封印の場合、アイテムやスキルが無い、さらに防御が封印されていたら何も選択出来ずに詰んでしまう。なので攻撃を「何もしない」に変更する必要があると思っている。それでも自動戦闘では問答無用で通常攻撃がアクションリストに含まれるので、その辺りも含めて設定する箇所が多い気がする。手動戦闘のコマンド、自動戦闘のアクションリスト、それと混乱時のアクションリストあたり。

 二つ目は、武器を装備していない場合、攻撃コマンドを「素手」という名称にしている。武器を装備している場合は、武器の名称が表示される。画像の武器アイコンが爪、名称が剣になっているのは初期設定から武器種別しか弄っていないため。

 三つ目は、「パッシブ」というスキル種別は戦闘中のコマンド(アクターコマンド)に現れないようにしている。

 以上のように、多少の改変を出来るところからちまちまと。


const _Window_ActorCommand_addItemCommand = Window_ActorCommand.prototype.addItemCommand;
Window_ActorCommand.prototype.addItemCommand = function() {
 _Window_ActorCommand_addItemCommand;
 const resItemCommand = this._actor._states.filter(state => {
  if($dataStates[state].meta.sealItem){
   return state;
  }
 });
 this.addCommand(TextManager.item, "item", resItemCommand.length === 0);
};


const _Window_ActorCommand_addAttackCommand = Window_ActorCommand.prototype.addAttackCommand;
Window_ActorCommand.prototype.addAttackCommand = function() {
 _Window_ActorCommand_addAttackCommand;
 let text = "";
 this._actor.equips()[0] ? text = this._actor.equips()[0].name : text = "素手";
    this.addCommand(text, "attack", this._actor.canAttack());
};

const _Window_ActorCommand_prototype_addSkillCommands = Window_ActorCommand.prototype.addSkillCommands;
    Window_ActorCommand.prototype.addSkillCommands = function() {
        _Window_ActorCommand_prototype_addSkillCommands;
  const skillTypes = this._actor.skillTypes();
         for (const stypeId of skillTypes) {
            const name = $dataSystem.skillTypes[stypeId];
            if(name !== 'パッシブ'){
      this.addCommand(name, "skill", true, stypeId);
       }
         }
};

RPGツクールMZを買ってこんストラくしョんナう!

2023-09-05 | RPGツクールMZ,VXace,VX,2000,95,1~5

 RPGツクールMZ(以下MZ)はJavaScriptを利用することが出来る。JAVAと名称が酷似しているが書き方は結構違うのでややこしい。寧ろ旧作で利用出来たRubyのほうがJAVA風な気がする。一番ややこしいのは先頭と末尾の括弧の数だ。眠くなる等の理由で消してしまうと、何処でSyntaxエラーが起きているのかトレースが非常に大変だ。そういう意味でもRubyのほうが分かり易かった。ただMZはプラグイン管理から@Typeによる設定項目が使えるなど非常にユーザーライクな点には、尿道から涙を流すほど感動したものだ。また買ってから一週間程度なので、ストーリーは皆無、ずっとインフラ整備に明け暮れている。

 そんな中で、ステート耐性の共有プラグインを作った。これは、毒や猛毒など似たようなステートを作成する場合に役立つのだろうか。この例の場合だと、毒に耐性を持つ防具を作る際、ステート有効度から毒耐性と猛毒耐性、二種類の有効度を設定することになる。でも今回のプラグインを使い、猛毒ステートのメモ欄に毒ステートのIDを記載することで、猛毒ステートは毒ステートの有効度を参照することになる。しかしまだ作ったばかりで満足にテストしきれていないのでバグってたら切ない。

 挙動に問題無いとして、注意点もある。ステート無効化を考慮していないので、必要な時以外は無効化を利用せずにステート有効度0%で済ませたい。

 あとはVXaceの時と同じように「二つ名を感情として扱い、感情によってTPチャージ率が変化する仕組み」も作った。しかし期待通りに動作すれば良いというものでもなく、あまりにゲロ臭いコードになってしまったのでとても紹介出来ない。いや、出来やしない。

 可否についてどう書くタイプか。俺は専ら出来る、出来ないと漢字で書くタイプだ。


// Copyright (c) 2023 GCC
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
/*:
 * @target MZ
 * @plugindesc ステート耐性を共有する
 * @version 1.0
 * @help ステートのメモ欄にの形式で記載。StateIdは数字で入力。
 * 例:←ID8のステート耐性を参照させる。
 * 【ver.1.0】
 */
(() => {
 const _Game_BattlerBase_share_stateRate = Game_BattlerBase.prototype.stateRate;
 Game_BattlerBase.prototype.stateRate = function(stateId) {
   if($dataStates[stateId].meta.ResistShare){
     return _Game_BattlerBase_share_stateRate.call(this, stateId) * this.traitsPi(Game_BattlerBase.TRAIT_STATE_RATE, Number($dataStates[stateId].meta.ResistShare));
   }
   else{
     return _Game_BattlerBase_share_stateRate.call(this, stateId);
   }
 };
})();

 そういえば色んなプラグインをダウンロードさせて頂いた。その中の自動戦闘プラグインを少し改変して、MP消費しない行動のみ、敵スコープの行動(スコープ1~6限定)のみ、それと通常攻撃だけ行う自動戦闘を追加してみた。そして自動戦闘中にキャンセルあるいはマウスの右クリックを押すと自動戦闘が解除される仕様にした。結局、できるできないを漢字で書くか否かだけで人を判断するのは危ういだろう。

 アクターコマンドについても忘れていた。攻撃という表示は撤廃し、装備中の武器タイプに応じたアイコンと、装備中の武器が表示されるようにした。なんかこうしたかったから、こうした。人間またはアフリカゾウは、なんかこうしたいと思った時にこうするタイプと、なんかこうしたいけど今はいいやってタイプに分けられるらしい。

 ※コードにreturnを書き忘れていたので追記した。


RPGツクールVXAceのRGSS3スクリプト!!本日のメニューは季節の吸収仕様を変更したやつとちょっとした挙動変更を再定義でお届け。

2022-02-07 | RPGツクールMZ,VXace,VX,2000,95,1~5

 こんにちはから始まる関係性でありたい。今日は日曜日でしたので(※実は私、今日本に居ますので日本時間では日曜日だったのです。)RPGツクールなるゲームをちまちま愛でていたのです。そうしましたら吸収スキルの仕様に「異議あり!」と申し立てを行いまして、折角の休日をほとんどスクリプトに費やすという悲喜交々の「悲」マシマシで候。以下、デフォルト仕様で変更したくなった部分。

 ・吸収率(割合)を設定できない。

 たったこれだけ設定出来れば、他の細かい部分はさほど気にならなかったわけだが、どうしても解せなかった。例えばHP吸収で100ダメージ与えた場合に、HPを100回復出来るのは強力すぎるでありんすでやんす。元々知っていたので、速度補正や得TPで代用していた。例えば速度補正0なら10%、9なら100%吸収、という具合だ。掛ける10設定だったので、0~9程度なら許容できると思い、スキル設定をちまちまやっていた。そしてドラクエ11Sのウィッチネイルのようなスキルを作ろうとした時に、はたと気が付いた。思わず「はた!?」と声に出たかどうかはご想像にお任せしやんすでありんす。

 結論から言うとデフォルト状態でドラクエのウィッチネイルは設定不可能だった。何故なら、HP吸収を設定した場合、HPが吸収対象となり、MP吸収を設定した場合はMPだけが吸収対象となる。ちなみに前述の技は「敵にHPダメージを与え、与えたダメージの5%、自分のMPを回復する」という効果を持つ。これだけで既に2点、出来ないことが確定している。ダメージの5%、HPダメージを与えてMP回復、この2点だ。という経験から、もう自分で作るしかないと奮起した。

 せっかく作るからには、自分用だけに留めておくのも勿体ないと思ったので、出来ることをもう少し増やしてみた。下記の4点を盛り込むこととし、更に吸収時のダメージ挙動も自分好みに少し変更してみた。あとこれは余談だが、インデントが無くなる件、一部記号がタグ判定されてしまう件は、HTMLエディターの機能を使うことで解決できるようだ。それも試してみようと思ったので連日スクリプトを弄る切っ掛けとなった。

 ・吸収率を設定できる。

 ・吸収成功率を設定できる。

 ・回復対象を設定できる。

 ・吸収失敗時にメッセージが出る。


#==============================================================================
# ! 吸収の仕様変更 Ver1.0
#==============================================================================
=begin
 スキルの属性に「吸収」を準備(データベースの用語タブ)しておき、
 吸収属性の場合に与えたダメージを吸収する。
 タイプのHP吸収、MP吸収は使わず、HPダメージ、MPダメージを用いる。

 何が出来るようになる?
 ①HPダメージまたはMPダメージを与えてHP,MP,TPのいずれかを回復する。
 ②吸収率(回復量)を割合で設定できる。
 ③成功率を設定できる。

 その他の仕様
 ・ダメージが入らなかった場合は吸収しない。
 ・与えたダメージより大きい値は吸収しない。
  ⇒HP50の敵に100ダメージ与えても吸収できるのは50まで。
 ・通常攻撃と同じようにダメージ効果(揺れたり)が発生する。

  スキルのメモ欄に記載
  体裁⇒タグ文言:種別,吸収率,成功率
   種別は0=HP、1=MP、2=TP
  
  記入例;
  <吸収:0,50,100>
   100%の確率で、与えたダメージの50%自分のHPを回復する。
  
  <吸収:1,100,20>
   20%の確率で、与えたダメージの100%自分のMPを回復する。
  
  スクリプト内の凡例
   ● 独自メソッド(競合無し)
   〇 エイリアス(競合注意)
   ◎ 再定義(競合要注意)
=end
module GCC
  DRAIN_ELEMENT = 19  # 吸収属性のID
  
  DRAIN_MARKER = "吸収" # メモ欄に記載する吸収のタグ文言

  ACTOR_DRAIN_FAILURE_MESSAGE = "%sは%sを吸収されなかった。" # 吸収失敗の表示、アクター名が入る
  ENEMY_DRAIN_FAILURE_MESSAGE = "%sの%sを吸収できなかった。" # 吸収失敗の表示、エネミー名が入る
end
#---------------------設定ここまでと言いたいがための点線---------------------
class RPG::UsableItem < RPG::BaseItem
  
  #--------------------------------------------------------------------------
  # ● 何を吸収(回復)するか判断するためのそれ
  #--------------------------------------------------------------------------
  def drain_configuration
    /<#{GCC::DRAIN_MARKER}[::](\S+)>/ =~ note ? $1.to_s.split(/\s*,/).inject([]) {|r,i| r.push(i.to_i)} : []
  end
end
class Game_ActionResult
  attr_accessor :drain_configuration        # 吸収判定
  attr_accessor :drain_flag        # 成否 判定
  attr_accessor :tp_drain        # TP吸収
  #--------------------------------------------------------------------------
  # 〇 オブジェクト初期化
  #--------------------------------------------------------------------------
  alias initialize_for_drain initialize
  def initialize(battler)
    @drain_configuration = []
    @drain_flag  = false
    @tp_drain = 0
    initialize_for_drain(battler)
  end
  #--------------------------------------------------------------------------
  # 〇 ダメージの作成
  #--------------------------------------------------------------------------
  alias make_damage_for_drain make_damage
  def make_damage(value, item)
    make_damage_for_drain(value, item)
    ## OR条件:ダメージが0の時、攻撃属性が吸収ではない時、回復の時は吸収判定無し
    return @success if @success == false || item.damage.element_id != GCC::DRAIN_ELEMENT || value < 1

    ##メモ欄の記述を取得
    @drain_configuration = item.drain_configuration
    if @drain_configuration == []
      p "吸収属性スキルのメモ欄に吸収項目が正しく設定されていません。"
      return @success
    end
    
    ## 吸収攻撃と判断
    @drain_flag = true
    
    ## 吸収成功の時、吸収量を得る。
    ## 最大吸収量は、相手のHPまたはMP残量まで。
    if rand(100) < @drain_configuration[2]
      case @drain_configuration[0]
      when 0
        @hp_drain = [@battler.hp, value * @drain_configuration[1] / 100].min if @hp_damage > 0
        @hp_drain = [@battler.mp, value * @drain_configuration[1] / 100].min if @mp_damage > 0
      when 1
        @mp_drain = [@battler.hp, value * @drain_configuration[1] / 100].min if @hp_damage > 0
        @mp_drain = [@battler.mp, value * @drain_configuration[1] / 100].min if @mp_damage > 0
      when 2
        @tp_drain = [@battler.hp, value * @drain_configuration[1] / 100].min if @hp_damage > 0
        @tp_drain = [@battler.mp, value * @drain_configuration[1] / 100].min if @mp_damage > 0
      end
    end
    return @success
  end
  #--------------------------------------------------------------------------
  # ◎ HP ダメージの文章を取得
  #--------------------------------------------------------------------------
  def hp_damage_text
    if @hp_damage > 0
      fmt = @battler.actor? ? Vocab::ActorDamage : Vocab::EnemyDamage
      sprintf(fmt, @battler.name, @hp_damage)
    elsif @hp_damage < 0
      fmt = @battler.actor? ? Vocab::ActorRecovery : Vocab::EnemyRecovery
      sprintf(fmt, @battler.name, Vocab::hp, -hp_damage)
    else
      fmt = @battler.actor? ? Vocab::ActorNoDamage : Vocab::EnemyNoDamage
      sprintf(fmt, @battler.name)
    end
  end
  #--------------------------------------------------------------------------
  # ◎ MP ダメージの文章を取得
  #--------------------------------------------------------------------------
  def mp_damage_text
    if @mp_damage > 0
      fmt = @battler.actor? ? Vocab::ActorLoss : Vocab::EnemyLoss
      sprintf(fmt, @battler.name, Vocab::mp, @mp_damage)
    elsif @mp_damage < 0
      fmt = @battler.actor? ? Vocab::ActorRecovery : Vocab::EnemyRecovery
      sprintf(fmt, @battler.name, Vocab::mp, -@mp_damage)
    else
      ""
    end
  end
  #--------------------------------------------------------------------------
  # ● HP吸収の文章を取得
  #--------------------------------------------------------------------------
  def hp_drain_damage_text
    @drain_flag = false
    if @hp_drain > 0
      fmt = @battler.actor? ? Vocab::ActorDrain : Vocab::EnemyDrain
      sprintf(fmt, @battler.name, Vocab::hp, @hp_drain)
    else
      fmt = @battler.actor? ? GCC::ACTOR_DRAIN_FAILURE_MESSAGE : GCC::ENEMY_DRAIN_FAILURE_MESSAGE
      sprintf(fmt, @battler.name, Vocab::hp)
    end
  end
  #--------------------------------------------------------------------------
  # ● MP吸収の文章を取得
  #--------------------------------------------------------------------------
  def mp_drain_damage_text
    @drain_flag = false
    if @mp_drain > 0
      fmt = @battler.actor? ? Vocab::ActorDrain : Vocab::EnemyDrain
      sprintf(fmt, @battler.name, Vocab::mp, @mp_drain)
    else
      fmt = @battler.actor? ? GCC::ACTOR_DRAIN_FAILURE_MESSAGE : GCC::ENEMY_DRAIN_FAILURE_MESSAGE
      sprintf(fmt, @battler.name, Vocab::mp)
    end
  end
  #--------------------------------------------------------------------------
  # ● TP吸収の文章を取得
  #--------------------------------------------------------------------------
  def tp_drain_damage_text
    @drain_flag = false
    if @tp_drain > 0
      fmt = @battler.actor? ? Vocab::ActorDrain : Vocab::EnemyDrain
      sprintf(fmt, @battler.name, Vocab::tp, @tp_drain)
    else
      fmt = @battler.actor? ? GCC::ACTOR_DRAIN_FAILURE_MESSAGE : GCC::ENEMY_DRAIN_FAILURE_MESSAGE
      sprintf(fmt, @battler.name, Vocab::tp)
    end
  end
end
class Game_Battler < Game_BattlerBase
  #--------------------------------------------------------------------------
  # 〇 ダメージの処理
  #    呼び出し前に @result.hp_damage @result.mp_damage @result.hp_drain
  #    @result.mp_drain が設定されていること。
  #--------------------------------------------------------------------------
  alias execute_drain_damage execute_damage
  def execute_damage(user)
    execute_drain_damage(user)
    user.tp += @result.tp_drain
  end
end
class Window_BattleLog < Window_Selectable
  #--------------------------------------------------------------------------
  # 〇 ダメージの表示
  #--------------------------------------------------------------------------
  alias display_drain_damage display_damage
  def display_damage(target, item)
    display_drain_damage(target, item)
    if !target.result.missed && !target.result.evaded && target.result.drain_flag
      display_hp_drain_damage(target, item) if target.result.drain_configuration[0] == 0
      display_mp_drain_damage(target, item) if target.result.drain_configuration[0] == 1
      display_tp_drain_damage(target, item) if target.result.drain_configuration[0] == 2
    end
  end
  #--------------------------------------------------------------------------
  # ◎ HP ダメージ表示
  #--------------------------------------------------------------------------
  def display_hp_damage(target, item)
    return if target.result.hp_damage == 0 && item && !item.damage.to_hp?
    if target.result.hp_damage > 0 || target.result.hp_drain > 0
      target.perform_damage_effect
    end
    Sound.play_recovery if target.result.hp_damage < 0
    add_text(target.result.hp_damage_text)
    wait
  end
  #--------------------------------------------------------------------------
  # ◎ MP ダメージ表示
  #--------------------------------------------------------------------------
  def display_mp_damage(target, item)
    return if target.dead? || target.result.mp_damage == 0
    if target.result.mp_damage > 0 || target.result.mp_drain > 0
      target.perform_damage_effect
    end
    Sound.play_recovery if target.result.mp_damage < 0
    add_text(target.result.mp_damage_text)
    wait
  end
  #--------------------------------------------------------------------------
  # ● HP吸収の表示
  #--------------------------------------------------------------------------
  def display_hp_drain_damage(target, item)
    replace_text(target.result.hp_drain_damage_text)
    wait
  end
  #--------------------------------------------------------------------------
  # ● MP吸収の表示
  #--------------------------------------------------------------------------
  def display_mp_drain_damage(target, item)
    replace_text(target.result.mp_drain_damage_text)
    wait
  end
  #--------------------------------------------------------------------------
  # ● TP吸収の表示
  #--------------------------------------------------------------------------
  def display_tp_drain_damage(target, item)
    replace_text(target.result.tp_drain_damage_text)
    wait
  end
end


 データベースの「用語」から吸収用の属性を1つ作ってから設定するため、デフォルトのダメージタイプ「HP 吸収」と「MP 吸収」が不要になる。分かり易いように吸収という名前の属性を登録しておけば良いと思う。ダメージ計算は該当の属性有効度が考慮される。また、吸収属性のスキルを使っているのに、<吸収:xxx>タグがメモ欄に無い場合、また記載方法が間違っている場合は効果が出ない。ダメージ時の挙動についてはデフォルトがいい場合、Window_BattleLogの◎ HP ダメージ表示(display_hp_damage)と◎ MP ダメージ表示(display_mp_damage)だけコメントアウトするか削除するか。個人的には魔法でMP吸収したとしても、普通にダメージ音があってもいいと思っている。ドラクエで言うところのマホトラとか、静かにMPを吸い取るような挙動だと確かに何も無いほうがいいのかもしれない。スキル内容次第だろうか、その辺りは。

 作り始めたから形になるまで頑張ったものの、よく探したら誰かが既に作っているかもしれない。自分のは素人すぎて何もサポート出来ないし、既出ならそちらを使ったほうがいいと思う心から。「吸収」で多少検索した限りでは無さそうだった。

 ※追記:行数増やさないほうがスマートかと思ったので、吸収表示はテキスト置換える方法に切り替えてみた。


RPGツクールVXAceの不満点はUIくらいなものだ。

2022-02-05 | RPGツクールMZ,VXace,VX,2000,95,1~5
2022/02/05更新
 テストしてみたら不具合を見付けたので更新した。ターゲットがHP0になっても発動していたので、頑張って修正した。ついでにステート発動時にアニメーションも表示させるように改変してみた。ちなみにターゲット撃破後にアニメーション表示がされたことで不具合に気付けた。また何か問題が発生すると困るので、(やる気という意味合いの)可能な範囲でテストした。下記を確認済みなのだが、今思い付かないだけで他にも状況はあるかもしれない。
・HP0以下の状態では発動しない。
・回復魔法で発動しない。
・混乱状態で発動する。
 ※挙動として好みの問題で、スクリプトの「movable?」を「confusion?」に書き換えると混乱時も発動しないようになる。
・全体攻撃でも1人ずつ判定される。

 あとタグ認識されるから不等号記号が記事中に使えないようだ、久し振りで忘れていた。仕方ないので<この記号だけ全角で記載する。あと行数の問題か記事が更新できなくなったので点線を概ね削った。

※下記スクリプト内、更新箇所は赤文字
-----------------------------------------------------------------------------------------

 以前、怒りステートを作ったが、また似たようなものを作った。オーラステートと命名して、敵味方ともに確率で発生するステートとなる。ドラクエ11Sのゾーンに影響を受けたものだが、少し違うのはダメージを受けた時にしか発生しないこと。また、どのキャラクターも一律同じ効果であるということ。(ドラクエのゾーンはキャラにより増加する能力値が異なる。)

 確率についてはドラクエ11Sのゾーン発生率がブラックボックスなので、最低限公開されている下記の情報だけ満たせるようにした。
 ・ターン経過するほど発生率が高まる
 ・一撃で大きなダメージを受けるほど発生しやすい
 ・行動可能な状態でなければ発生しない

 エネミーとアクターで処理を分けているのには次の理由がある。ドラクエ11Sのモンスターは、定期的にゾーン状態となったり、ゾーン状態に入らないものがいる。それも再現したかったのでエネミーのメモ欄に記載させることで対応した。素材として使えそうな書き方を心掛けたものの、たぶん使えると思うが如何せん素人を下回りし者なのでエラー対処は出来ない。TPチャージのスクリプトを併用するか、あるいは単独で使用する際は「 * GCC::TYPE_RATE[@nickname_type]」この部分だけ削除すれば問題無い。新規プロジェクトでのテストはしていないので、併用した場合に問題無いかは分からない。

#==============================================================================
# ! オーラステート Ver1.0
#==============================================================================
=begin
 攻撃を受けた際、確率でオーラ状態になる。
 敵と味方で確率が異なり、敵は結構簡単になる。

 下記3種類のいずれかをエネミーのメモ欄に記載する。
 表記しない場合は <オーラ通常>か<オーラ無し>のどちらをデフォルトにするか
 Module内で設定可能。

<オーラ通常>
 たまにオーラが発動する。

<オーラ行動:n>
指定の行動回数(n回)を経過すると、被ダメ量に関わらず必ずオーラが発動する。
そういうボスなんかにおすすめ。nを任意の数値にする。

<オーラ無し>
オーラの発動は無い。マシンの敵や感情を失った鬱野郎なんかにおすすめ。

スクリプト内の凡例
 ● 独自メソッド(競合無し)
 〇 エイリアス(競合注意)
 ◎ 再定義(競合要注意)
=end
module GCC
AURA_STATE = 120 ## オーラステートのID

AURATYPE_A = "オーラ通常" ## メモ欄に記載する文字。気に入らなければ変更可能。
AURATYPE_B = "オーラ行動"
AURATYPE_C = "オーラ無し"

AURA_DEFAULT = 1 ## メモ欄に表記無い場合、1が通常、2はオーラ無し

AURA_ANIMATION = 10 ## オーラ発動時のアニメーションID

end

class RPG::BaseItem
# ● オーラタイプ識別
def gcc_aura_type
if /<#{GCC::AURATYPE_A}>/ =~ @note
"通常"
elsif /<#{GCC::AURATYPE_B}[::](\d+)>/ =~ @note
@aura_type = $1.to_i
elsif /<#{GCC::AURATYPE_C}>/ =~ @note
"無し"
else
if GCC::AURA_DEFAULT == 1
"通常"
elsif GCC::AURA_DEFAULT == 2
"無し"
end
end
end
end
class Game_Battler < Game_BattlerBase
 ### メソッド「on_damage」を削除済み

attr_accessor :aura_flg # オーラ発動フラグ
attr_accessor :action_count # 行動数
attr_reader :aura_type # オーラ行動の回数
# 〇 エイリアス  オブジェクト初期化
alias init_aura_state initialize
def initialize
@aura_flg = false
@action_count = 0
@aura_type = 0
init_aura_state
end
# 〇 エイリアス 戦闘行動終了時の処理
alias action_end_aura_state on_action_end
def on_action_end
action_end_aura_state
@action_count += 1 if movable? && !state?(GCC::AURA_STATE)
end
# 〇 エイリアス スキル/アイテムの効果適用
alias aurastate_item_apply item_apply
def item_apply(user, item)
aurastate_item_apply(user, item)
aura_state_judgment(@result.hp_damage.to_f / mhp) if @result.hp_damage > 0 && self.movable?
end

end

class Game_Actor < Game_Battler
 ### 条件判定から「movable? &&」を、発動後の処理から「add_state(GCC::AURA_STATE)」,「@action_count = 0」を削除済み

# ● 確率計算と付与
def aura_state_judgment(value)
### 行動可能且つオーラ状態ではない
if !state?(GCC::AURA_STATE)
### ターン数×2ずつ、最大50まで積み上げ
t = $game_troop.turn_count * 2 >= 50 ? 50 : $game_troop.turn_count * 2
v = value * 100 + @action_count

### 0~(ターン数+ダメージ幅+累積の行動回数)を小数にして変動率を掛け、
### 1.0以上ならオーラ化
if rand(t + v) * 0.01 * GCC::TYPE_RATE[@nickname_type] >= 1.0
@aura_flg = true
end
end
end
end

class Game_Enemy < Game_Battler
 ### 条件判定から「movable? &&」を、発動後の処理から「add_state(GCC::AURA_STATE)」,「@action_count = 0」を削除済み

# ● 確率計算と付与
def aura_state_judgment(value)
if enemy.gcc_aura_type == "通常"
if !state?(GCC::AURA_STATE)
t = $game_troop.turn_count * 2 >= 50 ? 50 : $game_troop.turn_count * 2
v = value * 100 + (@action_count * 5)
if rand(t + v) * 0.01 >= 1.0
@aura_flg = true
end
end
elsif enemy.gcc_aura_type == "無し"
return
else
if !state?(GCC::AURA_STATE) && @action_count >= enemy.gcc_aura_type
@aura_flg = true
end
end
end
end
class Scene_Battle < Scene_Base
# 〇 エイリアス スキル/アイテムの効果を適用
alias on_aurastate_apply_item_effects apply_item_effects
def apply_item_effects(target, item)
on_aurastate_apply_item_effects(target, item)
### 元の処理実行後、オーラフラグがONであれば発動させる。
if target.aura_flg
show_animation([target], GCC::AURA_ANIMATION)
target.add_state(GCC::AURA_STATE)
target.action_count = 0
target.aura_flg = false
@log_window.display_added_states(target)
end
end
end


 上記オーラステートの計算式には「GCC::TYPE_RATE[@nickname_type]」がある。これとは別にオーラの発動率及びTPの増加率をコントロールするスクリプトも作成した。設定値は二次元配列にすればよかったと反省しているが、概ね理想通りの仕様に作ることが出来た。(そう、理想が低い。)
 前々から自分のゲームでは、二つ名の設定をゲーム中で活かしたことがないため、実質死にパラメータとなっていた。これを活用するために、アクターの感情という体裁にして、初期値は「ふつう」となっており、画面にも表示している。戦闘終了後のタイミングでランダム更新されるようにした。具体的にはタイプという変数を作成して数値基準の管理で、①変動無し、②1つ上がる、③1つ下がるのパターンで分岐する。さらに上下どちらかの最高値または最低値の場合、ランダムで大幅に変動する。

 感情タイプ毎のTPチャージ率、オーラ発動率は共有で最大1.5~最低0.65にしているが、ここはゲームを作っていくうえで要調整が必要になる想定だ。つまり、2次元配列で書けばよかったと後悔している。たとえば下記のようにすれば、もっと言えばパラメータ1つ追加して両方の確率を分けてもいいような気がする。メモ欄には対応させていないためあくまでスクリプト内で決めになる。
 ["さいこう",1.5],["こうふん",1.45]

module GCC
#ステータスに描画される文字列
TYPE_NAME = [
"さいこう",# type0
"こうふん",# type1
"そうかい",# type2
"はつらつ",# type3
"たかぶる",# type4
"わくわく",# type5
"かろやか",# type6
"それなり",# type7
"おだやか",# type8
"ふつう",# type9
"そわそわ",# type10
"もやもや",# type11
"ゆううつ",# type12
"むなしい",# type13
"さいあく",# type14
"いらいら"# type15
]

#タイプごとのTPチャージ、オーラ発動の変動率
TYPE_RATE = [1.5, 1.45, 1.4, 1.35, 1.3, 1.25, 1.2, 1.15, 1.1, 1.0, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65]
end

class Game_Actor < Game_Battler
attr_accessor :nickname_type
#--------------------------------------------------------------------------
# ● オブジェクト初期化(エイリアス)
#--------------------------------------------------------------------------
alias nicknametype_initialize initialize
def initialize(actor_id)
nicknametype_initialize(actor_id)
####二つ名
@nickname_type = 9
end
#--------------------------------------------------------------------------
# ☆ 性格によるTPチャージ率
#--------------------------------------------------------------------------
def charge_tp_rate
return GCC::TYPE_RATE[@nickname_type]
end
#--------------------------------------------------------------------------
# ● 被ダメージによる TP チャージ
#--------------------------------------------------------------------------
def charge_tp_by_damage(damage_rate)
self.tp += damage_rate > 0.08 ? 20 * damage_rate * tcr * charge_tp_rate : 1
end
#--------------------------------------------------------------------------
# ☆ ニックネームタイプの最大値
#--------------------------------------------------------------------------
def nt_max
return 15
end
#--------------------------------------------------------------------------
# ☆ ニックネームタイプの最低値
#--------------------------------------------------------------------------
def nt_min
return 0
end
#--------------------------------------------------------------------------
# ☆ 二つ名のランダム変更
#--------------------------------------------------------------------------
def emotional_change
case rand(3)
when 0
return
when 1
@nickname_type > nt_min && @nickname_type < nt_max ? @nickname_type -= 1 : @nickname_type = 9
when 2
@nickname_type > nt_min && @nickname_type
※ここから下のスクリプトは説明のためのもので、これだけ入れてもエラー出るので注意!

 その他、提供可能なスクリプトは無いが混乱(confusion)についても改変した。デフォルトのパターン①敵を攻撃する(命令出来ない)、②敵か味方を攻撃する、③味方を攻撃するがスクリプト内では混乱に当たり、混乱レベルとして3段階に分類されていた。ここに「魅了」というステートを追加して、魅了されている間はパターン④味方を攻撃する+攻撃スキルも使うようにした。敵を回復する行動は、更に手を加える必要があるので、コスト対効果(バグ取りのおそれと効果)を考えた時に以下の2点から避けることとした。
 ・そもそも魅了を受けることがあまり無いかもしれない。
 ・回復スキルを使うメンバーが魅了されるという状況はさらに限定される。
 ・行動選択で回復スキルとなる状況はもっと限定される。

 具体的には魅了時の行動リストを新たに作成することで対応した。対象選択が味方あるいは使用者のスキルを除外したリストになっているため実質的に「回復スキル以外を使う」挙動となっている。なお、ターゲットの仕様も変更しないといけないのか、自環境で競合が発生しているのか、全体スキルも単体効果になってしまうため、敵全体のスコープも外した。

# ● 魅了時用の行動候補リストを作成 ※対象が味方のスキルを除外
def make_charmed_action_list
list = []
list.push(Game_Action.new(self).set_attack.evaluate)
usable_skills.each do |skill|
list.push(Game_Action.new(self).set_skill(skill.id).evaluate) if skill.scope <= 6 && skill.scope != 2
end
list
end

 他に改変したのは即死魔法の種類を増やしたこと。以前もやっていたような気がするが、今回のほうがまともだ。たとえば女神転生シリーズの「ハマ」と「ムド」はどちらも即死魔法だが耐性が異なる。ハマは天使などに効かず、悪霊などに効果的であり、ムドはその逆になる。つまりそれを実現したかった。急所、呪殺、昇天という3種類の即死が出来た。※下記だけでは出来ない。

# ● 戦闘不能のステート ID を取得
def vital_state_id
return 145
end
# ● 戦闘不能のステート ID を取得
def dead_state_id
return 146
end
# ● 戦闘不能のステート ID を取得
def haven_state_id
return 147
end

 あとクリティカル時に音を再生するようにした。これは色んな人がやっていると思うし、何ならアニメーション表示を追加していたりバトラーのコメント表示(絵とセリフが出るやつ何て言うんだっけ)もあったりするだろうから、非常に地味な改変だ。

#--------------------------------------------------------------------------
# ● クリティカルヒットの表示
#--------------------------------------------------------------------------
def display_critical(target, item)
if target.result.critical
target.actor? ? Sound.play_actor_critical : Sound.play_enemy_critical
wait
text = target.actor? ? Vocab::CriticalToActor : Vocab::CriticalToEnemy
add_text(text)
wait
end
end

 結論、になっているかは不明だが、なんだかツクールをやっていて思うのは次の通り。
 ・俺はRPGが作りたいのか、プログラムが書けるようになりたいのか、どっちなんだい?




金縛りステートのスクリプト

2021-03-28 | RPGツクールMZ,VXace,VX,2000,95,1~5

 何を血迷ったのかまたRPGツクールを始めた。昨今はツクールMZなるものまで出現しているが、キャラ規格などがVX系に比べて大きいため、描ける自信が無い。あとRubyもまだ満足に扱えないのにJavaScriptなんて出来る気がしない。そんなわけで、まだまだVXAceを現役と思い愛でている次第だ。めでてめでてもう。

 血迷いがてら、頑張ってスクリプトを書いてみた。といっても、ほぼほぼデータベースで設定させるので補助的なスクリプトに過ぎない。内容は「金縛り」ステートの作成補助スクリプトだ。金縛りと言ったものの、別に雪だるまだろうが蛆虫だろうが筋肥大で動きにくい翁だろうが何でもいい。とにかく金縛り状態になると、ステートのメモ欄に指定した確率で行動不能になる。行動不能判定を行動直前に実施するため、コマンドの選択が出来るのに、そのターンの行動が封じられるというもの。有名なゲームで言うとドラクエのみとれるに近い。あとあれにも似てる、俺の知らんゲーム、何だっけかな知らんけど。

ステート設定1

 あくまでダミーステートとなる。このステートが付与されている状態の時、行動不能判定を実施する。内部的には、確率で行動不能効果のあるステートを付与する。そのため行動制約は無しに設定する。メモ欄には<動けない:n>の表記になる。nは単純に1~100を入力するだけ。ただし100にすると100%行動不能になるため、このスクリプトを使用する必要性は無い。  ステートで設定できたほうが、他の効果を付けたりできるし、手軽で管理しやすいような気がした。

ステート設定2

 実際に行動不能とさせるステート。名前はゲーム上に表示させないため、管理し易い名称にしておく。行動制約は「行動できない」を設定する。ゲーム上で急に状態異常が追加されると格好悪い(国家の粛清対象リストに載ります)ので、アイコンは設定せず、表示優先度も0にしておく。また、ターン終了時に解除とするが継続ターン数は0~0を設定する。このように設定すると、毎ターン人知れず付与され人知れず解除されるので、都度行動可否の判定がされる。人、それは窺い知れないもの。味方がこの状態のメッセージになった時、敵がこの状態になった時のメッセージは出力対象のため書き込むほうが雰囲気が出る。例えば幽霊に取りつかれてたまに行動できないとか、マザー2にそんなのがあったような気がするし、無かったとしても気にならない。

 以下、黒文字で記載しているのがスクリプト。再定義があり競合し兼ねないので、利用は完全自己責任で。何故なら俺には対処できるスキルが無い。DUMMY_STATEには上記ステート設定1のステートIDを指定する。IDと言っても昔ゴシックバンドとしてたまに紹介されてたSPEED-iDは関係無い。本当に関係無い、俺は何も知らない、見逃してほしい。ほんでBIND_STATEでは上記ステート設定2のステートIDを指定する。IDと言っても、またか君は。どうしてそうなんだ、いつもいつもあれだ。本当にあれだから、とにかく勘弁してほしい。  そもそもどうなるのか分かり安くするため動画にした。昔は写真を貼り付けるのが精いっぱいだったGooブログも、もはや動画を載せられるまでに発展した。ここはブログの発展場だろうか。だから一応、動画も載せておく。せっかくツクール起動して実装しても、思ってた挙動と違ったら悲しくて身投げするもんね。十中八九だもんね。



module GCC ; module RANDBIND


##### 疑似的に行動不能ステートとして扱うステートID

DUMMY_STATE = 27


##### 実際に行動不能を設定するステートID

BIND_STATE = 28


# ダミーステートのメモ欄に書く言葉+動けなくなる確率

# 例 50%で動けなくなる場合 → <動けない:50>

WORD = /<動けない:(\d+)>/

end;end



#============================================================================
# ■ RPG::State
#----------------------------------------------------------------------------
#  ステートのクラス。
#============================================================================
class RPG::State

#--------------------------------------------------------------------------
# ● 動けない確率を取得
#--------------------------------------------------------------------------
def random_bind_rate?

return @bind_rate if @bind_rate

if @bind_rate.nil?

@bind_rate = {}

@bind_rate = note[GCC::RANDBIND::WORD,1] ? $1.to_i : false

end

return @bind_rate ? @bind_rate : 0

end

end


#==============================================================================
# ■ Game_Battler
#==============================================================================
class Game_Battler

attr :bind_rate

#--------------------------------------------------------------------------
# ● 実際動けなくする(行動不能のステートをかける)
#--------------------------------------------------------------------------
def random_bind(state)

if state.random_bind_rate? > rand(100)

self.add_state(GCC::RANDBIND::BIND_STATE)

return true

end

return false

end

end


class Scene_Battle

#--------------------------------------------------------------------------
# ● 戦闘行動の処理※再定義
#--------------------------------------------------------------------------
def process_action

return if scene_changing?

if !@subject || !@subject.current_action

@subject = BattleManager.next_subject

end

return turn_end unless @subject

@subject.states.each do | state |

if state.id == GCC::RANDBIND::DUMMY_STATE

@log_window.display_added_states(@subject) if @subject.random_bind(state)

end

end


if @subject.current_action

@subject.current_action.prepare

if @subject.current_action.valid?

@status_window.open

execute_action

end

@subject.remove_current_action

end

process_action_end unless @subject.current_action

end

end