349 lines
No EOL
12 KiB
JavaScript
349 lines
No EOL
12 KiB
JavaScript
/*:
|
||
* @target MZ
|
||
* @plugindesc プレイヤー頭上イベント検出 → ピクチャ99 & タイトル表示 v2.1 ★スイッチ9で有効化★
|
||
* @author IvI
|
||
*
|
||
* ▼ 基本設定 --------------------------------------------------------------
|
||
*
|
||
* @param NotetagKey
|
||
* @text タグキー
|
||
* @desc ページ注釈に書く <●●:タイトル,ID> の “●●” 部分
|
||
* @default ShowPic
|
||
*
|
||
* @param PictureX
|
||
* @text ピクチャ X 座標
|
||
* @type number
|
||
* @default 920
|
||
*
|
||
* @param PictureY
|
||
* @text ピクチャ Y 座標
|
||
* @type number
|
||
* @default 0
|
||
*
|
||
* @param PictureScale
|
||
* @text ピクチャ拡大率(%)
|
||
* @type number
|
||
* @default 100
|
||
*
|
||
* @param TitleX
|
||
* @text タイトル X 座標
|
||
* @type number
|
||
* @default 940
|
||
*
|
||
* @param TitleY
|
||
* @text タイトル Y 座標
|
||
* @type number
|
||
* @default 20
|
||
*
|
||
* @param TitleFontSize
|
||
* @text タイトルフォントサイズ
|
||
* @type number
|
||
* @default 24
|
||
*
|
||
* ▼ 背景表示タイプ --------------------------------------------------------
|
||
*
|
||
* @param BackStyle
|
||
* @text 背景タイプ
|
||
* @desc 0: なし / 1: ウィンドウ / 2: 暗幕
|
||
* @type select
|
||
* @option なし
|
||
* @value 0
|
||
* @option ウィンドウ
|
||
* @value 1
|
||
* @option 暗幕
|
||
* @value 2
|
||
* @default 1
|
||
*
|
||
* @param BackOrigin
|
||
* @text 原点(ウィンドウ時のみ)
|
||
* @desc 0: 左上 / 1: 中央 (BackX/Y が中心座標)
|
||
* @type select
|
||
* @option 左上
|
||
* @value 0
|
||
* @option 中央
|
||
* @value 1
|
||
* @default 0
|
||
* @parent BackStyle
|
||
*
|
||
* @param BackX
|
||
* @text 背景X(ウィンドウ)
|
||
* @type number
|
||
* @default 900
|
||
* @parent BackStyle
|
||
*
|
||
* @param BackY
|
||
* @text 背景Y(ウィンドウ)
|
||
* @type number
|
||
* @default 0
|
||
* @parent BackStyle
|
||
*
|
||
* @param BackW
|
||
* @text 背景幅(ウィンドウ)
|
||
* @type number
|
||
* @default 200
|
||
* @parent BackStyle
|
||
*
|
||
* @param BackH
|
||
* @text 背景高(ウィンドウ)
|
||
* @type number
|
||
* @default 96
|
||
* @parent BackStyle
|
||
*
|
||
* @param BackOpacity
|
||
* @text 背景不透明度
|
||
* @type number
|
||
* @max 255
|
||
* @default 192
|
||
*
|
||
* ▼ ピクチャ ID → ファイル名対応表 ----------------------------------------
|
||
*
|
||
* @param PictureList
|
||
* @text ピクチャ対応表
|
||
* @type struct<PicItem>[]
|
||
* @default []
|
||
* * ▼ 一時非表示設定 --------------------------------------------------------
|
||
* @param TempHideSwitchId
|
||
* @text 一時非表示スイッチ番号
|
||
* @desc このスイッチがONの時、表示を一時的に隠します。0を指定すると無効になります。
|
||
* @type switch
|
||
* @default 0
|
||
*/
|
||
/*~struct~PicItem:
|
||
* @param id
|
||
* @text PictureID
|
||
* @type number
|
||
* @default 1
|
||
*
|
||
* @param file
|
||
* @text 画像ファイル名(拡張子不要)
|
||
* @type file
|
||
* @dir img/pictures
|
||
* @default
|
||
*/
|
||
|
||
(() => {
|
||
"use strict";
|
||
|
||
/* ------------------------------------------------------------------- */
|
||
/* パラメータ処理 */
|
||
/* ------------------------------------------------------------------- */
|
||
const PLUGIN_NAME = "EventPictureDisplay";
|
||
const PARAMS = PluginManager.parameters(PLUGIN_NAME);
|
||
|
||
// 有効化スイッチ番号(ここを書き換えれば好きなスイッチに変更可)
|
||
const ENABLE_SW = 9;
|
||
|
||
// ★★★ 追加ここから ★★★
|
||
// 一時非表示スイッチ番号
|
||
const TEMP_HIDE_SW = Number(PARAMS["TempHideSwitchId"] || 0);
|
||
// ★★★ 追加ここまで ★★★
|
||
|
||
const TAG_KEY = String(PARAMS["NotetagKey"] || "ShowPic");
|
||
const PIC_X = Number(PARAMS["PictureX"] || 920);
|
||
const PIC_Y = Number(PARAMS["PictureY"] || 0);
|
||
const PIC_SCALE = Number(PARAMS["PictureScale"] || 100);
|
||
const TITLE_X = Number(PARAMS["TitleX"] || 940);
|
||
const TITLE_Y = Number(PARAMS["TitleY"] || 20);
|
||
const TITLE_SIZE = Number(PARAMS["TitleFontSize"] || 24);
|
||
|
||
const BACK_STYLE = Number(PARAMS["BackStyle"] || 1); // 0:none 1:window 2:dim
|
||
const BACK_ORIGIN = Number(PARAMS["BackOrigin"] || 0);
|
||
const BACK_X = Number(PARAMS["BackX"] || 900);
|
||
const BACK_Y = Number(PARAMS["BackY"] || 0);
|
||
const BACK_W = Number(PARAMS["BackW"] || 200);
|
||
const BACK_H = Number(PARAMS["BackH"] || 96);
|
||
const BACK_OPA = Number(PARAMS["BackOpacity"] || 192);
|
||
|
||
const PIC_LIST = JSON.parse(PARAMS["PictureList"] || "[]").map(s => JSON.parse(s));
|
||
|
||
const picNameById = id => {
|
||
const item = PIC_LIST.find(e => Number(e.id) === id);
|
||
return item ? item.file : "";
|
||
};
|
||
|
||
/* ------------------------------------------------------------------- */
|
||
/* ユーティリティ */
|
||
/* ------------------------------------------------------------------- */
|
||
/** 注釈コメントからタグを抽出
|
||
* @return { title: string, picId: number, xOffset: number } | null */
|
||
// ▼▼▼ 変更点1 ▼▼▼
|
||
function extractTag(page) {
|
||
if (!page) return null;
|
||
// オフセット値(省略可能、マイナス値も許可)を取得できるように正規表現を変更
|
||
const re = new RegExp(`<${TAG_KEY}\\s*:\\s*([^,]+?)\\s*,\\s*(\\d+)(?:\\s*,\\s*(-?\\d+))?>`, "i");
|
||
let buf = "";
|
||
for (const cmd of page.list) {
|
||
if (cmd.code === 108) {
|
||
buf = cmd.parameters[0] + "\n";
|
||
} else if (cmd.code === 408) {
|
||
buf += cmd.parameters[0] + "\n";
|
||
} else {
|
||
const m = buf.match(re);
|
||
// m[3]がオフセット値。なければ0とする
|
||
if (m) return { title: m[1].trim(), picId: Number(m[2]), xOffset: Number(m[3] || 0) };
|
||
buf = "";
|
||
}
|
||
}
|
||
const m = buf.match(re);
|
||
return m ? { title: m[1].trim(), picId: Number(m[2]), xOffset: Number(m[3] || 0) } : null;
|
||
}
|
||
// ▲▲▲ 変更点1 ▲▲▲
|
||
|
||
/* ------------------------------------------------------------------- */
|
||
/* Scene_Map 拡張 */
|
||
/* ------------------------------------------------------------------- */
|
||
const _Scene_Map_create = Scene_Map.prototype.create;
|
||
Scene_Map.prototype.create = function() {
|
||
_Scene_Map_create.call(this);
|
||
|
||
// タイトルスプライト --------------------------------------------------
|
||
const bmp = new Bitmap(400, 64);
|
||
bmp.fontSize = TITLE_SIZE;
|
||
bmp.outlineWidth = 4;
|
||
bmp.outlineColor = "rgba(0,0,0,0.6)";
|
||
bmp.textColor = "#ffffff";
|
||
|
||
this._epdTitleSprite = new Sprite(bmp);
|
||
this._epdTitleSprite.anchor.x = 0;
|
||
this._epdTitleSprite.anchor.y = 0;
|
||
this._epdTitleSprite.x = TITLE_X;
|
||
this._epdTitleSprite.y = TITLE_Y;
|
||
this._epdTitleSprite.visible = false;
|
||
|
||
// 背景オブジェクト ----------------------------------------------------
|
||
this._epdBackObj = null;
|
||
if (BACK_STYLE === 1) {
|
||
// Window_Base
|
||
let wx = BACK_X, wy = BACK_Y;
|
||
if (BACK_ORIGIN === 1) { wx -= Math.round(BACK_W/2); wy -= Math.round(BACK_H/2); }
|
||
const rect = new Rectangle(wx, wy, BACK_W, BACK_H);
|
||
const win = new Window_Base(rect);
|
||
win.opacity = BACK_OPA;
|
||
this._epdBackObj = win;
|
||
} else if (BACK_STYLE === 2) {
|
||
let dx = BACK_X, dy = BACK_Y;
|
||
if (BACK_ORIGIN === 1) { dx -= Math.round(BACK_W/2); dy -= Math.round(BACK_H/2); }
|
||
const bmpDim = new Bitmap(BACK_W, BACK_H);
|
||
bmpDim.fillRect(0, 0, BACK_W, BACK_H, "#000000");
|
||
const dim = new Sprite(bmpDim);
|
||
dim.x = dx;
|
||
dim.y = dy;
|
||
dim.opacity = BACK_OPA;
|
||
this._epdBackObj = dim;
|
||
}
|
||
if (this._epdBackObj) {
|
||
if (this._spriteset && this._spriteset._pictureContainer) {
|
||
this._spriteset._pictureContainer.addChildAt(this._epdBackObj, 0);
|
||
} else {
|
||
// まだpictureContainerがない時点なので、仮配置 → 後で付け替える
|
||
this.addChild(this._epdBackObj);
|
||
this._epdBackObj._needReattach = true;
|
||
}
|
||
this._epdBackObj.visible = false;
|
||
}
|
||
|
||
this._epdLastPicName = ""; // 最後に表示したピクチャ名
|
||
};
|
||
|
||
const _Scene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;
|
||
Scene_Map.prototype.createAllWindows = function() {
|
||
_Scene_Map_createAllWindows.call(this);
|
||
// タイトルスプライトは windowLayer より上に置く
|
||
if (this._windowLayer) this._windowLayer.addChild(this._epdTitleSprite);
|
||
};
|
||
|
||
const _Scene_Map_update = Scene_Map.prototype.update;
|
||
Scene_Map.prototype.update = function() {
|
||
// pictureContainerが準備できたら背景を付け替え
|
||
if (this._epdBackObj && this._epdBackObj._needReattach && this._spriteset && this._spriteset._pictureContainer) {
|
||
this.removeChild(this._epdBackObj);
|
||
this._spriteset._pictureContainer.addChildAt(this._epdBackObj, 0);
|
||
delete this._epdBackObj._needReattach;
|
||
}
|
||
|
||
_Scene_Map_update.call(this);
|
||
this._epdUpdate();
|
||
};
|
||
|
||
/* ------------------------------------------------------------------- */
|
||
/* メイン表示更新 */
|
||
/* ------------------------------------------------------------------- */
|
||
// ▼▼▼ 変更点2 ▼▼▼
|
||
Scene_Map.prototype._epdUpdate = function() {
|
||
// スイッチがOFFなら即消去&待機
|
||
if (!$gameSwitches.value(ENABLE_SW)) {
|
||
this._epdHideAll();
|
||
return;
|
||
}
|
||
|
||
// 一時非表示スイッチがONなら消去して待機
|
||
if (TEMP_HIDE_SW > 0 && $gameSwitches.value(TEMP_HIDE_SW)) {
|
||
this._epdHideAll();
|
||
return;
|
||
}
|
||
|
||
// プレイヤー頭上のイベントを取得
|
||
const playerX = $gamePlayer.x;
|
||
const playerY = $gamePlayer.y;
|
||
const evts = ($gameMap.eventsXyUnitNt ? $gameMap.eventsXyUnitNt(playerX, playerY - 1)
|
||
: $gameMap.eventsXy(playerX, playerY - 1));
|
||
const evt = evts[0];
|
||
|
||
if (evt && evt.page()) {
|
||
const tag = extractTag(evt.page());
|
||
if (tag) {
|
||
// xOffset を受け取る
|
||
const { title, picId, xOffset } = tag;
|
||
const picName = picNameById(picId);
|
||
if (picName) {
|
||
// _epdShow に xOffset を渡す
|
||
this._epdShow(picName, title, xOffset);
|
||
return; // 表示したので抜ける
|
||
}
|
||
}
|
||
}
|
||
// 表示条件に合わなければ隠す
|
||
this._epdHideAll();
|
||
};
|
||
// ▲▲▲ 変更点2 ▲▲▲
|
||
|
||
/* ------------------------------------------------------------------- */
|
||
/* 表示 / 非表示 */
|
||
/* ------------------------------------------------------------------- */
|
||
/** @param {string} picName 画像ファイル名
|
||
* @param {string} title タイトル文字列
|
||
* @param {number} xOffset X座標のオフセット */
|
||
// ▼▼▼ 変更点3 ▼▼▼
|
||
Scene_Map.prototype._epdShow = function(picName, title, xOffset) {
|
||
// ピクチャ-------------------------------------------------------------
|
||
if (this._epdLastPicName !== picName) {
|
||
// 別画像なら描画し直し
|
||
const origin = 0; // 左上固定
|
||
// X座標にオフセット値を加算
|
||
$gameScreen.showPicture(99, picName, origin, PIC_X + xOffset, PIC_Y, PIC_SCALE, PIC_SCALE, 255, 0);
|
||
this._epdLastPicName = picName;
|
||
}
|
||
|
||
// タイトルテキスト ----------------------------------------------------
|
||
const bmp = this._epdTitleSprite.bitmap;
|
||
bmp.clear();
|
||
bmp.drawText(title, 0, 0, bmp.width, bmp.height, "left");
|
||
this._epdTitleSprite.visible = true;
|
||
|
||
// 背景オブジェクト ----------------------------------------------------
|
||
if (this._epdBackObj) {
|
||
this._epdBackObj.visible = true;
|
||
}
|
||
};
|
||
// ▲▲▲ 変更点3 ▲▲▲
|
||
|
||
Scene_Map.prototype._epdHideAll = function() {
|
||
if (this._epdLastPicName) {
|
||
if ($gameScreen.picture(99)) $gameScreen.erasePicture(99);
|
||
this._epdLastPicName = "";
|
||
}
|
||
this._epdTitleSprite.visible = false;
|
||
if (this._epdBackObj) this._epdBackObj.visible = false;
|
||
};
|
||
|
||
})(); |