//=============================================================================
// SoulsBlacksmith.js
//=============================================================================

/*:
 * @target MZ
 * @plugindesc [v1.0] Sistema de upgrade de armas estilo Souls (Troca de IDs, Pedras de Forja e Ouro por Categoria).
 * @author Você / Gemini
 *
 * @command OpenBlacksmith
 * @text Open Blacksmith Menu
 * @desc Opens the weapon upgrade interface.
 *
 * @param SmallStoneId
 * @text Small Stone Item ID
 * @type item
 * @default 1
 *
 * @param MediumStoneId
 * @text Medium Stone Item ID
 * @type item
 * @default 2
 *
 * @param LargeStoneId
 * @text Large Stone Item ID
 * @type item
 * @default 3
 *
 * @param WeakMultiplier
 * @text Weak Tier Gold Multiplier
 * @type number
 * @default 2
 * @desc Multiplier for weak weapons (e.g., Base Gold * 2).
 *
 * @param MediumMultiplier
 * @text Medium Tier Gold Multiplier
 * @type number
 * @default 5
 * @desc Multiplier for medium weapons (e.g., Base Gold * 5).
 *
 * @param StrongMultiplier
 * @text Strong Tier Gold Multiplier
 * @type number
 * @default 9
 * @desc Multiplier for strong weapons (e.g., Base Gold * 9).
 *
 * @param TextUpgradeCommand
 * @text Text: Upgrade Button
 * @default Upgrade
 *
 * @param TextCancelCommand
 * @text Text: Cancel Button
 * @default Cancel
 *
 * @param TextRequiredMaterials
 * @text Text: Materials Section
 * @default Required Materials:
 *
 * @param TextGoldCost
 * @text Text: Cost Section
 * @default Upgrade Cost:
 *
 * @param TextMaxLevel
 * @text Text: Max Level Label
 * @default MAX
 *
 * @param TextWeaponListTitle
 * @text Text: Menu Title
 * @default Weapon Reinforcement
 *
 * @param LevelSettings
 * @text Level Upgrade Settings
 * @type struct<LevelConfig>[]
 * @default ["{\"TargetLevel\":\"2\",\"StoneType\":\"1\",\"StoneAmount\":\"1\",\"BaseGold\":\"100\"}","{\"TargetLevel\":\"3\",\"StoneType\":\"1\",\"StoneAmount\":\"2\",\"BaseGold\":\"150\"}","{\"TargetLevel\":\"4\",\"StoneType\":\"1\",\"StoneAmount\":\"3\",\"BaseGold\":\"200\"}","{\"TargetLevel\":\"5\",\"StoneType\":\"2\",\"StoneAmount\":\"1\",\"BaseGold\":\"300\"}","{\"TargetLevel\":\"6\",\"StoneType\":\"2\",\"StoneAmount\":\"2\",\"BaseGold\":\"400\"}","{\"TargetLevel\":\"7\",\"StoneType\":\"2\",\"StoneAmount\":\"3\",\"BaseGold\":\"500\"}","{\"TargetLevel\":\"8\",\"StoneType\":\"3\",\"StoneAmount\":\"1\",\"BaseGold\":\"700\"}","{\"TargetLevel\":\"9\",\"StoneType\":\"3\",\"StoneAmount\":\"2\",\"BaseGold\":\"900\"}","{\"TargetLevel\":\"10\",\"StoneType\":\"3\",\"StoneAmount\":\"3\",\"BaseGold\":\"1200\"}"]
 */

/*~struct~LevelConfig:
 * @param TargetLevel
 * @text Upgrade to Level
 * @type number
 * @min 2
 * @max 10
 * * @param StoneType
 * @text Stone Type Needed
 * @type select
 * @option Small
 * @value 1
 * @option Medium
 * @value 2
 * @option Large
 * @value 3
 * @default 1
 * * @param StoneAmount
 * @text Stone Amount Needed
 * @type number
 * @default 1
 * * @param BaseGold
 * @text Base Gold Cost
 * @type number
 * @default 100
 */

(function() {
    'use strict';

    const pluginName = "SoulsBlacksmith";
    const parameters = PluginManager.parameters(pluginName);

    const stoneIds = {
        1: Number(parameters['SmallStoneId'] || 1),
        2: Number(parameters['MediumStoneId'] || 2),
        3: Number(parameters['LargeStoneId'] || 3)
    };

    const multipliers = {
        'weak': Number(parameters['WeakMultiplier'] || 2),
        'medium': Number(parameters['MediumMultiplier'] || 5),
        'strong': Number(parameters['StrongMultiplier'] || 9)
    };

    const texts = {
        upgrade: parameters['TextUpgradeCommand'] || "Upgrade",
        cancel: parameters['TextCancelCommand'] || "Cancel",
        materials: parameters['TextRequiredMaterials'] || "Required Materials:",
        gold: parameters['TextGoldCost'] || "Upgrade Cost:",
        max: parameters['TextMaxLevel'] || "MAX",
        title: parameters['TextWeaponListTitle'] || "Weapon Reinforcement"
    };

    let levelConfigs = {};
    try {
        if (parameters['LevelSettings']) {
            JSON.parse(parameters['LevelSettings']).forEach(str => {
                let cfg = JSON.parse(str);
                levelConfigs[Number(cfg.TargetLevel)] = {
                    stoneType: Number(cfg.StoneType),
                    stoneAmount: Number(cfg.StoneAmount),
                    baseGold: Number(cfg.BaseGold)
                };
            });
        }
    } catch(e) {
        console.error("SoulsBlacksmith: Error parsing level settings.");
    }

    PluginManager.registerCommand(pluginName, "OpenBlacksmith", () => {
        SceneManager.push(Scene_Blacksmith);
    });

    // Helper functions to read weapon tags
    function getWeaponLevel(item) {
        return item && item.meta.WeaponLevel ? Number(item.meta.WeaponLevel) : 1;
    }

    function getWeaponTier(item) {
        return item && item.meta.WeaponTier ? item.meta.WeaponTier.trim().toLowerCase() : 'weak';
    }

    function getUpgradeId(item) {
        return item && item.meta.UpgradeId ? Number(item.meta.UpgradeId) : 0;
    }

    function getUpgradeCost(item) {
        const nextLvl = getWeaponLevel(item) + 1;
        const cfg = levelConfigs[nextLvl];
        if (!cfg) return { gold: 0, stoneItem: null, stoneAmount: 0 };

        const tier = getWeaponTier(item);
        const mult = multipliers[tier] || 2;
        const goldCost = cfg.baseGold * mult;
        const stoneItem = $dataItems[stoneIds[cfg.stoneType]];

        return {
            gold: goldCost,
            stoneItem: stoneItem,
            stoneAmount: cfg.stoneAmount
        };
    }

    //=============================================================================
    // UI Windows (Sized for 816x624)
    //=============================================================================

    class Window_BlacksmithTitle extends Window_Base {
        initialize(rect) {
            super.initialize(rect);
            this.refresh();
        }
        refresh() {
            this.contents.clear();
            this.drawText(texts.title, 0, 0, this.innerWidth, 'center');
        }
    }

    class Window_BlacksmithWeaponList extends Window_Selectable {
        initialize(rect) {
            super.initialize(rect);
            this.makeItemList();
            this.refresh();
            this.select(0);
        }
        maxItems() { return this._data ? this._data.length : 0; }
        item() { return this._data && this.index() >= 0 ? this._data[this.index()] : null; }
        
        makeItemList() {
            this._data = [];
            // Weapons in inventory
            $gameParty.weapons().forEach(wpn => {
                if (wpn.meta.WeaponLevel || wpn.meta.UpgradeId) {
                    this._data.push({ item: wpn, actor: null, slotId: -1 });
                }
            });
            // Equipped weapons
            $gameParty.members().forEach(actor => {
                actor.equips().forEach((wpn, slotId) => {
                    if (wpn && DataManager.isWeapon(wpn) && (wpn.meta.WeaponLevel || wpn.meta.UpgradeId)) {
                        this._data.push({ item: wpn, actor: actor, slotId: slotId });
                    }
                });
            });
        }

        drawItem(index) {
            const data = this._data[index];
            if (!data) return;
            const rect = this.itemLineRect(index);
            this.resetFontSettings();
            
            // Draw name and icon
            this.drawItemName(data.item, rect.x, rect.y, rect.width - 100);
            
            // Draw level tag or MAX
            const lvl = getWeaponLevel(data.item);
            const upgradeId = getUpgradeId(data.item);
            this.changeTextColor(ColorManager.systemColor());
            if (upgradeId === 0 || lvl >= 10) {
                this.drawText(`[${texts.max}]`, rect.x + rect.width - 80, rect.y, 80, 'right');
            } else {
                this.drawText(`+${lvl}`, rect.x + rect.width - 80, rect.y, 80, 'right');
            }
        }

        isEnabled(index) {
            const data = this._data[index];
            if (!data) return false;
            const upgradeId = getUpgradeId(data.item);
            if (upgradeId <= 0) return false;

            const cost = getUpgradeCost(data.item);
            if ($gameParty.gold() < cost.gold) return false;
            if (cost.stoneItem && $gameParty.numItems(cost.stoneItem) < cost.stoneAmount) return false;

            return true;
        }
    }

    class Window_BlacksmithStatus extends Window_Base {
        setWeaponData(data) {
            this._data = data;
            this.refresh();
        }
        refresh() {
            this.contents.clear();
            if (!this._data) return;

            const currentWpn = this._data.item;
            const upgradeId = getUpgradeId(currentWpn);
            const nextWpn = upgradeId > 0 ? $dataWeapons[upgradeId] : null;

            this.resetFontSettings();
            this.drawText(currentWpn.name, 0, 0, this.innerWidth);
            
            let y = 50;
            const paramNames = [TextManager.param(2), TextManager.param(3), TextManager.param(4), TextManager.param(5)];
            const paramIds = [2, 3, 4, 5]; // ATK, DEF, MAT, MDF

            paramIds.forEach((id, index) => {
                const curVal = currentWpn.params[id];
                const nextVal = nextWpn ? nextWpn.params[id] : curVal;

                if (curVal > 0 || (nextWpn && nextVal > 0)) {
                    this.changeTextColor(ColorManager.systemColor());
                    this.drawText(paramNames[index], 10, y, 120);
                    
                    this.changeTextColor(ColorManager.normalColor());
                    this.drawText(curVal, 140, y, 50, 'right');
                    
                    if (nextWpn && nextVal !== curVal) {
                        this.changeTextColor(ColorManager.systemColor());
                        this.drawText("\u2192", 200, y, 30, 'center');
                        this.changeTextColor(ColorManager.powerUpColor());
                        this.drawText(nextVal, 240, y, 50, 'right');
                    }
                    y += 35;
                }
            });
        }
    }

    class Window_BlacksmithCost extends Window_Base {
        setWeaponData(data) {
            this._data = data;
            this.refresh();
        }
        refresh() {
            this.contents.clear();
            if (!this._data) return;

            const currentWpn = this._data.item;
            const upgradeId = getUpgradeId(currentWpn);
            
            if (upgradeId <= 0) {
                this.drawText(texts.max, 0, this.innerHeight / 2 - 15, this.innerWidth, 'center');
                return;
            }

            const cost = getUpgradeCost(currentWpn);

            // Draw Stones
            this.changeTextColor(ColorManager.systemColor());
            this.drawText(texts.materials, 10, 10, this.innerWidth - 20);
            this.resetFontSettings();
            if (cost.stoneItem) {
                this.drawItemName(cost.stoneItem, 20, 45, 300);
                const ownedStones = $gameParty.numItems(cost.stoneItem);
                this.changeTextColor(ownedStones >= cost.stoneAmount ? ColorManager.normalColor() : ColorManager.powerDownColor());
                this.drawText(`${ownedStones} / ${cost.stoneAmount}`, 330, 45, 100, 'left');
            }

            // Draw Gold
            this.changeTextColor(ColorManager.systemColor());
            this.drawText(texts.gold, 480, 10, 300);
            this.resetFontSettings();
            
            const currentGold = $gameParty.gold();
            this.changeTextColor(currentGold >= cost.gold ? ColorManager.normalColor() : ColorManager.powerDownColor());
            this.drawText(`${cost.gold} ${TextManager.currencyUnit()}`, 480, 45, 250, 'left');
        }
    }

    class Window_BlacksmithConfirm extends Window_Command {
        makeCommandList() {
            this.addCommand(texts.upgrade, 'confirm');
            this.addCommand(texts.cancel, 'cancel');
        }
    }

    //=============================================================================
    // Scene_Blacksmith
    //=============================================================================

    class Scene_Blacksmith extends Scene_MenuBase {
        create() {
            super.create();
            this.createAllWindows();
        }

        createAllWindows() {
            // Header
            this._titleWindow = new Window_BlacksmithTitle(new Rectangle(0, 0, Graphics.boxWidth, 60));
            this.addWindow(this._titleWindow);

            // Left Side: List
            const listRect = new Rectangle(0, 60, 430, 380);
            this._listWindow = new Window_BlacksmithWeaponList(listRect);
            this._listWindow.setHandler('ok', this.onWeaponOk.bind(this));
            this._listWindow.setHandler('cancel', this.popScene.bind(this));
            this._listWindow.setHandler('select', this.onWeaponSelect.bind(this));
            this.addWindow(this._listWindow);

            // Right Side: Status
            const statusRect = new Rectangle(430, 60, Graphics.boxWidth - 430, 380);
            this._statusWindow = new Window_BlacksmithStatus(statusRect);
            this.addWindow(this._statusWindow);

            // Bottom Side: Materials & Gold
            const costRect = new Rectangle(0, 440, Graphics.boxWidth, Graphics.boxHeight - 440);
            this._costWindow = new Window_BlacksmithCost(costRect);
            this.addWindow(this._costWindow);

            // Floating Small Confirmation Window
            const confRect = new Rectangle(Graphics.boxWidth / 2 - 120, Graphics.boxHeight / 2 - 60, 240, this.calcWindowHeight(2, true));
            this._confirmWindow = new Window_BlacksmithConfirm(confRect);
            this._confirmWindow.setHandler('confirm', this.onUpgradeConfirm.bind(this));
            this._confirmWindow.setHandler('cancel', this.onUpgradeCancel.bind(this));
            this._confirmWindow.hide();
            this._confirmWindow.deactivate();
            this.addWindow(this._confirmWindow);

            this.onWeaponSelect();
        }

        onWeaponSelect() {
            const data = this._listWindow.item();
            if (this._statusWindow) this._statusWindow.setWeaponData(data);
            if (this._costWindow) this._costWindow.setWeaponData(data);
        }

        onWeaponOk() {
            if (this._listWindow.isEnabled(this._listWindow.index())) {
                SoundManager.playOk();
                this._confirmWindow.show();
                this._confirmWindow.activate();
                this._confirmWindow.select(0);
            } else {
                SoundManager.playBuzzer();
                this._listWindow.activate();
            }
        }

        onUpgradeConfirm() {
            const data = this._listWindow.item();
            if (!data) return;

            const currentWpn = data.item;
            const upgradeId = getUpgradeId(currentWpn);
            const nextWpn = $dataWeapons[upgradeId];
            const cost = getUpgradeCost(currentWpn);

            // Spend Resources
            $gameParty.loseGold(cost.gold);
            if (cost.stoneItem) {
                $gameParty.loseItem(cost.stoneItem, cost.stoneAmount);
            }

            // Swap Weapons (Handles Equipment beautifully)
            if (data.actor && data.slotId >= 0) {
                $gameParty.gainItem(nextWpn, 1);
                data.actor.changeEquip(data.slotId, nextWpn);
                $gameParty.loseItem(currentWpn, 1); // Vaporizes the old weak item from inventory
            } else {
                $gameParty.gainItem(nextWpn, 1);
                $gameParty.loseItem(currentWpn, 1);
            }

            SoundManager.playUseItem();
            
            // Redraw and Reset
            this._confirmWindow.hide();
            this._confirmWindow.deactivate();
            this._listWindow.makeItemList();
            this._listWindow.refresh();
            this._listWindow.activate();
            this.onWeaponSelect();
        }

        onUpgradeCancel() {
            this._confirmWindow.hide();
            this._confirmWindow.deactivate();
            this._listWindow.activate();
        }
    }

})();

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: