//============================================================================= // CraftingSystem.js //============================================================================= /*: * @plugindesc Craft items, weapons and armors based on categorized recipe books. * @author Julian "Szyu" Heinen * @version 1.4 * * @param Categories * @desc The names of the categories. * @default Blacksmith, Alchemy * * @param CraftingSounds * @desc SE file names of sounds after creating an item for each category. * @default Sword2, Ice4 * * @param Price Text * @desc Text used for item's price in status display * @default Price * * @param Equip Text * @desc Text used for item's equipment type in status display * @default Equip * * @param Type Text * @desc Text used for item's equipment type in status display * @default Type * * @param Ingredients Text * @desc Text used for indicating an item's crafting ingredients * @default Ingredients: * * @param Currency Text * @desc Text used for currency ingredients * @default Currency * * @param Item Crafted Text * @desc Text used after crafting an item * @default Item crafted: * * * @help * * Plugin Command: * CraftingSystem open 0 # Opens the crafting scene for category #0 * CraftingSystem add_recipe 5: w3 # Adds the recipe of weapon #3 to recipe book #5 * CraftingSystem remove_recipe 5: a1 # Removes the recipe of armor #1 from recipe book #5 * * Defining recipes for items, weapons and armors in their notes: * * i: 1, 5 # requires 5 of item #1 * w: 3, 2 # requires 2 of weapon #3 * a: 2, 5 # requires 5 of armor #2 * c: 1000 # requires 1000 of currency * * * Defining recipe books (only key items) in their notes: * * category: x # recipe book is of category #x * i: 1, 3, 4 # recipe book contains the recipes of items #1, #3 and #4 * w: 3 # recipe book contains the recipes of weapon #3 * a: 2, 1 # recipe book contains the recipes of armors #1 and #2 * * * * To switch between ingredients display and status display, use the Q and W keys. */ (function () { var parameters = PluginManager.parameters("CraftingSystem"); var categories = parameters["Categories"] .replace(/^\s+|\s+$/gm, "") .split(",") || ["Blacksmithing", "Alchemy"]; var craftingSounds = parameters["CraftingSounds"] .replace(/^\s+|\s+$/gm, "") .split(",") || ["Sword2", "Ice4"]; //var animations = parameters['Animations'].replace(/^\s+|\s+$/gm,'').split(',').map(Number) || [12, 13]; var priceText = String(parameters["Price Text"] || "Price"); var equipText = String(parameters["Equip Text"] || "Equip"); var typeText = String(parameters["Type Text"] || "Type"); var ingredientsText = String( parameters["Ingredients Text"] || "Ingredients:" ); var currencyText = String(parameters["Currency Text"] || "Currency"); var itemCraftedText = String( parameters["Item Crafted Text"] || "Item crafted:" ); /*---------------------------------------------- * Game_Interpreter *---------------------------------------------*/ var _szcrsy_Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand; Game_Interpreter.prototype.pluginCommand = function (command, args) { _szcrsy_Game_Interpreter_pluginCommand.call(this, command, args); if (command == "CraftingSystem") { switch (args[0]) { case "open": SceneManager.push(Scene_CraftingMenu); SceneManager.prepareNextScene(args[1]); break; case "add_recipe": this.addRecipes(args.splice(1, args.length - 1)); break; case "remove_recipe": this.removeRecipes(args.splice(1, args.length - 1)); break; } } }; Game_Interpreter.prototype.addRecipes = function (args) { var book = $dataItems[parseInt(args[0])]; var item; var regex; if (book._recipe_book == null) return; for (var i = 1; i < args.length; i++) { regex = args[i].match(/([iwa])(\d+)/i); switch (regex[1]) { case "i": item = $dataItems[parseInt(regex[2])]; break; case "w": item = $dataWeapons[parseInt(regex[2])]; break; case "a": item = $dataArmors[parseInt(regex[2])]; break; } if (item._ingredients == null) continue; if ( book._recipe_book["recipes"].filter(function (obj) { return obj == item; }).length > 0 ) continue; book._recipe_book["recipes"].push(item); } }; Game_Interpreter.prototype.removeRecipes = function (args) { var book = $dataItems[parseInt(args[0])]; var item; var regex; if (book._recipe_book == null) return; for (var i = 1; i < args.length; i++) { regex = args[i].match(/([iwa])(\d+)/i); switch (regex[1]) { case "i": item = $dataItems[parseInt(regex[2])]; break; case "w": item = $dataWeapons[parseInt(regex[2])]; break; case "a": item = $dataArmors[parseInt(regex[2])]; break; } if (item._ingredients == null) continue; if ( book._recipe_book["recipes"].filter(function (obj) { return obj == item; }).length == 0 ) continue; book._recipe_book["recipes"].splice( book._recipe_book["recipes"].indexOf(item), 1 ); } }; /*---------------------------------------------- * DataManager *---------------------------------------------*/ var _szcrsy_DataManager_createGameObjects = DataManager.createGameObjects; DataManager.createGameObjects = function () { _szcrsy_DataManager_createGameObjects.call(this); // Create recipe book object this.load_recipeBooks(); this.load_ingredientLists(); }; DataManager.load_recipeBooks = function () { $dataItems.forEach(function (item) { if (item == null) { return; } item._recipe_book = null; if (item.note.match(/[\s\S]*<\/recipe_book>/m)) { item._recipe_book = { recipes: [] }; var cat; // check if category is correct if ((cat = item.note.match(/category:\s*(\d+)/m))) { item._recipe_book["category"] = parseInt(cat[1]); //now item is sure to be a recipe book with correct category var rec; var db; item.note .match(/([iwa]:\s*[\d+,\s]*)/gim) .forEach(function (recipe_line) { rec = recipe_line.match(/([iwa]):\s*([\d+,\s]*)/i); switch (rec[1]) { case "w": db = $dataWeapons; break; case "a": db = $dataArmors; break; case "i": db = $dataItems; break; } rec[2].split(",").forEach(function (id) { item._recipe_book["recipes"].push(db[parseInt(id)]); }, this); }, this); } } }, this); }; DataManager.load_ingredientLists = function () { var dbs = [$dataItems, $dataWeapons, $dataArmors]; dbs.forEach(function (db) { db.filter(function (obj) { return obj != null; }).forEach(function (item) { item._ingredients = null; if (item.note.match(/[\s\S]*<\/recipe>/gim)) { item._ingredients = []; item.note .match(/([iwa]:\s*\d+,\s*\d+|[c]:\s*\d+)/gim) .forEach(function (ing_line) { var ing = ing_line.match( /([iwa]):\s*(\d+),\s*(\d+)|([c]):\s*(\d+)/i ); var ing_db; var needed; if (ing[1] != null) { switch (ing[1]) { case "w": ing_db = $dataWeapons[parseInt(ing[2])]; break; case "a": ing_db = $dataArmors[parseInt(ing[2])]; break; case "i": ing_db = $dataItems[parseInt(ing[2])]; break; } } else { if (ing[4] == "c") { ing_db = currencyText; } } if (ing_db == currencyText) { needed = parseInt(ing[5]); } else { needed = parseInt(ing[3]); } item._ingredients.push({ item: ing_db, amount: needed }); }, this); } }, this); }, this); }; var _szcrsy_DataManager_makeSaveContents = DataManager.makeSaveContents; DataManager.makeSaveContents = function () { // A save data does not contain $gameTemp, $gameMessage, and $gameTroop. var contents = _szcrsy_DataManager_makeSaveContents.call(this); var recipe_books = {}; $dataItems .filter(function (item) { return item != null && item._recipe_book != null; }) .forEach(function (item) { var rb_ids = []; item._recipe_book.recipes.forEach(function (recipe) { if (DataManager.isItem(recipe)) rb_ids.push("i" + recipe.id); else if (DataManager.isWeapon(recipe)) rb_ids.push("w" + recipe.id); else if (DataManager.isArmor(recipe)) rb_ids.push("a" + recipe.id); }, this); recipe_books[item.id] = rb_ids; }, this); contents.recipe_books = recipe_books; return contents; }; var _szcrsy_DataManager_extractSaveContents = DataManager.extractSaveContents; DataManager.extractSaveContents = function (contents) { _szcrsy_DataManager_extractSaveContents.call(this, contents); var recipe_books = contents.recipe_books; var rex; for (var key in recipe_books) { $dataItems[key]._recipe_book["recipes"] = []; recipe_books[key].forEach(function (book) { rex = book.match(/([iwa])(\d+)/i); switch (rex[1]) { case "i": $dataItems[key]._recipe_book["recipes"].push( $dataItems[parseInt(rex[2])] ); break; case "w": $dataItems[key]._recipe_book["recipes"].push( $dataWeapons[parseInt(rex[2])] ); break; case "a": $dataItems[key]._recipe_book["recipes"].push( $dataArmors[parseInt(rex[2])] ); break; } }, this); //console.log($dataItems[key]); } }; /*---------------------------------------------- * Scene_CraftingMenu *---------------------------------------------*/ function Scene_CraftingMenu() { this.initialize.apply(this, arguments); } Scene_CraftingMenu.prototype = Object.create(Scene_MenuBase.prototype); Scene_CraftingMenu.prototype.constructor = Scene_CraftingMenu; Scene_CraftingMenu.prototype.initialize = function () { Scene_MenuBase.prototype.initialize.call(this); }; Scene_CraftingMenu.prototype.prepare = function (category) { this._category = category; }; Scene_CraftingMenu.prototype.create = function () { Scene_MenuBase.prototype.create.call(this); // Create category window this._categoryWindow = new Window_CraftingCategory(this._category); this.addWindow(this._categoryWindow); // Create item window this._indexWindow = new Window_CraftingItems( 0, this._categoryWindow.height, 288, Graphics.height - this._categoryWindow.height, this._category ); this._indexWindow.setHandler("cancel", this.popScene.bind(this)); this._indexWindow.setHandler("ok", this.onCraft.bind(this)); this.addWindow(this._indexWindow); // Create Item Status Window var swy = this._indexWindow.y + this._indexWindow.height; this._statusWindow = new Window_CraftingItemStatus( this._indexWindow.width, this._categoryWindow.height, Graphics.width - this._indexWindow.width ); this.addWindow(this._statusWindow); this._indexWindow.setStatusWindow(this._statusWindow); // Create Item Ingredients window this._ingredientsWindow = new Window_CraftingIngredients( this._indexWindow.width, this._statusWindow.y + this._statusWindow.height, 500, Graphics.height - this._statusWindow.y - this._statusWindow.height ); this.addWindow(this._ingredientsWindow); this._indexWindow.setIngredientsWindow(this._ingredientsWindow); //this._indexWindow.setHandler('pagedown', this.showStatus.bind(this)); // W this._messageWindow = new Window_Message(); this.addWindow(this._messageWindow); this._messageWindow.subWindows().forEach(function (window) { this.addWindow(window); }, this); this._activeWindow = 0; }; Scene_CraftingMenu.prototype.onCraft = function () { // Create crafting sound var craftingSound = new Object(); craftingSound.name = craftingSounds[this._category]; craftingSound.pan = 0; craftingSound.pitch = 100; craftingSound.volume = 90; AudioManager.playSe(craftingSound); // play crafting sound $gameParty.gainItem(this._indexWindow.item(), 1); this.loseIngredients(); // Show gain item Message $gameMessage.setBackground(0); $gameMessage.setPositionType(1) - 100; $gameMessage.add(itemCraftedText + "\n" + this._indexWindow.item().name); }; /* Scene_CraftingMenu.prototype.showStatus = function(){ if (this._activeWindow !== 1){ var sw = this._statusWindow; var iw = this._ingredientsWindow; iw.move(Graphics.boxWidth,iw.y, iw.width, iw.height); sw.move(0, sw.y, sw.width, sw.height); this._activeWindow = 1; this._indexWindow.setHandler('pageup', this.showIngredients.bind(this)); // Q delete this._indexWindow._handlers['pagedown']; } this._indexWindow.activate(); }; Scene_CraftingMenu.prototype.showIngredients = function(){ if (this._activeWindow !== 0){ var sw = this._statusWindow; var iw = this._ingredientsWindow; sw.move(-Graphics.boxWidth, sw.y, sw.width, sw.height); iw.move(0,iw.y, iw.width, iw.height); this._activeWindow = 0; this._indexWindow.setHandler('pagedown', this.showStatus.bind(this)); // W delete this._indexWindow._handlers['pageup']; } this._indexWindow.activate(); }; */ Scene_CraftingMenu.prototype.loseIngredients = function () { var item = this._indexWindow.item(); var ing; var db; var needed; item._ingredients.forEach(function (ing) { needed = ing["amount"]; if (ing["item"] == currencyText) { $gameParty.loseGold(needed); } else { $gameParty.loseItem(ing["item"], needed); } }, this); this._ingredientsWindow.refresh(); }; /*---------------------------------------------- * Window_CraftingCategory *---------------------------------------------*/ function Window_CraftingCategory() { this.initialize.apply(this, arguments); } Window_CraftingCategory.prototype = Object.create(Window_Base.prototype); Window_CraftingCategory.prototype.constructor = Window_CraftingCategory; Window_CraftingCategory.prototype.initialize = function (category) { this._category = category; Window_Base.prototype.initialize.call( this, 0, 0, Graphics.boxWidth, this.fittingHeight(1) ); this.refresh(); }; Window_CraftingCategory.prototype.refresh = function () { this.drawText( categories[this._category], 0, 0, this.contents.width, this.lineHeight(), "center" ); }; /*---------------------------------------------- * Window_CraftingItems *---------------------------------------------*/ function Window_CraftingItems() { this.initialize.apply(this, arguments); } Window_CraftingItems.prototype = Object.create(Window_Selectable.prototype); Window_CraftingItems.prototype.constructor = Window_CraftingItems; Window_CraftingItems.lastTopRow = 0; Window_CraftingItems.lastIndex = 0; Window_CraftingItems.prototype.initialize = function (x, y, w, h, category) { this._category = parseInt(category); Window_Selectable.prototype.initialize.call(this, x, y, w, h); this.refresh(); this.setTopRow(Window_CraftingItems.lastTopRow); this.select(Window_CraftingItems.lastIndex); this.activate(); }; Window_CraftingItems.prototype.maxCols = function () { return 1; }; Window_CraftingItems.prototype.maxItems = function () { return this._list ? this._list.length : 0; }; Window_CraftingItems.prototype.setStatusWindow = function (statusWindow) { this._statusWindow = statusWindow; this.updateStatus(); }; Window_CraftingItems.prototype.setIngredientsWindow = function ( ingredientsWindow ) { this._ingredientsWindow = ingredientsWindow; this.updateIngredients(); }; Window_CraftingItems.prototype.update = function () { if (!$gameMessage.isBusy()) { Window_Selectable.prototype.update.call(this); this.updateStatus(); this.updateIngredients(); } }; Window_CraftingItems.prototype.updateStatus = function () { if (this._statusWindow) { var item = this._list[this.index()]; this._statusWindow.setItem(item); } }; Window_CraftingItems.prototype.updateIngredients = function () { if (this._ingredientsWindow) { var item = this._list[this.index()]; this._ingredientsWindow.setItem(item); } }; Window_CraftingItems.prototype.refresh = function () { var i, item; var cat, c2; this._list = []; cat = parseInt(this._category); $gameParty .allItems() .filter(function (item) { return ( item._recipe_book != null && cat === parseInt(item._recipe_book["category"]) ); }) .forEach(function (item) { item._recipe_book.recipes.forEach(function (rec_item) { this._list.push(rec_item); }, this); }, this); this.createContents(); this.drawAllItems(); }; Window_CraftingItems.prototype.drawItem = function (index) { var item = this._list[index]; var rect = this.itemRect(index); var width = rect.width - this.textPadding(); this.drawItemName(item, rect.x, rect.y, width); }; Window_CraftingItems.prototype.processCancel = function () { Window_Selectable.prototype.processCancel.call(this); Window_CraftingItems.lastTopRow = this.topRow(); Window_CraftingItems.lastIndex = this.index(); }; Window_CraftingItems.prototype.processOk = function () { if (this.itemIngredientsMet()) { //this.playOkSound(); this.updateInputData(); this.callOkHandler(); } else { this.playBuzzerSound(); } }; Window_CraftingItems.prototype.item = function () { var index = this.index(); return this._list && index >= 0 ? this._list[index] : null; }; Window_CraftingItems.prototype.itemIngredientsMet = function () { var item = this.item(); var met = true; if (item == null) return false; var existingCount = 0, needed = 0; item._ingredients.forEach(function (ing) { needed = ing["amount"]; if (ing["item"] == currencyText) { existingCount = $gameParty.gold(); } else { existingCount = $gameParty.numItems(ing["item"]); } //console.log('ex: ' + existingCount + '; needed: ' + needed + '; RESULT: ' + (existingCount < needed)); if (existingCount < needed) { met = false; } }, this); return met; }; /*---------------------------------------------- * Window_CraftingItemStatus *---------------------------------------------*/ function Window_CraftingItemStatus() { this.initialize.apply(this, arguments); } Window_CraftingItemStatus.prototype = Object.create(Window_Base.prototype); Window_CraftingItemStatus.prototype.constructor = Window_CraftingItemStatus; Window_CraftingItemStatus.prototype.initialize = function (x, y, width) { Window_Base.prototype.initialize.call( this, x, y, width, this.fittingHeight(6) ); }; Window_CraftingItemStatus.prototype.setItem = function (item) { if (this._item !== item) { this._item = item; this.refresh(); } }; Window_CraftingItemStatus.prototype.refresh = function () { var item = this._item; var x = 0; var y = 0; var lineHeight = this.lineHeight(); var width = this.contents.width - this.textPadding() * 2; this.contents.clear(); if (item == null) { return; } this.drawItemName(item, x, y); x = this.textPadding(); y = lineHeight + this.textPadding(); var price = item.price > 0 ? item.price : "-"; this.changeTextColor(this.systemColor()); this.drawText(priceText, x, y, 120); this.resetTextColor(); this.drawText(price, x + 120, y, 120, "right"); y += lineHeight; if (DataManager.isWeapon(item) || DataManager.isArmor(item)) { var etype = $dataSystem.equipTypes[item.etypeId]; this.changeTextColor(this.systemColor()); this.drawText(equipText, x, y, 120); this.resetTextColor(); this.drawText(etype, x + 120, y, 120, "right"); y += lineHeight; var type; if (DataManager.isWeapon(item)) { type = $dataSystem.weaponTypes[item.wtypeId]; } else { type = $dataSystem.armorTypes[item.atypeId]; } this.changeTextColor(this.systemColor()); this.drawText(typeText, x, y, 120); this.resetTextColor(); this.drawText(type, x + 120, y, 120, "right"); x = this.textPadding() + 300; y = lineHeight + this.textPadding(); for (var i = 2; i < 6; i++) { this.changeTextColor(this.systemColor()); this.drawText(TextManager.param(i), x, y, 160); this.resetTextColor(); this.drawText(item.params[i], 0, y, width, "right"); y += lineHeight; } } }; /*---------------------------------------------- * Window_CraftingIngredients *---------------------------------------------*/ function Window_CraftingIngredients() { this.initialize.apply(this, arguments); } Window_CraftingIngredients.prototype = Object.create(Window_Base.prototype); Window_CraftingIngredients.prototype.constructor = Window_CraftingIngredients; Window_CraftingIngredients.prototype.initialize = function ( x, y, width, height ) { Window_Base.prototype.initialize.call(this, x, y, width, height); }; Window_CraftingIngredients.prototype.setItem = function (item) { if (this._item !== item) { this._item = item; this.refresh(); } }; Window_CraftingIngredients.prototype.refresh = function () { this.contents.clear(); var x = 0; var y = 0; var lineHeight = this.lineHeight(); var width = this.contents.width - this.textPadding() * 2; var existingCount = 0, needed = 0; this.changeTextColor(this.systemColor()); this.drawText(ingredientsText, x, y, width); this.resetTextColor(); this._item._ingredients.forEach(function (ing) { y += lineHeight; needed = ing["amount"]; if (ing["item"] == currencyText) { existingCount = $gameParty.gold(); this.drawText(ing["item"], x, y, width); } else { existingCount = $gameParty.numItems(ing["item"]); this.drawItemName(ing["item"], x, y, width); } this.drawText("/" + needed, x, y, width, "right"); if (existingCount < needed) this.changeTextColor(this.crisisColor()); else this.changeTextColor(this.powerUpColor()); this.drawText( existingCount, x, y, width - this.textWidth("/" + needed), "right" ); this.resetTextColor(); }, this); }; /*---------------------------------------------- * Window_CraftingAnimation *---------------------------------------------*/ function Window_CraftingAnimation() { this.initialize.apply(this, arguments); } Window_CraftingAnimation.prototype = Object.create(Window_Base.prototype); Window_CraftingAnimation.prototype.constructor = Window_CraftingAnimation; Window_CraftingAnimation.prototype.initialize = function (cat_id) { Window_Base.prototype.initialize.call( this, 0, 0, Graphics.width, Graphics.height ); this._category = cat_id; this._animation = $dataAnimations[animations[cat_id]]; this._finishedAnimation = false; }; })();