//=============================================================================
// Plugin for RPG Maker MZ
// KeepHp1ByGuts.js
//=============================================================================
/*:
 * @target MZ
 * @plugindesc Actor may survive with 1 HP when one receives fatal damage.
 * @author Sasuke KANNAZUKI
 *
 * @param validAtHp1
 * @text Valid also HP 1?
 * @desc Whether to survive also when one's HP is 1.
 * @type boolean
 * @on Yes
 * @off No
 * @default true
 *
 * @param gutsRateFormula
 * @text Invoke Rate Formula
 * @desc Percentage of survive by guts. a:target, v[n]:variable
 * @type multiline_string
 * @default a.luk * 2
 *
 * @param performGutsText
 * @text Text For When Invokes Survive
 * @desc Display on battle log when it invokes survive. %1:one's name %2:the text "HP"
 * @type string
 * @default %1 narrowly survived with 1 HP!
 *
 * @help This plugin does not provide plugin commands.
 * This plugin runs under RPG Maker MZ.
 *
 * [Summary]
 * This plugin enables if an actor receives fatal damage,
 * the actor has a chance of surviving with 1 HP.
 *
 * [License]
 * this plugin is released under MIT license.
 * http://opensource.org/licenses/mit-license.php
 */

/*:ja
 * @target MZ
 * @plugindesc 致命的ダメージを受けてもたまにHP1で踏み止まる
 * @author 神無月サスケ
 *
 * @param validAtHp1
 * @text 残りHP1でも発動？
 * @desc 
 * @type boolean
 * @on 発動する
 * @off 発動しない
 * @default true
 *
 * @param gutsRateFormula
 * @text 発動確率式
 * @desc 残りHP1で踏み止まる確率を％で返す数式。aは対象者に、v[n]はn番目の変数に
 * @type multiline_string
 * @default a.luk * 2
 *
 * @param performGutsText
 * @text 発動時メッセージ
 * @desc 残りHP1で踏み止まった際に表示する文字列。%1はアクター名、%2はHP(略)の名称に置き換え
 * @type string
 * @default %1は辛うじて%2 1 で踏み止まった！
 *
 * @help このプラグインには、プラグインコマンドはありません。
 * このプラグインは、RPGツクールMZに対応しています。
 *
 * ■概要
 * このプラグインは、任意のアクターが現在のHP以上のダメージを受けた際、
 * 指定された確率でHP 1での踏み止まりが発動します。
 *
 * ■ライセンス表記
 * このプラグインは MIT ライセンスで配布されます。
 * ご自由にお使いください。
 * http://opensource.org/licenses/mit-license.php
 */

(() => {
  const pluginName = 'KeepHp1ByGuts';
  //
  // process parameters
  //
  const parameters = PluginManager.parameters(pluginName);
  const validAtHp1 = eval(parameters['validAtHp1'] || 'false');
  const gutsRateFormula = parameters['gutsRateFormula'] || 'a.luk * 2';
  const performGutsText = parameters['performGutsText'] ||
    '%1 narrowly survived with 1 HP!';

  //
  // functions of parameters
  //
  const canInvokeGuts = a => a.hp > 1 || a.hp === 1 && validAtHp1;

  const doesSuccessGuts = actor => {
    try {
      const a = actor;
      const v = $gameVariables._data;
      const chance = +eval(gutsRateFormula);
      return !isNaN(chance) && Math.randomInt(100) < chance;
    } catch (e) {
      console.error("Error: Guts Formula is invalid!!");
      return false;
    }
  };

  //
  // process damage
  //
  const _Game_Actor_gainHp = Game_Actor.prototype.gainHp;
  Game_Actor.prototype.gainHp = function(value) {
    let originValue = null;
    if (this.hp + value <= 0 && canInvokeGuts(this)) {
      if (doesSuccessGuts(this)) {
        originValue = value;
        value = validAtHp1 && this.hp === 1 ? 0 : -Math.max(this.hp - 1, 0);
      }
    }
    _Game_Actor_gainHp.call(this, value);
    if (originValue) {
      this._result.hpDamage = -originValue;
      this._result.invokeGuts = true;
    }
  };

  //
  // display battle log
  //
  Game_Battler.prototype.didInvokeGuts = function() {
    return !!this._result.invokeGuts;
  };

  Game_Battler.prototype.resetInvokeGuts = function() {
    this._result.invokeGuts = null;
  };

  const _Window_BattleLog_displayDamage =
   Window_BattleLog.prototype.displayDamage;
  Window_BattleLog.prototype.displayDamage = function(target) {
    _Window_BattleLog_displayDamage.call(this, target);
    this.displayGuts(target);
  };

  Window_BattleLog.prototype.displayGuts = function(target) {
    if (target.didInvokeGuts()) {
      target.resetInvokeGuts();
      this.push("addText", performGutsText.format(
        target.actor().name, TextManager.hpA)
      );
    }
  };

})();
