//============================================================================= // AutomaticState.js // ---------------------------------------------------------------------------- // (C) 2016 Triacontane // This software is released under the MIT License. // http://opensource.org/licenses/mit-license.php // ---------------------------------------------------------------------------- // Version // 1.4.4 2021/01/19 1.4.2の修正でのみ指定したステートが敵キャラにも有効になってしまう問題を修正 // 1.4.3 2020/09/01 自動ステートでHPおよびMPの上限があがった状態でイベントコマンド『全回復』を実行するとあがった分が反映されない問題を修正 // 1.4.2 2020/04/09 同一ステートにのタグを付けられるよう修正 // 1.4.1 2019/01/27 AS武器装備およびAS防具装備のタグが敵にも適用される問題を修正 // 1.4.0 2017/09/13 自動ステート対象をアクター、敵キャラIDで限定するときに複数指定できる機能を追加 // 1.3.1 2017/08/06 メモリ上にロードされていないアクターの自動ステートチェックが実行されるとエラーになる現象を修正 // 処理の軽量化 // 1.3.0 2017/07/21 パーティの並び順で自動ステートを付与する機能を追加 // 1.2.5 2017/05/27 競合の可能性のある記述(Objectクラスへのプロパティ追加)をリファクタリング // 1.2.4 2017/05/27 全回復の直後に自動ステートが解除されてしまう問題を修正 // 1.2.3 2017/02/16 1.2.0以降、下限MPの設定が無効になっていた問題を修正 // 1.2.2 2017/02/07 端末依存の記述を削除 // 1.2.1 2017/01/17 1.2.0でスイッチの項目が正しく機能しなかった問題を修正 // 1.2.0 2017/01/14 ステート自動付与の条件に計算式を適用できる機能を追加 // 処理の軽量化 // 1.1.2 2016/06/03 スペルミス修正 // 1.1.1 2016/05/23 条件式で割合を算出する際に端数を切り捨てるよう修正 // 1.1.0 2016/05/22 複数の条件を適用できるよう修正 // 1.0.2 2016/04/30 アクターと敵キャラ限定のオートステートが一部正しく機能していなかった問題を修正 // 1.0.1 2016/02/14 オートステートの追加時にメッセージを表示する仕様を追加 // 1.0.0 2016/02/08 初版 // ---------------------------------------------------------------------------- // [Blog] : https://triacontane.blogspot.jp/ // [Twitter]: https://twitter.com/triacontane/ // [GitHub] : https://github.com/triacontane/ //============================================================================= /*: * @plugindesc ステート自動付与プラグイン * @author トリアコンタン * * @help AutomaticState.js * * 条件を満たしている間、指定したステートを付与します。 * ステートのメモ欄に以下の書式で条件を入力してください。 * * メモ欄書式(ステートIDには制御文字を利用できます) * * 1. 自動付与ステートの条件 * * 指定したHP(割合)を上回っている(>=)間、対象ステートを付与する。 * * 指定したHP(割合)を下回っている(<=)間、対象ステートを付与する。 * * 指定したMP(割合)を上回っている(>=)間、対象ステートを付与する。 * * 指定したMP(割合)を下回っている(<=)間、対象ステートを付与する。 * * 指定したMP(割合)を上回っている(>=)間、対象ステートを付与する。 * * 指定したMP(割合)を下回っている(<=)間、対象ステートを付与する。 * * 指定した武器を装備している間、対象ステートを付与する。 * * 指定した武器を装備している間、対象ステートを付与する。 * * 指定したスイッチがONになっている間、対象ステートを付与する。 * * 指定したJavaScript計算式がtrueの間、対象ステートを付与する。 * * 並び順(1~)が指定した値と一致する間、対象ステートを付与する。 * * 計算式中で不等号を使いたい場合、以下のように記述してください。 * < → < * > → > * 例: // 変数[2]が1より大きい場合 * * 2. 自動付与ステートの対象 * * ステート自動付与の対象を指定したアクターのみに設定する。 * IDの指定がない場合、全てのアクターに有効になる。 * 複数のアクターを指定したい場合、数値をカンマで区切る。 * 例: * * * ステート自動付与の対象を指定した敵キャラのみに設定する。 * IDの指定がない場合、全ての敵キャラに有効になる。 * 複数の敵キャラを指定したい場合、数値をカンマで区切る。 * 例: * * 複数の条件が指定された場合は、全ての条件を満たした場合のみ * ステートが付与されます。 * * スクリプト * 自動付与ステートが有効になったときに所定のメッセージを表示する場合 * $gameSystem.automaticStateAddMessage = true; * * 自動付与ステートが有効になったときに所定のメッセージを表示しない場合 * $gameSystem.automaticStateAddMessage = false; * * 利用規約: * 作者に無断で改変、再配布が可能で、利用形態(商用、18禁利用等) * についても制限はありません。 * このプラグインはもうあなたのものです。 */ (function () { 'use strict'; var metaTagPrefix = 'AS'; var getArgNumber = function (arg, min, max) { if (arguments.length < 2) min = -Infinity; if (arguments.length < 3) max = Infinity; return (parseInt(convertEscapeCharacters(arg)) || 0).clamp(min, max); }; var convertEscapeCharacters = function(text) { if (text == null || text === true) text = ''; text = text.replace(/>?/gi, '>'); text = text.replace(/<?/gi, '<'); text = text.replace(/\\/g, '\x1b'); text = text.replace(/\x1b\x1b/g, '\\'); text = text.replace(/\x1bV\[(\d+)\]/gi, function() { return $gameVariables.value(parseInt(arguments[1])); }.bind(this)); text = text.replace(/\x1bV\[(\d+)\]/gi, function() { return $gameVariables.value(parseInt(arguments[1])); }.bind(this)); text = text.replace(/\x1bN\[(\d+)\]/gi, function() { var actor = parseInt(arguments[1]) >= 1 ? $gameActors.actor(parseInt(arguments[1])) : null; return actor ? actor.name() : ''; }.bind(this)); text = text.replace(/\x1bP\[(\d+)\]/gi, function() { var actor = parseInt(arguments[1]) >= 1 ? $gameParty.members()[parseInt(arguments[1]) - 1] : null; return actor ? actor.name() : ''; }.bind(this)); text = text.replace(/\x1bG/gi, TextManager.currencyUnit); return text; }; var isEmpty = function(that) { return Object.keys(that).length <= 0; }; var iterate = function(that, handler) { Object.keys(that).forEach(function(key, index) { handler.call(that, key, that[key], index); }); }; //============================================================================= // Game_System // 自動付与ステートのメッセージ表示フラグを定義します。 //============================================================================= var _Game_System_initialize = Game_System.prototype.initialize; Game_System.prototype.initialize = function() { _Game_System_initialize.apply(this, arguments); this.automaticStateAddMessage = null; }; //============================================================================= // Game_BattlerBase // 自動付与ステートの更新処理を定義します。 //============================================================================= Game_BattlerBase.prototype.updateAutomaticState = function() { DataManager.iterateAutomaticState(function(state) { if (!state || isEmpty(state.meta)) return; var stateId = state.id; var result = this.isAutomaticValid(state, false); if (result) { if (!this.isStateAffected(stateId) && this.isStateAddable(stateId)) { this.addState(stateId); if ($gameSystem.automaticStateAddMessage) this.showAddedStates(); this._result.deleteAddedStates(stateId); } } else if (result === false && this.isStateAffected(stateId)) { this.removeState(stateId); this._result.deleteRemovedStates(stateId); } }.bind(this)); }; Game_BattlerBase.prototype.showAddedStates = function() { }; Game_BattlerBase.prototype.isAutomaticValid = function(state, result) { this._automaticTargetState = state; if (!this.isAutoStateBattler()) { return null; } var switchId = this.getStateMetaNumber(0, 1); if (switchId !== null) { if ($gameSwitches.value(switchId)) { result = true; } else { return false; } } var formula = this.getStateMetaString(1); if (formula !== null) { if (eval(formula)) { result = true; } else { return false; } } var upperLimitHp = this.getStateMetaNumber(2, 0, 100); if (upperLimitHp !== null) { if (Math.floor(this.hpRate() * 100) >= upperLimitHp) { result = true; } else { return false; } } var lowerLimitHp = this.getStateMetaNumber(3, 0, 100); if (lowerLimitHp !== null) { if (Math.floor(this.hpRate() * 100) <= lowerLimitHp) { result = true; } else { return false; } } var upperLimitMp = this.getStateMetaNumber(4, 0, 100); if (upperLimitMp !== null) { if (Math.floor(this.mpRate() * 100) >= upperLimitMp) { result = true; } else { return false; } } var lowerLimitMp = this.getStateMetaNumber(5, 0, 100); if (lowerLimitMp !== null) { if (Math.floor(this.mpRate() * 100) <= lowerLimitMp) { result = true; } else { return false; } } var upperLimitTp = this.getStateMetaNumber(6, 0, 100); if (upperLimitTp !== null) { if (Math.floor(this.tpRate() * 100) >= upperLimitTp) { result = true; } else { return false; } } var lowerLimitTp = this.getStateMetaNumber(7, 0, 100); if (lowerLimitTp !== null) { if (Math.floor(this.tpRate() * 100) <= lowerLimitTp) { result = true; } else { return false; } } var unitIndex = this.getStateMetaNumber(12, 0); if (unitIndex !== null) { if (this.index() === unitIndex - 1) { result = true; } else { return false; } } return result; }; Game_BattlerBase.prototype.index = function() { return 0; }; Game_BattlerBase.prototype.getStateMetaNumber = function(tagIndex, min, max) { var value = this._automaticTargetState.meta[DataManager.getAutomaticTagName(tagIndex)]; if (arguments.length < 2) min = -Infinity; if (arguments.length < 3) max = Infinity; return value !== undefined ? getArgNumber(value, min, max) : null; }; Game_BattlerBase.prototype.getStateMetaString = function(tagIndex) { var value = this._automaticTargetState.meta[DataManager.getAutomaticTagName(tagIndex)]; return value !== undefined ? convertEscapeCharacters(value) : null; }; Game_BattlerBase.prototype.isAutoStateBattler = function() { var battlerIdValue = this.getStateMetaString(this.getBattlerCheckTagIndex()); if (!battlerIdValue) { return !this.isStateMetaInfo(this.getOppositeBattlerCheckTagIndex()); } var batterId = this.getBattlerId(); return battlerIdValue.split(',').some(function(stateTargetIdText) { return batterId === parseInt(stateTargetIdText); }); }; Game_BattlerBase.prototype.isStateMetaInfo = function(tagIndex) { return this._automaticTargetState.meta.hasOwnProperty(DataManager.getAutomaticTagName(tagIndex)); }; var _Game_BattlerBase_setHp = Game_BattlerBase.prototype.setHp; Game_BattlerBase.prototype.setHp = function(hp) { _Game_BattlerBase_setHp.apply(this, arguments); this.updateAutomaticState(); }; var _Game_BattlerBase_setMp = Game_BattlerBase.prototype.setMp; Game_BattlerBase.prototype.setMp = function(mp) { _Game_BattlerBase_setMp.apply(this, arguments); this.updateAutomaticState(); }; var _Game_BattlerBase_setTp = Game_BattlerBase.prototype.setTp; Game_BattlerBase.prototype.setTp = function(tp) { _Game_BattlerBase_setTp.apply(this, arguments); this.updateAutomaticState(); }; var _Game_BattlerBase_recoverAll = Game_BattlerBase.prototype.recoverAll; Game_BattlerBase.prototype.recoverAll = function() { _Game_BattlerBase_recoverAll.apply(this, arguments); this.updateAutomaticState(); this._hp = this.mhp; this._mp = this.mmp; }; Game_BattlerBase.prototype.getBattlerId = function() { return 0; }; Game_BattlerBase.prototype.getBattlerCheckTagIndex = function() { return 0; }; Game_BattlerBase.prototype.getOppositeBattlerCheckTagIndex = function() { return 0; }; //============================================================================= // Game_Actors // データが存在するかどうかを返します。 //============================================================================= Game_Actors.prototype.isExistData = function(actorId) { return !!this._data[actorId]; }; //============================================================================= // Game_Actor // 自動付与ステートの更新処理を定義します。 //============================================================================= Game_Actor.prototype.updateAutomaticState = function() { if (!$gameActors.isExistData(this._actorId)) return; Game_BattlerBase.prototype.updateAutomaticState.call(this); }; Game_Actor.prototype.isAutomaticValid = function(state) { this._automaticTargetState = state; var result = null; var weaponId = this.getStateMetaString(10, 1); if (weaponId !== null) { if (this.hasWeapon($dataWeapons[weaponId])) { result = true; } else { return false; } } var armorId = this.getStateMetaNumber(11, 1); if (armorId !== null) { if (this.hasArmor($dataArmors[armorId])) { result = true; } else { return false; } } return Game_BattlerBase.prototype.isAutomaticValid.call(this, state, result); }; var _Game_Actor_changeEquip = Game_Actor.prototype.changeEquip; Game_Actor.prototype.changeEquip = function(slotId, item) { _Game_Actor_changeEquip.apply(this, arguments); this.updateAutomaticState(); }; Game_Actor.prototype.getBattlerId = function() { return this._actorId; }; Game_Actor.prototype.getBattlerCheckTagIndex = function() { return 8; }; Game_Actor.prototype.getOppositeBattlerCheckTagIndex = function() { return Game_Enemy.prototype.getBattlerCheckTagIndex.call(this); }; //============================================================================= // Game_Enemy // 自動付与ステートの更新処理を定義します。 //============================================================================= Game_Enemy.prototype.getBattlerId = function() { return this._enemyId; }; Game_Enemy.prototype.getBattlerCheckTagIndex = function() { return 9; }; Game_Enemy.prototype.getOppositeBattlerCheckTagIndex = function() { return Game_Actor.prototype.getBattlerCheckTagIndex.call(this); }; //============================================================================= // Game_Party // 全てのアクターの自動付与ステートを更新します。 //============================================================================= Game_Party.prototype.requestUpdateAutomaticState = function() { this._requestUpdateAutomaticState = true; }; Game_Party.prototype.updateAutomaticState = function() { this.members().forEach(function(actor) { actor.updateAutomaticState(); }); this._lastUpdateFrameAutomaticState = Graphics.frameCount; }; Game_Party.prototype.updateAutomaticStateIfRequested = function() { var coolTime = (this._lastUpdateFrameAutomaticState + 10 > Graphics.frameCount); if (this._requestUpdateAutomaticState && !coolTime) { this.updateAutomaticState(); this._requestUpdateAutomaticState = false; } }; var _Game_Party_swapOrder = Game_Party.prototype.swapOrder; Game_Party.prototype.swapOrder = function(index1, index2) { _Game_Party_swapOrder.apply(this, arguments); this.updateAutomaticState(); }; //============================================================================= // Game_Map // 場所移動時に自動付与ステートを更新します。 //============================================================================= var _Game_Map_refreshIfNeeded = Game_Map.prototype.refreshIfNeeded; Game_Map.prototype.refreshIfNeeded = function() { _Game_Map_refreshIfNeeded.apply(this, arguments); $gameParty.updateAutomaticStateIfRequested(); }; var _Game_Map_setup = Game_Map.prototype.setup; Game_Map.prototype.setup = function(mapId) { _Game_Map_setup.apply(this, arguments); $gameParty.updateAutomaticState(); }; var _Game_Map_refresh = Game_Map.prototype.refresh; Game_Map.prototype.refresh = function() { _Game_Map_refresh.apply(this, arguments); $gameParty.requestUpdateAutomaticState(); }; //============================================================================= // Game_ActionResult // ステート付与、解除時のメッセージを抑制します。 //============================================================================= Game_ActionResult.prototype.deleteRemovedStates = function(stateId) { iterate(this.removedStates, function(key, value, index) { if (value === stateId) this.removedStates.splice(index, 1); }.bind(this)); }; Game_ActionResult.prototype.deleteAddedStates = function(stateId) { iterate(this.addedStates, function(key, value, index) { if (value === stateId) this.addedStates.splice(index, 1); }.bind(this)); }; //============================================================================= // DataManager // データベースのロード時に自動付与ステートのみを抽出します。 //============================================================================= DataManager._automaticTagNames = [ 'スイッチ', '計算式', '上限HP', '下限HP', '上限MP', '下限MP', '上限TP', '下限TP', 'アクター', '敵キャラ', '武器装備', '防具装備', '並び順' ]; var _DataManager_onLoad = DataManager.onLoad; DataManager.onLoad = function(object) { _DataManager_onLoad.apply(this, arguments); if (object === $dataStates) { this.setupAutomaticState(); } }; DataManager.setupAutomaticState = function() { this._automaticStates = $dataStates.filter(function(state) { return this._automaticTagNames.some(function(tagName) { return state && !!state.meta[metaTagPrefix + tagName]; }); }.bind(this)); }; DataManager.iterateAutomaticState = function(callBackFunc) { this._automaticStates.forEach(callBackFunc); }; DataManager.getAutomaticTagName = function(index) { return metaTagPrefix + this._automaticTagNames[index]; }; })();