//============================================================================= // NRP_MessageWindow.js //============================================================================= /*: * @target MZ * @plugindesc v1.03 Adjust the message window. * @author Takeshi Sunagawa (http://newrpg.seesaa.net/) * @url https://newrpg.seesaa.net/article/492543897.html * * @help Make various adjustments to the message window. * For example, you can adjust the size and position of the window. * * ------------------------------------------------------------------- * [3-line Message Display] * ------------------------------------------------------------------- * For example, a larger font and a 3-line display of the message * will make the text easier to read. * * As you can find out, most JRPGs and ADVs nowadays * have a style of 2 to 3 lines plus a name field. * The MZ default style of 4 lines + name field is quite a lot of text, * and the text tends to be small, making it difficult to read. * It is not recommended to follow the default style without thinking. * * The key to this is to make the "LineHeight" wider. * * ------------------------------------------------------------------- * [Variable Window Size] * ------------------------------------------------------------------- * Formulas can be used for most items. * For example, if "WindowHeight" is set to "$gameVariables.value(1)", * the height of the message window will change according to * the value of variable 1. * * This is useful, for example, when you want to have * two lines of text in a scene displaying a large image. * * ------------------------------------------------------------------- * [Mask Image Function] * ------------------------------------------------------------------- * By setting "MaskImage", * you can finely adjust the transparency of the window. * For example, you can increase * the transparency only on the right side of the window. * White areas of the mask image * are opaque and black areas are transparent. * ※See the sample image for details. * * Note that this does not work in RPG Maker MV for some reason, * so it is for MZ only. * * ------------------------------------------------------------------- * [Terms] * ------------------------------------------------------------------- * There are no restrictions. * Modification, redistribution freedom, commercial availability, * and rights indication are also optional. * The author is not responsible, * but will deal with defects to the extent possible. * * @------------------------------------------------------------------ * @ Plugin Parameters * @------------------------------------------------------------------ * * @param * * @param WindowWidth * @parent * @default Graphics.boxWidth * @desc The width of the message window. * Default: Graphics.boxWidth * * @param WindowHeight * @parent * @default this.fittingHeight(4) + 8 * @desc The height of the message window. * Default: this.fittingHeight(4) + 8 * * @param WindowX * @parent * @desc X coordinate for displaying the message window. * * @param WindowY * @parent * @default (this._positionType * (Graphics.boxHeight - this.height)) / 2 * @desc Y coordinate for displaying the message window. * Default: (this._positionType * (Graphics.boxHeight - this.height)) / 2 * * @param LineHeight * @parent * @desc The height per line of the message. * Default: 36 * * @param AdjustMessageX * @parent * @type number * @desc Adjust the X coordinate of the message. * * @param AdjustMessageY * @parent * @type number * @desc Adjust the Y coordinate of the message. * * @param MessageFontSize * @parent * @desc The font size of the message. * * @param WindowOpacity * @parent * @desc Opacity of the message window. * 255 makes it completely opaque. * * @param MaskImage * @parent * @type file * @dir img/system * @desc A mask image that applies semi-transparent processing to the window. For MZ only. * * @param NoMaskOpacity * @parent MaskImage * @desc The opacity of the message window if the mask could not be applied to it. * * @param FixIconY * @parent * @type boolean * @default true * @desc Fix a problem in which the Y coordinate of an icon is misaligned when the height of a line is changed. * * @param * @desc This item is related to the name field. * This field is invalid because it does not exist in RPG Maker MV. * * @param NameBoxAdjustX * @parent * @desc X-coordinate correction value for the name field. * * @param NameBoxAdjustY * @parent * @desc Y-coordinate correction value for the name field. * * @param NameBoxFontSize * @parent * @desc The font size of the name field. * * @param NameBoxOpacity * @parent * @desc Opacity of the name field. * 255 makes it completely opaque. * * @param * @desc This section is about choices. * * @param FixChoiceX * @parent * @type boolean * @default true * @desc Align the X coordinate of the Choice window with the Message window. */ /*:ja * @target MZ * @plugindesc v1.03 メッセージウィンドウを調整する。 * @author 砂川赳(http://newrpg.seesaa.net/) * @url https://newrpg.seesaa.net/article/492543897.html * * @help メッセージウィンドウに対して様々な調整を行います。 * 例えば、ウィンドウのサイズや位置を調整できます。 * * ------------------------------------------------------------------- * ■メッセージ表示の3行化 * ------------------------------------------------------------------- * 例えば、フォントを大きくしてメッセージを3行表示にすれば、 * 文章を読みやすくすることができます。 * * 調べてみれば分かりますが、今時のJRPGやADVは * 2~3行+名前欄というスタイルが主流です。 * MZデフォルトの4行+名前欄というスタイルは、 * かなり文章量が多く、文字も小さくなりがちなので読みづらいです。 * 何も考えず初期状態を踏襲することはあまりオススメしません。 * * この際、『一行の縦幅』を広くすることがポイントです。 * 特に漢字にルビを振るプラグインと併用する場合は、 * 行間を広めに取ることをオススメします。 * * ------------------------------------------------------------------- * ■ウィンドウサイズの可変化 * ------------------------------------------------------------------- * ほとんどの項目で数式が使用可能です。 * 例えば『ウィンドウの縦幅』を「$gameVariables.value(1)」にすれば、 * 変数1の値によって、メッセージウィンドウの縦幅が変化するようになります。 * * 例えば「一枚絵を表示するシーンでは文章を2行にしたい」 * といった場合に便利です。 * * ------------------------------------------------------------------- * ■マスク画像機能 * ------------------------------------------------------------------- * 『マスク画像』を設定することで、ウィンドウの透明度を細かく設定できます。 * 例えば、ウィンドウの右側だけ透明度を上げるといった調整ができます。 * マスク画像の白い部分が不透明で黒い部分が透明となります。 * ※詳細はサンプル画像をご覧ください。 * * なお、RPGツクールMVではなぜか機能しないのでMZ専用です。 * * ------------------------------------------------------------------- * ■利用規約 * ------------------------------------------------------------------- * 特に制約はありません。 * 改変、再配布自由、商用可、権利表示も任意です。 * 作者は責任を負いませんが、不具合については可能な範囲で対応します。 * * @------------------------------------------------------------------ * @ プラグインパラメータ * @------------------------------------------------------------------ * * @param * @text <メッセージウィンドウ> * * @param WindowWidth * @parent * @text ウィンドウの横幅 * @default Graphics.boxWidth * @desc メッセージウィンドウの横幅です。 * 初期値は「Graphics.boxWidth」です。 * * @param WindowHeight * @parent * @text ウィンドウの縦幅 * @default this.fittingHeight(4) + 8 * @desc メッセージウィンドウの縦幅です。 * 初期値は「this.fittingHeight(4) + 8」です。 * * @param WindowX * @parent * @text ウィンドウのX座標 * @desc メッセージウィンドウを表示するX座標です。 * * @param WindowY * @parent * @text ウィンドウのY座標 * @default (this._positionType * (Graphics.boxHeight - this.height)) / 2 * @desc メッセージウィンドウを表示するY座標です。 * 初期値:(this._positionType * (Graphics.boxHeight - this.height)) / 2 * * @param LineHeight * @parent * @text 一行の縦幅 * @desc 文章の一行当たりの縦幅です。 * 初期値は36です。 * * @param AdjustMessageX * @parent * @text 文章のX座標調整 * @type number * @desc 文章のX座標を調整します。 * * @param AdjustMessageY * @parent * @text 文章のY座標調整 * @type number * @desc 文章のY座標を調整します。 * * @param MessageFontSize * @parent * @text 文章のフォントサイズ * @desc 文章のフォントサイズです。 * * @param WindowOpacity * @parent * @text ウィンドウの不透明度 * @desc メッセージウィンドウの不透明度です。 * 255で完全な不透明になります。 * * @param MaskImage * @parent * @text マスク画像 * @type file * @dir img/system * @desc ウィンドウに半透明処理を施すマスク画像です。 * この機能はMZ専用です。 * * @param NoMaskOpacity * @parent MaskImage * @text マスク対象外の不透明度 * @desc メッセージウィンドウにマスクを適用できなかった場合の不透明度です。 * * @param FixIconY * @parent * @text アイコンのY座標修正 * @type boolean * @default true * @desc 一行の縦幅を変更した時に、アイコンのY座標がズレる問題を修正します。 * * @param * @text <名前欄> * @desc 名前欄に関する項目です。 * ツクールMVでは存在しないため無効です。 * * @param NameBoxAdjustX * @parent * @text 名前欄のX座標補正 * @desc 名前欄のX座標補正値です。 * * @param NameBoxAdjustY * @parent * @text 名前欄のY座標補正 * @desc 名前欄のY座標補正値です。 * * @param NameBoxFontSize * @parent * @text 名前欄のフォントサイズ * @desc 名前欄のフォントサイズです。 * * @param NameBoxOpacity * @parent * @text 名前欄の不透明度 * @desc 名前欄の不透明度です。 * 255で完全な不透明になります。 * * @param * @text <選択肢> * @desc 選択肢に関する項目です。 * * @param FixChoiceX * @parent * @text 選択肢のX座標修正 * @type boolean * @default true * @desc 選択肢ウィンドウのX座標をメッセージウィンドウに合わせます。 */ (function () { "use strict"; function toBoolean(str, def) { if (str === true || str === "true") { return true; } else if (str === false || str === "false") { return false; } return def; } function toNumber(str, def) { if (str == undefined || str == "") { return def; } return isNaN(str) ? def : +(str || def); } function setDefault(str, def) { if (str == undefined || str == "") { return def; } return str; } /** * ●構造体(二重配列)をJSで扱えるように変換 */ function parseStruct2(arg) { var ret = []; if (arg) { JSON.parse(arg).forEach(function (str) { ret.push(JSON.parse(str)); }); } return ret; } const PLUGIN_NAME = "NRP_MessageWindow"; const parameters = PluginManager.parameters(PLUGIN_NAME); const pWindowWidth = setDefault(parameters["WindowWidth"]); const pWindowHeight = setDefault(parameters["WindowHeight"]); const pWindowX = setDefault(parameters["WindowX"]); const pWindowY = setDefault(parameters["WindowY"]); const pLineHeight = setDefault(parameters["LineHeight"]); const pAdjustMessageX = toNumber(parameters["AdjustMessageX"], 0); const pAdjustMessageY = toNumber(parameters["AdjustMessageY"], 0); const pMessageFontSize = setDefault(parameters["MessageFontSize"]); const pWindowOpacity = setDefault(parameters["WindowOpacity"]); const pMaskImage = setDefault(parameters["MaskImage"]); const pNoMaskOpacity = setDefault(parameters["NoMaskOpacity"]); const pFixIconY = toBoolean(parameters["FixIconY"]); const pNameBoxAdjustX = setDefault(parameters["NameBoxAdjustX"]); const pNameBoxAdjustY = setDefault(parameters["NameBoxAdjustY"]); const pNameBoxFontSize = setDefault(parameters["NameBoxFontSize"]); const pNameBoxOpacity = setDefault(parameters["NameBoxOpacity"]); const pFixChoiceX = toBoolean(parameters["FixChoiceX"], true); // ---------------------------------------------------------------------------- // Scene_Message // ---------------------------------------------------------------------------- // MZのみのクラスなので存在しない場合は無視 if (typeof Scene_Message !== "undefined") { /** * ●メッセージウィンドウのサイズ&配置 */ Scene_Message.prototype.messageWindowRect = function () { // 横幅 let ww = Graphics.boxWidth; if (pWindowWidth != null) { // とりあえず最大領域を確保しておく。 // ※値が小さいとはみ出した文字が表示されないため。 ww = Graphics.width; } // 縦幅 let wh = this.calcWindowHeight(4, false) + 8; if (pWindowHeight != null) { // ダミーのウィンドウを定義して計算 // ※この値は選択肢を呼んだ場合に参照される。 const dummyWindow = new Window_Message(new Rectangle(0, 0, 0, 0)); wh = dummyWindow.calcWindowHeight(); } // 座標はそのまま(updatePlacementで処理) const wx = (Graphics.boxWidth - ww) / 2; const wy = 0; return new Rectangle(wx, wy, ww, wh); }; } // /** // * ●ウィンドウの生成 // * ※PicturePriorityCustomize.jsと併用する場合は重複につき注釈化 // * ※他にも競合するプラグインがあるので保留 // */ // const _Scene_Message_createAllWindows = Scene_Message.prototype.createAllWindows; // Scene_Message.prototype.createAllWindows = function() { // _Scene_Message_createAllWindows.apply(this, arguments); // // //-------------------------------------------------------------------- // // 名前欄の位置変更時、下に隠れたメッセージウィンドウが消えないよう調整 // // ※WindowLayer.prototype.renderの挙動によって、 // //  ウィンドウは重ねられない仕様なので、Scene_Message直下に移動する。 // //-------------------------------------------------------------------- // // メッセージウィンドウ // this.addChild(this._windowLayer.removeChild(this._messageWindow)); // // 名前ウィンドウ // this.addChild(this._windowLayer.removeChild(this._nameBoxWindow)); // // UIエリアの幅を考慮して加算 // // this._messageWindow.x += this._windowLayer.x; // // this._nameBoxWindow.x += this._windowLayer.x; // }; // ---------------------------------------------------------------------------- // Window_Message // ---------------------------------------------------------------------------- let mInitialHeight = 0; /** * ●メッセージウィンドウの初期化 */ const _Window_Message_initialize = Window_Message.prototype.initialize; Window_Message.prototype.initialize = function (rect) { _Window_Message_initialize.apply(this, arguments); // 不透明度 if (pWindowOpacity != null) { this.backOpacity = eval(pWindowOpacity); } // マスク if (pMaskImage != null) { this._maskSprite = new Sprite(); this._maskSprite.bitmap = ImageManager.loadSystem(pMaskImage); this.addChild(this._maskSprite); this.backSprite().mask = this._maskSprite; } // メッセージ用スプライトを位置調整 this.contentsSprite().x += pAdjustMessageX; this.contentsSprite().y += pAdjustMessageY; mInitialHeight = this.height; }; /* * Window_Message.prototype.createContentsが未定義の場合は事前に定義 * ※これをしておかないと以後のWindow_Base側への追記が反映されない。 */ if ( Window_Message.prototype.createContents == Window_Base.prototype.createContents ) { Window_Message.prototype.createContents = function () { Window_Base.prototype.createContents.apply(this, arguments); }; } /** * ●コンテンツ作成 */ const _Window_Message_createContents = Window_Message.prototype.createContents; Window_Message.prototype.createContents = function () { _Window_Message_createContents.apply(this, arguments); // 縦幅が変更されている場合はマスクの対象外なのでクリアする。 // ※想定の縦幅以外はうまく表示できないため if (this._maskSprite && mInitialHeight != this.height) { this.backSprite().mask = null; this._maskSprite.visible = false; // マスク対象外の不透明度 if (pNoMaskOpacity != null) { this.backOpacity = eval(pNoMaskOpacity); } } }; /** * ●メッセージウィンドウの配置 * ※Y座標のみウィンドウ位置で変動するため、ここで制御されている。 */ const _Window_Message_updatePlacement = Window_Message.prototype.updatePlacement; Window_Message.prototype.updatePlacement = function () { let changeFlg = false; // ※サイズを参照して配置を決めているため、先に設定しておく。 // 横幅の更新 if (pWindowWidth != null) { const width = eval(pWindowWidth); if (this.width != width) { this.width = width; changeFlg = true; } } // 縦幅の更新 if (pWindowHeight != null) { const height = this.calcWindowHeight(); if (this.height != height) { this.height = height; changeFlg = true; } } // いずれかを更新した場合 if (changeFlg) { // 描画領域を更新 // これをやらないと文字が表示されなくなる。 this.createContents(); // サイズを文章の表示領域へ反映 // これをやらないと改ページ判定がおかしくなる。 this.contents.resize(this.width, this.height); } // 元の処理 _Window_Message_updatePlacement.apply(this, arguments); // X座標 if (pWindowX != null) { this.x = eval(pWindowX); } // Y座標 if (pWindowY != null) { this.y = eval(pWindowY); } }; /** * 【独自】ウィンドウの高さを計算する。 */ Window_Message.prototype.calcWindowHeight = function () { return eval(pWindowHeight); }; if (pLineHeight != null) { /** * ●メッセージウィンドウの一行当たりの縦幅 */ Window_Message.prototype.lineHeight = function () { return eval(pLineHeight); }; } // Window_Message.prototype.needsNewPage = function(textState) { // alert(textState.y + textState.height + " > " + this.contents.height); // return ( // !this.isEndOfText(textState) && // textState.y + textState.height > this.contents.height // ); // }; /** * ●アイコンのY座標修正 */ if (pFixIconY) { /* * Window_Messageのメソッドが未定義の場合は事前に定義 * ※これをしておかないと以後のWindow_Base側への追記が反映されない。 */ if ( Window_Message.prototype.processDrawIcon == Window_Base.prototype.processDrawIcon ) { Window_Message.prototype.processDrawIcon = function ( iconIndex, textState ) { Window_Base.prototype.processDrawIcon.apply(this, arguments); }; } /** * ●アイコンの描画 */ const _Window_Message_processDrawIcon = Window_Message.prototype.processDrawIcon; Window_Message.prototype.processDrawIcon = function (iconIndex, textState) { // 描画しない場合は処理終了 if (!textState.drawing) { _Window_Message_processDrawIcon.apply(this, arguments); return; } // アイコンのY座標の算出に縦幅を考慮 const iconY = textState.y + (this.lineHeight() - ImageManager.iconHeight) / 2; this.drawIcon(iconIndex, textState.x + 2, iconY); textState.x += ImageManager.iconWidth + 4; }; } if (pMessageFontSize != null) { /* * Window_Messageのメソッドが未定義の場合は事前に定義 * ※これをしておかないと以後のWindow_Base側への追記が反映されない。 */ if ( Window_Message.prototype.resetFontSettings == Window_Base.prototype.resetFontSettings ) { Window_Message.prototype.resetFontSettings = function () { Window_Base.prototype.resetFontSettings.apply(this, arguments); }; } /** * ●フォントサイズの設定 */ const _Window_Message_resetFontSettings = Window_Message.prototype.resetFontSettings; Window_Message.prototype.resetFontSettings = function () { _Window_Message_resetFontSettings.apply(this, arguments); this.contents.fontSize = eval(pMessageFontSize); }; } if (pMaskImage != null) { /* * Window_Messageのメソッドが未定義の場合は事前に定義 */ if ( Window_Message.prototype.showBackgroundDimmer == Window_Base.prototype.showBackgroundDimmer ) { Window_Message.prototype.showBackgroundDimmer = function () { Window_Base.prototype.showBackgroundDimmer.apply(this, arguments); }; } /** * ●暗いウィンドウの表示 */ const _Window_Message_showBackgroundDimmer = Window_Message.prototype.showBackgroundDimmer; Window_Message.prototype.showBackgroundDimmer = function () { this.backSprite().mask = null; this._maskSprite.visible = false; _Window_Message_showBackgroundDimmer.apply(this, arguments); }; /* * Window_Messageのメソッドが未定義の場合は事前に定義 */ if ( Window_Message.prototype.hideBackgroundDimmer == Window_Base.prototype.hideBackgroundDimmer ) { Window_Message.prototype.hideBackgroundDimmer = function () { Window_Base.prototype.hideBackgroundDimmer.apply(this, arguments); }; } /** * ●暗いウィンドウの非表示 */ const _Window_Message_hideBackgroundDimmer = Window_Message.prototype.hideBackgroundDimmer; Window_Message.prototype.hideBackgroundDimmer = function () { this.backSprite().mask = this._maskSprite; this._maskSprite.visible = true; _Window_Message_hideBackgroundDimmer.apply(this, arguments); }; } /** * 【独自】文字描画用のスプライトを取得 */ Window_Message.prototype.contentsSprite = function () { // MZ用 if (this._contentsSprite) { return this._contentsSprite; // MV用 } else if (this._windowContentsSprite) { return this._windowContentsSprite; } }; /** * 【独自】背景描画用のスプライトを取得 */ Window_Message.prototype.backSprite = function () { // MZ用 if (this._backSprite) { return this._backSprite; // MV用 } else if (this._windowBackSprite) { return this._windowBackSprite; } }; // ---------------------------------------------------------------------------- // Window_ChoiceList // ---------------------------------------------------------------------------- // 選択肢ウィンドウのX座標をメッセージウィンドウに合わせる。 if (pFixChoiceX) { /** * ●選択肢ウィンドウのX座標 */ const _Window_ChoiceList_windowX = Window_ChoiceList.prototype.windowX; Window_ChoiceList.prototype.windowX = function () { const positionType = $gameMessage.choicePositionType(); // メッセージウィンドウを取得 const messageWindow = SceneManager._scene._messageWindow; // 中 if (positionType === 1) { // 元のまま return _Window_ChoiceList_windowX.apply(this, arguments); // 右 } else if (positionType === 2) { return Math.min( Graphics.boxWidth - this.windowWidth(), messageWindow.x + messageWindow.width - this.windowWidth() ); // 左 } else { return Math.max(0, messageWindow.x); } }; } // ---------------------------------------------------------------------------- // Window_NameBox // ---------------------------------------------------------------------------- // MZのみのクラスなので存在しない場合は無視 if (typeof Window_NameBox !== "undefined") { /** * ●名前欄の初期化 */ const _Window_NameBox_initialize = Window_NameBox.prototype.initialize; Window_NameBox.prototype.initialize = function (rect) { _Window_NameBox_initialize.apply(this, arguments); // 不透明度 if (pNameBoxOpacity != null) { this.backOpacity = eval(pNameBoxOpacity); } }; /** * ●名前欄の配置 */ const _Window_NameBox_updatePlacement = Window_NameBox.prototype.updatePlacement; Window_NameBox.prototype.updatePlacement = function () { _Window_NameBox_updatePlacement.apply(this, arguments); // X座標補正 if (pNameBoxAdjustX != null) { this.x += eval(pNameBoxAdjustX); } // Y座標補正 if (pNameBoxAdjustY != null) { this.y += eval(pNameBoxAdjustY); } }; if (pNameBoxFontSize != null) { /* * Window_NameBoxのメソッドが未定義の場合は事前に定義 * ※これをしておかないと以後のWindow_Base側への追記が反映されない。 */ if ( Window_NameBox.prototype.resetFontSettings == Window_Base.prototype.resetFontSettings ) { Window_NameBox.prototype.resetFontSettings = function () { Window_Base.prototype.resetFontSettings.apply(this, arguments); }; } /** * ●フォントサイズの設定 */ const _Window_NameBox_resetFontSettings = Window_Message.prototype.resetFontSettings; Window_NameBox.prototype.resetFontSettings = function () { _Window_NameBox_resetFontSettings.apply(this, arguments); this.contents.fontSize = eval(pNameBoxFontSize); }; } } })();