1071 lines
32 KiB
JavaScript
1071 lines
32 KiB
JavaScript
/*---------------------------------------------------------------------------*
|
||
* TorigoyaMZ_NotifyMessage.js v.1.4.0
|
||
*---------------------------------------------------------------------------*
|
||
* Build Date: 2024/01/08 17:13:28 (JST)
|
||
*---------------------------------------------------------------------------*
|
||
* Ruたん ( @ru_shalm )
|
||
* https://torigoya-plugin.rutan.dev
|
||
*---------------------------------------------------------------------------*/
|
||
|
||
/*:
|
||
* @target MZ
|
||
* @plugindesc 通知メッセージプラグイン (v.1.4.0)
|
||
* @version 1.4.0
|
||
* @author Ruたん(ru_shalm)
|
||
* @license public domain
|
||
* @url https://raw.githubusercontent.com/rutan/torigoya-rpg-maker-plugin/gh-pages/TorigoyaMZ_NotifyMessage.js
|
||
*
|
||
* @base TorigoyaMZ_FrameTween
|
||
* @orderAfter TorigoyaMZ_FrameTween
|
||
*
|
||
* @help 通知メッセージプラグイン (v.1.4.0)
|
||
* https://torigoya-plugin.rutan.dev
|
||
*
|
||
* 画面の左下から通知メッセージを表示する機能を追加します。
|
||
* 通知メッセージはプラグインコマンドで表示できます。
|
||
*
|
||
* ------------------------------------------------------------
|
||
* ■ メモ欄を使ったカスタマイズ
|
||
* ------------------------------------------------------------
|
||
* プラグインコマンドのメモ欄に以下の記述を行うことで
|
||
* 通知ごとに一部動作をカスタマイズすることができます。
|
||
*
|
||
* ▼ 表示時の効果音を無しにする
|
||
* <noSound>
|
||
*
|
||
* ------------------------------------------------------------
|
||
* ■ 上級者設定:UIエリア余白
|
||
* ------------------------------------------------------------
|
||
* 通知メッセージの表示位置を調整するための設定です。
|
||
* 指定した値の分だけ、上下に余白を追加することができます。
|
||
*
|
||
* 例えば、上端に100、下端に100のような値を設定すると、
|
||
* 画面の真ん中の部分だけに通知が表示されるようになります。
|
||
*
|
||
* なお、上端と下端の合計値が画面の高さを超えてしまうと、
|
||
* 通知が正常に表示されなくなってしまうためご注意ください。
|
||
*
|
||
* @param base
|
||
* @text ■ 基本設定
|
||
* @type string
|
||
*
|
||
* @param baseAnimationDirection
|
||
* @text 通知の表示方向
|
||
* @desc 通知の表示方向を指定します。
|
||
* @parent base
|
||
* @type select
|
||
* @option 下から上へ
|
||
* @value bottomToTop
|
||
* @option 上から下へ
|
||
* @value topToBottom
|
||
* @default bottomToTop
|
||
*
|
||
* @param baseAppearTime
|
||
* @text 登場/退場時間
|
||
* @desc 通知が画面にスクロールイン/アウトする時間(フレーム数/60=1秒)を指定します。
|
||
* @parent base
|
||
* @type number
|
||
* @min 0
|
||
* @decimals 0
|
||
* @default 15
|
||
*
|
||
* @param baseViewTime
|
||
* @text 表示時間
|
||
* @desc 通知の表示時間(フレーム数/60=1秒)を指定します。0にすると画面外に押し出されるまで消えなくなります。
|
||
* @parent base
|
||
* @type number
|
||
* @min 0
|
||
* @decimals 0
|
||
* @default 90
|
||
*
|
||
* @param baseFontSize
|
||
* @text 文字サイズ
|
||
* @desc 通知メッセージの文字サイズを指定します
|
||
* @parent base
|
||
* @type number
|
||
* @min 1
|
||
* @decimals 0
|
||
* @default 22
|
||
*
|
||
* @param basePadding
|
||
* @text 余白サイズ
|
||
* @desc 通知メッセージの全体的な余白サイズを指定します
|
||
* @parent base
|
||
* @type number
|
||
* @min 0
|
||
* @decimals 0
|
||
* @default 4
|
||
*
|
||
* @param baseLeftPadding
|
||
* @text 左側の追加余白サイズ
|
||
* @desc 通知メッセージの左側の余白サイズを指定します。
|
||
* 全体の余白サイズに加え、この分が余白に追加されます。
|
||
* @parent base
|
||
* @type number
|
||
* @min 0
|
||
* @decimals 0
|
||
* @default 0
|
||
*
|
||
* @param baseRightPadding
|
||
* @text 右側の追加余白サイズ
|
||
* @desc 通知メッセージの右側の余白サイズを指定します。
|
||
* 全体の余白サイズに加え、この分が余白に追加されます。
|
||
* @parent base
|
||
* @type number
|
||
* @min 0
|
||
* @decimals 0
|
||
* @default 30
|
||
*
|
||
* @param baseItemPadding
|
||
* @text アイコンと文章の余白
|
||
* @desc 通知アイコンとメッセージの間の余白サイズを指定します。
|
||
* @parent base
|
||
* @type number
|
||
* @min 0
|
||
* @decimals 0
|
||
* @default 5
|
||
*
|
||
* @param baseSound
|
||
* @text 効果音
|
||
* @desc 通知表示時の効果音を指定します。
|
||
* @parent base
|
||
* @type struct<Sound>
|
||
* @default {"name":"Item1","volume":"90","pitch":"100","pan":"0"}
|
||
*
|
||
* @param advanced
|
||
* @text ■ 上級者設定
|
||
* @type string
|
||
*
|
||
* @param advancedVisibleSwitch
|
||
* @text 有効スイッチ
|
||
* @desc このスイッチがONのときのみ画面に通知を表示するようにします。「なし」の場合は常に表示されます。
|
||
* @parent advanced
|
||
* @type switch
|
||
* @default 0
|
||
*
|
||
* @param advancedBackgroundColor1
|
||
* @text 背景グラデーション:左端
|
||
* @desc 背景グラデーションの左端の色を指定します。
|
||
* 色はCSSの記法で指定できます。
|
||
* @parent advanced
|
||
* @type string
|
||
* @default rgba(0, 0, 64, 0.6)
|
||
*
|
||
* @param advancedBackgroundColor2
|
||
* @text 背景グラデーション:右端
|
||
* @desc 背景グラデーションの右端の色を指定します。
|
||
* 色はCSSの記法で指定できます。
|
||
* @parent advanced
|
||
* @type string
|
||
* @default rgba(0, 32, 64, 0)
|
||
*
|
||
* @param advancedUiPaddingTop
|
||
* @text UIエリア余白: 上端
|
||
* @desc 通知メッセージ表示位置の上側の余白を指定します。
|
||
* @parent advanced
|
||
* @type number
|
||
* @decimals 0
|
||
* @default 5
|
||
*
|
||
* @param advancedUiPaddingBottom
|
||
* @text UIエリア余白: 下端
|
||
* @desc 通知メッセージ表示位置の下側の余白を指定します。
|
||
* @parent advanced
|
||
* @type number
|
||
* @decimals 0
|
||
* @default 5
|
||
*
|
||
* @param advancedKeepMessage
|
||
* @text シーン遷移しても表示をキープ
|
||
* @desc 【危険:環境によってはONにすると不具合の原因となります】シーン遷移してもメッセージを全消ししないようにします。
|
||
* @parent advanced
|
||
* @type boolean
|
||
* @on キープする(危険)
|
||
* @off キープしない(安全)
|
||
* @default false
|
||
*
|
||
* @command notify
|
||
* @text 通知の表示
|
||
* @desc 指定内容の通知を表示します
|
||
*
|
||
* @arg message
|
||
* @text メッセージ
|
||
* @desc 通知に表示する文章を指定します。「文章の表示」のコマンドが一部利用できます。
|
||
* @type multiline_string
|
||
*
|
||
* @arg icon
|
||
* @text アイコンID
|
||
* @desc 通知に表示するアイコンのIDを指定します。
|
||
* 0の場合は表示しません。
|
||
* @type number
|
||
* @decimals 0
|
||
* @default 0
|
||
*
|
||
* @arg note
|
||
* @text メモ欄
|
||
* @desc メモ欄です。
|
||
* ツクールのメモ欄と同様に利用できます。
|
||
* @type note
|
||
*
|
||
* @command notifyWithVariableIcon
|
||
* @text 通知の表示(アイコン変数指定)
|
||
* @desc 指定内容の通知を表示します。アイコンのIDを変数で指定します。
|
||
*
|
||
* @arg message
|
||
* @text メッセージ
|
||
* @desc 通知に表示する文章を指定します。「文章の表示」のコマンドが一部利用できます。
|
||
* @type multiline_string
|
||
*
|
||
* @arg iconVariable
|
||
* @text アイコンID(変数指定)
|
||
* @desc 通知に表示するアイコンIDが設定された変数を指定します。
|
||
* 変数の中身が0またはマイナスの場合は表示しません。
|
||
* @type variable
|
||
* @default 0
|
||
*
|
||
* @arg note
|
||
* @text メモ欄
|
||
* @desc メモ欄です。
|
||
* ツクールのメモ欄と同様に利用できます。
|
||
* @type note
|
||
*/
|
||
|
||
/*~struct~Sound:
|
||
* @param name
|
||
* @text 効果音ファイル名
|
||
* @desc 通知表示時に再生する効果音ファイル
|
||
* 空っぽの場合は効果音なしになります
|
||
* @type file
|
||
* @dir audio/se
|
||
*
|
||
* @param volume
|
||
* @text 効果音の音量
|
||
* @desc 通知表示時に再生する効果音の音量(%)
|
||
* @type number
|
||
* @min 0
|
||
* @max 100
|
||
* @decimals 0
|
||
* @default 90
|
||
*
|
||
* @param pitch
|
||
* @text 効果音のピッチ
|
||
* @desc 通知表示時に再生する効果音のピッチ(%)
|
||
* @type number
|
||
* @min 0
|
||
* @max 200
|
||
* @decimals 0
|
||
* @default 100
|
||
*
|
||
* @param pan
|
||
* @text 効果音の位相
|
||
* @desc 通知表示時に再生する効果音の位相
|
||
* @type number
|
||
* @min -100
|
||
* @max 100
|
||
* @decimals 0
|
||
* @default 0
|
||
*/
|
||
|
||
(function () {
|
||
"use strict";
|
||
|
||
/**
|
||
* プラグインが存在するかチェックする
|
||
* @param pluginObject
|
||
* @param errorMessage
|
||
*/
|
||
function checkExistPlugin(pluginObject, errorMessage) {
|
||
if (typeof pluginObject !== "undefined") return;
|
||
alert(errorMessage);
|
||
throw new Error(errorMessage);
|
||
}
|
||
/**
|
||
* プラグインのバージョンをチェックする
|
||
* @param version
|
||
* @param requireVersion
|
||
* @param errorMessage
|
||
*/
|
||
function checkPluginVersion(version, requireVersion, errorMessage) {
|
||
if (isVersionString(version) && isGreaterThanOrEqualVersion(requireVersion, version)) return;
|
||
alert(errorMessage);
|
||
throw new Error(errorMessage);
|
||
}
|
||
/**
|
||
* x.y.z 形式のバージョン文字列かどうか判定する
|
||
* @param version
|
||
*/
|
||
function isVersionString(version) {
|
||
if (typeof version !== "string") return false;
|
||
return /^\d+\.\d+\.\d+$/.test(version);
|
||
}
|
||
/**
|
||
* x.y.z 形式のバージョン文字列を分解する
|
||
* @param version
|
||
*/
|
||
function parseVersion(version) {
|
||
if (!isVersionString(version)) throw new Error(`invalid version: ${version}`);
|
||
return version.split(".", 3).map((n) => parseInt(n || "0", 10));
|
||
}
|
||
/**
|
||
* b のバージョンが a 以上であるか判定する(a <= b)
|
||
* @param a
|
||
* @param b
|
||
*/
|
||
function isGreaterThanOrEqualVersion(a, b) {
|
||
if (a === b) return true;
|
||
const version1 = parseVersion(a);
|
||
const version2 = parseVersion(b);
|
||
if (version1[0] !== version2[0]) return version1[0] < version2[0];
|
||
if (version1[1] !== version2[1]) return version1[1] < version2[1];
|
||
return version1[2] < version2[2];
|
||
}
|
||
|
||
/**
|
||
* プラグインのファイル名を取得
|
||
*/
|
||
function getPluginName() {
|
||
const cs = document.currentScript;
|
||
return cs ? cs.src.split("/").pop().replace(/\.js$/, "") : "TorigoyaMZ_NotifyMessage";
|
||
}
|
||
|
||
function parseBooleanParam(value, defaultValue) {
|
||
if (value === undefined) return defaultValue;
|
||
return String(value).toLowerCase() === "true";
|
||
}
|
||
function parseIntegerParam(value, defaultValue) {
|
||
if (value === undefined || value === "") return defaultValue;
|
||
const intValue = Number.parseInt(String(value), 10);
|
||
return isNaN(intValue) ? defaultValue : intValue;
|
||
}
|
||
function parseStringParam(value, defaultValue) {
|
||
if (value === undefined) return defaultValue;
|
||
return String(value);
|
||
}
|
||
function parseStructObjectParam(value, defaultValue) {
|
||
if (value === undefined || value === "") return defaultValue;
|
||
if (typeof value === "string") return JSON.parse(value);
|
||
return value;
|
||
}
|
||
|
||
const Torigoya = (window.Torigoya = window.Torigoya || {});
|
||
|
||
function readStructSound(parameters) {
|
||
parameters = typeof parameters === "string" ? JSON.parse(parameters) : parameters;
|
||
return {
|
||
name: parseStringParam(parameters["name"], ""),
|
||
volume: parseIntegerParam(parameters["volume"], 90),
|
||
pitch: parseIntegerParam(parameters["pitch"], 100),
|
||
pan: parseIntegerParam(parameters["pan"], 0)
|
||
};
|
||
}
|
||
|
||
function readParameter() {
|
||
const parameters = PluginManager.parameters(getPluginName());
|
||
return {
|
||
version: "1.4.0",
|
||
base: parseStringParam(parameters["base"], ""),
|
||
baseAnimationDirection: parseStringParam(parameters["baseAnimationDirection"], "bottomToTop"),
|
||
baseAppearTime: parseIntegerParam(parameters["baseAppearTime"], 15),
|
||
baseViewTime: parseIntegerParam(parameters["baseViewTime"], 90),
|
||
baseFontSize: parseIntegerParam(parameters["baseFontSize"], 22),
|
||
basePadding: parseIntegerParam(parameters["basePadding"], 4),
|
||
baseLeftPadding: parseIntegerParam(parameters["baseLeftPadding"], 0),
|
||
baseRightPadding: parseIntegerParam(parameters["baseRightPadding"], 30),
|
||
baseItemPadding: parseIntegerParam(parameters["baseItemPadding"], 5),
|
||
baseSound: readStructSound(parseStructObjectParam(parameters["baseSound"], { name: "Item1", volume: 90, pitch: 100, pan: 0 })),
|
||
advanced: parseStringParam(parameters["advanced"], ""),
|
||
advancedVisibleSwitch: parseIntegerParam(parameters["advancedVisibleSwitch"], 0),
|
||
advancedBackgroundColor1: parseStringParam(parameters["advancedBackgroundColor1"], "rgba(0, 0, 64, 0.6)"),
|
||
advancedBackgroundColor2: parseStringParam(parameters["advancedBackgroundColor2"], "rgba(0, 32, 64, 0)"),
|
||
advancedUiPaddingTop: parseIntegerParam(parameters["advancedUiPaddingTop"], 5),
|
||
advancedUiPaddingBottom: parseIntegerParam(parameters["advancedUiPaddingBottom"], 5),
|
||
advancedKeepMessage: parseBooleanParam(parameters["advancedKeepMessage"], false)
|
||
};
|
||
}
|
||
|
||
checkExistPlugin(
|
||
Torigoya.FrameTween,
|
||
"「通知メッセージプラグイン」より上に「[鳥小屋.txt ベースプラグイン] Tweenアニメーション」が導入されていません。"
|
||
);
|
||
checkPluginVersion(
|
||
Torigoya.FrameTween.parameter.version,
|
||
"2.1.0",
|
||
"「[鳥小屋.txt ベースプラグイン] Tweenアニメーション」のバージョンが古いです。アップデートをしてください。"
|
||
);
|
||
|
||
Torigoya.NotifyMessage = {
|
||
name: getPluginName(),
|
||
parameter: readParameter()
|
||
};
|
||
|
||
(() => {
|
||
// -------------------------------------------------------------------------
|
||
// NotifyItem
|
||
|
||
class NotifyItem {
|
||
constructor(params) {
|
||
this.initialize(params);
|
||
}
|
||
|
||
initialize(params) {
|
||
this.message = params.message || "";
|
||
this.icon = params.icon;
|
||
this.note = params.note || "";
|
||
this._openness = 0;
|
||
|
||
DataManager.extractMetadata(this);
|
||
}
|
||
|
||
get openness() {
|
||
return this._openness;
|
||
}
|
||
|
||
set openness(value) {
|
||
if (value < 0) value = 0;
|
||
if (value > 255) value = 255;
|
||
this._openness = value;
|
||
}
|
||
|
||
/**
|
||
* 表示時に効果音再生が必要であるか?
|
||
* @returns {boolean}
|
||
*/
|
||
isRequirePlaySound() {
|
||
return !this.meta["noSound"];
|
||
}
|
||
|
||
/**
|
||
* 表示時の効果音を再生
|
||
*/
|
||
getDisplaySe() {
|
||
return Torigoya.NotifyMessage.parameter.baseSound;
|
||
}
|
||
}
|
||
|
||
Torigoya.NotifyMessage.NotifyItem = NotifyItem;
|
||
|
||
// -------------------------------------------------------------------------
|
||
// Window_NotifyMessage
|
||
|
||
/**
|
||
* 通知メッセージウィンドウ
|
||
*/
|
||
class Window_NotifyMessage extends Window_Base {
|
||
constructor() {
|
||
const rect = new Rectangle(0, 0, 1, 1);
|
||
super(rect);
|
||
this._notifyItem = new NotifyItem({});
|
||
this.opacity = 0;
|
||
this.createBackCoverSprite();
|
||
}
|
||
|
||
get contentsOpacity() {
|
||
return super.contentsOpacity;
|
||
}
|
||
|
||
set contentsOpacity(value) {
|
||
super.contentsOpacity = value;
|
||
this._backCoverSprite.opacity = value;
|
||
}
|
||
|
||
/**
|
||
* 背景用スプライトの生成
|
||
*/
|
||
createBackCoverSprite() {
|
||
this._backCoverSprite = new Sprite(new Bitmap(1, 1));
|
||
this.addChildAt(this._backCoverSprite, 0);
|
||
}
|
||
|
||
/**
|
||
* 通知メッセージの設定
|
||
* @param {NotifyItem} notifyItem
|
||
*/
|
||
setup(notifyItem) {
|
||
this._notifyItem = notifyItem;
|
||
this.refresh();
|
||
}
|
||
|
||
/**
|
||
* 更新
|
||
*/
|
||
update() {
|
||
this.contentsOpacity = this._notifyItem.openness;
|
||
super.update();
|
||
}
|
||
|
||
/**
|
||
* 画面の再描画
|
||
*/
|
||
refresh() {
|
||
if (!this._notifyItem) return;
|
||
|
||
this.refreshContents();
|
||
this.drawItem();
|
||
}
|
||
|
||
/**
|
||
* ウィンドウの再生成
|
||
*/
|
||
refreshContents() {
|
||
const { width, height } = this.itemSize();
|
||
this.width = width + this.padding * 2 + 200;
|
||
this.height = height + this.padding * 2;
|
||
this.createContents();
|
||
this._refreshBackCoverSprite();
|
||
}
|
||
|
||
/**
|
||
* アイテムの描画
|
||
*/
|
||
drawItem() {
|
||
const { message, icon } = this._notifyItem;
|
||
|
||
const messageRect = this.messageRect();
|
||
this.drawTextEx(message, messageRect.x, messageRect.y, messageRect.width);
|
||
if (icon) this.drawIcon(icon, this.leftPadding(), (this.innerHeight - ImageManager.iconHeight) / 2);
|
||
}
|
||
|
||
/**
|
||
* アイテムの描画領域サイズ
|
||
* @returns {{width: number, height: number}}
|
||
*/
|
||
itemSize() {
|
||
const { icon } = this._notifyItem;
|
||
const messageRect = this.messageRect();
|
||
return {
|
||
width: Math.min(Graphics.width, messageRect.x + messageRect.width + this.rightPadding()),
|
||
height: Math.max(messageRect.y + messageRect.height, icon ? ImageManager.iconHeight : 0)
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 本文領域
|
||
* @returns {Rectangle}
|
||
*/
|
||
messageRect() {
|
||
const { message, icon } = this._notifyItem;
|
||
const { width: messageWidth, height: messageHeight } = this.textSizeEx(message);
|
||
const gap = messageHeight - ImageManager.iconHeight;
|
||
const x = this.leftPadding() + (icon ? ImageManager.iconWidth + this.itemPadding() : 0);
|
||
return new Rectangle(x, icon ? (gap < 0 ? -gap / 2 : 0) : 0, Math.min(messageWidth, this.messageMaxWidth()), messageHeight);
|
||
}
|
||
|
||
/**
|
||
* 本文領域の最大幅
|
||
* @returns {number}
|
||
*/
|
||
messageMaxWidth() {
|
||
const { icon } = this._notifyItem;
|
||
return Graphics.width - this.leftPadding() - this.rightPadding() - (icon ? ImageManager.iconWidth + this.padding : 0);
|
||
}
|
||
|
||
/**
|
||
* 左側の空きスペースのサイズ
|
||
*/
|
||
leftPadding() {
|
||
return Torigoya.NotifyMessage.parameter.baseLeftPadding;
|
||
}
|
||
|
||
/**
|
||
* 右側の空きスペースのサイズ
|
||
*/
|
||
rightPadding() {
|
||
return Torigoya.NotifyMessage.parameter.baseRightPadding;
|
||
}
|
||
|
||
/**
|
||
* 背景画像の再生成
|
||
* @private
|
||
*/
|
||
_refreshBackCoverSprite() {
|
||
const bitmap = this._backCoverSprite.bitmap;
|
||
const w = this.width;
|
||
const h = this.height;
|
||
const c1 = Torigoya.NotifyMessage.parameter.advancedBackgroundColor1;
|
||
const c2 = Torigoya.NotifyMessage.parameter.advancedBackgroundColor2;
|
||
bitmap.resize(w, h);
|
||
bitmap.gradientFillRect(0, 0, w, h, c1, c2, false);
|
||
this._backCoverSprite.setFrame(0, 0, w, h);
|
||
this._backCoverSprite.opacity = this.contentsOpacity;
|
||
}
|
||
|
||
/**
|
||
* Paddingの設定
|
||
*/
|
||
updatePadding() {
|
||
this.padding = Torigoya.NotifyMessage.parameter.basePadding;
|
||
}
|
||
|
||
/**
|
||
* フォント設定
|
||
*/
|
||
resetFontSettings() {
|
||
super.resetFontSettings();
|
||
this.contents.fontSize = Torigoya.NotifyMessage.parameter.baseFontSize;
|
||
}
|
||
|
||
/**
|
||
* 行間
|
||
* @returns {number}
|
||
*/
|
||
lineHeight() {
|
||
return this.contents.fontSize * 1.25;
|
||
}
|
||
|
||
/**
|
||
* アイコンとメッセージの間の余白
|
||
* @returns {number}
|
||
*/
|
||
itemPadding() {
|
||
return Torigoya.NotifyMessage.parameter.baseItemPadding;
|
||
}
|
||
}
|
||
|
||
Torigoya.NotifyMessage.Window = Window_NotifyMessage;
|
||
|
||
// -------------------------------------------------------------------------
|
||
// NotifyManagerClass
|
||
|
||
/**
|
||
* 通知マネージャー
|
||
*/
|
||
class NotifyManagerClass {
|
||
constructor() {
|
||
this._currentScene = null;
|
||
this._stacks = [];
|
||
this._pools = [];
|
||
this._scrollAnimations = [];
|
||
this._group = new Torigoya.FrameTween.Group();
|
||
this._handlers = [];
|
||
}
|
||
|
||
/**
|
||
* 通知登録
|
||
* @param handler
|
||
*/
|
||
on(handler) {
|
||
this._handlers.push(handler);
|
||
}
|
||
|
||
/**
|
||
* 通知登録の解除
|
||
* @param handler
|
||
*/
|
||
off(handler) {
|
||
const index = this._handlers.indexOf(handler);
|
||
if (index === -1) return;
|
||
this._handlers.splice(index, 1);
|
||
}
|
||
|
||
/**
|
||
* すべての通知登録を解除
|
||
*/
|
||
offAll() {
|
||
this._handlers.length = 0;
|
||
}
|
||
|
||
/**
|
||
* 現在表示中のすべての通知ウィンドウを破棄
|
||
* ※シーン遷移時に呼び出される想定
|
||
*/
|
||
clear() {
|
||
this._currentScene = null;
|
||
|
||
this._stacks.forEach((stack) => {
|
||
if (!stack.window) return;
|
||
|
||
if (stack.window.parent) stack.window.parent.removeChild(window);
|
||
stack.window.parent = null;
|
||
stack.window = null;
|
||
});
|
||
|
||
if (!Torigoya.NotifyMessage.parameter.advancedKeepMessage) {
|
||
this._stacks.length = 0;
|
||
this._group.clear();
|
||
}
|
||
|
||
this._scrollAnimations.forEach((a) => a.abort());
|
||
this._scrollAnimations.length = 0;
|
||
|
||
this._pools.forEach((pool) => pool.destroy());
|
||
this._pools.length = 0;
|
||
}
|
||
|
||
/**
|
||
* 表示先シーンの設定
|
||
* @param scene
|
||
*/
|
||
setScene(scene) {
|
||
if (this._currentScene === scene) return;
|
||
if (this._currentScene) this.clear();
|
||
|
||
this._currentScene = scene;
|
||
if (!this._currentScene.torigoyaNotifyMessageContainer) {
|
||
const container = new Sprite();
|
||
this._currentScene.torigoyaNotifyMessageContainer = container;
|
||
this._currentScene.addChild(container);
|
||
}
|
||
|
||
if (Torigoya.NotifyMessage.parameter.advancedKeepMessage) {
|
||
this._stacks.forEach((stack) => {
|
||
stack.window = this._setupWindow(stack.notifyItem);
|
||
stack.window.y = stack.y;
|
||
stack.window.contentsOpacity = 255;
|
||
this._appendToScene(stack.window);
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 通知メッセージごとのマージン
|
||
* @returns {number}
|
||
*/
|
||
itemMargin() {
|
||
return 5;
|
||
}
|
||
|
||
/**
|
||
* 更新処理
|
||
*/
|
||
update() {
|
||
const visible = this.isVisible();
|
||
if (visible) this._group.update();
|
||
if (this._currentScene && this._currentScene.torigoyaNotifyMessageContainer)
|
||
this._currentScene.torigoyaNotifyMessageContainer.visible = visible;
|
||
}
|
||
|
||
/**
|
||
* 表示中であるか?
|
||
*/
|
||
isVisible() {
|
||
const switchId = Torigoya.NotifyMessage.parameter.advancedVisibleSwitch;
|
||
if (!switchId) return true;
|
||
|
||
return $gameSwitches.value(switchId);
|
||
}
|
||
|
||
/**
|
||
* 通知の発生
|
||
* @param {NotifyItem} notifyItem
|
||
*/
|
||
notify(notifyItem) {
|
||
// 非表示中は新規の追加を行わない
|
||
if (!this.isVisible()) return;
|
||
|
||
const window = this._setupWindow(notifyItem);
|
||
this._appendToScene(window);
|
||
|
||
const stack = {
|
||
notifyItem,
|
||
window,
|
||
y: 0,
|
||
appearAnimation: null,
|
||
waitAnimation: null,
|
||
exitAnimation: null
|
||
};
|
||
this._stacks.unshift(stack);
|
||
|
||
this.startAppearAndExitAnimation(stack);
|
||
this.startScrollAnimation(stack.window.height);
|
||
|
||
// 効果音再生
|
||
if (notifyItem.isRequirePlaySound()) {
|
||
const se = notifyItem.getDisplaySe();
|
||
if (se && se.name) AudioManager.playSe(se);
|
||
}
|
||
|
||
// 通知
|
||
this._handlers.forEach((func) => func(notifyItem));
|
||
}
|
||
|
||
/**
|
||
* 通知メッセージの登場/退場アニメーション
|
||
* @param stack
|
||
*/
|
||
startAppearAndExitAnimation(stack) {
|
||
const viewTime = Torigoya.NotifyMessage.parameter.baseViewTime;
|
||
const animationDirection = Torigoya.NotifyMessage.parameter.baseAnimationDirection;
|
||
const topPadding = Torigoya.NotifyMessage.parameter.advancedUiPaddingTop;
|
||
var bottomPadding = Torigoya.NotifyMessage.parameter.advancedUiPaddingBottom;
|
||
const mapId = $gameMap.mapId();
|
||
if ($dataMapInfos[mapId].name == "釣り場所_昼" || $dataMapInfos[mapId].name == "釣り場所_夕") {
|
||
bottomPadding += 130;
|
||
}
|
||
// 真田調整
|
||
bottomPadding -= 60;
|
||
|
||
// スタックの状態を初期化
|
||
stack.y = animationDirection === "topToBottom" ? -stack.window.height + topPadding - 270 : Graphics.height - bottomPadding - 270;
|
||
|
||
// ウィンドウの初期状態を設定
|
||
//stack.window.x = 0;
|
||
|
||
stack.window.x = Graphics.width - 20;
|
||
if (stack.notifyItem.icon) {
|
||
stack.window.x -= 32;
|
||
}
|
||
|
||
stack.window.x -= this._currentScene.torigoyaNotifyMessageContainer.children[0].textWidth(
|
||
stack.window.convertEscapeCharacters(stack.notifyItem.message)
|
||
);
|
||
stack.window.y = stack.y;
|
||
stack.window.contentsOpacity = 0;
|
||
|
||
// 登場アニメーション
|
||
stack.appearAnimation = this.createAppearAnimation(stack).call(() => (stack.waitAnimation ? stack.waitAnimation.start() : null));
|
||
|
||
// 停止アニメーション
|
||
stack.waitAnimation =
|
||
viewTime > 0 ? this.createWaitAnimation(stack).call(() => (stack.exitAnimation ? stack.exitAnimation.start() : null)) : null;
|
||
|
||
// 退場アニメーション
|
||
stack.exitAnimation = this.createExitAnimation(stack).call(() => this._destroyStack(stack));
|
||
|
||
stack.appearAnimation.start();
|
||
}
|
||
|
||
/**
|
||
* 登場時のTweenアニメーションの作成
|
||
* @param stack
|
||
* @return {Tween}
|
||
*/
|
||
createAppearAnimation(stack) {
|
||
const appearTime = Torigoya.NotifyMessage.parameter.baseAppearTime;
|
||
|
||
return Torigoya.FrameTween.create(stack.notifyItem)
|
||
.group(this._group)
|
||
.to({ openness: 255 }, appearTime, Torigoya.FrameTween.Easing.easeInOutQuad);
|
||
}
|
||
|
||
/**
|
||
* 待機時のTweenアニメーションの作成
|
||
* @param stack
|
||
* @return {Tween}
|
||
*/
|
||
createWaitAnimation(stack) {
|
||
const viewTime = Torigoya.NotifyMessage.parameter.baseViewTime;
|
||
|
||
return Torigoya.FrameTween.create(stack.notifyItem).group(this._group).wait(viewTime);
|
||
}
|
||
|
||
/**
|
||
* 終了時のTweenアニメーションの作成
|
||
* @param stack
|
||
* @return {Tween}
|
||
*/
|
||
createExitAnimation(stack) {
|
||
const appearTime = Torigoya.NotifyMessage.parameter.baseAppearTime;
|
||
|
||
return Torigoya.FrameTween.create(stack.notifyItem)
|
||
.group(this._group)
|
||
.to({ openness: 0 }, appearTime, Torigoya.FrameTween.Easing.easeInOutQuad);
|
||
}
|
||
|
||
/**
|
||
* 通知メッセージリストのスクロールアニメーション
|
||
* @param newWindowHeight
|
||
*/
|
||
startScrollAnimation(newWindowHeight) {
|
||
const animationDirection = Torigoya.NotifyMessage.parameter.baseAnimationDirection;
|
||
|
||
// 既に動作中のアニメーションがある場合は破棄
|
||
this._scrollAnimations.forEach((a) => a.abort());
|
||
this._scrollAnimations.length = 0;
|
||
|
||
if (animationDirection === "topToBottom") {
|
||
this.applyScrollAnimationForTopToBottom(newWindowHeight);
|
||
} else {
|
||
this.applyScrollAnimationForBottomToTop(newWindowHeight);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 上から下に移動するアニメーションを反映
|
||
* @param newWindowHeight
|
||
*/
|
||
applyScrollAnimationForTopToBottom(newWindowHeight) {
|
||
const appearTime = Torigoya.NotifyMessage.parameter.baseAppearTime;
|
||
const bottomPadding = Torigoya.NotifyMessage.parameter.advancedUiPaddingBottom;
|
||
|
||
let i = 0;
|
||
while (i < this._stacks.length) {
|
||
const stack = this._stacks[i];
|
||
|
||
if (stack.y > Graphics.height) {
|
||
this._destroyStack(stack);
|
||
continue;
|
||
}
|
||
|
||
if (stack.y + stack.window.height > Graphics.height - bottomPadding) {
|
||
this.forceStartExitAnimation(stack);
|
||
}
|
||
|
||
stack.y += newWindowHeight + this.itemMargin();
|
||
const animation = Torigoya.FrameTween.create(stack.window)
|
||
.group(this._group)
|
||
.to({ y: stack.y }, appearTime, Torigoya.FrameTween.Easing.easeInOutQuad)
|
||
.start();
|
||
this._scrollAnimations.push(animation);
|
||
|
||
++i;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 下から上に移動するアニメーションを反映
|
||
* @param newWindowHeight
|
||
*/
|
||
applyScrollAnimationForBottomToTop(newWindowHeight) {
|
||
const appearTime = Torigoya.NotifyMessage.parameter.baseAppearTime;
|
||
const topPadding = Torigoya.NotifyMessage.parameter.advancedUiPaddingTop;
|
||
|
||
let i = 0;
|
||
while (i < this._stacks.length) {
|
||
const stack = this._stacks[i];
|
||
|
||
if (stack.y + stack.window.height < 0) {
|
||
this._destroyStack(stack);
|
||
continue;
|
||
}
|
||
|
||
if (stack.y < topPadding) {
|
||
this.forceStartExitAnimation(stack);
|
||
}
|
||
|
||
stack.y -= newWindowHeight + this.itemMargin();
|
||
const animation = Torigoya.FrameTween.create(stack.window)
|
||
.group(this._group)
|
||
.to({ y: stack.y }, appearTime, Torigoya.FrameTween.Easing.easeInOutQuad)
|
||
.start();
|
||
this._scrollAnimations.push(animation);
|
||
|
||
++i;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 指定スタックの登場/待機アニメーションを強制終了して終了アニメーションを開始
|
||
* @param stack
|
||
*/
|
||
forceStartExitAnimation(stack) {
|
||
if (!stack.appearAnimation.finished) {
|
||
stack.appearAnimation.abort();
|
||
if (stack.waitAnimation) stack.waitAnimation.abort();
|
||
stack.exitAnimation.start();
|
||
} else if (stack.waitAnimation && !stack.waitAnimation.finished) {
|
||
stack.waitAnimation.abort();
|
||
stack.exitAnimation.start();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 通知メッセージをもとにウィンドウを初期化
|
||
* @param notifyItem
|
||
* @returns {Window|Window_NotifyMessage}
|
||
* @private
|
||
*/
|
||
_setupWindow(notifyItem) {
|
||
const window = this._createOrGetFromPoolWindow();
|
||
window.setup(notifyItem);
|
||
window.x = 0;
|
||
window.y = 0;
|
||
window.contentsOpacity = 0;
|
||
return window;
|
||
}
|
||
|
||
/**
|
||
* ウィンドウをプールから取得、ない場合は生成する
|
||
* @returns {Window_NotifyMessage|*}
|
||
* @private
|
||
*/
|
||
_createOrGetFromPoolWindow() {
|
||
const window = this._pools.pop();
|
||
if (window) return window;
|
||
|
||
return new Window_NotifyMessage();
|
||
}
|
||
|
||
/**
|
||
* 使用済みウィンドウをプールに戻す
|
||
* @param window
|
||
* @private
|
||
*/
|
||
_releaseWindow(window) {
|
||
if (window.parent) window.parent.removeChild(window);
|
||
window.parent = null;
|
||
this._pools.push(window);
|
||
}
|
||
|
||
/**
|
||
* シーンへのaddChild
|
||
* @param window
|
||
* @private
|
||
*/
|
||
_appendToScene(window) {
|
||
if (!this._currentScene) return;
|
||
if (!this._currentScene.torigoyaNotifyMessageContainer) return;
|
||
this._currentScene.torigoyaNotifyMessageContainer.addChild(window);
|
||
}
|
||
|
||
/**
|
||
* スタックから指定の通知を削除
|
||
* @param stack
|
||
* @private
|
||
*/
|
||
_destroyStack(stack) {
|
||
const index = this._stacks.indexOf(stack);
|
||
if (index === -1) return;
|
||
this._stacks.splice(index, 1);
|
||
if (stack.window) this._releaseWindow(stack.window);
|
||
stack.appearAnimation = null;
|
||
stack.waitAnimation = null;
|
||
stack.exitAnimation = null;
|
||
}
|
||
}
|
||
|
||
const NotifyManager = new NotifyManagerClass();
|
||
Torigoya.NotifyMessage.Manager = NotifyManager;
|
||
|
||
// -------------------------------------------------------------------------
|
||
// Scene_Map
|
||
|
||
const upstream_Scene_Map_createWindowLayer = Scene_Map.prototype.createWindowLayer;
|
||
Scene_Map.prototype.createWindowLayer = function () {
|
||
NotifyManager.setScene(this);
|
||
upstream_Scene_Map_createWindowLayer.apply(this);
|
||
};
|
||
|
||
const upstream_Scene_Map_update = Scene_Map.prototype.update;
|
||
Scene_Map.prototype.update = function () {
|
||
upstream_Scene_Map_update.apply(this);
|
||
NotifyManager.update();
|
||
};
|
||
|
||
// -------------------------------------------------------------------------
|
||
// SceneManager
|
||
|
||
const upstream_SceneManager_onSceneTerminate = SceneManager.onSceneTerminate;
|
||
SceneManager.onSceneTerminate = function () {
|
||
NotifyManager.clear();
|
||
upstream_SceneManager_onSceneTerminate.apply(this);
|
||
};
|
||
|
||
// -------------------------------------------------------------------------
|
||
// プラグインコマンド
|
||
|
||
function commandNotify({ message, icon, note }) {
|
||
const item = new NotifyItem({ message, icon: parseInt(icon, 10), note });
|
||
NotifyManager.notify(item);
|
||
}
|
||
|
||
function commandNotifyWithVariableIcon({ message, iconVariable, note }) {
|
||
const variableId = parseInt(iconVariable, 10);
|
||
const icon = Math.max($gameVariables.value(variableId), 0);
|
||
const item = new NotifyItem({ message, icon, note });
|
||
NotifyManager.notify(item);
|
||
}
|
||
|
||
PluginManager.registerCommand(Torigoya.NotifyMessage.name, "notify", commandNotify);
|
||
PluginManager.registerCommand(Torigoya.NotifyMessage.name, "notifyWithVariableIcon", commandNotifyWithVariableIcon);
|
||
})();
|
||
})();
|