エンカウント歩数の計算式を変更するプラグイン

Kpoal

ユーザー
製作者:Kpoal
  • 非商用利用: 自由
  • 商用利用: 自由
  • 再配布: OK
  • 加工: OK
  • 加工後の再配布: OK
  • シリーズ: ツクールMV
コード:
//=============================================================================
// new_encount_system.js
// ver1.12  2017/07/13
//=============================================================================

/*:
 * @plugindesc new_encount_system
 * @author KPoal
 *
 * @param RandomDice
 * @desc How many dice use to make encounter.
 * @default 2
 *
 * @param SafetyRate
 * @desc safety range's rate for average encount step. Input number 0 to 1.
 * @default 0.1
 *
 * @param TransEncUpd
 * @desc When transport, update the encounter or not. Input true or false.(default is false)
 * @default false
 *
 * @param EncNoChainLength
 * @desc How many groups record not to encounter the same enemy group.
 * @default 5
 *
 * @param EncNoChainRate
 * @desc How much reduce the recorded enemy group. input number 0 to 1.
 * @default 1.0
 *
 * @help
 *
 */


/*:ja
 * @plugindesc エンカウントシステム変更のプラグインです。
 * @author KPoal
 *
 * @param RandomDice
 * @desc エンカウント歩数の計算に、いくつの独立な乱数を用いるかです。この数値が大きいほど確率の分散が小さくなります。
 * @default 2
 *
 * @param SafetyRate
 * @desc エンカウント直後から、どれだけの間敵が出現しない領域を取るかです。0~1までの間の小数で設定して下さい
 * @default 0.1
 *
 * @param TransEncUpd
 * @desc 場所移動の際に、エンカウント歩数の更新を行うかどうかです。
 * @default false
 *
 * @param EncNoChainLength
 * @desc 同じ敵グループの出現を防ぐために、直前の敵グループをいくつまで記録するかです。
 * @default 5
 *
 * @param EncNoChainRate
 * @desc 直前に出現が記録された敵グループを、どれだけ出現しにくくするかです。0~1の小数で設定してください。
 * @default 1.0
 *
 * @help
 * エンカウントの計算式を、
 * 二つのパラメータを用いて自由に変更できるようにします。
 * また、システムを初期値から一歩ごとに
 * 2520/nの数値を引いて行く形式に変更し、
 * 場所移動コマンド実行時のエンカウント更新を撤廃します。
 * これにより、場所移動を多用する小部屋集合系のダンジョンが作りやすくなります。
 *
 * ver1.10追加
 * 直前に出現した敵グループを記録し、
 * 次のエンカウントでそのグループが選択されにくくなる機能を追加しました。
 * この機能を用いる事で、なるべく毎回違う敵が出現しやすくなるようにできます。
 *
 * ver1.11追加
 * 敵の出現しないマップからの場所移動の場合、
 * エンカ更新が行われるよう修正。
 *
 * ver1.12追加
 * ヘルプが文字化けする問題を修正。
 * SafetyRateを1以上に設定する事で歩数の絶対指定を可能に。
 */

(function() {
    var parameters = PluginManager.parameters('new_encount_system');

Game_Player.prototype.makeEncounterCount = function() {
    var dice =Number(parameters.RandomDice);
    var safety_rate=Number(parameters.SafetyRate);
    var n = $gameMap.encounterStep();
    if (safety_rate>=1){
    safety_rate=Math.min(safety_rate/n,0.99)
    }
    var randrange = 2520;
        randrange *= 1-safety_rate;
    this._encounterCount = 0;
    if (dice >= 1){
    for (var i = 1; i <= dice; i++) {
            this._encounterCount += Math.randomInt(randrange);
        }
    this._encounterCount *= 2;
    this._encounterCount = Math.floor(this._encounterCount / dice);
    this._encounterCount += Math.floor(2520*safety_rate) + 1;
    }
    else{
   this._encounterCount = 2520;
   }

};

Game_Player.prototype.encounterProgressValue = function() {
    var n = $gameMap.encounterStep();
    var value = Math.floor(2520 / n);
    var bush  = $gameMap.isBush(this.x, this.y) ? 2 : 1;
    value *= bush;
    if ($gameParty.hasEncounterHalf()) {
        value *= 0.5;
    }
    if (this.isInShip()) {
        value *= 0.5;
    }
    return value;
};

Game_Player.prototype.locate_new = function(x, y) {
    Game_Character.prototype.locate.call(this, x, y);
    this.center(x, y);
    if ((eval(String(parameters.TransEncUpd)))||(this._encounterCount <=0)) {
    this.makeEncounterCount();
    }
    if (this.isInVehicle()) {
        this.vehicle().refresh();
    }
    this._followers.synchronize(x, y, this.direction());
};

Game_Player.prototype.performTransfer = function() {
    if (this.isTransferring()) {
        this.setDirection(this._newDirection);
        if (this._newMapId !== $gameMap.mapId() || this._needsMapReload) {
            if (this.encCheckNew()==false) {
            this.makeEncounterCount();
            }
            $gameMap.setup(this._newMapId);
            this._needsMapReload = false;
        }
        this.locate_new(this._newX, this._newY);
        this.refresh();
        this.clearTransferInfo();
    }
};

Game_Player.prototype.encCheckNew = function(){
    var weightSum = 0;
   $gameMap.encounterList().forEach(function(encounter) {
            weightSum += encounter.weight;
    }, this);
 if (weightSum > 0) {
 return true
 }
 return false
};

//--------------------------------------------------------------------
//ver1.10 add
//--------------------------------------------------------------------
Game_Player.prototype.clearEnemyEncountArray = function() {
    var maxsize =Number(parameters.EncNoChainLength);
    this._enemyEncountArray = [];
 for (var i = 0; i <= maxsize; i++) {
  this._enemyEncountArray[i]=0;
  }
};


Game_Player.prototype.inputEnemyEncountArray = function(troopid) {
   var maxsize =Number(parameters.EncNoChainLength);
if (troopid>0){
 for (var i = 0; i < maxsize; i++) {
  this._enemyEncountArray[maxsize-i]=this._enemyEncountArray[maxsize-i-1];
  }
 this._enemyEncountArray[1] = troopid;
}
};


Game_Player.prototype.makeEncounterTroopId = function() {
    var maxsize =Number(parameters.EncNoChainLength);
    var new_w_rate = Number(parameters.EncNoChainRate);
    var encounterList = [];
    var weightSum = 0;
    var new_weight = 0
    if (!this._enemyEncountArray) {
            this.clearEnemyEncountArray();
        }
    $gameMap.encounterList().forEach(function(encounter) {
        if (this.meetsEncounterConditions(encounter)) {
            encounterList.push(encounter);
        }
    }, this);
 
      if (maxsize>=encounterList.length){
      maxsize = encounterList.length-1
    }
        for (var i = 0; i < encounterList.length; i++) {
         new_weight=  encounterList[i].weight;
          for (var j = 1;j <=maxsize;j++) {
            if (this._enemyEncountArray[j]==encounterList[i].troopId){
             new_weight*= new_w_rate;
             break;
           }
         }
         weightSum += Math.floor(new_weight);
     }
    if (weightSum > 0) {
        var value = Math.randomInt(weightSum);
        for (var i = 0; i < encounterList.length; i++) {
            new_weight=  encounterList[i].weight;
            for (var jj = 1;jj <=maxsize;jj++) {
              if (this._enemyEncountArray[jj]==encounterList[i].troopId){
                new_weight*= new_w_rate;
                break;
              }
            }
            value -= Math.floor(new_weight);
            if (value < 0) {
                this.inputEnemyEncountArray(encounterList[i].troopId);
                return encounterList[i].troopId;
            }
        }
    }
    this.clearEnemyEncountArray();
    return 0;
};

})();



他のスレッドでゲームのランダムエンカウントについて書いた事もあり、
せっかくなのでツクールMVでエンカウント式変更のためのプラグインを作ってみました。

主な特徴1
二つのパラメータ'RandomDice'と'SafetyRate'を変更する事で、
ランダムエンカウント式の特徴を変更できます。

RandomDice:
エンカウント歩数の計算にいくつの独立変数を用いるかです。
この数値が大きいほど分散が小さくなり、確率が平均値付近に集中するようになります。
=0に設定した場合、計算に乱数を用いず、
必ずマップに設定された「敵出現歩数」ごとにエンカウントするようになります。
tkool_enc5.png
(SafetyRate=0の場合のグラフ)



SafetyRate:
エンカウント直後からどれだけの間、
敵が絶対に出現しない領域(安全マージン)を取るかです。
ここに
0<= safetyrate <1
となるように数値を入れておくと、
「敵出現歩数」×(safetyrate) 歩の安全マージンを設定できます。
tkool_enc6.png
(safetyrateを大きくした場合も、やはり分散は小さくなります)

randomdice,safetyrateの値をどのように設定しても、
「敵出現歩数」の位置が確率の平均値となる事は変わりません。


主な特徴2
場所移動時のエンカウント歩数更新の撤廃
通常、ツクールでは場所移動が行われるたびにエンカウントまでの歩数が再計算されます。
これはつまり、
ダンジョンが25歩ごとに場所移動を繰り返すような構造だった場合、
30歩でエンカウントするように設定していたとしても
25歩歩いて場所移動&エンカ歩数の再計算が繰り返され、
ダンジョン通して絶対に敵とエンカウントすることがないという事です。

この仕様の為に、ツクールではランダムエンカウントを使う限り
頻繁に場所移動を繰り返す構造のダンジョン
(多くの小部屋を行き来するダンジョン、
ワープを渡り継いで進むダンジョン等、他にも色々)が作りづらく、
必然的に広い一枚マップで迷路構造のダンジョンに限定されてしまいがちです。

そこでこのプラグインを導入し、
パラメータ'TransEncUpd'をfalseに設定することで、この仕様をなくすことができます。
場所移動を何度してもエンカウントまでの歩数が維持されるため、
小部屋系のダンジョンなども作りやすくなります。

trueに設定しておくと、通常通り
場所移動のたびにエンカ歩数の更新が行われる仕様にすることもできます。
実は、この変更の為にエンカウントの計算を丸ごと書き換えています。
・元々
encounterCount = 1+Math.randomInt(n)+Math.randomInt(n)
として、
一歩ごとにencounterCountから-1
0以下になるとエンカウント

・当プラグイン
dice=2,safty=0の場合
encounterCount = 1+Math.randomInt(2520)+Math.randomInt(2520)
として、
一歩ごとにencounterCountから-2520/n
0以下になるとエンカウント

DQに近いシステムになるよう書き換えています。
普通に場所移動エンカ更新をOFFにするだけだと、
「敵出現歩数」の異なる二つのマップを場所移動でまたいだ際に
不具合が生じてしまうため、このような形にしました。


使用上の注意
ツクールMVのプラグインどころか、Javascriptすら今までほとんど触れたことがなかった自分が
即興で作ったものなので、バグ、不具合の類は間違いなくあると思います。

まず既に気付いているものとして、
「ニューゲーム」選択後最初に操作可能になるマップがエンカウントのあるマップだった場合、
0歩目でいきなり戦闘が始まってしまいます。
1回戦闘を終わらせれば通常の処理に戻りますが。

また、通常ツクールではセーブ&ロードでエンカウントがリセットされますから、
どうにもならないダンジョンで立ち往生したときは
数歩進む→セーブ&ロードでゴリ押し脱出ができるのですが、
このプラグインを使用しているとそれができません。
セーブ&ロードをしても、必ず同じ歩数でエンカウントしてしまいます。

※上記2点は、パラメータTransEncUpdをfalseにしているときのみの問題です。


この二点もできれば修正したかったのですが、
自分の知識不足のためそのまま放置してあります。

他にも問題に気付いた方はご報告下さい。
(修正できるとは限りません)
 
最後に編集:

Kpoal

ユーザー
追記
一つ目の不具合
(「ニューゲーム」選択後最初に操作可能になるマップがエンカウントのあるマップだった場合、
0歩目でいきなり戦闘が始まってしまう)
については修正しました。
 
私が振った話をここまで発展させて下さりありがとうございます。
どのように設定してもNが中央値である事は保たれているのが有難いですね。
現在製作中の作品はシステム検証が終わっているので新規導入は無理ですが
次回作から使わせて頂こうと思います。
それまでの間に更なる調整を期待しております。
 

Kpoal

ユーザー
追記
ver1.10追加
直前に出現した敵グループを記録し、
次のエンカウントでそのグループが選択されにくくなる機能を追加しました。
この機能を用いる事で、なるべく毎回違う敵が出現しやすくなるようにできます。

この機能は同スレッド内でしぐれんさんが提案されていたものですが、
エンカウント関連の機能拡張という事で同じプラグインにまとめてみました。

パラメータは以下の通りです。

EncNoChainLength
同じ敵グループの出現を防ぐために、直前の敵グループをいくつまで記録するかです。
例えば「1」に設定した場合、直前の一回のみの敵グループを記録し、
それだけが次のエンカウントで出にくくなります。
仮にこの数値がマップに設定された出現敵グループ数以上になっている場合、
このパラメータは(出現敵グループ数-1)になります。

EncNoChainRate
直前に出現が記録された敵グループが、どれだけ出にくくなるかです。
ここに0~1の数字を設定しておくと、その数値が出現テーブルの重みに掛けられます。
0であれば、直前のグループは絶対に選ばれなくなりますし、
もしこの機能を使用しないのであれば、ここの数値を1.0に設定すれば大丈夫です。

ちなみに、
敵グループの設定されていないマップでしばらく歩くと
この出現記録がリセットされます。
(正確には、エンカ歩数に達しても出現する敵が設定されていないときにリセットされます)


今後の改良案としては、
場所移動によるエンカ歩数非更新のせいで
「敵の出ないマップでエンカ直前まで歩数を稼ぐ→敵の出るマップに出ると数歩でエンカウント」
というストレスになりそうな仕様になってしまっているので、
ここを何とかしたいですね。
具体的には、
敵の出ないマップ→敵の出るマップの移動
の時のみエンカ歩数更新をするようにするなど。
ざっと見た感じ難しそうですが。
 

Kpoal

ユーザー
追記
ver1.11追加
敵出現テーブルが設定されていないマップからの場所移動の場合は、
TransEncUpdの有無に関わらずエンカ更新が行われるよう修正。
これにより、TransEncUpd=falseは
「『敵の出るマップ』→『敵の出るマップ』の移動の時にはエンカ更新が行われなくなる」
という仕様になりました。

「前の仕様の方がいい」という方がいないといいのですが。
 

Kpoal

ユーザー
追記
ver1.12追加
SafetyRateに1以上の数値を設定する事で、
安全マージンを割合ではなく歩数指定する事が可能に。
ただし、これを利用するとマップの「敵出現歩数」に関わらず
常に一定の安全マージンを取る事になるので、あまりお勧めはしないです。

加えて、プラグインコマンドに書いた日本語を文字化けさせずに
表示させる方法を理解したので、
ヘルプの文章を改めて書き直しました。
(文字コードの問題でした)

ひとまず、思いつく改良は出し尽くしたので、
利用する方が使いやすいよう、
プラグインを添付ファイルとして置いておきます。
 

Attachments

  • new_encount_system.js
    7.6 KB · 閲覧: 36
トップ