diff --git a/js/plugins.js b/js/plugins.js index 1013580..2a7b35c 100644 --- a/js/plugins.js +++ b/js/plugins.js @@ -2520,4 +2520,15 @@ var $plugins = [ url: "https://www.dlsite.com/maniax/announce/=/product_id/RJ01412576.html", }, }, + { + name: "AutoScrollHelpWindow", + status: true, + description: "Auto-scrolls help window text when it's too long to fit", + parameters: { + scrollSpeed: "1", + scrollDelay: "60", + pauseAtTop: "60", + pauseAtBottom: "120", + }, + }, ]; diff --git a/js/plugins/AutoScrollHelpWindow.js b/js/plugins/AutoScrollHelpWindow.js new file mode 100644 index 0000000..c6f62eb --- /dev/null +++ b/js/plugins/AutoScrollHelpWindow.js @@ -0,0 +1,133 @@ +/*: + * @target MZ + * @plugindesc Auto-scrolls help window text when it's too long to fit + * @author GitHub Copilot + * @url https://github.com/ + * + * @param scrollSpeed + * @text Scroll Speed + * @desc Speed of auto-scroll in pixels per frame (default: 0.5) + * @type number + * @decimals 2 + * @default 0.5 + * + * @param pauseAtTop + * @text Pause At Top + * @desc Frames to pause when at top before scrolling (default: 90) + * @type number + * @default 90 + * + * @param pauseAtBottom + * @text Pause At Bottom + * @desc Frames to pause when scrolled to bottom (default: 90) + * @type number + * @default 90 + * + * @help AutoScrollHelpWindow.js + * + * This plugin automatically scrolls the help window text when it's too long + * to fit in the window. This is particularly useful for passive skill + * descriptions in the body history menu. + * + * No plugin commands needed - it works automatically! + */ + +(() => { + 'use strict'; + + const pluginName = 'AutoScrollHelpWindow'; + const parameters = PluginManager.parameters(pluginName); + const scrollSpeed = Number(parameters['scrollSpeed'] || 0.5); + const pauseAtTop = Number(parameters['pauseAtTop'] || 90); + const pauseAtBottom = Number(parameters['pauseAtBottom'] || 90); + + //----------------------------------------------------------------------------- + // Window_Help + //----------------------------------------------------------------------------- + + const _Window_Help_initialize = Window_Help.prototype.initialize; + Window_Help.prototype.initialize = function(rect) { + _Window_Help_initialize.call(this, rect); + this._scrollData = { + y: 0, + timer: pauseAtTop, + state: 'waiting', + maxScroll: 0, + enabled: false + }; + this._baseContentsHeight = this.contents.height; + }; + + const _Window_Help_setText = Window_Help.prototype.setText; + Window_Help.prototype.setText = function(text) { + const changed = (this._text !== text); + _Window_Help_setText.call(this, text); + if (changed) { + this._scrollData.y = 0; + this._scrollData.timer = pauseAtTop; + this._scrollData.state = 'waiting'; + this.origin.y = 0; + } + }; + + // Call original refresh, then setup scrolling after + const _Window_Help_refresh = Window_Help.prototype.refresh; + Window_Help.prototype.refresh = function() { + // Measure text first + const textSize = this._text ? this.textSizeEx(this._text) : { width: 0, height: 0 }; + const neededHeight = textSize.height + 16; + + // Ensure contents is big enough + if (neededHeight > this.contents.height) { + this.contents.resize(this.contents.width, neededHeight); + } + + // Call original refresh (clears and draws) + _Window_Help_refresh.call(this); + + // Setup scroll parameters + const rect = this.baseTextRect(); + this._scrollData.maxScroll = Math.max(0, textSize.height - rect.height); + this._scrollData.enabled = this._scrollData.maxScroll > 2; + }; + + const _Window_Help_update = Window_Help.prototype.update; + Window_Help.prototype.update = function() { + _Window_Help_update.call(this); + this.updateAutoScroll(); + }; + + Window_Help.prototype.updateAutoScroll = function() { + const s = this._scrollData; + if (!s || !s.enabled) { + if (this.origin.y !== 0) this.origin.y = 0; + return; + } + + switch (s.state) { + case 'waiting': + if (--s.timer <= 0) s.state = 'down'; + break; + case 'down': + s.y = Math.min(s.y + scrollSpeed, s.maxScroll); + this.origin.y = Math.floor(s.y); + if (s.y >= s.maxScroll) { + s.state = 'paused'; + s.timer = pauseAtBottom; + } + break; + case 'paused': + if (--s.timer <= 0) s.state = 'up'; + break; + case 'up': + s.y = Math.max(s.y - scrollSpeed * 2, 0); + this.origin.y = Math.floor(s.y); + if (s.y <= 0) { + s.state = 'waiting'; + s.timer = pauseAtTop; + } + break; + } + }; + +})();