//=============================================================================
/*:
* @plugindesc v1.08 物品合成系统
* @author Yanfly Engine Plugins
*
* @param ---General---
* @default
*
* @param Synthesis Command
* @desc This is the text used for going to the item synthesis menu.
* @default Synthesis
*
* @param Show Command
* @desc Show the Synthesis command in the main menu by default?
* NO - false YES - true
* @default true
*
* @param Enable Command
* @desc Enable the Synthesis command in the main menu by default?
* NO - false YES - true
* @default true
*
* @param Auto Place Command
* @desc Allow this plugin to decide the menu placement position?
* NO - false YES - true
* @default true
*
* @param ---Command Window---
* @default
*
* @param Item Command
* @desc The command text used for synthesizing items.
* @default Craft Item
*
* @param Weapon Command
* @desc The command text used for synthesizing weapons.
* @default Craft Weapon
*
* @param Armor Command
* @desc The command text used for synthesizing armors.
* @default Craft Armor
*
* @param Finish Command
* @desc The command text used for exiting the synthesis scene.
* @default Finish
*
* @param Text Alignment
* @desc How to align the text for the command window.
* left center right
* @default center
*
* @param ---Status Window---
* @default
*
* @param Collected Recipes
* @desc Text used to represent total recipes collected.
* Leave this blank if you don't wish to show this.
* @default Collected Recipes
*
* @param Crafted Items
* @desc Text used to represent total items crafted.
* Leave this blank if you don't wish to show this.
* @default Crafted Items
*
* @param Crafted Weapons
* @desc Text used to represent total weapons crafted.
* Leave this blank if you don't wish to show this.
* @default Crafted Weapons
*
* @param Crafted Armors
* @desc Text used to represent total armors crafted.
* Leave this blank if you don't wish to show this.
* @default Crafted Armors
*
* @param ---List Window---
* @default
*
* @param Equipped Recipes
* @desc Check recipes from equipped items?
* NO - false YES - true
* @default true
*
* @param Mask Unknown
* @desc Mask the names of items that haven't been created yet?
* NO - false YES - true
* @default true
*
* @param Mask Text
* @desc This will be used to mask over each letter for unknown item
* names that are to be synthesized.
* @default ?
*
* @param Mask Italic
* @desc Causes the name for unknown items to appear in italic.
* @default true
*
* @param Mask Help Text
* @desc This is the text that will be displayed in the help window
* if the item is masked.
* @default This item has not been synthesized yet.
*
* @param Ingredients Text
* @desc This is the text used to describe the Ingredients list.
* @default Ingredients
*
* @param Amount Text
* @desc This is the text used for the amount to synthesize.
* @default Quantity
*
* @param Quantity Text Size
* @desc This is the text size used for the item quantity.
* Default: 28
* @default 20
*
* @param ---Sound---
* @default
*
* @param Default SE
* @desc This is the default SE played when synthesizing an item.
* This is case sensitive. Do not include the extension.
* @default Twine
*
* @param Default Volume
* @desc This is the default volume when synthesizing an item.
* @default 100
*
* @param Default Pitch
* @desc This is the default pitch when synthesizing an item.
* @default 100
*
* @param Default Pan
* @desc This is the default pan when synthesizing an item.
* @default 0
*
* @help
* ============================================================================
* Introduction
* ============================================================================
*
* 物品合成系统是大多数角色扮演游戏常见的方面,玩家可以通过制作书合成他们自
* 己的物品。这个插件让玩家实现这个功能。制作书可以涉及物品,武器或者装备,
* 并且可以合成物品,武器或者装备。这些物品可以从主菜单或者合成菜单制作。
*
* ============================================================================
* Notetags
* ============================================================================
*
* 为了让玩家打造出某个物品,这些物品必须拥有制作书的标签
*
* Item, Weapon, and Armor Notetags:
* <Item Recipe: x>
* <Item Recipe: x, x, x>
* <Item Recipe: x to y>
* 在数据库建立名为制作书的物品,备注放入这些标签,例如:
* <Item Recipe: 41, 42, 43> 表示ID为41、42、43的物品可以合成。
* 前提是你必须在游戏中得到这个制作书。武器和防具例同。
* 注意:没有名字的条目,以及没有合成消耗和合成原料列表的条目都不会参与合成
*
* <Weapon Recipe: x>
* <Weapon Recipe: x, x, x>
* <Weapon Recipe: x to y>
* 可以把这些武器放入制作书,只要队伍拥有这个武器,他就可以被玩家和其他原料
* 一起合成
* 注意:没有名字的条目,以及没有合成消耗和合成原料列表的条目都不会参与合成
*
* <Armor Recipe: x>
* <Armor Recipe: x, x, x>
* <Armor Recipe: x to y>
* 可以把这些装备放入制作书,只要队伍拥有这个装备,他就可以被玩家和其他原料
* 一起合成
* 注意:没有名字的条目,以及没有合成消耗和合成原料列表的条目都不会参与合成
*
* <Synthesis Ingredients>
* item id 物品ID例如:item 40 表示需要ID为40的物品1个。
* item id: x 需要的数量例如:item 40: 3 表示ID为40的物品需要3个。
* weapon id
* weapon id: x
* armor id
* armor id: x
* gold: x
* named item
* named item: x
* </Synthesis Ingredients>
* 使用这个标签,可以让物品通过这些原料合成。替代ID即可。如果没有指定ID,数
* 据库认为只需要任何一件物品作为原料即可。如果金钱被指定,则需要消耗如此数
* 量金钱来合成物品
*
* 如果你使用名字,则会优先使用ID最高的
*
* 注意:如果你使用了物品核心插件。独立物品不能成为合成原料,将会自动被漏掉
*
* <Mask Name: x>
* 如果你伪装了物品名字,你可以改变物品显示的文本。这将造成游戏采用伪装名代
* 替平时使用的。这可以让玩家生成他们想要的合成品例如“奇异水”或者“特殊水
* 晶”等
*
* ============================================================================
* Lunatic Mode - Custom Synthesis Effects
* ============================================================================
*
* For those with a JavaScript experience, you can use these notetags to make
* a custom effect that will occur when a specific item is synthesized. For
* example, when a Potion is made, you can give the player an empty bottle as a
* side product of the synthesis.
*
* ---
*
* Item, Weapon, and Armor Notetags:
*
* <Custom Synthesis Effect>
* var bottle = $dataItems[123];
* $gameParty.gainItem(bottle, 2);
* </Custom Synthesis Effect>
*
* For this notetag, the 'item' variable will refer to the item being
* synthesized. Changing it will do nothing but it will be used as a
* convenience variable to refer to it.
*
* ---
*
* ============================================================================
* Plugin Commands
* ============================================================================
*
* 下面的插件命令可以使用在事件里面
*
* Plugin Command:
* OpenSynthesis 打开合成界面
* ShowSynthesis 主菜单显示合成命令
* HideSynthesis 主菜单隐藏合成命令
* EnableSynthesis 开启主菜单合成命令
* DisableSynthesis 关闭主菜单合成命令
*
* For those who wish to make the player synthesize only specific recipes, you
* can use the following command.
*
* OpenSynthesis Item 15 Recipe
* - or -
* OpenSynthesis Weapon 20 Recipe
* - or -
* OpenSynthesis Armor 30 Recipe
*
* This will make the synthesis menu, when opened up, only allow the recipes of
* the Item 15, Weapon 20, or Armor 30 without needing it and not showing the
* recipes of any recipe items within the player's inventory.
*
* ============================================================================
* Changelog
* ============================================================================
*
* Version 1.08:
* - Lunatic Mode fail safes added.
*
* Version 1.07:
* - Added <Custom Synthesis Effect> Lunatic Mode notetag.
*
* Version 1.06:
* - Fixed an error with the calculation of total recipes.
*
* Version 1.05:
* - Updated for RPG Maker MV version 1.1.0.
*
* Version 1.04:
* - Added failsafes to prevent crashes from saved games that did not have this
* plugin already installed.
*
* Version 1.03a:
* - Fixed a bug that caused a crash for OpenSynthesis recipe commands.
* - Fixed an issue with recipe counts not appearing right.
*
* Version 1.02:
* - Added 'Equipped Recipes' plugin parameter. If enabled, this will allow the
* Item Synthesis menu to check your party's equipment to see if any of them
* are recipe holders.
*
* Version 1.01:
* - Fixed a bug with the synthesis gold costs taking more than they should.
* - Extended the OpenSynthesis plugin command. If you add Item, Weapon, or
* Armor after the command along with an ID, the synthesis menu will only show
* the items listed on the recipe for Item x, Weapon x, or Armor x.
*
* Version 1.00:
* - Finished Plugin!
*/
//=============================================================================
Game_System.prototype.canSynthesize = function(item, times) {
if (!item) return false;
if ($gameParty.numItems(item) >= $gameParty.maxItems(item)) return false;
times = times || 1;
if (item.synthCost * times > $gameParty.gold()) return false;
for (var i = 0; i < item.synthIngredients.length; ++i) {
var ingredient = DataManager.getSynthesisIngredient(item, i);
var quantity = DataManager.getSynthesisQuantity(item, i);
if (quantity * times > $gameParty.numItems(ingredient)) return false;
}
return true;
};
Game_System.prototype.maxSynthesize = function(item) {
var maximum = $gameParty.maxItems(item) - $gameParty.numItems(item);
if (item.synthCost > 0) {
maximum = Math.min(maximum, $gameParty.gold() / item.synthCost);
}
for (var i = 0; i < item.synthIngredients.length; ++i) {
var ingredient = DataManager.getSynthesisIngredient(item, i);
var quantity = DataManager.getSynthesisQuantity(item, i);
maximum = Math.min(maximum, $gameParty.numItems(ingredient) / quantity);
}
return parseInt(Math.max(maximum, 0));
};
Window_MenuCommand.prototype.addSynthesisCommand = function() {
if (!eval(Yanfly.Param.ISAutoPlaceCmd)) return;
if (!$gameSystem.isShowSynthesis()) return;
if (this.findSymbol('synthesis') > -1) return;
if ($gameSystem.totalRecipes() <= 0) return;
var text = Yanfly.Param.ISSynthCmd;
var enabled = $gameSystem.isEnableSynthesis();
this.addCommand(text, 'synthesis', enabled);
};
Window_SynthesisStatus.prototype.refresh = function() {
this.contents.clear();
var dy = 0;
dy = this.drawCollectedRecipes(dy);
dy = this.drawCraftedItems(dy);
dy = this.drawCraftedWeapons(dy);
dy = this.drawCraftedArmors(dy);
};
Window_SynthesisStatus.prototype.drawCollectedRecipes = function(dy) {
if (Yanfly.Param.ISColRecipes.length <= 0) return dy;
var dw = this.contents.width;
this.changeTextColor(this.systemColor());
this.drawText(Yanfly.Param.ISColRecipes, 0, dy, dw);
this.changeTextColor(this.normalColor());
var value = parseFloat($gameSystem.totalRecipes()) /
Yanfly.IS.SynthesisRecipeCount;
var text = String(parseInt(value * 100)) + '%';
this.drawText(text, 0, dy, dw, 'right');
dw -= this.textWidth('100%') + this.standardPadding() * 2;
var fmt = '%1/%2'
text = fmt.format($gameSystem.totalRecipes(),
Yanfly.IS.SynthesisRecipeCount);
this.drawText(text, 0, dy, dw, 'right');
return dy + this.lineHeight();
};
Window_SynthesisStatus.prototype.drawCraftedItems = function(dy) {
if (Yanfly.Param.ISCraftedItems.length <= 0) return dy;
var dw = this.contents.width;
this.changeTextColor(this.systemColor());
this.drawText(Yanfly.Param.ISCraftedItems, 0, dy, dw);
this.changeTextColor(this.normalColor());
var value = parseFloat($gameSystem.synthedItems().length) /
Math.max(1, Yanfly.IS.SynthesisItemTotal);
var text = String(parseInt(value * 100)) + '%';
this.drawText(text, 0, dy, dw, 'right');
dw -= this.textWidth('100%') + this.standardPadding() * 2;
var fmt = '%1/%2'
text = fmt.format($gameSystem.synthedItems().length,
Yanfly.IS.SynthesisItemTotal);
this.drawText(text, 0, dy, dw, 'right');
return dy + this.lineHeight();
};
Window_SynthesisStatus.prototype.drawCraftedWeapons = function(dy) {
if (Yanfly.Param.ISCraftedWeapons.length <= 0) return dy;
var dw = this.contents.width;
this.changeTextColor(this.systemColor());
this.drawText(Yanfly.Param.ISCraftedWeapons, 0, dy, dw);
this.changeTextColor(this.normalColor());
var value = parseFloat($gameSystem.synthedWeapons().length) /
Math.max(1, Yanfly.IS.SynthesisWeaponTotal);
var text = String(parseInt(value * 100)) + '%';
this.drawText(text, 0, dy, dw, 'right');
dw -= this.textWidth('100%') + this.standardPadding() * 2;
var fmt = '%1/%2'
text = fmt.format($gameSystem.synthedWeapons().length,
Yanfly.IS.SynthesisWeaponTotal);
this.drawText(text, 0, dy, dw, 'right');
return dy + this.lineHeight();
};
Window_SynthesisStatus.prototype.drawCraftedArmors = function(dy) {
if (Yanfly.Param.ISCraftedArmors.length <= 0) return dy;
var dw = this.contents.width;
this.changeTextColor(this.systemColor());
this.drawText(Yanfly.Param.ISCraftedArmors, 0, dy, dw);
this.changeTextColor(this.normalColor());
var value = parseFloat($gameSystem.synthedArmors().length) /
Math.max(1, Yanfly.IS.SynthesisArmorTotal);
var text = String(parseInt(value * 100)) + '%';
this.drawText(text, 0, dy, dw, 'right');
dw -= this.textWidth('100%') + this.standardPadding() * 2;
var fmt = '%1/%2'
text = fmt.format($gameSystem.synthedArmors().length,
Yanfly.IS.SynthesisArmorTotal);
this.drawText(text, 0, dy, dw, 'right');
return dy + this.lineHeight();
};
Window_SynthesisList.prototype.drawItem = function(index) {
var item = this._data[index];
if (!item) return;
this.resetFontSettings();
var rect = this.itemRect(index);
this.changePaintOpacity(this.isEnabled(item));
this.drawItemName(item, rect.x, rect.y, rect.width);
this.drawItemNumber(item, rect.x, rect.y, rect.width);
};
Window_SynthesisList.prototype.drawItemName = function(item, x, y, width) {
if (!item) return;
if ($gameSystem.hasSynthed(item)) {
Window_Base.prototype.drawItemName.call(this, item, x, y, width);
return;
}
var iconBoxWidth = Window_Base._iconWidth + 4;
this.resetTextColor();
this.drawIcon(item.iconIndex, x + 2, y + 2);
var text = item.name;
if (eval(Yanfly.Param.ISMaskUnknown)) {
this.contents.fontItalic = Yanfly.Param.ISMaskItalic;
if (item.maskName !== '') {
text = item.maskName;
} else {
text = Yanfly.Util.maskString(text, Yanfly.Param.ISMaskText);
}
}
this.drawText(text, x + iconBoxWidth, y, width - iconBoxWidth);
this.contents.fontItalic = false;
};
Window_SynthesisList.prototype.drawItemNumber = function(item, wx, wy, ww) {
if (eval(Yanfly.Param.ISMaskUnknown) && !$gameSystem.hasSynthed(item)) {
return;
}
ww -= this.textPadding();
if (Imported.YEP_ItemCore && DataManager.isIndependent(item)) {
var baseItem = DataManager.getBaseItem(item);
var value = $gameParty.numIndependentItems(baseItem);
var numItems = Yanfly.Util.toGroup(value);
} else {
var numItems = Yanfly.Util.toGroup($gameParty.numItems(item));
}
this.contents.fontSize = Yanfly.Param.ISQuantitySize;
this.drawText('\u00d7' + numItems, wx, wy, ww - 2, 'right');
};
Window_SynthesisNumber.prototype.drawMultiplicationSign = function() {
var sign = '\u00d7';
var width = this.textWidth(sign);
var x = this.cursorX() - width * 2;
var y = this.itemY();
this.resetTextColor();
this.drawText(sign, x, y, width);
};
Window_SynthesisNumber.prototype.drawNumber = function() {
var x = this.cursorX();
var y = this.itemY();
var width = this.cursorWidth() - this.textPadding();
this.resetTextColor();
this.drawText(Yanfly.Util.toGroup(this._number), x, y, width, 'right');
};
Window_SynthesisNumber.prototype.drawIngredients = function() {
var wy = this.lineHeight();
for (var i = 0; i < this._item.synthIngredients.length; ++i) {
wy = this.drawItemDetails(i, wy);
if (wy + this.lineheight > this.contents.height) break;
}
this.drawItemSynthCost(this._item, wy);
};
Window_SynthesisNumber.prototype.drawItemDetails = function(index, wy) {
var ingredient = DataManager.getSynthesisIngredient(this._item, index);
var quantity = DataManager.getSynthesisQuantity(this._item, index);
var ww = this.contents.width;
if (!ingredient) return wy;
this.resetFontSettings();
this.drawItemName.call(this, ingredient, 0, wy, ww);
this.drawItemQuantity(index, wy);
return wy + this.lineHeight();
};
Window_SynthesisNumber.prototype.drawItemQuantity = function(index, wy) {
var ingredient = DataManager.getSynthesisIngredient(this._item, index);
var quantity = DataManager.getSynthesisQuantity(this._item, index);
quantity *= this.number();
var ww = this.contents.width;
this.contents.fontSize = Yanfly.Param.ISQuantitySize;
this.changeTextColor(this.normalColor());
var num = '/' + Yanfly.Util.toGroup($gameParty.numItems(ingredient));
this.drawText(num, 0, wy, ww, 'right');
ww -= this.textWidth(num);
if ($gameParty.numItems(ingredient) >= quantity) {
this.changeTextColor(this.powerUpColor());
} else {
this.changeTextColor(this.powerDownColor());
}
var text = String(Yanfly.Util.toGroup(quantity));
this.drawText(text, 0, wy, ww, 'right');
}
Window_SynthesisNumber.prototype.drawItemSynthCost = function(item, wy) {
if (item.synthCost <= 0) return;
this.resetFontSettings();
var value = item.synthCost * this.number();
var ww = this.contents.width - 4;
this.drawCurrencyValue(value, TextManager.currencyUnit, 0, wy, ww)
};
Scene_Synthesis.addSynthesisItem = function(obj, list) {
if (!obj) return;
if (obj.name.length <= 0) return;
if (obj.synthCost <= 0 && obj.synthIngredients.length <= 0) return;
if (list.contains(obj)) return;
list.push(obj);
};
Scene_Synthesis.getAvailableItems = function(type) {
var list = [];
var lib = this.availableLibrary();
var length = lib.length;
for (var i = 0; i < length; ++i) {
var set = lib[i];
this.getAvailableRecipes(set, type, list);
}
return list;
};
Scene_Synthesis.getAvailableRecipes = function(set, type, list) {
var length = set.length;
for (var i = 0; i < length; ++i) {
var item = set[i];
if (!item) continue;
if (type === 0 && item.recipeItem) {
this.getAvailableSynthesisItems(item.recipeItem, type, list);
} else if (type === 1 && item.recipeWeapon) {
this.getAvailableSynthesisItems(item.recipeWeapon, type, list);
} else if (type === 2 && item.recipeArmor) {
this.getAvailableSynthesisItems(item.recipeArmor, type, list);
}
}
};
Scene_Synthesis.getAvailableSynthesisItems = function(array, type, list) {
var length = array.length;
for (var i = 0; i < length; ++i) {
if (type === 0) var obj = $dataItems[array[i]];
if (type === 1) var obj = $dataWeapons[array[i]];
if (type === 2) var obj = $dataArmors[array[i]];
this.addSynthesisItem(obj, list);
}
};
Scene_Synthesis.availableLibrary = function() {
if ($gameTemp._synthRecipe) {
return [[$gameTemp._synthRecipe]];
}
var library = [];
library.push($gameParty.items());
library.push($gameParty.weapons());
library.push($gameParty.armors());
if (Yanfly.Param.ISEquRecipes) {
var length = $gameParty.allMembers().length;
for (var i = 0; i < length; ++i) {
var member = $gameParty.allMembers()[i];
if (member) library.push(member.equips());
}
}
return library;
};
Scene_Synthesis.availableItems = function() {
var list = this.getAvailableItems(0);
return this.sortList(list);
};
Scene_Synthesis.availableWeapons = function() {
var list = this.getAvailableItems(1);
return this.sortList(list);
};
Scene_Synthesis.availableArmors = function() {
var list = this.getAvailableItems(2);
return this.sortList(list);
};
Scene_Synthesis.sortList = function(list) {
list.sort(function(a, b) {
var p1 = a.id;
var p2 = b.id;
if (p1 !== p2) {
return p1 - p2;
}
return b - a;
});
return list;
};
//=============================================================================
// New Function
//=============================================================================
Yanfly.Util = Yanfly.Util || {};
Yanfly.Util.getRange = function(n, m) {
var result = [];
for (var i = n; i <= m; ++i) result.push(i);
return result;
};
Yanfly.Util.maskString = function(str, mask) {
var text = mask;
if (mask.length === 1) {
text = Array(str.length + 1).join(mask);
return text;
} else {
return mask;
}
};