//=============================================================================
// OperateDearFollowers.js
// ----------------------------------------------------------------------------
// Copyright (c) 2017 Tsumio
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
// ----------------------------------------------------------------------------
// Version
// 1.0.2 2017/09/10 フォロワーの操作解除時、自動ですり抜けをONにするよう変更。
// 1.0.1 2017/09/09 プラグインコマンドを追加。不具合の修正。
// 1.0.0 2017/09/09 公開。
// ----------------------------------------------------------------------------
// [GitHub] : https://github.com/Tsumio/rmmv-plugins
// [Blog]   : http://ntgame.wpblog.jp/
// [Twitter]: https://twitter.com/TsumioNtGame
//=============================================================================

/*:
 * @plugindesc This plugin enables the operation of the follower.
 * @author Tsumio
 *
 * @param ----Basic Settings----
 * @desc 
 * @default 
 * 
 * @param OperatingSwitchNumber
 * @type switch
 * @desc When you want to operate followers, this switch should be turned on.
 * @default 11
 * 
 * @help This plugin enables the operation of the follower.
 * 
 * ----feature----
 * -> Turn on a specific switch so you can operate the follower.
 * -> When you switch off the switch, the follower will automatically return.
 * 
 * ----how to use----
 * You can use this plugin after setting some plugin parameters.
 * 
 * ----script command operation----
 * When you want to operate a follower with a script command, turn ON the operation switch and write the following script.
 * this.operateFollower(followerNumber, moveRoute);
 * 
 * "followerNumber" start from 0;
 * "moveRoute" of argument can be received the same object as the object passed to the forceMoveRoute method.
 * Details of moveRoute are written in the following site.
 * https://ameblo.jp/rpgmaker1892/entry-12113554385.html
 * 
 * For example.
 * When you want the first follower to move to right one step, write as the following.
 *     var moveRoute = {
 *       "list":[{"code":3},
 *       ],
 *       "repeat":false,
 *       "skippable":true,
 *       "wait":true};
 *   this.operateFollower(0, moveRoute);
 * 
 * ----plugin command----
 * All plugin commands start with "ODF".
 * Plugin commands are distinguish uppercase and lowercase.
 * And separate each word with a space.
 * Please make sure.
 * 
 * "ODF processRouteEnd FollowerNumber" : RouteEnd.
 * "ODF moveDown FollowerNumber"  : Move down.
 * "ODF moveLeft FollowerNumber"  : Move left.
 * "ODF moveRight FollowerNumber" : Move right.
 * "ODF moveUp FollowerNumber"    : Move up.
 * "ODF moveLowerLeft FollowerNumber"  : Move lower left.
 * "ODF moveLowerRight FollowerNumber" : Move lower right.
 * "ODF moveUpperLeft FollowerNumber"  : Move upper left.
 * "ODF moveUpperRight FollowerNumber" : Move upper right.
 * "ODF moveRandom FollowerNumber" : Move random.
 * "ODF moveTowardPlayer FollowerNumber"   : Move toward player.
 * "ODF moveAwayFromPlayer FollowerNumber" : Move away from player.
 * "ODF moveForward FollowerNumber"  : Move forward.
 * "ODF moveBackward FollowerNumber" : Move backward.
 * "ODF turnDown FollowerNumber"  : Turn down.
 * "ODF turnLeft FollowerNumber"  : Turn left.
 * "ODF turnRight FollowerNumber" : Turn right.
 * "ODF turnUp FollowerNumber"    : Turn up.
 * "ODF turnRight90 FollowerNumber" : Turn right 90 dgrees.
 * "ODF turnLeft90 FollowerNumber" : Turn left 90 dgrees.
 * "ODF turn180 FollowerNumber" : Turn 180 dgrees.
 * "ODF turnRightOrLeft90 FollowerNumber" : Turn right or left 90 dgrees.
 * "ODF turnRandom FollowerNumber" : Turn random.
 * "ODF turnTowardPlayer FollowerNumber" : Turn toward player.
 * "ODF turnAwayFromPlayer FollowerNumber" : Turn away from player.
 * "ODF setWalkAnimeOn FollowerNumber" : On walking anime.
 * "ODF setWalkAnimeOff FollowerNumber" : Off walking anime.
 * "ODF setStepAnimeOn FollowerNumber" : On stepping anime.
 * "ODF setStepAnimeOff FollowerNumber" : Off stepping anime.
 * "ODF setDirectionFixOn FollowerNumber" : On fixing direction.
 * "ODF setDirectionFixOff FollowerNumber" : Off fixing direction.
 * "ODF setThroughOn FollowerNumber" : On through mode.
 * "ODF setThroughOff FollowerNumber" : Off through mode.
 * "ODF setTransparentOn FollowerNumber" : On transparent mode.
 * "ODF setTransparentOff FollowerNumber" : Off transparent mode.
 * "ODF jump FollowerNumber OffsetX OffsetY" : Jump.
 * "ODF setImage FollowerNumber ImageName ImageNumber" : Change character image.
 * "ODF wait FollowerNumber WaitTime" : Wait.
 * "ODF setMoveSpeed FollowerNumber Speed" : Change moving speed.
 * "ODF setMoveFrequency FollowerNumber Frequency" : Change moving requency.
 * "ODF setOpacity FollowerNumber Opacity" : Change opacity.
 * "ODF setBlendMode FollowerNumber BlendMode" : Change blend mode.
 * 
 * ----change log---
 * 1.0.2 2017/09/10 When canceling the follower's operation, change to automatically turn on through mode.
 * 1.0.1 2017/09/09 Add plugin commands.Bug fix.
 * 1.0.0 2017/09/09 Release.
 * 
 * ----remarks----
 * I shall not be responsible for any loss, damages and troubles from using this plugin.
 * 
 * --Terms of Use--
 * This plugin is free for both commercial and non-commercial use.
 * You may edit the source code to suit your needs,
 * so long as you don't claim the source code belongs to you.
 * 
 */
/*:ja
 * @plugindesc フォロワーを操作するプラグインです。
 * @author ツミオ
 *
 * @param ----基本的な設定----
 * @desc 
 * @default 
 * 
 * @param 操作用スイッチ番号
 * @type switch
 * @desc フォロワーを操作したいとき、ONにするスイッチ番号を設定します。
 * @default 11
 * 
 * @help フォロワーを操作するプラグインです。
 * 
 * 【特徴】
 * ・特定のスイッチをONにすると、フォロワーを操作できるようになります。
 * ・スイッチをOFFにすると、フォロワーは自動で戻ってきます。
 * 
 * 【使用方法】
 * プラグインの導入後、プラグインパラメーターを設定することによって使用できます。
 * 
 * 
 * 【スクリプトコマンドでの操作】
 * フォロワーをスクリプトコマンドで操作するには、操作用のスイッチをONにしたあと、以下のような記述をします。
 * this.operateFollower(followerNumber, moveRoute);
 * 
 * followerNumberは0から始まります。
 * 引数moveRouteには、forceMoveRouteメソッドに渡すオブジェクトと同じオブジェクトを渡せます。
 * moveRouteの詳細は、以下のサイトに詳しく載っています。
 * https://ameblo.jp/rpgmaker1892/entry-12113554385.html
 * 
 * 例えば一番最初のフォロワーを右に一歩動かしたい場合、以下のように記述します。
 *     var moveRoute = {
 *       "list":[{"code":3},
 *       ],
 *       "repeat":false,
 *       "skippable":true,
 *       "wait":true};
 *   this.operateFollower(0, moveRoute);
 * 
 * 【プラグインコマンド】
 * 全てのプラグインコマンドは「ODF」から始まります。
 * また、説明上では視認性のためにカギカッコを使用していますが、実際にプラグインコマンドに入力する際には
 * カギカッコの入力は不要です。
 * 
 * 全てのプラグインコマンドは大文字と小文字を区別します。
 * 各単語の間は半角スペースで区切ります（全角では認識しません）。
 * 間違わないように気をつけてください。
 * 
 * 「ODF processRouteEnd フォロワー番号」 : 移動終了。
 * 「ODF moveDown フォロワー番号」  : 下に移動。
 * 「ODF moveLeft フォロワー番号」  : 左に移動。
 * 「ODF moveRight フォロワー番号」 : 右に移動。
 * 「ODF moveUp フォロワー番号」    : 上に移動。
 * 「ODF moveLowerLeft フォロワー番号」  : 左下に移動。
 * 「ODF moveLowerRight フォロワー番号」 : 右下に移動。
 * 「ODF moveUpperLeft フォロワー番号」  : 左上に移動。
 * 「ODF moveUpperRight フォロワー番号」 : 右上に移動。
 * 「ODF moveRandom フォロワー番号」 : ランダムに移動。
 * 「ODF moveTowardPlayer フォロワー番号」   : プレイヤーに近づく。
 * 「ODF moveAwayFromPlayer フォロワー番号」 : プレイヤーから遠ざかる。
 * 「ODF moveForward フォロワー番号」  : 一歩前進。
 * 「ODF moveBackward フォロワー番号」 : 一歩後退。
 * 「ODF turnDown フォロワー番号」  : 下を向く。
 * 「ODF turnLeft フォロワー番号」  : 左を向く。
 * 「ODF turnRight フォロワー番号」 : 右を向く。
 * 「ODF turnUp フォロワー番号」    : 上を向く。
 * 「ODF turnRight90 フォロワー番号」 : 右に90度回転。
 * 「ODF turnLeft90 フォロワー番号」 : 左に90度回転。
 * 「ODF turn180 フォロワー番号」 : 180度回転。
 * 「ODF turnRightOrLeft90 フォロワー番号」 : 右か左に90度回転。
 * 「ODF turnRandom フォロワー番号」 : ランダムに方向回転
 * 「ODF turnTowardPlayer フォロワー番号」 : プレイヤーの方を向く。
 * 「ODF turnAwayFromPlayer フォロワー番号」 : プレイヤーの逆を向く。
 * 「ODF setWalkAnimeOn フォロワー番号」 : 歩行アニメON。
 * 「ODF setWalkAnimeOff フォロワー番号」 : 歩行アニメOFF。
 * 「ODF setStepAnimeOn フォロワー番号」 : 足踏みアニメON。
 * 「ODF setStepAnimeOff フォロワー番号」 : 足踏みアニメOFF。
 * 「ODF setDirectionFixOn フォロワー番号」 : 向き固定ON。
 * 「ODF setDirectionFixOff フォロワー番号」 : 向き固定OFF。
 * 「ODF setThroughOn フォロワー番号」 : すり抜けON。
 * 「ODF setThroughOff フォロワー番号」 : すり抜けOFF。
 * 「ODF setTransparentOn フォロワー番号」 : 透明化ON。
 * 「ODF setTransparentOff フォロワー番号」 : 透明化OFF。
 * 「ODF jump フォロワー番号 オフセットX オフセットY」 : ジャンプ。
 * 「ODF setImage フォロワー番号 イメージ名 イメージ番号」 : 画像の変更。
 * 「ODF wait フォロワー番号 待機時間」 : ウェイト。
 * 「ODF setMoveSpeed フォロワー番号 移動速度」 : 移動速度の変更。
 * 「ODF setMoveFrequency フォロワー番号 移動頻度」 : 移動頻度の変更。
 * 「ODF setOpacity フォロワー番号 不透明度」 : 不透明度の変更。
 * 「ODF setBlendMode フォロワー番号 合成方法」 : 合成方法の変更。
 * 
 * 【更新履歴】
 * 1.0.2 2017/09/10 フォロワーの操作解除時、自動ですり抜けをONにするよう変更。
 * 1.0.1 2017/09/09 プラグインコマンドを追加。不具合の修正。
 * 1.0.0 2017/09/09 公開。
 * 
 * 【備考】
 * 当プラグインを利用したことによるいかなる損害に対しても、制作者は一切の責任を負わないこととします。
 * 
 * 【利用規約】
 * ソースコードの著作権者が自分であると主張しない限り、
 * 作者に無断で改変、再配布が可能です。
 * 利用形態（商用、18禁利用等）についても制限はありません。
 * 自由に使用してください。
 * 
 */

(function() {
    'use strict';
    var pluginName = 'OperateDearFollowers';

////=============================================================================
//// NTMO
////  Declare NTMO namespace.
////=============================================================================
    var NTMO = NTMO || {};
    NTMO.ODF = function(){
    };

////=============================================================================
//// Local function
////  These functions checks & formats pluguin's command parameters.
////  I borrowed these functions from Triacontane.Thanks!
////=============================================================================
    var getParamString = 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 '';
    };

    var getParamNumber = function(paramNames, min, max) {
        var value = getParamString(paramNames);
        if (arguments.length < 2) min = -Infinity;
        if (arguments.length < 3) max = Infinity;
        return (parseInt(value) || 0).clamp(min, max);
    };

////=============================================================================
//// Get and set pluguin parameters.
////=============================================================================
    var param                          = {};
    //Basic Stteings
    param.operatingSwitchNumber        = getParamNumber(['OperatingSwitchNumber', '操作用スイッチ番号']);

//-----------------------------------------------------------------------------
// Settings for plugin command.
//-----------------------------------------------------------------------------
    var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
    Game_Interpreter.prototype.pluginCommand = function (command, args) {
        _Game_Interpreter_pluginCommand.call(this, command, args);
        if (command === 'ODF') {
            switch (args[0]) {
                case 'processRouteEnd':
                case 'moveDown':
                case 'moveLeft':
                case 'moveRight':
                case 'moveUp':
                case 'moveLowerLeft':
                case 'moveLowerRight':
                case 'moveUpperLeft':
                case 'moveUpperRight':
                case 'moveRandom':
                case 'moveTowardPlayer':
                case 'moveAwayFromPlayer':
                case 'moveForward':
                case 'moveBackward':
                case 'turnDown':
                case 'turnLeft':
                case 'turnRight':
                case 'turnUp':
                case 'turnRight90':
                case 'turnLeft90':
                case 'turn180':
                case 'turnRightOrLeft90':
                case 'turnRandom':
                case 'turnTowardPlayer':
                case 'turnAwayFromPlayer':
                case 'setWalkAnimeOn':
                case 'setWalkAnimeOff':
                case 'setStepAnimeOn':
                case 'setStepAnimeOff':
                case 'setDirectionFixOn':
                case 'setDirectionFixOff':
                case 'setThroughOn':
                case 'setThroughOff':
                case 'setTransparentOn':
                case 'setTransparentOff':
                    NTMO.ODF_Base.operate(args[0], args[1]);
                    break;
                case 'jump':
                case 'setImage':
                    NTMO.ODF_Base.operate(args[0], args[1], args[2], args[3]);
                    break;
                case 'wait':
                case 'setMoveSpeed':
                case 'setMoveFrequency':
                case 'setOpacity':
                case 'setBlendMode':
                    NTMO.ODF_Base.operate(args[0], args[1], args[2]);
                    break;
            }
        }
    };


////==============================
//// NTMO.BGB_Base
//================================
    NTMO.ODF_Base = function(){
    };

    NTMO.ODF_Base.canGetFollower = function(num) {
        return $gamePlayer.followers()._data.length > num;
    };

    NTMO.ODF_Base.operate = function(command, num) {
        if(!NTMO.ODF_Base.canGetFollower(num)){
            return;
        }

        var follower = $gamePlayer.followers()._data[Number(num)];

        switch (command) {
            case 'processRouteEnd':
                follower.processRouteEnd();
                break;
            case 'moveDown':
                follower.moveStraight(2);
                break;
            case 'moveLeft':
                follower.moveStraight(4);
                break;
            case 'moveRight':
                follower.moveStraight(6);
                break;
            case 'moveUp':
                follower.moveStraight(8);
                break;
            case 'moveLowerLeft':
                follower.moveDiagonally(4, 2);
                break;
            case 'moveLowerRight':
                follower.moveDiagonally(6, 2);
                break;
            case 'moveUpperLeft':
                follower.moveDiagonally(4, 8);
                break;
            case 'moveUpperRight':
                follower.moveDiagonally(6, 8);
                break;
            case 'moveRandom':
                follower.moveRandom();
                break;
            case 'moveTowardPlayer':
                follower.moveTowardPlayer();
                break;
            case 'moveAwayFromPlayer':
                follower.moveAwayFromPlayer();
                break;
            case 'moveForward':
                follower.moveForward();
                break;
            case 'moveBackward':
                follower.moveBackward();
                break;
            case 'jump':
                follower.jump(Number(arguments[2]), Number(arguments[3]));
                break;
            case 'wait':
                follower._waitCount = Number(arguments[2]) - 1;
                break;
            case 'turnDown':
                follower.setDirection(2);
                break;
            case 'turnLeft':
                follower.setDirection(4);
                break;
            case 'turnRight':
                follower.setDirection(6);
                break;
            case 'turnUp':
                follower.setDirection(8);
                break;
            case 'turnRight90':
                follower.turnRight90();
                break;
            case 'turnLeft90':
                follower.turnLeft90();
                break;
            case 'turn180':
                follower.turn180();
                break;
            case 'turnRightOrLeft90':
                follower.turnRightOrLeft90();
                break;
            case 'turnRandom':
                follower.turnRandom();
                break;
            case 'turnTowardPlayer':
                follower.turnTowardPlayer();
                break;
            case 'turnAwayFromPlayer':
                follower.turnAwayFromPlayer();
                break;
            case 'setMoveSpeed':
                follower.setMoveSpeed(Number(arguments[2]));
                break;
            case 'setMoveFrequency':
                follower.setMoveFrequency(Number(arguments[2]));
                break;
            case 'setWalkAnimeOn':
                follower.setWalkAnime(true);
                break;
            case 'setWalkAnimeOff':
                follower.setWalkAnime(false);
                break;
            case 'setStepAnimeOn':
                follower.setStepAnime(true);
                break;
            case 'setStepAnimeOff':
                follower.setStepAnime(false);
                break;
            case 'setDirectionFixOn':
                follower.setDirectionFix(true);
                break;
            case 'setDirectionFixOff':
                follower.setDirectionFix(false);
                break;
            case 'setThroughOn':
                follower.setThrough(true);
                break;
            case 'setThroughOff':
                follower.setThrough(false);
                break;
            case 'setTransparentOn':
                follower.setTransparent(true);
                break;
            case 'setTransparentOff':
                follower.setTransparent(false);
                break;
            case 'setImage':
                follower.setImage(arguments[2], Number(arguments[3]));
                break;
            case 'setOpacity':
                follower.setOpacity(Number(arguments[2]));
                break;
            case 'setBlendMode':
                follower.setBlendMode(Number(arguments[2]));
                break;
        }
    };

////=============================================================================
//// Game_Followers
////  Add operating followers function.
////  Maybe I must override some methods.
////=============================================================================

    //Override.
    var _Game_Followers_updateMove = Game_Followers.prototype.updateMove;
    Game_Followers.prototype.updateMove = function() {
        //If user turn on the switch for operating followers, original method does not excute.
        if(this.canOperateFollowers()){
            this.updateOperatingFollowers();
            return;
        }

        _Game_Followers_updateMove.call(this);
    };

    Game_Followers.prototype.updateOperatingFollowers = function() {

    };

    Game_Followers.prototype.canOperateFollowers = function() {
        return $gameSwitches.value(param.operatingSwitchNumber);
    };

    Game_Followers.prototype.forceMoveRoute = function(num, moveRoute) {
        this._data[num].forceMoveRoute(moveRoute);
    };

    Game_Followers.prototype.clearMoveRoute = function() {
        for(var follower of this._data){
            follower.setMoveRoute(null);
            follower.setTransparent($dataSystem.optTransparent);
            follower.setThrough(true);
        }
    };

////=============================================================================
//// Game_Follower
////  Add operating follower function.
////  This is not follower"s" but follower class !
////=============================================================================

   var _Game_Follower_update = Game_Follower.prototype.update;
    Game_Follower.prototype.update = function() {
        if(this.canOperateFollower()){
            Game_Character.prototype.update.call(this);
            return;
        }

        _Game_Follower_update.call(this);
    };

    Game_Follower.prototype.canOperateFollower = function() {
        return $gameSwitches.value(param.operatingSwitchNumber);
    };

////=============================================================================
//// Game_Switches
////  Set gathering event !
////=============================================================================
    var _Game_Switches_setValue = Game_Switches.prototype.setValue;
    Game_Switches.prototype.setValue = function(switchId, value) {
        _Game_Switches_setValue.call(this, switchId, value);

        //Set gathering event.
        if(switchId === param.operatingSwitchNumber && 
            !$gameSwitches.value(param.operatingSwitchNumber)){
            $gamePlayer.followers().clearMoveRoute();
            $gamePlayer.gatherFollowers();
        }
    };

////=============================================================================
//// Game_Interpreter
////  Add a operating function !
////=============================================================================
    Game_Interpreter.prototype.operateFollower = function(num, moveRoute) {
        $gamePlayer.followers().forceMoveRoute(num, moveRoute);
    };

})();