//============================================================================= // ConfusionExtend.js // ---------------------------------------------------------------------------- // (C)2016 Triacontane // This software is released under the MIT License. // http://opensource.org/licenses/mit-license.php // ---------------------------------------------------------------------------- // Version // 1.5.0 2020/05/23 混乱スキルの指定で、最後に使用したスキルを選択できる機能を追加 // 1.4.1 2020/04/22 混乱スキルのターゲットが「敵n体ランダム」のとき全体攻撃になってしまう問題を修正 // 1.4.0 2017/10/07 混乱スキルのターゲット選択方法にラストターゲット(直前に選択した対象)を追加しました。 // 1.3.0 2017/06/10 制約「敵を攻撃」の場合に味方対象スキルを実行した場合、対象を味方にするよう修正 // 使用可能スキルに除外設定を追加 // 1.2.0 2017/05/02 使用可能なスキルの中からランダムで使用する機能を追加 // 1.1.0 2016/11/12 裏切り機能と味方対象スキルの対象を反転させる機能を追加 // 1.0.0 2016/08/13 初版 // ---------------------------------------------------------------------------- // [Blog] : https://triacontane.blogspot.jp/ // [Twitter]: https://twitter.com/triacontane/ // [GitHub] : https://github.com/triacontane/ //============================================================================= /*: @url https://triacontane.blogspot.com/ @plugindesc Confusion State Extension Plugin @author Triacontane @license MIT License @help English Help Translator: munokura This is an unofficial English translation of the plugin help, created to support global RPG Maker users. Feedback is welcome to improve translation quality (see: https://github.com/munokura/triacontane-MV-plugins ). Original plugin by Triacontane. Please check the latest official version at: https://triacontane.blogspot.com ----- For confusion-type states (action constraints set to "1" through "3"), you can expand the options to specify skills (multiple options available) instead of standard attacks. You can also specify backup skills to use if all of those skills are unavailable. The target is determined by the state's action constraints, the skill's range, and the value set in the Note field. - If the skill's range is "User," Regardless of the action constraint, the target will always be the "User." - If the action constraint is "Attack Enemy," The target will be "Single Enemy" (specified in the Note field or random) or "All Enemies." - If the action constraint is "Attack Someone," The target will be "Single Enemy" (specified in the Note field or random), "All Enemies," "Single Ally" (specified in the Note field or random), or "All Allies." - If the action constraint is "Attack Ally," The target will be "Single Ally" (specified in the Note field or random) or "All Allies." 1. Select the action creation dropdown in the state database. ・Attack enemy ・Attack someone ・Attack ally 2. Specify the following in the state's Note field. # Skills with ID [3..5] will be used instead of normal attacks. # Skills from the fourth skill onwards can be specified in the same way. # Specifying -1 will use the last used skill. # All available skills will be candidates. # If all specified skills cannot be used due to insufficient MP, etc., skill with ID [6] will be used. # Specify the target of a single-target skill to the [0]th character. If no Note field is specified, a random target will be selected. Specifying -1 will make it the last target. When specifying available skills, you can separately specify skills you do not want the character to use. # Removes [1], [2], and [3] from the available skills. - Additional Features When the Betrayal feature is enabled, the battler with the active state will no longer be targeted by enemies or confusion skills. Furthermore, if all other battlers are incapacitated, they will be considered annihilated. Enter the following in the Note field of the feature database. # The target battler will temporarily be removed from your team. This plugin does not have plugin commands. Terms of Use: You may modify and redistribute this plugin without permission from the author, and there are no restrictions on its use (commercial, 18+, etc.). This plugin is now yours. @param TargetFriendSkill @desc When this is turned on, if the action constraint is "Attack allies," using a skill that targets an ally will target the enemy. @type boolean @default false */ /*:ja @plugindesc 混乱ステート拡張プラグイン @author トリアコンタン @param 味方対象スキルの対象 @desc ONにすると行動制約が「味方を攻撃」のときに味方対象のスキルを使用すると、敵を対象にします。 @default false @type boolean @help 混乱系(行動制約のプルダウンの選択値が「1」~「3」)ステートの 指定内容を拡張し、通常攻撃ではなくスキル(複数指定可能)を指定したり さらにそれらのスキルがすべて使用できない場合に使用する予備スキルも 指定できます。 誰をターゲットにするかは、ステートの行動制約の種類と使用スキルの効果範囲 およびメモ欄で設定した値によって決まります。 ・スキルの効果範囲が「使用者」の場合 行動制約の種類とは無関係に、対象は必ず「使用者」になります。 ・行動制約が「敵を攻撃」の場合 対象は「敵単体」(メモ欄指定対象もしくはランダム)か「敵全体」になります。 ・行動制約が「誰かを攻撃」の場合 対象は「敵単体」(メモ欄指定対象もしくはランダム)か「敵全体」もしくは 「味方単体」(メモ欄指定対象もしくはランダム)か「味方全体」になります。 ・行動制約が「味方を攻撃」の場合 対象は「味方単体」(メモ欄指定対象もしくはランダム)か「味方全体」になります。 1. ステートのデータベースで行動制作のプルダウンを指定してください。 ・敵を攻撃 ・誰かを攻撃 ・味方を攻撃 2. ステートのメモ欄を以下の通り指定してください。 # 通常攻撃の代わりにID[3..5]のスキルが使用されます。 # 4番目以降も同様に指定可能です。 # -1を指定すると最後に使用したスキルを使います。 # 使用可能なスキルが全て候補になります。 # 指定されたスキルがMP不足等の理由ですべて 使用できない場合、ID[6]のスキルが使用されます。 # 単体スキルの対象を[0]番目のキャラクターに指定します。 メモ欄の指定がない場合はランダムで決定されます。 -1を指定するとラストターゲットになります。 使用可能スキルを指定する際、使わせたくないスキルを別途指定できます。 # 使用可能スキルのうち[1][2][3]を候補から外します。 ・追加機能 裏切り機能を有効にすると対象のステートが有効になっているバトラーが 敵や混乱スキルの攻撃対象から外れ、さらにそのバトラー以外が戦闘不能になると 全滅扱いになります。 特徴を有するデータベースのメモ欄に、以下の通り記述してください。 # 対象バトラーが一時的に味方から外れます。 # 同上 このプラグインにはプラグインコマンドはありません。 利用規約: 作者に無断で改変、再配布が可能で、利用形態(商用、18禁利用等) についても制限はありません。 このプラグインはもうあなたのものです。 */ (function () { 'use strict'; var pluginName = 'ConfusionExtend'; var metaTagPrefix = 'CE'; var getParamOther = function (paramNames) { if (!Array.isArray(paramNames)) paramNames = [paramNames]; for (var i = 0; i < paramNames.length; i++) { var name = PluginManager.parameters(pluginName)[paramNames[i]]; if (name) return name; } return null; }; var getParamBoolean = function (paramNames) { var value = (getParamOther(paramNames) || '').toUpperCase(); return value === 'ON' || value === 'TRUE'; }; var getArgNumber = function (arg, min, max) { if (arguments.length < 2) min = -Infinity; if (arguments.length < 3) max = Infinity; return (parseInt(convertEscapeCharacters(arg), 10) || 0).clamp(min, max); }; var getArgArrayNumber = function (args, min, max) { var values = getArgArrayString(args, false); if (arguments.length < 2) min = -Infinity; if (arguments.length < 3) max = Infinity; for (var i = 0; i < values.length; i++) { values[i] = (parseFloat(values[i], 10) || 0).clamp(min, max); } return values; }; var getArgArrayString = function (args) { var values = args.split(','); for (var i = 0; i < values.length; i++) { values[i] = values[i].trim(); } return values; }; var getMetaValue = function (object, name) { var metaTagName = metaTagPrefix + (name ? name : ''); return object.meta.hasOwnProperty(metaTagName) ? object.meta[metaTagName] : undefined; }; var getMetaValues = function (object, names) { if (!Array.isArray(names)) return getMetaValue(object, names); for (var i = 0, n = names.length; i < n; i++) { var value = getMetaValue(object, names[i]); if (value !== undefined) return value; } return undefined; }; var convertEscapeCharacters = function (text) { if (text == null) text = ''; var windowLayer = SceneManager._scene._windowLayer; return windowLayer ? windowLayer.children[0].convertEscapeCharacters(text) : text; }; //============================================================================= // パラメータの取得と整形 //============================================================================= var paramTargetFriendSkill = getParamBoolean(['TargetFriendSkill', '味方対象スキルの対象']); //============================================================================= // Game_BattlerBase // 行動制約が有効なステートデータを取得します。 //============================================================================= Game_BattlerBase.prototype.getRestrictStates = function () { var restriction = this.restriction(); if (restriction === 0 || restriction >= 4) return []; return this.states().filter(function (state) { return state.restriction === restriction; }); }; Game_BattlerBase.prototype.getRestrictState = function () { return this.getRestrictStates().sort(this.compareOrderStatePriority.bind(this))[0]; }; Game_BattlerBase.prototype.compareOrderStatePriority = function (stateA, stateB) { return stateA.priority - stateB.priority; }; Game_BattlerBase.prototype.isBetrayer = function () { return this.traitObjects().some(function (traitObject) { return getMetaValues(traitObject, ['裏切り', 'Betrayal']); }); }; Game_BattlerBase.prototype.getUsableSkillIdList = function () { return [this.attackSkillId(), this.guardSkillId()]; }; Game_BattlerBase.prototype.getLastUsedSkillId = function () { return this._lastUsedSkillId; }; Game_BattlerBase.prototype.setLastUsedSkillId = function (id) { this._lastUsedSkillId = id; }; //============================================================================= // Game_Battler // ラストターゲットを取得します。 //============================================================================= Game_Battler.prototype.getLastTargetIndex = function () { return this._lastTargetIndex; }; //============================================================================= // Game_Actor // 使用可能なスキル一覧を取得します。 //============================================================================= Game_Actor.prototype.getUsableSkillIdList = function () { var skillIds = this.usableSkills().map(function (skill) { return skill.id; }); return Game_BattlerBase.prototype.getUsableSkillIdList.call(this).concat(skillIds); }; //============================================================================= // Game_Enemy // 使用可能なスキル一覧を取得します。 //============================================================================= Game_Enemy.prototype.getUsableSkillIdList = function () { var actionList = this.enemy().actions.filter(function (a) { return this.isActionValid(a); }, this); return actionList.map(function (action) { return action.skillId; }); }; //============================================================================= // Game_Unit // 裏切り機能を追加します。 //============================================================================= var _Game_Unit_aliveMembers = Game_Unit.prototype.aliveMembers; Game_Unit.prototype.aliveMembers = function () { var members = _Game_Unit_aliveMembers.apply(this, arguments); return members.filter(function (member) { return !member.isBetrayer(); }); }; //============================================================================= // Game_Action // 混乱時のスキルを別途設定します。 //============================================================================= var _Game_Action_apply = Game_Action.prototype.apply; Game_Action.prototype.apply = function (target) { if (this.isSkill()) { this.subject().setLastUsedSkillId(this.item().id); } _Game_Action_apply.apply(this, arguments); }; var _Game_Action_setConfusion = Game_Action.prototype.setConfusion; Game_Action.prototype.setConfusion = function () { _Game_Action_setConfusion.apply(this, arguments); var skillIds = this.getConfusionSkills(); if (!skillIds) return; skillIds = skillIds.filter(function (skillId) { return this.subject().canUse($dataSkills[skillId]); }.bind(this)); if (skillIds.length > 0) { this.setConfusionSkill(skillIds); } else { this.setConfusionSpareSkill(); } }; Game_Action.prototype.getConfusionSkills = function () { var state = this.getRestrictState(); if (!state) return null; var skillIds = [], i = 1; while (i) { var metaValue = getMetaValues(state, ['スキル' + i, 'Skill' + i]); if (metaValue) { var id = getArgNumber(metaValue, -1); if (id <= 0) { id = this.findSubjectLastBattleSkill(); } skillIds.push(id); i++; } else { i = (i > 10 ? null : i + 1); } } return skillIds.concat(this.getConfusionUsableSkills(state)); }; Game_Action.prototype.findSubjectLastBattleSkill = function () { return this.subject().getLastUsedSkillId() || 1; }; Game_Action.prototype.getConfusionUsableSkills = function (state) { var usableSkillInclude = getMetaValues(state, ['使用可能スキル', 'UsableSkill']); var skillList = []; if (usableSkillInclude) { skillList = this.subject().getUsableSkillIdList(); if (usableSkillInclude !== true) { skillList = this.filterConfusionUsableSkills(skillList, usableSkillInclude); } } return skillList; }; Game_Action.prototype.filterConfusionUsableSkills = function (skillList, usableSkillInclude) { var filterList = getArgArrayNumber(usableSkillInclude); skillList = skillList.filter(function (skillId) { return !filterList.contains(skillId); }); return skillList; }; Game_Action.prototype.getRestrictState = function () { return this.subject().getRestrictState(); }; Game_Action.prototype.isExistConfusionSkill = function () { var skillIds = this.getConfusionSkills(); return skillIds && skillIds.length > 0; }; Game_Action.prototype.setConfusionSkill = function (skillIds) { var skillId = skillIds[Math.randomInt(skillIds.length)]; this.setSkill(skillId); }; Game_Action.prototype.setConfusionSpareSkill = function () { var state = this.getRestrictState(); var value = getMetaValues(state, ['予備スキル', 'SpareSkill']); if (value) { var skillId = getArgNumber(value, 1); if (this.subject().canUse($dataSkills[skillId])) { this.setSkill(skillId); } } }; var _Game_Action_repeatTargets = Game_Action.prototype.repeatTargets; Game_Action.prototype.repeatTargets = function (targets) { if (Array.isArray(targets[0])) arguments[0] = targets[0]; return _Game_Action_repeatTargets.apply(this, arguments); }; var _Game_Action_confusionTarget = Game_Action.prototype.confusionTarget; Game_Action.prototype.confusionTarget = function () { var target = _Game_Action_confusionTarget.apply(this, arguments); if (this.isExistConfusionSkill()) { target = this.confusionSkillTarget(); } return target; }; Game_Action.prototype.confusionSkillTarget = function () { var state = this.getRestrictState(); var value = getMetaValues(state, ['ターゲット', 'Target']); if (value) { var index = getArgNumber(value, -1); this._targetIndex = (index === -1 ? this.subject().getLastTargetIndex() : index); } if (this.isForUser()) { return this.subject(); } return this.isConfusionSkillTargetForFriend() ? this.targetsForConfusionFriends() : this.targetsForOpponents(); }; Game_Action.prototype.targetsForConfusionFriends = function () { if (this.isForRandom()) { var targets = []; var unit = this.friendsUnit(); for (var i = 0; i < this.numTargets(); i++) { targets.push(unit.randomTarget()); } return targets; } else { return this.targetsForFriends(); } }; Game_Action.prototype.isConfusionSkillTargetForFriend = function () { switch (this.subject().confusionLevel()) { case 1: return this.isForFriend(); case 2: return Math.randomInt(2) === 0; case 3: return !this.isConfusionSkillTargetReverse(); } return false; }; Game_Action.prototype.isConfusionSkillTargetReverse = function () { return paramTargetFriendSkill && this.isForFriend(); }; })();