code:
//=============================================================================
// Yanfly Engine Plugins - Item Core
// YEP_ItemCore.js
//=============================================================================

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

var Yanfly = Yanfly || {};
Yanfly.Item = Yanfly.Item || {};

//=============================================================================
/*:
 * @plugindesc v1.21 Changes the way Items are handled for your game
 * and the Item Scene, too.
 * @author Yanfly Engine Plugins
 *
 * @param ---General---
 * @default
 *
 * @param Max Items
 * @desc Maximum number of items. If this is set to 0, then there
 * will be no independent items.
 * @default 0
 *
 * @param Max Weapons
 * @desc Maximum number of weapons. If this is set to 0, then there
 * will be no independent weapons.
 * @default 100
 *
 * @param Max Armors
 * @desc Maximum number of armors. If this is set to 0, then there
 * will be no independent armors.
 * @default 100
 *
 * @param Starting ID
 * @desc This will be the starting ID number for independent items
 * so that they don't interfere with default items.
 * @default 3000
 *
 * @param Random Variance
 * @desc Randomize the stats found for non shop items by this value
 * either positive or negative. Set as 0 for no random.
 * @default 5
 *
 * @param Negative Variance
 * @desc If using random variance, allow random variance equipment
 * stats to go under 0? NO - false     YES - true
 * @default false
 *
 * @param Name Format
 * @desc How item names will be ordered and structured.
 * %1 - Prefix, %2 - Base Name, %3 - Suffix, %4 Boost
 * @default %1%2%3%4
 *
 * @param Name Spacing
 * @desc Place a space between name prefixes and suffixes?
 * NO - false     YES - true
 * @default true
 *
 * @param Boost Format
 * @desc This is the text format for a boosted independent item.
 * %1 - Boost Amount
 * @default (+%1)
 *
 * @param ---Item Scene---
 * @default
 *
 * @param Updated Scene Item
 * @desc Enabling this will change Scene Item's visual appearance.
 * NO - false     YES - true (recommended)
 * @default true
 *
 * @param List Equipped Items
 * @desc Show equipped independent items in the item lists?
 * NO - false     YES - true
 * @default true
 *
 * @param Show Icon
 * @desc Show the icon in the status window?
 * NO - false     YES - true
 * @default true
 *
 * @param Icon Size
 * @desc This will be the width and height of the icon to be drawn.
 * This is normally 4x the default Icon Width and Icon Height.
 * @default 128
 *
 * @param Font Size
 * @desc This changes the font size for description items.
 * Default: 20
 * @default 20
 *
 * @param Command Alignment
 * @desc This is the text alignment for the command windows.
 * left     center     right
 * @default center
 *
 * @param Recovery Format
 * @desc This is the text format for HP/MP Recovery.
 * @default %1 Heal
 *
 * @param Add State
 * @desc This is the text for adding states.
 * @default +State
 *
 * @param Add Buff
 * @desc This is the text for adding buffs.
 * @default +Buff
 *
 * @param Remove State
 * @desc This is the text for remove states.
 * @default -State
 *
 * @param Remove Buff
 * @desc This is the text for remove buffs.
 * @default -Buff
 *
 * @param Maximum Icons
 * @desc Maximum number of icons drawn for states and buffs.
 * @default 4
 *
 * @param Use Command
 * @desc Command text for using the selected item.
 * %1 - Item Icon and Name
 * @default Use %1
 *
 * @param Carry Format
 * @desc This is the visual text format for independent item ID.
 * %1 - Item Index     %2 - Maximum
 * @default %1/%2
 *
 * @param --Independent Items--
 * @default
 *
 * @param Midgame Note Parsing
 * @desc Allow midgame note parsing or do it at beginning?
 * NO - false     YES - true    Recommended: false
 * @default false
 *
 * @help
 * ============================================================================
 * Introduction
 * ============================================================================
 *
 * This plugin makes a couple of main changes to your game and the way items
 * are handled to allow a base core for future plugins.
 *
 * 1. Independent Items
 * If you choose to have maximum limit on your items, weapons, and/or armors,
 * those items will become independent and have their own individual stats and
 * whatnot. Independent items are capable of being upgraded, altered, modified,
 * etc. and retain those changed properties independent of other items of the
 * same type. Items without a maximum limit (aka 0), will continue working as
 * they normally did in RPG Maker MV.
 *
 * 2. New Scene_Item
 * The item scene has been revamped to look a little bit different. With the
 * new layout, the item list is no longer two columns, but one. Added are a few
 * more windows, such as the item status window (which displays basic item
 * information), an item information window (which shows information applied to
 * the item via upgrades, etc.), and an item action window, which appears when
 * you select an item and it will ask you if you wish to Use the item or any
 * action added via plugins (such as upgrading the item). If you wish to not
 * use this revamp, you can disable it from the parameters.
 *
 * 3. Random Variance
 * Newly acquired items that aren't from shop can be given randomized stats to
 * a small degree for items that are independent. Items can be above the stock
 * value or below the stock value by the variance value. If you wish for an
 * item to not have a variance value, you can use a notetag to set the variance
 * value to 0. If you wish for all of your items to not have a variance value,
 * you can set the parameter to 0.
 *
 * Note: During battle test, independent items are disabled.
 *
 * ============================================================================
 * Notetags
 * ============================================================================
 *
 * If you are using independent items, items that aren't gained through the
 * shop can have a random variance applied to its stats.
 *
 * Item, Weapon, Armor Notetag
 *   <Random Variance: x>
 *   If this item is acquired through non-shop means, it will have random
 *   stats offset by x amount in either a positive or negative value.
 *
 *   <Not Independent item>
 *   Sets an item that is independent by default to become a nonindependent
 *   item, allowing it to stack and making it unable to be affected by
 *   independent item modifiers.
 *
 *   <Priority Name>
 *   This sets the item, weapon, or armor's priority name to its database
 *   entry so that name schemes cannot affect the item.
 *
 *   <Text Color: x>
 *   This sets the text color of this item, weapon, or armor to use text color
 *   x from the window skin.
 *
 * ============================================================================
 * Plugin Commands
 * ============================================================================
 *
 * If you wish to be able to add items to your player's inventory without the
 * random variance being applied to it, you can use the following plugin
 * commands to adjust the settings for that.
 *
 * Plugin Command:
 *   EnableVarianceStock  - Causes all items acquired from this point forward
 *                          to have its variance give stock (nonrandom) values.
 *   DisableVarianceStock - Causes all items acquired from this point forward
 *                          to have its variance give random values.
 *
 * A small note is that if you enabled the variance stock values, if the player
 * restarts the game by either going through the title screen or just turning
 * off the program and starting it back up, the random variance will be in
 * effect again. This plugin command is meant to exist as a short term disable.
 *
 * ============================================================================
 * Eventing Changes
 * ============================================================================
 *
 * A few changes have been made to eventing in order to adjust for independent
 * items. They are as follows:
 *
 * Event Page Conditions and Conditional Branches:
 *   Checking to see if an item exists in the party's inventory will differ if
 * the item can be independent. Instead, the condition can be fulfilled if
 * there is an item, even when upgraded, that has the selected item as the base
 * item. This means your Long Sword (+1) will fulfill the condition of having
 * the target Long Sword item in the event editor.
 *
 * Actor Has X Equip:
 *   Just like the previous condition, this condition will be fulfilled if the
 * actor has a weapon whose base item matches the event editor's target item.
 * The Long Sword (+1) will fulfill the condition of needing the actor to have
 * a Long Sword item equipped.
 *
 * Change Equipment:
 *   If the target equipment is independent, the game will first check to see
 * if the actor has an item equipped with the matching base item. If not, the
 * game will then check to see if the party has a matching base item in the
 * inventory first and use that. If not, then the game will create a new stock
 * version of the item and equip that to the actor.
 *
 * ============================================================================
 * Item Name System
 * ============================================================================
 *
 * For independent items, they have a unique name handling system. Independent
 * items consist of four parts:
 *
 *      Prefix     Base Name     Suffix     Boost Count
 *
 * The prefix, base name, suffix, and boost count are adjusted by plugins.
 * Depending on the effects applied, they can be altered or changed. Using the
 * name system, an item with a prefix of 'Fiery', base name of 'Sword', suffix
 * being 'of Might', and a boost count of 5 will end up looking like:
 *
 *      Fiery Sword of Might (+5)
 *
 * This item would appear that way only if its various name parts have been
 * altered some way or another. However, there is a fifth name convention, and
 * that is the priority name. If an item has a priority name, it will completely
 * overwrite the current name scheme with just the priority name itself. So even
 * if the item's name is 'Fiery Sword of Might (+5)', if the item's priority
 * name is 'Legendary Blade', then 'Legendary Blade' will take priority.
 *
 * ============================================================================
 * Lunatic Mode - On Independent Item Creation
 * ============================================================================
 *
 * For those with JavaScript experience, you can use the following Lunatic Mode
 * to run JavaScript code upon the creation of the item. This only applies to
 * newly made independent items.
 *
 * Item, Weapon, Armor
 *
 *   <On Creation Eval>
 *    item.price = baseItem.price;
 *    item.price += Math.floor(Random() * 100);
 *   </On Creation Eval>
 *   The 'item' variable refers to the independent item being made. 'baseItem'
 *   refers to the item's base item. Any alterations made to the 'item' will be
 *   applied to the independent item.
 *
 * ============================================================================
 * Lunatic Mode - Custom Info Window Display
 * ============================================================================
 *
 * If you want to display unique and custom stuff into your info window on the
 * side, you can use the following notetags:
 *
 *   <Info Text Top>
 *    text
 *    text
 *   </Info Text Top>
 *   Type in extra information you wish to type in for the item info window
 *   here, whether it is lore or other information. Text codes can be used.
 *   Information here is is displayed towards the top of the info window.
 *
 *   <Info Text Bottom>
 *    text
 *    text
 *   </Info Text Bottom>
 *   Type in extra information you wish to type in for the item info window
 *   here, whether it is lore or other information. Text codes can be used.
 *   Information here is is displayed towards the bottom of the info window.
 *
 *   <Info Eval>
 *    var variableId = 1;
 *    var value = 500;
 *    $gameVariables.setValue(variableId, value);
 *   </Info Eval>
 *   If you know JavaScript, you can use these notetags to run some code before
 *   displaying any new info. This way, if you plan on using text codes that
 *   display variable values, you can run a bit of code before displaying them
 *   to synch up what's shown in the item info window.
 *
 * ============================================================================
 * Independent Items and Midgame Note Parsing
 * ============================================================================
 *
 * The "Midgame Note Parsing" option in the plugin parameters is made for any
 * plugins that may only parse notetags midgame as opposed to at the loading of
 * the game. This is an option that you should enable AT YOUR OWN RISK.
 *
 * Why is it at your own risk? Because enabling this option means independent
 * items will keep their notedata, thus, increasing the file sizes of your save
 * files several times bigger, and it can cause lag midgame, too.
 *
 * ============================================================================
 * Changelog
 * ============================================================================
 *
 * Version 1.21:
 * - Fixed an error with sorting algorithm when items have the same base ID.
 *
 * Version 1.20:
 * - Added <On Creation Eval> Lunatic Mode notetag. Read the help file for more
 * information about it.
 *
 * Version 1.19:
 * - Updated for RPG Maker MV version 1.1.0.
 *
 * Version 1.18a:
 * - Added 'Midgame Note Parsing' plugin parameter.
 * - Fixed a visual error with MP recovery displaying a 0 instead of ---.
 *
 * Version 1.17:
 * - Added <Text Color: x> notetag for items, weapons, and armors.
 *
 * Version 1.16:
 * - Fixed a bug that made mid-game actor initialization not display items
 * correctly in the item menu.
 *
 * Version 1.15:
 * - Fixed a bug with independent items getting values that crash the game.
 *
 * Version 1.14:
 * - Fixed an unintended function of the game not granting a piece of equipment
 * through events.
 *
 * Version 1.13:
 * - Fixed a bug that didn't unequip items properly.
 *
 * Version 1.12:
 * - Added 'Negative Variance' parameter.
 *
 * Version 1.11:
 * - Fixed a bug that caused random variance to not calculate correctly.
 * - Fixed a bug that didn't return the correct conditional branch results.
 * - Fixed the display in the shop window to show number of independent items
 * owned by the player rather than just 0.
 *
 * Version 1.10:
 * - Added Lunatic Mode - Custom Info Window Display.
 *
 * Version 1.09:
 * - Fixed a bug with evented item removal that didn't remove equipped items if
 * the 'Include Equipment' checkbox was checked.
 *
 * Version 1.08:
 * - Fixed a bug with the Control Variable event that would not gather the
 * right amount of independent items.
 *
 * Version 1.07:
 * - Fixed a bug with the Change Equipment event where armors wouldn't equip.
 *
 * Version 1.06:
 * - Fixed a bug and rewrote the initializing equipment process.
 *
 * Version 1.05:
 * - Compatibility update with ItemBook.
 *
 * Version 1.04:
 * - Added 'List Equipped Items' parameter to allow for equipment restricted
 * actors to be able to alt their equipment.
 *
 * Version 1.03:
 * - Fixed a bug where using events to remove independent items weren't working
 * properly and instead added more items.
 * - Fixed a bug where a Random Variance of 0 still gave random stats.
 *
 * Version 1.02:
 * - Fixed a bug where initializing equipment slots didn't work properly and/or
 * added incorrect equips from the wrong actors into the inventory.
 *
 * Version 1.01:
 * - Fixed bug where if you are using no independent pieces of equipment,
 * actors would fail to start with initial equipment.
 *
 * Version 1.00:
 * - Finished plugin!
 */

/*:ja
 * @plugindesc v1.21 ゲーム内やアイテムシーン内でのアイテムの処理を変更します
 * @author Yanfly Engine Plugins
 *
 * @param ---一般---
 * @default
 *
 * @param Max Items
 * @desc アイテムの最大値を指定します。0にすると個別アイテムが無効になります。
 * @default 0
 *
 * @param Max Weapons
 * @desc 武器の最大値を指定します。0にすると個別武器が無効になります。
 * @default 100
 *
 * @param Max Armors
 * @desc 防具の最大値を指定します。0にすると個別防具が無効になります。
 * @default 100
 *
 * @param Starting ID
 * @desc 個別アイテムの適用を始めるIDを指定します。デフォルトアイテムとの干渉を防ぎます。
 * @default 3000
 *
 * @param Random Variance
 * @desc ショップ以外で手に入れたアイテムに対して、この値の範囲内でランダム値を付与します(増減)。0にすると無効になります。
 * @default 5
 *
 * @param Negative Variance
 * @desc Random Varianceを使った場合ランダム値の数値を０以下にすることを許可しますか？
 * いいえ - false     はい - true
 * @default false
 *
 * @param Name Format
 * @desc アイテム名がどのように構成されるかを指定します。
 * %1 - 接頭辞, %2 - ベース名, %3 - 接尾辞, %4 増減値
 * @default %1%2%3%4
 *
 * @param Name Spacing
 * @desc 接頭辞と接尾辞の間にスペースを挿入します。
 * NO - false     YES - true
 * @default true
 *
 * @param Boost Format
 * @desc 個別アイテムの増減値の表し方を指定します
 * %1 - 増減値
 * @default (+%1)
 *
 * @param ---アイテムシーン---
 * @default
 *
 * @param Updated Scene Item
 * @desc アイテムシーンでの見た目を変更します。
 * NO - false     YES - true (おすすめ)
 * @default true
 *
 * @param List Equipped Items
 * @desc 装備された個別アイテムをアイテムリスト表示するか選択します。
 * NO - false     YES - true
 * @default true
 *
 * @param Show Icon
 * @desc ステータスウィンドウ内にアイコンを表示します。
 * NO - false     YES - true
 * @default true
 *
 * @param Icon Size
 * @desc アイコンの縦横のサイズを変更します。通常は、デフォルトサイズの4倍です
 * @default 128
 *
 * @param Font Size
 * @desc 詳細のフォントサイズを変更します
 * Default: 20
 * @default 20
 *
 * @param Command Alignment
 * @desc コマンドウィンドウでのテキストの揃え方を指定します。
 * left(左)     center(中央)     right(右)
 * @default center
 *
 * @param Recovery Format
 * @desc HP/MP回復のテキスト形式を指定します。
 * @default %1 回復
 *
 * @param Add State
 * @desc ステータス追加時のテキスト形式を指定します。
 * @default +State
 *
 * @param Add Buff
 * @desc バフ追加時のテキスト形式を指定します。
 * @default +Buff
 *
 * @param Remove State
 * @desc ステータス減少時のテキスト形式を指定します。
 * @default -State
 *
 * @param Remove Buff
 * @desc バフ解除時のテキスト形式を指定します。
 * @default -Buff
 *
 * @param Maximum Icons
 * @desc ステータスとバフに描写されるアイコンの最大数を決定します。
 * @default 4
 *
 * @param Use Command
 * @desc 選択したアイテムを使う際のコマンドテキストを指定します。
 * %1 - アイテムアイコンと名前
 * @default %1 を使う
 *
 * @param Carry Format
 * @desc 個別アイテムのIDに対するテキスト形式を指定します。
 * %1 - アイテムインデックス     %2 - 最大値
 * @default %1/%2
 *
 * @param --Independent Items--
 * @default
 *
 * @param Midgame Note Parsing
 * @desc ノート解析をゲームの最中に行わせますか？
 * 開始時 - false     ゲーム中 - true  （おすすめはfalse）
 * @default false
 *
 * @help
 * ============================================================================
 * Introduction
 * ============================================================================
 *
 * このプラグインは、ゲームそのもの、そして
 * ゲーム内でのアイテムの扱われ方にいくつかの変更を行います。
 *
 *
 * １．個別アイテム
 * アイテム・武器・防具などに上限値を設定した場合、各アイテムは独立した
 * アイテムとして扱われ、個別にステータスを持たせて管理することができます。
 * このステータスはアップグレードしたり、変更、修正などを行うことも可能で、
 * 変更後も元の特性を保持し、別個のアイテムとして管理することができます。
 * 上限設定のないアイテム(0指定)は、デフォルトアイテムと同様の扱いとなります
 *
 * ２．新しいアイテム画面
 * アイテム画面の表示方法についても、変更されています。
 * 新しいレイアウトでは、アイテムのリストは2列ではなく1列で構成されています。
 * 「アイテムステータスウィンドウ」(アイテムの基本性能表示)や、
 * 「アイテムインフォメーションウィンドウ」(アップグレードの反映情報などを表示)
 * が追加されています。
 * また、アイテムを選択した際にどんなアクションを取りたいか
 * (使用する、アップグレードするなど。その他プラグインから追加も可能)を尋ねる、
 * 「アイテムアクションウィンドウ」も追加されています。
 *
 * ３．ランダムな値の付与
 * ショップからの購入アイテムを除き、新たに取得したアイテムには、
 * ランダムな値を付与することができます。
 * アイテムのパラメータを、ランダムに標準値から増減させることができます。
 * 不要な場合は、notetagの"Varience value"を0にすることで、無効化できます。
 * もしすべてのアイテムでこの設定を無効化したい場合は、
 * パラメータを0にすることで設定することもできます。
 *
 * 注＊バトルテスト時には、上記の個別アイテム機能は無効になります。
 *
 *
 * ============================================================================
 * Notetags
 * ============================================================================
 *
 * 個別アイテムのパラメータにはランダムな値が付与されます。
 * (ショップ購入アイテムを除く)
 *
 * アイテム、武器、防具のNotetag
 *   <Random Variance: x>
 *   そのアイテムがショップ購入アイテムでない場合、
 *   正負 x の範囲内で、性能値がランダムに増減します。
 *
 *   <Not Independent item>
 *   デフォルトの個別アイテムを、非個別アイテムに変換します。
 *   これにより、個別アイテムに対する処理の影響を受けなくなります。
 *
 *   <Priority Name>
 *    アイテム、武器や防具のプライオリティネーム(優先度の高い名称)を、
 *    データベース上での見出し名に設定します。
 *    これにより、ネームスキームがアイテムに影響することがなくなります。
 *
 *   <Text Color: x>
 *   ウインドウスキンで設定したテキストカラー ｘ をこのアイテム、武器や防具の
 *   テキストカラーに設定します。
 *
 * ============================================================================
 * Plugin Commands
 * ============================================================================
 *
 * 上記のランダム値の適用無しで、アイテムをインベントリに追加させたい場合は、
 * 下記のプラグインコマンドを用いてください。
 *
 * <プラグインコマンド>
 *   EnableVarianceStock  - これより先のポイントで得られた全てのアイテムには
 *                          標準の値を付与します。
 *   DisableVarianceStock - これより先のポイントで得られた全てのアイテムには
 *                          ランダムな値を付与します。
 *
 * 標準値を有効にしても、プレイヤーがタイトル画面からゲームをリスタートしたり
 * プログラムを再起動したりすると、再びランダム値が適用されるようになります。
 * このプラグインコマンドは、一時的なコマンドであることに注意してください。
 *
 * ============================================================================
 * Eventing Changes
 * ============================================================================
 *
 * 個別アイテムのシステムを最適化させるために、
 * イベント生成においてもいくつかの変更が成されています。
 *
 *・イベントページの条件と条件分岐
 *   システムは、アイテムがパーティインベントリ内に存在するか確認することで
 * そのアイテムが個別アイテムとして扱えるか否かを判断します。
 * もしそのアイテムがアップグレード済だったとしても、
 * アップグレード前のベースアイテム名と照合して、条件分岐を行います。
 * 例）アップグレード済の"長剣(+1)"を持っていても、
 *     イベントエディタのターゲットである"長剣"と照合し、
 *    「"長剣"を持っている」という条件を満たしているとみなします。
 *
 *・アクターの装備の条件
 *   前述の条件分岐と同様に、アクターの所持装備がアップグレード済であっても、
 * 「装備 x を所持している」という条件を満たしているものとみなされます。
 * 例）アクターがアップグレード済の"長剣(+1)"を持っていても、
 *    「アクターが"長剣"を持っている」という条件を満たしているとみなします。
 *
 * ・装備変更
 *   ターゲットとなる装備が個別装備だった場合、ゲームは最初に、
 * 「合致するベースアイテムをアクターが持っているかどうか」を確認します。
 * 持っていない場合、今度は「合致するベースアイテムをパーティが持っているか」
 * を確認し、持っていた場合はそれを使用します。
 * そこでも持っていなかった場合は、ゲームは新規で標準値のアイテムを作成し
 * それをアクターに装備させます。
 *
 * ============================================================================
 * Item Name System
 * ============================================================================
 *
 * 個別アイテムの名前は以下の4つのパートで構成されています。
 *
 *  Prefix(接頭辞)  Base Name(ベース名)  Suffix(接尾辞)  Boost Count(増加値)
 *
 * 上記の4つはプラグインによって調整されます。
 * 適用されるエフェクトによって、それぞれを入れ替えたり変更することも可能です。
 * 例）'Fiery'という接頭辞 + 'Sword'というベースネーム + 'of Might'という接尾辞
 *      + '5' の増加値で構成されたアイテムは、以下のように表示されます。
 *
 *      Fiery Sword of Might (+5)
 *
 * このアイテムは、その名称の各パーツが何らかの形で変更された場合のみ現れます。
 *
 * また、他にも第5の命名規則(プライオリティネーム)があり、
 * 名称としてはそちらが優先されることに気を付けてください。
 * このプライオリティネームは、現在のネームスキームを完全に上書きしてしまいます。
 * 上記のように、アイテム名を 'Fiery Sword of Might (+5)'としたとしても、
 * そのプライオリティネームが別の名前だった場合は、そちらが優先されてしまいます。
 *
 * ============================================================================
 * Lunatic Mode - On Independent Item Creation
 * ============================================================================
 *
 * JavaScriptが書ける方に・・・Lunatic Modeを使って、アイテム作成時に
 * コードを実行する事が出来ます。新しく作った個別アイテムに限ります。
 *
 * アイテム, 武器, 防具
 *
 *   <On Creation Eval>
 *    item.price = baseItem.price;
 *    item.price += Math.floor(Random() * 100);
 *   </On Creation Eval>
 *   ここで書かれてる「item」は作成されている個別アイテムを指しています。
 *   「baseItem」はベースアイテムのことです。「item」に変更があった場合、
 *   個別アイテムにも同じ変更が実行されます。
 *
 * ============================================================================
 * Lunatic Mode - Custom Info Window Display
 * ============================================================================
 *
 * 端にあるインフォウインドウにオリジナルコンテンツを追加したい場合は
 * 以下のノートタグを使用してください。
 *
 *   <Info Text Top>
 *    text
 *    text
 *   </Info Text Top>
 *   アイテムインフォウインドウに足したい情報をここに書いてください。
 *   好きなテキストをご自由に記載することができます。
 *   テキストコードを使う事も出来ます。ここに書かれてる情報は
 *   ウインドウの上部に表示されます。
 *
 *   <Info Text Bottom>
 *    text
 *    text
 *   </Info Text Bottom>
 *   アイテムインフォウインドウに足したい情報をここに書いてください。
 *   好きなテキストをご自由に記載することができます。
 *   テキストコードを使う事も出来ます。ここに書かれてる情報は
 *   ウインドウの下部に表示されます。
 *
 *   <Info Eval>
 *    var variableId = 1;
 *    var value = 500;
 *    $gameVariables.setValue(variableId, value);
 *   </Info Eval>
 *   ジャバスクリプトが書ける方はこちらのノートタグを使って、新しい情報を
 *   表示する前にジャバスクリプトを実行する事が出来ます。これを使う事に
 *   よって、テキストコードなどで数値を表示するつもりでいれば、
 *   表示する前にデータベースから新しい情報を引っ張ってきて、最新の
 *   情報を表示する事が出来ます。
 *
 * ============================================================================
 * Independent Items and Midgame Note Parsing
 * ============================================================================
 *
 * 追加した「Midgame Note Parsing」オプションは、他のプラグインで、開始時に
 * ノートタグを解析させるのではなく、途中で行っているようなプラグインのために
 * 追加されてます。
 *
 * 自己責任でのご使用をお願いいたします。理由としては、これをオンにする事に
 * よって個別アイテムもノートデータを残すので、ファイルや保存データが大きく
 * なり、下手をしたらゲームのラグを生じさせてしまう恐れがあるからです。
 *
 * ============================================================================
 * Changelog
 * ============================================================================
 *
 * Version 1.21:
 * - Fixed an error with sorting algorithm when items have the same base ID.
 *
 * Version 1.20:
 * - Added <On Creation Eval> Lunatic Mode notetag. Read the help file for more
 * information about it.
 *
 * Version 1.19:
 * - Updated for RPG Maker MV version 1.1.0.
 *
 * Version 1.18a:
 * - Added 'Midgame Note Parsing' plugin parameter.
 * - Fixed a visual error with MP recovery displaying a 0 instead of ---.
 *
 * Version 1.17:
 * - Added <Text Color: x> notetag for items, weapons, and armors.
 *
 * Version 1.16:
 * - Fixed a bug that made mid-game actor initialization not display items
 * correctly in the item menu.
 *
 * Version 1.15:
 * - Fixed a bug with independent items getting values that crash the game.
 *
 * Version 1.14:
 * - Fixed an unintended function of the game not granting a piece of equipment
 * through events.
 *
 * Version 1.13:
 * - Fixed a bug that didn't unequip items properly.
 *
 * Version 1.12:
 * - Added 'Negative Variance' parameter.
 *
 * Version 1.11:
 * - Fixed a bug that caused random variance to not calculate correctly.
 * - Fixed a bug that didn't return the correct conditional branch results.
 * - Fixed the display in the shop window to show number of independent items
 * owned by the player rather than just 0.
 *
 * Version 1.10:
 * - Added Lunatic Mode - Custom Info Window Display.
 *
 * Version 1.09:
 * - Fixed a bug with evented item removal that didn't remove equipped items if
 * the 'Include Equipment' checkbox was checked.
 *
 * Version 1.08:
 * - Fixed a bug with the Control Variable event that would not gather the
 * right amount of independent items.
 *
 * Version 1.07:
 * - Fixed a bug with the Change Equipment event where armors wouldn't equip.
 *
 * Version 1.06:
 * - Fixed a bug and rewrote the initializing equipment process.
 *
 * Version 1.05:
 * - Compatibility update with ItemBook.
 *
 * Version 1.04:
 * - Added 'List Equipped Items' parameter to allow for equipment restricted
 * actors to be able to alt their equipment.
 *
 * Version 1.03:
 * - Fixed a bug where using events to remove independent items weren't working
 * properly and instead added more items.
 * - Fixed a bug where a Random Variance of 0 still gave random stats.
 *
 * Version 1.02:
 * - Fixed a bug where initializing equipment slots didn't work properly and/or
 * added incorrect equips from the wrong actors into the inventory.
 *
 * Version 1.01:
 * - Fixed bug where if you are using no independent pieces of equipment,
 * actors would fail to start with initial equipment.
 *
 * Version 1.00:
 * - Finished plugin!
 */
//=============================================================================

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

Yanfly.Parameters = PluginManager.parameters("YEP_ItemCore");
Yanfly.Param = Yanfly.Param || {};

Yanfly.Param.ItemMaxItems = Number(Yanfly.Parameters["Max Items"]);
Yanfly.Param.ItemMaxWeapons = Number(Yanfly.Parameters["Max Weapons"]);
Yanfly.Param.ItemMaxArmors = Number(Yanfly.Parameters["Max Armors"]);
Yanfly.Param.ItemStartingId = Number(Yanfly.Parameters["Starting ID"]);
Yanfly.Param.ItemRandomVariance = Number(Yanfly.Parameters["Random Variance"]);
Yanfly.Param.ItemNegVar = eval(String(Yanfly.Parameters["Negative Variance"]));
Yanfly.Param.ItemNameFmt = String(Yanfly.Parameters["Name Format"]);
Yanfly.Param.ItemNameSpacing = String(Yanfly.Parameters["Name Spacing"]);
Yanfly.Param.ItemBoostFmt = String(Yanfly.Parameters["Boost Format"]);

Yanfly.Param.ItemSceneItem = String(Yanfly.Parameters["Updated Scene Item"]);
Yanfly.Param.ItemShEquipped = String(Yanfly.Parameters["List Equipped Items"]);
Yanfly.Param.ItemShowIcon = String(Yanfly.Parameters["Show Icon"]);
Yanfly.Param.ItemIconSize = Number(Yanfly.Parameters["Icon Size"]);
Yanfly.Param.ItemFontSize = Number(Yanfly.Parameters["Font Size"]);
Yanfly.Param.ItemCmdAlign = String(Yanfly.Parameters["Command Alignment"]);
Yanfly.Param.ItemRecoverFmt = String(Yanfly.Parameters["Recovery Format"]);
Yanfly.Param.ItemAddState = String(Yanfly.Parameters["Add State"]);
Yanfly.Param.ItemAddBuff = String(Yanfly.Parameters["Add Buff"]);
Yanfly.Param.ItemRemoveState = String(Yanfly.Parameters["Remove State"]);
Yanfly.Param.ItemRemoveBuff = String(Yanfly.Parameters["Remove Buff"]);
Yanfly.Param.ItemMaxIcons = Number(Yanfly.Parameters["Maximum Icons"]);
Yanfly.Param.ItemUseCmd = String(Yanfly.Parameters["Use Command"]);
Yanfly.Param.ItemCarryFmt = String(Yanfly.Parameters["Carry Format"]);

Yanfly.Param.ItemNoteParse = String(Yanfly.Parameters["Midgame Note Parsing"]);
Yanfly.Param.ItemNoteParse = eval(Yanfly.Param.ItemNoteParse);

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

Yanfly.Item.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function () {
  if (!Yanfly.Item.DataManager_isDatabaseLoaded.call(this)) return false;
  if (!Yanfly._loaded_YEP_ItemCore) {
    this.setDatabaseLengths();
    this.processItemCoreNotetags($dataItems);
    this.processItemCoreNotetags($dataWeapons);
    this.processItemCoreNotetags($dataArmors);
    Yanfly._loaded_YEP_ItemCore = true;
  }
  return true;
};

DataManager.processItemCoreNotetags = function (group) {
  var note1 = /<(?:RANDOM VARIANCE):[ ](\d+)>/i;
  var note2 = /<(?:NONINDEPENDENT ITEM|not independent item)>/i;
  var note3 = /<(?:PRIORITY NAME)>/i;
  for (var n = 1; n < group.length; n++) {
    var obj = group[n];
    var notedata = obj.note.split(/[\r\n]+/);

    obj.randomVariance = Yanfly.Param.ItemRandomVariance;
    obj.textColor = 0;
    if (Imported.YEP_CoreEngine) obj.textColor = Yanfly.Param.ColorNormal;
    obj.nonIndepdent = false;
    obj.setPriorityName = false;
    obj.infoEval = "";
    obj.infoTextTop = "";
    obj.infoTextBottom = "";
    obj.onCreationEval = "";
    var evalMode = "none";

    for (var i = 0; i < notedata.length; i++) {
      var line = notedata[i];
      if (line.match(note1)) {
        obj.randomVariance = parseInt(RegExp.$1);
      } else if (line.match(note2)) {
        obj.nonIndepdent = true;
      } else if (line.match(note3)) {
        obj.setPriorityName = true;
      } else if (line.match(/<(?:INFO EVAL)>/i)) {
        evalMode = "info eval";
      } else if (line.match(/<\/(?:INFO EVAL)>/i)) {
        evalMode = "none";
      } else if (line.match(/<(?:INFO TEXT TOP)>/i)) {
        evalMode = "info text top";
      } else if (line.match(/<\/(?:INFO TEXT TOP)>/i)) {
        evalMode = "none";
      } else if (line.match(/<(?:INFO TEXT BOTTOM)>/i)) {
        evalMode = "info text bottom";
      } else if (line.match(/<\/(?:INFO TEXT BOTTOM)>/i)) {
        evalMode = "none";
      } else if (evalMode === "info eval") {
        obj.infoEval = obj.infoEval + line + "\n";
      } else if (evalMode === "info text top") {
        if (obj.infoTextTop !== "") obj.infoTextTop += "\n";
        obj.infoTextTop = obj.infoTextTop + line;
      } else if (evalMode === "info text bottom") {
        if (obj.infoTextBottom !== "") obj.infoTextBottom += "\n";
        obj.infoTextBottom = obj.infoTextBottom + line;
      } else if (line.match(/<(?:TEXT COLOR):[ ](\d+)>/i)) {
        obj.textColor = parseInt(RegExp.$1);
      } else if (line.match(/<(?:ON CREATE EVAL|ON CREATION EVAL)>/i)) {
        evalMode = "on create eval";
      } else if (line.match(/<\/(?:ON CREATE EVAL|ON CREATION EVAL)>/i)) {
        evalMode = "none";
      } else if (evalMode === "on create eval") {
        obj.onCreationEval = obj.onCreationEval + line + "\n";
      }
    }
  }
};

DataManager.setDatabaseLengths = function () {
  this._baseItemsLength = $dataItems.length;
  this._baseWeaponsLength = $dataWeapons.length;
  this._baseArmorsLength = $dataArmors.length;
};

Yanfly.Item.DataManager_createGameObjects = DataManager.createGameObjects;
DataManager.createGameObjects = function () {
  Yanfly.Item.DataManager_createGameObjects.call(this);
  this.createIndependentObjects();
};

DataManager.createIndependentObjects = function () {
  DataManager.createIndependentGroups();
  this.loadIndependentItems();
};

DataManager.loadIndependentItems = function () {
  if (Yanfly.Param.ItemMaxItems > 0) {
    var difItems = $dataItems.length - DataManager._baseItemsLength;
    $dataItems.splice(DataManager._baseItemsLength, difItems);
    this.setIndependentLength($dataItems);
    $dataItems = $dataItems.concat(this._independentItems);
  }
  if (Yanfly.Param.ItemMaxWeapons > 0) {
    var difWeapons = $dataWeapons.length - DataManager._baseWeaponsLength;
    $dataWeapons.splice(DataManager._baseWeaponsLength, difWeapons);
    this.setIndependentLength($dataWeapons);
    $dataWeapons = $dataWeapons.concat(this._independentWeapons);
  }
  if (Yanfly.Param.ItemMaxArmors > 0) {
    var difArmors = $dataArmors.length - DataManager._baseArmorsLength;
    $dataArmors.splice(DataManager._baseArmorsLength, difArmors);
    this.setIndependentLength($dataArmors);
    $dataArmors = $dataArmors.concat(this._independentArmors);
  }
};

DataManager.setIndependentLength = function (group) {
  for (;;) {
    if (group.length > Yanfly.Param.ItemStartingId) break;
    group.push(null);
  }
};

DataManager.saveGameWithoutRescue = function (savefileId) {
  var json = JsonEx.stringify(this.makeSaveContents());
  StorageManager.save(savefileId, json);
  this._lastAccessedId = savefileId;
  var globalInfo = this.loadGlobalInfo() || [];
  globalInfo[savefileId] = this.makeSavefileInfo();
  this.saveGlobalInfo(globalInfo);
  return true;
};

Yanfly.Item.DataManager_makeSaveContents = DataManager.makeSaveContents;
DataManager.makeSaveContents = function () {
  var contents = Yanfly.Item.DataManager_makeSaveContents.call(this);
  contents.items = this._independentItems;
  contents.weapons = this._independentWeapons;
  contents.armors = this._independentArmors;
  return contents;
};

Yanfly.Item.DataManager_extractSaveContents = DataManager.extractSaveContents;
DataManager.extractSaveContents = function (contents) {
  Yanfly.Item.DataManager_extractSaveContents.call(this, contents);
  this._independentItems = contents.items || [];
  this._independentWeapons = contents.weapons || [];
  this._independentArmors = contents.armors || [];
  this.loadIndependentItems();
};

DataManager.createIndependentGroups = function () {
  this._independentItems = [];
  this._independentWeapons = [];
  this._independentArmors = [];
};

DataManager.isIndependent = function (item) {
  if (!item) return false;
  if (DataManager.isBattleTest()) return false;
  if (item.nonIndepdent) return false;
  if (DataManager.isItem(item)) return Yanfly.Param.ItemMaxItems > 0;
  if (DataManager.isWeapon(item)) return Yanfly.Param.ItemMaxWeapons > 0;
  if (DataManager.isArmor(item)) return Yanfly.Param.ItemMaxArmors > 0;
  return false;
};

DataManager.registerNewItem = function (item) {
  if (!this.isNewItemValid(item)) return item;
  var newItem = JsonEx.makeDeepCopy(item);
  this.addNewIndependentItem(item, newItem);
  return newItem;
};

DataManager.isNewItemValid = function (item) {
  if (!item) return false;
  if (item.baseItemId) return false;
  return item.id === this.getDatabase(item).indexOf(item);
};

DataManager.addNewIndependentItem = function (baseItem, newItem) {
  newItem.id = this.getDatabase(baseItem).length;
  ItemManager.setNewIndependentItem(baseItem, newItem);
  ItemManager.customizeNewIndependentItem(baseItem, newItem);
  ItemManager.onCreationEval(baseItem, newItem);
  this.getDatabase(baseItem).push(newItem);
  this.getContainer(baseItem).push(newItem);
};

DataManager.removeIndependentItem = function (item) {
  if (!item) return;
  if (this.independentItemIsUsed(item)) return;
  var container = this.getContainer(item);
  var database = this.getDatabase(item);
  var index = container.indexOf(item);
  container[index] = null;
  var index = database.indexOf(item);
  database[index] = null;
};

DataManager.independentItemIsUsed = function (item) {
  if ($gameParty.numItems(item) > 0) return false;
  for (var i = 0; i < $dataActors.length; ++i) {
    var actor = $gameActors.actor(i);
    if (!actor) continue;
    if (actor.equips().contains(item)) return true;
  }
  return false;
};

DataManager.getDatabase = function (item) {
  if (!item) return [];
  if (DataManager.isItem(item)) return $dataItems;
  if (DataManager.isWeapon(item)) return $dataWeapons;
  if (DataManager.isArmor(item)) return $dataArmors;
  return [];
};

DataManager.getContainer = function (item) {
  if (!item) return [];
  if (DataManager.isItem(item)) return this._independentItems;
  if (DataManager.isWeapon(item)) return this._independentWeapons;
  if (DataManager.isArmor(item)) return this._independentArmors;
  return [];
};

DataManager.getBaseItem = function (item) {
  if (!this.isIndependent(item)) return item;
  if (!item.baseItemId) return item;
  var baseItemId = item.baseItemId;
  var baseItem = this.getDatabase(item)[baseItemId];
  return baseItem;
};

//=============================================================================
// ItemManager
//=============================================================================

function ItemManager() {
  throw new Error("This is a static class");
}

ItemManager.setNewIndependentItem = function (baseItem, newItem) {
  newItem.baseItemId = baseItem.id;
  newItem.baseItemName = baseItem.name;
  newItem.baseItemPrice = baseItem.price;
  newItem.baseItemIconIndex = baseItem.iconIndex;
  newItem.namePrefix = "";
  newItem.nameSuffix = "";
  if (baseItem.setPriorityName) {
    newItem.priorityName = baseItem.name;
  } else {
    newItem.priorityName = "";
  }
  newItem.boostCount = 0;
  if (!Yanfly.Param.ItemNoteParse) newItem.note = "";
};

ItemManager.customizeNewIndependentItem = function (baseItem, newItem) {
  this.randomizeInitialItem(baseItem, newItem);
  this.updateItemName(newItem);
};

ItemManager.randomizeInitialItem = function (baseItem, newItem) {
  if ($gameTemp.varianceStock()) return;
  if (DataManager.isItem(baseItem)) {
    this.randomizeInitialEffects(baseItem, newItem);
  } else {
    this.randomizeInitialStats(baseItem, newItem);
  }
};

ItemManager.randomizeInitialEffects = function (baseItem, newItem) {
  if (baseItem.randomVariance <= 0) return;
  var randomValue = baseItem.randomVariance * 2 + 1;
  var offset = baseItem.randomVariance;
  newItem.effects.forEach(function (effect) {
    if (effect.code === Game_Action.EFFECT_RECOVER_HP) {
      if (effect.value1 !== 0) {
        var boost = Math.floor(Math.random() * randomValue - offset);
        effect.value1 += boost * 0.01;
        effect.value1 = parseFloat(effect.value1.toFixed(2));
        effect.value1 = effect.value1.clamp(0, 1);
      }
      if (effect.value2 !== 0) {
        effect.value2 += Math.floor(Math.random() * randomValue - offset);
      }
    }
    if (effect.code === Game_Action.EFFECT_RECOVER_MP) {
      if (effect.value1 !== 0) {
        var boost = Math.floor(Math.random() * randomValue - offset);
        effect.value1 += boost * 0.01;
        effect.value1 = parseFloat(effect.value1.toFixed(2));
        effect.value1 = effect.value1.clamp(0, 1);
      }
      if (effect.value2 !== 0) {
        effect.value2 += Math.floor(Math.random() * randomValue - offset);
      }
    }
  }, this);
};

ItemManager.randomizeInitialStats = function (baseItem, newItem) {
  if (baseItem.randomVariance <= 0) return;
  var randomValue = baseItem.randomVariance * 2 + 1;
  var offset = baseItem.randomVariance;
  for (var i = 0; i < 8; ++i) {
    if (newItem.params[i] === 0) continue;
    newItem.params[i] += Math.floor(Math.random() * randomValue - offset);
    if (!Yanfly.Param.ItemNegVar && baseItem.params[i] >= 0) {
      newItem.params[i] = Math.max(newItem.params[i], 0);
    }
  }
};

ItemManager.setBaseName = function (item, value) {
  item.baseItemName = value;
};

ItemManager.setNamePrefix = function (item, value) {
  item.namePrefix = value;
  if (eval(Yanfly.Param.ItemNameSpacing) && item.namePrefix.length > 0) {
    item.namePrefix = item.namePrefix + " ";
  }
};

ItemManager.setNameSuffix = function (item, value) {
  item.nameSuffix = value;
  if (eval(Yanfly.Param.ItemNameSpacing) && item.nameSuffix.length > 0) {
    item.nameSuffix = " " + item.nameSuffix;
  }
};

ItemManager.setPriorityName = function (item, value) {
  item.priorityName = value;
};

ItemManager.updateItemName = function (item) {
  if (item.priorityName && item.priorityName.length > 0) {
    item.name = item.priorityName;
    return;
  }
  var prefix = item.namePrefix || "";
  var baseName = item.baseItemName || "";
  var suffix = item.nameSuffix || "";
  var boostCount = item.boostCount || 0;
  var fmt = Yanfly.Param.ItemBoostFmt;
  var boostText = fmt.format(Yanfly.Util.toGroup(boostCount));
  if (boostText === fmt.format(0)) {
    boostText = "";
  } else if (eval(Yanfly.Param.ItemNameSpacing)) {
    boostText = " " + boostText;
  }
  fmt = Yanfly.Param.ItemNameFmt;
  item.name = fmt.format(prefix, baseName, suffix, boostText);
};

ItemManager.increaseItemBoostCount = function (item, value) {
  value = value || 1;
  if (!item.boostCount) item.boostCount = 0;
  item.boostCount += value;
  this.updateItemName(item);
};

ItemManager.onCreationEval = function (baseItem, newItem) {
  var item = newItem;
  if (item.onCreationEval === "") return;
  var weapon = item;
  var armor = item;
  var baseWeapon = baseItem;
  var baseArmor = baseItem;
  var s = $gameSwitches._data;
  var v = $gameVariables._data;
  eval(item.onCreationEval);
  item.onCreationEval = "";
};

//=============================================================================
// Game_Temp
//=============================================================================

Game_Temp.prototype.enableVarianceStock = function () {
  this._independentStock = true;
};

Game_Temp.prototype.disableVarianceStock = function () {
  this._independentStock = false;
};

Game_Temp.prototype.varianceStock = function () {
  return this._independentStock;
};

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

Yanfly.Item.Game_Actor_setup = Game_Actor.prototype.setup;
Game_Actor.prototype.setup = function (actorId) {
  Yanfly.Item.Game_Actor_setup.call(this, actorId);
  if ($gameTemp._initializeStartingMemberEquipment) return;
  this.initIndependentEquips($dataActors[actorId].equips);
};

Game_Actor.prototype.initIndependentEquips = function (equips) {
  var equips = this.convertInitEquips(equips);
  this.equipInitIndependentEquips(equips);
  this.releaseUnequippableItems(true);
  this.recoverAll();
  this.refresh();
};

Game_Actor.prototype.convertInitEquips = function (equips) {
  var items = [];
  for (var i = 0; i < equips.length; ++i) {
    var equipId = equips[i];
    if (equipId <= 0) continue;
    var equipType = $dataSystem.equipTypes[i + 1];
    if (
      equipType === $dataSystem.equipTypes[1] ||
      (i === 1 && this.isDualWield())
    ) {
      var equip = $dataWeapons[equipId];
    } else {
      var equip = $dataArmors[equipId];
    }
    items.push(equip);
  }
  return items;
};

Game_Actor.prototype.equipInitIndependentEquips = function (equips) {
  var slots = this.equipSlots();
  var maxSlots = slots.length;
  this._equips = [];
  for (var i = 0; i < maxSlots; ++i) {
    this._equips[i] = new Game_Item();
  }
  for (var i = 0; i < maxSlots; ++i) {
    var slotType = slots[i];
    var equip = this.grabInitEquips(equips, slotType);
    if (DataManager.isIndependent(equip) && this.canEquip(equip)) {
      var array = $gameParty.gainIndependentItem(equip, 1);
      if (array instanceof Array) {
        newItem = array[0];
        this.changeEquip(i, newItem);
      }
    } else if (this.canEquip(equip)) {
      this._equips[i].setObject(equip);
    }
  }
};

Game_Actor.prototype.grabInitEquips = function (equips, slotType) {
  var item = null;
  for (var i = 0; i < equips.length; ++i) {
    var equip = equips[i];
    if (!equip) continue;
    if (slotType === 1 && DataManager.isWeapon(equip)) {
      item = equip;
      break;
    } else if (equip.etypeId === slotType) {
      item = equip;
      break;
    }
  }
  if (item) equips[i] = null;
  return item;
};

Yanfly.Item.Game_Actor_hasWeapon = Game_Actor.prototype.hasWeapon;
Game_Actor.prototype.hasWeapon = function (weapon) {
  if (this.hasBaseItem(weapon)) return true;
  return Yanfly.Item.Game_Actor_hasWeapon.call(this, weapon);
};

Yanfly.Item.Game_Actor_hasArmor = Game_Actor.prototype.hasArmor;
Game_Actor.prototype.hasArmor = function (armor) {
  if (this.hasBaseItem(armor)) return true;
  return Yanfly.Item.Game_Actor_hasArmor.call(this, armor);
};

Game_Actor.prototype.hasBaseItem = function (baseItem) {
  if (!DataManager.isIndependent(baseItem)) return false;
  var type = DataManager.isWeapon(baseItem) ? "weapon" : "armor";
  for (var i = 0; i < this.equips().length; ++i) {
    var equip = this.equips()[i];
    if (!equip) continue;
    if (!equip.baseItemId) continue;
    if (DataManager.isWeapon(equip) && type === "weapon") {
      if (equip.baseItemId === baseItem.id) return true;
    } else if (DataManager.isArmor(equip) && type === "armor") {
      if (equip.baseItemId === baseItem.id) return true;
    }
  }
  return false;
};

Yanfly.Item.Game_Actor_changeEquipById = Game_Actor.prototype.changeEquipById;
Game_Actor.prototype.changeEquipById = function (etypeId, itemId) {
  if (itemId > 0) {
    var slotId = etypeId - 1;
    if (this.equipSlots()[slotId] === 1) {
      var baseItem = $dataWeapons[itemId];
    } else {
      var baseItem = $dataArmors[itemId];
    }
    if (!$gameParty.hasItem(baseItem)) {
      $gameParty.gainItem(baseItem, 1);
    }
    if (DataManager.isIndependent(baseItem)) {
      if (this.hasBaseItem(baseItem)) return;
      var item = $gameParty.getMatchingBaseItem(baseItem, false);
      if (item === null) {
        $gameTemp.enableVarianceStock();
        $gameParty.gainItem(baseItem, 1);
        $gameTemp.disableVarianceStock();
        item = $gameParty.getMatchingBaseItem(baseItem, false);
      }
      this.changeEquip(slotId, item);
      return;
    }
  }
  Yanfly.Item.Game_Actor_changeEquipById.call(this, etypeId, itemId);
};

Game_Actor.prototype.unequipItem = function (item) {
  for (var i = 0; i < this.equips().length; ++i) {
    var equip = this.equips()[i];
    if (!equip) continue;
    if (equip !== item) continue;
    this.changeEquip(i, null);
  }
};

//=============================================================================
// Game_Party
//=============================================================================

Yanfly.Item.Game_Party_setupStartingMembers =
  Game_Party.prototype.setupStartingMembers;
Game_Party.prototype.setupStartingMembers = function () {
  Yanfly.Item.Game_Party_setupStartingMembers.call(this);
  $gameTemp.enableVarianceStock();
  this.initActorEquips();
  $gameTemp.disableVarianceStock();
};

Game_Party.prototype.initActorEquips = function () {
  $gameTemp._initializeStartingMemberEquipment = true;
  for (var i = 0; i < $dataActors.length; ++i) {
    var actor = $gameActors.actor(i);
    if (actor) {
      var baseActor = $dataActors[i];
      actor.initIndependentEquips(baseActor.equips);
    }
  }
  $gameTemp._initializeStartingMemberEquipment = undefined;
};

Yanfly.Item.Game_Party_gainItem = Game_Party.prototype.gainItem;
Game_Party.prototype.gainItem = function (item, amount, includeEquip) {
  if (DataManager.isIndependent(item)) {
    this.gainIndependentItem(item, amount, includeEquip);
  } else {
    Yanfly.Item.Game_Party_gainItem.call(this, item, amount, includeEquip);
  }
};

Game_Party.prototype.gainIndependentItem = function (
  item,
  amount,
  includeEquip
) {
  var arr = [];
  if (amount > 0) {
    for (var i = 0; i < amount; ++i) {
      var newItem = DataManager.registerNewItem(item);
      this.registerNewItem(item, newItem);
      arr.push(newItem);
    }
  } else if (amount < 0) {
    amount = Math.abs(amount);
    for (var i = 0; i < amount; ++i) {
      if (item.baseItemId) {
        this.removeIndependentItem(item, includeEquip);
      } else if (DataManager.isIndependent(item)) {
        var target = $gameParty.getMatchingBaseItem(item, includeEquip);
        if (target !== null) this.removeIndependentItem(target, includeEquip);
      } else {
        this.removeBaseItem(item, includeEquip);
      }
    }
  }
  return arr;
};

Game_Party.prototype.getIndependentItemTypeMax = function (item) {
  if (!item) return 0;
  if (DataManager.isItem(item)) return Yanfly.Param.ItemMaxItems;
  if (DataManager.isWeapon(item)) return Yanfly.Param.ItemMaxWeapons;
  if (DataManager.isArmor(item)) return Yanfly.Param.ItemMaxArmors;
};

Game_Party.prototype.getIndependentItemTypeCur = function (item) {
  if (!item) return 0;
  if (DataManager.isItem(item)) return this.items().length;
  if (DataManager.isWeapon(item)) return this.weapons().length;
  if (DataManager.isArmor(item)) return this.armors().length;
};

Game_Party.prototype.registerNewItem = function (baseItem, newItem) {
  var container = this.itemContainer(baseItem);
  if (container) {
    var lastNumber = this.numItems(newItem);
    container[newItem.id] = 1;
  }
};

Game_Party.prototype.removeIndependentItem = function (item, includeEquip) {
  if (includeEquip && this.checkItemIsEquipped(item)) {
    for (var i = 1; i < $gameActors._data.length; ++i) {
      var actor = $gameActors.actor(i);
      if (!actor) continue;
      if (!actor.equips().contains(item)) continue;
      actor.unequipItem(item);
    }
  }
  var container = this.itemContainer(item);
  container[item.id] = 0;
  if (container[item.id] <= 0) delete container[item.id];
};

Game_Party.prototype.removeBaseItem = function (item, includeEquip) {
  var container = this.itemContainer(item);
  container[item.id]--;
  if (container[item.id] <= 0) delete container[item.id];
  if (includeEquip) this.discardMembersEquip(item, -1);
};

Game_Party.prototype.getMatchingBaseItem = function (baseItem, equipped) {
  if (!baseItem) return null;
  if (DataManager.isItem(baseItem)) var group = this.items();
  if (DataManager.isWeapon(baseItem)) var group = this.weapons();
  if (DataManager.isArmor(baseItem)) var group = this.armors();
  if (equipped) {
    for (var a = 0; a < this.members().length; ++a) {
      var actor = this.members()[a];
      if (!actor) continue;
      group = group.concat(actor.equips());
    }
  }
  var baseItemId = baseItem.id;
  for (var i = 0; i < group.length; ++i) {
    var item = group[i];
    if (!item) continue;
    if (!item.baseItemId) continue;
    if (item.baseItemId !== baseItemId) continue;
    return item;
  }
  return null;
};

Game_Party.prototype.checkItemIsEquipped = function (item) {
  for (var i = 1; i < $gameActors._data.length; ++i) {
    var actor = $gameActors.actor(i);
    if (!actor) continue;
    if (actor.equips().contains(item)) return true;
  }
  return false;
};

Yanfly.Item.Game_Party_items = Game_Party.prototype.items;
Game_Party.prototype.items = function () {
  var results = Yanfly.Item.Game_Party_items.call(this);
  results.sort(this.independentItemSort);
  return results;
};

Yanfly.Item.Game_Party_weapons = Game_Party.prototype.weapons;
Game_Party.prototype.weapons = function () {
  var results = Yanfly.Item.Game_Party_weapons.call(this);
  results.sort(this.independentItemSort);
  return results;
};

Yanfly.Item.Game_Party_armors = Game_Party.prototype.armors;
Game_Party.prototype.armors = function () {
  var results = Yanfly.Item.Game_Party_armors.call(this);
  results.sort(this.independentItemSort);
  return results;
};

Game_Party.prototype.independentItemSort = function (a, b) {
  var aa = a.baseItemId ? a.baseItemId : a.id;
  var bb = b.baseItemId ? b.baseItemId : b.id;
  if (aa < bb) return -1;
  if (aa >= bb) return 1;
  return 0;
};

Yanfly.Item.Game_Party_maxItems = Game_Party.prototype.maxItems;
Game_Party.prototype.maxItems = function (item) {
  if (DataManager.isIndependent(item)) return 1;
  return Yanfly.Item.Game_Party_maxItems.call(this, item);
};

Yanfly.Item.Game_Party_hasItem = Game_Party.prototype.hasItem;
Game_Party.prototype.hasItem = function (item, includeEquip) {
  if (DataManager.isIndependent(item)) {
    if (this.numIndependentItems(item) > 0) return true;
  }
  return Yanfly.Item.Game_Party_hasItem.call(this, item, includeEquip);
};

Yanfly.Item.Game_Party_isAnyMemberEquipped =
  Game_Party.prototype.isAnyMemberEquipped;
Game_Party.prototype.isAnyMemberEquipped = function (item) {
  if (DataManager.isIndependent(item)) {
    for (var i = 0; i < this.members().length; ++i) {
      var actor = this.members()[i];
      if (!actor) continue;
      if (actor.hasBaseItem(item)) return true;
    }
  }
  return Yanfly.Item.Game_Party_isAnyMemberEquipped.call(this, item);
};

Game_Party.prototype.numIndependentItems = function (baseItem) {
  var value = 0;
  if (!DataManager.isIndependent(baseItem)) return this.numItems(baseItem);
  var id = baseItem.id;
  if (DataManager.isItem(baseItem)) var group = this.items();
  if (DataManager.isWeapon(baseItem)) var group = this.weapons();
  if (DataManager.isArmor(baseItem)) var group = this.armors();
  for (var i = 0; i < group.length; ++i) {
    var item = group[i];
    if (!item) continue;
    if (item.baseItemId && item.baseItemId === id) value += 1;
  }
  return value;
};

//=============================================================================
// Game_Interpreter
//=============================================================================

Yanfly.Item.Game_Interpreter_pluginCommand =
  Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function (command, args) {
  Yanfly.Item.Game_Interpreter_pluginCommand.call(this, command, args);
  if (command === "EnableVarianceStock") $gameTemp.enableVarianceStock();
  if (command === "DisableVarianceStock") $gameTemp.disableVarianceStock();
};

Yanfly.Item.Game_Interpreter_gDO = Game_Interpreter.prototype.gameDataOperand;
Game_Interpreter.prototype.gameDataOperand = function (type, param1, param2) {
  switch (type) {
    case 0:
      return $gameParty.numIndependentItems($dataItems[param1]);
      break;
    case 1:
      return $gameParty.numIndependentItems($dataWeapons[param1]);
      break;
    case 2:
      return $gameParty.numIndependentItems($dataArmors[param1]);
      break;
    default:
      return Yanfly.Item.Game_Interpreter_gDO.call(this, type, param1, param2);
      break;
  }
};

//=============================================================================
// Window_Base
//=============================================================================

Yanfly.Item.Window_Base_drawItemName = Window_Base.prototype.drawItemName;
Window_Base.prototype.drawItemName = function (item, wx, wy, ww) {
  ww = ww || 312;
  this.setItemTextColor(item);
  Yanfly.Item.Window_Base_drawItemName.call(this, item, wx, wy, ww);
  this._resetTextColor = undefined;
  this.resetTextColor();
};

Window_Base.prototype.setItemTextColor = function (item) {
  if (!item) return;
  if (item.textColor === undefined) return;
  this._resetTextColor = item.textColor;
};

Yanfly.Item.Window_Base_normalColor = Window_Base.prototype.normalColor;
Window_Base.prototype.normalColor = function () {
  if (this._resetTextColor !== undefined) {
    return this.textColor(this._resetTextColor);
  }
  return Yanfly.Item.Window_Base_normalColor.call(this);
};

//=============================================================================
// Window_ItemList
//=============================================================================

Yanfly.Item.Window_ItemList_makeItemList =
  Window_ItemList.prototype.makeItemList;
Window_ItemList.prototype.makeItemList = function () {
  Yanfly.Item.Window_ItemList_makeItemList.call(this);
  if (SceneManager._scene instanceof Scene_Item) this.listEquippedItems();
};

Window_ItemList.prototype.listEquippedItems = function () {
  if (!eval(Yanfly.Param.ItemShEquipped)) return;
  var results = [];
  for (var a = 0; a < $gameParty.members().length; ++a) {
    var actor = $gameParty.members()[a];
    if (!actor) continue;
    for (var i = 0; i < actor.equips().length; ++i) {
      var equip = actor.equips()[i];
      if (!equip) continue;
      if (!equip.baseItemId) continue;
      if (this.includes(equip)) results.push(equip);
    }
  }
  this._data = results.concat(this._data);
};

Yanfly.Item.Window_ItemList_drawItemNumber =
  Window_ItemList.prototype.drawItemNumber;
Window_ItemList.prototype.drawItemNumber = function (item, dx, dy, dw) {
  if (DataManager.isIndependent(item)) {
    this.drawItemCarryNumber(item, dx, dy, dw);
    return;
  }
  Yanfly.Item.Window_ItemList_drawItemNumber.call(this, item, dx, dy, dw);
};

Window_ItemList.prototype.drawItemCarryNumber = function (item, dx, dy, dw) {
  if (DataManager.isItem(item)) {
    var index = $gameParty.items().indexOf(item);
  } else if (DataManager.isWeapon(item)) {
    var index = $gameParty.weapons().indexOf(item);
  } else if (DataManager.isArmor(item)) {
    var index = $gameParty.armors().indexOf(item);
  }
  if (index < 0) return this.drawEquippedActor(item, dx, dy, dw);
  index += 1;
  var max = $gameParty.getIndependentItemTypeMax(item);
  var fmt = Yanfly.Param.ItemCarryFmt;
  var text = fmt.format(Yanfly.Util.toGroup(index), Yanfly.Util.toGroup(max));
  if (Yanfly.Param.ItemQuantitySize) {
    this.contents.fontSize = Yanfly.Param.ItemQuantitySize;
  }
  if (index > max) {
    this.changeTextColor(this.powerDownColor());
  } else if (index === max) {
    this.changeTextColor(this.crisisColor());
  } else {
    this.changeTextColor(this.normalColor());
  }
  this.drawText(text, dx, dy, dw, "right");
  this.resetFontSettings();
};

Window_ItemList.prototype.drawEquippedActor = function (item, dx, dy, dw) {
  var carrier = null;
  for (var a = 0; a < $gameParty.members().length; ++a) {
    var actor = $gameParty.members()[a];
    if (!actor) continue;
    if (actor.equips().contains(item)) carrier = actor;
  }
  if (Yanfly.Param.ItemQuantitySize) {
    this.contents.fontSize = Yanfly.Param.ItemQuantitySize;
  }
  var text = carrier.name();
  this.drawText(text, dx, dy, dw, "right");
  this.resetFontSettings();
};

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

Yanfly.Item.Window_EquipItem_includes = Window_EquipItem.prototype.includes;
Window_EquipItem.prototype.includes = function (item) {
  if (this._actor && item !== null) {
    if (!item) return false;
  }
  return Yanfly.Item.Window_EquipItem_includes.call(this, item);
};

//=============================================================================
// Window_ShopBuy
//=============================================================================

Yanfly.Item.Window_ShopBuy_isEnabled = Window_ShopBuy.prototype.isEnabled;
Window_ShopBuy.prototype.isEnabled = function (item) {
  if (DataManager.isIndependent(item)) {
    var typeMax = $gameParty.getIndependentItemTypeMax(item);
    var typeCur = $gameParty.getIndependentItemTypeCur(item);
    if (typeCur >= typeMax) return false;
  }
  return Yanfly.Item.Window_ShopBuy_isEnabled.call(this, item);
};

//=============================================================================
// Window_ShopStatus
//=============================================================================

Yanfly.Item.Window_ShopStatus_drawPossession =
  Window_ShopStatus.prototype.drawPossession;
Window_ShopStatus.prototype.drawPossession = function (x, y) {
  if (DataManager.isIndependent(this._item)) {
    return this.drawIndependentPossession(x, y);
  }
  Yanfly.Item.Window_ShopStatus_drawPossession.call(this, x, y);
};

Window_ShopStatus.prototype.drawIndependentPossession = function (x, y) {
  var width = this.contents.width - this.textPadding() - x;
  var baseItem = DataManager.getBaseItem(this._item);
  var value = $gameParty.numIndependentItems(baseItem);
  value = Yanfly.Util.toGroup(value);
  var possessionWidth = this.textWidth(value);
  this.changeTextColor(this.systemColor());
  this.drawText(TextManager.possession, x, y, width - possessionWidth);
  this.resetTextColor();
  this.drawText(value, x, y, width, "right");
};

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

Yanfly.Item.Scene_Equip_refreshActor = Scene_Equip.prototype.refreshActor;
Scene_Equip.prototype.refreshActor = function () {
  this.actor().releaseUnequippableItems();
  Yanfly.Item.Scene_Equip_refreshActor.call(this);
};

//=============================================================================
// Scene_Shop
//=============================================================================

Yanfly.Item.Scene_Shop_doBuy = Scene_Shop.prototype.doBuy;
Scene_Shop.prototype.doBuy = function (number) {
  $gameTemp.enableVarianceStock();
  Yanfly.Item.Scene_Shop_doBuy.call(this, number);
  $gameTemp.disableVarianceStock();
};

Yanfly.Item.Scene_Shop_doSell = Scene_Shop.prototype.doSell;
Scene_Shop.prototype.doSell = function (number) {
  Yanfly.Item.Scene_Shop_doSell.call(this, number);
  if (!DataManager.isIndependent(this._item)) return;
  DataManager.removeIndependentItem(this._item);
};

//=============================================================================
// Scene_Item Update
//=============================================================================

if (eval(Yanfly.Param.ItemSceneItem)) {
  //=============================================================================
  // Window_ItemCategory
  //=============================================================================

  Yanfly.Item.Window_ItemCategory_windowWidth =
    Window_ItemCategory.prototype.windowWidth;
  Window_ItemCategory.prototype.windowWidth = function () {
    if (SceneManager._scene instanceof Scene_Item) return 240;
    return Yanfly.Item.Window_ItemCategory_windowWidth.call(this);
  };

  Yanfly.Item.Window_ItemCategory_numVisibleRows =
    Window_ItemCategory.prototype.numVisibleRows;
  Window_ItemCategory.prototype.numVisibleRows = function () {
    if (SceneManager._scene instanceof Scene_Item) return 4;
    return Yanfly.Item.Window_ItemCategory_numVisibleRows.call(this);
  };

  Yanfly.Item.Window_ItemCategory_maxCols =
    Window_ItemCategory.prototype.maxCols;
  Window_ItemCategory.prototype.maxCols = function () {
    if (SceneManager._scene instanceof Scene_Item) return 1;
    return Yanfly.Item.Window_ItemCategory_maxCols.call(this);
  };

  Yanfly.Item.Window_ItemCategory_itemTextAlign =
    Window_ItemCategory.prototype.itemTextAlign;
  Window_ItemCategory.prototype.itemTextAlign = function () {
    if (SceneManager._scene instanceof Scene_Item) {
      return Yanfly.Param.ItemCmdAlign;
    }
    return Yanfly.Item.Window_ItemCategory_itemTextAlign.call(this);
  };

  //=============================================================================
  // Window_ItemList
  //=============================================================================

  Yanfly.Item.Window_ItemList_initialize = Window_ItemList.prototype.initialize;
  Window_ItemList.prototype.initialize = function (x, y, width, height) {
    if (SceneManager._scene instanceof Scene_Item) {
      width = Graphics.boxWidth / 2;
    }
    Yanfly.Item.Window_ItemList_initialize.call(this, x, y, width, height);
  };

  Yanfly.Item.Window_ItemList_maxCols = Window_ItemList.prototype.maxCols;
  Window_ItemList.prototype.maxCols = function () {
    if (SceneManager._scene instanceof Scene_Item) return 1;
    return Yanfly.Item.Window_ItemList_maxCols.call(this);
  };

  Yanfly.Item.Window_ItemList_isEnabled = Window_ItemList.prototype.isEnabled;
  Window_ItemList.prototype.isEnabled = function (item) {
    if (!item) return false;
    if (SceneManager._scene instanceof Scene_Item) return true;
    return Yanfly.Item.Window_ItemList_isEnabled.call(this, item);
  };

  Window_ItemList.prototype.setStatusWindow = function (statusWindow) {
    this._statusWindow = statusWindow;
    this.update();
  };

  Window_ItemList.prototype.setInfoWindow = function (infoWindow) {
    this._infoWindow = infoWindow;
    this.update();
  };

  Yanfly.Item.Window_ItemList_updateHelp = Window_ItemList.prototype.updateHelp;
  Window_ItemList.prototype.updateHelp = function () {
    Yanfly.Item.Window_ItemList_updateHelp.call(this);
    if (SceneManager._scene instanceof Scene_Item && this._statusWindow) {
      this._statusWindow.setItem(this.item());
    }
    if (SceneManager._scene instanceof Scene_Item && this._infoWindow) {
      this._infoWindow.setItem(this.item());
    }
  };

  //=============================================================================
  // Window_ItemStatus
  //=============================================================================

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

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

  Window_ItemStatus.prototype.initialize = function (x, y, width, height) {
    Window_Base.prototype.initialize.call(this, x, y, width, height);
    this._item = null;
    this.deactivate();
    this.refresh();
  };

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

  Window_ItemStatus.prototype.refresh = function () {
    this.contents.clear();
    this.drawDarkRectEntries();
    if (!this._item) return;
    this.contents.fontSize = Yanfly.Param.ItemFontSize;
    this.drawItemEntry();
  };

  Window_ItemStatus.prototype.drawDarkRectEntries = function () {
    var rect = new Rectangle();
    if (eval(Yanfly.Param.ItemShowIcon)) {
      rect.width = Window_Base._faceWidth;
      rect.height = Window_Base._faceHeight;
      this.drawDarkRect(rect.x, rect.y, rect.width, rect.height);
      rect.width = (this.contents.width - Window_Base._faceWidth) / 2;
    } else {
      rect.width = this.contents.width / 2;
    }
    rect.height = this.lineHeight();
    for (var i = 0; i < 8; ++i) {
      rect = this.getRectPosition(rect, i);
      this.drawDarkRect(rect.x, rect.y, rect.width, rect.height);
    }
  };

  Window_ItemStatus.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_ItemStatus.prototype.getRectPosition = function (rect, i) {
    if (i % 2 === 0) {
      if (eval(Yanfly.Param.ItemShowIcon)) {
        rect.x = Window_Base._faceWidth;
      } else {
        rect.x = 0;
      }
      rect.y = (i / 2) * this.lineHeight();
    } else {
      if (eval(Yanfly.Param.ItemShowIcon)) {
        rect.x = Window_Base._faceWidth + rect.width;
      } else {
        rect.x = rect.width;
      }
    }
    return rect;
  };

  Window_ItemStatus.prototype.drawItemEntry = function () {
    var item = this._item;
    if (eval(Yanfly.Param.ItemShowIcon)) this.drawItemIcon(item);
    if (DataManager.isItem(item)) this.drawItemInfo(item);
    if (DataManager.isWeapon(item)) this.drawEquipInfo(item);
    if (DataManager.isArmor(item)) this.drawEquipInfo(item);
  };

  Window_ItemStatus.prototype.drawItemIcon = function () {
    this.drawLargeIcon();
  };

  Window_ItemStatus.prototype.drawLargeIcon = function () {
    var iconIndex = this._item.iconIndex;
    var bitmap = ImageManager.loadSystem("IconSet");
    var pw = Window_Base._iconWidth;
    var ph = Window_Base._iconHeight;
    var sx = (iconIndex % 16) * pw;
    var sy = Math.floor(iconIndex / 16) * ph;
    var dw = Yanfly.Param.ItemIconSize;
    var dh = Yanfly.Param.ItemIconSize;
    var dx = (Window_Base._faceWidth - dw) / 2;
    var dy = (Window_Base._faceHeight - dh) / 2;
    this.contents._context.imageSmoothingEnabled = false;
    this.contents.blt(bitmap, sx, sy, pw, ph, dx, dy, dw, dh);
    this.contents._context.imageSmoothingEnabled = true;
  };

  Window_ItemStatus.prototype.drawEquipInfo = function (item) {
    var rect = new Rectangle();
    if (eval(Yanfly.Param.ItemShowIcon)) {
      rect.width = (this.contents.width - Window_Base._faceWidth) / 2;
    } else {
      rect.width = this.contents.width / 2;
    }
    for (var i = 0; i < 8; ++i) {
      rect = this.getRectPosition(rect, i);
      var dx = rect.x + this.textPadding();
      var dw = rect.width - this.textPadding() * 2;
      this.changeTextColor(this.systemColor());
      this.drawText(TextManager.param(i), dx, rect.y, dw);
      this.changeTextColor(this.paramchangeTextColor(item.params[i]));
      var text = Yanfly.Util.toGroup(item.params[i]);
      if (item.params[i] >= 0) text = "+" + text;
      if (text === "+0") this.changePaintOpacity(false);
      this.drawText(text, dx, rect.y, dw, "right");
      this.changePaintOpacity(true);
    }
  };

  Window_ItemStatus.prototype.drawItemInfo = function (item) {
    var rect = new Rectangle();
    if (eval(Yanfly.Param.ItemShowIcon)) {
      rect.width = (this.contents.width - Window_Base._faceWidth) / 2;
    } else {
      rect.width = this.contents.width / 2;
    }
    for (var i = 0; i < 8; ++i) {
      rect = this.getRectPosition(rect, i);
      var dx = rect.x + this.textPadding();
      var dw = rect.width - this.textPadding() * 2;
      this.changeTextColor(this.systemColor());
      var text = this.getItemInfoCategory(i);
      this.drawText(text, dx, rect.y, dw);
      this.drawItemData(i, dx, rect.y, dw);
    }
  };

  Window_ItemStatus.prototype.getItemInfoCategory = function (i) {
    var fmt = Yanfly.Param.ItemRecoverFmt;
    if (i === 0) return fmt.format(TextManager.param(0));
    if (i === 1) return fmt.format(TextManager.hp);
    if (i === 2) return fmt.format(TextManager.param(1));
    if (i === 3) return fmt.format(TextManager.mp);
    if (i === 4) return Yanfly.Param.ItemAddState;
    if (i === 5) return Yanfly.Param.ItemRemoveState;
    if (i === 6) return Yanfly.Param.ItemAddBuff;
    if (i === 7) return Yanfly.Param.ItemRemoveBuff;
    return "";
  };

  Window_ItemStatus.prototype.drawItemData = function (i, dx, dy, dw) {
    if (!this._item) return;
    var effect;
    var value = "---";
    var pre = "";
    var text = "";
    var icons = [];
    if (i === 0) {
      effect = this.getEffect(Game_Action.EFFECT_RECOVER_HP);
      value = effect ? effect.value1 : "---";
      if (value === 0) value = "---";
      if (value !== "---" && value !== 0) value *= 100;
    }
    if (i === 1) {
      effect = this.getEffect(Game_Action.EFFECT_RECOVER_HP);
      value = effect ? effect.value2 : "---";
      if (value === 0) value = "---";
    }
    if (i === 2) {
      effect = this.getEffect(Game_Action.EFFECT_RECOVER_MP);
      value = effect ? effect.value1 : "---";
      if (value === 0) value = "---";
      if (value !== "---" && value !== 0) value *= 100;
    }
    if (i === 3) {
      effect = this.getEffect(Game_Action.EFFECT_RECOVER_MP);
      value = effect ? effect.value2 : "---";
      if (value === 0) value = "---";
    }
    if (i >= 4) {
      icons = this.getItemIcons(i, icons);
    }
    this.changeTextColor(this.normalColor());
    if (value === "---") {
      this.changePaintOpacity(false);
    } else if (i < 4) {
      if (value > 0) pre = "+";
      value = Yanfly.Util.toGroup(parseInt(value));
      if ([0, 2].contains(i)) text = "%";
    }
    if (icons.length > 0) {
      this.changePaintOpacity(true);
      dx = dx + dw - icons.length * Window_Base._iconWidth;
      dx += this.textPadding() - 2;
      for (var j = 0; j < icons.length; ++j) {
        var icon = icons[j];
        this.drawIcon(icon, dx, dy + 2);
        dx += Window_Base._iconWidth;
      }
    } else {
      text = pre + value + text;
      this.drawText(text, dx, dy, dw, "right");
      this.changePaintOpacity(true);
    }
  };

  Window_ItemStatus.prototype.getEffect = function (code) {
    var targetEffect;
    this._item.effects.forEach(function (effect) {
      if (effect.code === code) targetEffect = effect;
    }, this);
    return targetEffect;
  };

  Window_ItemStatus.prototype.getItemIcons = function (i, array) {
    this._item.effects.forEach(function (effect) {
      if (i === 4 && effect.code === Game_Action.EFFECT_ADD_STATE) {
        var state = $dataStates[effect.dataId];
        if (state && state.iconIndex !== 0) array.push(state.iconIndex);
      }
      if (i === 5 && effect.code === Game_Action.EFFECT_REMOVE_STATE) {
        var state = $dataStates[effect.dataId];
        if (state && state.iconIndex !== 0) array.push(state.iconIndex);
      }
      if (i === 6 && effect.code === Game_Action.EFFECT_ADD_BUFF) {
        var icon = Game_BattlerBase.ICON_BUFF_START + effect.dataId;
        array.push(icon);
      }
      if (i === 6 && effect.code === Game_Action.EFFECT_ADD_DEBUFF) {
        var icon = Game_BattlerBase.ICON_DEBUFF_START + effect.dataId;
        array.push(icon);
      }
      if (i === 7 && effect.code === Game_Action.EFFECT_REMOVE_BUFF) {
        var icon = Game_BattlerBase.ICON_BUFF_START + effect.dataId;
        array.push(icon);
      }
      if (i === 7 && effect.code === Game_Action.EFFECT_REMOVE_DEBUFF) {
        var icon = Game_BattlerBase.ICON_DEBUFF_START + effect.dataId;
        array.push(icon);
      }
    }, this);
    array = array.slice(0, Yanfly.Param.ItemMaxIcons);
    return array;
  };

  //=============================================================================
  // Window_ItemInfo
  //=============================================================================

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

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

  Window_ItemInfo.prototype.initialize = function (x, y, width, height) {
    Window_Base.prototype.initialize.call(this, x, y, width, height);
    this._item = null;
    this.deactivate();
    this.refresh();
  };

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

  Window_ItemInfo.prototype.refresh = function () {
    this.contents.clear();
    var dy = 0;
    if (!this._item) return dy;
    this.preInfoEval();
    dy = this.drawPreItemInfo(dy);
    dy = this.drawItemInfo(dy);
    dy = this.drawItemInfoA(dy);
    dy = this.drawItemInfoB(dy);
    dy = this.drawItemInfoC(dy);
    dy = this.drawItemInfoD(dy);
    dy = this.drawItemInfoE(dy);
    return this.drawItemInfoF(dy);
  };

  Window_ItemInfo.prototype.preInfoEval = function () {
    var item = this._item;
    if (item.infoEval === undefined) {
      item.infoEval = DataManager.getBaseItem(item).infoEval;
    }
    if (item.infoEval === "") return;
    var weapon = this._item;
    var armor = this._item;
    var s = $gameSwitches._data;
    var v = $gameVariables._data;
    eval(item.infoEval);
  };

  Window_ItemInfo.prototype.drawPreItemInfo = function (dy) {
    return dy;
  };

  Window_ItemInfo.prototype.drawItemInfo = function (dy) {
    var dx = this.textPadding();
    var dw = this.contents.width - this.textPadding() * 2;
    this.resetFontSettings();
    this.drawItemName(this._item, dx, dy, dw);
    return dy + this.lineHeight();
  };

  Window_ItemInfo.prototype.drawItemInfoA = function (dy) {
    dy = this.drawInfoTextTop(dy);
    return dy;
  };

  Window_ItemInfo.prototype.drawItemInfoB = function (dy) {
    return dy;
  };

  Window_ItemInfo.prototype.drawItemInfoC = function (dy) {
    return dy;
  };

  Window_ItemInfo.prototype.drawItemInfoD = function (dy) {
    return dy;
  };

  Window_ItemInfo.prototype.drawItemInfoE = function (dy) {
    return dy;
  };

  Window_ItemInfo.prototype.drawItemInfoF = function (dy) {
    dy = this.drawInfoTextBottom(dy);
    return dy;
  };

  Window_ItemInfo.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_ItemInfo.prototype.drawInfoTextTop = function (dy) {
    var item = this._item;
    if (item.infoTextTop === undefined) {
      item.infoTextTop = DataManager.getBaseItem(item).infoTextTop;
    }
    if (item.infoTextTop === "") return dy;
    var info = item.infoTextTop.split(/[\r\n]+/);
    for (var i = 0; i < info.length; ++i) {
      var line = info[i];
      this.drawTextEx(line, this.textPadding(), dy);
      dy += this.lineHeight();
    }
    return dy;
  };

  Window_ItemInfo.prototype.drawInfoTextBottom = function (dy) {
    var item = this._item;
    if (item.infoTextBottom === undefined) {
      item.infoTextBottom = DataManager.getBaseItem(item).infoTextBottom;
    }
    if (item.infoTextBottom === "") return dy;
    var info = item.infoTextBottom.split(/[\r\n]+/);
    for (var i = 0; i < info.length; ++i) {
      var line = info[i];
      this.drawTextEx(line, this.textPadding(), dy);
      dy += this.lineHeight();
    }
    return dy;
  };

  //=============================================================================
  // Window_ItemActionCommand
  //=============================================================================

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

  Window_ItemActionCommand.prototype = Object.create(Window_Command.prototype);
  Window_ItemActionCommand.prototype.constructor = Window_ItemActionCommand;

  Window_ItemActionCommand.prototype.initialize = function (x, y) {
    this._windowHeight = Graphics.boxHeight - y;
    Window_Command.prototype.initialize.call(this, x, y);
    this._item = null;
    this.hide();
    this.deactivate();
  };

  Window_ItemActionCommand.prototype.windowWidth = function () {
    return Graphics.boxWidth / 2;
  };

  Window_ItemActionCommand.prototype.setItem = function (item) {
    this._item = item;
    this.refresh();
    this.show();
    this.activate();
    this.select(0);
  };

  Window_ItemActionCommand.prototype.windowHeight = function () {
    return this._windowHeight;
  };

  Window_ItemActionCommand.prototype.makeCommandList = function () {
    if (!this._item) return;
    this.addUseCommand();
    this.addCustomCommandsA();
    this.addCustomCommandsB();
    this.addCustomCommandsC();
    this.addCustomCommandsD();
    this.addCustomCommandsE();
    this.addCustomCommandsF();
    this.addCancelCommand();
  };

  Window_ItemActionCommand.prototype.addUseCommand = function () {
    var enabled = this.isEnabled(this._item);
    var fmt = Yanfly.Param.ItemUseCmd;
    text = "\\i[" + this._item.iconIndex + "]";
    if (this._item.textColor !== undefined) {
      text += "\\c[" + this._item.textColor + "]";
    }
    text += this._item.name;
    text = fmt.format(text);
    this.addCommand(text, "use", enabled);
  };

  Window_ItemActionCommand.prototype.isEnabled = function (item) {
    if (!item) return false;
    return $gameParty.canUse(item);
  };

  Window_ItemActionCommand.prototype.addCustomCommandsA = function () {};

  Window_ItemActionCommand.prototype.addCustomCommandsB = function () {};

  Window_ItemActionCommand.prototype.addCustomCommandsC = function () {};

  Window_ItemActionCommand.prototype.addCustomCommandsD = function () {};

  Window_ItemActionCommand.prototype.addCustomCommandsE = function () {};

  Window_ItemActionCommand.prototype.addCustomCommandsF = function () {};

  Window_ItemActionCommand.prototype.addCancelCommand = function () {
    this.addCommand(TextManager.cancel, "cancel");
  };

  Window_ItemActionCommand.prototype.drawItem = function (index) {
    var rect = this.itemRectForText(index);
    var align = this.itemTextAlign();
    this.resetTextColor();
    this.changePaintOpacity(this.isCommandEnabled(index));
    this.drawTextEx(this.commandName(index), rect.x, rect.y);
  };

  //=============================================================================
  // Scene_Item
  //=============================================================================

  Yanfly.Item.Scene_Item_createItemWindow =
    Scene_Item.prototype.createItemWindow;
  Scene_Item.prototype.createItemWindow = function () {
    Yanfly.Item.Scene_Item_createItemWindow.call(this);
    this.createStatusWindow();
    this.createInfoWindow();
    this.createActionWindow();
    this._categoryWindow.setHandler("cancel", this.exitScene.bind(this));
  };

  Scene_Item.prototype.createStatusWindow = function () {
    var wx = this._categoryWindow.width;
    var wy = this._helpWindow.height;
    var ww = Graphics.boxWidth - wx;
    var wh = this._categoryWindow.height;
    this._statusWindow = new Window_ItemStatus(wx, wy, ww, wh);
    this._itemWindow.setStatusWindow(this._statusWindow);
    this.addWindow(this._statusWindow);
  };

  Scene_Item.prototype.createInfoWindow = function () {
    var wx = this._itemWindow.width;
    var wy = this._itemWindow.y;
    var ww = Graphics.boxWidth - wx;
    var wh = this._itemWindow.height;
    this._infoWindow = new Window_ItemInfo(wx, wy, ww, wh);
    this._itemWindow.setInfoWindow(this._infoWindow);
    this.addWindow(this._infoWindow);
  };

  Scene_Item.prototype.createActionWindow = function () {
    var wy = this._itemWindow.y;
    this._itemActionWindow = new Window_ItemActionCommand(0, wy);
    this._itemActionWindow.setHandler("use", this.onActionUse.bind(this));
    this._itemActionWindow.setHandler("cancel", this.onActionCancel.bind(this));
    this.addWindow(this._itemActionWindow);
  };

  Scene_Item.prototype.isCursorLeft = function () {
    return true;
  };

  Scene_Item.prototype.onItemOk = function () {
    var item = this.item();
    this._itemActionWindow.setItem(item);
  };

  Yanfly.Item.Scene_Item_onItemCancel = Scene_Item.prototype.onItemCancel;
  Scene_Item.prototype.onItemCancel = function () {
    Yanfly.Item.Scene_Item_onItemCancel.call(this);
    this._statusWindow.setItem(null);
    this._infoWindow.setItem(null);
  };

  Scene_Item.prototype.onActionUse = function () {
    this._itemActionWindow.hide();
    this._itemActionWindow.deactivate();
    $gameParty.setLastItem(this.item());
    this.determineItem();
  };

  Scene_Item.prototype.onActionCancel = function () {
    this._itemActionWindow.hide();
    this._itemActionWindow.deactivate();
    this._itemWindow.activate();
  };

  Yanfly.Item.Scene_Item_applyItem = Scene_Item.prototype.applyItem;
  Scene_Item.prototype.applyItem = function () {
    Yanfly.Item.Scene_Item_applyItem.call(this);
    if (DataManager.isIndependent(this.item())) this.onActorCancel();
  };

  Scene_Item.prototype.exitScene = function () {
    var length = $gameParty.members().length;
    for (var i = 0; i < length; ++i) {
      var member = $gameParty.members()[i];
      if (member) member.refresh();
    }
    this.popScene();
  };

  //=============================================================================
  // Scene_Item Update
  //=============================================================================
} // End Scene_Item

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

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

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

//=============================================================================
// End of File
//=============================================================================