alter-egoism/js/plugins/KMS_MapActiveMessage.js
2025-11-01 14:17:42 -05:00

1587 lines
45 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. 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: 2022/05/22
//=============================================================================
/*:
* @plugindesc
* [v0.3.2] 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
* フキダシのヤツ、CBRって所が改造
* [v0.3.2] プレイヤーが近付いたときに、自動的にメッセージを表示するイベントを作成します。
*
* @author かめお (Kamesoft)
*
* @param Balloon offset Y
* @default 20
* @desc 吹き出しの縦方向の位置をピクセル単位で調整します。
*
* @param Balloon margin
* @default -8
* @desc 吹き出しの枠サイズをピクセル単位で調整します。
*
* @param Default range
* @default 4
* @desc メッセージを表示する距離をタイル単位で指定します。
*
* @param Display duration
* @default 300
* @desc メッセージ表示時間をフレーム単位で指定します。
*
* @param Max message count
* @default 10
* @desc 表示できるメッセージの最大数です。
*
* @param Message skin
* @default ActiveMessageSkin
* @require 1
* @dir img/system/
* @type file
* @desc メッセージの表示に使用するスキン画像です。 img/system から読み込みます。
*
*
* @help
*
* ■ プラグインコマンド
*
* MapActiveMessage enable # アクティブメッセージを有効にします。
* MapActiveMessage disable # アクティブメッセージを無効にします。
* MapActiveMessage show 10 # イベント ID:10 のメッセージを表示します。
* MapActiveMessage show # 全イベントのメッセージを表示します。
*
*/
var KMS = KMS || {};
(function () {
"use strict";
// 定数
var Const = {
debug: false, // デバッグモード
pluginCode: "MapActiveMessage", // プラグインコード
regex: {
activeMessage: /<(?:アクティブメッセージ|ActiveMessage)\s*[:\s]\s*([^>]+)>/i,
displayRange: /<(?:アクティブメッセージ距離|ActiveMessageRange)\s*[:\s]\s*(\d+)>/i,
displayDuration: /<(?:アクティブメッセージ表示時間|ActiveMessageDuration)\s*[:\s]\s*(\d+)>/i,
loopMessage: /<(?:アクティブメッセージループ|ActiveMessageLoop)>/i,
beginMessage: /<(?:アクティブメッセージ|ActiveMessage)\s*[:\s][^>]+$/i,
endMessage: /([^>]*)>/
},
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.pushMapActiveMessages = function (targetEvent, messages, needsLoop, isForced) {
var message = {
id: this._mapActiveMessageNextId++,
event: targetEvent,
messages: messages,
needsLoop: needsLoop,
isForced: isForced
};
this._mapActiveMessages.push(message);
};
/**
* アクティブメッセージのクリア
*/
Game_Temp.prototype.clearMapActiveMessage = function () {
this._mapActiveMessageNextId = 0;
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.pushMapActiveMessages(event, event.getMapActiveMessages(), event.needsMapActiveMessageLoop());
});
};
/**
* アクティブメッセージの強制表示
*/
Game_Map.prototype.forceDisplayActiveMessage = function (eventId) {
var invoker = function (event) {
$gameTemp.pushMapActiveMessages(event, event.getMapActiveMessages(), event.needsMapActiveMessageLoop(), 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._mapActiveMessageList = [];
this._mapActiveMessageRange = Params.defaultRange;
this._mapActiveMessageDuration = Params.displayDuration;
this._needsMapActiveMessageLoop = false;
this._isMapActiveMessageShown = false;
var page = this.page();
if (isNullOrUndefined(page)) {
return;
}
var parsed = this.parseCommentForMapActiveMessage(page);
var mergedComment = parsed.mergedComment;
var commentUnits = parsed.commentUnits;
// メッセージ距離を解析
var rangeMatch = Const.regex.displayRange.exec(mergedComment);
if (!isNullOrUndefined(rangeMatch)) {
this._mapActiveMessageRange = Math.max(parseIntWithDefault(rangeMatch[1], Params.defaultRange), 1);
}
// ループ設定を解析
var loopMatch = Const.regex.loopMessage.exec(mergedComment);
if (!isNullOrUndefined(loopMatch)) {
this._needsMapActiveMessageLoop = true;
}
commentUnits.forEach(function (unit) {
// メッセージ定義を解析
var messageMatch = Const.regex.activeMessage.exec(unit);
if (!isNullOrUndefined(messageMatch)) {
this._mapActiveMessageList.push({
text: messageMatch[1],
duration: this._mapActiveMessageDuration
});
}
// メッセージ表示時間を解析
var durationMatch = Const.regex.displayDuration.exec(unit);
if (!isNullOrUndefined(durationMatch)) {
var duration = parseIntWithDefault(durationMatch[1], Params.displayDuration);
this._mapActiveMessageDuration = duration;
// 直前のメッセージの duration を変更
if (this._mapActiveMessageList.length > 0) {
this._mapActiveMessageList[this._mapActiveMessageList.length - 1].duration = duration;
}
}
}, this);
};
/**
* アクティブメッセージ用のコメント解析
*
* @param {Object} page 解析対象のイベントページ
*/
Game_Event.prototype.parseCommentForMapActiveMessage = function (page) {
function isComment(command) {
return command && (command.code === 108 || command.code === 408);
}
// 注釈以外に達するまで解析
var commandIndex = 0;
var command = page.list[commandIndex];
var mergedComment = ""; // コメントを結合した文字列
var commentUnit = "";
var commentUnits = []; // 解析単位ごとに結合した文字列のリスト
var inMessage = false;
while (isComment(command)) {
if (mergedComment.length > 0) {
mergedComment += "\n";
}
var commentText = command.parameters[0];
mergedComment += commentText;
if (inMessage) {
if (commentUnit.length > 0) {
commentUnit += "\n";
}
commentUnit += commentText;
if (Const.regex.endMessage.test(commentText)) {
commentUnits.push(commentUnit);
commentUnit = "";
inMessage = false;
}
} else {
if (Const.regex.beginMessage.test(commentText)) {
commentUnit = commentText;
inMessage = true;
} else {
commentUnits.push(commentText);
}
}
command = page.list[++commandIndex];
}
if (inMessage) {
commentUnits.push(commentUnit);
}
return {
mergedComment: mergedComment,
commentUnits: commentUnits
};
};
/**
* アクティブメッセージを取得
*
* @return {String} メッセージ
*/
Game_Event.prototype.getMapActiveMessages = function () {
return this._mapActiveMessageList;
};
/**
* アクティブメッセージが存在するか
*
* @return {Boolean} true if exists
*/
Game_Event.prototype.hasMapActiveMessage = function () {
return this._mapActiveMessageList.length !== 0;
};
/**
* アクティブメッセージを表示可能な範囲
*
* @return {Number} タイル単位の表示範囲半径
*/
Game_Event.prototype.getMapActiveMessageRange = function () {
return this._mapActiveMessageRange;
};
/**
* アクティブメッセージをループするか
*
* @return {Boolean} true if needs loop
*/
Game_Event.prototype.needsMapActiveMessageLoop = function () {
return this._needsMapActiveMessageLoop;
};
/**
* アクティブメッセージを表示するフレーム数
*
* @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.prototype);
Sprite_MapActiveMessageBalloon.prototype.constructor = Sprite_MapActiveMessageBalloon;
Sprite_MapActiveMessageBalloon.prototype.initialize = function () {
Sprite.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 + 4, 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 + 1,
frame.srcSize,
vertexSize.width - 2,
vertexSize.height,
newDx + 1,
newDy,
vertexSize.width - 2,
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 - 2, dy, rightWidth + 4, 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, { x: 0, y: 0, width: 64, height: 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();
this.CBR_t = 0;
};
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._message = null;
this._pendingMessages = [];
this._textState = null;
this._event = null;
this._characterSprite = null;
this._targetPageIndex = 0;
this._duration = 0;
this._isHiding = false;
this._balloonPosition = Const.balloonPosition.above;
};
Window_MapActiveMessage.prototype.printDebug = function (message) {
if (Const.debug) {
console.log("[MapActiveMessage] " + this.getId() + ": " + message);
}
};
Window_MapActiveMessage.prototype.show = function () {
Window_Base.prototype.show.call(this);
if (!isNullOrUndefined(this._balloonSprite)) {
this._balloonSprite.show();
}
};
Window_MapActiveMessage.prototype.hide = function () {
// ロールバック処理中はメッセージ無しで呼ばれる
if (this._message) {
this.printDebug("Hide");
}
this._duration = 0;
this._isHiding = true;
Window_Base.prototype.hide.call(this);
if (!isNullOrUndefined(this._balloonSprite)) {
this._balloonSprite.hide();
}
};
/**
* フェードアウト
*/
Window_MapActiveMessage.prototype.fadeOut = function () {
if (this.isFadingOut()) {
return;
}
this.printDebug("Fading out");
this._isHiding = true;
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;
};
/**
* メッセージ ID を取得
*/
Window_MapActiveMessage.prototype.getId = function () {
return this._message.id;
};
/**
* ループ表示するか
*/
Window_MapActiveMessage.prototype.needsLoop = function () {
return this._message.needsLoop;
};
/**
* 強制表示されたか
*/
Window_MapActiveMessage.prototype.isForced = function () {
return this._message.isForced;
};
/**
* フェードイン中か
*/
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.isHiding = function () {
return this._isHiding;
};
/**
* 表示中のイベントと同一イベントか
*/
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} message 表示するメッセージ
* @param {Sprite_Character} sprite 表示対象のキャラクタースプライト
*/
Window_MapActiveMessage.prototype.display = function (message, sprite) {
if (isNullOrUndefined(message)) {
throw "'message' must not be null or undefined.";
}
// 表示のキャンセル
function rollback() {
this.initMembers();
this.hide();
}
if (message.messages.length <= 0 || isNullOrUndefined(message.event)) {
rollback.call(this);
return;
}
this._message = message;
this._event = message.event;
this._characterSprite = sprite;
if (!this.isEventInScreen()) {
rollback.call(this);
return;
}
this._targetPageIndex = this._event.pageIndex();
this.initializeMessage();
this.show();
this.printDebug("Display new message for event " + this._event.eventId() + ".");
// 多重表示抑止のため、表示済みフラグを立てる
this._event.setMapActiveMessageShown(true);
};
/**
* メッセージの初期化
*/
Window_MapActiveMessage.prototype.initializeMessage = function () {
this._pendingMessages = this._message.messages.slice();
this.displayNextMessage();
};
/**
* 次のメッセージを表示
*/
Window_MapActiveMessage.prototype.displayNextMessage = function () {
var message = this._pendingMessages.shift();
if (isNullOrUndefined(message)) {
return false;
}
this._textState = {
index: 0,
text: this.convertEscapeCharacters(message.text)
};
this._allTextWidth = 0;
this._initialDisplayDuration = message.duration;
this._duration = this._initialDisplayDuration;
this.newPage(this._textState);
this.updatePosition();
this.updateOpacity();
this.refreshBalloon();
/// CBRここでテキスト入力
this.drawTextEx(this._textState.text, 10, 10, this._textState.width);
return 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);
//CBR heightはここ
this.contents.fontSize = 22;
var lines = textState.text.split("\n");
this._allTextHeight = this.calcTextHeight(textState, false) * lines.length + 20;
textState.width = 0;
for (var i = 0; i < lines.length; i++) {
var w = this.textWidth(lines[i]);
if (w && textState.width < w) {
textState.width = w;
}
}
//this._allTextWidth = 598;
//textState.width = this.textWidth(textState.text)
this.updateMessage();
// コンテンツを一時領域から正式に反映
this.createContents();
this.contents.blt(
Window_MapActiveMessage.tempMessageBuffer,
0,
0,
this._allTextWidth,
this._allTextHeight,
0,
0,
this._allTextWidth,
this._allTextHeight
);
};
var Window_MapActiveMessage_update = Window_MapActiveMessage.prototype.update;
Window_MapActiveMessage.prototype.update = function () {
Window_MapActiveMessage_update.call(this);
this.CBR_t++;
};
/**
* メッセージの表示位置を設定
*/
Window_MapActiveMessage.prototype.updatePosition = function () {
if (isNullOrUndefined(this._event)) {
return;
}
// 画面外に出る場合は消去
if (!this.isEventInScreen()) {
this.hide();
return;
}
// 吹き出しの枠ぶんのマージン
var margin = Const.balloonFrameInfo.size - 24;
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 beforePosit = this.getBalloonPosition();
this._balloonPosition = Const.balloonPosition.above;
// 画面左右にははみ出させない
//CBRまだよくわかんないから発生した時にやる
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;
}
// 画面下側にはみ出る場合は上に表示
else 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();
}
//##################### CBR、位置が違う場合は再描写
if (beforePosit != this._balloonPosition) {
this.refreshBalloon();
}
};
/**
* ウィンドウのサイズを更新
*/
Window_MapActiveMessage.prototype.updateWindowSize = function () {
var offset = $gameSystem.windowPadding() * 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();
}
};
/**
* プレイヤーと距離が離れていたら消去する
*
* @return {Boolean} true if hidden
*/
Window_MapActiveMessage.prototype.hideFarMessage = function () {
// 表示範囲外に出た場合は消す
var distance = $gamePlayer.calcDistanceForMapActiveMessage(this._event);
if (distance > this._event.getMapActiveMessageRange()) {
this.fadeOut();
return true;
}
return false;
};
/**
* プレイヤーとの距離を確認
*/
Window_MapActiveMessage.prototype.checkPlayerDistance = function () {
// 強制表示 or 消去中は距離判定しない
if (this.isForced() || this._duration <= Params.fadeFrameCount) {
return;
}
this.hideFarMessage();
};
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()) {
if (this.displayNextMessage()) {
this.printDebug("Display next message.");
} else if (this.needsLoop() && !this.isHiding()) {
// 距離が離れていたらループしない
if (!this.hideFarMessage()) {
//this.printDebug('Loop message.');
//this.initializeMessage();
}
} else {
// 表示が終了したら初期化
this.printDebug("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.width+20);
if (this._textState.width) {
this._allTextWidth = this._textState.width + 20;
}
}
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.x = x;
//this._activeMessageWindowLayer.y = y;
//this._activeMessageWindowLayer.width = width;
//this._activeMessageWindowLayer.height = height;
//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();
const ww = Graphics.boxWidth;
const wh = this.calcWindowHeight(4, false) + 8;
const wx = (Graphics.boxWidth - ww) / 2;
const wy = 0;
const rect = new Rectangle(wx, wy, ww, wh);
var window = new Window_MapActiveMessage(rect);
window.setBalloonSprite(balloon);
window.display(message, character);
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;
}
};
})();