/*: * @target MZ * @plugindesc 通知メッセージアドオン: 変数変動通知(中央固定版) v2.1.1 * @author IvI, 改変: Google Gemini * * 監視したい複数の変数が増減したとき、自動で個別メッセージを表示します。 * ウィンドウは常に画面縦中央(既定 y = 360px)の上端に固定されます。 * * ▼ 使い方 * 1. TorigoyaMZ_NotifyMessage.js の直下に配置してください。 * 2. 「監視リスト」で変数を追加し、メッセージとアイコンを設定してください。 * メッセージ中の {delta} が「±付き増減値」に置換されます。 * 3. ★変数ごとに個別の効果音を設定できるようになりました。 * * ▼ 更新履歴 * v2.1.1 (Geminiによる改変) buildMessage関数の構文エラーを修正 * v2.1.0 (Geminiによる改変) 変数ごとに通知SEを設定できる機能を追加 * v2.0.0 複数変数対応/旧単一パラメータは自動移行に対応 * v1.5.2 初回だけ高さが異常になるバグを厳密に修正 * v1.5.1 パラメータ/ヘルプが表示されない不具合を修正 * v1.5.0 初版 * * @param watchList * @text 監視リスト * @type struct[] * @default [] * * @param centerY * @text 表示Y座標 * @desc 通知ウィンドウの上端を合わせる Y 座標 * @type number * @default 360 * * @help * 【概要】 * 指定した複数のゲーム変数が増減したとき、増減量を含む * メッセージを画面中央にポップアップ表示します。 * * 【メッセージテンプレート】 * - {delta} : 増減値(符号付き)に置換 * * 【プラグインコマンド】 * ありません(自動動作のみ)。 */ /*~struct~WatchItem: * @param variableId * @text 変数ID * @type variable * @default 5 * * @param messageTemplate * @text メッセージ * @type string * @default \c[1]値が {delta} した… * * @param iconId * @text アイコンID * @type number * @default 0 * * @param se * @text ★通知効果音 * @desc この変数専用の効果音を設定します。 * 未設定の場合は基本設定のSEが再生されます。 * @type struct * @default */ /*~struct~Sound: * @param name * @text ファイル名 * @type file * @dir audio/se * @default * * @param volume * @text 音量 * @type number * @min 0 * @max 100 * @default 90 * * @param pitch * @text ピッチ * @type number * @min 50 * @max 150 * @default 100 * * @param pan * @text 位相 * @type number * @min -100 * @max 100 * @default 0 */ (() => { 'use strict'; // ------------------------------------------------------------------------- // パラメータ読み込み const PLUGIN_NAME = 'TorigoyaMZ_NotifyMessage_AddonVariableChangeCenter'; const params = PluginManager.parameters(PLUGIN_NAME); // 監視リスト(配列) const watchListRaw = JSON.parse(params.watchList || '[]'); const WATCHERS = watchListRaw .map((raw) => { if (!raw) return null; const obj = JSON.parse(raw); const se = obj.se ? JSON.parse(obj.se) : null; return { variableId: Number(obj.variableId || 0), messageTemplate: String(obj.messageTemplate || '\\c[1]値が {delta} した…'), iconId: Number(obj.iconId || 0), se: (se && se.name) ? { name: String(se.name), volume: Number(se.volume ?? 90), pitch: Number(se.pitch ?? 100), pan: Number(se.pan ?? 0), } : null, }; }) .filter(Boolean) .filter((w) => w.variableId > 0); // 旧バージョン(単一変数)パラメータが残っている場合は自動移行 if (WATCHERS.length === 0 && params.variableId) { WATCHERS.push({ variableId: Number(params.variableId), messageTemplate: String(params.messageTemplate || '\\c[1]値が {delta} した…'), iconId: Number(params.iconId || 0), se: null, }); } // id → watcher のハッシュ const WATCH_TABLE = {}; for (const w of WATCHERS) WATCH_TABLE[w.variableId] = w; const CENTER_Y = Number(params.centerY || 360); // ------------------------------------------------------------------------- // 依存チェック const Torigoya = (window.Torigoya = window.Torigoya || {}); if (!Torigoya.NotifyMessage) { console.error('[%s] TorigoyaMZ_NotifyMessage が見つかりません。', PLUGIN_NAME); return; } const Manager = Torigoya.NotifyMessage.Manager; const NotifyItem = Torigoya.NotifyMessage.NotifyItem; // ------------------------------------------------------------------------- // ★ NotifyItemのSE取得処理を上書きするパッチ // ------------------------------------------------------------------------- if (NotifyItem && !NotifyItem.prototype._variableCenterSePatched) { NotifyItem.prototype._variableCenterSePatched = true; const _NotifyItem_getDisplaySe = NotifyItem.prototype.getDisplaySe; NotifyItem.prototype.getDisplaySe = function() { if (this.se && this.se.name) { return this.se; } return _NotifyItem_getDisplaySe.apply(this, arguments); }; } // ------------------------------------------------------------------------- // ★ Window_NotifyMessage パッチ(元コードそのまま) ★ (function patchWindow() { const W = Torigoya.NotifyMessage.Window; if (!W || W.prototype._variableCenterPatched) return; W.prototype._variableCenterPatched = true; const _refreshContents = W.prototype.refreshContents; W.prototype.refreshContents = function () { const minW = Graphics.width - this.padding * 2; this.contents.resize(minW, this.lineHeight()); _refreshContents.call(this); }; const _refreshBackCoverSprite = W.prototype._refreshBackCoverSprite; W.prototype._refreshBackCoverSprite = function () { _refreshBackCoverSprite.call(this); }; const _setup = W.prototype.setup; W.prototype.setup = function (notifyItem) { _setup.call(this, notifyItem); setTimeout(() => { if (!this.parent) return; this.refresh(); }); }; })(); // ------------------------------------------------------------------------- // ユーティリティ function placeAtCenter(stack) { if (!stack?.window) return; stack.y = CENTER_Y; stack.window.y = CENTER_Y; } function buildMessage(template, delta) { // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ // ★ 修正点: ここにあった構文エラーを修正しました // ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ const signed = delta > 0 ? `+${delta}` : `${delta}`; return template.replace('{delta}', signed); } // ------------------------------------------------------------------------- // スクロールアニメーション パッチ(元コードそのまま) if (!Manager._variableCenterScrollPatched) { Manager._variableCenterScrollPatched = true; const baseStartScroll = Manager.startScrollAnimation; Manager.startScrollAnimation = function (newH) { const locked = this._stacks.filter((s) => s.notifyItem?.note === ''); if (locked.length) this._stacks = this._stacks.filter((s) => !locked.includes(s)); baseStartScroll.call(this, newH); locked.forEach((s) => { placeAtCenter(s); this._stacks.push(s); }); }; } // ------------------------------------------------------------------------- // 通知出現後に中央へ Manager.on((item) => { if (item.note !== '') return; setTimeout(() => { placeAtCenter(Manager._stacks.find((s) => s.notifyItem === item)); }); }); // ------------------------------------------------------------------------- // 内部ヘルパ function findActiveStack(variableId) { return Manager._stacks.find((s) => s.notifyItem?._watchVarId === variableId); } function createNew(watcher, delta) { const notifyItem = new Torigoya.NotifyMessage.NotifyItem({ message: buildMessage(watcher.messageTemplate, delta), icon: watcher.iconId, note: '', }); notifyItem._accumDelta = delta; notifyItem._watchVarId = watcher.variableId; notifyItem.se = watcher.se; Manager.notify(notifyItem); } function handleNotify(watcher, delta) { const stack = findActiveStack(watcher.variableId); createNew(watcher, delta); } // ------------------------------------------------------------------------- // Game_Variables 拡張 const _setValue = Game_Variables.prototype.setValue; Game_Variables.prototype.setValue = function (variableId, value) { const old = this.value(variableId); _setValue.apply(this, arguments); const watcher = WATCH_TABLE[variableId]; if (!watcher) return; const delta = value - old; if (!delta) return; handleNotify(watcher, delta); }; })();