/*:
 * @target MZ
 * @plugindesc Menu principal ultra stylisé - Inspiré Persona 5 + Street Fighter 6
 * @author Superagent for Akira1kurusu
 * @version 1.7
 *
 * @param menuColor1
 * @text Couleur principale
 * @type string
 * @default #E8003A
 *
 * @param menuColor2
 * @text Couleur secondaire
 * @type string
 * @default #1A1A1A
 *
 * @param accentColor
 * @text Couleur accent
 * @type string
 * @default #FFFFFF
 *
 * @param paintColor
 * @text Couleur effet peinture
 * @type string
 * @default #FFD700
 *
 * @param transitionSpeed
 * @text Vitesse de transition (frames)
 * @type number
 * @min 5
 * @max 60
 * @default 30
 *
 * @help
 * UNIQUE MENU v1.7 — Persona 5 x Street Fighter 6
 * Transitions stylisées, formation corrigée, gold window améliorée.
 */

(() => {
    'use strict';

    const pluginName  = 'UniqueMenu_MZ';
    const params      = PluginManager.parameters(pluginName);
    const COLOR1      = params.menuColor1  || '#E8003A';
    const COLOR2      = params.menuColor2  || '#1A1A1A';
    const ACCENT      = params.accentColor || '#FFFFFF';
    const PAINT       = params.paintColor  || '#FFD700';
    const TRANS_SPEED = parseInt(params.transitionSpeed) || 30;
    const GOLD_H      = 96;
    const BAR_WIDTH   = 14;

    // ============================================================
    // UTILITAIRES CANVAS
    // ============================================================

    function getCtx(bmp) {
        return bmp && bmp._canvas ? bmp._canvas.getContext('2d') : null;
    }

    function drawSkewedRect(ctx, x, y, w, h, skew, color, alpha) {
        if (alpha === undefined) alpha = 1;
        ctx.save();
        ctx.globalAlpha = alpha; ctx.fillStyle = color;
        ctx.beginPath();
        ctx.moveTo(x + skew,     y);
        ctx.lineTo(x + w + skew, y);
        ctx.lineTo(x + w - skew, y + h);
        ctx.lineTo(x - skew,     y + h);
        ctx.closePath(); ctx.fill(); ctx.restore();
    }

    function drawPaintSplash(ctx, cx, cy, size, color, alpha) {
        if (alpha === undefined) alpha = 0.7;
        ctx.save();
        ctx.globalAlpha = alpha; ctx.fillStyle = color;
        const pts = 8 + Math.floor(Math.random() * 5);
        ctx.beginPath();
        for (let i = 0; i < pts * 2; i++) {
            const ang = (i / (pts * 2)) * Math.PI * 2;
            const r   = (i % 2 === 0)
                ? size * (0.7 + Math.random() * 0.5)
                : size * (0.3 + Math.random() * 0.3);
            if (i === 0) ctx.moveTo(cx + Math.cos(ang) * r, cy + Math.sin(ang) * r);
            else         ctx.lineTo(cx + Math.cos(ang) * r, cy + Math.sin(ang) * r);
        }
        ctx.closePath(); ctx.fill(); ctx.restore();
    }

    function drawSpeedLines(ctx, cx, cy, count, length, color, alpha) {
        if (alpha === undefined) alpha = 0.12;
        ctx.save();
        ctx.globalAlpha = alpha; ctx.strokeStyle = color; ctx.lineWidth = 1;
        for (let i = 0; i < count; i++) {
            const ang = (i / count) * Math.PI * 2;
            const s   = 20 + Math.random() * 30;
            const e   = s + length * (0.5 + Math.random() * 0.5);
            ctx.beginPath();
            ctx.moveTo(cx + Math.cos(ang) * s, cy + Math.sin(ang) * s);
            ctx.lineTo(cx + Math.cos(ang) * e, cy + Math.sin(ang) * e);
            ctx.stroke();
        }
        ctx.restore();
    }

    function drawBg(ctx, w, h, opts) {
        opts = opts || {};
        const bgAlpha  = opts.bgAlpha  !== undefined ? opts.bgAlpha  : 0.93;
        const barColor = opts.barColor || COLOR1;
        const barSide  = opts.barSide  || 'left';
        const barSize  = opts.barSize  || 6;
        const splashes = Array.isArray(opts.splashes) ? opts.splashes : [];
        const lines    = opts.speedLines !== false;

        ctx.save(); ctx.globalAlpha = bgAlpha; ctx.fillStyle = COLOR2;
        ctx.fillRect(0, 0, w, h); ctx.restore();

        ctx.save(); ctx.globalAlpha = 1; ctx.fillStyle = barColor;
        if (barSide === 'left') ctx.fillRect(0, 0, barSize, h);
        else                    ctx.fillRect(0, 0, w, barSize);
        ctx.restore();

        for (const s of splashes) drawPaintSplash(ctx, s.x, s.y, s.size, s.color, s.alpha);

        if (lines) drawSpeedLines(ctx, w * 0.85, h * 0.5, 28, h * 0.6, PAINT, 0.05);

        ctx.save(); ctx.strokeStyle = COLOR1; ctx.globalAlpha = 0.18;
        ctx.lineWidth = 1.5; ctx.beginPath();
        ctx.moveTo(w * 0.55, 0); ctx.lineTo(w, h * 0.4);
        ctx.stroke(); ctx.restore();
    }

    function p5Text(ctx, text, x, y, opts) {
        opts = opts || {};
        const sz    = opts.size  || 16;
        const color = opts.color || ACCENT;
        ctx.save();
        ctx.font         = `bold ${sz}px "Arial Black", Arial, sans-serif`;
        ctx.textBaseline = opts.baseline || 'middle';
        ctx.textAlign    = opts.align    || 'left';
        if (opts.shadow !== false) {
            ctx.fillStyle = '#000'; ctx.globalAlpha = 0.65;
            ctx.fillText(text, x + 2, y + 2);
        }
        ctx.fillStyle   = color;
        ctx.globalAlpha = opts.alpha !== undefined ? opts.alpha : 1;
        ctx.fillText(text, x, y);
        ctx.restore();
    }

    function drawStatBar(ctx, x, y, w, h, ratio, fillColor) {
        ctx.save();
        ctx.fillStyle = '#2a2a2a'; ctx.globalAlpha = 0.9;
        ctx.fillRect(x, y, w, h);
        ctx.fillStyle = fillColor; ctx.globalAlpha = 1;
        ctx.fillRect(x, y, Math.max(0, w * ratio), h);
        ctx.fillStyle = '#fff'; ctx.globalAlpha = 0.12;
        ctx.fillRect(x, y, Math.max(0, w * ratio), Math.ceil(h / 2));
        ctx.restore();
    }

    // ============================================================
    // MIXIN STYLE GÉNÉRIQUE — sans toucher aux prototypes pour opacity
    // ============================================================
    function applyUniqueStyle(WinClass) {
        const _init = WinClass.prototype.initialize;
        WinClass.prototype.initialize = function (rect) {
            _init.call(this, rect);
            this.opacity = 0; this.frameVisible = false;
        };
        const _ref = WinClass.prototype.refresh;
        WinClass.prototype.refresh = function () {
            if (this.contents) {
                const ctx = getCtx(this.contents);
                if (ctx) drawBg(ctx, this.contentsWidth(), this.contentsHeight(),
                    { barSide: 'left', barSize: 5, speedLines: false });
            }
            _ref.call(this);
        };
    }

    [Window_ItemCategory, Window_SkillType, Window_EquipItem,
     Window_SavefileList, Window_Options, Window_GameEnd
    ].forEach(applyUniqueStyle);

    // Window_Help
    const _HI = Window_Help.prototype.initialize;
    Window_Help.prototype.initialize = function (rect) {
        _HI.call(this, rect); this.opacity = 0; this.frameVisible = false;
    };
    const _HR = Window_Help.prototype.refresh;
    Window_Help.prototype.refresh = function () {
        if (this.contents) {
            const ctx = getCtx(this.contents);
            if (ctx) drawBg(ctx, this.contentsWidth(), this.contentsHeight(),
                { barSide: 'top', barSize: 4, speedLines: false });
        }
        _HR.call(this);
    };

    // ============================================================
    // WINDOW_ITEMLIST
    // ============================================================
    const _ILI = Window_ItemList.prototype.initialize;
    Window_ItemList.prototype.initialize = function (rect) {
        _ILI.call(this, rect); this.opacity = 0; this.frameVisible = false;
    };
    const _ILR = Window_ItemList.prototype.refresh;
    Window_ItemList.prototype.refresh = function () {
        if (this.contents) {
            const ctx = getCtx(this.contents);
            if (ctx) drawBg(ctx, this.contentsWidth(), this.contentsHeight(),
                { barSide: 'left', barSize: 5, speedLines: false });
        }
        _ILR.call(this);
    };
    Window_ItemList.prototype.drawItem = function (index) {
        const item = this.itemAt(index);
        if (!item) return;
        const rect = this.itemLineRect(index);
        const ctx  = getCtx(this.contents);
        if (!ctx) { Window_Selectable.prototype.drawItem.call(this, index); return; }
        const enabled = this.isEnabled(item);
        const pad = 4, skew = 8;
        drawSkewedRect(ctx, rect.x + pad, rect.y + pad,
            rect.width - pad * 2, rect.height - pad * 2, skew, ACCENT, enabled ? 0.07 : 0.03);
        this.drawIcon(item.iconIndex, rect.x + 8,
            rect.y + (rect.height - ImageManager.iconHeight) / 2);
        p5Text(ctx, item.name.toUpperCase(), rect.x + 40, rect.y + rect.height / 2,
            { size: 15, color: enabled ? ACCENT : '#666', shadow: true });
        const count = $gameParty.numItems(item);
        const countStr = `×${count}`;
        ctx.save();
        ctx.font = 'bold 13px "Arial Black", Arial, sans-serif';
        ctx.textBaseline = 'middle'; ctx.textAlign = 'right';
        const cw = ctx.measureText(countStr).width + 12;
        drawSkewedRect(ctx, rect.x + rect.width - cw - pad - 4, rect.y + pad + 2,
            cw, rect.height - pad * 2 - 4, 4, PAINT, enabled ? 0.18 : 0.07);
        ctx.fillStyle = PAINT; ctx.globalAlpha = enabled ? 1 : 0.4;
        ctx.fillText(countStr, rect.x + rect.width - pad - 6, rect.y + rect.height / 2);
        ctx.restore();
    };

    // ============================================================
    // WINDOW_SKILLLIST
    // ============================================================
    const _SLI = Window_SkillList.prototype.initialize;
    Window_SkillList.prototype.initialize = function (rect) {
        _SLI.call(this, rect); this.opacity = 0; this.frameVisible = false;
    };
    const _SLR = Window_SkillList.prototype.refresh;
    Window_SkillList.prototype.refresh = function () {
        if (this.contents) {
            const ctx = getCtx(this.contents);
            if (ctx) drawBg(ctx, this.contentsWidth(), this.contentsHeight(),
                { barSide: 'left', barSize: 5, speedLines: false });
        }
        _SLR.call(this);
    };
    Window_SkillList.prototype.drawItem = function (index) {
        const skill = this.itemAt(index);
        if (!skill) return;
        const rect = this.itemLineRect(index);
        const ctx  = getCtx(this.contents);
        const actor = this._actor;
        if (!ctx || !actor) { Window_Selectable.prototype.drawItem.call(this, index); return; }
        const enabled = this.isEnabled(skill);
        const pad = 4, skew = 8;
        drawSkewedRect(ctx, rect.x + pad, rect.y + pad,
            rect.width - pad * 2, rect.height - pad * 2, skew, ACCENT, enabled ? 0.07 : 0.03);
        this.drawIcon(skill.iconIndex, rect.x + 8,
            rect.y + (rect.height - ImageManager.iconHeight) / 2);
        p5Text(ctx, skill.name.toUpperCase(), rect.x + 40, rect.y + rect.height / 2,
            { size: 15, color: enabled ? ACCENT : '#666', shadow: true });
        const cost = actor.skillMpCost(skill);
        const tp   = actor.skillTpCost(skill);
        if (cost > 0 || tp > 0) {
            const label  = cost > 0 ? `${cost} MP` : `${tp} TP`;
            const lcolor = cost > 0 ? '#5599FF' : '#33DDAA';
            ctx.save();
            ctx.font = 'bold 12px "Arial Black", Arial, sans-serif';
            ctx.textBaseline = 'middle'; ctx.textAlign = 'right';
            const lw = ctx.measureText(label).width + 10;
            drawSkewedRect(ctx, rect.x + rect.width - lw - pad - 4,
                rect.y + pad + 2, lw, rect.height - pad * 2 - 4, 4, lcolor, 0.2);
            ctx.fillStyle = lcolor; ctx.globalAlpha = enabled ? 1 : 0.4;
            ctx.fillText(label, rect.x + rect.width - pad - 6, rect.y + rect.height / 2);
            ctx.restore();
        }
    };

    // ============================================================
    // WINDOW_EQUIPSLOT
    // ============================================================
    const _ESI = Window_EquipSlot.prototype.initialize;
    Window_EquipSlot.prototype.initialize = function (rect) {
        _ESI.call(this, rect); this.opacity = 0; this.frameVisible = false;
    };
    const _ESR = Window_EquipSlot.prototype.refresh;
    Window_EquipSlot.prototype.refresh = function () {
        if (this.contents) {
            const ctx = getCtx(this.contents);
            if (ctx) drawBg(ctx, this.contentsWidth(), this.contentsHeight(),
                { barSide: 'left', barSize: 5, speedLines: false });
        }
        _ESR.call(this);
    };
    Window_EquipSlot.prototype.drawItem = function (index) {
        if (!this._actor) return;
        const rect = this.itemLineRect(index);
        const ctx  = getCtx(this.contents);
        if (!ctx) { Window_StatusBase.prototype.drawItem.call(this, index); return; }
        const slotName   = this.slotName(index);
        const item       = this._actor.equips()[index];
        const isSelected = (index === this.index());
        const pad = 4, skew = 6;
        drawSkewedRect(ctx, rect.x + pad, rect.y + pad,
            rect.width - pad * 2, rect.height - pad * 2, skew,
            isSelected ? COLOR1 : ACCENT, isSelected ? 0.35 : 0.06);
        p5Text(ctx, slotName.toUpperCase(), rect.x + 10, rect.y + rect.height / 2,
            { size: 11, color: COLOR1, shadow: false });
        ctx.save(); ctx.fillStyle = COLOR1; ctx.globalAlpha = 0.4;
        ctx.fillRect(rect.x + 10, rect.y + rect.height - 3, rect.width - 20, 1);
        ctx.restore();
        if (item) {
            this.drawIcon(item.iconIndex, rect.x + rect.width / 2 - 60,
                rect.y + (rect.height - ImageManager.iconHeight) / 2);
            p5Text(ctx, item.name.toUpperCase(),
                rect.x + rect.width / 2 - 36, rect.y + rect.height / 2,
                { size: 14, color: isSelected ? PAINT : ACCENT, shadow: true });
        } else {
            p5Text(ctx, '—', rect.x + rect.width / 2, rect.y + rect.height / 2,
                { size: 14, color: '#555', shadow: false, align: 'center' });
        }
    };

    // ============================================================
    // WINDOW_STATUS
    // ============================================================
    const _WSI = Window_Status.prototype.initialize;
    Window_Status.prototype.initialize = function (rect) {
        _WSI.call(this, rect); this.opacity = 0; this.frameVisible = false;
    };
    Window_Status.prototype.refresh = function () {
        if (!this.contents || !this._actor) return;
        this.contents.clear();
        const ctx   = getCtx(this.contents);
        const actor = this._actor;
        const w = this.contentsWidth(), h = this.contentsHeight();
        if (!ctx) { Window_StatusBase.prototype.refresh.call(this); return; }

        drawBg(ctx, w, h, { barSide: 'left', barSize: 6, speedLines: true });
        drawPaintSplash(ctx, w - 50, 30, 40, PAINT, 0.06);
        drawPaintSplash(ctx, w - 30, h - 20, 25, COLOR1, 0.05);

        // ── PORTRAIT ──────────────────────────────────────────
        const faceW = 128, faceH = 128;
        this.drawFace(actor.faceName(), actor.faceIndex(), 14, 14, faceW, faceH);
        ctx.save();
        ctx.strokeStyle = COLOR1; ctx.globalAlpha = 0.9; ctx.lineWidth = 3;
        ctx.strokeRect(12, 12, faceW + 4, faceH + 4);
        ctx.strokeStyle = PAINT; ctx.globalAlpha = 0.4; ctx.lineWidth = 1;
        ctx.strokeRect(8, 8, faceW + 12, faceH + 12);
        ctx.restore();

        // ── NOM + CLASSE + NIVEAU ─────────────────────────────
        const infoX = faceW + 28;
        p5Text(ctx, actor.name().toUpperCase(), infoX, 28, { size: 28, color: ACCENT });
        p5Text(ctx, actor.currentClass().name.toUpperCase(), infoX + 2, 60,
            { size: 14, color: COLOR1, shadow: false });

        // Badge niveau
        drawSkewedRect(ctx, infoX, 72, 100, 28, 7, COLOR1, 0.95);
        p5Text(ctx, `LV. ${actor.level}`, infoX + 8, 86, { size: 16, color: '#000', shadow: false });

        // ── HP / MP BARRES LARGES ─────────────────────────────
        const hpRatio = actor.mhp > 0 ? actor.hp / actor.mhp : 0;
        const mpRatio = actor.mmp > 0 ? actor.mp / actor.mmp : 0;
        const hpColor = hpRatio > 0.5 ? '#00DD55' : hpRatio > 0.25 ? '#FFAA00' : COLOR1;
        const mpColor = '#5599FF';
        const barW    = w - infoX - 16;

        // HP
        ctx.save();
        ctx.font = 'bold 12px "Arial Black", Arial'; ctx.textBaseline = 'middle';
        ctx.fillStyle = hpColor; ctx.globalAlpha = 1;
        ctx.fillText('HP', infoX, 112);
        ctx.font = '11px Arial'; ctx.fillStyle = ACCENT; ctx.globalAlpha = 0.95;
        ctx.fillText(`${actor.hp} / ${actor.mhp}`, infoX + 28, 112);
        ctx.restore();
        drawStatBar(ctx, infoX, 122, barW, 9, hpRatio, hpColor);

        // MP
        ctx.save();
        ctx.font = 'bold 12px "Arial Black", Arial'; ctx.textBaseline = 'middle';
        ctx.fillStyle = mpColor; ctx.globalAlpha = 1;
        ctx.fillText('MP', infoX, 142);
        ctx.font = '11px Arial'; ctx.fillStyle = ACCENT; ctx.globalAlpha = 0.95;
        ctx.fillText(`${actor.mp} / ${actor.mmp}`, infoX + 28, 142);
        ctx.restore();
        drawStatBar(ctx, infoX, 152, barW, 9, mpRatio, mpColor);

        // EXP
        const expRate = actor.isMaxLevel() ? 1
            : (actor.currentExp() - actor.currentLevelExp()) /
              (actor.nextLevelExp() - actor.currentLevelExp());
        ctx.save();
        ctx.font = 'bold 10px "Arial Black", Arial'; ctx.textBaseline = 'middle';
        ctx.fillStyle = PAINT; ctx.globalAlpha = 1;
        ctx.fillText('EXP', infoX, 170);
        ctx.font = '10px Arial'; ctx.fillStyle = ACCENT; ctx.globalAlpha = 0.7;
        const expPct = Math.floor(expRate * 100);
        ctx.fillText(`${expPct}%`, infoX + 32, 170);
        ctx.restore();
        drawStatBar(ctx, infoX, 178, barW, 6, expRate, PAINT);

        // ── SÉPARATEUR ────────────────────────────────────────
        ctx.save(); ctx.fillStyle = COLOR1; ctx.globalAlpha = 0.55;
        ctx.fillRect(10, faceH + 22, w - 20, 2); ctx.restore();

        // ── GRILLE DE STATS ──────────────────────────────────
        // 4 colonnes x 2 lignes pour plus de lisibilité
        const stats = [
            { label: 'ATK',     val: actor.atk, color: '#FF6666' },
            { label: 'DEF',     val: actor.def, color: '#66AAFF' },
            { label: 'M.ATK',   val: actor.mat, color: '#CC66FF' },
            { label: 'M.DEF',   val: actor.mdf, color: '#66CCFF' },
            { label: 'VITESSE', val: actor.agi, color: '#66FF99' },
            { label: 'CHANCE',  val: actor.luk, color: PAINT     },
            { label: 'HP MAX',  val: actor.mhp, color: hpColor   },
            { label: 'MP MAX',  val: actor.mmp, color: mpColor   },
        ];

        const gridY  = faceH + 30;
        const cols   = 4;
        const colW   = Math.floor((w - 20) / cols);
        const rowH   = Math.floor((h - gridY - 8) / 2);

        stats.forEach((st, i) => {
            const col = i % cols;
            const row = Math.floor(i / cols);
            const sx  = 10 + col * colW;
            const sy  = gridY + row * rowH;

            // Fond de la cellule
            drawSkewedRect(ctx, sx + 2, sy + 3, colW - 4, rowH - 6, 4, ACCENT, 0.06);

            // Trait coloré à gauche de la cellule
            ctx.save();
            ctx.fillStyle = st.color; ctx.globalAlpha = 0.85;
            ctx.fillRect(sx + 2, sy + 5, 3, rowH - 10);
            ctx.restore();

            // Label
            p5Text(ctx, st.label, sx + 10, sy + rowH / 2 - 8,
                { size: 9, color: st.color, shadow: false });
            // Valeur (grande)
            p5Text(ctx, String(st.val), sx + 10, sy + rowH / 2 + 8,
                { size: 18, color: ACCENT, shadow: true });
        });
    };

    // ============================================================
    // WINDOW_MENU_COMMAND
    // ============================================================
    class Window_UniqueMenuCommand extends Window_MenuCommand {
        constructor(rect) {
            super(rect);
            this._splashes      = [];
            this._hoverAlphas   = new Array(10).fill(0);
            this._animFrame     = 0;
            this._lastIndex     = -1;
            this._selectedFlash = 0;
            this.opacity        = 0;
            this.frameVisible   = false;
            this._generateItemSplashes();
        }
        _generateItemSplashes() {
            this._splashes = [];
            const w = this.width || 300, h = this.height || 400;
            for (let i = 0; i < 8; i++) {
                this._splashes.push({
                    x: w * 0.75 + Math.random() * w * 0.5,
                    y: 20 + Math.random() * h,
                    size: 12 + Math.random() * 30,
                    color: Math.random() > 0.6 ? COLOR1 : PAINT,
                    alpha: 0.05 + Math.random() * 0.09
                });
            }
        }
        itemHeight()  { return 62; }
        itemPadding() { return 16; }
        maxCols()     { return 1;  }
        update() {
            super.update();
            this._animFrame++;
            if (!Array.isArray(this._hoverAlphas)) this._hoverAlphas = new Array(10).fill(0);
            if (!Array.isArray(this._splashes))    this._splashes    = [];
            const idx = this.index();
            for (let i = 0; i < this.maxItems(); i++) {
                if (i === idx) this._hoverAlphas[i] = Math.min(1, (this._hoverAlphas[i] || 0) + 0.08);
                else           this._hoverAlphas[i] = Math.max(0, (this._hoverAlphas[i] || 0) - 0.05);
            }
            if (idx !== this._lastIndex) { this._lastIndex = idx; this._selectedFlash = 15; this.refresh(); }
            if (this._selectedFlash > 0) { this._selectedFlash--; this.refresh(); }
            if (this._animFrame % 4 === 0) this.refresh();
        }
        _refreshBack() {}
        refresh() {
            if (!this.contents) return;
            if (!Array.isArray(this._splashes))    this._splashes    = [];
            if (!Array.isArray(this._hoverAlphas)) this._hoverAlphas = new Array(10).fill(0);
            this.contents.clear();
            const ctx = getCtx(this.contents);
            if (ctx) drawBg(ctx, this.contentsWidth(), this.contentsHeight(),
                { barSide: 'left', barSize: 8, splashes: this._splashes });
            super.refresh();
        }
        drawItem(index) {
            const rect = this.itemLineRect(index);
            const ctx  = getCtx(this.contents);
            if (!ctx) { super.drawItem(index); return; }
            const name       = this.commandName(index);
            const enabled    = this.isCommandEnabled(index);
            const isSelected = (index === this.index());
            const hoverAlpha = (this._hoverAlphas && this._hoverAlphas[index]) || 0;
            const skew = 12, pad = 4;
            drawSkewedRect(ctx, rect.x + BAR_WIDTH + pad, rect.y + pad,
                rect.width - BAR_WIDTH - pad * 2, rect.height - pad * 2, skew, '#000', 0.25);
            drawSkewedRect(ctx, rect.x + BAR_WIDTH + pad + 2, rect.y + pad,
                rect.width - BAR_WIDTH - pad * 2 - 2, rect.height - pad * 2, skew,
                ACCENT, enabled ? (0.15 + hoverAlpha * 0.25) : 0.07);
            if (isSelected) {
                const fb = this._selectedFlash > 0 ? (this._selectedFlash / 15) * 0.3 : 0;
                drawSkewedRect(ctx, rect.x + BAR_WIDTH + pad + 2, rect.y + pad,
                    rect.width - BAR_WIDTH - pad * 2 - 2, rect.height - pad * 2, skew, COLOR1, 0.55 + fb);
                if (this._selectedFlash > 8)
                    drawPaintSplash(ctx, rect.x + rect.width - 30, rect.y + rect.height / 2,
                        25 + (this._selectedFlash / 15) * 20, PAINT, 0.6 + (this._selectedFlash / 15) * 0.3);
                ctx.save();
                ctx.fillStyle = PAINT;
                ctx.globalAlpha = 0.9 + Math.sin(this._animFrame * 0.15) * 0.1;
                ctx.beginPath();
                ctx.moveTo(rect.x + BAR_WIDTH + pad - 2, rect.y + rect.height / 2 - 8);
                ctx.lineTo(rect.x + BAR_WIDTH + pad + 10, rect.y + rect.height / 2);
                ctx.lineTo(rect.x + BAR_WIDTH + pad - 2, rect.y + rect.height / 2 + 8);
                ctx.closePath(); ctx.fill(); ctx.restore();
            }
            const textX = rect.x + BAR_WIDTH + pad + skew + 12;
            const textY = rect.y + rect.height / 2;
            const fontSize = isSelected ? 22 : 19;
            ctx.save();
            ctx.font = `bold ${fontSize}px "Arial Black", Arial, sans-serif`;
            ctx.textBaseline = 'middle';
            ctx.fillStyle = '#000'; ctx.globalAlpha = 0.6;
            ctx.fillText(name.toUpperCase(), textX + 2, textY + 2);
            ctx.fillStyle   = !enabled ? '#888' : ACCENT;
            ctx.globalAlpha = !enabled ? 0.5 : isSelected ? 1 : 0.85;
            ctx.fillText(name.toUpperCase(), textX, textY);
            if (isSelected) {
                const tw = ctx.measureText(name.toUpperCase()).width;
                ctx.fillStyle = PAINT; ctx.globalAlpha = 0.9;
                ctx.fillRect(textX, textY + fontSize / 2 + 2, tw * 0.6, 2);
            }
            ctx.restore();
        }
        _updateCursor() { this.setCursorRect(0, 0, 0, 0); }
    }

    // ============================================================
    // WINDOW_MENU_STATUS
    // ============================================================
    class Window_UniqueMenuStatus extends Window_MenuStatus {
        constructor(rect) {
            super(rect);
            this.opacity = 0; this.frameVisible = false;
        }
        refresh() {
            if (!this.contents) return;
            this.contents.clear();
            const ctx = getCtx(this.contents);
            if (ctx) {
                drawBg(ctx, this.contentsWidth(), this.contentsHeight(),
                    { barSide: 'top', barSize: 5, speedLines: false });
                p5Text(ctx, 'PARTY', 12, 18, { size: 13, color: COLOR1 });
                ctx.save(); ctx.fillStyle = PAINT; ctx.globalAlpha = 0.6;
                ctx.fillRect(12, 30, 50, 2); ctx.restore();
            }
            super.refresh();
        }
        drawItem(index) {
            const actor = $gameParty.members()[index];
            if (!actor) return;
            const rect = this.itemRect(index);
            const ctx  = getCtx(this.contents);
            if (!ctx) { super.drawItem(index); return; }
            const pad = 5;
            const faceSize = 58;

            // Fond oblique item
            drawSkewedRect(ctx, rect.x + pad, rect.y + pad,
                rect.width - pad * 2, rect.height - pad * 2, 6, ACCENT, 0.07);

            // Portrait
            this.drawFace(actor.faceName(), actor.faceIndex(),
                rect.x + rect.width - faceSize - pad - 2,
                rect.y + pad,
                faceSize, rect.height - pad * 2);

            // Nom + niveau
            const infoX = rect.x + pad + 10;
            p5Text(ctx, actor.name().toUpperCase(), infoX, rect.y + pad + 14, { size: 15 });
            p5Text(ctx, `LV. ${actor.level}`, infoX, rect.y + pad + 32,
                { size: 11, color: PAINT, shadow: false });

            // Zone barres — occupe le bas de la carte
            const barW   = rect.width - faceSize - pad * 2 - 20;
            const barX   = infoX;
            const midY   = rect.y + rect.height / 2 + 6;

            const hpRatio = actor.mhp > 0 ? actor.hp / actor.mhp : 0;
            const mpRatio = actor.mmp > 0 ? actor.mp / actor.mmp : 0;
            const hpColor = hpRatio > 0.5 ? '#00DD55' : hpRatio > 0.25 ? '#FFAA00' : COLOR1;
            const mpColor = '#5599FF';

            // --- HP ---
            // Label HP
            ctx.save();
            ctx.font = 'bold 10px "Arial Black", Arial'; ctx.textBaseline = 'middle';
            ctx.fillStyle = hpColor; ctx.globalAlpha = 1;
            ctx.fillText('HP', barX, midY);
            // Valeur HP
            ctx.font = '10px Arial';
            ctx.fillStyle = ACCENT; ctx.globalAlpha = 0.9;
            ctx.fillText(`${actor.hp}/${actor.mhp}`, barX + 22, midY);
            ctx.restore();
            // Barre HP
            drawStatBar(ctx, barX, midY + 8, barW, 6, hpRatio, hpColor);

            // --- MP ---
            const mpRowY = midY + 22;
            ctx.save();
            ctx.font = 'bold 10px "Arial Black", Arial'; ctx.textBaseline = 'middle';
            ctx.fillStyle = mpColor; ctx.globalAlpha = 1;
            ctx.fillText('MP', barX, mpRowY);
            ctx.font = '10px Arial';
            ctx.fillStyle = ACCENT; ctx.globalAlpha = 0.9;
            ctx.fillText(`${actor.mp}/${actor.mmp}`, barX + 22, mpRowY);
            ctx.restore();
            // Barre MP
            drawStatBar(ctx, barX, mpRowY + 8, barW, 6, mpRatio, mpColor);
        }
    }

    // ============================================================
    // GOLD WINDOW
    // ============================================================
    Window_Gold.prototype.refresh = function () {
        if (!this.contents) return;
        this.contents.clear();
        const ctx = getCtx(this.contents);
        if (!ctx) { Window_Base.prototype.refresh.call(this); return; }
        const w = this.contentsWidth();
        const h = this.contentsHeight();

        // Fond sombre + barre dorée en haut
        drawBg(ctx, w, h, {
            barSide: 'top', barSize: 6, barColor: PAINT,
            speedLines: false, splashes: []
        });

        // Badge "GOLD" en haut à gauche
        ctx.save();
        ctx.fillStyle = COLOR1; ctx.globalAlpha = 1;
        ctx.fillRect(6, 4, 46, 18);
        ctx.font = 'bold 11px "Arial Black", Arial, sans-serif';
        ctx.fillStyle = ACCENT; ctx.globalAlpha = 1;
        ctx.textBaseline = 'middle'; ctx.textAlign = 'left';
        ctx.fillText('GOLD', 9, 13);
        ctx.restore();

        // Séparateur
        ctx.save(); ctx.fillStyle = PAINT; ctx.globalAlpha = 0.5;
        ctx.fillRect(6, 26, w - 12, 1); ctx.restore();

        // Centre vertical de la zone sous le séparateur
        const cy = 26 + Math.floor((h - 26) / 2);

        // Icône pièce
        const iconR = Math.min(18, Math.floor((h - 30) / 2) - 2);
        const iconX = 8 + iconR;
        const iconY = cy;
        ctx.save();
        const grad = ctx.createRadialGradient(iconX - 3, iconY - 3, 1, iconX, iconY, iconR);
        grad.addColorStop(0, '#FFF59D');
        grad.addColorStop(0.4, '#FFD700');
        grad.addColorStop(1,   '#7B5E00');
        ctx.beginPath(); ctx.arc(iconX, iconY, iconR, 0, Math.PI * 2);
        ctx.fillStyle = grad; ctx.fill();
        ctx.strokeStyle = '#FFE566'; ctx.lineWidth = 1.5; ctx.globalAlpha = 0.9; ctx.stroke();
        ctx.fillStyle = '#1A1A1A'; ctx.globalAlpha = 1;
        ctx.font = 'bold 13px "Arial Black", Arial';
        ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
        ctx.fillText('G', iconX, iconY + 1);
        ctx.restore();

        // Valeur + unité
        const value    = $gameParty.gold();
        const unit     = TextManager.currencyUnit;
        const valueStr = value.toLocaleString();
        const startX   = iconX + iconR + 6;

        ctx.save();
        ctx.textBaseline = 'middle'; ctx.textAlign = 'left';

        // Ombre valeur
        ctx.font = 'bold 28px "Arial Black", Arial, sans-serif';
        ctx.fillStyle = '#000000'; ctx.globalAlpha = 0.55;
        ctx.fillText(valueStr, startX + 2, cy + 2);
        // Valeur dorée
        ctx.fillStyle = PAINT; ctx.globalAlpha = 1;
        ctx.fillText(valueStr, startX, cy);

        // Unité "Mo" — badge rouge oblique bien lisible
        const vw   = ctx.measureText(valueStr).width;
        const ux   = startX + vw + 10;
        ctx.font = 'bold 20px "Arial Black", Arial, sans-serif';
        const uw   = ctx.measureText(unit).width + 14;
        const uh   = 28;
        // Fond oblique rouge
        ctx.fillStyle = COLOR1; ctx.globalAlpha = 0.95;
        ctx.beginPath();
        ctx.moveTo(ux + 5,      cy - uh / 2);
        ctx.lineTo(ux + uw + 5, cy - uh / 2);
        ctx.lineTo(ux + uw - 5, cy + uh / 2);
        ctx.lineTo(ux - 5,      cy + uh / 2);
        ctx.closePath(); ctx.fill();
        // Contour PAINT
        ctx.strokeStyle = PAINT; ctx.lineWidth = 1.5; ctx.globalAlpha = 0.7;
        ctx.beginPath();
        ctx.moveTo(ux + 5,      cy - uh / 2);
        ctx.lineTo(ux + uw + 5, cy - uh / 2);
        ctx.lineTo(ux + uw - 5, cy + uh / 2);
        ctx.lineTo(ux - 5,      cy + uh / 2);
        ctx.closePath(); ctx.stroke();
        // Texte unité blanc
        ctx.fillStyle = ACCENT; ctx.globalAlpha = 1;
        ctx.fillText(unit, ux + (uw - ctx.measureText(unit).width) / 2, cy + 1);
        ctx.restore();

        // Décoration coin
        drawPaintSplash(ctx, w - 12, h - 8, 10, PAINT, 0.06);
        ctx.save(); ctx.strokeStyle = COLOR1; ctx.globalAlpha = 0.15; ctx.lineWidth = 1.5;
        ctx.beginPath(); ctx.moveTo(w - 30, 0); ctx.lineTo(w + 2, h);
        ctx.stroke(); ctx.restore();
    };

    // ============================================================
    // SCENE_MENU — layout + création fenêtres
    // ============================================================
    Scene_Menu.prototype.commandWindowRect = function () {
        const ww = Math.floor(Graphics.boxWidth * 0.42);
        const wh = this.mainAreaHeight() - GOLD_H - 4;
        return new Rectangle(0, this.mainAreaTop(), ww, wh);
    };
    Scene_Menu.prototype.statusWindowRect = function () {
        const cx = Math.floor(Graphics.boxWidth * 0.42) + 4;
        return new Rectangle(cx, this.mainAreaTop(),
            Graphics.boxWidth - cx, this.mainAreaHeight());
    };
    Scene_Menu.prototype.goldWindowRect = function () {
        const ww = Math.floor(Graphics.boxWidth * 0.42);
        const wy = this.mainAreaBottom() - GOLD_H;
        return new Rectangle(0, wy, ww, GOLD_H);
    };

    Scene_Menu.prototype.createCommandWindow = function () {
        const rect = this.commandWindowRect();
        this._commandWindow = new Window_UniqueMenuCommand(rect);
        this._commandWindow.setHandler('item',      this.commandItem.bind(this));
        this._commandWindow.setHandler('skill',     this.commandPersonal.bind(this));
        this._commandWindow.setHandler('equip',     this.commandPersonal.bind(this));
        this._commandWindow.setHandler('status',    this.commandPersonal.bind(this));
        this._commandWindow.setHandler('formation', this.commandFormation.bind(this));
        this._commandWindow.setHandler('options',   this.commandOptions.bind(this));
        this._commandWindow.setHandler('save',      this.commandSave.bind(this));
        this._commandWindow.setHandler('gameEnd',   this.commandGameEnd.bind(this));
        this._commandWindow.setHandler('cancel',    this._startCloseTransition.bind(this));
        this.addWindow(this._commandWindow);
    };
    Scene_Menu.prototype.createStatusWindow = function () {
        this._statusWindow = new Window_UniqueMenuStatus(this.statusWindowRect());
        this.addWindow(this._statusWindow);
    };
    const _createGold = Scene_Menu.prototype.createGoldWindow;
    Scene_Menu.prototype.createGoldWindow = function () {
        _createGold.call(this);
        if (this._goldWindow) { this._goldWindow.opacity = 0; this._goldWindow.frameVisible = false; }
    };

    // Supprimer "^:Select / X:Back" — on cache la fenêtre d'info de formation
    const _Scene_Menu_create = Scene_Menu.prototype.create;
    Scene_Menu.prototype.create = function () {
        _Scene_Menu_create.call(this);
        // Masquer toute fenêtre d'info/help éventuellement créée
        if (this._helpWindow) {
            this._helpWindow.opacity      = 0;
            this._helpWindow.frameVisible = false;
            this._helpWindow.visible      = false;
        }
    };
    // Empêcher la mise à jour du texte d'aide (^:Select, X:Back)
    Window_UniqueMenuStatus.prototype.updateHelp = function () {};

    // ============================================================
    // TRANSITIONS MENU — Sweep SF6 stylisé + slide des fenêtres
    // ============================================================
    const _Scene_Menu_start = Scene_Menu.prototype.start;
    Scene_Menu.prototype.start = function () {
        _Scene_Menu_start.call(this);
        this._menuState   = 'opening'; // 'opening' | 'idle' | 'closing'
        this._transTimer  = 0;

        // Positions de départ pour le slide
        this._commandWindow.x = -this._commandWindow.width;
        this._statusWindow.x  = Graphics.boxWidth;
        this._goldWindow.y    = Graphics.boxHeight;

        // Sprite de sweep par-dessus tout
        this._sweepSprite = new Sprite(new Bitmap(Graphics.width, Graphics.height));
        this._sweepSprite.z = 100;
        this.addChild(this._sweepSprite);
        this._drawSweepOpen(0);
    };

    // Sweep d'ouverture : rideau rouge qui part de la gauche
    Scene_Menu.prototype._drawSweepOpen = function (progress) {
        if (!this._sweepSprite) return;
        const bmp = this._sweepSprite.bitmap; bmp.clear();
        const ctx = getCtx(bmp); if (!ctx) return;
        const W = Graphics.width, H = Graphics.height;
        const sweepX = W * progress;

        // Flash blanc très bref au tout début (impact)
        if (progress < 0.08) {
            ctx.save(); ctx.fillStyle = '#ffffff';
            ctx.globalAlpha = (0.08 - progress) / 0.08 * 0.6;
            ctx.fillRect(0, 0, W, H); ctx.restore();
        }

        // Rideau principal rouge qui recule vers la gauche
        if (sweepX < W) {
            ctx.save(); ctx.fillStyle = COLOR1; ctx.globalAlpha = 1;
            ctx.beginPath();
            ctx.moveTo(0, 0); ctx.lineTo(sweepX + 50, 0);
            ctx.lineTo(sweepX - 25, H); ctx.lineTo(0, H);
            ctx.closePath(); ctx.fill(); ctx.restore();

            // Bande sombre derrière le rideau (épaisseur du bord)
            ctx.save(); ctx.fillStyle = '#000'; ctx.globalAlpha = 0.5;
            ctx.beginPath();
            ctx.moveTo(sweepX - 10, 0); ctx.lineTo(sweepX + 50, 0);
            ctx.lineTo(sweepX - 5,  H); ctx.lineTo(sweepX - 50, H);
            ctx.closePath(); ctx.fill(); ctx.restore();

            // Ligne lumineuse sur le bord tranchant
            ctx.save(); ctx.strokeStyle = PAINT; ctx.lineWidth = 3; ctx.globalAlpha = 0.9;
            ctx.beginPath();
            ctx.moveTo(sweepX + 50, 0); ctx.lineTo(sweepX - 25, H);
            ctx.stroke(); ctx.restore();
        }

        // Scanlines sur le rideau (style rétro)
        if (sweepX > 10) {
            ctx.save(); ctx.strokeStyle = '#000'; ctx.lineWidth = 1; ctx.globalAlpha = 0.12;
            for (let y = 0; y < H; y += 4) {
                ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(Math.min(sweepX + 50, W), y);
                ctx.stroke();
            }
            ctx.restore();
        }

        // Splashes sur le bord tranchant
        if (progress > 0.05 && progress < 0.95) {
            for (let i = 0; i < 6; i++) {
                drawPaintSplash(ctx,
                    sweepX + (Math.random() - 0.5) * 70,
                    (i / 5) * H + (Math.random() - 0.5) * 60,
                    8 + Math.random() * 22, PAINT,
                    0.55 * (1 - progress));
            }
        }

        // Texte "MENU" avec double ombre style P5
        if (progress < 0.65) {
            const label   = 'MENU';
            const alpha   = Math.max(0, (0.65 - progress) / 0.65);
            const centerX = sweepX * 0.45;
            ctx.save();
            ctx.font = 'bold 72px "Arial Black", Arial, sans-serif';
            ctx.textBaseline = 'middle'; ctx.textAlign = 'center';
            // Ombre rouge décalée (effet P5 signature)
            ctx.fillStyle = COLOR1; ctx.globalAlpha = alpha * 0.8;
            ctx.fillText(label, centerX + 6, H / 2 + 6);
            // Ombre dorée
            ctx.fillStyle = PAINT; ctx.globalAlpha = alpha * 0.6;
            ctx.fillText(label, centerX + 3, H / 2 + 3);
            // Texte principal blanc
            ctx.fillStyle = ACCENT; ctx.globalAlpha = alpha;
            ctx.fillText(label, centerX, H / 2);
            ctx.restore();
        }
    };

    // Sweep de fermeture : rideau rouge vient de la droite
    Scene_Menu.prototype._drawSweepClose = function (progress) {
        if (!this._sweepSprite) return;
        const bmp = this._sweepSprite.bitmap; bmp.clear();
        const ctx = getCtx(bmp); if (!ctx) return;
        const W = Graphics.width, H = Graphics.height;
        const sweepX = W * (1 - progress); // bord gauche du rideau, avance de droite à gauche

        // Rideau principal rouge
        ctx.save(); ctx.fillStyle = COLOR1; ctx.globalAlpha = 1;
        ctx.beginPath();
        ctx.moveTo(sweepX - 50, 0); ctx.lineTo(W, 0);
        ctx.lineTo(W, H); ctx.lineTo(sweepX + 25, H);
        ctx.closePath(); ctx.fill(); ctx.restore();

        // Bande sombre sur le bord avant (impact visuel)
        ctx.save(); ctx.fillStyle = '#000'; ctx.globalAlpha = 0.45;
        ctx.beginPath();
        ctx.moveTo(sweepX - 50, 0); ctx.lineTo(sweepX + 10, 0);
        ctx.lineTo(sweepX + 50, H); ctx.lineTo(sweepX - 10, H);
        ctx.closePath(); ctx.fill(); ctx.restore();

        // Ligne lumineuse sur le bord
        ctx.save(); ctx.strokeStyle = PAINT; ctx.lineWidth = 3; ctx.globalAlpha = 0.85;
        ctx.beginPath();
        ctx.moveTo(sweepX - 50, 0); ctx.lineTo(sweepX + 25, H);
        ctx.stroke(); ctx.restore();

        // Scanlines
        ctx.save(); ctx.strokeStyle = '#000'; ctx.lineWidth = 1; ctx.globalAlpha = 0.1;
        for (let y = 0; y < H; y += 4) {
            ctx.beginPath();
            ctx.moveTo(Math.max(0, sweepX - 50), y); ctx.lineTo(W, y);
            ctx.stroke();
        }
        ctx.restore();

        // Splashes sur le bord
        if (progress > 0.05 && progress < 0.95) {
            for (let i = 0; i < 6; i++) {
                drawPaintSplash(ctx,
                    sweepX + (Math.random() - 0.5) * 70,
                    (i / 5) * H + (Math.random() - 0.5) * 60,
                    8 + Math.random() * 22, PAINT,
                    0.55 * progress);
            }
        }

        // Texte "MENU" avec triple ombre style P5
        if (progress > 0.40) {
            const label  = 'MENU';
            const alpha  = Math.min(1, (progress - 0.40) / 0.4);
            const cx     = sweepX + (W - sweepX) * 0.5;
            ctx.save();
            ctx.font = 'bold 72px "Arial Black", Arial, sans-serif';
            ctx.textBaseline = 'middle'; ctx.textAlign = 'center';
            ctx.fillStyle = COLOR1; ctx.globalAlpha = alpha * 0.8;
            ctx.fillText(label, cx + 6, H / 2 + 6);
            ctx.fillStyle = PAINT; ctx.globalAlpha = alpha * 0.6;
            ctx.fillText(label, cx + 3, H / 2 + 3);
            ctx.fillStyle = ACCENT; ctx.globalAlpha = alpha;
            ctx.fillText(label, cx, H / 2);
            ctx.restore();
        }

        // Flash blanc à la fin (écran couvert)
        if (progress > 0.92) {
            ctx.save(); ctx.fillStyle = '#fff';
            ctx.globalAlpha = (progress - 0.92) / 0.08 * 0.35;
            ctx.fillRect(0, 0, W, H); ctx.restore();
        }
    };

    Scene_Menu.prototype._startCloseTransition = function () {
        if (this._menuState === 'closing') return;
        this._menuState  = 'closing';
        this._transTimer = 0;
        if (!this._sweepSprite) {
            this._sweepSprite = new Sprite(new Bitmap(Graphics.width, Graphics.height));
            this._sweepSprite.z = 100;
            this.addChild(this._sweepSprite);
        }
    };

    const _Scene_Menu_update = Scene_Menu.prototype.update;
    Scene_Menu.prototype.update = function () {
        _Scene_Menu_update.call(this);
        this._transTimer++;
        const speed = TRANS_SPEED;

        if (this._menuState === 'opening') {
            const p = Math.min(1, this._transTimer / speed);
            this._drawSweepOpen(p);

            // Slide des fenêtres avec easing
            const ease = t => 1 - Math.pow(1 - t, 3); // ease out cubic
            const ep   = ease(p);
            const cmdTargetX = 0;
            const stTargetX  = Math.floor(Graphics.boxWidth * 0.42) + 4;
            const gdTargetY  = this.mainAreaBottom() - GOLD_H;

            this._commandWindow.x = Math.round(-this._commandWindow.width * (1 - ep));
            this._statusWindow.x  = Math.round(Graphics.boxWidth - (Graphics.boxWidth - stTargetX) * ep);
            this._goldWindow.y    = Math.round(Graphics.boxHeight - GOLD_H * ep);

            if (p >= 1) {
                this._menuState = 'idle';
                this._commandWindow.x = cmdTargetX;
                this._statusWindow.x  = stTargetX;
                this._goldWindow.y    = gdTargetY;
                this.removeChild(this._sweepSprite);
                this._sweepSprite = null;
            }

        } else if (this._menuState === 'closing') {
            const p = Math.min(1, this._transTimer / speed);
            this._drawSweepClose(p);
            if (p >= 1) {
                this._menuState = 'done';
                this.popScene();
            }
        }
    };

    // ============================================================
    // SWEEP SOUS-SCÈNES (Items, Skill, Equip, Status, Save…)
    // ============================================================
    function addSceneSweep(SceneClass) {
        const _start  = SceneClass.prototype.start;
        const _update = SceneClass.prototype.update;
        SceneClass.prototype.start = function () {
            _start.call(this);
            this._subTimer = 0; this._subDone = false;
            this._subSprite = new Sprite(new Bitmap(Graphics.width, Graphics.height));
            this._subSprite.z = 100;
            this.addChild(this._subSprite);
            _drawSubSweep(this._subSprite, 0);
        };
        SceneClass.prototype.update = function () {
            _update.call(this);
            if (this._subSprite && !this._subDone) {
                this._subTimer++;
                const p = Math.min(1, this._subTimer / Math.round(TRANS_SPEED * 1.1));
                _drawSubSweep(this._subSprite, p);
                if (p >= 1) {
                    this._subDone = true;
                    this.removeChild(this._subSprite); this._subSprite = null;
                }
            }
        };
    }

    function _drawSubSweep(sprite, progress) {
        const bmp = sprite.bitmap; bmp.clear();
        const ctx = getCtx(bmp); if (!ctx) return;
        const W = Graphics.width, H = Graphics.height;
        const sweepX = W * progress;

        // Flash bref au début
        if (progress < 0.06) {
            ctx.save(); ctx.fillStyle = COLOR1;
            ctx.globalAlpha = (0.06 - progress) / 0.06 * 0.5;
            ctx.fillRect(0, 0, W, H); ctx.restore();
        }

        // Rideau sombre principal
        ctx.save(); ctx.fillStyle = COLOR2; ctx.globalAlpha = 0.97;
        ctx.beginPath();
        ctx.moveTo(0, 0); ctx.lineTo(sweepX + 35, 0);
        ctx.lineTo(sweepX - 18, H); ctx.lineTo(0, H);
        ctx.closePath(); ctx.fill(); ctx.restore();

        // Bande rouge sur le bord tranchant
        ctx.save(); ctx.fillStyle = COLOR1; ctx.globalAlpha = 0.9;
        ctx.beginPath();
        ctx.moveTo(sweepX + 20, 0); ctx.lineTo(sweepX + 35, 0);
        ctx.lineTo(sweepX - 4,  H); ctx.lineTo(sweepX - 18, H);
        ctx.closePath(); ctx.fill(); ctx.restore();

        // Ligne lumineuse PAINT
        ctx.save(); ctx.strokeStyle = PAINT; ctx.lineWidth = 2; ctx.globalAlpha = 0.7;
        ctx.beginPath();
        ctx.moveTo(sweepX + 35, 0); ctx.lineTo(sweepX - 18, H);
        ctx.stroke(); ctx.restore();

        // Barre rouge verticale à gauche
        ctx.save(); ctx.fillStyle = COLOR1; ctx.globalAlpha = 1;
        ctx.fillRect(0, 0, 5, H * Math.max(0, 1.05 - progress));
        ctx.restore();

        // Splashes
        if (progress > 0.05 && progress < 0.90) {
            for (let i = 0; i < 4; i++) {
                drawPaintSplash(ctx,
                    sweepX + (Math.random() - 0.5) * 50,
                    (i / 3) * H + (Math.random() - 0.5) * 50,
                    5 + Math.random() * 14, PAINT,
                    0.45 * (1 - progress));
            }
        }
    }

    [Scene_Item, Scene_Skill, Scene_Equip, Scene_Status,
     Scene_Save, Scene_Options, Scene_GameEnd].forEach(addSceneSweep);

    // ============================================================
    // FORMATION — corrigée et fonctionnelle
    // ============================================================
    Scene_Menu.prototype.commandFormation = function () {
        this._commandWindow.deactivate();
        this._statusWindow.setFormationMode(true);
        this._statusWindow.selectLast();
        this._statusWindow.activate();
        this._statusWindow.setHandler('ok',     this.onFormationOk.bind(this));
        this._statusWindow.setHandler('cancel', this.onFormationCancel.bind(this));
    };

    Scene_Menu.prototype.onFormationOk = function () {
        const index = this._statusWindow.index();
        const pendingIndex = this._statusWindow.pendingIndex();
        if (pendingIndex >= 0) {
            $gameParty.swapOrder(index, pendingIndex);
            this._statusWindow.setPendingIndex(-1);
            this._statusWindow.redrawItem(index);
            this._statusWindow.redrawItem(pendingIndex);
            this._statusWindow.activate();
        } else {
            this._statusWindow.setPendingIndex(index);
            this._statusWindow.activate();
        }
    };

    Scene_Menu.prototype.onFormationCancel = function () {
        if (this._statusWindow.pendingIndex() >= 0) {
            this._statusWindow.setPendingIndex(-1);
            this._statusWindow.activate();
        } else {
            this._statusWindow.deactivate();
            this._statusWindow.setFormationMode(false);
            this._commandWindow.activate();
        }
    };

    console.log('[UniqueMenu_MZ v1.7] Transitions stylisées + Formation corrigée');

})();

Embed on website

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