treasure/js/plugins/LL_GalgeChoiceWindow.js
2025-10-01 19:10:49 -05:00

660 lines
23 KiB
JavaScript

//=============================================================================
// RPGツクールMZ - LL_GalgeChoiceWindow.js v2.0.1
//-----------------------------------------------------------------------------
// ルルの教会 (Lulu's Church)
// https://nine-yusha.com/
//
// URL below for license details.
// https://nine-yusha.com/plugin/
//=============================================================================
/*:
* @target MZ
* @plugindesc ノベルゲーム風選択肢ウィンドウプラグイン
* @author ルルの教会
* @url https://nine-yusha.com/plugin-galgechoicewindow/
*
* @help LL_GalgeChoiceWindow.js
*
* ノベルゲーム風の選択肢ウィンドウを表示します。
* 独自のウィンドウ画像、ボタン画像を設定することもできます。
* (画像はimg/systemフォルダに配置してください)
*
* プラグインコマンド:
* 選択肢の表示: 選択肢を表示し、結果を変数で受け取ります。
*
* 利用規約:
* ・著作権表記は必要ございません。
* ・利用するにあたり報告の必要は特にございません。
* ・商用・非商用問いません。
* ・R18作品にも使用制限はありません。
* ・ゲームに合わせて自由に改変していただいて問題ございません。
* ・プラグイン素材としての再配布(改変後含む)は禁止させていただきます。
*
* 作者: ルルの教会
* 作成日: 2022/12/9
*
* @command showChoice
* @text 選択肢の表示
* @desc 選択肢を表示し、結果を変数で受け取ります。
*
* @arg messageText
* @text 質問メッセージ
* @desc 質問メッセージです。 (2行以内推奨)
* \V[n]、\N[n]、\P[n]、\Gの制御文字が使用できます。
* @type multiline_string
*
* @arg choices
* @text 選択肢リスト
* @desc 選択肢として表示する文字列のリストです。
* @default []
* @type struct<choices>[]
*
* @arg maxCols
* @text 選択肢列数
* @desc 選択肢を何列で表示するかの設定です。
* @default 1
* @min 1
* @max 20
* @type number
*
* @arg variableNumber
* @text 結果受け取り変数
* @desc 選択結果を受け取る変数IDを指定します。
* @type variable
*
* @arg cancelType
* @text キャンセル許可
* @desc キャンセルされた場合は-1が変数に代入されます。
* @default true
* @type boolean
*
* @arg iniPosition
* @text 初期カーソル位置
* @desc カーソルの初期位置です。(0にすると選択なし)
* 数値を入力するか変数で指定することもできます。
* @default 1
* @type combo
* @option $gameVariables.value(1) // 変数ID:1の値
* @option 0
* @option 1
* @option 2
* @option 3
* @option 4
* @option 5
* @option 6
*
* @arg windowWidth
* @text ウィンドウ幅
* @desc 選択肢ウィンドウの幅です。
* 背景画像を使用する場合は横幅を調整してください。
* @default 480
* @min 0
* @max 9999
* @type number
*
* @arg windowBgImage
* @text ウィンドウ画像
* @desc ウィンドウ画像を使用する場合は画像を選択してください。
* 標準のウィンドウ枠は非表示になります。
* @dir img/system
* @type file
* @require 1
*
* @arg buttonBgImage
* @text ボタン画像
* @desc ボタン画像を使用する場合は画像を選択してください。
* @dir img/system
* @type file
* @require 1
*
* @arg buttonFocusImage
* @text ボタン画像(選択時)
* @desc フォーカス時のボタン画像を選択してください。
* ベースとなるボタン画像と大きさを必ず統一してください。
* @dir img/system
* @type file
* @require 1
*
* @arg buttonImageAdjustX
* @text ボタン画像X座標
* @desc ボタン画像の表示位置(X)の調整値です。(初期値: 0)
* +で右へ、-で左へ調整します。
* @default 0
* @min -9999
* @max 9999
* @type number
*
* @arg buttonImageAdjustY
* @text ボタン画像Y座標
* @desc ボタン画像の表示位置(Y)の調整値です。(初期値: 0)
* +で下へ、-で上へ調整します。
* @default 0
* @min -9999
* @max 9999
* @type number
*
* @arg itemHeightAdjust
* @text 選択肢項目高さ
* @desc 選択肢項目の高さの調整値です。(初期値: 8)
* 画像が重なってしまう場合はこの数値を大きくしてください。
* @default 8
* @min -9999
* @max 9999
* @type number
*/
/*~struct~choices:
*
* @param label
* @text 選択肢文字列
* @desc 選択肢として表示する文字列です。
* \V[n]、\N[n]、\P[n]、\Gの制御文字が使用できます。
* @type string
*
* @param switchId
* @text スイッチID
* @desc スイッチON時のみ選択肢を表示したい場合に設定します。
* 通常は「なし」のままで問題ありません。
* @type switch
*
* @param resultNumber
* @text 結果返却値
* @desc この選択肢が選ばれた時に変数に入力する値を指定できます。
* 「0」にすると自動で選択肢番号が返却されます。
* @default 0
* @min 0
* @max 99999999
* @type number
*/
(() => {
"use strict";
const pluginName = "LL_GalgeChoiceWindow";
const parameters = PluginManager.parameters(pluginName);
// Padding
const gcwWindowPadding = 32;
// キャンセル許可時のタッチUI戻るボタンの表示
const gcwCancelButtonEnabled = false;
// フェードイン効果フレーム
const gcwFadeInFrame = 32;
// 設定保存用変数定義
let messageTextLists = [];
let choiceLists = [];
let maxCols = 1;
let variableNumber = 0;
let cancelType = true;
let iniPosition = 1;
let gcwWindowWidth = 480;
let backgroundImage = "";
let gcwButtonImage = "";
let gcwButtonFocusImage = "";
let gcwButtonAdjustX = 0;
let gcwButtonAdjustY = 0;
let gcwItemHeightAdjust = 8;
PluginManager.registerCommand(pluginName, "showChoice", function(args) {
// 設定を取得
const messageText = String(args.messageText).split("\n");
const choices = JSON.parse(args.choices || "null");
maxCols = Number(args.maxCols || 1);
variableNumber = Number(args.variableNumber);
cancelType = String(args.cancelType) === "true" ? true : false;
iniPosition = eval(args.iniPosition);
gcwWindowWidth = Number(args.windowWidth || 480);
backgroundImage = String(args.windowBgImage || "");
gcwButtonImage = String(args.buttonBgImage || "");
gcwButtonFocusImage = String(args.buttonFocusImage || "");
gcwButtonAdjustX = Number(args.buttonImageAdjustX || 0);
gcwButtonAdjustY = Number(args.buttonImageAdjustY || 0);
gcwItemHeightAdjust = Number(args.itemHeightAdjust || 8);
messageTextLists = [];
if (messageText != "") {
messageText.forEach((elm) => {
messageTextLists.push(String(elm));
});
}
// 選択肢を定義
choiceLists = [];
if (choices) {
choices.forEach((elm) => {
if (Number(JSON.parse(elm).switchId) === 0 || $gameSwitches.value(Number(JSON.parse(elm).switchId))) {
choiceLists.push(JSON.parse(elm));
}
});
}
// 選択肢が空の場合、終了
if (choiceLists.length == 0) {
console.log(pluginName + ": 有効な選択肢が存在しなかったため、コマンドがスキップされました");
return;
}
if (!$gameMessage.isBusy()) {
$gameMessage.setGalgeChoices(choiceLists);
this.setWaitMode('message');
}
});
//-----------------------------------------------------------------------------
// Game_Message
//
const _Game_Message_clear = Game_Message.prototype.clear;
Game_Message.prototype.clear = function() {
_Game_Message_clear.apply(this, arguments);
this._galgeChoices = [];
};
Game_Message.prototype.galgeChoices = function() {
return this._galgeChoices;
};
Game_Message.prototype.isGalgeChoice = function() {
return this._galgeChoices.length > 0;
};
Game_Message.prototype.setGalgeChoices = function(choices) {
this._galgeChoices = choices;
};
const _Game_Message_isBusy = Game_Message.prototype.isBusy;
Game_Message.prototype.isBusy = function() {
return (
_Game_Message_isBusy.apply(this, arguments) ||
this.isGalgeChoice()
);
};
//-----------------------------------------------------------------------------
// Scene_Message
//
const _Scene_Message_createAllWindows = Scene_Message.prototype.createAllWindows;
Scene_Message.prototype.createAllWindows = function() {
this.createGalgeChoiceListWindow();
_Scene_Message_createAllWindows.apply(this, arguments);
};
Scene_Message.prototype.createGalgeChoiceListWindow = function() {
this._galgeChoiceListWindow = new Window_GalgeChoiceList();
this.addWindow(this._galgeChoiceListWindow);
};
const _Scene_Message_associateWindows = Scene_Message.prototype.associateWindows;
Scene_Message.prototype.associateWindows = function() {
_Scene_Message_associateWindows.apply(this, arguments);
const messageWindow = this._messageWindow;
messageWindow.setGalgeChoiceListWindow(this._galgeChoiceListWindow);
if (this._galgeChoiceListWindow) this._galgeChoiceListWindow.setMessageWindow(messageWindow);
};
//-----------------------------------------------------------------------------
// Window_Message
//
const _Window_Message_initMembers = Window_Message.prototype.initMembers;
Window_Message.prototype.initMembers = function() {
_Window_Message_initMembers.apply(this, arguments);
this._galgeChoiceListWindow = null;
};
const _Window_Message_startInput = Window_Message.prototype.startInput;
Window_Message.prototype.startInput = function() {
if ($gameMessage.isGalgeChoice()) {
this._galgeChoiceListWindow.start();
return true;
}
return _Window_Message_startInput.apply(this, arguments);
};
Window_Message.prototype.setGalgeChoiceListWindow = function(galgeChoiceListWindow) {
this._galgeChoiceListWindow = galgeChoiceListWindow;
};
const _Window_Message_isAnySubWindowActive = Window_Message.prototype.isAnySubWindowActive;
Window_Message.prototype.isAnySubWindowActive = function() {
if (this._galgeChoiceListWindow) {
return (
_Window_Message_isAnySubWindowActive.apply(this, arguments) ||
this._galgeChoiceListWindow.active
);
}
return _Window_Message_isAnySubWindowActive.apply(this, arguments);
};
//-----------------------------------------------------------------------------
// Window_GalgeChoiceList
//
// ノベルゲーム風選択肢ウィンドウを定義します。
function Window_GalgeChoiceList() {
this.initialize(...arguments);
}
Window_GalgeChoiceList.prototype = Object.create(Window_Command.prototype);
Window_GalgeChoiceList.prototype.constructor = Window_GalgeChoiceList;
Window_GalgeChoiceList.prototype.initialize = function() {
Window_Command.prototype.initialize.call(this, new Rectangle());
this.createCancelButton();
this.openness = 0;
this.deactivate();
this._background = 0;
this._canRepeat = false;
// フォーカスアニメーション判定
this._originalCursorSpriteFade = true;
};
Window_GalgeChoiceList.prototype.setMessageWindow = function(messageWindow) {
this._messageWindow = messageWindow;
};
Window_GalgeChoiceList.prototype.createCancelButton = function() {
if (ConfigManager.touchUI) {
this._cancelButton = new Sprite_Button("cancel");
this._cancelButton.visible = false;
this.addChild(this._cancelButton);
}
};
Window_GalgeChoiceList.prototype.start = function() {
this.updatePlacement();
this.createCancelButton();
this.placeCancelButton();
this.createContents();
this.refresh();
this.setQuestionText();
this.setSymbol();
this.createOriginalBackground();
this.open();
this.activate();
};
const _Window_GalgeChoiceList_refresh = Window_GalgeChoiceList.prototype.refresh;
Window_GalgeChoiceList.prototype.refresh = function() {
this.removeChild(this._bgSprite);
this._bgSprite = null;
this.removeChild(this._bgDummy);
this._bgDummy = null;
this.removeChild(this._originalCursorSprite);
this._originalCursorSprite = null;
this.removeChild(this._originalButtonSprite);
this._originalButtonSprite = null;
// ウィンドウ枠、カーソルを初期化
this.setCursorRect(0, 0, 0, 0);
this.opacity = 255;
_Window_GalgeChoiceList_refresh.apply(this, arguments);
};
Window_GalgeChoiceList.prototype.updatePlacement = function() {
const wh = this.calcWindowHeight();
const ww = gcwWindowWidth;
const wx = (Graphics.boxWidth - ww) / 2;
const wy = (Graphics.boxHeight - wh) / 2;
this.width = ww;
this.height = wh;
this.x = wx;
this.y = wy;
};
Window_GalgeChoiceList.prototype.calcWindowHeight = function() {
// ウィンドウの高さを計算
const itemCols = Math.ceil(choiceLists.length / maxCols);
let height = this.lineHeight() * messageTextLists.length;
if (messageTextLists.length > 0) height += gcwWindowPadding;
height += (this.itemHeight()) * itemCols;
height += gcwWindowPadding * 2; // padding
return height;
};
Window_GalgeChoiceList.prototype.createCancelButton = function() {
if (ConfigManager.touchUI) {
this._cancelButton = new Sprite_Button("cancel");
this._cancelButton.visible = false;
this.addChild(this._cancelButton);
}
};
Window_GalgeChoiceList.prototype.createOriginalBackground = function() {
if (backgroundImage != "") {
this._bgSprite = new Sprite();
this._bgSprite.bitmap = ImageManager.loadSystem(backgroundImage);
this._bgSprite.bitmap.addLoadListener(function() {
this._bgSprite.x = this.width / 2 - this._bgSprite.width / 2;
this._bgSprite.y = this.height / 2 - this._bgSprite.height / 2;
}.bind(this));
this._bgSprite.opacity = 0;
this.addChildToBack(this._bgSprite);
// ウィンドウ枠を消去
this.opacity = 0;
}
};
Window_GalgeChoiceList.prototype.drawAllItems = function() {
this.createOriginalCursor();
this.createOriginalButton();
Window_Selectable.prototype.drawAllItems.call(this);
};
Window_GalgeChoiceList.prototype.createOriginalCursor = function() {
if (gcwButtonFocusImage != "") {
this._originalCursorSprite = null;
this._originalCursorSprite = new Sprite();
this._originalCursorSprite.bitmap = ImageManager.loadSystem(gcwButtonFocusImage);
this._originalCursorSprite.opacity = 128;
this._originalCursorSprite.visible = true;
this.addChildToBack(this._originalCursorSprite);
}
};
Window_GalgeChoiceList.prototype.createOriginalButton = function() {
if (gcwButtonImage != "") {
this._originalButtonSprite = null;
this._originalButtonSprite = new Sprite();
this._originalButtonSprite.visible = false;
this.addChildToBack(this._originalButtonSprite);
}
};
Window_GalgeChoiceList.prototype.drawBackgroundRect = function(rect) {
const c1 = ColorManager.itemBackColor1();
const c2 = ColorManager.itemBackColor2();
const x = rect.x;
const y = rect.y;
const w = rect.width;
const h = rect.height;
if (gcwButtonImage != "") {
const originalButtonSprite = new Sprite();
originalButtonSprite.bitmap = ImageManager.loadSystem(gcwButtonImage);
originalButtonSprite.x = x + gcwButtonAdjustX + gcwWindowPadding;
originalButtonSprite.y = y + gcwButtonAdjustY + gcwWindowPadding;
this._originalButtonSprite.addChild(originalButtonSprite);
} else {
this.contentsBack.gradientFillRect(x, y, w, h, c1, c2, true);
this.contentsBack.strokeRect(x, y, w, h, c1);
}
};
Window_GalgeChoiceList.prototype.refreshCursor = function() {
if (this._cursorAll) {
this.refreshCursorForAll();
} else if (this.index() >= 0) {
const rect = this.itemRect(this.index());
if (gcwButtonFocusImage != "") {
if (this._originalCursorSprite) {
this._originalCursorSprite.x = rect.x + gcwButtonAdjustX + gcwWindowPadding;
this._originalCursorSprite.y = rect.y + gcwButtonAdjustY + gcwWindowPadding;
}
} else {
this.setCursorRect(rect.x, rect.y, rect.width, rect.height);
}
} else {
this.setCursorRect(0, 0, 0, 0);
}
};
Window_GalgeChoiceList.prototype.refreshCursorForAll = function() {
const maxItems = this.maxItems();
if (maxItems > 0) {
const rect = this.itemRect(0);
rect.enlarge(this.itemRect(maxItems - 1));
if (gcwButtonFocusImage != "") {
if (this._originalCursorSprite) {
this._originalCursorSprite.x = rect.x + gcwButtonAdjustX;
this._originalCursorSprite.y = rect.y + gcwButtonAdjustY;
}
} else {
this.setCursorRect(rect.x, rect.y, rect.width, rect.height);
}
} else {
this.setCursorRect(0, 0, 0, 0);
}
};
Window_GalgeChoiceList.prototype.update = function() {
Window_Command.prototype.update.call(this);
this.updateCancelButton();
this.updateOriginalButton();
this.updateOriginalCursorButton();
if (this._bgSprite) this._bgSprite.opacity = this.openness;
};
Window_GalgeChoiceList.prototype.updateOriginalButton = function() {
if (this._originalButtonSprite) {
if (this.isOpen()) {
this._originalButtonSprite.visible = true;
} else {
this._originalButtonSprite.visible = false;
}
}
};
Window_GalgeChoiceList.prototype.updateOriginalCursorButton = function() {
if (this._originalCursorSprite) {
if (this.isOpen() && this._index > -1) {
this._originalCursorSprite.visible = true;
if (this._originalCursorSprite.opacity >= 255) this._originalCursorSpriteFade = false;
if (this._originalCursorSprite.opacity <= 128) this._originalCursorSpriteFade = true;
this._originalCursorSprite.opacity += this._originalCursorSpriteFade ? 6 : -6;
} else {
this._originalCursorSprite.visible = false;
}
}
};
Window_GalgeChoiceList.prototype.updateOpen = function() {
if (this._opening) {
this.openness += gcwFadeInFrame;
if (this.isOpen()) {
this._opening = false;
}
}
};
Window_GalgeChoiceList.prototype.updateCancelButton = function() {
if (this._cancelButton) {
this._cancelButton.visible = this.needsCancelButton() && this.isOpen() && gcwCancelButtonEnabled;
}
};
Window_GalgeChoiceList.prototype.needsCancelButton = function() {
return cancelType;
};
Window_GalgeChoiceList.prototype.placeCancelButton = function() {
if (this._cancelButton) {
const spacing = 8;
const button = this._cancelButton;
const right = this.x + this.width;
if (right < Graphics.boxWidth - button.width + spacing) {
button.x = this.width + spacing;
} else {
button.x = -button.width - spacing;
}
button.y = this.height / 2 - button.height / 2;
}
};
Window_GalgeChoiceList.prototype.maxCols = function() {
return maxCols;
};
Window_GalgeChoiceList.prototype.setQuestionText = function() {
messageTextLists.forEach((text, index) => {
this.drawText(this.convertEscapeCharacters(text), 0, this.lineHeight() * index, this.innerWidth, "center");
}, this);
};
Window_GalgeChoiceList.prototype.makeCommandList = function() {
choiceLists.forEach(function(elm, index) {
this.addCommand(String(elm.label), Number(elm.resultNumber || 0) !== 0 ? Number(elm.resultNumber) : index + 1);
}, this);
};
Window_GalgeChoiceList.prototype.updatePadding = function() {
this.padding = gcwWindowPadding;
};
Window_GalgeChoiceList.prototype.scrollBaseY = function(index) {
let margin = this.lineHeight() * messageTextLists.length;
if (messageTextLists.length > 0) margin += gcwWindowPadding;
return this._scrollBaseY - margin;
};
Window_GalgeChoiceList.prototype.setSymbol = function() {
if (iniPosition > 0) {
this.selectSymbol(iniPosition);
} else {
this.deselect();
}
};
Window_GalgeChoiceList.prototype.itemHeight = function() {
return Window_Scrollable.prototype.itemHeight.call(this) + gcwItemHeightAdjust;
};
Window_GalgeChoiceList.prototype.drawItem = function(index) {
const rect = this.itemLineRect(index);
const align = this.itemTextAlign();
this.resetTextColor();
this.changePaintOpacity(this.isCommandEnabled(index));
this.drawText(this.convertEscapeCharacters(this.commandName(index)), rect.x, rect.y, rect.width, align);
};
Window_GalgeChoiceList.prototype.isCancelEnabled = function() {
return cancelType;
};
Window_GalgeChoiceList.prototype.isOkTriggered = function() {
return Input.isTriggered('ok');
};
Window_GalgeChoiceList.prototype.callOkHandler = function() {
$gameVariables.setValue(variableNumber, this.currentSymbol());
this._messageWindow.terminateMessage();
this.close();
};
Window_GalgeChoiceList.prototype.callCancelHandler = function() {
$gameVariables.setValue(variableNumber, -1);
this._messageWindow.terminateMessage();
this.close();
};
})();