magical-girls-runa-and-nanami/js/plugins/KMS_MapActiveMessage.js
2026-02-28 12:33:13 -06:00

1480 lines
48 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//=============================================================================
// KMS_MapActiveMessage.js
// Last update: 2019/08/31
//=============================================================================
/*:
* @plugindesc
* [v0.2.0] Show messages automatically for events on map.
*
* @author Kameo (Kamesoft)
*
* @param Balloon offset Y
* @default 20
* @desc Vertical position offset for balloons by pixel.
*
* @param Balloon margin
* @default -8
* @desc Adjust frame size of balloons by pixel.
*
* @param Default range
* @default 4
* @desc Default distance for displaying message by tile unit.
*
* @param Display duration
* @default 300
* @desc Display frame count.
*
* @param Max message count
* @default 10
* @desc Max number of active messages.
*
* @param Message skin
* @default ActiveMessageSkin
* @require 1
* @dir img/system/
* @type file
* @desc Message skin for active message. Load from img/system.
*
*
* @help
*
* ## Plugin command
*
* MapActiveMessage enable # Enable active message
* MapActiveMessage disable # Display active message
* MapActiveMessage show 10 # Show message of the event whose ID is 10
* MapActiveMessage show # Show messages of all events
*
*/
/*:ja
* @plugindesc
* [v0.2.0 munokura改変] プレイヤーが近付いたときに、自動的にメッセージを表示するイベントを作成します。
*
* @author かめお (Kamesoft)
*
* @param Balloon offset Y
* @text 縦位置調整
* @default 20
* @desc 吹き出しの縦方向の位置をピクセル単位で調整します。
*
* @param Balloon margin
* @text 枠サイズ調整
* @default -8
* @desc 吹き出しの枠サイズをピクセル単位で調整します。
*
* @param Default range
* @text メッセージ表示距離
* @default 4
* @desc メッセージを表示する距離をタイル単位で指定します。
*
* @param Display duration
* @text メッセージ表示時間
* @default 300
* @desc メッセージ表示時間をフレーム単位で指定します。
*
* @param Max message count
* @text メッセージ最大数
* @default 10
* @desc 表示できるメッセージの最大数です。
*
* @param Message skin
* @text メッセージのスキン画像
* @default ActiveMessageSkin
* @require 1
* @dir img/system/
* @type file
* @desc メッセージの表示に使用するスキン画像です。 img/system から読み込みます。
*
*
* @help
*
* ■ プラグインコマンド
*
* MapActiveMessage enable # アクティブメッセージを有効にします。
* MapActiveMessage disable # アクティブメッセージを無効にします。
* MapActiveMessage show 10 # イベント ID:10 のメッセージを表示します。
* MapActiveMessage show # 全イベントのメッセージを表示します。
*
*
* ◆改変箇所(ムノクラ)
* 注釈タグにオフセットの機能を追加しました。
*
* <ActiveMessageOffsetX:100>
* <アクティブメッセージXオフセット:100>
* 100ピクセル右にオフセットします。
*
* <ActiveMessageOffsetY:100>
* <アクティブメッセージYオフセット:100>
* 100ピクセル下にオフセットします。
*
*
* 利用規約:
* MITライセンスです。
* https://licenses.opensource.jp/MIT/MIT.html
* 作者に無断で改変、再配布が可能で、
* 利用形態商用、18禁利用等についても制限はありません。
*/
var KMS = KMS || {};
(function () {
'use strict';
// 定数
var Const =
{
debug: false, // デバッグモード
pluginCode: 'MapActiveMessage', // プラグインコード
regex: {
messageOffsetX: /<(?:アクティブメッセージXオフセット|ActiveMessageOffsetX)\s*[:\s]\s*([^>]+)>/i, // munokura追記
messageOffsetY: /<(?:アクティブメッセージYオフセット|ActiveMessageOffsetY)\s*[:\s]\s*([^>]+)>/i, // munokura追記
activeMessage: /<(?:アクティブメッセージ|ActiveMessage)\s*[:\s]\s*([^>]+)>/i,
displayRange: /<(?:アクティブメッセージ距離|ActiveMessageRange)\s*[:\s]\s*(\d+)>/i,
displayDuration: /<(?:アクティブメッセージ表示時間|ActiveMessageDuration)\s*[:\s]\s*(\d+)>/i,
beginMessage: /<(?:アクティブメッセージ開始|BeginActiveMessage)>/i, // * 未使用
endMessage: /<(?:アクティブメッセージ終了|EndActiveMessage)>/i // * 未使用
},
balloonFrameInfo: { margin: 4, size: 24, lineLength: 48, srcSize: 96 },
balloonVertexSize: { width: 24, height: 48 },
// 吹き出しの表示位置
balloonPosition: { below: 0, above: 1 }
};
var PluginName = 'KMS_' + Const.pluginCode;
KMS.imported = KMS.imported || {};
KMS.imported[Const.pluginCode] = true;
function isNullOrUndefined(value) {
return value === null || value === undefined;
}
// デフォルト値つきで文字列から int を解析
function parseIntWithDefault(param, defaultValue) {
var value = parseInt(param);
return isNaN(value) ? defaultValue : value;
}
var pluginParams = PluginManager.parameters(PluginName);
var Params = {};
Params.messageSkin = pluginParams['Message skin'] || 'ActiveMessageSkin';
Params.messageCountMax = Math.max(parseIntWithDefault(pluginParams['Max message count'], 8), 1);
Params.balloonOffsetY = parseIntWithDefault(pluginParams['Balloon offset Y'], 20);
Params.balloonMargin = parseIntWithDefault(pluginParams['Balloon margin'], -8);
Params.defaultRange = Math.max(parseIntWithDefault(pluginParams['Default range'], 4), 1);
Params.displayDuration = Math.max(parseIntWithDefault(pluginParams['Display duration'], 300), 1);
Params.fadeFrameCount = Math.max(parseIntWithDefault(pluginParams['Fade frame count'], 8), 1);
Params.fontSize = Math.max(parseIntWithDefault(pluginParams['Font size'], 18), 1);
// デバッグログ
var debuglog;
if (Const.debug) {
debuglog = function () { console.log(arguments); };
}
else {
debuglog = function () { };
}
var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function (command, args) {
_Game_Interpreter_pluginCommand.call(this, command, args);
if (command !== Const.pluginCode) {
return;
}
switch (args[0]) {
case 'enable': // 有効化
$gameSystem.setMapActiveMessageEnabled(true);
break;
case 'disable': // 無効化
$gameSystem.setMapActiveMessageEnabled(false);
break;
case 'show': // 強制表示 (eventId)
// eventId 省略時 (undefined) は全イベントが対象
$gameMap.forceDisplayActiveMessage(parseInt(args[1]));
break;
default:
// 不明なコマンド
console.error('[%s %s] Unknown command.', Const.pluginCode, args[0]);
break;
}
};
// タイリング描画
function tileBlt(dstImage, srcImage, sx, sy, sw, sh, dx, dy, dw, dh) {
for (var offY = 0; offY < dh; offY += sh) {
for (var offX = 0; offX < dw; offX += sw) {
var tempSh = Math.min(sh, dh - offY);
var tempSw = Math.min(sw, dw - offX);
dstImage.blt(
srcImage,
sx, sy, tempSw, tempSh,
dx + offX, dy + offY, tempSw, tempSh
);
}
}
}
//-----------------------------------------------------------------------------
// Game_Temp
var _Game_Temp_initialize = Game_Temp.prototype.initialize;
Game_Temp.prototype.initialize = function () {
_Game_Temp_initialize.call(this);
this.clearMapActiveMessage();
};
/**
* アクティブメッセージの登録
*/
Game_Temp.prototype.pushMapActiveMessage = function (text, targetEvent, isForced) {
var message = { text: text, event: targetEvent, isForced: !!isForced };
this._mapActiveMessages.push(message);
};
/**
* アクティブメッセージのクリア
*/
Game_Temp.prototype.clearMapActiveMessage = function () {
this._mapActiveMessages = [];
};
/**
* 次のアクティブメッセージを取得
*/
Game_Temp.prototype.popNextMapActiveMessage = function () {
return this._mapActiveMessages.shift();
};
/**
* アクティブメッセージが登録されているか
*/
Game_Temp.prototype.isMapActiveMessageReady = function () {
return this._mapActiveMessages.length > 0;
};
//-----------------------------------------------------------------------------
// Game_System
/**
* アクティブメッセージの有効状態を取得
*/
Game_System.prototype.isMapActiveMessageEnabled = function () {
return !isNullOrUndefined(this._mapActiveMessageEnabled) ?
this._mapActiveMessageEnabled :
true;
};
/**
* アクティブメッセージの有効状態を設定
*/
Game_System.prototype.setMapActiveMessageEnabled = function (enabled) {
this._mapActiveMessageEnabled = !!enabled;
};
//-----------------------------------------------------------------------------
// Game_Map
var _Game_Map_setup = Game_Map.prototype.setup;
Game_Map.prototype.setup = function (mapId) {
_Game_Map_setup.call(this, mapId);
this.initializeActiveMessage();
};
/**
* アクティブメッセージの初期化
*/
Game_Map.prototype.initializeActiveMessage = function () {
// 最初は全イベントの表示済みフラグを解除
this.clearActiveMessageShownFlags();
};
/**
* アクティブメッセージの表示済みフラグを解除
*/
Game_Map.prototype.clearActiveMessageShownFlags = function () {
this.events().forEach(function (event) {
event.setMapActiveMessageShown(false);
});
this.requestUpdateActiveMessage();
};
/**
* アクティブメッセージの更新要求
*/
Game_Map.prototype.requestUpdateActiveMessage = function () {
this._needsUpdateActiveMessage = true;
};
var _Game_Map_update = Game_Map.prototype.update;
Game_Map.prototype.update = function (sceneActive) {
_Game_Map_update.call(this, sceneActive);
this.updateDisplayActiveMessage();
};
/**
* アクティブメッセージの表示判定
*/
Game_Map.prototype.updateDisplayActiveMessage = function () {
if (!this._needsUpdateActiveMessage) {
return;
}
this._needsUpdateActiveMessage = false;
// アクティブメッセージの登録
var events = $gamePlayer.findAvailableMapActiveMessageEvents();
events.forEach(function (event) {
$gameTemp.pushMapActiveMessage(event.getMapActiveMessage(), event);
});
};
/**
* アクティブメッセージの強制表示
*/
Game_Map.prototype.forceDisplayActiveMessage = function (eventId) {
var invoker = function (event) {
$gameTemp.pushMapActiveMessage(event.getMapActiveMessage(), event, true);
};
if (isNullOrUndefined(eventId) || isNaN(eventId)) {
// 全表示
this.events().forEach(invoker);
}
else {
// イベント ID 指定
this.events().filter(function (event) {
return event.eventId() === eventId;
}).forEach(invoker);
}
};
var _Game_Map_refresh = Game_Map.prototype.refresh;
Game_Map.prototype.refresh = function () {
_Game_Map_refresh.call(this);
this.requestUpdateActiveMessage();
};
//-----------------------------------------------------------------------------
// Game_CharacterBase
var _Game_CharacterBase = Game_CharacterBase.prototype.setDirection;
Game_CharacterBase.prototype.setDirection = function (d) {
_Game_CharacterBase.call(this, d);
// 移動時には方向指定があるはずなので、ここでメッセージの更新要求を出す
if (!isNullOrUndefined($gameMap)) {
$gameMap.requestUpdateActiveMessage();
}
};
//-----------------------------------------------------------------------------
// Game_Player
/**
* アクティブメッセージを表示可能なイベントを探す
*/
Game_Player.prototype.findAvailableMapActiveMessageEvents = function () {
if (!this.canMove()) {
return [];
}
// 指定距離内でメッセージ未表示のイベントを列挙
var candidateEvents = $gameMap.events().filter(function (event) {
return event.hasMapActiveMessage() &&
!event.isMapActiveMessageShown() &&
this.calcDistanceForMapActiveMessage(event) <= event.getMapActiveMessageRange();
}, this);
// 表示済みフラグの解除判定
$gameMap.events().forEach(function (event) {
var distance = this.calcDistanceForMapActiveMessage(event);
if (event.isMapActiveMessageShown()) {
// メッセージ表示距離から出ていれば表示済みフラグ解除
if (distance > event.getMapActiveMessageRange()) {
event.setMapActiveMessageShown(false);
}
}
}, this);
return candidateEvents;
};
Game_Player.prototype.calcDistanceForMapActiveMessage = function (event) {
var diffX = this.x - event.x;
var diffY = this.y - event.y;
return Math.sqrt(diffX * diffX + diffY * diffY);
};
//-----------------------------------------------------------------------------
// Game_Event
var _Game_Event_setupPage = Game_Event.prototype.setupPage;
Game_Event.prototype.setupPage = function () {
_Game_Event_setupPage.call(this);
this.setupMapActiveMessage();
};
/**
* 現在のページ番号を取得
*/
Game_Event.prototype.pageIndex = function () {
return this._pageIndex;
};
/**
* アクティブメッセージを構築
*/
Game_Event.prototype.setupMapActiveMessage = function () {
this._mapActiveMessage = null;
this._mapActiveMessageRange = Params.defaultRange;
this._mapActiveMessageDuration = Params.displayDuration;
this._isMapActiveMessageShown = false;
this._messageOffsetX = 0; // munokura追記
this._messageOffsetY = 0; // munokura追記
// 注釈以外に達するまで解析
var page = this.page();
if (isNullOrUndefined(page)) {
return;
}
var isComment = function (command) {
return command && (command.code === 108 || command.code === 408);
};
// 複数行対応のために注釈を結合
var index = 0;
var command = page.list[index];
var comment = '';
while (isComment(command)) {
if (comment.length > 0) {
comment += '\n';
}
comment += command.parameters[0];
command = page.list[++index];
}
// メッセージ定義を解析
var messageMatch = Const.regex.activeMessage.exec(comment);
if (!isNullOrUndefined(messageMatch)) {
this._mapActiveMessage = messageMatch[1];
}
// メッセージ距離を解析
var rangeMatch = Const.regex.displayRange.exec(comment);
if (!isNullOrUndefined(rangeMatch)) {
this._mapActiveMessageRange =
Math.max(parseIntWithDefault(rangeMatch[1], Params.defaultRange), 1);
}
// メッセージ表示時間を解析
var durationMatch = Const.regex.displayDuration.exec(comment);
if (!isNullOrUndefined(durationMatch)) {
this._mapActiveMessageDuration =
parseIntWithDefault(durationMatch[1], Params.displayDuration);
}
// Xオフセットを解析 // munokura追記
var messageOffsetX = Const.regex.messageOffsetX.exec(comment);
if (!isNullOrUndefined(messageOffsetX)) {
this._messageOffsetX =
parseIntWithDefault(messageOffsetX[1], 0);
}
// Yオフセットを解析 // munokura追記
var messageOffsetY = Const.regex.messageOffsetY.exec(comment);
if (!isNullOrUndefined(messageOffsetY)) {
this._messageOffsetY =
parseIntWithDefault(messageOffsetY[1], 0);
}
};
/**
* アクティブメッセージを取得
*
* @return {String} メッセージ
*/
Game_Event.prototype.getMapActiveMessage = function () {
return this._mapActiveMessage;
};
/**
* アクティブメッセージが存在するか
*
* @return {Boolean} true if exists
*/
Game_Event.prototype.hasMapActiveMessage = function () {
return !isNullOrUndefined(this._mapActiveMessage);
};
/**
* アクティブメッセージを表示可能な範囲
*
* @return {Number} タイル単位の表示範囲半径
*/
Game_Event.prototype.getMapActiveMessageRange = function () {
return this._mapActiveMessageRange;
};
/**
* アクティブメッセージのXオフセット // munokura追記
*
* @return {Number} ピクセル単位のオフセット量
*/
Game_Event.prototype.getMessageOffsetX = function () {
return this._messageOffsetX;
};
/**
* アクティブメッセージのYオフセット // munokura追記
*
* @return {Number} ピクセル単位のオフセット量
*/
Game_Event.prototype.getMessageOffsetY = function () {
return this._messageOffsetY;
};
/**
* アクティブメッセージを表示するフレーム数
*
* @return {Number} 自動消去するまでのフレーム数
*/
Game_Event.prototype.getMapActiveMessageDuration = function () {
return this._mapActiveMessageDuration;
};
/**
* アクティブメッセージを表示済みか
*
* @return {Boolean} true if shown
*/
Game_Event.prototype.isMapActiveMessageShown = function () {
return this._isMapActiveMessageShown;
};
/**
* アクティブメッセージ表示済みかどうかを設定
*
* @param {Boolean} shown 設定する値
*/
Game_Event.prototype.setMapActiveMessageShown = function (shown) {
this._isMapActiveMessageShown = !!shown;
};
//-----------------------------------------------------------------------------
// Sprite_MapActiveMessageBalloon
//
// アクティブメッセージの吹き出し用スプライト
function Sprite_MapActiveMessageBalloon() {
this.initialize.apply(this, arguments);
}
Sprite_MapActiveMessageBalloon.prototype = Object.create(Sprite_Base.prototype);
Sprite_MapActiveMessageBalloon.prototype.constructor = Sprite_MapActiveMessageBalloon;
Sprite_MapActiveMessageBalloon.prototype.initialize = function () {
Sprite_Base.prototype.initialize.call(this);
this.anchor.y = 0.5;
this.initMembers();
};
Sprite_MapActiveMessageBalloon.prototype.initMembers = function () {
this._owner = null;
};
/**
* オーナーウィンドウの設定
*/
Sprite_MapActiveMessageBalloon.prototype.setOwner = function (owner) {
this._owner = owner;
};
/**
* 位置をオーナーウィンドウに合わせる
*/
Sprite_MapActiveMessageBalloon.prototype.followOwner = function () {
this.y = this._owner.height / 2;
};
/**
* サイズをオーナーウィンドウに合わせる
*/
Sprite_MapActiveMessageBalloon.prototype.fitToOwner = function () {
if (isNullOrUndefined(this._owner)) {
return;
}
var frameSize = Const.balloonFrameInfo.size;
var vertexHeight = Const.balloonVertexSize.height;
var heightOffset = (vertexHeight - frameSize) * 2;
// Bitmap のサイズ調整
var bitmapWidth = this._owner.width;
var bitmapHeight = this._owner.height + heightOffset;
if (isNullOrUndefined(this.bitmap) ||
(this.width != bitmapWidth || this.height != bitmapHeight)) {
this.bitmap = new Bitmap(bitmapWidth, bitmapHeight);
}
else {
this.bitmap.clear();
}
if (Const.debug) {
this.bitmap.fillRect(0, 0, bitmapWidth, bitmapHeight, 'rgba(160, 255, 160, 0.5)');
}
};
/**
* 吹き出しの再描画
*/
Sprite_MapActiveMessageBalloon.prototype.refresh = function () {
if (isNullOrUndefined(this._owner)) {
return;
}
// サイズの調整
this.fitToOwner();
// 吹き出しの描画
var frameSize = Const.balloonFrameInfo.size;
var vertexHeight = Const.balloonVertexSize.height;
var offsetX = -Params.balloonMargin;
var offsetY = vertexHeight - frameSize - Params.balloonMargin;
this.drawBalloon(
offsetX,
offsetY,
this.width - offsetX * 2,
this.height - offsetY * 2
);
};
/**
* 吹き出しを描画
*/
Sprite_MapActiveMessageBalloon.prototype.drawBalloon = function (x, y, width, height) {
if (isNullOrUndefined(this._owner)) {
return;
}
this.drawBalloonBackground(x, y, width, height);
this.drawBalloonFrame(x, y, width, height);
};
/**
* 吹き出しの背景を描画
*/
Sprite_MapActiveMessageBalloon.prototype.drawBalloonBackground = function (x, y, width, height) {
var srcImage = this._owner.getWindowSkin();
var frame = Const.balloonFrameInfo;
var prevOpacity = this.bitmap.paintOpacity;
this.bitmap.paintOpacity = this._owner.backOpacity;
// 背景下層
this.bitmap.blt(
srcImage,
0, 0, frame.srcSize, frame.srcSize,
x + frame.margin, y + frame.margin, width - frame.margin * 2, height - frame.margin * 2
);
// 背景上層
tileBlt(
this.bitmap, srcImage,
0, frame.srcSize, frame.srcSize, frame.srcSize,
x + frame.margin, y + frame.margin, width - frame.margin * 2, height - frame.margin * 2
);
this.bitmap.paintOpacity = prevOpacity;
};
/**
* 吹き出しの枠を描画
*/
Sprite_MapActiveMessageBalloon.prototype.drawBalloonFrame = function (x, y, width, height) {
var srcImage = this._owner.getWindowSkin();
var vertexOffset = this._owner.getBalloonVertexX();
var balloonPos = this._owner.getBalloonPosition();
var frame = Const.balloonFrameInfo;
var vertexSize = Const.balloonVertexSize;
// 吹き出しの頂点は枠内に収める
vertexOffset = Math.min(
Math.max(vertexOffset, 0),
width - (frame.size * 2 + vertexSize.width)
);
// 縦枠 + コーナーを描画
function drawFrameV(sx, dx, dy) {
this.bitmap.blt(
srcImage,
sx, 0, frame.size, frame.size,
dx, dy, frame.size, frame.size
);
this.bitmap.blt(
srcImage,
sx, frame.size, frame.size, frame.lineLength,
dx, dy + frame.size, frame.size, height - frame.size * 2
);
this.bitmap.blt(
srcImage,
sx, frame.size + frame.lineLength, frame.size, frame.size,
dx, dy + height - frame.size, frame.size, frame.size
);
}
// 横枠と頂点を描画
function drawFrameH(sy, dx, dy, showVertex) {
var baseSx = frame.srcSize + frame.size;
var frameWidth = width - frame.size * 2;
var leftWidth = showVertex ? vertexOffset : frameWidth;
// 枠線の左側 (頂点がない場合は全体)
this.bitmap.blt(
srcImage,
baseSx, sy, frame.lineLength, frame.size,
dx, dy, leftWidth, frame.size
);
if (!showVertex) {
// 頂点を描画しない
return;
}
// sy > 0 なら下枠、sy === 0 なら上枠のはず
var newDx = dx + leftWidth;
var newDy = dy + (sy > 0 ? 0 : -(vertexSize.height - frame.size));
// 頂点
var vertexSx = frame.srcSize + (sy > 0 ? 0 : vertexSize.width);
this.bitmap.blt(
srcImage,
vertexSx, frame.srcSize, vertexSize.width, vertexSize.height,
newDx, newDy, vertexSize.width, vertexSize.height
);
if (Const.debug) {
this.bitmap.fillRect(newDx, newDy, vertexSize.width, vertexSize.height, 'rgba(255, 160, 160, 0.5)');
}
// 枠線の右側
var rightWidth = frameWidth - (leftWidth + vertexSize.width);
if (rightWidth > 0) {
newDx += vertexSize.width;
this.bitmap.blt(
srcImage,
baseSx, sy, frame.lineLength, frame.size,
newDx, dy, rightWidth, frame.size
);
}
}
// 左枠
drawFrameV.call(this, frame.srcSize, x, y);
// 右枠
drawFrameV.call(this, frame.srcSize + frame.size + frame.lineLength, x + width - frame.size, y);
// 上枠 + 頂点
drawFrameH.call(
this,
0, x + frame.size, y,
balloonPos === Const.balloonPosition.below
);
// 下枠 + 頂点
drawFrameH.call(
this,
frame.size + frame.lineLength, x + frame.size, y + height - frame.size,
balloonPos === Const.balloonPosition.above
);
};
//-----------------------------------------------------------------------------
// Sprite_Character
/**
* 同一のイベントか判定
*/
Sprite_Character.prototype.isSameEvent = function (event) {
if (isNullOrUndefined(this._character) ||
isNullOrUndefined(event) ||
!(this._character instanceof Game_Event)) {
return false;
}
return this._character.eventId() === event.eventId();
};
//-----------------------------------------------------------------------------
// Spriteset_Map
/**
* 指定されたイベントに対応するキャラクタースプライトを取得
*/
Spriteset_Map.prototype.findCharacterSpriteByEvent = function (event) {
var sameSprites = this._characterSprites.filter(function (sprite) {
return sprite.isSameEvent(event);
});
if (sameSprites.length > 0) {
return sameSprites[0];
}
else {
return null;
}
};
//-----------------------------------------------------------------------------
// Window_MapActiveMessage
//
// マップ上でアクティブメッセージを表示するウィンドウ
// (スプライトでも良いが、メッセージ周りはウィンドウの方が扱いやすい)
function Window_MapActiveMessage() {
this.initialize.apply(this, arguments);
}
Window_MapActiveMessage.prototype = Object.create(Window_Base.prototype);
Window_MapActiveMessage.prototype.constructor = Window_MapActiveMessage;
// メッセージの一時描画バッファ
Window_MapActiveMessage.tempMessageBuffer = null;
/**
* アクティブメッセージ用スキンの事前読み込み
*/
Window_MapActiveMessage.preloadWindowskin = function () {
ImageManager.loadSystem(Params.messageSkin);
};
Window_MapActiveMessage.prototype.initialize = function () {
// コンテンツサイズは内容に応じて可変なので、ウィンドウサイズは仮
Window_Base.prototype.initialize.call(this, 0, 0, 64, 64);
if (isNullOrUndefined(Window_MapActiveMessage.tempMessageBuffer)) {
Window_MapActiveMessage.tempMessageBuffer =
new Bitmap(Graphics.boxWidth, Graphics.boxHeight / 2);
}
this._balloonSprite = null;
this.opacity = 0;
this.contentsOpacity = 0;
this.initMembers();
};
Window_MapActiveMessage.prototype.standardFontSize = function () {
return Params.fontSize;
};
Window_MapActiveMessage.prototype.loadWindowskin = function () {
// デフォルトのスキンの代わりに、アクティブメッセージ用のスキンを読み込む
this._windowskin = ImageManager.loadSystem(Params.messageSkin);
};
/**
* ウィンドウスキンを取得
*/
Window_MapActiveMessage.prototype.getWindowSkin = function () {
return this._windowskin;
};
Window_MapActiveMessage.prototype.initMembers = function () {
this._textState = null;
this._event = null;
this._characterSprite = null;
this._targetPageIndex = 0;
this._duration = 0;
this._isForceDisplay = false;
this._balloonPosition = Const.balloonPosition.above;
};
Window_MapActiveMessage.prototype.show = function () {
Window_Base.prototype.show.call(this);
if (!isNullOrUndefined(this._balloonSprite)) {
this._balloonSprite.show();
}
};
Window_MapActiveMessage.prototype.hide = function () {
this._duration = 0;
Window_Base.prototype.hide.call(this);
if (!isNullOrUndefined(this._balloonSprite)) {
this._balloonSprite.hide();
}
};
/**
* フェードアウト
*/
Window_MapActiveMessage.prototype.fadeOut = function () {
if (this.isFadingOut()) {
return;
}
if (this.isFadingIn()) {
// フェードイン中は同じ不透明度からフェードアウトする
this._duration = this._initialDisplayDuration - this._duration;
}
else {
this._duration = Params.fadeFrameCount;
}
};
Window_MapActiveMessage.prototype.numVisibleRows = function () {
return 4;
};
/**
* 吹き出しスプライトの設定
*/
Window_MapActiveMessage.prototype.setBalloonSprite = function (sprite) {
sprite.setOwner(this);
this._balloonSprite = sprite;
// ウィンドウの裏に表示
this.addChildAt(sprite, 0);
};
/**
* イベントに対する吹き出しの表示位置を取得
*/
Window_MapActiveMessage.prototype.getBalloonPosition = function () {
return this._balloonPosition;
};
/**
* メッセージ表示中か
*/
Window_MapActiveMessage.prototype.isDisplaying = function () {
return this._duration > 0;
};
/**
* 強制表示されたか
*/
Window_MapActiveMessage.prototype.isForced = function () {
return this._isForceDisplay;
};
/**
* フェードイン中か
*/
Window_MapActiveMessage.prototype.isFadingIn = function () {
return this._duration >= this._initialDisplayDuration - Params.fadeFrameCount;
};
/**
* フェードアウト中か
*/
Window_MapActiveMessage.prototype.isFadingOut = function () {
return this._duration < Params.fadeFrameCount;
};
/**
* 表示中のイベントと同一イベントか
*/
Window_MapActiveMessage.prototype.isSameEvent = function (event) {
if (isNullOrUndefined(this._event)) {
return false;
}
// ページ番号まで同じ場合に同一と見なす
if (this._event.eventId() === event.eventId() &&
this._targetPageIndex === event.pageIndex()) {
return true;
}
return false;
};
/**
* イベントが画面内にあるか判定
*/
Window_MapActiveMessage.prototype.isEventInScreen = function () {
if (isNullOrUndefined(this._event)) {
return false;
}
var x = this._event.screenX();
var y = this._event.screenY();
return x >= 0 && y >= 0 && x <= Graphics.boxWidth && y <= Graphics.boxHeight;
};
/**
* メッセージの表示開始
*
* @param {String} text '\n' 区切りのメッセージ
* @param {Game_Event} event 表示対象のイベント
* @param {Sprite_Character} sprite 表示対象のキャラクタースプライト
* @param {boolean} isForce 表示時間満了まで強制表示
*/
Window_MapActiveMessage.prototype.display = function (text, event, sprite, isForce) {
// 表示のキャンセル
function rollback() {
this.initMembers();
this.hide();
}
if (isNullOrUndefined(text) || isNullOrUndefined(event)) {
rollback.call(this);
return;
}
this._event = event;
this._characterSprite = sprite;
if (!this.isEventInScreen()) {
rollback.call(this);
return;
}
// 表示パラメータの設定
this._textState =
{
index: 0,
text: this.convertEscapeCharacters(text)
};
this._allTextWidth = 0;
this._targetPageIndex = event.pageIndex();
this._initialDisplayDuration = event.getMapActiveMessageDuration();
this._duration = this._initialDisplayDuration;
this._isForceDisplay = !!isForce;
this._initialgetMessageOffsetX = event.getMessageOffsetX(); // munokura追記
this._getMessageOffsetX = this._initialgetMessageOffsetX; // munokura追記
this._initialgetMessageOffsetY = event.getMessageOffsetY(); // munokura追記
this._getMessageOffsetY = this._initialgetMessageOffsetY; // munokura追記
this.newPage(this._textState);
this.updatePosition();
this.updateOpacity();
this.refreshBalloon();
this.show();
// 多重表示抑止のため、表示済みフラグを立てる
event.setMapActiveMessageShown(true);
};
/**
* 新しいページの表示
*/
Window_MapActiveMessage.prototype.newPage = function (textState) {
// コンテンツを一時領域に書く
this.contents = Window_MapActiveMessage.tempMessageBuffer;
this.contents.clear();
this.resetFontSettings();
textState.x = this.newLineX();
textState.y = 0;
textState.left = this.newLineX();
textState.height = this.calcTextHeight(textState, false);
this._allTextHeight = this.calcTextHeight(textState, true);
this.updateMessage();
// コンテンツを一時領域から正式に反映
this.createContents();
this.contents.blt(
Window_MapActiveMessage.tempMessageBuffer,
0, 0, this._allTextWidth, this._allTextHeight,
0, 0, this._allTextWidth, this._allTextHeight
);
};
/**
* メッセージの表示位置を設定
*/
Window_MapActiveMessage.prototype.updatePosition = function () {
if (isNullOrUndefined(this._event)) {
return;
}
// 画面外に出る場合は消去
if (!this.isEventInScreen()) {
this.hide();
return;
}
// 吹き出しの枠ぶんのマージン
var margin = Const.balloonFrameInfo.size;
var balloonOffsetY = Const.balloonVertexSize.height
- Params.balloonOffsetY
- margin;
var heightOffset = this.height
+ (!isNullOrUndefined(this._characterSprite) ? this._characterSprite.patternHeight() : $gameMap.tileHeight());
// デフォルトの位置は上
// var x = this._event.screenX() - this.width / 2;
// var y = this._event.screenY() - (heightOffset + balloonOffsetY);
var x = this._event.screenX() - this.width / 2 + this._event._messageOffsetX; // munokura追記
var y = this._event.screenY() - (heightOffset + balloonOffsetY - this._event._messageOffsetY); // munokura追記
this._balloonPosition = Const.balloonPosition.above;
// 画面左右にははみ出させない
x = Math.min(Math.max(x, margin), Graphics.boxWidth - this.width - margin);
// 画面上側にはみ出る場合は下に表示
if (y < margin) {
y = this._event.screenY() + balloonOffsetY;
this._balloonPosition = Const.balloonPosition.below;
}
// 画面下側にはみ出る場合は上に表示
if (y + this.height > Graphics.boxHeight - margin) {
y -= heightOffset + balloonOffsetY;
this._balloonPosition = Const.balloonPosition.above;
}
this.x = x;
this.y = y;
if (!isNullOrUndefined(this._balloonSprite)) {
// 吹き出しの頂点表示を考慮した位置に移動
this._balloonSprite.followOwner();
}
};
/**
* ウィンドウのサイズを更新
*/
Window_MapActiveMessage.prototype.updateWindowSize = function () {
var offset = this.standardPadding() * 2;
this.width = this._allTextWidth + offset;
this.height = this._allTextHeight + offset;
};
/**
* 不透明度の更新
*/
Window_MapActiveMessage.prototype.updateOpacity = function () {
var opacity = 255;
if (this.isFadingIn()) {
// フェードイン
opacity = 255 * (this._initialDisplayDuration - this._duration) / Params.fadeFrameCount;
}
else if (this.isFadingOut()) {
// フェードアウト
opacity = 255 * this._duration / Params.fadeFrameCount;
}
this.contentsOpacity = opacity;
if (!isNullOrUndefined(this._balloonSprite)) {
this._balloonSprite.opacity = opacity;
}
};
/**
* 吹き出しの再描画
*/
Window_MapActiveMessage.prototype.refreshBalloon = function () {
if (!isNullOrUndefined(this._balloonSprite)) {
this._balloonSprite.refresh();
}
};
/**
* プレイヤーとの距離を確認
*/
Window_MapActiveMessage.prototype.checkPlayerDistance = function () {
// 強制表示 or 消去中は距離判定しない
if (this.isForced() ||
this._duration <= Params.fadeFrameCount) {
return;
}
// 表示範囲外に出た場合は消す
var distance = $gamePlayer.calcDistanceForMapActiveMessage(this._event);
if (distance > this._event.getMapActiveMessageRange()) {
this.fadeOut();
}
};
Window_MapActiveMessage.prototype.update = function () {
Window_Base.prototype.update.call(this);
if (!isNullOrUndefined(this._balloonSprite)) {
this._balloonSprite.update();
}
if (!this.isDisplaying()) {
return;
}
this._duration--;
this.updateOpacity();
this.updatePosition();
this.checkPlayerDistance();
// 表示が終了したら初期化
if (!this.isDisplaying()) {
debuglog('[MapActiveMessage] Finished to display');
this.initMembers();
}
};
/**
* メッセージの更新
*/
Window_MapActiveMessage.prototype.updateMessage = function () {
if (isNullOrUndefined(this._textState)) {
return false;
}
while (!this.isEndOfText(this._textState)) {
this.processCharacter(this._textState);
this._allTextWidth = Math.max(this._allTextWidth, this._textState.x);
}
this.updateWindowSize();
return true;
};
/**
* 吹き出しの頂点位置を取得
*/
Window_MapActiveMessage.prototype.getBalloonVertexX = function () {
if (isNullOrUndefined(this._event)) {
return 0;
}
return this._event.screenX()
- this.x
- Const.balloonFrameInfo.size
- Const.balloonVertexSize.width / 2
+ Params.balloonMargin;
};
/**
* 改行時の描画先 X 座標
*/
Window_MapActiveMessage.prototype.newLineX = function () {
return 0;
};
/**
* 改行の処理
*/
Window_MapActiveMessage.prototype.processNewLine = function (textState) {
this._allTextWidth = Math.max(this._allTextWidth, textState.x);
Window_Base.prototype.processNewLine.call(this, textState);
};
/**
* 改ページの処理
*/
Window_MapActiveMessage.prototype.processNewPage = function (textState) {
Window_Base.prototype.processNewPage.call(this, textState);
if (textState.text[textState.index] === '\n') {
textState.index++;
}
textState.y = this.contents.height;
};
/**
* テキスト終端か
*/
Window_MapActiveMessage.prototype.isEndOfText = function (textState) {
return textState.index >= textState.text.length;
};
/**
* 改ページが必要か
*/
Window_MapActiveMessage.prototype.needsNewPage = function (textState) {
return !this.isEndOfText(textState) &&
textState.y + textState.height > this.contents.height;
};
//-----------------------------------------------------------------------------
// Scene_Map
var _Scene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;
Scene_Map.prototype.createAllWindows = function () {
_Scene_Map_createAllWindows.call(this);
this.createActiveMessageWindow();
};
/**
* アクティブメッセージウィンドウの作成
*/
Scene_Map.prototype.createActiveMessageWindow = function () {
if (!isNullOrUndefined(this._activeMessageWindowLayer)) {
return;
}
var width = Graphics.boxWidth;
var height = Graphics.boxHeight;
var x = (Graphics.width - width) / 2;
var y = (Graphics.height - height) / 2;
this._activeMessageWindowLayer = new WindowLayer();
this._activeMessageWindowLayer.move(x, y, width, height);
this.addChild(this._activeMessageWindowLayer);
Window_MapActiveMessage.preloadWindowskin();
};
var _Scene_Map_update = Scene_Map.prototype.update;
Scene_Map.prototype.update = function () {
_Scene_Map_update.call(this);
this.updateActiveMessageDisplay();
};
var _Scene_Map_stop = Scene_Map.prototype.stop;
Scene_Map.prototype.stop = function () {
_Scene_Map_stop.call(this);
$gameTemp.clearMapActiveMessage();
};
var _Scene_Map_terminate = Scene_Map.prototype.terminate;
Scene_Map.prototype.terminate = function () {
_Scene_Map_terminate.call(this);
this.destroyActiveMessageWindows();
};
/**
* アクティブメッセージウィンドウの破棄
*/
Scene_Map.prototype.destroyActiveMessageWindows = function () {
this._activeMessageWindowLayer.removeChildren();
this.removeChild(this._activeMessageWindowLayer);
this._activeMessageWindowLayer = null;
};
/**
* アクティブメッセージの表示を更新
*/
Scene_Map.prototype.updateActiveMessageDisplay = function () {
if (!$gameSystem.isMapActiveMessageEnabled() ||
$gameMap.isEventRunning()) {
// メッセージを表示できないときは非表示にしつつ各種フラグを解除
$gameTemp.clearMapActiveMessage();
$gameMap.clearActiveMessageShownFlags();
this._activeMessageWindowLayer.children.forEach(function (child) {
child.fadeOut();
});
return;
}
// 表示が完了したものを削除
this._activeMessageWindowLayer.children.filter(function (child) {
return !child.isDisplaying();
}).forEach(function (item) {
this._activeMessageWindowLayer.removeChild(item);
}, this);
// 要求されているメッセージを表示できるだけ表示
while ($gameTemp.isMapActiveMessageReady()) {
if (!this.displayActiveMessage()) {
break;
}
}
};
/**
* 指定されたイベントのアクティブメッセージが表示されているか判定
*/
Scene_Map.prototype.isActiveMessageDisplayed = function (event) {
var layer = this._activeMessageWindowLayer;
for (var i = 0; i < layer.children.length; i++) {
var window = layer.children[i];
if (window.isDisplaying() && window.isSameEvent(event)) {
return true;
}
}
return false;
};
/**
* アクティブメッセージの表示
*/
Scene_Map.prototype.displayActiveMessage = function () {
var layer = this._activeMessageWindowLayer;
// 最大数に達していたら表示を諦める
// (children には吹き出しも含まれるので / 2)
if (layer.children.length / 2 >= Params.messageCountMax) {
return false;
}
// 予約されているメッセージを表示
var message = $gameTemp.popNextMapActiveMessage();
while (!isNullOrUndefined(message)) {
// まだ表示していないもののみ表示
if (!this.isActiveMessageDisplayed(message.event)) {
var character = this._spriteset.findCharacterSpriteByEvent(message.event);
var balloon = new Sprite_MapActiveMessageBalloon();
var window = new Window_MapActiveMessage();
window.setBalloonSprite(balloon);
window.display(
message.text,
message.event,
character,
message.isForced);
layer.addChild(window);
}
message = $gameTemp.popNextMapActiveMessage();
}
return true;
};
var _Scene_Map_snapForBattleBackground = Scene_Map.prototype.snapForBattleBackground;
Scene_Map.prototype.snapForBattleBackground = function () {
// アクティブメッセージはキャプチャしない
var layer = this._activeMessageWindowLayer;
if (!isNullOrUndefined(layer)) {
layer.visible = false;
}
_Scene_Map_snapForBattleBackground.call(this);
if (!isNullOrUndefined(layer)) {
layer.visible = true;
}
};
})();