magical-girls-runa-and-nanami/js/plugins/TextPicture.js
2026-03-04 23:57:24 -06:00

138 lines
4.8 KiB
JavaScript

//=============================================================================
// RPG Maker MZ - Text Picture
//=============================================================================
/*:
* @target MZ
* @plugindesc Displays text as a picture.
* @author Yoji Ojima
*
* @help TextPicture.js
*
* This plugin provides a command to show text as a picture.
*
* Use it in the following procedure.
* 1. Call the plugin command "Set Text Picture".
* 2. Execute "Show Picture" without specifying an image.
*
* @command set
* @text Set Text Picture
* @desc Sets text to display as a picture.
* After this, execute "Show Picture" without specifying an image.
*
* @arg text
* @type multiline_string
* @text Text
* @desc Text to display as a picture.
* Control characters are allowed.
*/
/*:ja
* @target MZ
* @plugindesc テキストをピクチャとして表示します。
* @author Yoji Ojima
*
* @help TextPicture.js
*
* このプラグインは、テキストをピクチャとして表示するコマンドを提供します。
*
* 次の手順で使用してください。
* 1. プラグインコマンド「テキストピクチャの設定」を呼び出します。
* 2. 画像を指定せずに「ピクチャの表示」を実行します。
*
* @command set
* @text テキストピクチャの設定
* @desc ピクチャとして表示するテキストを設定します。
* この後、画像を指定せずに「ピクチャの表示」を実行してください。
*
* @arg text
* @type multiline_string
* @text テキスト
* @desc ピクチャとして表示するテキストです。
* 制御文字が使用可能です。
*/
(() => {
const pluginName = "TextPicture";
let textPictureText = "";
function breakLigatures(text) {
// Insert zero-width non-joiner (U+200C) to prevent missing ligature glyphs (fi, fl, ff, etc.)
return text.replace(/f([filt])/g, "f\u200C$1");
}
PluginManager.registerCommand(pluginName, "set", args => {
textPictureText = breakLigatures(String(args.text));
});
const _Game_Picture_show = Game_Picture.prototype.show;
Game_Picture.prototype.show = function() {
_Game_Picture_show.apply(this, arguments);
if (this._name === "" && textPictureText) {
this.mzkp_text = textPictureText;
this.mzkp_textChanged = true;
textPictureText = "";
}
};
const _Sprite_Picture_destroy = Sprite_Picture.prototype.destroy;
Sprite_Picture.prototype.destroy = function() {
destroyTextPictureBitmap(this.bitmap);
_Sprite_Picture_destroy.apply(this, arguments);
};
const _Sprite_Picture_updateBitmap = Sprite_Picture.prototype.updateBitmap;
Sprite_Picture.prototype.updateBitmap = function() {
_Sprite_Picture_updateBitmap.apply(this, arguments);
if (this.visible && this._pictureName === "") {
const picture = this.picture();
const text = picture ? picture.mzkp_text || "" : "";
const textChanged = picture && picture.mzkp_textChanged;
if (this.mzkp_text !== text || textChanged) {
this.mzkp_text = text;
destroyTextPictureBitmap(this.bitmap);
this.bitmap = createTextPictureBitmap(text);
picture.mzkp_textChanged = false;
}
} else {
this.mzkp_text = "";
}
};
function createTextPictureBitmap(text) {
const tempWindow = new Window_Base(new Rectangle());
tempWindow.resetFontSettings = function() {
this.contents.fontFace = $gameSystem.mainFontFace();
this.contents.fontSize = 22;
this.resetTextColor();
};
const size = tempWindow.textSizeEx(text);
const pad = 4; // extra pixels on each side to prevent outline clipping
tempWindow.padding = 0;
tempWindow.move(0, 0, size.width + pad * 2, size.height + pad * 2);
tempWindow.createContents();
tempWindow.drawTextEx(text, pad, pad, 0);
const bitmap = tempWindow.contents;
tempWindow.contents = null;
tempWindow.destroy();
bitmap.mzkp_isTextPicture = true;
return bitmap;
}
function destroyTextPictureBitmap(bitmap) {
if (bitmap && bitmap.mzkp_isTextPicture) {
bitmap.destroy();
}
}
})();
// Global ligature fix — prevents missing glyph blanks (fi, fl, ff, ft, etc.) across all text rendering.
(function() {
const _Bitmap_drawText = Bitmap.prototype.drawText;
Bitmap.prototype.drawText = function(text, x, y, maxWidth, lineHeight, align) {
if (typeof text === "string") {
text = text.replace(/f([filt])/g, "f\u200C$1");
}
_Bitmap_drawText.call(this, text, x, y, maxWidth, lineHeight, align);
};
})();