pure-full-lily/js/plugins/MogBattleHud_StateTooltip.js
2025-09-16 10:12:44 -05:00

250 lines
No EOL
9 KiB
JavaScript

//=============================================================================
// MogBattleHud_StateTooltip.js
//=============================================================================
//
//=============================================================================
// Copyright (c) 2024 Your Name
// Released under the MIT license.
// http://opensource.org/licenses/mit-license.php
//=============================================================================
/*:
* @target MZ
* @plugindesc MOG_BattleHudのステートアイコンにマウスオーバーで説明を表示します。
* @author Your Name
* @version 1.0.0
*
* @param list
* @text アイコン説明リスト
* @desc アイコンと説明文を紐づけるリストです。
* @default []
* @type struct<Description>[]
*
* @param hoverDelay
* @text ホバー遅延
* @desc マウスを重ねてから説明が表示されるまでの時間(フレーム数)。
* @default 30
* @type number
*
* @param fontSize
* @text フォントサイズ
* @desc 説明ウィンドウのフォントサイズです。0でデフォルトサイズ。
* @default 22
* @type number
*
* @param padding
* @text 余白
* @desc 説明ウィンドウの余白です。0でデフォルトの余白。
* @default 8
* @type number
*
* @param backOpacity
* @text 背景不透明度
* @desc 説明ウィンドウの背景不透明度です。0でデフォルト値。255で完全不透明。
* @default 224
* @type number
*
* @help
* このプラグインは、MOG_BattleHud.jsと連携して、戦闘中の
* ステートアイコンにマウスカーソルを合わせると、ツールチップで
* 説明を表示する機能を提供します。
*
* 【重要】
* ・このプラグインは「MOG_BattleHud.js」より下に配置してください。
* ・「IconDescription.js」は不要です。
*
* 【設定】
* プラグインパラメータの「アイコン説明リスト」に、対象のアイコンと
* 表示したい説明文を登録してください。
*/
/*~struct~Description:
* @param iconIndex
* @text アイコン
* @desc 説明を表示するアイコンのインデックスです。
* @default 1
* @type icon
*
* @param caption
* @text 説明テキスト
* @desc アイコンの説明文です。制御文字が使えます。
* @default
* @type multiline_string
*/
(() => {
'use strict';
const pluginName = 'MogBattleHud_StateTooltip';
const params = PluginManager.parameters(pluginName);
const paramList = JSON.parse(params.list || '[]').map(JSON.parse);
const paramHoverDelay = Number(params.hoverDelay) || 30;
const paramFontSize = Number(params.fontSize) || 22;
const paramPadding = Number(params.padding) || 8;
const paramBackOpacity = Number(params.backOpacity) || 224;
function findIconCaptionParam(iconIndex) {
return paramList.find(desc => Number(desc.iconIndex) === iconIndex);
}
//-----------------------------------------------------------------------------
// Window_StateTooltip
//
// 説明文を表示するためのウィンドウです。
class Window_StateTooltip extends Window_Base {
constructor(iconIndex, x, y) {
super(new Rectangle(x, y + ImageManager.iconHeight, 1, 1));
this._iconIndex = iconIndex;
this.setup();
this.updatePlacement(x, y);
this.update(); // Force a single update to ensure visibility
}
setup() {
const item = findIconCaptionParam(this._iconIndex);
if (!item) return;
const text = item.caption;
const rect = this.textSizeEx(text);
this.updatePadding();
this.width = rect.width + this.padding * 2;
this.height = rect.height + this.padding * 2;
this.createContents();
this.drawTextEx(text, 0, 0);
}
updatePlacement(x, y) {
this.x = x;
this.y = y + ImageManager.iconHeight;
if (this.y + this.height > Graphics.height) {
this.y = y - this.height;
}
if (this.x + this.width > Graphics.width) {
this.x = Math.max(0, Graphics.width - this.width);
}
}
resetFontSettings() {
super.resetFontSettings();
if (paramFontSize > 0) {
this.contents.fontSize = paramFontSize;
}
}
updatePadding() {
this.padding = paramPadding > 0 ? paramPadding : this.defaultPadding();
}
updateBackOpacity() {
this.backOpacity = paramBackOpacity;
}
}
//-----------------------------------------------------------------------------
// SceneManager
//
// ツールチップウィンドウを管理します。
SceneManager._stateTooltipWindow = null;
SceneManager.showStateTooltip = function(iconIndex, x, y) {
if (this._stateTooltipWindow && this._stateTooltipWindow._iconIndex === iconIndex) {
return;
}
this.hideStateTooltip();
if (findIconCaptionParam(iconIndex)) {
this._stateTooltipWindow = new Window_StateTooltip(iconIndex, x, y);
this._scene.addChild(this._stateTooltipWindow);
}
};
SceneManager.hideStateTooltip = function() {
if (this._stateTooltipWindow) {
this._scene.removeChild(this._stateTooltipWindow);
this._stateTooltipWindow = null;
}
};
//-----------------------------------------------------------------------------
// Battle_Hud (MOG_BattleHud.js) の機能を拡張
//
if (typeof Battle_Hud !== 'undefined') {
const _Battle_Hud_initialize = Battle_Hud.prototype.initialize;
Battle_Hud.prototype.initialize = function(hud_id) {
_Battle_Hud_initialize.apply(this, arguments);
this._hoveredIconSprite = null;
this._hoverCount = 0;
};
const _Battle_Hud_refresh_states = Battle_Hud.prototype.refresh_states;
Battle_Hud.prototype.refresh_states = function() {
_Battle_Hud_refresh_states.apply(this, arguments);
if (this._state_icon) {
this._state_icon.iconIndex = this._states_data[0];
}
};
const _Battle_Hud_refresh_states2 = Battle_Hud.prototype.refresh_states2;
Battle_Hud.prototype.refresh_states2 = function() {
_Battle_Hud_refresh_states2.apply(this, arguments);
const icons = this._battler.allIcons();
if (this._stateIcons) {
for (let i = 0; i < this._stateIcons.length; i++) {
if (this._stateIcons[i] && icons[i]) {
this._stateIcons[i].iconIndex = icons[i];
}
}
}
};
const _Battle_Hud_update = Battle_Hud.prototype.update;
Battle_Hud.prototype.update = function() {
_Battle_Hud_update.apply(this, arguments);
if (this.visible) {
this.updateStateTooltip();
}
};
Battle_Hud.prototype.getHoveredIconSprite = function() {
const touchPos = new Point(TouchInput.x, TouchInput.y);
const checkSprite = (sprite) => {
if (!sprite || !sprite.visible || !findIconCaptionParam(sprite.iconIndex)) {
return false;
}
const localPos = sprite.worldTransform.applyInverse(touchPos);
const rect = new Rectangle(0, 0, sprite.width, sprite.height);
return rect.contains(localPos.x, localPos.y);
};
if (this._stateType === 0 && this._state_icon) {
if (checkSprite(this._state_icon)) return this._state_icon;
} else if (this._stateType === 1 && this._stateIcons) {
for (const iconSprite of this._stateIcons) {
if (checkSprite(iconSprite)) return iconSprite;
}
}
return null;
};
Battle_Hud.prototype.updateStateTooltip = function() {
const currentlyHovered = this.getHoveredIconSprite();
if (this._hoveredIconSprite === currentlyHovered) {
if (currentlyHovered) {
this._hoverCount++;
if (this._hoverCount >= paramHoverDelay) {
const worldPos = currentlyHovered.worldTransform.apply(new Point(0, 0));
SceneManager.showStateTooltip(currentlyHovered.iconIndex, worldPos.x, worldPos.y);
}
}
} else {
this._hoveredIconSprite = currentlyHovered;
this._hoverCount = 0;
SceneManager.hideStateTooltip();
}
};
}
})();