/*:
 * @plugindesc 方向キーとボタンでのコマンド入力を実行します。
 * @author hiz
 *
 * @param success SE
 * @desc 入力時（成功）のSE
 * @default Decision2
 *
 * @param miss SE
 * @desc 入力時（失敗）のSE
 * @default Buzzer1
 *
 * @param penalty
 * @desc 入力ミス時の入力不能時間（フレーム）
 * @default 10
 *
 * @help
 * 方向キーとボタンでのコマンド入力を実行します。
 *
 *  プラグインコマンド:
 *   HzCommand [mode] [switch_no] [command] [x] [y] [align]  # コマンド入力起動
 *
 *   [mode]
 *    【必須】入力モード。
 *        1:入力ミスしても入力を継続　2:入力ミスしたらその時点で失敗
 *   [switch_no]
 *    【必須】入力結果をセットするスイッチ番号を指定します。
 *   [command]
 *    【必須】コマンドの内容を指定します。
 *        2:↓ 4:← 6:→ 8:↑ z:Zキー x:Xキー
 *      例） 2486z              # ↓←↑→Zキー
 *
 *      また、以下のように記述することでコマンドをランダムで設定できます。（複数繋げて設定可）
 *        <[コマンドに含めるキー],[入力数]>
 *      例） <2468,2>           # ↓←、↑↑、→←等、コマンドに「↓←↑→」のキーがランダムで2個セットされる
 *           <2468,4><zx,1>    # ↓←↑→Zキー、↑↑→←Xキー等、コマンドに「↓←↑→」のキーが
 *                              # ランダムで4個セットされた後にZキー又はXキーが1個セットされる
 *      NG例）
 *           <2468,4>z          # ランダム指定と直接指定を混ぜる事はできません。
 *                              # <2468,4><z,1>のように記述して下さい。
 *   [x]
 *     【任意】コマンドの表示位置を指定します。（デフォルトでは画面中央）
 *   [y]
 *     【任意】コマンドの表示位置を指定します。（デフォルトでは画面中央）
 *   [align]
 *     【任意】コマンドの表示の基準を指定します。（デフォルトでは"center"）
 *       left:左端基準 center:中央基準 right:右端基準
 *
 *  コマンド例）
 *    HzCommand 1 1 2486          # コマンド「↓←↑→」。入力ミスしても処理継続。失敗/成功はスイッチ番号１にセットされる。
 *    HzCommand 2 1 <2486,4>      # コマンドには「↓←↑→」のキーがランダムで4個セットされる。
 *                                # 入力ミスしたらその場で失敗。失敗/成功はスイッチ番号１にセットされる。
 *   HzCommand 1 1 2486 0 40 left # コマンド「↓←↑→」。入力ミスしても処理継続。失敗/成功はスイッチ番号１にセットされる。
 *                                # コマンドの表示位置は画面左上端。
 *
 * ※ 時間制限を設ける場合
 *   時間制限を設ける場合は、予めツクールのタイマーを起動して下さい。
 *   タイマーが0秒になった際にコマンド入力が強制終了され、失敗となります。
 *
 */

(function () {
  var parameters = PluginManager.parameters("HzInputCommand");
  var successSe = parameters["success SE"];
  var missSe = parameters["miss SE"];
  var penaltyFrame = Number(parameters["penalty"] || 0);

  var _Game_Interpreter_pluginCommand =
    Game_Interpreter.prototype.pluginCommand;
  Game_Interpreter.prototype.pluginCommand = function (command, args) {
    _Game_Interpreter_pluginCommand.call(this, command, args);
    // スクリプトコマンド「HZCOMMAND」
    if (command.toUpperCase() === "HZCOMMAND") {
      this.setWaitMode("hzCommand");
      var x = args[3] != null ? Number(args[3]) : SceneManager._screenWidth / 2;
      var y =
        args[4] != null ? Number(args[4]) : SceneManager._screenHeight / 2;
      var align = args[5] || "center";
      // ランダムコマンドの処理
      var com = args[2];
      var randCom = com.match(/<([2468zx]*),(\d*)>+/g);
      if (randCom != null) {
        com = "";
        randCom.forEach(function (randComParmOrg) {
          var randComParm = randComParmOrg.match(/<([2468zx]*),(\d*)>/);
          for (var i = 1; i < randComParm.length; i += 2) {
            var target = randComParm[i];
            var num = Number(randComParm[i + 1]);
            var result = "";
            for (var j = 0; j < num; j++) {
              com += target[Math.randomInt(target.length)];
            }
          }
        });
      }
      this._inputCommand = new HzInputCommand(
        x,
        y,
        com,
        align,
        Number(args[0]),
        Number(args[1])
      );
    }
  };

  // 待機状態の更新用関数に機能追加
  var _Game_Interpreter_updateWaitMode =
    Game_Interpreter.prototype.updateWaitMode;
  Game_Interpreter.prototype.updateWaitMode = function () {
    var waiting = null;
    switch (this._waitMode) {
      case "hzCommand":
        // 待機状態の更新
        // ※ waitingには必ずtrueかfalseをセットすること！
        waiting = this._inputCommand.update();
        if (!waiting) {
          // 終了処理
          this._inputCommand.terminate();
          this._inputCommand = null;
        }
        break;
    }
    if (waiting !== null) {
      if (!waiting) {
        this._waitMode = "";
      }
      return waiting;
    }
    return _Game_Interpreter_updateWaitMode.call(this);
  };

  // コマンド入力実行用クラス
  function HzInputCommand() {
    this.initialize.apply(this, arguments);
  }

  var bmpCursorRight = new Bitmap(80, 70);
  drawCursorRight(bmpCursorRight.context);
  var bmpButtonZ = new Bitmap(80, 80);
  drawButtonZ(bmpButtonZ.context);
  var bmpButtonX = new Bitmap(80, 80);
  drawButtonX(bmpButtonX.context);

  function createCursorSprite(d, x, y) {
    var sprite = new Sprite(bmpCursorRight);
    sprite.anchor = new Point(0.5, 0.5);
    switch (d) {
      case 2:
        // down
        sprite.rotation = Math.PI / 2.0;
        break;
      case 4:
        // left
        sprite.rotation = Math.PI;
        break;
      case 6:
        // right
        sprite.rotation = 0;
        break;
      case 8:
        // up
        sprite.rotation = -Math.PI / 2.0;
        break;
    }
    sprite.x = x;
    sprite.y = y;
    return sprite;
  }

  function createButtonSprite(type, x, y) {
    var sprite;
    switch (type) {
      case 1:
        sprite = new Sprite(bmpButtonZ);
        break;
      case 2:
        sprite = new Sprite(bmpButtonX);
        break;
      case 3:
        sprite = new Sprite(bmpButtonC);
        break;
    }
    sprite.anchor = new Point(0.5, 0.5);
    sprite.x = x;
    sprite.y = y;
    return sprite;
  }

  // 初期化処理（プロパティの初期化・スプライトの作成等を行う）
  HzInputCommand.prototype.initialize = function (
    x,
    y,
    command,
    align,
    mode,
    switchNo
  ) {
    this._mode = mode; // モード。 1:ミスを許す 2:ミスを許さない
    this._switchNo = switchNo; // 結果を返すスイッチの番号
    this._sprites = []; // コマンド表示用スプライト
    this._command = command; // コマンドの内容
    this._cursorIdx = 0; // コマンドの入力位置
    this._penalty = 0; // コマンド入力ミス時のペナルティ

    var space = 80;
    if (align === "center") {
      x -= (command.length * space) / 2;
    } else if (align === "right") {
      x -= command.length * space;
    }
    x += space / 2;
    for (var i = 0; i < command.length; i++) {
      var c = command.charAt(i);
      switch (c) {
        case "2":
          this._sprites.push(createCursorSprite(2, x + space * i, y));
          break;
        case "4":
          this._sprites.push(createCursorSprite(4, x + space * i, y));
          break;
        case "6":
          this._sprites.push(createCursorSprite(6, x + space * i, y));
          break;
        case "8":
          this._sprites.push(createCursorSprite(8, x + space * i, y));
          break;
        case "z":
          this._sprites.push(createButtonSprite(1, x + space * i, y));
          break;
        case "x":
          this._sprites.push(createButtonSprite(2, x + space * i, y));
          break;
      }
    }

    this._sprites.forEach(function (elm) {
      SceneManager._scene._spriteset.addChild(elm);
    });
  };

  // 入力チェック
  HzInputCommand.prototype.checkInput = function () {
    if (Input.isTriggered("down")) {
      if (this._command.charAt(this._cursorIdx) === "2") {
        return 1;
      } else {
        return 2;
      }
    } else if (Input.isTriggered("left")) {
      if (this._command.charAt(this._cursorIdx) === "4") {
        return 1;
      } else {
        return 2;
      }
    } else if (Input.isTriggered("right")) {
      if (this._command.charAt(this._cursorIdx) === "6") {
        return 1;
      } else {
        return 2;
      }
    } else if (Input.isTriggered("up")) {
      if (this._command.charAt(this._cursorIdx) === "8") {
        return 1;
      } else {
        return 2;
      }
    } else if (Input.isTriggered("ok")) {
      if (this._command.charAt(this._cursorIdx) === "z") {
        return 1;
      } else {
        return 2;
      }
    } else if (Input.isTriggered("cancel")) {
      if (this._command.charAt(this._cursorIdx) === "x") {
        return 1;
      } else {
        return 2;
      }
    }
    return 0;
  };

  // 更新処理（終了時はfalseを返す）
  HzInputCommand.prototype.update = function () {
    // タイマーによる時間制限
    if ($gameTimer.isWorking() && $gameTimer._frames === 0) {
      // 終了（失敗）
      $gameSwitches.setValue(this._switchNo, false);
      return false;
    }
    // ミス時のペナルティ処理
    if (this._penalty > 0) {
      this._penalty--;
      return true;
    }
    // 入力チェック
    var result = this.checkInput();
    if (result === 1) {
      // 成功
      SceneManager._scene._spriteset.removeChild(
        this._sprites[this._cursorIdx]
      );
      if (successSe) {
        AudioManager.playSe({
          name: successSe,
          volume: 90,
          pitch: 100,
          pan: 0,
        });
      }
      this._cursorIdx++;
      if (this._cursorIdx >= this._command.length) {
        // 終了（成功）
        $gameSwitches.setValue(this._switchNo, true);
        return false;
      }
    } else if (result === 2) {
      // 失敗
      this._penalty = penaltyFrame; // nフレーム入力不可
      if (this._mode === 2) {
        // 終了（失敗）
        $gameSwitches.setValue(this._switchNo, false);
        return false;
      } else if (missSe) {
        // 失敗時SE再生
        AudioManager.playSe({ name: missSe, volume: 90, pitch: 100, pan: 0 });
      }
    }
    return true;
  };

  // 終了処理
  HzInputCommand.prototype.terminate = function () {
    this._sprites.forEach(function (sprite) {
      SceneManager._scene._spriteset.removeChild(sprite);
    });
    this._sprites = null;
  };

  //------------------------------------------------------------------------------
  // これより下は画像描画命令
  //------------------------------------------------------------------------------

  function drawCursorRight(ctx) {
    ctx.save();
    ctx.scale(0.75, 0.75);
    ctx.translate(-152.23133, -218.07933);
    ctx.beginPath();
    ctx.lineJoin = "round";
    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineCap = "round";
    ctx.lineWidth = 8.0;
    ctx.fillStyle = "rgb(80, 134, 220)";
    ctx.miterLimit = 4;
    ctx.globalAlpha = 1.0;
    ctx.moveTo(254.5365, 264.31992);
    ctx.lineTo(201.98025, 222.07933);
    ctx.lineTo(202.05065, 244.2141);
    ctx.lineTo(159.23133, 244.2141);
    ctx.lineTo(159.23133, 284.92375);
    ctx.lineTo(202.17945, 284.92375);
    ctx.lineTo(202.24985, 307.21652);
    ctx.lineTo(254.53648, 264.31992);
    ctx.fill();
    ctx.stroke();
    ctx.restore();
  }

  function drawButtonZ(ctx) {
    ctx.save();
    ctx.scale(0.75, 0.75);
    ctx.translate(-44, -345);
    ctx.beginPath();
    ctx.lineJoin = "round";
    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineCap = "round";
    ctx.lineWidth = 5.0;
    ctx.fillStyle = "rgb(230, 97, 137)";
    ctx.miterLimit = 4;
    ctx.globalAlpha = 1.0;
    ctx.arc(96.12484, 398.93362, 46.42857, 0.0, 6.28318531, 1);
    ctx.fill();
    ctx.stroke();
    ctx.beginPath();
    ctx.lineJoin = "round";
    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineCap = "round";
    ctx.lineWidth = 10.0;
    ctx.miterLimit = 4;
    ctx.globalAlpha = 1.0;
    ctx.moveTo(74.734076, 376.50069);
    ctx.lineTo(117.42568, 376.10107);
    ctx.lineTo(74.263246, 421.63148);
    ctx.lineTo(117.91456, 421.76555);
    ctx.stroke();
    ctx.restore();
  }

  function drawButtonX(ctx) {
    ctx.save();
    ctx.scale(0.75, 0.75);
    ctx.translate(-164, -346);
    ctx.beginPath();
    ctx.lineJoin = "round";
    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineCap = "round";
    ctx.lineWidth = 5.0;
    ctx.fillStyle = "rgb(232, 148, 53)";
    ctx.miterLimit = 4;
    ctx.globalAlpha = 1.0;
    ctx.arc(214.91956, 398.93362, 46.42857, 0.0, 6.28318531, 1);
    ctx.fill();
    ctx.stroke();
    ctx.save();
    ctx.transform(1.0, 0.0, 0.0, 1.0, -751.41761, 87.01326);
    ctx.beginPath();
    ctx.lineJoin = "round";
    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineCap = "round";
    ctx.lineWidth = 10.0;
    ctx.fillStyle = "rgb(244, 122, 188)";
    ctx.miterLimit = 4;
    ctx.globalAlpha = 1.0;
    ctx.moveTo(942.09352, 287.17165);
    ctx.lineTo(990.58084, 336.66912);
    ctx.fill();
    ctx.stroke();
    ctx.beginPath();
    ctx.lineJoin = "round";
    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineCap = "round";
    ctx.lineWidth = 10.0;
    ctx.fillStyle = "rgb(244, 122, 188)";
    ctx.miterLimit = 4;
    ctx.globalAlpha = 1.0;
    ctx.moveTo(990.58084, 287.17165);
    ctx.lineTo(942.09352, 336.66912);
    ctx.fill();
    ctx.stroke();
    ctx.restore();
    ctx.restore();
  }

  function drawButtonC(ctx) {
    ctx.save();
    ctx.scale(0.75, 0.75);
    ctx.translate(-280, -346);
    ctx.beginPath();
    ctx.lineJoin = "round";
    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineCap = "round";
    ctx.lineWidth = 5.0;
    ctx.fillStyle = "rgb(91, 230, 49)";
    ctx.miterLimit = 4;
    ctx.globalAlpha = 1.0;
    ctx.arc(333.71429, 398.93362, 46.42857, 0.0, 6.28318531, 1);
    ctx.fill();
    ctx.stroke();
    ctx.beginPath();
    ctx.lineJoin = "round";
    ctx.strokeStyle = "rgb(255, 255, 255)";
    ctx.lineCap = "round";
    ctx.lineWidth = 10.0;
    ctx.miterLimit = 4;
    ctx.globalAlpha = 1.0;
    ctx.moveTo(359.72685, 410.73759);
    ctx.bezierCurveTo(
      354.31555,
      422.41929,
      341.63155,
      428.90089,
      328.99435,
      426.442
    );
    ctx.bezierCurveTo(
      316.35715,
      423.98308,
      307.02885,
      413.21839,
      306.39255,
      400.35998
    );
    ctx.bezierCurveTo(
      305.75615,
      387.50153,
      313.97615,
      375.86844,
      326.30875,
      372.17383
    );
    ctx.bezierCurveTo(
      338.64135,
      368.47922,
      351.90345,
      373.67681,
      358.44165,
      384.7672
    );
    ctx.stroke();
    ctx.restore();
  }
})();
