1999 lines
55 KiB
JavaScript
1999 lines
55 KiB
JavaScript
//=============================================================================
|
||
// MPP_EncounterEffect.js
|
||
//=============================================================================
|
||
// Copyright (c) 2021 - 2024 Mokusei Penguin
|
||
// Released under the MIT license
|
||
// http://opensource.org/licenses/mit-license.php
|
||
//=============================================================================
|
||
|
||
/*:
|
||
* @target MZ
|
||
* @plugindesc Change the effect at the time of encounter to a special effect.
|
||
* @author Mokusei Penguin
|
||
* @url
|
||
*
|
||
* @help [version 4.2.2]
|
||
* - This plugin is for RPG Maker MZ.
|
||
* - Change the effect at the time of encounter to a special effect.
|
||
*
|
||
* ▼ Plugin command
|
||
* - In the item to enter a numerical value,
|
||
* select the text and write 'v[N]' to refer to the variable N.
|
||
*
|
||
* 〇 setType
|
||
* - The effect type will be changed to the specified number
|
||
* only once next.
|
||
*
|
||
* 〇 setCharacter
|
||
* - The effect will be executed around the specified character
|
||
* only once next.
|
||
* - This setting is valid only for effect type 1.
|
||
*
|
||
* 〇 setColor
|
||
* - The effect will change to the specified color only once next.
|
||
*
|
||
* ▼ Effect type
|
||
* -1 : No SE & effects
|
||
* 0 : Default.
|
||
* 1 : Breaks around the character.
|
||
* 2 : The screen splits from the left and scatters to the left.
|
||
* 3 : The entire screen scatters to the front.
|
||
* 4 : The screen splits from the left and scatters to the right.
|
||
* 5 : Divide into squares and expand to the front.
|
||
*
|
||
* ▼ Other
|
||
* - In effect type 1, if the main character is not specified,
|
||
* [Player] will be the center for random encounters,
|
||
* and [This Event] will be the center for
|
||
* the event command [Battle Processing].
|
||
* - Effect type -1 does not allow the map screen to be used as
|
||
* the background.
|
||
*
|
||
* ================================
|
||
* Mail : wood_penguin@yahoo.co.jp (@ is half-width)
|
||
* Blog : http://woodpenguin.blog.fc2.com/
|
||
* License : MIT license
|
||
*
|
||
* @command setType
|
||
* @desc Change the effect type only in the next battle.
|
||
* @arg type
|
||
* @desc
|
||
* @type number
|
||
* @min -1
|
||
* @max 5
|
||
* @default 1
|
||
*
|
||
*
|
||
* @command setCharacter
|
||
* @desc Specify the main character for the next effect.
|
||
* This setting is valid only for effect type 1.
|
||
* @arg character
|
||
* @desc -1:Player, 0:This event, 1-:Event with specified ID
|
||
* @type number
|
||
* @min -1
|
||
* @max 999
|
||
* @default 0
|
||
*
|
||
* @command setColor
|
||
* @desc Specifies the color of the next effect.
|
||
* @arg color
|
||
* @desc R,G,B
|
||
* @default 255,255,255
|
||
*
|
||
*
|
||
* @param Effect Type
|
||
* @desc
|
||
* @type number
|
||
* @min 0
|
||
* @max 5
|
||
* @default 1
|
||
*
|
||
* @param Effect Color
|
||
* @desc R,G,B
|
||
* @default 255,255,255
|
||
*
|
||
*/
|
||
|
||
/*:ja
|
||
* @target MZ
|
||
* @plugindesc エンカウント時の演出を特殊なエフェクトに変更します。
|
||
* @author 木星ペンギン
|
||
* @url
|
||
*
|
||
* @help [version 4.2.2]
|
||
* - このプラグインはRPGツクールMZ用です。
|
||
* - エンカウント時の演出を特殊なエフェクトに変更します。
|
||
*
|
||
* ▼ プラグインコマンド
|
||
* - 数値を入力する項目で、テキストを選択して v[N] と記述することで
|
||
* 変数N番を参照します。
|
||
*
|
||
* 〇 エフェクトタイプ変更
|
||
* - 次の1回のみ、エフェクトタイプが指定した番号に変更されます。
|
||
*
|
||
* 〇 中心キャラ指定
|
||
* - 次の1回のみ、エフェクトが指定したキャラクターを中心に実行されます。
|
||
* - この設定はエフェクトタイプ1のみ有効です。
|
||
*
|
||
* 〇 エフェクト色指定
|
||
* - 次の1回のみ、エフェクトが指定した色に変更されます。
|
||
*
|
||
* ▼ エフェクトタイプ
|
||
* -1: SE & エフェクトなし
|
||
* 0 : デフォルト
|
||
* 1 : キャラクターを中心に割れる
|
||
* 2 : 画面が左から割れて左に散る
|
||
* 3 : 画面全体が前面に飛び散る
|
||
* 4 : 画面が左から割れて右に散る
|
||
* 5 : 四角く区切り、手前に拡大する
|
||
*
|
||
* ▼ その他
|
||
* - エフェクトタイプ 1 にて、中心となるキャラクターを指定していない場合、
|
||
* ランダムエンカウントでは[プレイヤー]、
|
||
* イベントコマンドの【戦闘の処理】では[このイベント]が中心となります。
|
||
* - エフェクトタイプ -1 ではマップ画面を背景にはできません。
|
||
*
|
||
* ================================
|
||
* Mail : wood_penguin@yahoo.co.jp (@は半角)
|
||
* Blog : http://woodpenguin.blog.fc2.com/
|
||
* License : MIT license
|
||
*
|
||
* @command setType
|
||
* @text エフェクトタイプ変更
|
||
* @desc 次に行う戦闘のみエフェクトタイプを変更します。
|
||
* @arg type
|
||
* @text タイプ
|
||
* @desc エフェクトタイプ
|
||
* @type number
|
||
* @min -1
|
||
* @max 5
|
||
* @default 1
|
||
*
|
||
* @command setCharacter
|
||
* @text 中心キャラ指定
|
||
* @desc 次に行うエフェクトで中心となるキャラクターを指定します。
|
||
* この設定はエフェクトタイプ1でのみ有効です。
|
||
* @arg character
|
||
* @text キャラクター
|
||
* @desc 中心となるキャラクター
|
||
* -1:プレイヤー, 0:このイベント, 1~:指定したIDのイベント
|
||
* @type number
|
||
* @min -1
|
||
* @max 999
|
||
* @default 0
|
||
*
|
||
* @command setColor
|
||
* @text エフェクト色指定
|
||
* @desc 次に行うエフェクトの色を指定します。
|
||
* @arg color
|
||
* @text 色(RGB)
|
||
* @desc
|
||
* @default 255,255,255
|
||
*
|
||
*
|
||
* @param Effect Type
|
||
* @text エフェクトタイプ
|
||
* @desc 画面割れエフェクトのタイプ
|
||
* @type number
|
||
* @min 0
|
||
* @max 5
|
||
* @default 1
|
||
*
|
||
* @param Effect Color
|
||
* @text エフェクト色
|
||
* @desc エフェクトのデフォルト色
|
||
* (r,g,bで指定)
|
||
* @default 255,255,255
|
||
*
|
||
*
|
||
*/
|
||
|
||
(() => {
|
||
"use strict";
|
||
|
||
const pluginName = "MPP_EncounterEffect";
|
||
|
||
// Plugin Parameters
|
||
const parameters = PluginManager.parameters(pluginName);
|
||
const param_EffectType = Number(parameters["Effect Type"] || 1);
|
||
const param_DefaultColor = parameters["Effect Color"].split(",").map(Number);
|
||
|
||
const _importedPlugin = (...names) => {
|
||
return names.some((name) => PluginManager._scripts.includes(name));
|
||
};
|
||
const pluginOptions = [
|
||
"MPP_EncounterEffect_Op1",
|
||
"MPP_EncounterEffect_Op2",
|
||
"MPP_EncounterEffect_Op3",
|
||
];
|
||
|
||
// JsExtensions 代替
|
||
const MathExt = (() => {
|
||
// Number.prototype.clamp と違い、下限優先
|
||
const clamp = (x, min, max) => Math.max(Math.min(x, max), min);
|
||
const mod = (x, n) => ((x % n) + n) % n;
|
||
const randomInt = (x) => Math.floor(x * Math.random());
|
||
return { clamp, mod, randomInt };
|
||
})();
|
||
|
||
// 各タイプのパラメータ
|
||
const baseTypeParameters = [
|
||
null,
|
||
|
||
// Type 1
|
||
{
|
||
"Shape Type": "square",
|
||
Center: "character",
|
||
"Break Direction": "none",
|
||
"Break Duration": 45,
|
||
"Interval Duration": 45,
|
||
"Scatter Duration": 0,
|
||
"Move Duration": 60,
|
||
"Split Radial": 8,
|
||
"Radial Random Rate": 90,
|
||
"Circle Radius": 96,
|
||
"Circle Increase Rate": 150,
|
||
"Circle Random Rate": 40,
|
||
},
|
||
|
||
// Type 2
|
||
{
|
||
"Shape Type": "random",
|
||
"Break Direction": "left",
|
||
"Break Duration": 30,
|
||
"Interval Duration": 45,
|
||
"Scatter Direction": "left",
|
||
"Scatter Duration": 24,
|
||
"Move Duration": 60,
|
||
"Split X": 7,
|
||
"X Random Rate": 75,
|
||
"Split Y": 5,
|
||
"Y Random Rate": 75,
|
||
},
|
||
|
||
// Type 3
|
||
{
|
||
"Shape Type": "triangle",
|
||
"Break Direction": "inside",
|
||
"Break Duration": 35,
|
||
"Interval Duration": 40,
|
||
"Scatter Direction": "inside",
|
||
"Scatter Duration": 16,
|
||
"Move Duration": 100,
|
||
"Split X": 8,
|
||
"X Random Rate": 75,
|
||
"Split Y": 6,
|
||
"Y Random Rate": 75,
|
||
Jump: true,
|
||
},
|
||
|
||
// Type 4
|
||
{
|
||
"Shape Type": "random",
|
||
"Break Direction": "left",
|
||
"Break Duration": 30,
|
||
"Interval Duration": 45,
|
||
"Scatter Direction": "right",
|
||
"Scatter Duration": 6,
|
||
"Move Duration": 45,
|
||
"Split X": 9,
|
||
"X Random Rate": 70,
|
||
"Split Y": 7,
|
||
"Y Random Rate": 70,
|
||
},
|
||
|
||
// Type 5
|
||
{
|
||
"Shape Type": "square",
|
||
"Break Direction": "outside",
|
||
"Break Duration": 30,
|
||
"Interval Duration": 45,
|
||
"Scatter Direction": "left",
|
||
"Scatter Duration": 50,
|
||
"Move Duration": 80,
|
||
"Split X": 15,
|
||
"X Random Rate": 0,
|
||
"Split Y": 11,
|
||
"Y Random Rate": 0,
|
||
},
|
||
];
|
||
|
||
// 競合対策
|
||
const __base = (obj, prop) => {
|
||
if (obj.hasOwnProperty(prop)) {
|
||
return obj[prop];
|
||
} else {
|
||
const proto = Object.getPrototypeOf(obj);
|
||
return function () {
|
||
return proto[prop].apply(this, arguments);
|
||
};
|
||
}
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// EncounterEffect
|
||
|
||
function EncounterEffect() {
|
||
throw new Error("This is a static class");
|
||
}
|
||
|
||
if (_importedPlugin(...pluginOptions)) {
|
||
window.EncounterEffect = EncounterEffect;
|
||
}
|
||
|
||
EncounterEffect.centerPoint = new Point();
|
||
EncounterEffect.windowBounds = null;
|
||
|
||
EncounterEffect.clear = function () {
|
||
this._fadeSign = 0;
|
||
this._duration = 0;
|
||
this._opacity = 0;
|
||
this._backOpacity = 0;
|
||
this._fragments = null;
|
||
this._angle = 0;
|
||
this._type = param_EffectType;
|
||
this._character = null;
|
||
this._color = param_DefaultColor;
|
||
this._params = null;
|
||
this.destroy();
|
||
};
|
||
|
||
EncounterEffect.destroy = function () {
|
||
if (this._snapTexture) {
|
||
this._snapTexture.destroy();
|
||
}
|
||
this._snapTexture = null;
|
||
};
|
||
|
||
EncounterEffect.clear();
|
||
|
||
EncounterEffect.params = function () {
|
||
return this._type >= 0 ? baseTypeParameters[this._type] : null;
|
||
};
|
||
|
||
EncounterEffect.type = function () {
|
||
return this._type;
|
||
};
|
||
|
||
EncounterEffect.isValid = function () {
|
||
return !!this.params();
|
||
};
|
||
|
||
EncounterEffect.isRunning = function () {
|
||
return this._fadeSign !== 0;
|
||
};
|
||
|
||
EncounterEffect.isFadeOut = function () {
|
||
return this._fadeSign < 0;
|
||
};
|
||
|
||
EncounterEffect.isFadeIn = function () {
|
||
return this._fadeSign > 0;
|
||
};
|
||
|
||
EncounterEffect.isReady = function () {
|
||
return !this.isRunning() || this._duration < 45;
|
||
};
|
||
|
||
EncounterEffect.isSpritesetVisible = function () {
|
||
return this._opacity < 255 || this._backOpacity < 255;
|
||
};
|
||
|
||
EncounterEffect.currentParam = function (name, def = null) {
|
||
return this._params ? this._params[name] || def : def;
|
||
};
|
||
|
||
EncounterEffect.maxItems = function () {
|
||
return this._fragments ? this._fragments.length : 0;
|
||
};
|
||
|
||
EncounterEffect.fragments = function () {
|
||
return this._fragments || [];
|
||
};
|
||
|
||
EncounterEffect.breakDuration = function () {
|
||
return this.currentParam("Break Duration", 45);
|
||
};
|
||
|
||
EncounterEffect.effectSpeed = function () {
|
||
const d = this.currentParam("Interval Duration", 45);
|
||
return this.breakDuration() + d + 2;
|
||
};
|
||
|
||
EncounterEffect.fadeSpeed = function () {
|
||
return this.currentParam("Move Duration", 60);
|
||
};
|
||
|
||
EncounterEffect.rotation = function () {
|
||
return (this._angle * Math.PI) / 180;
|
||
};
|
||
|
||
EncounterEffect.snapTexture = function () {
|
||
return this._snapTexture;
|
||
};
|
||
|
||
EncounterEffect.setType = function (type) {
|
||
this._type = type;
|
||
};
|
||
|
||
EncounterEffect.opacity = function () {
|
||
return this._opacity;
|
||
};
|
||
|
||
EncounterEffect.backOpacity = function () {
|
||
return this._backOpacity;
|
||
};
|
||
|
||
EncounterEffect.setColor = function (...color) {
|
||
this._color = color;
|
||
};
|
||
|
||
EncounterEffect.color = function () {
|
||
return this._color;
|
||
};
|
||
|
||
EncounterEffect.setCharacter = function (character) {
|
||
this._character = character;
|
||
};
|
||
|
||
EncounterEffect.centerCharacter = function () {
|
||
return (
|
||
this._character || $gameMap.getInterpreterCharacter(0) || $gamePlayer
|
||
);
|
||
};
|
||
|
||
EncounterEffect.setup = function (snapTexture) {
|
||
this.destroy();
|
||
this._snapTexture = snapTexture;
|
||
this._params = this.params();
|
||
this.setupWindowBounds();
|
||
this.setupCenterPoint();
|
||
};
|
||
|
||
EncounterEffect.setupWindowBounds = function () {
|
||
const { width, height } = Graphics;
|
||
this.windowBounds = { minX: 0, maxX: width, minY: 0, maxY: height };
|
||
};
|
||
|
||
EncounterEffect.setupCenterPoint = function () {
|
||
if (this.currentParam("Center") === "character") {
|
||
const { minX, maxX, minY, maxY } = this.windowBounds;
|
||
const character = this.centerCharacter();
|
||
const charX = character.screenX();
|
||
const charY = character.screenY();
|
||
const cx = Math.round(MathExt.clamp(charX, minX, maxX));
|
||
const cy = Math.round(MathExt.clamp(charY - 24, minY, maxY));
|
||
this.centerPoint.set(cx, cy);
|
||
} else {
|
||
const cx = Graphics.width / 2;
|
||
const cy = Graphics.height / 2;
|
||
this.centerPoint.set(cx, cy);
|
||
}
|
||
};
|
||
|
||
EncounterEffect.startFadeOut = function () {
|
||
this._fadeSign = -1;
|
||
this._duration = this.effectSpeed();
|
||
this._opacity = 255;
|
||
this._backOpacity = 255;
|
||
this.createFragments();
|
||
this.sortFragment(this.currentParam("Break Direction"));
|
||
this.startFadeOutAngle();
|
||
};
|
||
|
||
EncounterEffect.startFadeOutAngle = function () {
|
||
this._angle = 0;
|
||
this._targetAngle = 0;
|
||
this._angleEasing = new Easing();
|
||
if (this._type === 5) {
|
||
const speed = this.effectSpeed();
|
||
this._targetAngle = -3;
|
||
this._angleEasing.start("Slow end", speed);
|
||
}
|
||
};
|
||
|
||
EncounterEffect.createFragments = function () {
|
||
this._fragments = [];
|
||
switch (this._type) {
|
||
case 1:
|
||
this.createFragmentsT1();
|
||
break;
|
||
case 2:
|
||
case 3:
|
||
case 4:
|
||
case 5:
|
||
this.createFragmentsT2();
|
||
break;
|
||
}
|
||
};
|
||
|
||
EncounterEffect.createFragmentsT1 = function () {
|
||
const { minX, maxX, minY, maxY } = this.windowBounds;
|
||
const allPoints = this.createAllPointsT1();
|
||
for (let points of this.generatorPointsT1(allPoints)) {
|
||
points = this.cutProtrusionX(points, minX, false);
|
||
points = this.cutProtrusionX(points, maxX, true);
|
||
points = this.cutProtrusionY(points, minY, false);
|
||
points = this.cutProtrusionY(points, maxY, true);
|
||
points = this.removeOuterPoint(points);
|
||
if (points.length >= 3) {
|
||
this.addFragment(this.uniqPoints(points));
|
||
}
|
||
}
|
||
};
|
||
|
||
EncounterEffect.generatorPointsT1 = function* (allPoints) {
|
||
const square = this.currentParam("Shape Type", "square") === "square";
|
||
const max = allPoints[0] ? allPoints[0].length : 1;
|
||
for (const [i, outPoints] of allPoints.entries()) {
|
||
const inPoints = i > 0 ? allPoints[i - 1] : null;
|
||
for (const [j, point2] of outPoints.entries()) {
|
||
const point3 = outPoints[(j + 1) % max];
|
||
if (inPoints) {
|
||
const point4 = inPoints[(j + 1) % max];
|
||
const point1 = inPoints[j];
|
||
if (square) {
|
||
yield [point1, point2, point3, point4];
|
||
} else {
|
||
yield [point1, point2, point4];
|
||
yield [point2, point3, point4];
|
||
}
|
||
} else {
|
||
yield [this.centerPoint, point2, point3];
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
EncounterEffect.cutProtrusionX = function (points, x, cutAbove) {
|
||
const size = points.length;
|
||
for (const p1 of points) {
|
||
const i = points.indexOf(p1);
|
||
const p2 = points[(i + 1) % points.length];
|
||
const p3 = this.verticalIntersectionPoint(p1, p2, x);
|
||
if (p3) {
|
||
points.splice(i + 1, 0, p3);
|
||
}
|
||
}
|
||
if (size < points.length) {
|
||
return points.filter((p) => (cutAbove ? p.x <= x : p.x >= x));
|
||
}
|
||
return points;
|
||
};
|
||
|
||
EncounterEffect.verticalIntersectionPoint = function (point1, point2, x) {
|
||
const x1 = point1.x;
|
||
const y1 = point1.y;
|
||
const x2 = point2.x;
|
||
const y2 = point2.y;
|
||
if ((x1 < x && x2 > x) || (x1 > x && x2 < x)) {
|
||
const y = y1 + Math.round(((y2 - y1) * (x - x1)) / (x2 - x1));
|
||
return new Point(x, y);
|
||
}
|
||
return null;
|
||
};
|
||
|
||
EncounterEffect.cutProtrusionY = function (points, y, cutAbove) {
|
||
const size = points.length;
|
||
for (const p1 of points) {
|
||
const i = points.indexOf(p1);
|
||
const p2 = points[(i + 1) % points.length];
|
||
const p3 = this.horizontalIntersectionPoint(p1, p2, y);
|
||
if (p3) {
|
||
points.splice(i + 1, 0, p3);
|
||
}
|
||
}
|
||
if (size < points.length) {
|
||
return points.filter((p) => (cutAbove ? p.y <= y : p.y >= y));
|
||
}
|
||
return points;
|
||
};
|
||
|
||
EncounterEffect.horizontalIntersectionPoint = function (point1, point2, y) {
|
||
const x1 = point1.x;
|
||
const y1 = point1.y;
|
||
const x2 = point2.x;
|
||
const y2 = point2.y;
|
||
if ((y1 < y && y2 > y) || (y1 > y && y2 < y)) {
|
||
const x = x1 + Math.round(((x2 - x1) * (y - y1)) / (y2 - y1));
|
||
return new Point(x, y);
|
||
}
|
||
return null;
|
||
};
|
||
|
||
EncounterEffect.removeOuterPoint = function (points) {
|
||
const { minX, maxX, minY, maxY } = this.windowBounds;
|
||
return points.filter(
|
||
({ x, y }) => x >= minX && x <= maxX && y >= minY && y <= maxY
|
||
);
|
||
};
|
||
|
||
EncounterEffect.uniqPoints = function (points) {
|
||
return points.filter(
|
||
(p1, i) => points.findIndex((p2) => p2.equals(p1)) === i
|
||
);
|
||
};
|
||
|
||
EncounterEffect.createAllPointsT1 = function () {
|
||
const {
|
||
"Shape Type": sType = "square",
|
||
"Split Radial": splitX = 8,
|
||
"Circle Radius": baseRadius = 96,
|
||
"Circle Increase Rate": circleRate = 150,
|
||
} = this._params;
|
||
const maxRadius = this.maxRadius();
|
||
|
||
const allPoints = [];
|
||
let startAngle = 360 * Math.random();
|
||
let innerR = 0;
|
||
let currentR = baseRadius;
|
||
for (let i = 0; i < 8; i++) {
|
||
if (sType === "triangle") startAngle += 180 / splitX;
|
||
if (i === 7) innerR = 1000000;
|
||
allPoints.push(this.createRoundPoints(startAngle, innerR, currentR));
|
||
if (innerR > maxRadius) break;
|
||
innerR += currentR;
|
||
currentR *= circleRate / 100;
|
||
}
|
||
return allPoints;
|
||
};
|
||
|
||
EncounterEffect.createRoundPoints = function (startAngle, innerR, currentR) {
|
||
const {
|
||
"Split Radial": splitX = 8,
|
||
"Radial Random Rate": rRate = 90,
|
||
"Circle Random Rate": cRate = 40,
|
||
} = this._params;
|
||
const baseAngle = 360 / splitX;
|
||
|
||
const randomAngle = (n) => {
|
||
return (
|
||
(startAngle +
|
||
baseAngle * n +
|
||
(baseAngle * rRate * Math.random()) / 100) %
|
||
360
|
||
);
|
||
};
|
||
const randomRadius = () => {
|
||
return innerR + currentR * (1 - (cRate * (0.75 - Math.random())) / 100);
|
||
};
|
||
|
||
return [...Array(splitX).keys()].map((i) =>
|
||
this.calculatePoint(randomAngle(i), randomRadius())
|
||
);
|
||
};
|
||
|
||
EncounterEffect.calculatePoint = function (angle, radius) {
|
||
const { x, y } = this.centerPoint;
|
||
const sx = Math.round(radius * Math.cos((angle * Math.PI) / 180));
|
||
const sy = Math.round(radius * Math.sin((angle * Math.PI) / 180));
|
||
return new Point(x + sx, y + sy);
|
||
};
|
||
|
||
EncounterEffect.maxRadius = function () {
|
||
const { width, height } = Graphics;
|
||
const { x, y } = this.centerPoint;
|
||
const deltaX = x < width / 2 ? width - x : x;
|
||
const deltaY = y < height / 2 ? height - y : y;
|
||
return Math.hypot(deltaX, deltaY);
|
||
};
|
||
|
||
EncounterEffect.createFragmentsT2 = function () {
|
||
switch (this.currentParam("Shape Type", "square")) {
|
||
case "square":
|
||
this.createFragmentsT2Square();
|
||
break;
|
||
case "triangle":
|
||
this.createFragmentsT2Triangle();
|
||
break;
|
||
case "random":
|
||
this.createFragmentsT2Random();
|
||
break;
|
||
}
|
||
};
|
||
|
||
EncounterEffect.createFragmentsT2Square = function () {
|
||
const allPoints = this.createAllPointsT2Square();
|
||
for (const points of this.generatorPointsT2(allPoints)) {
|
||
this.addFragment(points);
|
||
}
|
||
};
|
||
|
||
EncounterEffect.generatorPointsT2 = function* (allPoints) {
|
||
const {
|
||
"Shape Type": sType = "square",
|
||
"Split X": splitX = 12,
|
||
"Split Y": splitY = 9,
|
||
} = this._params;
|
||
for (let i = 0; i < splitX; i++) {
|
||
const leftPoints = allPoints[i];
|
||
const rightPoints = allPoints[i + 1];
|
||
for (let j = 0; j < splitY; j++) {
|
||
const point1 = leftPoints[j];
|
||
const point2 = rightPoints[j];
|
||
const point3 = rightPoints[j + 1];
|
||
const point4 = leftPoints[j + 1];
|
||
if (sType === "triangle") {
|
||
if (i % 2 === 0) {
|
||
yield [point1, point2, point3];
|
||
yield [point1, point3, point4];
|
||
} else {
|
||
yield [point1, point2, point4];
|
||
yield [point2, point3, point4];
|
||
}
|
||
} else {
|
||
yield [point1, point2, point3, point4];
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
EncounterEffect.createAllPointsT2Square = function () {
|
||
const {
|
||
"Split X": splitX = 12,
|
||
"Split Y": splitY = 9,
|
||
"X Random Rate": xRate = 80,
|
||
"Y Random Rate": yRate = 80,
|
||
} = this._params;
|
||
const { minX, maxX, minY, maxY } = this.windowBounds;
|
||
const width = Graphics.width / Math.max(splitX - xRate / 100, 1);
|
||
const height = Graphics.height / Math.max(splitY - yRate / 100, 1);
|
||
|
||
const pointX = (i) => {
|
||
if (i === 0) {
|
||
return minX;
|
||
} else if (i === splitX) {
|
||
return maxX;
|
||
}
|
||
return this.randomValue(width, i, xRate);
|
||
};
|
||
const pointY = (j) => {
|
||
if (j === 0) {
|
||
return minY;
|
||
} else if (j === splitY) {
|
||
return maxY;
|
||
}
|
||
return this.randomValue(height, j, yRate);
|
||
};
|
||
|
||
return [...Array(splitX + 1).keys()].map((i) => {
|
||
return [...Array(splitY + 1).keys()].map((j) => {
|
||
return new Point(pointX(i), pointY(j));
|
||
});
|
||
});
|
||
};
|
||
|
||
EncounterEffect.randomValue = function (value, index, rate) {
|
||
return Math.round(value * (index - (rate * Math.random()) / 100));
|
||
};
|
||
|
||
EncounterEffect.createFragmentsT2Triangle = function () {
|
||
const allPoints = this.createAllPointsT2Triangle();
|
||
for (const points of this.generatorPointsT2(allPoints)) {
|
||
this.addFragment(points);
|
||
}
|
||
};
|
||
|
||
EncounterEffect.createAllPointsT2Triangle = function () {
|
||
const {
|
||
"Split X": splitX = 12,
|
||
"Split Y": splitY = 9,
|
||
"X Random Rate": xRate = 80,
|
||
"Y Random Rate": yRate = 80,
|
||
} = this._params;
|
||
const { minX, maxX, minY, maxY } = this.windowBounds;
|
||
const width = Graphics.width / Math.max(splitX - xRate / 100, 1);
|
||
const height = Graphics.height / Math.max(splitY - 0.5, 1);
|
||
const bottomY = ((height / 2) * yRate) / 100;
|
||
|
||
const pointX = (i) => {
|
||
if (i === 0) {
|
||
return minX;
|
||
} else if (i === splitX) {
|
||
return maxX;
|
||
}
|
||
return this.randomValue(width, i, xRate);
|
||
};
|
||
const pointY = (i, j) => {
|
||
if (j === 0) {
|
||
return minY;
|
||
} else if (j === splitY) {
|
||
return maxY;
|
||
}
|
||
if (i % 2 === 1 && j === 1) {
|
||
return this.randomValue(height / 2, j, yRate);
|
||
}
|
||
const py = bottomY - (i % 2 === 0 ? 0 : height / 2);
|
||
return py + this.randomValue(height, j, yRate);
|
||
};
|
||
|
||
return [...Array(splitX + 1).keys()].map((i) => {
|
||
return [...Array(splitY + 1).keys()].map((j) => {
|
||
return new Point(pointX(i), pointY(i, j));
|
||
});
|
||
});
|
||
};
|
||
|
||
EncounterEffect.createFragmentsT2Random = function () {
|
||
const allPolygons = this.createPolygonsT2Random();
|
||
|
||
const sidePolygon = (i, j, pos) => {
|
||
const si = i + (pos === 0 || pos === 1 ? -1 : 1);
|
||
const subPolygons = allPolygons[si];
|
||
if (!subPolygons) {
|
||
return null;
|
||
}
|
||
const sj = Math.floor(j / 2) * 2;
|
||
const polygon2 = subPolygons[sj];
|
||
if (Math.floor(pos / 2) === Math.floor(polygon2.pos / 2)) {
|
||
return subPolygons[sj + 1];
|
||
}
|
||
return polygon2;
|
||
};
|
||
|
||
for (const [i, mainPolygons] of allPolygons.entries()) {
|
||
for (const [j, polygon1] of mainPolygons.entries()) {
|
||
if (polygon1.state === "none") {
|
||
const d = MathExt.randomInt(3);
|
||
let polygon2;
|
||
if (d === 0) {
|
||
// 上
|
||
polygon2 = mainPolygons[j - 1];
|
||
} else if (d === 1) {
|
||
// 下
|
||
polygon2 = mainPolygons[j + 1];
|
||
} else {
|
||
// 横
|
||
polygon2 = sidePolygon(i, j, polygon1.pos);
|
||
}
|
||
if (polygon2 && polygon2.state === "none") {
|
||
this.joinPolygon(polygon1, polygon2, d);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
for (const polygon of allPolygons.flat()) {
|
||
if (polygon.state === "none" || polygon.state === "received") {
|
||
this.addFragment(polygon.points);
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
*
|
||
* @returns {array} 二次元配列。
|
||
* pos: 分割した際の位置。0=左上, 1=左下, 2=右上, 3=右下。
|
||
*/
|
||
EncounterEffect.createPolygonsT2Random = function () {
|
||
const allPoints = this.createAllPointsT2Square();
|
||
const polygons = [];
|
||
for (const [p1, p2, p3, p4] of this.generatorPointsT2(allPoints)) {
|
||
if (Math.random() < 0.5) {
|
||
polygons.push(
|
||
{ points: [p4, p1, p2], pos: 0, state: "none" },
|
||
{ points: [p4, p2, p3], pos: 3, state: "none" }
|
||
);
|
||
} else {
|
||
polygons.push(
|
||
{ points: [p1, p2, p3], pos: 2, state: "none" },
|
||
{ points: [p4, p1, p3], pos: 1, state: "none" }
|
||
);
|
||
}
|
||
}
|
||
|
||
const splitY = this.currentParam("Split Y", 9);
|
||
const allPolygons = [];
|
||
while (polygons.length > 0) {
|
||
allPolygons.push(polygons.splice(0, splitY * 2));
|
||
}
|
||
return allPolygons;
|
||
};
|
||
|
||
EncounterEffect.joinPolygon = function (polygon1, polygon2, d) {
|
||
const pos1 = polygon1.pos;
|
||
const pos2 = polygon2.pos;
|
||
let start = 0,
|
||
index = 0;
|
||
if (d === 0) {
|
||
start = pos1 === 0 || pos1 === 1 ? 2 : 1;
|
||
index = 1;
|
||
} else if (d === 1) {
|
||
start = 0;
|
||
index = pos1 === 0 ? 2 : pos1 === 2 ? 0 : pos2 === 0 ? 0 : 2;
|
||
} else {
|
||
start = pos1 === 0 || pos1 === 1 ? 1 : 2;
|
||
index = pos2 === 0 || pos2 === 1 ? 2 : 0;
|
||
}
|
||
polygon1.points.splice(start, 0, polygon2.points[index]);
|
||
polygon1.state = "received";
|
||
polygon2.state = "joined";
|
||
};
|
||
|
||
EncounterEffect.addFragment = function (points) {
|
||
const fragment = new Encounter_Fragment(points);
|
||
if (fragment.isValid()) {
|
||
fragment.setup();
|
||
this._fragments.push(fragment);
|
||
}
|
||
};
|
||
|
||
EncounterEffect.sortFragment = function (direction) {
|
||
const formula = this.compareFormula(direction);
|
||
if (formula) {
|
||
this._fragments.sort((a, b) => formula(a) - formula(b));
|
||
}
|
||
};
|
||
|
||
EncounterEffect.compareFormula = function (direction) {
|
||
const { x, y } = this.centerPoint;
|
||
switch (direction) {
|
||
case "left":
|
||
return (f) => {
|
||
return f._x;
|
||
};
|
||
case "center":
|
||
return (f) => {
|
||
return Math.abs(x - f._x);
|
||
};
|
||
case "right":
|
||
return (f) => {
|
||
return -f._x;
|
||
};
|
||
case "inside":
|
||
return (f) => {
|
||
return Math.abs(x - f._x) + (Math.abs(y - f._y) * y) / x;
|
||
};
|
||
case "outside":
|
||
return (f) => {
|
||
return -Math.abs(x - f._x) - (Math.abs(y - f._y) * y) / x;
|
||
};
|
||
}
|
||
return null;
|
||
};
|
||
|
||
EncounterEffect.breakFragments = function (start, end, duration) {
|
||
for (let i = start; i < end; i++) {
|
||
this._fragments[i].onBreak(duration, i);
|
||
}
|
||
};
|
||
|
||
EncounterEffect.startFadeIn = function () {
|
||
if (!this.isFadeOut()) {
|
||
return;
|
||
}
|
||
this._fadeSign = 1;
|
||
const {
|
||
"Move Duration": duration = 60,
|
||
"Scatter Direction": direction = "none",
|
||
"Scatter Duration": delay = 0,
|
||
} = this._params;
|
||
this._duration = duration;
|
||
this.sortFragment(direction);
|
||
this.startFadeInFragments(duration, delay);
|
||
this.startFadeInAngle(duration);
|
||
};
|
||
|
||
EncounterEffect.startFadeInFragments = function (duration, delay) {
|
||
const maxItems = this.maxItems();
|
||
for (const [i, fragment] of this._fragments.entries()) {
|
||
fragment.startFadeIn(duration, delay);
|
||
fragment.setDelay(Math.floor((delay * i) / maxItems));
|
||
}
|
||
};
|
||
|
||
EncounterEffect.startFadeInAngle = function (duration) {
|
||
if (this._type === 5) {
|
||
this._targetAngle = -4;
|
||
this._angleEasing.start("Straight", duration);
|
||
}
|
||
};
|
||
|
||
EncounterEffect.update = function () {
|
||
if (this.isRunning()) {
|
||
this._fragments.forEach((fragment) => fragment.update());
|
||
this.updateMain();
|
||
this.updateOpacity();
|
||
this.updateBackOpacity();
|
||
this.updateAngle();
|
||
if (this.isFadeIn() && this._duration === 0) {
|
||
this.clear();
|
||
}
|
||
}
|
||
};
|
||
|
||
EncounterEffect.updateMain = function () {
|
||
if (this._duration > 0) {
|
||
if (this.isFadeOut()) {
|
||
const speed = this.effectSpeed();
|
||
const n = speed - this._duration;
|
||
const breakEnd = this.breakDuration();
|
||
if (n > 2 && n <= breakEnd + 2) {
|
||
const maxItems = this.maxItems();
|
||
const start = Math.floor((maxItems * (n - 3)) / breakEnd);
|
||
const end = Math.floor((maxItems * (n - 2)) / breakEnd);
|
||
this.breakFragments(start, end, speed);
|
||
}
|
||
}
|
||
this._duration--;
|
||
}
|
||
};
|
||
|
||
EncounterEffect.updateOpacity = function () {
|
||
if (this.isFadeIn()) {
|
||
const d = this._duration;
|
||
const speed = this.effectSpeed();
|
||
const delay = this._type === 5 ? speed - 1 : Math.floor(speed / 2);
|
||
if (d < speed - delay) {
|
||
this._opacity -= this._opacity / d;
|
||
}
|
||
}
|
||
};
|
||
|
||
EncounterEffect.updateBackOpacity = function () {
|
||
if (this.isFadeIn()) {
|
||
const d = this._duration;
|
||
const speed = this.effectSpeed();
|
||
const delay = Math.floor(speed / 3);
|
||
if (d < speed - delay) {
|
||
this._backOpacity -= this._backOpacity / d;
|
||
}
|
||
}
|
||
};
|
||
|
||
EncounterEffect.updateAngle = function () {
|
||
const easing = this._angleEasing;
|
||
if (easing.isMoving()) {
|
||
this._angle = easing.apply(this._angle, this._targetAngle);
|
||
easing.update();
|
||
}
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// SceneManager
|
||
|
||
SceneManager.snapTexture = function () {
|
||
const stage = this._scene;
|
||
const width = Graphics.width;
|
||
const height = Graphics.height;
|
||
const renderTexture = PIXI.RenderTexture.create(width, height);
|
||
if (stage) {
|
||
const renderer = Graphics.app.renderer;
|
||
renderer.render(stage, renderTexture);
|
||
stage.worldTransform.identity();
|
||
}
|
||
return renderTexture;
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// SoundManager
|
||
|
||
const _SoundManager_playBattleStart = SoundManager.playBattleStart;
|
||
SoundManager.playBattleStart = function () {
|
||
if (EncounterEffect.type() >= 0) {
|
||
_SoundManager_playBattleStart.apply(this, arguments);
|
||
}
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Encounter_Fragment
|
||
|
||
class Encounter_Fragment {
|
||
constructor(points) {
|
||
this._points = points;
|
||
this.initRect(points);
|
||
this.initMembers();
|
||
}
|
||
|
||
initMembers() {
|
||
const rect = this._rect;
|
||
this._x = rect.x + Math.floor(rect.width / 2);
|
||
this._y = rect.y + Math.floor(rect.height / 2);
|
||
this._targetX = 0;
|
||
this._targetY = 0;
|
||
this._jumpHeight = 0;
|
||
this._scale = 1;
|
||
this._targetScale = 1;
|
||
this._moveEasing = new Easing();
|
||
this._opacity = 255;
|
||
this._opacityDuration = 0;
|
||
this._delay = 0;
|
||
this._flash = false;
|
||
this._break = false;
|
||
this._slideX = 0;
|
||
this._slideY = 0;
|
||
this.visible = true;
|
||
}
|
||
|
||
initRect(points) {
|
||
const allX = points.map((point) => point.x);
|
||
const allY = points.map((point) => point.y);
|
||
const x = Math.min(...allX);
|
||
const y = Math.min(...allY);
|
||
const width = Math.max(...allX) - x;
|
||
const height = Math.max(...allY) - y;
|
||
this._rect = new Rectangle(x, y, width, height);
|
||
}
|
||
|
||
isValid() {
|
||
return this._rect.width > 4 && this._rect.height > 4;
|
||
}
|
||
|
||
setDelay(delay) {
|
||
this._delay = delay;
|
||
}
|
||
|
||
clearFlash() {
|
||
this._flash = false;
|
||
}
|
||
|
||
isFlashRequested() {
|
||
return this._flash;
|
||
}
|
||
|
||
rect() {
|
||
return this._rect;
|
||
}
|
||
|
||
isBreak() {
|
||
return this._break;
|
||
}
|
||
|
||
lineWidth() {
|
||
return 4;
|
||
}
|
||
|
||
flashOpacity() {
|
||
return 255;
|
||
}
|
||
|
||
breakRate() {
|
||
return 1;
|
||
}
|
||
|
||
slideRate() {
|
||
return 1;
|
||
}
|
||
|
||
rotationRate() {
|
||
return 1;
|
||
}
|
||
|
||
screenX() {
|
||
return this._x;
|
||
}
|
||
|
||
screenY() {
|
||
return this._y - this._jumpHeight;
|
||
}
|
||
|
||
flashColor() {
|
||
return [...EncounterEffect.color(), this.flashOpacity()];
|
||
}
|
||
|
||
points() {
|
||
return this._points;
|
||
}
|
||
|
||
setup() {
|
||
this.setupRotation();
|
||
}
|
||
|
||
setupRotation() {
|
||
this._speed = 0;
|
||
this._pace = 0;
|
||
this._rotationX = 0;
|
||
this._rotationY = 0;
|
||
this._rotationZ = 0;
|
||
const rate = this.rotationRate();
|
||
if (Math.random() < 0.5) {
|
||
this._rotationSpeedX = (Math.random() + 0.5) * 2 * rate;
|
||
this._rotationSpeedY = 0;
|
||
} else {
|
||
this._rotationSpeedX = 0;
|
||
this._rotationSpeedY = (Math.random() + 0.5) * 2 * rate;
|
||
}
|
||
this._rotationSpeedZ = (Math.random() - 0.5) * 3 * rate;
|
||
}
|
||
|
||
textureMatrix() {
|
||
const tx = this._break ? this._slideX : 0;
|
||
const ty = this._break ? this._slideY : 0;
|
||
return new PIXI.Matrix(1, 0, 0, 1, tx, ty);
|
||
}
|
||
|
||
onBreak(duration, index) {
|
||
this.startEncounter(duration, index);
|
||
this._flash = true;
|
||
this._break = true;
|
||
}
|
||
|
||
startEncounter(duration, index) {
|
||
switch (EncounterEffect.type()) {
|
||
case 1:
|
||
this.setupMoveT1(duration);
|
||
this.setupSlideT1();
|
||
break;
|
||
case 2:
|
||
case 3:
|
||
case 4:
|
||
this.setupMoveT2();
|
||
this.setupSlideT2();
|
||
break;
|
||
case 5:
|
||
this.setupMoveT5(duration);
|
||
break;
|
||
}
|
||
}
|
||
|
||
setupMoveT1(duration) {
|
||
const breakRate = this.breakRate();
|
||
this._moveEasing.start("Slow end", duration);
|
||
this._speed = this.hypotSpeed(1.5) * breakRate;
|
||
this._pace = -1;
|
||
this.setMoveT1(breakRate / 100, breakRate / 100);
|
||
}
|
||
|
||
setupMoveT2() {
|
||
const breakRate = this.breakRate();
|
||
this._speed = 0.125 * breakRate;
|
||
this._pace = -1;
|
||
}
|
||
|
||
setupSlideT1() {
|
||
const slideRate = this.slideRate();
|
||
const { x, y } = EncounterEffect.centerPoint;
|
||
const radian = Math.atan2(this._y - y, this._x - x);
|
||
this._slideX = 20 * Math.cos(radian) * slideRate;
|
||
this._slideY = 20 * Math.sin(radian) * slideRate;
|
||
}
|
||
|
||
setupSlideT2() {
|
||
const slideRate = this.slideRate();
|
||
const { x, y, width, height } = this._rect;
|
||
const mx = (MathExt.randomInt(21) - 10) * slideRate;
|
||
const my = (MathExt.randomInt(21) - 10) * slideRate;
|
||
const minX = x + width - Graphics.width;
|
||
const minY = y + height - Graphics.height;
|
||
this._slideX = MathExt.clamp(mx, minX, x);
|
||
this._slideY = MathExt.clamp(my, minY, y);
|
||
}
|
||
|
||
setupMoveT5(duration) {
|
||
this._moveEasing.start("Slow end", duration);
|
||
this._speed = 0;
|
||
this._pace = 0;
|
||
this.setMoveAway("outside", 1.1);
|
||
}
|
||
|
||
update() {
|
||
if (this.visible && this.updateDelay()) {
|
||
this.updateMove();
|
||
this.updateOpacity();
|
||
this.updateRotation();
|
||
}
|
||
}
|
||
|
||
updateDelay() {
|
||
if (this._delay > 0) {
|
||
this._delay--;
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
updateMove() {
|
||
const easing = this._moveEasing;
|
||
if (easing.isMoving()) {
|
||
this._x = easing.apply(this._x, this._targetX);
|
||
this._y = easing.apply(this._y, this._targetY);
|
||
this._scale = easing.apply(this._scale, this._targetScale);
|
||
this.visible = this._scale < 8;
|
||
if (EncounterEffect.currentParam("Jump")) {
|
||
const d = easing._duration;
|
||
const wd = easing._wholeDuration;
|
||
const m = (4 * (d - 1)) / wd;
|
||
this._jumpHeight = (2 * 2 - Math.pow(m - 2, 2)) * 96;
|
||
}
|
||
easing.update();
|
||
}
|
||
}
|
||
|
||
updateOpacity() {
|
||
if (this._opacityDuration > 0) {
|
||
const d = this._opacityDuration--;
|
||
this._opacity *= (d - 1) / d;
|
||
}
|
||
}
|
||
|
||
updateRotation() {
|
||
if (this._speed > 0) {
|
||
this._speed *= 1 + 0.04 * this._pace;
|
||
this._rotationX += this._rotationSpeedX * this._speed;
|
||
this._rotationY += this._rotationSpeedY * this._speed;
|
||
this._rotationZ += this._rotationSpeedZ * this._speed;
|
||
}
|
||
}
|
||
|
||
startFadeIn(duration, delay) {
|
||
switch (EncounterEffect.type()) {
|
||
case 1:
|
||
this.startFadeInT1(duration);
|
||
break;
|
||
case 2:
|
||
this.startFadeInT2(Math.max(duration - delay, 1));
|
||
break;
|
||
case 3:
|
||
this.startFadeInT3(duration);
|
||
break;
|
||
case 4:
|
||
this.startFadeInT4(duration);
|
||
break;
|
||
case 5:
|
||
this.startFadeInT5(Math.max(duration - delay, 1));
|
||
break;
|
||
}
|
||
}
|
||
|
||
startFadeInT1(duration) {
|
||
this._moveEasing.start("Slow end", duration);
|
||
this._speed = this.hypotSpeed(40);
|
||
this._pace = -1;
|
||
this.setMoveT1(0.8 + Math.random() / 2, 0.8 + Math.random() / 2);
|
||
}
|
||
|
||
hypotSpeed(baseSpeed) {
|
||
const { x, y } = EncounterEffect.centerPoint;
|
||
return baseSpeed / Math.sqrt(Math.hypot(this._x - x, this._y - y));
|
||
}
|
||
|
||
setMoveT1(rateX, rateY) {
|
||
const { minX, maxX, minY, maxY } = EncounterEffect.windowBounds;
|
||
const { x: cx, y: cy } = EncounterEffect.centerPoint;
|
||
const sx = this._x - cx;
|
||
const sy = this._y - cy;
|
||
let ox = sx;
|
||
let oy = sy;
|
||
if (ox < 0) {
|
||
oy *= (minX - cx) / ox;
|
||
ox = minX - cx;
|
||
} else if (ox > 0) {
|
||
oy *= (maxX - cx) / ox;
|
||
ox = maxX - cx;
|
||
} else {
|
||
oy = oy < cy ? minY - cy : maxY - cy;
|
||
}
|
||
if (oy < minY - cy) {
|
||
ox *= (minY - cy) / oy;
|
||
oy = minY - cy;
|
||
} else if (oy > maxY - cy) {
|
||
ox *= (maxY - cy) / oy;
|
||
oy = maxY - cy;
|
||
}
|
||
this._targetX = this._x + (ox - sx) * rateX;
|
||
this._targetY = this._y + (oy - sy) * rateY;
|
||
}
|
||
|
||
startFadeInT2(duration) {
|
||
this._moveEasing.start("Slow start", duration);
|
||
this._speed = 1;
|
||
this._pace = 1;
|
||
const dir = EncounterEffect.currentParam("Scatter Direction");
|
||
this.setMoveT2(dir);
|
||
}
|
||
|
||
setMoveT2(direction) {
|
||
const { x: cx, y: cy } = EncounterEffect.centerPoint;
|
||
switch (direction) {
|
||
case "left":
|
||
this._targetX = this._x - Graphics.width;
|
||
this._targetY = this._y + (this._y - cy);
|
||
break;
|
||
case "right":
|
||
this._targetX = this._x + Graphics.width;
|
||
this._targetY = this._y + (this._y - cy);
|
||
break;
|
||
case "outside": {
|
||
const radian = Math.atan2(this._y - cy, this._x - cx);
|
||
const d = (cx + cy) / 2;
|
||
this._targetX = this._x + d * Math.cos(radian);
|
||
this._targetY = this._y + d * Math.sin(radian);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
startFadeInT3(duration) {
|
||
this._moveEasing.start("Slow end", duration);
|
||
this._speed = 2;
|
||
this._pace = 0;
|
||
this.setMoveT3();
|
||
}
|
||
|
||
setMoveT3() {
|
||
const { x: cx, y: cy } = EncounterEffect.centerPoint;
|
||
const sx = this._x - cx;
|
||
const sy = this._y - cy;
|
||
|
||
const rate = 3;
|
||
this._targetX = (sx + 80 * (Math.random() - 0.5)) * rate + cx;
|
||
this._targetY = (sy + 32 * (Math.random() - 0.5)) * rate + cy * 3;
|
||
|
||
const delta = Math.abs(sx) + Math.abs(sy);
|
||
this._targetScale = delta < 128 && Math.random() < 0.4 ? 12 : 1;
|
||
this._targetScale += 2.5 * Math.random();
|
||
}
|
||
|
||
startFadeInT4(duration) {
|
||
this._moveEasing.start("Slow end", duration);
|
||
this._speed = 2;
|
||
this._pace = -1;
|
||
const dir = EncounterEffect.currentParam("Scatter Direction");
|
||
this.setMoveAway(dir, 2);
|
||
}
|
||
|
||
startFadeInT5(duration) {
|
||
this._moveEasing.start("Straight", duration);
|
||
this._speed = 0;
|
||
this._pace = 0;
|
||
this.setMoveAway("outside", 2.25);
|
||
this._targetScale = 1.75;
|
||
this._opacityDuration = duration;
|
||
}
|
||
|
||
setMoveAway(direction, rate) {
|
||
let { x, y } = EncounterEffect.centerPoint;
|
||
switch (direction) {
|
||
case "left":
|
||
x = Graphics.width;
|
||
break;
|
||
case "right":
|
||
x = 0;
|
||
break;
|
||
}
|
||
this._targetX = x + (this._x - x) * rate;
|
||
this._targetY = y + (this._y - y) * rate;
|
||
}
|
||
|
||
opacity() {
|
||
return this._opacity;
|
||
}
|
||
|
||
scaleX() {
|
||
return Math.cos((this._rotationX * Math.PI) / 180) * this._scale;
|
||
}
|
||
|
||
scaleY() {
|
||
return Math.cos((this._rotationY * Math.PI) / 180) * this._scale;
|
||
}
|
||
|
||
rotation() {
|
||
return (this._rotationZ * Math.PI) / 180;
|
||
}
|
||
}
|
||
|
||
if (_importedPlugin(...pluginOptions)) {
|
||
window.Encounter_Fragment = Encounter_Fragment;
|
||
}
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Easing
|
||
|
||
class Easing {
|
||
constructor(type = "", duration = 0) {
|
||
this.setType(type);
|
||
this.setDuration(duration);
|
||
}
|
||
|
||
start(type, duration) {
|
||
this.setType(type);
|
||
this.setDuration(duration);
|
||
}
|
||
|
||
setType(type) {
|
||
this._type = type || "Slow end";
|
||
}
|
||
|
||
setDuration(duration) {
|
||
this._duration = duration;
|
||
this._wholeDuration = duration;
|
||
}
|
||
|
||
clear() {
|
||
this._duration = 0;
|
||
}
|
||
|
||
isMoving() {
|
||
return this._duration > 0;
|
||
}
|
||
|
||
update() {
|
||
if (this._duration > 0) {
|
||
this._duration--;
|
||
}
|
||
}
|
||
|
||
apply(current, target) {
|
||
const d = this._duration;
|
||
const wd = this._wholeDuration;
|
||
const lt = this.calc((wd - d) / wd);
|
||
const t = this.calc((wd - d + 1) / wd);
|
||
const start = (current - target * lt) / (1 - lt);
|
||
return start + (target - start) * t;
|
||
}
|
||
|
||
calc(t) {
|
||
switch (this._type) {
|
||
case "Slow start":
|
||
return this.easeIn(t);
|
||
case "Slow end":
|
||
return this.easeOut(t);
|
||
case "Slow start and end":
|
||
return this.easeInOut(t);
|
||
default:
|
||
return t;
|
||
}
|
||
}
|
||
|
||
easeIn(t) {
|
||
return Math.pow(t, 2);
|
||
}
|
||
|
||
easeOut(t) {
|
||
return 1 - Math.pow(1 - t, 2);
|
||
}
|
||
|
||
easeInOut(t) {
|
||
if (t < 0.5) {
|
||
return this.easeIn(t * 2) / 2;
|
||
} else {
|
||
return this.easeOut(t * 2 - 1) / 2 + 0.5;
|
||
}
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------------
|
||
// PluginManager
|
||
|
||
PluginManager.registerCommand(pluginName, "setType", (args) => {
|
||
EncounterEffect.setType(PluginManager.mppValue(args.type));
|
||
});
|
||
|
||
PluginManager.registerCommand(pluginName, "setCharacter", function (args) {
|
||
const eId = PluginManager.mppValue(args.character);
|
||
EncounterEffect.setCharacter(this.character(eId));
|
||
});
|
||
|
||
PluginManager.registerCommand(pluginName, "setColor", (args) => {
|
||
const color = args.color.split(",");
|
||
const r = PluginManager.mppValue(color[0]);
|
||
const g = PluginManager.mppValue(color[1]);
|
||
const b = PluginManager.mppValue(color[2]);
|
||
EncounterEffect.setColor(r, g, b);
|
||
});
|
||
|
||
PluginManager.mppValue = function (value) {
|
||
const match = /^V\[(\d+)\]$/i.exec(value);
|
||
return match ? $gameVariables.value(+match[1]) : +value;
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Game_Map
|
||
|
||
Game_Map.prototype.getInterpreterCharacter = function (param) {
|
||
const interpreter = this._interpreter;
|
||
return interpreter.isRunning() ? interpreter.character(param) : null;
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Graphics_Fragment
|
||
|
||
class Graphics_Fragment extends PIXI.Graphics {
|
||
constructor(fragment) {
|
||
super();
|
||
this._fragment = fragment;
|
||
this._blendColor = [0, 0, 0, 0];
|
||
this._break = fragment.isBreak();
|
||
this._flashDuration = 0;
|
||
this.initPivot();
|
||
this.refresh();
|
||
this.update();
|
||
}
|
||
|
||
initPivot() {
|
||
const rect = this._fragment.rect();
|
||
const x = rect.x + Math.floor(rect.width / 2);
|
||
const y = rect.y + Math.floor(rect.height / 2);
|
||
this.pivot.set(x, y);
|
||
}
|
||
|
||
refreshIfNeeded() {
|
||
if (!this._break && this._fragment.isBreak()) {
|
||
this._break = true;
|
||
this.refresh();
|
||
}
|
||
}
|
||
|
||
refresh() {
|
||
this.clear();
|
||
const options = {
|
||
texture: EncounterEffect.snapTexture(),
|
||
matrix: this._fragment.textureMatrix(),
|
||
};
|
||
this.beginTextureFill(options);
|
||
this.drawPolygon();
|
||
this.endFill();
|
||
const lw = this._fragment.lineWidth() / 2;
|
||
if (this._break && lw > 0) {
|
||
const c = EncounterEffect.color();
|
||
const color = c[0] * 256 * 256 + c[1] * 256 + c[2];
|
||
this.lineStyle(lw + 0.5, color, 0.25, 0.3);
|
||
this.drawPolygon();
|
||
this.lineStyle(lw, color, 0.5, 0.3);
|
||
this.drawPolygon();
|
||
}
|
||
}
|
||
|
||
drawPolygon() {
|
||
for (const [i, point] of this._fragment.points().entries()) {
|
||
i === 0 ? this.moveTo(point.x, point.y) : this.lineTo(point.x, point.y);
|
||
}
|
||
this.closePath();
|
||
}
|
||
|
||
update() {
|
||
this.refreshIfNeeded();
|
||
this.updatePosition();
|
||
this.updateOpacity();
|
||
this.updateFlash();
|
||
this.updateVisibility();
|
||
}
|
||
|
||
updatePosition() {
|
||
const fragment = this._fragment;
|
||
this.x = fragment.screenX();
|
||
this.y = fragment.screenY();
|
||
this.scale.x = fragment.scaleX();
|
||
this.scale.y = fragment.scaleY();
|
||
this.rotation = fragment.rotation();
|
||
}
|
||
|
||
updateOpacity() {
|
||
this.alpha = this._fragment.opacity() / 255;
|
||
}
|
||
|
||
updateFlash() {
|
||
this.setupFlash();
|
||
if (this._flashDuration > 0) {
|
||
const d = this._flashDuration--;
|
||
this._blendColor[3] *= (d - 1) / d;
|
||
if (this._flashDuration % 8 === 0) {
|
||
this._updateColorFilter();
|
||
}
|
||
}
|
||
}
|
||
|
||
setupFlash() {
|
||
if (this._fragment.isFlashRequested()) {
|
||
this._flashDuration = 25;
|
||
this._blendColor = this._fragment.flashColor();
|
||
this._fragment.clearFlash();
|
||
}
|
||
}
|
||
|
||
_createColorFilter() {
|
||
this._colorFilter = new BlendColorFilter();
|
||
this.filters = [this._colorFilter];
|
||
}
|
||
|
||
_removeColorFilter() {
|
||
this.filters = null;
|
||
this._colorFilter = null;
|
||
}
|
||
|
||
_updateColorFilter() {
|
||
if (this._colorFilter && this._blendColor[3] === 0) {
|
||
this._removeColorFilter();
|
||
return;
|
||
}
|
||
if (!this._colorFilter) {
|
||
this._createColorFilter();
|
||
}
|
||
this._colorFilter.setColor(this._blendColor);
|
||
}
|
||
|
||
updateVisibility() {
|
||
this.visible = this._fragment.visible;
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------------
|
||
// BlendColorFilter
|
||
|
||
class BlendColorFilter extends PIXI.Filter {
|
||
constructor() {
|
||
super(null, BlendColorFilter._fragmentSrc);
|
||
this.uniforms.blendColor = [0, 0, 0, 0];
|
||
}
|
||
|
||
static _fragmentSrc =
|
||
"varying vec2 vTextureCoord;" +
|
||
"uniform sampler2D uSampler;" +
|
||
"uniform vec4 blendColor;" +
|
||
"void main() {" +
|
||
" vec4 sample = texture2D(uSampler, vTextureCoord);" +
|
||
" float a = sample.a;" +
|
||
" vec3 rgb = sample.rgb;" +
|
||
" float r = rgb.r;" +
|
||
" float g = rgb.g;" +
|
||
" float b = rgb.b;" +
|
||
" float r3 = blendColor.r / 255.0;" +
|
||
" float g3 = blendColor.g / 255.0;" +
|
||
" float b3 = blendColor.b / 255.0;" +
|
||
" float i3 = blendColor.a / 255.0;" +
|
||
" float i1 = 1.0 - i3;" +
|
||
" r = clamp(r * i1 + r3 * i3 * a, 0.0, 1.0);" +
|
||
" g = clamp(g * i1 + g3 * i3 * a, 0.0, 1.0);" +
|
||
" b = clamp(b * i1 + b3 * i3 * a, 0.0, 1.0);" +
|
||
" gl_FragColor = vec4(r, g, b, a);" +
|
||
"}";
|
||
|
||
setColor(color) {
|
||
if (!(color instanceof Array)) {
|
||
throw new Error("Argument must be an array");
|
||
}
|
||
this.uniforms.blendColor = [...color];
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Sprite_EncounterEffect
|
||
//
|
||
// スプライトクラスではないですが、
|
||
// RPGツクールのSpriteクラスのような扱いをするという意味でのクラス名です。
|
||
|
||
class Sprite_EncounterEffect extends PIXI.Container {
|
||
constructor() {
|
||
super();
|
||
this.createBlackBack();
|
||
this.createFragments();
|
||
this.initPosition();
|
||
this.updateRotation();
|
||
}
|
||
|
||
destroy() {
|
||
const options = { children: true };
|
||
super.destroy(options);
|
||
}
|
||
|
||
createBlackBack() {
|
||
const p = 40;
|
||
const width = Graphics.width + p * 2;
|
||
const height = Graphics.height + p * 2;
|
||
this._backGraphics = new PIXI.Graphics();
|
||
this._backGraphics.beginFill(0);
|
||
this._backGraphics.drawRect(-p, -p, width, height);
|
||
this._backGraphics.endFill();
|
||
this.addChild(this._backGraphics);
|
||
}
|
||
|
||
createFragments() {
|
||
for (const fragment of EncounterEffect.fragments()) {
|
||
this.addChild(new Graphics_Fragment(fragment));
|
||
}
|
||
}
|
||
|
||
initPosition() {
|
||
const { x, y } = EncounterEffect.centerPoint;
|
||
this.x = x;
|
||
this.y = y;
|
||
this.pivot.set(x, y);
|
||
}
|
||
|
||
update() {
|
||
this.updateChildren();
|
||
this.updateRotation();
|
||
this.updateOpacity();
|
||
}
|
||
|
||
updateChildren() {
|
||
for (const child of this.children) {
|
||
if (child.update) {
|
||
child.update();
|
||
}
|
||
}
|
||
}
|
||
|
||
updateRotation() {
|
||
this.rotation = EncounterEffect.rotation();
|
||
}
|
||
|
||
updateOpacity() {
|
||
this.alpha = EncounterEffect.opacity() / 255;
|
||
this._backGraphics.alpha = EncounterEffect.backOpacity() / 255;
|
||
}
|
||
|
||
updateFadeDelay() {
|
||
if (this._fadeDelay > 0) {
|
||
this._fadeDelay--;
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Sprite_Actor
|
||
|
||
const _Sprite_Actor_updateMove = Sprite_Actor.prototype.updateMove;
|
||
Sprite_Actor.prototype.updateMove = function () {
|
||
if (EncounterEffect.isReady()) {
|
||
_Sprite_Actor_updateMove.apply(this, arguments);
|
||
}
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Spriteset_Map
|
||
|
||
Spriteset_Map.prototype.showDestination = function () {
|
||
this._destinationSprite.visible = true;
|
||
};
|
||
|
||
Spriteset_Map.prototype.hideDestination = function () {
|
||
this._destinationSprite.visible = false;
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Scene_Base
|
||
|
||
Scene_Base.prototype.createEncEffSprite = function () {
|
||
if (EncounterEffect.isRunning() && !this._encEffSprite) {
|
||
this._encEffSprite = new Sprite_EncounterEffect();
|
||
this.addChild(this._encEffSprite);
|
||
}
|
||
};
|
||
|
||
Scene_Base.prototype.destroyEncEffSprite = function () {
|
||
if (this._encEffSprite) {
|
||
this.removeChild(this._encEffSprite);
|
||
this._encEffSprite.destroy();
|
||
delete this._encEffSprite;
|
||
}
|
||
};
|
||
|
||
Scene_Base.prototype.startEncEffFadeOut = function () {
|
||
if (!EncounterEffect.isRunning()) {
|
||
this.snapEncEffTexture();
|
||
EncounterEffect.startFadeOut();
|
||
this.createEncEffSprite();
|
||
}
|
||
};
|
||
|
||
Scene_Base.prototype.snapEncEffTexture = function () {
|
||
this._windowLayer.visible = false;
|
||
EncounterEffect.setup(SceneManager.snapTexture());
|
||
this._windowLayer.visible = true;
|
||
};
|
||
|
||
Scene_Base.prototype.startEncEffFadeIn = function () {
|
||
if (EncounterEffect.isFadeOut()) {
|
||
EncounterEffect.startFadeIn();
|
||
this.createEncEffSprite();
|
||
}
|
||
};
|
||
|
||
Scene_Base.prototype.updateMppEncEffManager = function () {
|
||
if (EncounterEffect.isRunning()) {
|
||
EncounterEffect.update();
|
||
this._spriteset.visible = EncounterEffect.isSpritesetVisible();
|
||
if (!EncounterEffect.isRunning()) {
|
||
this.destroyEncEffSprite();
|
||
this._spriteset.visible = true;
|
||
}
|
||
}
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Scene_Title
|
||
|
||
const _Scene_Title_initialize = Scene_Title.prototype.initialize;
|
||
Scene_Title.prototype.initialize = function () {
|
||
_Scene_Title_initialize.apply(this, arguments);
|
||
EncounterEffect.clear();
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Scene_Map
|
||
|
||
const _Scene_Map_startFadeIn = __base(Scene_Map.prototype, "startFadeIn");
|
||
Scene_Map.prototype.startFadeIn = function (duration, white) {
|
||
if (!EncounterEffect.isRunning()) {
|
||
_Scene_Map_startFadeIn.apply(this, arguments);
|
||
}
|
||
};
|
||
|
||
const _Scene_Map_update = Scene_Map.prototype.update;
|
||
Scene_Map.prototype.update = function () {
|
||
_Scene_Map_update.apply(this, arguments);
|
||
this.updateMppEncEffManager();
|
||
};
|
||
|
||
const _Scene_Map_startEncounterEffect =
|
||
Scene_Map.prototype.startEncounterEffect;
|
||
Scene_Map.prototype.startEncounterEffect = function () {
|
||
if (EncounterEffect.type() < 0) {
|
||
this.startFadeOut(this.fadeSpeed(), false);
|
||
EncounterEffect.clear();
|
||
return;
|
||
}
|
||
if (EncounterEffect.isValid()) {
|
||
this.startEncEffFadeOut();
|
||
} else {
|
||
EncounterEffect.clear();
|
||
}
|
||
_Scene_Map_startEncounterEffect.apply(this, arguments);
|
||
};
|
||
|
||
const _Scene_Map_updateEncounterEffect =
|
||
Scene_Map.prototype.updateEncounterEffect;
|
||
Scene_Map.prototype.updateEncounterEffect = function () {
|
||
EncounterEffect.isRunning()
|
||
? this.updateMppEncounterEffect()
|
||
: _Scene_Map_updateEncounterEffect.apply(this, arguments);
|
||
};
|
||
|
||
const _Scene_Map_encounterEffectSpeed =
|
||
Scene_Map.prototype.encounterEffectSpeed;
|
||
Scene_Map.prototype.encounterEffectSpeed = function () {
|
||
return EncounterEffect.isRunning()
|
||
? EncounterEffect.effectSpeed()
|
||
: _Scene_Map_encounterEffectSpeed.apply(this, arguments);
|
||
};
|
||
|
||
Scene_Map.prototype.snapEncEffTexture = function () {
|
||
this._spriteset.hideDestination();
|
||
Scene_Message.prototype.snapEncEffTexture.call(this);
|
||
this._spriteset.showDestination();
|
||
};
|
||
|
||
Scene_Map.prototype.updateMppEncounterEffect = function () {
|
||
if (this._encounterEffectDuration > 0) {
|
||
this._encounterEffectDuration--;
|
||
const speed = this.encounterEffectSpeed();
|
||
const n = speed - this._encounterEffectDuration;
|
||
if (n === 2) {
|
||
this._spriteset.visible = true;
|
||
this._encEffSprite.visible = false;
|
||
this.snapForBattleBackground();
|
||
this._encEffSprite.visible = true;
|
||
}
|
||
if (n === Math.floor(speed / 4)) {
|
||
BattleManager.playBattleBgm();
|
||
}
|
||
}
|
||
};
|
||
|
||
//-------------------------------------------------------------------------
|
||
// Scene_Battle
|
||
|
||
const _Scene_Battle_create = Scene_Battle.prototype.create;
|
||
Scene_Battle.prototype.create = function () {
|
||
_Scene_Battle_create.apply(this, arguments);
|
||
this.startEncEffFadeIn();
|
||
};
|
||
|
||
const _Scene_Battle_startFadeIn = __base(
|
||
Scene_Battle.prototype,
|
||
"startFadeIn"
|
||
);
|
||
Scene_Battle.prototype.startFadeIn = function (duration, white) {
|
||
if (!EncounterEffect.isRunning()) {
|
||
_Scene_Battle_startFadeIn.apply(this, arguments);
|
||
}
|
||
};
|
||
|
||
const _Scene_Battle_update = Scene_Battle.prototype.update;
|
||
Scene_Battle.prototype.update = function () {
|
||
_Scene_Battle_update.apply(this, arguments);
|
||
this.updateMppEncEffManager();
|
||
};
|
||
})();
|