show-first/js/plugins/CustomMadeMenuScene.js
2024-08-08 11:24:10 -05:00

1081 lines
27 KiB
JavaScript

/*:
* @target MZ
* @author F_
* @base Fs
* @base ApngCore
* @orderAfter Fs
*
* @plugindesc
*
* 独自のメニュー画面を実装します。
*
* @help
*
* 独自のメニュー画面を実装します。
*
*
* ■ アクター画像の設定
*
* 各アクターに対応する画像は img/pictures/ 以下に配置する必要があります。
*
* 配置した画像は「アクター画像設定」により各アクターと対応付けます。
*
*
*
* @param ActorImages
* @type struct<ActorImage>[]
* @default []
* @text アクター画像設定
* @desc アクターに対応する画像の設定。
*
* @param HelpWindowConfig
* @type struct<HelpWindowConfig>
* @text ヘルプウィンドウ設定
* @desc ヘルプウィンドウに関する設定。
*
* @param CommandWindowConfig
* @type struct<CommandWindowConfig>
* @text コマンドウィンドウ設定
* @desc コマンドウィンドウに関する設定。
*
* @param GoldWindowConfig
* @type struct<GoldWindowConfig>
* @text 所持金ウィンドウ設定
* @desc 所持金ウィンドウに関する設定。
*
* @param StatusWindowConfig
* @type struct<StatusWindowConfig>
* @text ステータスウィンドウ設定
* @desc ステータスウィンドウに関する設定。
*/
/*~struct~ActorImage:
* @param actorId
* @type actor
* @default 0
* @text 対象アクター
* @desc 画像を設定する対象のアクター。
*
* @param path
* @type file
* @dir img/pictures/
* @text 画像
* @desc アクターに対応する画像。
*/
/*~struct~HelpWindowConfig:
* @param lines
* @type number
* @min 1
* @max 9
* @default 1
* @text 行数
* @desc 説明文の表示行数。
*
* @param descriptions
* @type struct<CommandDescs>
* @text コマンド説明文
* @desc 各コマンドに対応する説明文。
*/
/*~struct~CommandDescs:
* @param item
* @type multiline_string
* @text アイテム
* @desc 「アイテム」コマンドの説明文。
*
* @param skill
* @type multiline_string
* @text スキル
* @desc 「スキル」コマンドの説明文。
*
* @param equip
* @type multiline_string
* @text 装備
* @desc 「装備」コマンドの説明文。
*
* @param status
* @type multiline_string
* @text ステータス
* @desc 「ステータス」コマンドの説明文。
*
* @param formation
* @type multiline_string
* @text 並び替え
* @desc 「並び替え」コマンドの説明文。
*
* @param options
* @type multiline_string
* @text オプション
* @desc 「オプション」コマンドの説明文。
*
* @param save
* @type multiline_string
* @text セーブ
* @desc 「セーブ」コマンドの説明文。
*
* @param load
* @type multiline_string
* @text ロード
* @desc 「ロード」コマンドの説明文。
*
* @param gameEnd
* @type multiline_string
* @text ゲーム終了
* @desc 「ゲーム終了」コマンドの説明文。
*/
/*~struct~CommandWindowConfig:
* @param useLoadCommand
* @type boolean
* @default true
* @text ロードコマンドの追加
* @desc 「ロード」コマンドを追加するかどうか。
*
* @param loadCommandName
* @parent useLoadCommand
* @type string
* @default ロード
* @text ロードコマンド名
* @desc 「ロード」コマンドの表示名。
*/
/*~struct~GoldWindowConfig:
* @param goldLabel
* @type string
* @default 所持金
* @text 所持金項目名
* @desc 所持金の左側に表示する項目名。
*
* @param playtimeLabel
* @type string
* @default プレイ時間
* @text プレイ時間項目名
* @desc プレイ時間の左側に表示する項目名。
*
* @param lineHeight
* @type number
* @default 36
* @text 行の高さ
* @desc 行の高さ(px)。
*
* @param fontSize
* @type number
* @default 26
* @text フォントサイズ
* @desc フォントサイズ(px)。
*/
/*~struct~StatusWindowConfig:
* @param columns
* @type number
* @min 1
* @max 8
* @default 4
* @text 列数
* @desc 同時に表示する列数。
*
* @param baseX
* @type number
* @default 0
* @text 基本水平位置
* @desc 基本情報のX方向の位置(px)。
*
* @param baseY
* @type number
* @default 0
* @text 基本垂直位置
* @desc 基本情報のY方向の位置(px)。
*
* @param imageY
* @type number
* @default 0
* @text アクター画像位置
* @desc アクター画像下端のY方向の位置(px)。
*
* @param gaugeY
* @type number
* @default 0
* @text ゲージ位置
* @desc ゲージ群上端のY方向の位置(px)。
*
* @param gaugeWidth
* @type number
* @default 128
* @text ゲージ長
* @desc ゲージのラベルを含めたX方向の長さ(px)。
*/
"use strict";
{
const PLUGIN_NAME = "CustomMadeMenuScene";
const DEFAULT_COMMAND_DESCS = {
item: "",
skill: "",
equip: "",
status: "",
formation: "",
options: "",
save: "",
load: "",
gameEnd: "",
};
const DEFAULT_HELP_WINDOW_CONFIG = {
lines: 1,
descriptions: DEFAULT_COMMAND_DESCS,
};
const DEFAULT_COMMAND_WINDOW_CONFIG = {
useLoadCommand: true,
loadCommandName: "Load",
};
const DEFAULT_GOLD_WINDOW_CONFIG = {
goldLabel: "Gold",
playtimeLabel: "Play Time",
lineHeight: 36,
fontSize: 26,
};
const DEFAULT_STATUS_WINDOW_CONFIG = {
columns: 4,
baseX: 0,
baseY: 0,
imageY: 0,
gaugeY: 0,
gaugeWidth: 128,
};
const { P, Z } = Fs.v0_4;
const parseParam = P.begin(PluginManager.parameters(PLUGIN_NAME));
const ACTOR_IMAGE_MAP = parseParam(
"ActorImages",
P.validate(
P.like([
{
actorId: P.natural,
path: P.string,
},
]),
(value, ok, err) => {
const map = new Map();
for (const { actorId, path } of value) {
if (!map.has(actorId)) {
map.set(actorId, path);
} else {
return err(`duplicate actor ID: ${actorId}`);
}
}
return ok(map);
}
)
);
const HELP_WINDOW_CONFIG = parseParam(
"HelpWindowConfig",
P.optional(
P.like({
lines: P.natural,
descriptions: P.optional(
P.like({
item: P.string,
skill: P.string,
equip: P.string,
status: P.string,
formation: P.string,
options: P.string,
save: P.string,
load: P.string,
gameEnd: P.string,
}),
DEFAULT_COMMAND_DESCS
),
}),
DEFAULT_HELP_WINDOW_CONFIG
)
);
const COMMAND_WINDOW_CONFIG = parseParam(
"CommandWindowConfig",
P.optional(
P.like({
useLoadCommand: P.boolean,
loadCommandName: P.string,
}),
DEFAULT_COMMAND_WINDOW_CONFIG
)
);
const GOLD_WINDOW_CONFIG = parseParam(
"GoldWindowConfig",
P.optional(
P.like({
goldLabel: P.string,
playtimeLabel: P.string,
lineHeight: P.natural,
fontSize: P.natural,
}),
DEFAULT_GOLD_WINDOW_CONFIG
)
);
const STATUS_WINDOW_CONFIG = parseParam(
"StatusWindowConfig",
P.optional(
P.like({
columns: P.natural,
baseX: P.natural,
baseY: P.natural,
imageY: P.natural,
gaugeY: P.natural,
gaugeWidth: P.natural,
}),
DEFAULT_STATUS_WINDOW_CONFIG
)
);
const LOAD_COMMAND_SYMBOL = "load";
class ApngSprite extends PIXI.Sprite {
#apng;
#time;
#prevTime;
#canvas;
#prevCanvas;
#texture;
constructor() {
super(null);
this.#apng = undefined;
this.#time = 0;
this.#prevTime = -1;
this.#canvas = this.#initCanvas();
this.#prevCanvas = this.#initCanvas();
this.#texture = this.#initTexture(this.#canvas);
}
get time() {
return this.#time;
}
set time(value) {
this.#time = value;
}
setImage(apng) {
if (this.#apng !== apng) {
this.#apng = apng;
this.#prevTime = -1;
if (apng !== undefined) {
this.#canvas.width = apng.width;
this.#canvas.height = apng.height;
this.#prevCanvas.width = apng.width;
this.#prevCanvas.height = apng.height;
this.texture = this.#texture;
} else {
this.texture = null;
}
}
}
update() {
this.#updateCanvas();
}
destroy(...args) {
const texture = this.#texture;
if (texture !== null) {
this.texture = this.#texture = null;
texture.destroy(true);
}
super.destroy(...args);
}
#initCanvas() {
return Object.assign(document.createElement("canvas"), {
width: 1,
height: 1,
});
}
#initTexture(canvas) {
return new PIXI.Texture(
new PIXI.BaseTexture(canvas, {
mipmap: PIXI.MIPMAP_MODES.OFF,
scaleMode: PIXI.SCALE_MODES.LINEAR,
})
);
}
#updateCanvas() {
const apng = this.#apng;
const time = this.#time;
const prevTime = this.#prevTime;
const canvas = this.#canvas;
const prevCanvas = this.#prevCanvas;
if (apng !== undefined) {
const data = this.#makeRenderData(apng, prevTime, time);
if (data !== undefined) {
this.#renderFrames(canvas, prevCanvas, data);
this.#texture.update();
}
this.#prevTime = time;
}
}
#makeRenderData(apng, prevTime, time) {
if (prevTime !== time) {
const prevOrder = this.#frameOrder(apng, prevTime);
const order = this.#frameOrder(apng, time);
if (prevTime < 0 || prevOrder !== order) {
return order !== -1
? this.#makeRangeRenderData(apng, prevOrder, order)
: this.#makeClearRenderData();
}
}
return undefined;
}
#frameOrder(apng, time) {
const { numPlays, duration, frames } = apng;
if (time >= 0) {
const maxLoops = numPlays !== 0 ? numPlays : Number.POSITIVE_INFINITY;
const loops =
duration !== 0 ? Math.min(Math.floor(time / duration), maxLoops) : 0;
const frame = this.#frameIndex(frames, time - loops * duration);
const order = frame !== -1 ? frame + loops * frames.length : -1;
return order;
} else {
return -1;
}
}
#frameIndex(frames, position) {
let rest = position;
for (const [index, frame] of frames.entries()) {
if (rest <= frame.delay) {
return index;
}
rest -= frame.delay;
}
return frames.length - 1;
}
#makeRangeRenderData(apng, prevOrder, order) {
const { frames } = apng;
const { start, end } = this.#deltaFrameRange(frames, prevOrder, order);
const last = start - 1;
return {
lastFrame: last !== -1 ? frames[last] : undefined,
frames: this.#deltaFrames(frames, start, end),
};
}
#deltaFrameRange(frames, prevOrder, order) {
const prevIndex = prevOrder % frames.length;
const index = order % frames.length;
const start =
prevOrder !== -1 && prevOrder < order && prevIndex < index
? prevIndex + 1
: 0;
const end = index + 1;
return { start, end };
}
#deltaFrames(frames, start, end) {
const result = [];
const filledRects = [];
for (const [n, frame] of frames.slice(start, end).reverse().entries()) {
const { offsetX, offsetY, width, height, disposeOp } = frame;
if (n === 0 || disposeOp !== APNG.DISPOSE_OP_PREVIOUS) {
const minX = offsetX;
const maxX = offsetX + width;
const minY = offsetY;
const maxY = offsetY + height;
if (
filledRects.every(
(r) =>
minX < r.minX || maxX > r.maxX || minY < r.minY || maxY > r.maxY
)
) {
result.push(frame);
if (disposeOp === APNG.DISPOSE_OP_BACKGROUND) {
filledRects.push({ minX, maxX, minY, maxY });
}
}
}
}
return result.reverse();
}
#makeClearRenderData() {
return { lastFrame: undefined, frames: [] };
}
#renderFrames(canvas, prevCanvas, data) {
const { lastFrame, frames } = data;
const context = canvas.getContext("2d");
const prevContext = prevCanvas.getContext("2d");
if (frames.length !== 0) {
let prevFrame = lastFrame;
for (const frame of frames) {
this.#renderSingleFrame(context, prevContext, frame, prevFrame);
prevFrame = frame;
}
} else {
this.#disposeOfPrevFrame(context, prevContext, lastFrame);
}
}
#renderSingleFrame(context, prevContext, frame, prevFrame) {
this.#disposeOfPrevFrame(context, prevContext, prevFrame);
this.#savePrevFrameIfRequired(context, prevContext, frame);
this.#drawFrameImage(context, frame);
}
#disposeOfPrevFrame(context, prevContext, prevFrame) {
if (prevFrame !== undefined) {
this.#applyDisposeOp(context, prevContext, prevFrame);
} else {
const { canvas } = context;
context.clearRect(0, 0, canvas.width, canvas.height);
}
}
#applyDisposeOp(context, prevContext, frame) {
const { disposeOp } = frame;
switch (disposeOp) {
case APNG.DISPOSE_OP_NONE:
return this.#applyDisposeOpNone();
case APNG.DISPOSE_OP_BACKGROUND:
return this.#applyDisposeOpBackground(context, frame);
case APNG.DISPOSE_OP_PREVIOUS:
return this.#applyDisposeOpPrevious(context, prevContext, frame);
default:
throw new Error(`invalid APNG disposeOp: ${disposeOp}`);
}
}
#applyDisposeOpNone() {}
#applyDisposeOpBackground(context, frame) {
const { offsetX, offsetY, width, height } = frame;
context.clearRect(offsetX, offsetY, width, height);
}
#applyDisposeOpPrevious(context, prevContext, frame) {
const { offsetX, offsetY, width, height } = frame;
context.clearRect(offsetX, offsetY, width, height);
context.drawImage(
prevContext.canvas,
offsetX,
offsetY,
width,
height,
offsetX,
offsetY,
width,
height
);
}
#savePrevFrameIfRequired(context, prevContext, frame) {
const { offsetX, offsetY, width, height, disposeOp } = frame;
if (disposeOp === APNG.DISPOSE_OP_PREVIOUS) {
prevContext.clearRect(offsetX, offsetY, width, height);
prevContext.drawImage(
context.canvas,
offsetX,
offsetY,
width,
height,
offsetX,
offsetY,
width,
height
);
}
}
#drawFrameImage(context, frame) {
const { offsetX, offsetY, width, height, image } = frame;
if (this.#shouldClearRect(frame)) {
context.clearRect(offsetX, offsetY, width, height);
}
context.drawImage(image, offsetX, offsetY, width, height);
}
#shouldClearRect(frame) {
const { blendOp } = frame;
switch (blendOp) {
case APNG.BLEND_OP_SOURCE:
return true;
case APNG.BLEND_OP_OVER:
return false;
default:
throw new Error(`invalid APNG blendOp: ${blendOp}`);
}
}
}
class MenuActorImageSprite extends Sprite {
initialize() {
super.initialize();
this._actor = null;
this._path = undefined;
this._time = 0;
this._innerSprite = this.initApngSprite();
}
initApngSprite() {
const sprite = new ApngSprite();
sprite.anchor.set(0.5, 1);
return this.addChild(sprite);
}
setup(actor) {
this._actor = actor;
this.updateBitmap();
}
update() {
super.update();
this.updateTime();
this.updateBitmap();
}
updateTime() {
this._time++;
}
updateBitmap() {
const ASSUMED_FPS = 60;
const actor = this._actor;
const time = this._time;
const sprite = this._innerSprite;
const path =
actor !== null ? ACTOR_IMAGE_MAP.get(actor.actorId()) : undefined;
if (this._path !== path) {
this._path = path;
ImageManager.loadApngPicture(path, (apng) => sprite.setImage(apng));
}
sprite.time = (time * 1000) / ASSUMED_FPS;
}
}
class MenuGaugeSprite extends Sprite_Gauge {
bitmapWidth() {
return STATUS_WINDOW_CONFIG.gaugeWidth;
}
}
class MenuHelpWindow extends Window_Help {
refresh() {
const text = this._text;
const lines = text.split("\n");
const rect = this.baseTextRect();
const lineHeight = this.lineHeight();
this.contents.clear();
for (const [i, line] of lines.entries()) {
this.drawText(
line,
rect.x,
rect.y + lineHeight * i,
rect.width,
"left"
);
}
}
}
class MenuGoldWindow extends Window_Gold {
initialize(...args) {
super.initialize(...args);
this._playtime = 0;
}
lineHeight() {
return GOLD_WINDOW_CONFIG.lineHeight;
}
update() {
super.update();
this.updatePlaytime();
}
updatePlaytime() {
const playtime = $gameSystem.playtime();
if (this._playtime !== playtime) {
this._playtime = playtime;
this.refreshPlaytimeValue();
}
}
resetFontSettings() {
super.resetFontSettings();
this.contents.fontSize = GOLD_WINDOW_CONFIG.fontSize;
}
refresh() {
this.contents.clear();
this.drawGoldLabel();
this.drawGoldValue();
this.drawPlaytimeLabel();
this.drawPlaytimeValue();
}
refreshPlaytimeValue() {
this.clearPlaytimeValue();
this.drawPlaytimeValue();
}
drawGoldLabel() {
const { x, y, width } = this.itemLineRect(0);
this.resetTextColor();
this.drawText(GOLD_WINDOW_CONFIG.goldLabel, x, y, width, "left");
}
drawGoldValue() {
const { x, y, width } = this.itemLineRect(1);
this.drawCurrencyValue(this.value(), this.currencyUnit(), x, y, width);
}
drawPlaytimeLabel() {
const { x, y, width } = this.itemLineRect(2);
this.resetTextColor();
this.drawText(GOLD_WINDOW_CONFIG.playtimeLabel, x, y, width, "left");
}
drawPlaytimeValue() {
const { x, y, width } = this.itemLineRect(3);
this.resetTextColor();
this.drawText($gameSystem.playtimeText(), x, y, width, "right");
}
clearPlaytimeValue() {
const { x, y, width, height } = this.itemLineRect(3);
this.contents.clearRect(x, y, width, height);
}
}
const swapSpriteGauge = Z.swapper("Sprite_Gauge");
const swapWindowSelectable = Z.swapper("Window_Selectable");
const swapWindowHelp = Z.swapper("Window_Help");
const swapWindowGold = Z.swapper("Window_Gold");
Z.redef(ImageManager, ($) => {
const PICTURE_DIR = "img/pictures/";
const APNG_EXT = ".png";
const ENCRYPTED_FILE_SUFFIX = "_";
$._apngEntries = new Map();
$.modifyApngEntry = function (url, modifyFn) {
const entries = this._apngEntries;
const oldEntry = entries.get(url);
const newEntry = modifyFn(oldEntry);
const nextEntry =
newEntry.status === "loaded"
? this.onApngEntryLoaded(newEntry)
: newEntry;
entries.set(url, nextEntry);
};
$.onApngEntryLoaded = function (entry) {
const { callbacks, value } = entry;
for (const callback of callbacks) {
callback(value);
}
return { ...entry, callbacks: [] };
};
$.loadApngPicture = function (filename, callback) {
this.loadApng(PICTURE_DIR, filename, callback);
};
$.loadApng = function (folder, filename, callback) {
if (filename !== "") {
const url = folder + Utils.encodeURI(filename) + APNG_EXT;
this.loadApngFromUrl(url, callback);
} else {
callback(APNG.EMPTY);
}
};
$.loadApngFromUrl = function (url, callback) {
this.modifyApngEntry(url, (entry) => {
if (entry !== undefined) {
return {
...entry,
callbacks: [...entry.callbacks, callback],
};
} else {
return this.startLoadApngEntry(
{
status: "none",
url,
callbacks: [callback],
},
(result) => this.applyApngLoadResult(url, result)
);
}
});
};
$.retryLoadApngFromUrl = function (url) {
this.modifyApngEntry(url, (entry) => {
if (entry.status === "error") {
return this.startLoadApngEntry(entry, (result) =>
this.applyApngLoadResult(url, result)
);
} else {
return entry;
}
});
};
$.applyApngLoadResult = function (url, result) {
this.modifyApngEntry(url, (entry) => {
const { url, callbacks } = entry;
if (result.ok) {
return {
status: "loaded",
url,
callbacks,
value: result.value,
};
} else {
return {
status: "error",
url,
callbacks,
error: result.error,
};
}
});
};
$.startLoadApngEntry = function (entry, callback) {
const { url, callbacks } = entry;
const controller = new AbortController();
const { signal } = controller;
const invokeCallback = (result) => {
if (!signal.aborted) {
callback(result);
}
};
this.loadApngFromUrlAsync(url, { signal }).then(
(value) => invokeCallback({ ok: true, value }),
(error) => invokeCallback({ ok: false, error })
);
return {
status: "loading",
url,
callbacks,
controller,
};
};
$.loadApngFromUrlAsync = async function (url, options) {
const encrypted = Utils.hasEncryptedImages();
const actualUrl = encrypted ? url + ENCRYPTED_FILE_SUFFIX : url;
const response = await fetch(actualUrl, options);
const buffer = await response.arrayBuffer();
const data = encrypted ? Utils.decryptArrayBuffer(buffer) : buffer;
const apng = await APNG.parse(data);
return apng;
};
const base$clear = $.clear;
$.clear = function () {
base$clear.apply(this, arguments);
this.clearApngImages();
};
$.clearApngImages = function () {
const entries = this._apngEntries;
for (const entry of entries.values()) {
if (entry.status === "loading") {
entry.controller.abort();
}
}
entries.clear();
};
const base$isReady = $.isReady;
$.isReady = function () {
const normalReady = base$isReady.apply(this, arguments);
const apngReady = this.checkApngLoaded();
return normalReady && apngReady;
};
$.checkApngLoaded = function () {
const entries = Array.from(this._apngEntries.values());
const error = entries.find((entry) => entry.status === "error");
if (error !== undefined) {
const { url } = error;
const retry = this.retryLoadApngFromUrl.bind(this, url);
throw ["LoadError", url, retry];
} else {
return entries.every((entry) => entry.status === "loaded");
}
};
});
Z.redef(Window_MenuCommand.prototype, ($) => {
$.updateHelp = function () {
const { descriptions } = HELP_WINDOW_CONFIG;
const helpWindow = this._helpWindow;
if (helpWindow !== null) {
const symbol = this.currentSymbol();
const text =
symbol !== null && descriptions.hasOwnProperty(symbol)
? descriptions[symbol]
: "";
helpWindow.setText(text);
}
};
const base$addSaveCommand = $.addSaveCommand;
$.addSaveCommand = function () {
base$addSaveCommand.apply(this, arguments);
this.addLoadCommand();
};
$.addLoadCommand = function () {
const { useLoadCommand, loadCommandName } = COMMAND_WINDOW_CONFIG;
if (useLoadCommand) {
const enabled = this.isLoadEnabled();
this.addCommand(loadCommandName, LOAD_COMMAND_SYMBOL, enabled);
}
};
$.isLoadEnabled = function () {
return !DataManager.isEventTest() && DataManager.isAnySavefileExists();
};
});
Z.redef(Window_MenuStatus.prototype, ($) => {
$.maxCols = function () {
return STATUS_WINDOW_CONFIG.columns;
};
$.itemHeight = function () {
return this.innerHeight;
};
$.drawItemImage = function (_index) {};
$.drawItemStatus = function (index) {
const {
baseX: baseOffsetX,
baseY: baseOffsetY,
imageY: imageOffsetY,
gaugeY: gaugeOffsetY,
gaugeWidth,
} = STATUS_WINDOW_CONFIG;
const actor = this.actor(index);
const { x, y, width } = this.itemRect(index);
const lineHeight = this.lineHeight();
const baseX = x + baseOffsetX;
const baseY = y + baseOffsetY;
const imageX = x + width / 2;
const imageY = y + imageOffsetY;
const gaugeX = x + Math.floor((width - gaugeWidth) / 2);
const gaugeY = y + gaugeOffsetY;
this.drawActorName(actor, baseX, baseY + lineHeight * 0);
this.drawActorLevel(actor, baseX, baseY + lineHeight * 1);
this.placeActorImage(actor, imageX, imageY);
swapSpriteGauge(globalThis, MenuGaugeSprite, () => {
this.placeBasicGauges(actor, gaugeX, gaugeY);
});
};
$.placeActorImage = function (actor, x, y) {
const key = "actor%1-image".format(actor.actorId());
const sprite = this.createInnerSprite(key, MenuActorImageSprite);
sprite.setup(actor);
sprite.move(x, y);
sprite.show();
};
});
Z.redef(Scene_Menu.prototype, ($) => {
$.isBottomHelpMode = function () {
return false;
};
$.helpAreaHeight = function () {
return this.calcWindowHeight(HELP_WINDOW_CONFIG.lines, false);
};
const base$create = $.create;
$.create = function () {
base$create.apply(this, arguments);
this.createHelpWindow();
this._commandWindow.setHelpWindow(this._helpWindow);
};
const base$createHelpWindow = $.createHelpWindow;
$.createHelpWindow = function () {
swapWindowHelp(globalThis, MenuHelpWindow, () =>
base$createHelpWindow.apply(this, arguments)
);
};
const base$createCommandWindow = $.createCommandWindow;
$.createCommandWindow = function () {
base$createCommandWindow.apply(this, arguments);
this._commandWindow.setHandler(
LOAD_COMMAND_SYMBOL,
this.commandLoad.bind(this)
);
};
const base$createGoldWindow = $.createGoldWindow;
$.createGoldWindow = function () {
swapWindowGold(globalThis, MenuGoldWindow, () =>
base$createGoldWindow.apply(this, arguments)
);
};
$.goldWindowRect = function () {
return swapWindowSelectable(globalThis, MenuGoldWindow, () => {
const ww = this.mainCommandWidth();
const wh = this.calcWindowHeight(4, true);
const wx = this.isRightInputMode() ? Graphics.boxWidth - ww : 0;
const wy = this.mainAreaBottom() - wh;
return new Rectangle(wx, wy, ww, wh);
});
};
$.commandLoad = function () {
SceneManager.push(Scene_Load);
};
});
}