/*:
 * @target MZ
 * @plugindesc (v1.0) キャラクターの下に丸い影を描画します。タイルに合わせた位置調整・サイズ・不透明度をプラグインパラメータで設定できます。
 * @author WXY
 * 
 * @param ShadowWidth
 * @text 影の幅
 * @desc 影の幅（ピクセル）
 * @default 10
 * 
 * @param ShadowHeight
 * @text 影の高さ
 * @desc 影の高さ（ピクセル）
 * @default 8
 * 
 * @param Opacity
 * @text 不透明度
 * @desc 影の不透明度（0〜255）
 * @default 160
 * 
 * @param YOffset
 * @text Yオフセット
 * @desc キャラクターの中心から影をどれだけ下にずらすか（ピクセル）
 * @default 5
 * 
 * @param ScaleWithDistance
 * @text 距離で拡大縮小
 * @desc Y座標が小さく（ジャンプ等）なるときに影を小さくする（true/false）
 * @type boolean
 * @default true
 * 
 * @help
 * mz_character_shadow.js
 * 
 * 使い方:
 * 1. 作成したこのプラグインファイルをプロジェクトの
 *    js/plugins フォルダに置き、プラグインマネージャーで有効化してください。
 * 2. パラメータで影のサイズやオフセット、不透明度を調整できます。
 * 
 * このプラグインはマップ上のキャラクターごとに楕円のスプライトを生成し、
 * 親コンテナ（キャラクタースプライトの親）に背面として挿入します。
 * キャラクターの移動・表示状態に合わせて影を自動更新します。
 */

(() => {
    const pluginName = "mz_character_shadow";
    const params = PluginManager.parameters(pluginName) || {};

    const SHADOW_WIDTH = Number(params.ShadowWidth || 48);
    const SHADOW_HEIGHT = Number(params.ShadowHeight || 16);
    const SHADOW_OPACITY = Number(params.Opacity || 160);
    const SHADOW_YOFFSET = Number(params.YOffset || 12);
    const SCALE_WITH_DISTANCE = (params.ScaleWithDistance === 'true');

// Bitmap に楕円を描くユーティリティ
function createShadowBitmap(width, height) {
    const bmp = new Bitmap(width, height);
    const ctx = bmp.context;
    ctx.save();
    ctx.clearRect(0, 0, width, height);
    ctx.fillStyle = "black";
    ctx.globalAlpha = 1.0;
    ctx.beginPath();
    // ellipse がある環境なら ellipse、なければ scale+arc で代用
    if (ctx.ellipse) {
        ctx.ellipse(width / 2, height / 2, width / 2, height / 2, 0, 0, Math.PI * 2);
    } else {
        ctx.translate(width / 2, height / 2);
        ctx.scale(width / 2, height / 2);
        ctx.arc(0, 0, 1, 0, Math.PI * 2);
    }
    ctx.fill();
    ctx.restore();
    bmp._baseTexture.update();
    return bmp;
}

    // Sprite_Character に影スプライトを作るフック
    const _SC_initialize = Sprite_Character.prototype.initialize;
    Sprite_Character.prototype.initialize = function(character) {
        _SC_initialize.call(this, character);
        this._shadowSprite = null;
        this._shadowCreated = false;
    };

    // update の中で親が揃ったら影を生成して親コンテナの後ろに入れる
    const _SC_update = Sprite_Character.prototype.update;
    Sprite_Character.prototype.update = function() {
        _SC_update.call(this);
        if (!this._shadowCreated && this.parent) {
            this._createShadow();
            this._shadowCreated = true;
        }
        if (this._shadowSprite) {
            this._updateShadow();
        }
    };

    Sprite_Character.prototype._createShadow = function() {
        const bmp = createShadowBitmap(SHADOW_WIDTH, SHADOW_HEIGHT);
        const spr = new Sprite(bmp);
        spr.anchor.x = 0.5;
        spr.anchor.y = 0.5;
        spr.opacity = SHADOW_OPACITY; // 0-255
        spr.blendMode = 0; // normal
        spr.scale.x = 1.0;
        spr.scale.y = 1.0;
        spr.z = this.z - 1; // 可能な限りキャラクターより背面に

        // 初期位置を設定
        spr.x = this.x;
        spr.y = this.y + SHADOW_YOFFSET;

        // 親がいる場合、親の先頭（背景寄り）に挿入してキャラクタ類の背面にする。
        // parent.addChildAt は既存の描画順を崩すことがありますが、ほとんどのケースで期待通り動きます。
        try {
            // なるべくキャラクター自身よりも後ろ（=背面）に配置
            const p = this.parent;
            if (p) {
                // 親の先頭に追加して背面に
                p.addChildAt(spr, 0);
            } else {
                // 親がないなら自分の子に入れておく
                this.addChildAt(spr, 0);
            }
        } catch (e) {
            // 失敗したら自分の子に入れる
            this.addChildAt(spr, 0);
        }

        this._shadowSprite = spr;
    };

    Sprite_Character.prototype._updateShadow = function() {
        const s = this._shadowSprite;
        if (!s || !this.parent) return;

        // 影は常にキャラクターの下に表示
        s.x = this.x;
        s.y = this.y + SHADOW_YOFFSET;

        // キャラクターの表示・透明度を反映
        s.visible = this.visible;
        s.opacity = Math.min(255, Math.max(0, Math.round((this.opacity / 255) * SHADOW_OPACITY)));

        // 距離（y座標）で影を小さくする（ジャンプ等に追随）
        if (SCALE_WITH_DISTANCE) {
            // マップ上での仮想的な "高さ" を作る（標準タイル高さは48、ただの目安）
            const baseY = this._character && this._character.screenY ? this._character.screenY() : this.y;
            // 高さが小さい（上にいる）ほど縮小させる。
            // clamp factor between 0.6 and 1.0
            const factor = (baseY / (Graphics.height || 600));
            const scale = 0.6 + Math.max(0, Math.min(1, factor));
            s.scale.x = scale;
            s.scale.y = scale;
        }

        // もしキャラクターが移動して親コンテナより手前に来る場合、Z順の調整が必要なケースがある。
        // ここでは目立つ問題が出たらプラグインパラメータで調整してください。
    };

    // スプライトが破棄されるときは影も削除
    const _SC_terminate = Sprite_Character.prototype.terminate;
    if (_SC_terminate) {
        Sprite_Character.prototype.terminate = function() {
            if (this._shadowSprite && this._shadowSprite.parent) {
                this._shadowSprite.parent.removeChild(this._shadowSprite);
            }
            _SC_terminate.call(this);
        };
    }

})();
