//=============================================================================
// PatchNotes_MZ.js
//=============================================================================
/*:
 * @target MZ
 * @plugindesc [PatchNotes_MZ] Ajoute "Patch Notes" sur l'écran titre.
 * @author Bertran
 *
 * @param commandName
 * @text Nom du bouton
 * @desc Texte affiché sur l'écran titre.
 * @type string
 * @default PATCH NOTES
 *
 * @param entries
 * @text Entrées de patch notes
 * @type struct<Entry>[]
 * @default []
 *
 * @param scrollSpeed
 * @text Vitesse de défilement
 * @type number
 * @min 1
 * @max 10
 * @default 3
 *
 */
/*~struct~Entry:
 *
 * @param version
 * @text Version
 * @type string
 * @default Version X.X.X
 *
 * @param date
 * @text Date
 * @type string
 * @default
 *
 * @param notes
 * @text Contenu
 * @type multiline_string
 * @default - Nouveautés
 */

(() => {
    'use strict';

    // -------------------------------------------------------------------------
    // Récupération des paramètres — cherche avec plusieurs variantes du nom
    // au cas où le gestionnaire de plugins utilise un nom légèrement différent
    // -------------------------------------------------------------------------
    const NAMES = ['PatchNotes_MZ', 'patchnotes_mz', 'PatchNotes', 'patchnotes'];
    let params = {};
    for (const n of NAMES) {
        const p = PluginManager.parameters(n);
        if (p && (p.commandName || p.entries)) { params = p; break; }
    }
    // Fallback : parcourir TOUS les paramètres enregistrés
    if (!params.commandName && !params.entries) {
        for (const key of Object.keys(PluginManager._parameters || {})) {
            if (key.toLowerCase().includes('patchnote')) {
                params = PluginManager._parameters[key];
                break;
            }
        }
    }

    const COMMAND_NAME = String(params.commandName || 'PATCH NOTES');
    const SCROLL_SPEED = Number(params.scrollSpeed  || 3);

    function parseEntries(raw) {
        if (!raw || raw.trim() === '' || raw.trim() === '[]') return [];
        let arr;
        try { arr = JSON.parse(raw); } catch(e) { return []; }
        if (!Array.isArray(arr)) return [];
        const result = [];
        for (const item of arr) {
            let obj;
            try { obj = (typeof item === 'string') ? JSON.parse(item) : item; }
            catch(e) { continue; }
            if (!obj) continue;
            result.push({
                version : String(obj.version || ''),
                date    : String(obj.date    || ''),
                notes   : String(obj.notes   || '').replace(/\\n/g, '\n'),
            });
        }
        return result;
    }

    const ENTRIES = parseEntries(params.entries);

    // -------------------------------------------------------------------------
    // Menu titre
    // -------------------------------------------------------------------------
    const _makeCommandList = Window_TitleCommand.prototype.makeCommandList;
    Window_TitleCommand.prototype.makeCommandList = function() {
        _makeCommandList.call(this);
        this.addCommand(COMMAND_NAME, 'patchNotes');
    };

    const _createCommandWindow = Scene_Title.prototype.createCommandWindow;
    Scene_Title.prototype.createCommandWindow = function() {
        _createCommandWindow.call(this);
        this._commandWindow.setHandler('patchNotes', this.commandPatchNotes.bind(this));
    };

    Scene_Title.prototype.commandPatchNotes = function() {
        this._commandWindow.close();
        SceneManager.push(Scene_PatchNotes);
    };

    // =========================================================================
    // Scene_PatchNotes
    // =========================================================================
    function Scene_PatchNotes() { this.initialize(...arguments); }
    Scene_PatchNotes.prototype = Object.create(Scene_MenuBase.prototype);
    Scene_PatchNotes.prototype.constructor = Scene_PatchNotes;

    Scene_PatchNotes.prototype.create = function() {
        Scene_MenuBase.prototype.create.call(this);
        const rect = new Rectangle(0, 0, Graphics.boxWidth, Graphics.boxHeight);
        this._patchWindow = new Window_PatchNotes(rect);
        this.addWindow(this._patchWindow);
    };

    Scene_PatchNotes.prototype.update = function() {
        Scene_MenuBase.prototype.update.call(this);
        if (Input.isTriggered('cancel')) {
            SoundManager.playCancel();
            this.popScene();
        }
    };

    // =========================================================================
    // Window_PatchNotes
    // =========================================================================
    function Window_PatchNotes() { this.initialize(...arguments); }
    Window_PatchNotes.prototype = Object.create(Window_Scrollable.prototype);
    Window_PatchNotes.prototype.constructor = Window_PatchNotes;

    Window_PatchNotes.prototype.initialize = function(rect) {
        Window_Scrollable.prototype.initialize.call(this, rect);
        this.refresh();
    };

    Window_PatchNotes.prototype.scrollBlockHeight = function() { return this.lineHeight(); };
    Window_PatchNotes.prototype.overallHeight      = function() { return this._totalHeight || this.innerHeight; };
    Window_PatchNotes.prototype.isScrollEnabled    = function() { return true; };

    Window_PatchNotes.prototype.refresh = function() {
        const lh  = this.lineHeight();
        const pad = this.itemPadding();
        const iw  = this.innerWidth - pad * 2;
        let   y   = pad;

        this.contents.clear();

        if (ENTRIES.length === 0) {
            this._totalHeight = this.innerHeight;
            this.contents.resize(this.innerWidth, this._totalHeight);
            this.resetTextColor();
            // Affiche aussi les params bruts pour aider au debug
            const debugLine = 'Params: cmd="' + COMMAND_NAME + '" entries="' + (params.entries || '') + '"';
            this.contents.fontSize = 14;
            this.contents.drawText(debugLine, pad, 20, iw, lh);
            this.contents.fontSize = $gameSystem.mainFontSize();
            this.contents.drawText(
                'Aucune note de mise à jour disponible.',
                pad, Math.floor(this.innerHeight / 2 - lh / 2), iw, lh, 'center'
            );
            return;
        }

        // Calculer hauteur totale
        let totalH = pad;
        for (const e of ENTRIES) {
            totalH += lh + 8;
            if (e.date) totalH += lh;
            totalH += 12;
            totalH += e.notes.split('\n').length * lh;
            totalH += lh;
        }
        totalH += pad;
        this._totalHeight = Math.max(totalH, this.innerHeight);
        this.contents.resize(this.innerWidth, this._totalHeight);

        for (const entry of ENTRIES) {
            this.changeTextColor(ColorManager.systemColor());
            const fs = this.contents.fontSize;
            this.contents.fontSize = fs + 4;
            this.contents.drawText(entry.version, pad, y, iw, lh);
            this.contents.fontSize = fs;
            y += lh + 8;

            if (entry.date) {
                this.changeTextColor(ColorManager.textColor(8));
                this.contents.drawText(entry.date, pad, y, iw, lh);
                y += lh;
            }

            this.contents.fillRect(pad, y + 4, iw, 2, ColorManager.textColor(7));
            y += 12;

            this.resetTextColor();
            for (const line of entry.notes.split('\n')) {
                this.contents.drawText(line, pad + 8, y, iw - 8, lh);
                y += lh;
            }
            y += lh;
        }
    };

    Window_PatchNotes.prototype.update = function() {
        Window_Scrollable.prototype.update.call(this);
        if (Input.isPressed('down')) this.smoothScrollDown(SCROLL_SPEED);
        if (Input.isPressed('up'))   this.smoothScrollUp(SCROLL_SPEED);
    };

})();
// ============================================================================
// PATCH : Ajout du retour avec Échap / B / clic droit
// ============================================================================
(() => {

    // Ajoute un handler de retour à la fenêtre Patch Notes
    const _PatchNotes_initialize = Window_PatchNotes.prototype.initialize;
    Window_PatchNotes.prototype.initialize = function(rect) {
        _PatchNotes_initialize.call(this, rect);
        this.setHandler('cancel', () => {
            SoundManager.playCancel();
            SceneManager.pop();
        });
        this.activate();
    };

    // Permet aussi de quitter même si la fenêtre n’a pas le focus
    const _Scene_PatchNotes_update = Scene_PatchNotes.prototype.update;
    Scene_PatchNotes.prototype.update = function() {
        _Scene_PatchNotes_update.call(this);
        if (Input.isTriggered('cancel') || TouchInput.isCancelled()) {
            SoundManager.playCancel();
            SceneManager.pop();
        }
    };

})();

Embed on website

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