code:
//=============================================================================
// Yanfly Engine Plugins - Damage Extension - Critical Control
// YEP_X_CriticalControl.js
//=============================================================================

var Imported = Imported || {};
Imported.YEP_X_CriticalControl = true;

var Yanfly = Yanfly || {};
Yanfly.Crit = Yanfly.Crit || {};
Yanfly.Crit.version = 1.05;

//=============================================================================
 /*:
 * @plugindesc v1.05 (Requires YEP_DamageCore.js) Control over critical
 * hits have been added.
 * @author Yanfly Engine Plugins
 *
 * @param Critical Rate Formula
 * @desc This is the default critical hit rate formula.
 * Default: rate = user.cri * (1 - target.cev);
 * @default rate = user.cri * (1 - target.cev);
 *
 * @param Critical Multplier Formula
 * @desc This is the default formula used for a critical multiplier.
 * Default: value *= 3.0;
 * @default value *= 3.0 + bonus;
 *
 * @param Flat Critical Formula
 * @desc Add a little bonus to your critical hits with flat
 * increases in damage and/or healing.
 * @default value += ((baseDamage >= 0) ? 1 : -1) * 1.5 * user.luk + bonus;
 *
 * @help
 * ============================================================================
 * Introduction
 * ============================================================================
 *
 * This plugin requires YEP_DamageCore.
 * Make sure this plugin is located under YEP_DamageCore in the plugin list.
 *
 * This plugin allows you to modify the critical hit rate formula across a
 * global scale and for an individual skill/item scale.
 *
 * ============================================================================
 * Notetags
 * ============================================================================
 * You may use these notetags to adjust various factors for critical success
 * rates and critical damage adjustments.
 *
 * Skill and Item Notetags:
 *   <Critical Rate: x%>
 *   This sets the skill/item's critical hit rate to x%, ignoring any critical
 *   hit rate bonuses the user may have and ignoring any critical hit evasion
 *   bonuses the target may have.
 *   *Note: Using this tag sets the skill/item to enable Critical Hits.
 *
 *   <Critical Rate: x.y>
 *   This sets the skill/item's critical hit rate to the float x.y, ignoring
 *   any critical hit rate bonuses the user may have and ignoring any critical
 *   hit evasion bonuses the target may have.
 *   *Note: Using this tag sets the skill/item to enable Critical Hits.
 *
 *   <Critical Multiplier: x%>
 *   This sets the skill/item's critical damage multiplier as x% while still
 *   factoring in the user's critical damage multiplier bonuses.
 *   *Note: Using this tag sets the skill/item to enable Critical Hits.
 *
 *   <Critical Multiplier: x.y>
 *   This sets the skill/item's critical damage multiplier as x.y while still
 *   factoring in the user's critical damage multiplier bonuses.
 *   *Note: Using this tag sets the skill/item to enable Critical Hits.
 *
 *   <Flat Critical: x% stat>
 *   Increases the skill/item's flat critical bonus by x% of 'stat'. Replace
 *   'stat' with 'hp', 'mp', 'atk', 'def', 'mat', 'mdf', 'agi', or 'luk'. Using
 *   multiple instances of this notetag will override the previous.
 *
 * Actor, Class, Enemy, Weapon, Armor, and State Notetags:
 *   <Critical Multiplier: +x%>
 *   <Critical Multiplier: -x%>
 *   Alters the damage of a critical hit by x% for this actor, class, enemy,
 *   weapon, armor, or state. This is an additive trait.
 *
 *   <Flat Critical: +x>
 *   <Flat Critical: -x>
 *   Alters the damage of a critical hit by +x or -x for this actor, class,
 *   enemy, weapon, armor, or state. This is an additive trait.
 *
 *   <Certain Hit Critical Rate: +x%>
 *   <Certain Hit Critical Rate: -x%>
 *   Alters the critical hit rate chance of certain hit skills for the user by
 *   +x% or -x% if this notetag exists in the actor, class, enemy, weapon,
 *   armor, or state notetags. This is an additive trait.
 *
 *   <Physical Critical Rate: +x%>
 *   <Physical Critical Rate: -x%>
 *   Alters the physical critical rate chance of certain hit skills for the user
 *   by +x% or -x% if this notetag exists in the actor, class, enemy, weapon,
 *   armor, or state notetags. This is an additive trait.
 *
 *   <Magical Critical Rate: +x%>
 *   <Magical Critical Rate: -x%>
 *   Alters the magical critical rate chance of certain hit skills for the user
 *   by +x% or -x% if this notetag exists in the actor, class, enemy, weapon,
 *   armor, or state notetags. This is an additive trait.
 *
 * ============================================================================
 * Lunatic Mode - Critical Formulas
 * ============================================================================
 *
 * For those with a bit of JavaScript experience, you can create more in-depth
 * formulas for critical hits for individual skills.
 *
 * Skill and Item Notetags:
 *   <Critical Rate Formula>
 *   rate = user.cri + 0.2;
 *   rate -= 1 - target.cev;
 *   </Critical Rate Formula>
 *   This adjusts the critical hit success rate for the skill/item. You can use
 *   multiplie lines to write out the formula, and 'rate' will be the success
 *   rate used to determine the skill's critical success rate.
 *   *Note: Using this tag sets the skill/item to enable Critical Hits.
 *
 *   <Critical Multiplier Formula>
 *   value *= 3.0 + bonus;
 *   value *= $gameVariables.value(1) * 0.01;
 *   </Critical Multiplier Formula>
 *   This adjusts the critical multiplier formula for the skill/item. You can
 *   use multiple lines to write out the formula, and 'value' will be the amount
 *   of damage adjusted for the critical multiplier.
 *   *Note: Using this tag sets the skill/item to enable Critical Hits.
 *
 *   <Flat Critical Formula>
 *   value += 1.5 * user.luk + bonus;
 *   value -= 0.75 * target.luk;
 *   </Flat Critical Formula>
 *   This adjusts the flat critical formula for the skill/item if you wish for
 *   there to be one. This is primarily used for a flat increase in critical
 *   damage and is usually applied after all other applied multipliers.
 *   *Note: Remember to use a negative number for heals.
 *   *Note: Using this tag sets the skill/item to enable Critical Hits.
 *
 * ============================================================================
 * Yanfly Engine Plugins - Battle Engine Extension - Action Sequence Commands
 * ============================================================================
 *
 * If you have YEP_BattleEngineCore.js installed with this plugin located
 * underneath it in the Plugin Manager, you can make use of these extra
 * damage related action sequences.
 *
 *=============================================================================
 * CRITICAL MULTIPLIER: x%
 * CRITICAL MULTIPLIER: x.y
 * CRITICAL MULTIPLIER: VARIABLE x
 *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 * This changes the critical multiplier for the skill/item until the end of the
 * action sequence. This will only take effect if there is a critical hit. If
 * you use a variable, it is treated as a percentage.
 *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 * Usage Example: critical multiplier: 50%
 *                critical multiplier: 8.667
 *                critical multiplier: variable 3
 *=============================================================================
 *
 *=============================================================================
 * FLAT CRITICAL: +x
 * FLAT CRITICAL: -x
 * FLAT CRITICAL: VARIABLE x
 *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 * This changes the flat critical increase for the skill/item until the end of
 * the action sequence. This will only take effect if there is a critical hit.
 * This will automatically adjust for damage or healing.
 *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 * Usage Example: flat critical: +100
 *                flat critical: -250
 *                flat critical: variable 3
 *=============================================================================
 *
 *=============================================================================
 * FORCE CRITICAL
 * FORCE NO CRITICAL
 * NORMAL CRITICAL
 *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 * This forces the following action effects in the action sequence to either
 * always be a critical hit or not a critical hit ignoring all other factors.
 * Using 'normal critical' will reduce the following action effects to use the
 * regular critical hit rate calculation.
 *- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 * Usage Example: force critical
 *                force no critical
 *                normal critical
 *=============================================================================
 *
 * ============================================================================
 * Changelog
 * ============================================================================
 *
 * Version 1.05:
 * - Updated for RPG Maker MV version 1.5.0.
 *
 * Version 1.04:
 * - Bug fixed where the physical critical modifier replaced the magical
 * critical modifier. This should be fixed now.
 *
 * Version 1.03:
 * - Lunatic Mode fail safes added.
 *
 * Version 1.02:
 * - Updated for RPG Maker MV version 1.1.0.
 *
 * Version 1.01b:
 * - Fixed a bug regarding Lunatic Critical Hit Rates.
 * - Fixed a default formula that caused critical hits to heal unexpectedly.
 *
 * Version 1.00:
 * - Finished Plugin!
 */
//=============================================================================

if (Imported.YEP_DamageCore) {

//=============================================================================
// Parameter Variables
//=============================================================================

Yanfly.Parameters = PluginManager.parameters('YEP_X_CriticalControl');
Yanfly.Param = Yanfly.Param || {};

Yanfly.Param.critRate = String(Yanfly.Parameters['Critical Rate Formula']);
Yanfly.Param.critMult = String(Yanfly.Parameters['Critical Multplier Formula']);
Yanfly.Param.flatCrit = String(Yanfly.Parameters['Flat Critical Formula']);

//=============================================================================
// DataManager
//=============================================================================

Yanfly.Crit.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function() {
  if (!Yanfly.Crit.DataManager_isDatabaseLoaded.call(this)) return false;
  if (!Yanfly._loaded_YEP_X_CriticalControl) {

    this.processCritNotetags1($dataSkills);
    this.processCritNotetags1($dataItems);
    this.processCritNotetags2($dataActors);
    this.processCritNotetags2($dataClasses);
    this.processCritNotetags2($dataWeapons);
    this.processCritNotetags2($dataArmors);
    this.processCritNotetags2($dataStates);
    this.processCritNotetags2($dataEnemies);

    Yanfly._loaded_YEP_X_CriticalControl = true;
  }
  return true;
};

DataManager.processCritNotetags1 = function(group) {
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);

    var evalMode = 'none';
    obj.critRate = Yanfly.Param.critRate;
    obj.critMult = Yanfly.Param.critMult;
    obj.flatCrit = Yanfly.Param.flatCrit;

	continue;

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata[i];
      if (line.match(/<(?:CRITICAL RATE):[ ](\d+)([%％])>/i)) {
        var rate = parseFloat(RegExp.$1 * 0.01);
        obj.critRate = 'rate = ' + String(rate);
        obj.damage.critical = true;
      } else if (line.match(/<(?:CRITICAL RATE):[ ](\d+).(\d+)>/i)) {
        var rate = parseFloat(String(RegExp.$1) + '.' + String(RegExp.$2));
        obj.critRate = 'rate = ' + String(rate);
        obj.damage.critical = true;
      } else if (line.match(/<(?:CRITICAL MULTIPLIER):[ ](\d+)([%％])>/i)) {
        var rate = parseFloat(RegExp.$1 * 0.01);
        obj.critMult = 'value *= ' + String(rate) + ' + bonus;';
        obj.damage.critical = true;
      } else if (line.match(/<(?:CRITICAL MULTIPLIER):[ ](\d+).(\d+)>/i)) {
        var rate = parseFloat(String(RegExp.$1) + '.' + String(RegExp.$2));
        obj.critMult = 'value *= ' + String(rate) + ' + bonus;';
        obj.damage.critical = true;
      } else if (line.match(/<(?:FLAT CRITICAL):[ ](\d+)([%％])[ ](.*)>/i)) {
        var rate = parseFloat(RegExp.$1 * 0.01);
        var stat = String(RegExp.$3).toLowerCase();
        obj.flatCrit = 'value += ((baseDamage > 0) ? 1 : -1)';
        obj.flatCrit = obj.flatCrit + ' * ' + String(rate) + ' * user.';
        obj.flatCrit = obj.flatCrit + stat + ' + bonus;'
        obj.damage.critical = true;
      } else if (line.match(/<(?:CRITICAL RATE FORMULA)>/i)) {
        evalMode = 'critical rate';
        obj.critRate = '';
        obj.damage.critical = true;
      } else if (line.match(/<\/(?:CRITICAL RATE FORMULA)>/i)) {
        evalMode = 'none';
      } else if (line.match(/<(?:CRITICAL MULTIPLIER FORMULA)>/i)) {
        evalMode = 'critical multiplier';
        obj.critMult = '';
        obj.damage.critical = true;
      } else if (line.match(/<\/(?:CRITICAL MULTIPLIER FORMULA)>/i)) {
        evalMode = 'none';
      } else if (line.match(/<(?:FLAT CRITICAL FORMULA)>/i)) {
        evalMode = 'flat critical';
        obj.flatCrit = '';
        obj.damage.critical = true;
      } else if (line.match(/<\/(?:FLAT CRITICAL FORMULA)>/i)) {
        evalMode = 'none';
      } else {
        if (evalMode === 'critical rate') {
          obj.critRate = obj.critRate + line + '\n';
        } else if (evalMode === 'critical multiplier') {
          obj.critMult = obj.critMult + line + '\n';
        } else if (evalMode === 'flat critical') {
          obj.flatCrit = obj.flatCrit + line + '\n';
        }
      }
    }
  }
};

DataManager.processCritNotetags2 = function(group) {
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);

    obj.critMultBonus = 0.0;
    obj.flatCritBonus = 0;
    obj.physicalCritRateBonus = 0.0;
    obj.magicalCritRateBonus = 0.0;
    obj.certainCritRateBonus = 0.0;

	continue;

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata[i];
      if (line.match(/<(?:CRITICAL MULTIPLIER):[ ]([\+\-]\d+)([%％])>/i)) {
        obj.critMultBonus = parseFloat(RegExp.$1 * 0.01);
      } else if (line.match(/<(?:FLAT CRITICAL):[ ]([\+\-]\d+)>/i)) {
        obj.flatCritBonus = parseInt(RegExp.$1);
      } else if
      (line.match(/<(?:PHYSICAL CRITICAL RATE):[ ]([\+\-]\d+)([%％])>/i)) {
        obj.physicalCritRateBonus = parseFloat(RegExp.$1 * 0.01);
      } else if
      (line.match(/<(?:MAGICAL CRITICAL RATE):[ ]([\+\-]\d+)([%％])>/i)) {
        obj.magicalCritRateBonus = parseFloat(RegExp.$1 * 0.01);
      } else if
      (line.match(/<(?:CERTAIN HIT CRITICAL RATE):[ ]([\+\-]\d+)([%％])>/i)) {
        obj.certainCritRateBonus = parseFloat(RegExp.$1 * 0.01);
      }
    }
  }
};

//=============================================================================
// BattleManager
//=============================================================================

if (Imported.YEP_BattleEngineCore) {
Yanfly.Crit.BattleManager_processActionSequence =
  BattleManager.processActionSequence;
  BattleManager.processActionSequence = function(actionName, actionArgs) {
    // CRITICAL MULTIPLIER
    if (actionName === 'CRITICAL MULTIPLIER') {
      return this.actionCriticalMultiplier(actionArgs);
    }
    // FLAT CRITICAL
    if (actionName === 'FLAT CRITICAL') {
      return this.actionFlatCritical(actionArgs);
    }
    // FORCE CRITICAL
    if (actionName === 'FORCE CRITICAL') {
      return this.actionForceCritical();
    }
    // FORCE NO CRITICAL
    if (actionName === 'FORCE NO CRITICAL') {
      return this.actionForceNoCritical();
    }
    // NORMAL CRITICAL
    if (actionName === 'NORMAL CRITICAL') {
      return this.actionNormalCritical();
    }
    return Yanfly.Crit.BattleManager_processActionSequence.call(this,
      actionName, actionArgs);
  };
};

BattleManager.actionCriticalMultiplier = function(actionArgs) {
    if (actionArgs[0].match(/(?:VARIABLE|VAR)[ ](\d+)/i)) {
      var value = parseFloat($gameVariables.value(parseInt(RegExp.$1)) * 0.01);
    } else if (actionArgs[0].match(/(\d+)([%％])/i)) {
      var value = parseFloat(RegExp.$1 * 0.01);
    } else if (actionArgs[0].match(/(\d+).(\d+)/i)) {
      var value = parseFloat(String(RegExp.$1) + '.' + String(RegExp.$1));
    } else {
      return true;
    }
    $gameSystem._critMult = value;
    return true;
};

BattleManager.actionFlatCritical = function(actionArgs) {
    if (actionArgs[0].match(/(?:VARIABLE|VAR)[ ](\d+)/i)) {
      var value = parseInt($gameVariables.value(parseInt(RegExp.$1)));
    } else if (actionArgs[0].match(/([\+\-]\d+)/i)) {
      var value = parseInt(RegExp.$1);
    } else if (actionArgs[0].match(/(\d+)/i)) {
      var value = parseInt(RegExp.$1);
    } else {
      return true;
    }
    $gameSystem._flatCrit = value;
    return true;
};

BattleManager.actionForceCritical = function(actionArgs) {
    $gameSystem._forceCritical = true;
    $gameSystem._forceNoCritical = false;
    return true;
};

BattleManager.actionForceNoCritical = function(actionArgs) {
    $gameSystem._forceCritical = false;
    $gameSystem._forceNoCritical = true;
    return true;
};

BattleManager.actionNormalCritical = function(actionArgs) {
    $gameSystem._forceCritical = false;
    $gameSystem._forceNoCritical = false;
    return true;
};

//=============================================================================
// Game_System
//=============================================================================

Yanfly.Crit.Game_System_rDS = Game_System.prototype.resetDamageSettings;
Game_System.prototype.resetDamageSettings = function() {
    Yanfly.Crit.Game_System_rDS.call(this);
    this._critMult = 1.0;
    this._flatCrit = 0;
    this._forceCritical = false;
    this._forceNoCritical = false;
};

Game_System.prototype.criticalMultiplier = function() {
    if (this._critMult === undefined) this.resetDamageSettings();
    return this._critMult;
};

Game_System.prototype.flatCritical = function() {
    if (this._flatCrit === undefined) this.resetDamageSettings();
    return this._flatCrit;
};

Game_System.prototype.forceCritical = function() {
    if (this._forceCritical === undefined) this.resetDamageSettings();
    return this._forceCritical;
};

Game_System.prototype.forceNoCritical = function() {
    if (this._forceNoCritical === undefined) this.resetDamageSettings();
    return this._forceNoCritical;
};

//=============================================================================
// Game_Battler
//=============================================================================

Game_Battler.prototype.criticalMultiplierBonus = function() {
	return 0;
    let multiplier = 0.0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states()[i];
      if (state) multiplier += state.critMultBonus;
    }
    return Math.max(0, multiplier);
};

Game_Battler.prototype.flatCriticalBonus = function() {
	return 0;
    let value = 0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states()[i];
      if (state) value += state.flatCritBonus;
    }
    return value;
};

Game_Battler.prototype.certainCritRateBonus = function() {
	return 0;
    let multiplier = 0.0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states()[i];
      if (state) multiplier += state.certainCritRateBonus;
    }
    return Math.max(0, multiplier);
};

Game_Battler.prototype.physicalCritRateBonus = function() {
	return 0;
    let multiplier = 0.0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states()[i];
      if (state) multiplier += state.physicalCritRateBonus;
    }
    return Math.max(0, multiplier);
};

Game_Battler.prototype.magicalCritRateBonus = function() {
	return 0;
    let multiplier = 0.0;
    for (var i = 0; i < this.states().length; ++i) {
      var state = this.states()[i];
      if (state) multiplier += state.magicalCritRateBonus;
    }
    return Math.max(0, multiplier);
};

//=============================================================================
// Game_Actor
//=============================================================================

Game_Actor.prototype.criticalMultiplierBonus = function() {
	return Game_Battler.prototype.criticalMultiplierBonus.call(this);
    multiplier = Game_Battler.prototype.criticalMultiplierBonus.call(this);
    multiplier += this.actor().critMultBonus;
    multiplier += this.currentClass().critMultBonus;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips()[i];
      if (equip) multiplier += equip.critMultBonus;
    }
    return multiplier;
};

Game_Actor.prototype.flatCriticalBonus = function() {
	return Game_Battler.prototype.flatCriticalBonus.call(this);
    value = Game_Battler.prototype.flatCriticalBonus.call(this);
    value += this.actor().flatCritBonus;
    value += this.currentClass().flatCritBonus;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips()[i];
      if (equip) value += equip.flatCritBonus;
    }
    return value;
};

Game_Actor.prototype.certainCritRateBonus = function() {
	return Game_Battler.prototype.certainCritRateBonus.call(this);
    multiplier = Game_Battler.prototype.certainCritRateBonus.call(this);
    multiplier += this.actor().certainCritRateBonus;
    multiplier += this.currentClass().certainCritRateBonus;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips()[i];
      if (equip) multiplier += equip.certainCritRateBonus;
    }
    return multiplier;
};

Game_Actor.prototype.physicalCritRateBonus = function() {
	return Game_Battler.prototype.physicalCritRateBonus.call(this);
    multiplier = Game_Battler.prototype.physicalCritRateBonus.call(this);
    multiplier += this.actor().physicalCritRateBonus;
    multiplier += this.currentClass().physicalCritRateBonus;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips()[i];
      if (equip) multiplier += equip.physicalCritRateBonus;
    }
    return multiplier;
};

Game_Actor.prototype.magicalCritRateBonus = function() {
	return Game_Battler.prototype.magicalCritRateBonus.call(this);
    multiplier = Game_Battler.prototype.magicalCritRateBonus.call(this);
    multiplier += this.actor().magicalCritRateBonus;
    multiplier += this.currentClass().magicalCritRateBonus;
    for (var i = 0; i < this.equips().length; ++i) {
      var equip = this.equips()[i];
      if (equip) multiplier += equip.magicalCritRateBonus;
    }
    return multiplier;
};

//=============================================================================
// Game_Enemy
//=============================================================================

Game_Enemy.prototype.criticalMultiplierBonus = function() {
	return Game_Battler.prototype.criticalMultiplierBonus.call(this);
    multiplier = Game_Battler.prototype.criticalMultiplierBonus.call(this);
    multiplier += this.enemy().critMultBonus;
    return multiplier;
};

Game_Enemy.prototype.flatCriticalBonus = function() {
	return Game_Battler.prototype.flatCriticalBonus.call(this);
    value = Game_Battler.prototype.flatCriticalBonus.call(this);
    value += this.enemy().flatCritBonus;
    return value;
};

Game_Enemy.prototype.certainCritRateBonus = function() {
	return Game_Battler.prototype.certainCritRateBonus.call(this);
    multiplier = Game_Battler.prototype.certainCritRateBonus.call(this);
    multiplier += this.enemy().certainCritRateBonus;
    return multiplier;
};

Game_Enemy.prototype.physicalCritRateBonus = function() {
	return Game_Battler.prototype.physicalCritRateBonus.call(this);
    multiplier = Game_Battler.prototype.physicalCritRateBonus.call(this);
    multiplier += this.enemy().physicalCritRateBonus;
    return multiplier;
};

Game_Enemy.prototype.magicalCritRateBonus = function() {
	return Game_Battler.prototype.magicalCritRateBonus.call(this);
    multiplier = Game_Battler.prototype.magicalCritRateBonus.call(this);
    multiplier += this.enemy().magicalCritRateBonus;
    return multiplier;
};

//=============================================================================
// Game_Action
//=============================================================================

Game_Action.prototype.itemCri = function(target) {
    if (!this.item().damage.critical) return 0;
    var user = this.subject();
    var rate = this.applyItemCriticalRate(target);
    if (this.isCertainHit()) rate += user.certainCritRateBonus();
    if (this.isPhysical()) rate += user.physicalCritRateBonus();
    if (this.isMagical()) rate += user.magicalCritRateBonus();
    return rate;
};

Game_Action.prototype.applyItemCriticalRate = function(target) {
    var item = this.item();
    var a = this.subject();
    var b = target;
    var user = this.subject();
    var subject = this.subject();
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var rate = 0;
    var bonus = user.criticalMultiplierBonus();
    var code = item.critRate;
    try {
      eval(code);
    } catch (e) {
      Yanfly.Util.displayError(e, code, 'CRITICAL RATE FORMULA ERROR');
    }
    return rate;
};

Game_Action.prototype.applyCritical = function(value) {
    return value;
};

Yanfly.Crit.Game_Action_applyCritRate = Game_Action.prototype.applyCriticalRate;
Game_Action.prototype.applyCriticalRate = function(value, baseDamage, target) {
    value = Yanfly.Crit.Game_Action_applyCritRate.call(this, value, baseDamage,
        target);
    value = this.applyItemCriticalMult(value, baseDamage, target);
    value *= $gameSystem.criticalMultiplier();
    return value;
};

Yanfly.Crit.Game_Action_modifyCrit = Game_Action.prototype.modifyCritical;
Game_Action.prototype.modifyCritical = function(critical, baseDamage, target) {
    critical = Yanfly.Crit.Game_Action_modifyCrit.call(this, critical,
      baseDamage, target);
    if ($gameSystem.forceCritical()) critical = true;
    if ($gameSystem.forceNoCritical()) critical = false;
    return critical;
};

Game_Action.prototype.applyItemCriticalMult =
  function(value, baseDamage, target) {
    var item = this.item();
    var a = this.subject();
    var b = target;
    var user = this.subject();
    var subject = this.subject();
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var bonus = user.criticalMultiplierBonus();
    var code = item.critMult;
    try {
      eval(code);
    } catch (e) {
      Yanfly.Util.displayError(e, code, 'CRITICAL MULTIPLIER ERROR');
    }
    return value;
};

Yanfly.Crit.Game_Acion_applyFlatCrit = Game_Action.prototype.applyFlatCritical;
Game_Action.prototype.applyFlatCritical = function(value, baseDamage, target) {
    value = Yanfly.Crit.Game_Acion_applyFlatCrit.call(this, value,
        baseDamage, target);
    value = this.applyItemFlatCrit(value, baseDamage, target);
    if (baseDamage > 0) {
      value += $gameSystem.flatCritical();
    } else if (baseDamage < 0) {
      value -= $gameSystem.flatCritical();
    }
    return value;
};

Game_Action.prototype.applyItemFlatCrit = function(value, baseDamage, target) {
    var item = this.item();
    var a = this.subject();
    var b = target;
    var user = this.subject();
    var subject = this.subject();
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var bonus = user.flatCriticalBonus();
    var code = item.flatCrit;
    try {
      eval(code);
    } catch (e) {
      Yanfly.Util.displayError(e, code, 'CRITICAL FLAT BONUS ERROR');
    }
    return value;
};

//=============================================================================
// Utilities
//=============================================================================

Yanfly.Util = Yanfly.Util || {};

Yanfly.Util.displayError = function(e, code, message) {
  console.log(message);
  console.log(code || 'NON-EXISTENT');
  console.error(e);
  if (Utils.isNwjs() && Utils.isOptionValid('test')) {
    if (!require('nw.gui').Window.get().isDevToolsOpen()) {
      require('nw.gui').Window.get().showDevTools();
    }
  }
};

//=============================================================================
// End of File
//=============================================================================
};

license: unknown


code:
//=============================================================================
// Yanfly Engine Plugins - Equip Core Extension - Equip Requirements
// YEP_X_EquipRequirements.js
//=============================================================================

var Imported = Imported || {};
Imported.YEP_X_EquipRequirements = true;

var Yanfly = Yanfly || {};
Yanfly.EqReq = Yanfly.EqReq || {};
Yanfly.EqReq.version = 1.09;

//=============================================================================
 /*:
 * @plugindesc v1.09 (Requires YEP_EquipCore.js) Place requirements on
 * pieces of equipment before actors can use them!
 * @author Yanfly Engine Plugins
 *
 * @param ---General---
 * @default
 *
 * @param Requirement Window
 * @parent ---General---
 * @type boolean
 * @on YES
 * @off NO
 * @desc Add the requirement window for the Equip menu?
 * NO - false     YES - true
 * @default true
 *
 * @param Battle Test Ignore
 * @parent ---General---
 * @type boolean
 * @on YES
 * @off NO
 * @desc Ignore equip requirements during battle test?
 * NO - false     YES - true
 * @default true
 *
 * @param ---Window---
 * @default
 *
 * @param Requirement Title
 * @parent ---Window---
 * @desc The title used for equipment requirements.
 * @default Requirements
 *
 * @param No Requirement
 * @parent ---Window---
 * @desc The text used to display no requirements needed.
 * @default No Requirements!
 *
 * @param Positive Color
 * @parent ---Window---
 * @type number
 * @min 0
 * @max 31
 * @desc Text color used for positive color.
 * @default 24
 *
 * @param Negative Color
 * @parent ---Window---
 * @type number
 * @min 0
 * @max 31
 * @desc Text color used for positive color.
 * @default 25
 *
 * @param At Least Text
 * @parent ---Window---
 * @desc The text used to describe >= a parameter.
 * %1 - Parameter   %2 - Requirement   %3 - Compare
 * @default \c[16]Minimum %1:\c[0] %2 (%3)
 *
 * @param At Most Text
 * @parent ---Window---
 * @desc The text used to describe >= a parameter.
 * %1 - Parameter   %2 - Requirement   %3 - Compare
 * @default \c[16]Maximum %1:\c[0] %2 (%3)
 *
 * @param Draw Classes
 * @parent ---Window---
 * @type boolean
 * @on YES
 * @off NO
 * @desc Draw the classes required?
 * NO - false     YES - true
 * @default true
 *
 * @param Class Style
 * @parent ---Window---
 * @type select
 * @option Name Only
 * @value 0
 * @option Icon Only
 * @value 1
 * @option Icon and Name
 * @value 2
 * @desc If classes are drawn, what style to draw them in?
 * 0 - Name Only     1 - Icon Only     2 - Icon and Name
 * @default 0
 *
 * @param Class Text
 * @parent ---Window---
 * @desc Text displayed to say what class is allowed.
 * @default Class:
 *
 * @param Draw Skills
 * @parent ---Window---
 * @type boolean
 * @on YES
 * @off NO
 * @desc Draw the skills required?
 * NO - false     YES - true
 * @default true
 *
 * @param Skill Style
 * @parent ---Window---
 * @type select
 * @option Name Only
 * @value 0
 * @option Icon Only
 * @value 1
 * @option Icon and Name
 * @value 2
 * @desc If skills are drawn, what style to draw them in?
 * 0 - Name Only     1 - Icon Only     2 - Icon and Name
 * @default 2
 *
 * @param Skill Text
 * @parent ---Window---
 * @desc Text displayed to say what skills are needed.
 * @default Skill:
 *
 * @param Draw Switches
 * @parent ---Window---
 * @type boolean
 * @on YES
 * @off NO
 * @desc Draw the switch names required?
 * NO - false     YES - true
 * @default true
 *
 * @help
 * ============================================================================
 * Introduction
 * ============================================================================
 *
 * This plugin requires YEP_EquipCore.js to work.
 * Place this plugin beneath YEP_EquipCore.js in the Plugin Manager list.
 *
 * Place restrictions on when an actor can equip a weapon or piece of armor.
 * Set level requirements, stat requirements, switch requirements, and more.
 * This plugin will also provide a separate equipment requirement window to
 * show the player what is needed in order for gear to be equipped.
 *
 * ============================================================================
 * Notetags
 * ============================================================================
 *
 * You can use these notetags to implement requirements onto your weapons and
 * armors. These notetags will have to be set up in a certain way:
 *
 * Weapon and Armor Notetags:
 *
 *   <Equip Requirement>
 *    requirement
 *    requirement
 *   </Equip Requirement>
 *   - The main requirements will have to be placed in between these notetags.
 *   You can have a multitude of requirements for your weapons/armors. Replace
 *   'requirement' with any of the following below:
 *
 * Weapon and Armor Requiprements:
 *
 *   param > x
 *   param >= x
 *   param === x
 *   param <= x
 *   param < x
 *   - Replace 'param' with 'level', 'maxhp', 'maxmp', 'atk', 'def', 'mat',
 *   'mdf', 'agi', or 'luk'. This will make the piece of equipment require the
 *   actor's base parameter to be greater than (>), greater than or equal to
 *   (>=), equal to (===), less than or equal to (<=), or less than (<). This
 *   is NOT the value for the total parameter, only the base parameter. The
 *   base parameter is calculated by the user's class parameter value, any
 *   bonuses received by equipment and/or permanent stat increases.
 *
 *   class: x
 *   class: name
 *   - This will make the piece of equipment require the actor to be class x.
 *   If 'name' is used, priority will be given to the class with the highest ID
 *   in the database. Insert multiple of these requirements to add more
 *   classes. Having multiple classes will mean that the actor can be any of
 *   those classes to be able to equip the gear.
 *
 *   skill: x
 *   skill: name
 *   - This will make the piece of equipment require the actor to have learned
 *   skill x. If 'name' is used, priority will be given to the skill with the
 *   highest ID in the database. Insert multiple of these requirements to add
 *   more skills. Having multiple skills means the actor must have learned ALL
 *   of the skills to be able to equip the gear.
 *   *NOTE: The actor needs to have LEARNED the skill. This means that if you
 *   have added a skill to the actor's skill library through a trait, it will
 *   not count.
 *
 *   switch: x
 *   - This will require switch X to be on. If it isn't, the piece of equipment
 *   cannot be worn. Insert multiple of these to add more switches that are
 *   are required to be on.
 *
 *   unique only
 *   - This will make the piece of equipment to be "unique", rendering the
 *   actor to be unable to wear more than 1 of its kind.
 *
 * ============================================================================
 * Lunatic Mode - Custom Equip Requirement Conditions
 * ============================================================================
 *
 * For those with JavaScript proficiency, you can use these notetags to give
 * certain pieces of equipment a special requirement before it can be equipped.
 *
 * Weapon and Armor Notetags:
 *
 *   <Custom Equip Requirement Condition>
 *    if (user.name() === 'Harold') {
 *      condition = true;
 *    } else {
 *      condition = false;
 *    }
 *   </Custom Equip Requirement Condition>
 *   The 'condition' variable will determine whether or not the piece of
 *   equipment can be worn by the user. If 'condition' returns 'true', then the
 *   piece of equipment can be worn. If 'condition' returns 'false', then the
 *   piece of equipment can't be worn.
 *
 * ============================================================================
 * Lunatic Mode - Custom Equip Requirement Text
 * ============================================================================
 *
 * For those with JavaScript proficiency, you can use these notetags to alter
 * the text displayed in the Requirement Window.
 *
 * Weapon and Armor Notetags:
 *
 *   <Custom Equip Requirement Text>
 *    text = user.name() + ' has used this sword since young!\n';
 *    text += 'This is another line for the text!'
 *   </Custom Equip Requirement Text>
 *   For those who would like to write custom text for the Requirement Window,
 *   you can use this notetag. Text codes are allowed here. Use \n for line
 *   breaks. If you plan on using text codes, \i[4] would appear as \\i[4].
 *   Whatever value the 'text' variable has at the end will determine the text
 *   that will be displayed.
 *
 * ============================================================================
 * Changelog
 * ============================================================================
 *
 * Version 1.09:
 * - Bypass the isDevToolsOpen() error when bad code is inserted into a script
 * call or custom Lunatic Mode code segment due to updating to MV 1.6.1.
 *
 * Version 1.08:
 * - Updated for RPG Maker MV version 1.5.0.
 *
 * Version 1.07:
 * - Fixed a bug that caused unique equipment to not work properly.
 *
 * Version 1.06:
 * - Lunatic Mode fail safes added.
 *
 * Version 1.05a:
 * - Fixed a bug that caused unremovable items to be removed.
 * - Added anti-crash for non-existent actors.
 *
 * Version 1.04:
 * - Fixed a bug that caused stat comparisons to remain after cancel.
 *
 * Version 1.03:
 * - Notetags now allows spaces (whitespace) to be before the requirements.
 *
 * Version 1.02:
 * - Fixed a bug where Optimize was able to bypass equip requirements.
 *
 * Version 1.01:
 * - Updated for RPG Maker MV version 1.1.0.
 *
 * Version 1.00:
 * - Finished Plugin!
 */
//=============================================================================

if (Imported.YEP_EquipCore) {

//=============================================================================
// Parameter Variables
//=============================================================================

Yanfly.Parameters = PluginManager.parameters('YEP_X_EquipRequirements');
Yanfly.Param = Yanfly.Param || {};

Yanfly.Param.EqReqWindow = String(Yanfly.Parameters['Requirement Window']);
Yanfly.Param.EqReqWindow = eval(Yanfly.Param.EqReqWindow);
Yanfly.Param.EqReqBTest = String(Yanfly.Parameters['Battle Test Ignore']);
Yanfly.Param.EqReqBTest = eval(Yanfly.Param.EqReqBTest);

Yanfly.Param.EqReqTitle = String(Yanfly.Parameters['Requirement Title']);
Yanfly.Param.EqReqNone = String(Yanfly.Parameters['No Requirement']);
Yanfly.Param.EqReqPosColor = Number(Yanfly.Parameters['Positive Color']);
Yanfly.Param.EqReqNegColor = Number(Yanfly.Parameters['Negative Color']);
Yanfly.Param.EqReqAtLeast = String(Yanfly.Parameters['At Least Text']);
Yanfly.Param.EqReqAtMost = String(Yanfly.Parameters['At Most Text']);
Yanfly.Param.EqReqClasses = eval(String(Yanfly.Parameters['Draw Classes']));
Yanfly.Param.EqReqClassStyle = Number(Yanfly.Parameters['Class Style']);
Yanfly.Param.EqReqClassText = String(Yanfly.Parameters['Class Text']);
Yanfly.Param.EqReqSkills = eval(String(Yanfly.Parameters['Draw Skills']));
Yanfly.Param.EqReqSkillStyle = Number(Yanfly.Parameters['Skill Style']);
Yanfly.Param.EqReqSkillText = String(Yanfly.Parameters['Skill Text']);
Yanfly.Param.EqReqSwitches = eval(String(Yanfly.Parameters['Draw Switches']));

//=============================================================================
// DataManager
//=============================================================================

Yanfly.EqReq.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function() {
  if (!Yanfly.EqReq.DataManager_isDatabaseLoaded.call(this)) return false;
  if (!Yanfly._loaded_YEP_X_EquipRequirements) {
    this.processEqReqNotetagsC($dataClasses);
    this.processEqReqNotetagsS($dataSkills);
    this.processEqReqNotetags1($dataWeapons);
    this.processEqReqNotetags1($dataArmors);
    Yanfly._loaded_YEP_X_EquipRequirements = true;
  }
  return true;
};

DataManager.processEqReqNotetagsC = function(group) {
  if (Yanfly.ClassIdRef) return;
  Yanfly.ClassIdRef = {};
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    if (obj.name.length <= 0) continue;
    Yanfly.ClassIdRef[obj.name.toUpperCase()] = n;
  }
};

DataManager.processEqReqNotetagsS = function(group) {
  if (Yanfly.SkillIdRef) return;
  Yanfly.SkillIdRef = {};
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    if (obj.name.length <= 0) continue;
    Yanfly.SkillIdRef[obj.name.toUpperCase()] = n;
  }
};

DataManager.processEqReqNotetags1 = function(group) {
  var noteA1 = /<(?:EQUIP REQUIREMENT|EQUIP REQUIREMENTS|REQUIREMENT)>/i;
  var noteA2 = /<\/(?:EQUIP REQUIREMENT|EQUIP REQUIREMENTS|REQUIREMENT)>/i;
  var noteB1 = /<(?:CUSTOM EQUIP REQUIREMENT TEXT)>/i;
  var noteB2 = /<\/(?:CUSTOM EQUIP REQUIREMENT TEXT)>/i;
  var noteC1 = /<(?:CUSTOM EQUIP REQUIREMENT CONDITION)>/i;
  var noteC2 = /<\/(?:CUSTOM EQUIP REQUIREMENT CONDITION)>/i;
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);

    obj.equipRequirements = {
      atLeast: [0, 0, 0, 0, 0, 0, 0, 0, 0],
      atMost: [0, 0, 0, 0, 0, 0, 0, 0, 0],
      classes: [],
      skills: [],
      switches: [],
      unique: false
    };
    var evalMode = 'none';
    obj.customEquipReqText = '';
    obj.customEquipReqCondition = '';

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata[i];
      if (line.match(noteA1)) {
        evalMode = 'equip requirements';
      } else if (line.match(noteA2)) {
        evalMode = 'none';
      } else if (evalMode === 'equip requirements') {
        this.makeEquipRequirement(obj, line);
      } else if (line.match(noteB1)) {
        evalMode = 'custom equip requirement text';
      } else if (line.match(noteB2)) {
        evalMode = 'none';
      } else if (evalMode === 'custom equip requirement text') {
        obj.customEquipReqText = obj.customEquipReqText + line + '\n';
      } else if (line.match(noteC1)) {
        evalMode = 'custom equip requirement condition';
      } else if (line.match(noteC2)) {
        evalMode = 'none';
      } else if (evalMode === 'custom equip requirement condition') {
        obj.customEquipReqCondition = obj.customEquipReqCondition + line + '\n';
      }
    }
  }
};

DataManager.makeEquipRequirement = function(obj, line) {
  if (line.match(/UNIQUE ONLY/i)) {
    obj.equipRequirements['unique'] = true;
  } else if (line.match(/SWITCH:[ ](\d+)/i)) {
    obj.equipRequirements['switches'].push(parseInt(RegExp.$1));
  } else if (line.match(/CLASS:[ ](\d+)/i)) {
    obj.equipRequirements['classes'].push(parseInt(RegExp.$1));
  } else if (line.match(/CLASS:[ ](.*)/i)) {
    var name = String(RegExp.$1).toUpperCase();
    if (Yanfly.ClassIdRef[name]) {
      var id = Yanfly.ClassIdRef[name];
      obj.equipRequirements['classes'].push(id);
    }
  } else if (line.match(/SKILL:[ ](\d+)/i)) {
    obj.equipRequirements['skills'].push(parseInt(RegExp.$1));
  } else if (line.match(/SKILL:[ ](.*)/i)) {
    var name = String(RegExp.$1).toUpperCase();
    if (Yanfly.SkillIdRef[name]) {
      var id = Yanfly.SkillIdRef[name];
      obj.equipRequirements['skills'].push(id);
    }
  } else if (line.match(/(.*)[ ]>=[ ](\d+)/i)) {
    var stat = String(RegExp.$1).toUpperCase();
    stat = this.getEquipRequirementStatIndex(stat);
    var value = parseInt(RegExp.$2);
    obj.equipRequirements['atLeast'][stat] = value;
  } else if (line.match(/(.*)[ ]>[ ](\d+)/i)) {
    var stat = String(RegExp.$1).toUpperCase();
    stat = this.getEquipRequirementStatIndex(stat);
    var value = parseInt(RegExp.$2) + 1;
    obj.equipRequirements['atLeast'][stat] = value;
  } else if (line.match(/(.*)[ ]<=[ ](\d+)/i)) {
    var stat = String(RegExp.$1).toUpperCase();
    stat = this.getEquipRequirementStatIndex(stat);
    var value = parseInt(RegExp.$2);
    obj.equipRequirements['atMost'][stat] = value;
  } else if (line.match(/(.*)[ ]<[ ](\d+)/i)) {
    var stat = String(RegExp.$1).toUpperCase();
    stat = this.getEquipRequirementStatIndex(stat);
    var value = parseInt(RegExp.$2) + 1;
    obj.equipRequirements['atMost'][stat] = value;
  } else if (line.match(/(.*)[ ](?:=|==|===)[ ](\d+)/i)) {
    var stat = String(RegExp.$1).toUpperCase();
    stat = this.getEquipRequirementStatIndex(stat);
    var value = parseInt(RegExp.$2);
    obj.equipRequirements['atLeast'][stat] = value;
    obj.equipRequirements['atMost'][stat] = value;
  }
};

DataManager.getEquipRequirementStatIndex = function(stat) {
  stat = stat.trim();
  if (['MAX HP', 'MAXHP', 'HP'].contains(stat)) {
    return 0;
  } else if (['MAX MP', 'MAXMP', 'MP', 'MAX SP', 'MAXSP',
  'SP'].contains(stat)) {
    return 1;
  } else if (['ATK', 'STR'].contains(stat)) {
    return 2;
  } else if (['DEF'].contains(stat)) {
    return 3;
  } else if (['MAT', 'INT', 'SPI'].contains(stat)) {
    return 4;
  } else if (['MDF', 'RES'].contains(stat)) {
    return 5;
  } else if (['AGI', 'SPD'].contains(stat)) {
    return 6;
  } else if (['LUK'].contains(stat)) {
    return 7;
  } else if (['LEVEL', 'LV', 'LVL'].contains(stat)) {
    return 8;
  }
  return null;
};

//=============================================================================
// MainCode
//=============================================================================

Yanfly.EqReq.Game_BattlerBase_refresh = Game_BattlerBase.prototype.refresh;
Game_BattlerBase.prototype.refresh = function() {
    this._equipReq = undefined;
    Yanfly.EqReq.Game_BattlerBase_refresh.call(this);
};

Yanfly.EqReq.Game_BattlerBase_canEquip = Game_BattlerBase.prototype.canEquip;
Game_BattlerBase.prototype.canEquip = function(item) {
    var value = Yanfly.EqReq.Game_BattlerBase_canEquip.call(this, item);
    if (!value) return false;
    if (BattleManager.isBattleTest() && Yanfly.Param.EqReqBTest) return value;
    if (!$gameTemp._optimizing) {
      if (SceneManager._scene instanceof Scene_Equip) return value;
      if (this._equipReq !== undefined) return this._equipReq;
    }
    this._equipReq = this.meetAllEquipRequirements(item)
    return this._equipReq;
};

Game_BattlerBase.prototype.equips = function() {
    return [];
};

Game_BattlerBase.prototype.meetAllEquipRequirements = function(item) {
  if (!item.equipRequirements) {
    if (item.baseItemId) {
      item.equipRequirements = DataManager.getBaseItem(item).equipRequirements;
    } else {
      return true;
    }
  }
  if (!this.meetEquipParamRequirements(item)) return false;
   if (!this.meetEquipClassRequirements(item)) return false;
  if (!this.meetEquipSkillRequirements(item)) return false;
  if (!this.meetEquipSwitchRequirements(item)) return false;
  if (!this.meetEquipUniqueRequirements(item)) return false;
  if (!this.meetEquipEvalRequirements(item)) return false;
  return true;
};

Game_BattlerBase.prototype.meetEquipParamRequirements = function(item) {
  var requirements = item.equipRequirements;
  for (var i = 0; i < 9; ++i) {
    if (i === 8) {
      var param = this.level;
    } else {
      var param = this.paramBase(i) + this.paramPlus(i);
    }
    if (requirements['atLeast'][i] > 0) {
      if (requirements['atLeast'][i] > param) return false;
    }
    if (requirements['atMost'][i] > 0) {
      if (requirements['atMost'][i] < param) return false;
    }
  }
  return true;
};

Game_BattlerBase.prototype.meetEquipClassRequirements = function(item) {
  var requirements = item.equipRequirements;
  var classes = requirements['classes'];
  if (classes.length <= 0) return true;
  if (classes.contains(this.currentClass().id)) return true;
  return false;
};

Game_BattlerBase.prototype.meetEquipSkillRequirements = function(item) {
  var requirements = item.equipRequirements;
  var skills = requirements['skills'];
  var length = skills.length;
  if (length <= 0) return true;
  for (var i = 0; i < length; ++i) {
    var skillId = skills[i];
    if (!this.isLearnedSkill(skillId)) return false;
  }
  return true;
};

Game_BattlerBase.prototype.meetEquipSwitchRequirements = function(item) {
  var requirements = item.equipRequirements;
  var switches = requirements['switches'];
  var length = switches.length;
  for (var i = 0; i < length; ++i) {
    var sw = switches[i];
    if (!$gameSwitches.value(sw)) return false;
  }
  return true;
};

Game_BattlerBase.prototype.meetEquipUniqueRequirements = function(item) {
  if (!this.equips().contains(item)) return true;
  var requirements = item.equipRequirements;
  if (!requirements['unique']) return true;
  var length = this.equips().length;
  for (var i = 0; i < length; ++i) {
    var obj = this.equips()[i];
    if (!obj) continue;
    if (obj.id === item.id) return false;
    if (obj.baseItemId && item.baseItemId) {
      if (obj.baseItemId === item.baseItemId) return false;
    }
  }
  return true;
};

Game_BattlerBase.prototype.meetEquipEvalRequirements = function(item) {
  if (item.customEquipReqCondition === '') return true;
  var condition = true;
  var a = this;
  var user = this;
  var subject = this;
  var b = this;
  var target = this;
  var s = $gameSwitches._data;
  var v = $gameVariables._data;
  var code = item.customEquipReqCondition;
  try {
    eval(code);
  } catch (e) {
    Yanfly.Util.displayError(e, code, 'EQUIP REQUIREMENT EVAL ERROR');
  }
  return condition;
};

//=============================================================================
// Window_EquipSlot
//=============================================================================

Window_EquipSlot.prototype.setRequirementWindow = function(target) {
    this._requirementWindow = target;
    this.update();
};

Yanfly.EqReq.Window_EqSlot_updateHelp = Window_EquipSlot.prototype.updateHelp;
Window_EquipSlot.prototype.updateHelp = function() {
    Yanfly.EqReq.Window_EqSlot_updateHelp.call(this);
    if (SceneManager._scene instanceof Scene_Equip && this._requirementWindow) {
      this._requirementWindow.setItem(this.item());
    }
};

//=============================================================================
// Window_EquipItem
//=============================================================================

Yanfly.EqReq.Window_EquipItem_isEnabled = Window_EquipItem.prototype.isEnabled;
Window_EquipItem.prototype.isEnabled = function(item) {
    if (item !== null && this._actor) {
      if (!this._actor.meetAllEquipRequirements(item)) return false;
    }
    return Yanfly.EqReq.Window_EquipItem_isEnabled.call(this, item);
};

Window_EquipItem.prototype.setRequirementWindow = function(target) {
    this._requirementWindow = target;
    this.update();
};

Yanfly.EqReq.Window_EqItem_updateHelp = Window_EquipItem.prototype.updateHelp;
Window_EquipItem.prototype.updateHelp = function() {
    Yanfly.EqReq.Window_EqItem_updateHelp.call(this);
    if (SceneManager._scene instanceof Scene_Equip && this._requirementWindow) {
      this._requirementWindow.setItem(this.item());
    }
};

//=============================================================================
// Window_EquipRequirement
//=============================================================================

function Window_EquipRequirement() {
    this.initialize.apply(this, arguments);
}

Window_EquipRequirement.prototype = Object.create(Window_Base.prototype);
Window_EquipRequirement.prototype.constructor = Window_EquipRequirement;

Window_EquipRequirement.prototype.initialize = function(wx, wy, ww, wh) {
    Window_Base.prototype.initialize.call(this, wx, wy, ww, wh);
    this._actor = null;
    this._item = null;
    this.refresh();
};

Window_EquipRequirement.prototype.setActor = function(actor) {
    if (this._actor === actor) return;
    this._actor = actor;
    this.refresh();
};

Window_EquipRequirement.prototype.setItem = function(item) {
    if (this._item === item) return;
    this._item = item;
    this.refresh();
};

Window_EquipRequirement.prototype.itemRect = function(index) {
    var rect = new Rectangle();
    rect.width = this.contents.width;
    rect.height = this.lineHeight();
    rect.x = 0;
    rect.y = index * rect.height;
    return rect;
};

Window_EquipRequirement.prototype.drawDarkRect = function(dx, dy, dw, dh) {
    var color = this.gaugeBackColor();
    this.changePaintOpacity(false);
    this.contents.fillRect(dx + 1, dy + 1, dw - 2, dh - 2, color);
    this.changePaintOpacity(true);
};

Window_EquipRequirement.prototype.refresh = function() {
    this.contents.clear();
    this.checkActor();
    if (!this._actor) return;
    var length = Math.ceil(this.contents.height / this.lineHeight());
    for (var i = 0; i < length; ++i) {
      this.drawItem(i);
    }
    if (!this._item) return;
    var dy = this.drawRequirementTitle();
    if (this.drawRequirements(dy) === dy) this.drawNoRequirements(dy);
};

Window_EquipRequirement.prototype.checkActor = function() {
    if (this._actor) return;
    this.setActor(SceneManager._scene._actor);
};

Window_EquipRequirement.prototype.drawItem = function(index) {
    var rect = this.itemRect(index);
    this.drawDarkRect(rect.x, rect.y, rect.width, rect.height);
};

Window_EquipRequirement.prototype.drawRequirementTitle = function() {
    this.resetFontSettings();
    this.changeTextColor(this.systemColor());
    var ww = this.contents.width;
    this.drawText(Yanfly.Param.EqReqTitle, 0, 0, ww, 'center');
    return this.lineHeight();
};

Window_EquipRequirement.prototype.getRequirements = function() {
    var requirements = this._item.equipRequirements;
    if (!requirements) {
      if (this._item.baseItemId) {
        this._item.equipRequirements =
          DataManager.getBaseItem(this._item).equipRequirements;
        requirements = this._item.equipRequirements;
      }
    }
    return requirements;
};

Window_EquipRequirement.prototype.drawRequirements = function(dy) {
    if (!this.getRequirements()) return dy;
    if (Yanfly.Param.EqReqClasses) dy = this.drawClassRequirements(dy);
    dy = this.drawLevelRequirements(dy);
    dy = this.drawParamRequirements(dy);
    if (Yanfly.Param.EqReqSkills) dy = this.drawSkillRequirements(dy);
    if (Yanfly.Param.EqReqSwitches) dy = this.drawSwitchRequirements(dy);
    dy = this.drawCustomText(dy);
    return dy;
};

Window_EquipRequirement.prototype.drawClassRequirements = function(dy) {
    if (this._item.equipRequirements['classes'].length <= 0) return dy;
    var style = Yanfly.Param.EqReqClassStyle;
    var classes = this._item.equipRequirements['classes'];
    var classTx = Yanfly.Param.EqReqClassText;
    var currentClassId = this._actor.currentClass().id;
    var length = classes.length;
    var ww = this.contents.width - this.textPadding();
    this.resetFontSettings();
    this.changePaintOpacity(true);
    this.changeTextColor(this.systemColor());
    this.drawText(classTx, this.textPadding(), dy, ww);
    var dx = this.textWidth(classTx) + this.textPadding();
    ww -= dx;
    if (style === 1 && Imported.YEP_ClassChangeCore) {
      for (var i = 0; i < length; ++i) {
        if (dx + Window_Base._iconHeight > this.contents.width) {
          dy += this.lineHeight();
          dx = this.textWidth(classTx) + this.textPadding();
        }
        var classId = classes[i];
        this.changePaintOpacity(classId === currentClassId);
        var iconIndex = $dataClasses[classId].iconIndex;
        this.drawIcon(iconIndex, dx, dy + 2);
        dx += Window_Base._iconHeight;
      }
      dy += this.lineHeight();
    } else if (style === 2 && Imported.YEP_ClassChangeCore) {
      for (var i = 0; i < length; ++i) {
        var classId = classes[i];
        this.changePaintOpacity(classId === currentClassId);
        var item = $dataClasses[classId];
        this.drawItemName(item, dx, dy, ww);
        dy += this.lineHeight();
      }
    } else {
      this.changeTextColor(this.normalColor());
      for (var i = 0; i < length; ++i) {
        var classId = classes[i];
        this.changePaintOpacity(classId === currentClassId);
        var name = $dataClasses[classId].name;
        this.drawText(name, dx, dy, ww);
        dy += this.lineHeight();
      }
    }
    return dy;
};

Window_EquipRequirement.prototype.drawLevelRequirements = function(dy) {
    this.resetFontSettings();
    this.changePaintOpacity(true);
    var wx = this.textPadding();
    if (this._item.equipRequirements['atLeast'][8] > 0) {
      var fmt = Yanfly.Param.EqReqAtLeast;
      var value1 = this._item.equipRequirements['atLeast'][8];
      if (this._actor.level >= value1) {
        var value2 = '\\c[' + Yanfly.Param.EqReqPosColor + ']';
      } else {
        var value2 = '\\c[' + Yanfly.Param.EqReqNegColor + ']';
      }
      value2 += Yanfly.Util.toGroup(this._actor.level) + '\\c[0]';
      value1 = Yanfly.Util.toGroup(value1);
      var text = fmt.format(TextManager.level, value1, value2);
      this.drawTextEx(text, wx, dy);
      dy += this.lineHeight();
    }
    if (this._item.equipRequirements['atMost'][8] > 0) {
      var fmt = Yanfly.Param.EqReqAtMost;
      var value1 = this._item.equipRequirements['atMost'][8];
      if (this._actor.level <= value1) {
        var value2 = '\\c[' + Yanfly.Param.EqReqPosColor + ']';
      } else {
        var value2 = '\\c[' + Yanfly.Param.EqReqNegColor + ']';
      }
      value2 += Yanfly.Util.toGroup(this._actor.level) + '\\c[0]';
      value1 = Yanfly.Util.toGroup(value1);
      var text = fmt.format(TextManager.level, value1, value2);
      this.drawTextEx(text, wx, dy);
      dy += this.lineHeight();
    }
    return dy;
};

Window_EquipRequirement.prototype.drawParamRequirements = function(dy) {
    this.resetFontSettings();
    this.changePaintOpacity(true);
    var wx = this.textPadding();
    for (var i = 0; i < 8; ++i) {
      if (this._item.equipRequirements['atLeast'][i] > 0) {
        var fmt = Yanfly.Param.EqReqAtLeast;
        var value1 = this._item.equipRequirements['atLeast'][i];
        var valueA = this._actor.paramBase(i) + this._actor.paramPlus(i);
        if (valueA >= value1) {
          var value2 = '\\c[' + Yanfly.Param.EqReqPosColor + ']';
        } else {
          var value2 = '\\c[' + Yanfly.Param.EqReqNegColor + ']';
        }
        value2 += Yanfly.Util.toGroup(valueA) + '\\c[0]';
        value1 = Yanfly.Util.toGroup(value1);
        var text = fmt.format(TextManager.param(i), value1, value2);
        this.drawTextEx(text, wx, dy);
        dy += this.lineHeight();
      }
      if (this._item.equipRequirements['atMost'][i] > 0) {
        var fmt = Yanfly.Param.EqReqAtMost;
        var value1 = this._item.equipRequirements['atMost'][i];
        if (valueA <= value1) {
          var value2 = '\\c[' + Yanfly.Param.EqReqPosColor + ']';
        } else {
          var value2 = '\\c[' + Yanfly.Param.EqReqNegColor + ']';
        }
        value2 += Yanfly.Util.toGroup(valueA) + '\\c[0]';
        value1 = Yanfly.Util.toGroup(value1);
        var text = fmt.format(TextManager.param(i), value1, value2);
        this.drawTextEx(text, wx, dy);
        dy += this.lineHeight();
      }
    }
    return dy;
};

Window_EquipRequirement.prototype.drawSkillRequirements = function(dy) {
    if (this._item.equipRequirements['skills'].length <= 0) return dy;
    var style = Yanfly.Param.EqReqSkillStyle;
    var skills = this._item.equipRequirements['skills'];
    var skillTx = Yanfly.Param.EqReqSkillText;
    var length = skills.length;
    var ww = this.contents.width - this.textPadding();
    this.resetFontSettings();
    this.changePaintOpacity(true);
    this.changeTextColor(this.systemColor());
    this.drawText(skillTx, this.textPadding(), dy, ww);
    var dx = this.textWidth(skillTx) + this.textPadding();
    ww -= dx;
    if (style === 1) {
      for (var i = 0; i < length; ++i) {
        if (dx + Window_Base._iconHeight > this.contents.width) {
          dy += this.lineHeight();
          dx = this.textWidth(skillTx) + this.textPadding();
        }
        var skillId = skills[i];
        this.changePaintOpacity(this._actor.isLearnedSkill(skillId));
        var iconIndex = $dataSkills[skillId].iconIndex;
        this.drawIcon(iconIndex, dx, dy + 2);
        dx += Window_Base._iconHeight;
      }
      dy += this.lineHeight();
    } else if (style === 2) {
      for (var i = 0; i < length; ++i) {
        var skillId = skills[i];
        this.changePaintOpacity(this._actor.isLearnedSkill(skillId));
        var item = $dataSkills[skillId];
        this.drawItemName(item, dx, dy, ww);
        dy += this.lineHeight();
      }
    } else {
      this.changeTextColor(this.normalColor());
      for (var i = 0; i < length; ++i) {
        var skillId = skills[i];
        this.changePaintOpacity(this._actor.isLearnedSkill(skillId));
        var name = $dataSkills[skillId].name;
        this.drawText(name, dx, dy, ww);
        dy += this.lineHeight();
      }
    }
    return dy;
};

Window_EquipRequirement.prototype.drawSwitchRequirements = function(dy) {
    this.resetFontSettings();
    this.changePaintOpacity(true);
    var switches = this._item.equipRequirements['switches'];
    var length = switches.length;
    for (var i = 0; i < length; ++i) {
      var sw = switches[i];
      var name = $dataSystem.switches[sw];
      name = name.replace(/<<(.*?)>>/i, '');
      this.changePaintOpacity($gameSwitches.value(sw));
      this.drawTextEx(name, this.textPadding(), dy);
      dy += this.lineHeight();
    }
    this.changePaintOpacity(true)
    return dy;
};

Window_EquipRequirement.prototype.drawCustomText = function(dy) {
    if (this._item.customEquipReqText === '') return dy;
    this.resetFontSettings();
    this.changePaintOpacity(true);
    var text = '';
    var a = this._actor;
    var user = this._actor;
    var subject = this._actor;
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    var code = this._item.customEquipReqText;
    try {
      eval(code);
    } catch (e) {
      Yanfly.Util.displayError(e, code, 'EQUIP CUSTOM TEXT ERROR');
    }
    this.drawTextEx(text, this.textPadding(), dy);
    return dy + this.lineHeight();
};

Window_EquipRequirement.prototype.drawNoRequirements = function(dy) {
    this.resetFontSettings();
    this.changePaintOpacity(true);
    this.changeTextColor(this.normalColor());
    var ww = this.contents.width;
    dy += this.lineHeight();
    this.drawText(Yanfly.Param.EqReqNone, 0, dy, ww, 'center');
    return dy;
};

//=============================================================================
// Scene_Equip
//=============================================================================

Yanfly.EqReq.Scene_Equip_createCompareWindow =
    Scene_Equip.prototype.createCompareWindow;
Scene_Equip.prototype.createCompareWindow = function() {
    Yanfly.EqReq.Scene_Equip_createCompareWindow.call(this);
    if (Yanfly.Param.EqReqWindow) this.createRequirementWindow();
};

Yanfly.EqReq.Scene_Equip_refreshActor =
    Scene_Equip.prototype.refreshActor;
Scene_Equip.prototype.refreshActor = function() {
    Yanfly.EqReq.Scene_Equip_refreshActor.call(this);
    if (this._requirementWindow) this._requirementWindow.setActor(this.actor());
};

Yanfly.EqReq.Scene_Equip_commandOptimize =
    Scene_Equip.prototype.commandOptimize;
Scene_Equip.prototype.commandOptimize = function() {
    $gameTemp._optimizing = true;
    Yanfly.EqReq.Scene_Equip_commandOptimize.call(this);
    $gameTemp._optimizing = false;
    if (this._requirementWindow) this._requirementWindow.refresh();
};

Yanfly.EqReq.Scene_Equip_commandClear = Scene_Equip.prototype.commandClear;
Scene_Equip.prototype.commandClear = function() {
    Yanfly.EqReq.Scene_Equip_commandClear.call(this);
    if (this._requirementWindow) this._requirementWindow.refresh();
};

Scene_Equip.prototype.createRequirementWindow = function() {
    var wx = this._itemWindow.width;
    var wy = this._itemWindow.y;
    var ww = Graphics.boxWidth - wx;
    var wh = this._itemWindow.height;
    this._requirementWindow = new Window_EquipRequirement(wx, wy, ww, wh);
    this._slotWindow.setRequirementWindow(this._requirementWindow);
    this._itemWindow.setRequirementWindow(this._requirementWindow);
    this.addWindow(this._requirementWindow);
    this._lowerRightWindows.push(this._requirementWindow);
};

Yanfly.EqReq.Scene_Equip_onSlotCancel = Scene_Equip.prototype.onSlotCancel;
Scene_Equip.prototype.onSlotCancel = function() {
    Yanfly.EqReq.Scene_Equip_onSlotCancel.call(this);
    if (this._requirementWindow) this._requirementWindow.setItem(null);
};

//=============================================================================
// Utilities
//=============================================================================

Yanfly.Util = Yanfly.Util || {};

if (!Yanfly.Util.toGroup) {
    Yanfly.Util.toGroup = function(inVal) {
        return inVal;
    }
};

Yanfly.Util.displayError = function(e, code, message) {
  console.log(message);
  console.log(code || 'NON-EXISTENT');
  console.error(e);
  if (Utils.RPGMAKER_VERSION && Utils.RPGMAKER_VERSION >= "1.6.0") return;
  if (Utils.isNwjs() && Utils.isOptionValid('test')) {
    if (!require('nw.gui').Window.get().isDevToolsOpen()) {
      require('nw.gui').Window.get().showDevTools();
    }
  }
};

//=============================================================================
// End of File
//=============================================================================
};


code:
//=============================================================================
// Yanfly Engine Plugins - Buffs & States Extension - Extended Damage Over Time
// YEP_X_ExtDoT.js
//=============================================================================

if (Imported.YEP_BattleEngineCore && Imported.YEP_BuffsStatesCore) {

var Imported = Imported || {};
Imported.YEP_X_ExtDoT = true;

var Yanfly = Yanfly || {};
Yanfly.EDoT = Yanfly.EDoT || {};
Yanfly.EDoT.version = 1.03;

//=============================================================================
 /*:
 * @plugindesc v1.03 (Req YEP_BattleEngineCore & YEP_BuffsStatesCore)
 * Create custom DoT formulas and effects with ease.
 * @author Yanfly Engine Plugins + Tigress Collaboration
 *
 * @param ---Defaults---
 * @default
 *
 * @param Regen Animation
 * @parent ---Defaults---
 * @type animation
 * @desc When creating a regen state, this will be the default animation.
 * Leave at 0 to play no animation.
 * @default 46
 *
 * @param DoT Animation
 * @type animation
 * @desc When creating a DoT state, this will be the default animation.
 * Leave at 0 to play no animation.
 * @default 59
 *
 * @param Default Variance
 * @type number
 * @desc This is the default variance value for Extended DoT formulas.
 * Leave at 0 for no variance.
 * @default 20
 *
 * @param Default Element
 * @type number
 * @desc This is the default element used for Extended DoT formulas.
 * Leave at 0 for no element.
 * @default 0
 *
 * @help
 * ============================================================================
 * Introduction
 * ============================================================================
 *
 * This plugin requires both YEP_BattleEngineCore && YEP_BuffsStatesCore. Make
 * sure this plugin is located under both YEP_BattleEngineCore and
 * YEP_BuffsStatesCore in the plugin list.
 *
 * RPG Maker MV does not provide the ability to utilize custom formulas for any
 * damage or healing over time state effects. This plugin, through aid of
 * Yanfly's Buffs & States Core, will allow usage for formulas to create custom
 * damage or healing over time values, animations to go with them, variance
 * control, and elemental rate aspects.
 *
 * This is a collaboration plugin by Tigress and Yanfly to ensure compatibility
 * with the Yanfly Engine Plugins library.
 *
 * ============================================================================
 * Notetags
 * ============================================================================
 *
 * Insert the following notetags into your states to achieve their respective
 * damage over time effects.
 *
 * State Notetags:
 *
 *    ---
 *
 *   <Regen Animation: x>
 *   <DoT Animation: x>
 *   - This will make the state play animation x for regen/damage over time if
 *   there is any healing or damage dealt through the extended damage over time
 *   formulas used below.
 *
 *   Examples:
 *     <Regen Animation: 41>  // Play animation 41 when regen occurs
 *     <DoT Animation: 59>    // Play animation 59 when DoT occurs
 *
 *   * NOTE: Animations will only occur if it is used with one of the below
 *   formulas and the formula does not yield a 0 value.
 *
 *   ---
 *
 *   <Regen Formula: x>
 *   - This will make the affected battler regenerate x HP each turn. You can
 *   use either a formula or a numeric value in place of 'x'.
 *
 *   Examples:
 *     <Regen Formula: 100>        // Regen 100 HP exactly each turn
 *     <Regen Formula: a.mdf * 2>  // Regen HP equal to the origin's MDF
 *
 *   ---
 *
 *   <DoT Formula: x>
 *   - This will make the affected battler take x HP damage each turn. You can
 *   use either a formula or a numeric value in place of 'x'.
 *
 *   Examples:
 *     <DoT Formula: 100>        // Damage 100 HP exactly each turn
 *     <DoT Formula: a.mat * 2>  // Damage HP equal to the origin's MAT
 *
 *   ---
 *
 *   <Regen Element: x>
 *   <DoT Element: x>
 *   - This will make the healing/damage done by this state to be element 'x'.
 *   This will take into consideration the target's elemental rates towards
 *   that element. If this is left blank, there will be no element modifiers.
 *
 *   Examples:
 *     <Regen Element: 4>   // Healing done will be affected by element 4.
 *     <DoT Element: 5>     // Damage done will be affected by element 5.
 *
 *   ---
 *
 *   <Regen Variance: x%>
 *   <DoT Variance: x%>
 *   - The amount of variance you want the DoT effect to have. Replace x with
 *   a percentage value. If this is left blank, the settings in the plugin
 *   parameters will be used by default.
 *
 *   Examples:
 *     <Regen Variance: 10%>   // Regen will have 10% healing variance
 *     <DoT Variance: 20%>     // DoT will have 20% damage variance
 *
 * ============================================================================
 * Lunatic Mode - Custom DoT Formula
 * ============================================================================
 *
 * For those with JavaScript experience and would like to create more complex
 * formulas for custom damage/healing over time states, you can use these
 * following notetags below.
 *
 * State Notetags:
 *
 *   ---
 *
 *   <Custom DoT Formula>
 *    if (a.isActor()) {
 *      value = a.level * 100;
 *      variance = 20;
 *      element = 1;
 *    } else {
 *      value = a.hp / 50;
 *      variance = 10;
 *      element = 2;
 *    }
 *   </Custom DoT Formula>
 *   - The damage to be dealt will be equal to the 'value'. This is the base
 *   damage dealt primarily by the formula alone. The finalized damage to be
 *   dealt will be affected by the 'variance' and 'element' values, which can
 *   be changed within this formula, too. If 'variance' or 'element' are left
 *   out of the formula, they will take on their default values. If you are
 *   going to make a healing effect, use the notetag below this one.
 *
 *   ---
 *
 *   <Custom Regen Formula>
 *    if (a.isActor()) {
 *      value = a.level * 8;
 *      variance = 15;
 *      element = 3;
 *    } else {
 *      value = a.hp / 2;
 *      variance = 5;
 *      element = 4;
 *    }
 *   </Custom Regen Formula>
 *   - The healing to be dealt will be equal to the 'value'. This is the base
 *   heal dealt primarily by the formula alone. The finalized healing to be
 *   dealt will be affected by the 'variance' and 'element' values, which can
 *   be changed within this formula, too. If 'variance' or 'element' are left
 *   out of the formula, they will take on their default values. If you are
 *   going to make a damaging effect, use the notetag above this one.
 *
 * ============================================================================
 * Changelog
 * ============================================================================
 *
 * Version 1.03:
 * - Updated for RPG Maker MV version 1.6.1.
 *
 * Version 1.02:
 * - Made DoT effects battle only to prevent errors and crashes.
 *
 * Version 1.01:
 * - Updated for RPG Maker MV version 1.5.0.
 *
 * Version 1.00:
 * - Finished Plugin!
 */
//=============================================================================

//=============================================================================
// Parameter Variables
//=============================================================================

Yanfly.Parameters = PluginManager.parameters('YEP_X_ExtDoT');
Yanfly.Param = Yanfly.Param || {};

Yanfly.Param.EDoTRegenAni = Number(Yanfly.Parameters['Regen Animation']);
Yanfly.Param.EDoTDamageAni = Number(Yanfly.Parameters['DoT Animation']);
Yanfly.Param.EDoTDefVariance = Number(Yanfly.Parameters['Default Variance']);
Yanfly.Param.EDoTDefElement = Number(Yanfly.Parameters['Default Element']);

//=============================================================================
// DataManager
// ----------------------------------------------------------------------------
// Notetags added by Yanfly
//=============================================================================

Yanfly.EDoT.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function() {
  if (!Yanfly.EDoT.DataManager_isDatabaseLoaded.call(this)) return false;

  if (!Yanfly._loaded_YEP_X_ExtDoT) {
    this.processEDoTNotetags1($dataStates);
    Yanfly._loaded_YEP_X_ExtDoT = true;
  }

  return true;
};

DataManager.processEDoTNotetags1 = function(group) {
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);

    obj.dotAnimation = 0;
    obj.dotElement = Yanfly.Param.EDoTDefElement;
    obj.dotVariance = Yanfly.Param.EDoTDefVariance;
    var evalMode = 'none';
    obj.dotFormula = '';

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata[i];
      if (line.match(/<(?:REGEN|DOT) ANIMATION:[ ](\d+)>/i)) {
        obj.dotAnimation = parseInt(RegExp.$1);
      } else if (line.match(/<(?:REGEN|REGENERATE) FORMULA:[ ](.*)>/i)) {
        var formula = String(RegExp.$1);
        obj.dotFormula = 'value = Math.max(0, ' + formula + ');\n';
        obj.dotFormula += 'healing = true;'
        if (obj.dotAnimation === 0) {
          obj.dotAnimation = Yanfly.Param.EDoTRegenAni;
        }
      } else if (line.match(/<(?:DOT|DAMAGE OVER TIME) FORMULA:[ ](.*)>/i)) {
        var formula = String(RegExp.$1);
        obj.dotFormula = 'value = Math.max(0, ' + formula + ');\n';
        obj.dotFormula += 'healing = false;'
        if (obj.dotAnimation === 0) {
          obj.dotAnimation = Yanfly.Param.EDoTDamageAni;
        }
      } else if (line.match(/<(?:REGEN|DOT) VARIANCE:[ ](\d+)([%％])>/i)) {
        obj.dotVariance = parseInt(RegExp.$1);
      } else if (line.match(/<(?:REGEN|DOT) ELEMENT:[ ](\d+)>/i)) {
        obj.dotElement = parseInt(RegExp.$1);
      } else if (line.match(/<(?:CUSTOM REGEN FORMULA)>/i)) {
        evalMode = 'custom dot formula';
      } else if (line.match(/<\/(?:CUSTOM REGEN FORMULA)>/i)) {
        obj.dotFormula += 'healing = true';
        evalMode = 'none';
      } else if (line.match(/<(?:CUSTOM DOT FORMULA)>/i)) {
        evalMode = 'custom dot formula';
      } else if (line.match(/<\/(?:CUSTOM DOT FORMULA)>/i)) {
        obj.dotFormula += 'healing = false';
        evalMode = 'none';
      } else if (evalMode === 'custom dot formula') {
        obj.dotFormula += line + '\n';
      }
    }
  }
};

//=============================================================================
// Game_Battler
// ----------------------------------------------------------------------------
// Compatibility with YEP_BuffsStatesCore
//=============================================================================

Yanfly.EDoT.Game_Battler_regenerateAll = Game_Battler.prototype.regenerateAll;
Game_Battler.prototype.regenerateAll = function() {
  if (this.isAlive() && $gameParty.inBattle()) {
    this.processDamageOverTimeStates();
  }
  Yanfly.EDoT.Game_Battler_regenerateAll.call(this);
};

Game_Battler.prototype.processDamageOverTimeStates = function() {
  if (!$gameParty.inBattle()) return;
  var result = JsonEx.makeDeepCopy(this._result);
  var states = this.states();
  while (states.length > 0) {
    var state = states.shift();
    if (state) {
      this.processDamageOverTimeStateEffect(state);
    }
  }
  this._result = result;
};

Game_Battler.prototype.processDamageOverTimeStateEffect = function(state) {
  var stateId = state.id;
  var state = $dataStates[stateId];
  if (!state) return;
  if (state.dotFormula === '') return;
  var a = this.stateOrigin(stateId);
  var b = this;
  var user = this;
  var target = this;
  var origin = this.stateOrigin(stateId);
  var s = $gameSwitches._data;
  var v = $gameVariables._data;
  var healing = false;
  var variance = state.dotVariance;
  var element = state.dotElement;
  var code = state.dotFormula;
  try {
    eval(code);
    if (healing) {
      value = Math.abs(Math.max(0, value));
    } else {
      value = Math.abs(Math.max(0, value)) * -1;
    }
    value = this.applyDamageOverTimeVariance(value, variance);
    value = this.applyDamageOverTimeElement(value, element);
    value = Math.round(value);
    if (value !== 0) {
      this.clearResult();
      this.gainHp(value);
      this.startDamagePopup();
      if (state.dotAnimation > 0) {
        this.startAnimation(state.dotAnimation);
      }
      if (this.isDead()) {
        this.performCollapse();
      }
      this.clearResult();
    }
  } catch (e) {
    Yanfly.Util.displayError(e, code, 'CUSTOM DOT ' + stateId + ' CODE ERROR');
  }
};

Game_Battler.prototype.applyDamageOverTimeVariance = function(damage, vari) {
  if (vari === 0) return damage;
  var variance = vari;
  var amp = Math.floor(Math.max(Math.abs(damage) * variance / 100, 0));
  var v = Math.randomInt(amp + 1) + Math.randomInt(amp + 1) - amp;
  return damage >= 0 ? damage + v : damage - v;
};

Game_Battler.prototype.applyDamageOverTimeElement = function(damage, element) {
  if (element === 0) return damage;
  return damage * this.elementRate(element);
};

//=============================================================================
// Utilities
// ----------------------------------------------------------------------------
// From Yanfly's Utility Library
//=============================================================================

Yanfly.Util = Yanfly.Util || {};

Yanfly.Util.displayError = function(e, code, message) {
  console.log(message);
  console.log(code || 'NON-EXISTENT');
  console.error(e);
  if (Utils.isNwjs() && Utils.isOptionValid('test')) {
    if (!require('nw.gui').Window.get().isDevToolsOpen()) {
      require('nw.gui').Window.get().showDevTools();
    }
  }
};

//=============================================================================
// End of File
//=============================================================================
} else {

var text = '================================================================\n';
text += 'YEP_X_ExtDoT requires YEP_BattleEngineCore and ';
text += 'YEP_BuffsStatesCoreto be at the latest version to run properly. '
text += '\n\nPlease go to www.yanfly.moe and update to the latest version for ';
text += 'the YEP_BattleEngineCore and YEP_BuffsStatesCore plugins.\n';
text += '================================================================\n';
console.log(text);
require('nw.gui').Window.get().showDevTools();

}; // Imported.YEP_BuffsStatesCore