3947 lines
112 KiB
JavaScript
3947 lines
112 KiB
JavaScript
/*:
|
||
@target MV MZ
|
||
@plugindesc Skill tree v1.8.2
|
||
@author unagi ootoro
|
||
@url https://raw.githubusercontent.com/unagiootoro/RPGMZ/master/SkillTree.js
|
||
|
||
@param SpName
|
||
@type string
|
||
@default SP
|
||
@desc
|
||
Specify the wording of SP in the game.
|
||
|
||
@param MaxSp
|
||
@type number
|
||
@default 9999
|
||
@desc
|
||
Set the maximum value of SP that can be acquired.
|
||
|
||
@param EnabledSkillTreeSwitchId
|
||
@type switch
|
||
@default 0
|
||
@desc
|
||
Specify the ID of the switch that enables/disables the skill tree with the menu command.
|
||
|
||
@param EnableGetSpWhenBattleEnd
|
||
@type boolean
|
||
@default true
|
||
@desc
|
||
If set to true, SP will be available at the end of battle.
|
||
|
||
@param EnableGetSpWhenLevelUp
|
||
@type boolean
|
||
@default true
|
||
@desc
|
||
If you set true, you will be able to get SP when you level up.
|
||
|
||
@param ViewMode
|
||
@type string
|
||
@default wide
|
||
@desc
|
||
wide: Skill tree will be displayed next to it. long: Skill tree will be displayed vertically.
|
||
|
||
@param EnableMZLayout
|
||
@type boolean
|
||
@default false
|
||
@desc
|
||
Set to true to match the layout format of RPG Maker MZ. (MZ limited)
|
||
|
||
@param IconWidth
|
||
@type number
|
||
@default 32
|
||
@desc
|
||
Specify the width of the icon.
|
||
|
||
@param IconHeight
|
||
@type number
|
||
@default 32
|
||
@desc
|
||
Specifies the vertical width of the icon.
|
||
|
||
@param IconSpaceWidth
|
||
@type number
|
||
@default 32
|
||
@desc
|
||
Specifies the width of the space between the icons.
|
||
|
||
@param IconSpaceHeight
|
||
@type number
|
||
@default 32
|
||
@desc
|
||
Specifies the vertical width of the space between icons.
|
||
|
||
@param ViewLineWidth
|
||
@type number
|
||
@default 3
|
||
@desc
|
||
Specifies the line width.
|
||
|
||
@param ViewLineColorBase
|
||
@type string
|
||
@default #000000
|
||
@desc
|
||
Specifies the color of the line for which the skill has not been learned.
|
||
|
||
@param ViewLineColorLearned
|
||
@type string
|
||
@default #00aaff
|
||
@desc
|
||
Specify the color of the line for which the skill has been acquired.
|
||
|
||
@param ViewBeginXOffset
|
||
@type number
|
||
@default 24
|
||
@desc
|
||
Specifies the X coordinate of the drawing start of the skill tree.
|
||
|
||
@param ViewBeginYOffset
|
||
@type number
|
||
@default 24
|
||
@desc
|
||
Specify the drawing start Y coordinate of the skill tree.
|
||
|
||
@param ViewCursorOfs
|
||
@type number
|
||
@default 6
|
||
@desc
|
||
Specifies the cursor coordinate offset for the skill tree icon.
|
||
|
||
@param ViewRectColor
|
||
@type string
|
||
@default #ffff00
|
||
@desc
|
||
Specifies the color of the border surrounding the acquired skill icon.
|
||
|
||
@param ViewRectOfs
|
||
@type number
|
||
@default 1
|
||
@desc
|
||
Specify the coordinate offset of the border or border image that surrounds the acquired skill icon.
|
||
|
||
@param LearnSkillSeFileName
|
||
@type file
|
||
@dir audio/se
|
||
@default Item3
|
||
@desc
|
||
Specify the file name of the SE to play when the skill is acquired.
|
||
|
||
@param LearnSkillSeVolume
|
||
@type number
|
||
@default 90
|
||
@desc
|
||
Specify the volume of SE to play when the skill is acquired.
|
||
|
||
@param LearnSkillSePitch
|
||
@type number
|
||
@default 100
|
||
@desc
|
||
Specify the SE pitch to play when the skill is acquired.
|
||
|
||
@param LearnSkillSePan
|
||
@type number
|
||
@default 0
|
||
@desc
|
||
Specify the SE pan to play when the skill is acquired.
|
||
|
||
@param MenuSkillTreeText
|
||
@type string
|
||
@default Skill tree
|
||
@desc
|
||
Specify the skill tree command name to be displayed in the menu command.
|
||
|
||
@param NeedSpText
|
||
@type string
|
||
@default Required %1:
|
||
@desc
|
||
Specify the required SP text to be displayed in the skill tree window. %1:SP name
|
||
|
||
@param OpenedNodeText
|
||
@type string
|
||
@default Acquired
|
||
@desc
|
||
Specifies the text to display in place of the required SP if the skill is already acquired.
|
||
|
||
@param NodeOpenConfirmationText
|
||
@type string
|
||
@default Do you consume %1%2 and get %3?
|
||
@desc
|
||
Specifies the text for skill acquisition selection. %1:SP value, %2:SP name, %3:skill name to be acquired
|
||
|
||
@param NodeOpenYesText
|
||
@type string
|
||
@default Learn
|
||
@desc
|
||
On the selection screen of whether to acquire the skill, specify the text for acquiring the skill.
|
||
|
||
@param NodeOpenNoText
|
||
@type string
|
||
@default Don't learn
|
||
@desc
|
||
In the selection screen of whether to acquire the skill, specify the text when the skill is not acquired.
|
||
|
||
@param NodeCloseConfirmationText
|
||
@type string
|
||
@default Do you reset %1 and return %2%3?
|
||
@desc
|
||
Specifies the text for skill acquisition selection. %1:skill name,%2:SP value, %3:SP name name to be acquired
|
||
|
||
@param NodeCloseYesText
|
||
@type string
|
||
@default reset
|
||
@desc
|
||
On the selection screen of whether to reset the skill, specify the text for resetting the skill.
|
||
|
||
@param NodeCloseNoText
|
||
@type string
|
||
@default Don't reset
|
||
@desc
|
||
In the selection screen of whether to reset the skill, specify the text when the skill is not reset.
|
||
|
||
@param BattleEndGetSpText
|
||
@type string
|
||
@default I got %1%2.
|
||
@desc
|
||
Specifies the text to display when the SP is obtained at the end of the battle. %1:SP value, %2:SP name
|
||
|
||
@param LevelUpGetSpText
|
||
@type string
|
||
@default I got %1%2.
|
||
@desc
|
||
Specify the text to display when you get the SP when you level up. %1:SP value, %2:SP name
|
||
|
||
@help
|
||
A plugin that introduces a skill tree.
|
||
Please refer to "SkillTreeConfig.js" for the setting method.
|
||
|
||
[License]
|
||
This plugin is available under the terms of the MIT license.
|
||
*/
|
||
|
||
/*:ja
|
||
@target MV MZ
|
||
@plugindesc スキルツリー v1.8.2
|
||
@author うなぎおおとろ
|
||
@url https://raw.githubusercontent.com/unagiootoro/RPGMZ/master/SkillTree.js
|
||
|
||
@param SpName
|
||
@type string
|
||
@default SP
|
||
@desc
|
||
ゲーム中でのSPの文言を指定します。
|
||
|
||
@param MaxSp
|
||
@type number
|
||
@default 9999
|
||
@desc
|
||
取得可能なSPの最大値を設定します。
|
||
|
||
@param EnabledSkillTreeSwitchId
|
||
@type switch
|
||
@default 0
|
||
@desc
|
||
メニューコマンドでスキルツリーを有効/無効を設定するスイッチのIDを指定します。0を指定すると常にスキルツリーは有効になります。
|
||
|
||
@param EnableGetSpWhenBattleEnd
|
||
@type boolean
|
||
@default true
|
||
@desc
|
||
trueを設定すると、戦闘終了時にSPを入手できるようになります。
|
||
|
||
@param EnableGetSpWhenLevelUp
|
||
@type boolean
|
||
@default true
|
||
@desc
|
||
trueを設定すると、レベルアップ時にSPを入手できるようになります。
|
||
|
||
@param ViewMode
|
||
@type string
|
||
@default wide
|
||
@desc
|
||
wideを設定すると、横にスキルツリーを表示します。longを設定すると、縦にスキルツリーを表示します。
|
||
|
||
@param EnableMZLayout
|
||
@type boolean
|
||
@default false
|
||
@desc
|
||
trueを設定すると、RPGツクールMZのレイアウト形式に合わせます。(MZ限定)
|
||
|
||
@param IconWidth
|
||
@type number
|
||
@default 32
|
||
@desc
|
||
アイコンの横幅を指定します。
|
||
|
||
@param IconHeight
|
||
@type number
|
||
@default 32
|
||
@desc
|
||
アイコンの縦幅を指定します。
|
||
|
||
@param IconSpaceWidth
|
||
@type number
|
||
@default 32
|
||
@desc
|
||
アイコン間のスペースの横幅を指定します。
|
||
|
||
@param IconSpaceHeight
|
||
@type number
|
||
@default 32
|
||
@desc
|
||
アイコン間のスペースの縦幅を指定します。
|
||
|
||
@param ViewLineWidth
|
||
@type number
|
||
@default 2
|
||
@desc
|
||
ラインの幅を指定します。
|
||
|
||
@param ViewLineColorBase
|
||
@type string
|
||
@default #000000
|
||
@desc
|
||
スキル未習得の線の色を指定します。
|
||
|
||
@param ViewLineColorLearned
|
||
@type string
|
||
@default #00aaff
|
||
@desc
|
||
スキル習得済みの線の色を指定します。
|
||
|
||
@param ViewBeginXOffset
|
||
@type number
|
||
@default 24
|
||
@desc
|
||
スキルツリーの描画開始X座標を指定します。
|
||
|
||
@param ViewBeginYOffset
|
||
@type number
|
||
@default 24
|
||
@desc
|
||
スキルツリーの描画開始Y座標を指定します。
|
||
|
||
@param ViewCursorOfs
|
||
@type number
|
||
@default 6
|
||
@desc
|
||
スキルツリーのアイコンに対するカーソルの座標オフセットを指定します。
|
||
|
||
@param ViewRectColor
|
||
@type string
|
||
@default #ffff00
|
||
@desc
|
||
取得済みスキルのアイコンを囲む枠線の色を指定します。
|
||
|
||
@param ViewRectOfs
|
||
@type number
|
||
@default 1
|
||
@desc
|
||
取得済みスキルのアイコンを囲む枠線または枠画像の座標オフセットを指定します。
|
||
|
||
@param LearnSkillSeFileName
|
||
@type file
|
||
@dir audio/se
|
||
@default Item3
|
||
@desc
|
||
スキルを習得したときに再生するSEのファイル名を指定します。
|
||
|
||
@param LearnSkillSeVolume
|
||
@type number
|
||
@default 90
|
||
@desc
|
||
スキルを習得したときに再生するSEのvolumeを指定します。
|
||
|
||
@param LearnSkillSePitch
|
||
@type number
|
||
@default 100
|
||
@desc
|
||
スキルを習得したときに再生するSEのpitchを指定します。
|
||
|
||
@param LearnSkillSePan
|
||
@type number
|
||
@default 0
|
||
@desc
|
||
スキルを習得したときに再生するSEのpanを指定します。
|
||
|
||
@param MenuSkillTreeText
|
||
@type string
|
||
@default スキルツリー
|
||
@desc
|
||
メニューコマンドに表示するスキルツリーのコマンド名を指定します。
|
||
|
||
@param NeedSpText
|
||
@type string
|
||
@default 必要%1:
|
||
@desc
|
||
スキルツリーウィンドウに表示する必要SPのテキストを指定します。%1:SP名
|
||
|
||
@param OpenedNodeText
|
||
@type string
|
||
@default 取得済み
|
||
@desc
|
||
スキルが取得済みの場合に必要SPの代わりに表示するテキストを指定します。
|
||
|
||
@param NodeOpenConfirmationText
|
||
@type string
|
||
@default %1%2を消費して%3を取得しますか?
|
||
@desc
|
||
スキル取得有無の選択画面で、確認用のテキストを表示します。%1:消費するSP値, %2:SP名, %3:取得するスキル名
|
||
|
||
|
||
@param NodeOpenYesText
|
||
@type string
|
||
@default 習得する
|
||
@desc
|
||
スキル取得有無の選択画面で、スキルを取得する場合のテキストを指定します。
|
||
|
||
@param NodeOpenNoText
|
||
@type string
|
||
@default 習得しない
|
||
@desc
|
||
スキル取得有無の選択画面で、スキルを取得しない場合のテキストを指定します。
|
||
|
||
@param NodeCloseConfirmationText
|
||
@type string
|
||
@default %1をリセットしますか?(%2%3獲得)
|
||
@desc
|
||
既に取得したスキルをリセットするかどうかの確認画面で、確認用のテキストを表示します。%1:リセットするスキル名, %2:SP値, %3:SP名
|
||
|
||
@param NodeCloseYesText
|
||
@type string
|
||
@default リセットする
|
||
@desc
|
||
既に取得したスキルをリセットするかどうかの確認画面で、スキルを取得する場合のテキストを指定します。
|
||
|
||
@param NodeCloseNoText
|
||
@type string
|
||
@default リセットしない
|
||
@desc
|
||
既に取得したスキルをリセットするかどうかの確認画面で、スキルを取得しない場合のテキストを指定します。
|
||
|
||
@param BattleEndGetSpText
|
||
@type string
|
||
@default %1%2を入手した。
|
||
@desc
|
||
戦闘終了時にSPを入手したときに表示するテキストを指定します。%1:入手するSP値, %2:SP名
|
||
|
||
@param LevelUpGetSpText
|
||
@type string
|
||
@default %1%2を入手した。
|
||
@desc
|
||
レベルアップ時にSPを入手したときに表示するテキストを指定します。%1:入手するSP値, %2:SP名
|
||
|
||
@help
|
||
!!!!!!!!!!!!!!!!!!!!!!!
|
||
このプラグインは大幅に改造されています。
|
||
使用する場合の上記URLの配布サイト元から取るようにしてください。
|
||
2024/10/17 西ヤスアキ
|
||
連絡先 @nishi_ak1
|
||
mail: nishi_aki11@gmail.com
|
||
|
||
シーンが呼ばれたときのアクティブになるウィンドウをthis._windowActorInfoに変えています。
|
||
で、そのウィンドウにsethundlerで上下左右キャンセルなどの操作を付けてます。
|
||
this._windowActorInfo →(ok)→ this._windowTypeSelect
|
||
!!!!!!!!!!!!!!!!!!!!!!!!!
|
||
|
||
|
||
スキルツリーを導入するプラグインです。
|
||
設定方法については、「SkillTreeConfig.js」を参照してください。
|
||
|
||
|
||
[ライセンス]
|
||
このプラグインは、MITライセンスの条件の下で利用可能です。
|
||
*/
|
||
|
||
const SkillTreePluginName =
|
||
document.currentScript.src.match(/^.*\/(.+)\.js$/)[1];
|
||
let $skillTreeData = null;
|
||
let $skillTreeConfigLoader = null;
|
||
const $skillTreeMapLoaders = {};
|
||
|
||
const skt_open = (actorId) => {
|
||
$gameParty.setMenuActor($gameActors.actor(actorId));
|
||
SceneManager.push(SkillTreeClassAlias.Scene_SkillTree);
|
||
};
|
||
|
||
const skt_gainSp = (actorId, value) => {
|
||
const actor = $gameParty
|
||
.members()
|
||
.find((actor) => actor.actorId() === actorId);
|
||
if (actor) actor.gainSp(value);
|
||
};
|
||
|
||
const skt_skillReset = (actorId) => {
|
||
const totalSp = $skillTreeData.totalSpAllTypes(actorId);
|
||
$skillTreeData.skillResetAllTypes(actorId);
|
||
$skillTreeData.gainSp(actorId, totalSp);
|
||
};
|
||
|
||
const skt_totalSp = (actorId, variableId) => {
|
||
const totalSp = $skillTreeData.totalSpAllTypes(actorId);
|
||
$gameVariables.setValue(variableId, totalSp);
|
||
};
|
||
|
||
const skt_learn = (actorId, typeName, skillId, force = false) => {
|
||
const types = $skillTreeData.types(actorId);
|
||
const findedType = types.find((type) => type.skillTreeName() === typeName);
|
||
if (!findedType) return;
|
||
if (force) {
|
||
$skillTreeData.forceOpenNode(findedType, skillId);
|
||
} else {
|
||
$skillTreeData.openNode(findedType, skillId);
|
||
}
|
||
};
|
||
|
||
const skt_enableType = (actorId, typeName) => {
|
||
const types = $skillTreeData.types(actorId);
|
||
let targetType = null;
|
||
for (const type of types) {
|
||
if (type.skillTreeName() === typeName) {
|
||
targetType = type;
|
||
}
|
||
}
|
||
if (!targetType) return;
|
||
targetType.setEnabled(true);
|
||
};
|
||
|
||
const skt_disableType = (actorId, typeName) => {
|
||
const types = $skillTreeData.types(actorId);
|
||
let targetType = null;
|
||
for (const type of types) {
|
||
if (type.skillTreeName() === typeName) {
|
||
targetType = type;
|
||
}
|
||
}
|
||
if (!targetType) return;
|
||
targetType.setEnabled(false);
|
||
};
|
||
|
||
const skt_migrationType = (actorId, fromTypeName, toTypeName, reset) => {
|
||
let dstType = null;
|
||
let srcType = null;
|
||
const types = $skillTreeData.types(actorId);
|
||
for (const type of types) {
|
||
if (type.skillTreeName() === fromTypeName) {
|
||
srcType = type;
|
||
} else if (type.skillTreeName() === toTypeName) {
|
||
dstType = type;
|
||
}
|
||
}
|
||
if (!dstType || !srcType) return;
|
||
srcType.setEnabled(false);
|
||
dstType.setEnabled(true);
|
||
if (reset) {
|
||
const resetSp = $skillTreeData.totalSp(srcType);
|
||
$skillTreeData.skillReset(srcType);
|
||
$skillTreeData.gainSp(actorId, resetSp);
|
||
} else {
|
||
$skillTreeData.copyTree(dstType, srcType);
|
||
$skillTreeData.skillReset(srcType);
|
||
}
|
||
};
|
||
|
||
const SkillTreeClassAlias = (() => {
|
||
"use strict";
|
||
|
||
const params = PluginManager.parameters(SkillTreePluginName);
|
||
const SpName = params["SpName"];
|
||
const MaxSp = parseInt(params["MaxSp"]);
|
||
|
||
const EnableGetSpWhenBattleEnd =
|
||
params["EnableGetSpWhenBattleEnd"] === "true" ? true : false;
|
||
const EnableGetSpWhenLevelUp =
|
||
params["EnableGetSpWhenLevelUp"] === "true" ? true : false;
|
||
const EnabledSkillTreeSwitchId = parseInt(params["EnabledSkillTreeSwitchId"]);
|
||
const EnableMZLayout = params["EnableMZLayout"] === "true" ? true : false;
|
||
|
||
const ViewMode = params["ViewMode"];
|
||
const IconWidth = parseInt(params["IconWidth"]);
|
||
const IconHeight = parseInt(params["IconHeight"]);
|
||
const IconSpaceWidth = parseInt(params["IconSpaceWidth"]);
|
||
const IconSpaceHeight = parseInt(params["IconSpaceHeight"]);
|
||
const ViewLineWidth = parseInt(params["ViewLineWidth"]);
|
||
const ViewLineColorBase = params["ViewLineColorBase"];
|
||
const ViewLineColorLearned = params["ViewLineColorLearned"];
|
||
const ViewBeginXOffset = parseInt(params["ViewBeginXOffset"]);
|
||
const ViewBeginYOffset = parseInt(params["ViewBeginYOffset"]);
|
||
const ViewCursorOfs = parseInt(params["ViewCursorOfs"]);
|
||
const ViewRectOfs = parseInt(params["ViewRectOfs"]);
|
||
const ViewRectColor = params["ViewRectColor"];
|
||
|
||
const LearnSkillSeFileName = params["LearnSkillSeFileName"];
|
||
const LearnSkillSeVolume = parseInt(params["LearnSkillSeVolume"]);
|
||
const LearnSkillSePitch = parseInt(params["LearnSkillSePitch"]);
|
||
const LearnSkillSePan = parseInt(params["LearnSkillSePan"]);
|
||
|
||
const MenuSkillTreeText = params["MenuSkillTreeText"];
|
||
const NeedSpText = params["NeedSpText"];
|
||
const OpenedNodeText = params["OpenedNodeText"];
|
||
const NodeOpenConfirmationText = params["NodeOpenConfirmationText"];
|
||
const NodeOpenYesText = params["NodeOpenYesText"];
|
||
const NodeOpenNoText = params["NodeOpenNoText"];
|
||
const NodeCloseConfirmationText = params["NodeCloseConfirmationText"];
|
||
const NodeCloseYesText = params["NodeCloseYesText"];
|
||
const NodeCloseNoText = params["NodeCloseNoText"];
|
||
const BattleEndGetSpText = params["BattleEndGetSpText"];
|
||
const LevelUpGetSpText = params["LevelUpGetSpText"];
|
||
|
||
class HttpResponse {
|
||
constructor(result, xhr, event) {
|
||
this._result = result;
|
||
this._xhr = xhr;
|
||
this._event = event;
|
||
}
|
||
|
||
result() {
|
||
return this._result;
|
||
}
|
||
|
||
status() {
|
||
return this._xhr.status;
|
||
}
|
||
|
||
response() {
|
||
return this._xhr.response;
|
||
}
|
||
}
|
||
|
||
class HttpRequest {
|
||
static get(path, opt, responseCallback) {
|
||
const req = new HttpRequest(path, "GET", opt, responseCallback);
|
||
req.send();
|
||
return req;
|
||
}
|
||
|
||
static post(path, params, opt, responseCallback) {
|
||
const req = new HttpRequest(path, "POST", opt, responseCallback);
|
||
req.send(params);
|
||
return req;
|
||
}
|
||
|
||
constructor(path, method, opt, responseCallback) {
|
||
this._path = path;
|
||
this._method = method;
|
||
this._responseCallback = responseCallback;
|
||
this._mimeType = opt.mimeType;
|
||
}
|
||
|
||
send(params = null) {
|
||
const xhr = new XMLHttpRequest();
|
||
xhr.open(this._method, this._path);
|
||
if (this._mimeType) xhr.overrideMimeType(this._mimeType);
|
||
let json = null;
|
||
if (params) json = JSON.stringify(params);
|
||
xhr.addEventListener("load", (e) => {
|
||
this._responseCallback(new HttpResponse("load", xhr, e));
|
||
});
|
||
xhr.addEventListener("error", (e) => {
|
||
this._responseCallback(new HttpResponse("error", xhr, e));
|
||
});
|
||
xhr.send(json);
|
||
}
|
||
}
|
||
|
||
class SkillTreeNodeInfo {
|
||
constructor(actorId, skillId, needSp, iconData, helpMessage) {
|
||
this._actorId = actorId;
|
||
this._skillId = skillId;
|
||
this._needSp = needSp;
|
||
this._iconData = iconData;
|
||
this._helpMessage = helpMessage;
|
||
}
|
||
|
||
actorId() {
|
||
return this._actorId;
|
||
}
|
||
|
||
actor() {
|
||
const actor = $gameActors.actor(this._actorId);
|
||
if (!actor) throw new Error(`actor id: ${this._actorId} is not found.`);
|
||
return actor;
|
||
}
|
||
|
||
skillId() {
|
||
return this._skillId;
|
||
}
|
||
|
||
skill() {
|
||
const skill = $dataSkills[this._skillId];
|
||
if (!skill) throw new Error(`skill id: ${this._skillId} is not found.`);
|
||
return skill;
|
||
}
|
||
|
||
canLearn(nowSp) {
|
||
return nowSp >= this._needSp;
|
||
}
|
||
|
||
learnSkill() {
|
||
this.actor().learnSkill(this._skillId);
|
||
}
|
||
|
||
forgetSkill() {
|
||
this.actor().forgetSkill(this._skillId);
|
||
}
|
||
|
||
trimIconset(iconIndex) {
|
||
const srcBitmap = ImageManager.loadSystem("IconSet");
|
||
const dstBitmap = new Bitmap(32, 32);
|
||
const sx = (iconIndex % 16) * 32;
|
||
const sy = Math.floor(iconIndex / 16) * 32;
|
||
dstBitmap.blt(srcBitmap, sx, sy, 32, 32, 0, 0);
|
||
return dstBitmap;
|
||
}
|
||
|
||
iconBitmap() {
|
||
if (this._iconData[0] === "img") {
|
||
return ImageManager.loadPicture(this._iconData[1]);
|
||
} else if (this._iconData[0] === "icon") {
|
||
let iconIndex;
|
||
if (this._iconData.length >= 2) {
|
||
iconIndex = this._iconData[1];
|
||
} else {
|
||
iconIndex = this.skill().iconIndex;
|
||
}
|
||
return this.trimIconset(iconIndex);
|
||
}
|
||
throw new Error(`Unknown ${this._iconData[0]}`);
|
||
}
|
||
|
||
checkIconBitmapReady() {
|
||
if (this._iconData[0] === "img") {
|
||
const bitmap = ImageManager.loadPicture(this._iconData[1]);
|
||
if (!bitmap.isReady()) return false;
|
||
} else if (this._iconData[0] === "icon") {
|
||
const iconSet = ImageManager.loadSystem("IconSet");
|
||
if (!iconSet.isReady()) return false;
|
||
} else if (this._iconData[0] === "icon_ex") {
|
||
const iconSet = ImageManager.loadSystem("IconSet");
|
||
if (!iconSet.isReady()) return false;
|
||
if (typeof this._iconData[1] === "string") {
|
||
const backBitmap = ImageManager.loadPicture(this._iconData[1]);
|
||
if (!backBitmap.isReady()) return false;
|
||
} else {
|
||
const backBitmap = ImageManager.loadPicture(this._iconData[1][0]);
|
||
if (!backBitmap.isReady()) return false;
|
||
}
|
||
} else {
|
||
throw new Error(`Unknown ${this._iconData[0]}`);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
needSp() {
|
||
return this._needSp;
|
||
}
|
||
|
||
helpMessage() {
|
||
return this._helpMessage;
|
||
}
|
||
}
|
||
|
||
class SkillTreeNode {
|
||
constructor(tag) {
|
||
this._tag = tag;
|
||
this._parents = [];
|
||
this._childs = [];
|
||
this._info = null;
|
||
this._opened = false;
|
||
this._point = null;
|
||
this._reservedPoint = null;
|
||
}
|
||
|
||
get point() {
|
||
return this._point;
|
||
}
|
||
set point(_point) {
|
||
this._point = _point;
|
||
}
|
||
|
||
tag() {
|
||
return this._tag;
|
||
}
|
||
|
||
info() {
|
||
return this._info;
|
||
}
|
||
|
||
reservedPoint() {
|
||
return this._reservedPoint;
|
||
}
|
||
|
||
setReservedPoint(point) {
|
||
this._reservedPoint = point;
|
||
}
|
||
|
||
parents() {
|
||
return this._parents;
|
||
}
|
||
|
||
childs() {
|
||
return this._childs;
|
||
}
|
||
|
||
getAllChilds() {
|
||
let allChilds = [this];
|
||
for (const child of this._childs) {
|
||
allChilds = allChilds.concat(child.getAllChilds());
|
||
}
|
||
return allChilds;
|
||
}
|
||
|
||
parent(index) {
|
||
if (index < 0) index = this._parents.length - index;
|
||
return this._parents[index % this._parents.length];
|
||
}
|
||
|
||
child(index) {
|
||
if (index < 0) index = this._childs.length - index;
|
||
return this._childs[index % this._childs.length];
|
||
}
|
||
|
||
addChild(child) {
|
||
if (!child) throw new Error("child is none.");
|
||
child._parents.push(this);
|
||
this._childs.push(child);
|
||
}
|
||
|
||
setup(info) {
|
||
this._info = info;
|
||
}
|
||
|
||
isOpenable() {
|
||
// スキルツリーをOKしたときにスキルが取得可能かどうかを判定
|
||
// ノードがすでに開放されている場合はダメ
|
||
if (this.isOpened()) {
|
||
return false;
|
||
}
|
||
// SPが足りるかを判定
|
||
if (this.canCostConsumption()) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
isSelectable() {
|
||
for (const parent of this._parents) {
|
||
if (!parent.isOpened()) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
isOpened() {
|
||
return this._opened;
|
||
}
|
||
|
||
setOpenedStatus(openStatus) {
|
||
this._opened = openStatus;
|
||
}
|
||
|
||
open(costConsume = true) {
|
||
// 複数の親ノードが存在する場合、それぞれをチェック
|
||
if (this._parents !== undefined && this._parents.length !== 0) {
|
||
this._parents.forEach((parent) => {
|
||
if (!parent._opened) {
|
||
parent.open(); // 未開放の親ノードを先に開放
|
||
}
|
||
});
|
||
}
|
||
|
||
// 現在のノードを解放
|
||
this._info.learnSkill();
|
||
if (costConsume) this.costConsumption();
|
||
this._opened = true;
|
||
}
|
||
|
||
close() {
|
||
// 複数の親ノードが存在する場合、それぞれをチェック
|
||
if (this._childs !== undefined && this._childs.length !== 0) {
|
||
this._childs.forEach((child) => {
|
||
if (child._opened) {
|
||
child.close(); // 未開放の親ノードを先に開放
|
||
}
|
||
});
|
||
}
|
||
|
||
this._info.forgetSkill();
|
||
this.costReturn();
|
||
this._opened = false;
|
||
}
|
||
|
||
canCostConsumption() {
|
||
const actorId = this._info.actorId();
|
||
return $skillTreeData.sp(actorId) >= this.needSp();
|
||
}
|
||
|
||
costConsumption() {
|
||
const actorId = this._info.actorId();
|
||
$skillTreeData.gainSp(actorId, -this.needSp());
|
||
}
|
||
|
||
costReturn() {
|
||
const actorId = this._info.actorId();
|
||
$skillTreeData.gainSp(actorId, this.needSp());
|
||
}
|
||
|
||
clearPointNode() {
|
||
this.point = null;
|
||
if (this._childs.length === 0) return;
|
||
for (const child of this._childs) {
|
||
child.clearPointNode();
|
||
}
|
||
}
|
||
|
||
makePointNode(x, y, mode) {
|
||
if (this.reservedPoint()) {
|
||
this.point = this.reservedPoint();
|
||
x = this.reservedPoint().x;
|
||
y = this.reservedPoint().y;
|
||
} else {
|
||
if (this.point) {
|
||
if (mode === "wide") {
|
||
if (x < this.point.x) {
|
||
this.point = { x: this.point.x, y: y };
|
||
} else {
|
||
this.point = { x: x, y: this.point.y };
|
||
}
|
||
} else if (mode === "long") {
|
||
if (y < this.point.y) {
|
||
this.point = { x: x, y: this.point.y };
|
||
} else {
|
||
this.point = { x: this.point.x, y: y };
|
||
}
|
||
}
|
||
} else {
|
||
this.point = { x: x, y: y };
|
||
}
|
||
}
|
||
if (this._childs.length === 0) return 1;
|
||
if (mode === "wide") {
|
||
let yOfs = 0;
|
||
for (const child of this._childs) {
|
||
yOfs += child.makePointNode(x + 1, y + yOfs, mode);
|
||
}
|
||
return yOfs;
|
||
} else if (mode === "long") {
|
||
let xOfs = 0;
|
||
for (const child of this._childs) {
|
||
xOfs += child.makePointNode(x + xOfs, y + 1, mode);
|
||
}
|
||
return xOfs;
|
||
}
|
||
}
|
||
|
||
needSp() {
|
||
// 現在選択されているノードとその親ノードを含むSPを合計
|
||
let totalSp = this._info.needSp(); // 最初に現在選択されているスキルノードのSPを取得
|
||
|
||
// 親ノードが未習得の場合、その親ノードのSPを合算する
|
||
if (this._parents && this._parents.length > 0) {
|
||
for (let parent of this._parents) {
|
||
if (!parent.isOpened()) {
|
||
// 親ノードが未習得の場合
|
||
totalSp += parent.needSp(); // 親ノードのSPを合算
|
||
}
|
||
}
|
||
}
|
||
|
||
return totalSp; // 合算したSPを返す
|
||
}
|
||
|
||
iconBitmap() {
|
||
return this._info.iconBitmap();
|
||
}
|
||
|
||
checkIconBitmapReady() {
|
||
return this._info.checkIconBitmapReady();
|
||
}
|
||
|
||
helpMessage() {
|
||
return this._info.helpMessage();
|
||
}
|
||
}
|
||
|
||
class SkillTreeTopNode extends SkillTreeNode {
|
||
constructor() {
|
||
super(null);
|
||
this._opened = true;
|
||
const dummyInfo = new SkillTreeNodeInfo(null, null, 0, 0, "");
|
||
this.setup(dummyInfo);
|
||
}
|
||
|
||
getAllChilds() {
|
||
let allChilds = [];
|
||
for (const child of this._childs) {
|
||
allChilds = allChilds.concat(child.getAllChilds());
|
||
}
|
||
return allChilds;
|
||
}
|
||
|
||
skillReset() {
|
||
for (const child of this._childs) {
|
||
if (child.isOpened()) child.skillReset();
|
||
}
|
||
}
|
||
}
|
||
|
||
class SkillDataType {
|
||
constructor(skillTreeName, actorId, message, helpMessage, enabled) {
|
||
this._skillTreeName = skillTreeName;
|
||
this._actorId = actorId;
|
||
this._message = message;
|
||
this._helpMessage = helpMessage;
|
||
this._enabled = enabled;
|
||
}
|
||
|
||
message() {
|
||
return this._message;
|
||
}
|
||
|
||
skillTreeName() {
|
||
return this._skillTreeName;
|
||
}
|
||
|
||
skillTreeTag() {
|
||
return `${this._skillTreeName}_actorId${this._actorId}`;
|
||
}
|
||
|
||
helpMessage() {
|
||
return this._helpMessage;
|
||
}
|
||
|
||
enabled() {
|
||
return this._enabled;
|
||
}
|
||
|
||
setEnabled(enabled) {
|
||
this._enabled = enabled;
|
||
}
|
||
}
|
||
|
||
class SkillTreeMapLoader {
|
||
constructor(mapId) {
|
||
this._mapId = mapId;
|
||
this._mapData = null;
|
||
}
|
||
|
||
applyMapData(type) {
|
||
const allNodes = $skillTreeData.getAllNodesByType(type);
|
||
for (const eventData of this.mapData().events) {
|
||
if (!eventData) continue;
|
||
let nodeTag = eventData.note;
|
||
let node = allNodes[nodeTag];
|
||
if (!node) continue;
|
||
node.setReservedPoint({ x: eventData.x, y: eventData.y });
|
||
}
|
||
}
|
||
|
||
isLoaded() {
|
||
return this._response;
|
||
}
|
||
|
||
mapData() {
|
||
return JSON.parse(this._response);
|
||
}
|
||
|
||
loadMap() {
|
||
const fileName = "Map%1.json".format(this._mapId.padZero(3));
|
||
this.loadData(fileName);
|
||
}
|
||
|
||
loadData(fileName) {
|
||
HttpRequest.get(
|
||
`data/${fileName}`,
|
||
{ mimeType: "application/json" },
|
||
(res) => {
|
||
if (res.result() === "error") {
|
||
throw new Error(`Unknow file: ${fileName}`);
|
||
} else if (res.status() === 200) {
|
||
this._response = res.response();
|
||
} else {
|
||
throw new Error(`Load failed: ${fileName}`);
|
||
}
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
class SkillTreeConfigLoadError extends Error {}
|
||
|
||
class SkillTreeConfigLoader {
|
||
constructor() {
|
||
this._configData = loadSkillTreeConfig();
|
||
}
|
||
|
||
configData() {
|
||
return this._configData;
|
||
}
|
||
|
||
loadConfig(actorId) {
|
||
let types = $skillTreeData.types(actorId);
|
||
if (!types) {
|
||
types = this.loadTypes(actorId);
|
||
$skillTreeData.setTypes(actorId, types);
|
||
}
|
||
for (const type of types) {
|
||
let topNode = $skillTreeData.topNode(type);
|
||
if (!topNode) {
|
||
topNode = this.loadSkillTreeNodes(type);
|
||
$skillTreeData.setTopNode(type, topNode);
|
||
this.loadSkillTreeInfo(
|
||
actorId,
|
||
$skillTreeData.getAllNodesByType(type)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
loadTypes(actorId) {
|
||
let cfgTypes = null;
|
||
let typesArray = [];
|
||
for (const cfg of this._configData.skillTreeTypes) {
|
||
if (cfg.actorId === actorId) {
|
||
cfgTypes = cfg.types;
|
||
break;
|
||
}
|
||
}
|
||
if (!cfgTypes) return [];
|
||
for (const cfgType of cfgTypes) {
|
||
const enabled = cfgType.length === 3 ? true : cfgType[3];
|
||
typesArray.push(
|
||
new SkillDataType(
|
||
cfgType[0],
|
||
actorId,
|
||
cfgType[1],
|
||
cfgType[2],
|
||
enabled
|
||
)
|
||
);
|
||
}
|
||
return typesArray;
|
||
}
|
||
|
||
loadSkillTreeNodes(type) {
|
||
const nodes = {};
|
||
let derivative = null;
|
||
for (const skillTreeType in this._configData.skillTreeDerivative) {
|
||
if (skillTreeType === type.skillTreeName()) {
|
||
derivative = this._configData.skillTreeDerivative[skillTreeType];
|
||
break;
|
||
}
|
||
}
|
||
if (!derivative)
|
||
throw new SkillTreeConfigLoadError(
|
||
`Missing skill type name ${type.skillTreeName()}`
|
||
);
|
||
for (const data of derivative) {
|
||
const nodeTag = data[0];
|
||
nodes[nodeTag] = new SkillTreeNode(nodeTag);
|
||
}
|
||
for (const data of derivative) {
|
||
const nodeTag = data[0];
|
||
if (data.length >= 2) {
|
||
const childsTag = data[1];
|
||
for (const childTag of childsTag) {
|
||
if (!nodes[childTag])
|
||
throw new SkillTreeConfigLoadError(
|
||
`Unknow derivative ${childTag}`
|
||
);
|
||
nodes[nodeTag].addChild(nodes[childTag]);
|
||
}
|
||
}
|
||
}
|
||
const topNode = new SkillTreeTopNode();
|
||
for (const node of Object.values(nodes)) {
|
||
if (node.parents().length === 0) topNode.addChild(node);
|
||
}
|
||
if (topNode.length === 0)
|
||
throw new SkillTreeConfigLoadError(`Missing top nodes`);
|
||
return topNode;
|
||
}
|
||
|
||
loadSkillTreeInfo(actorId, allNodes) {
|
||
for (const cfgInfoKey in this._configData.skillTreeInfo) {
|
||
const cfgInfo = this._configData.skillTreeInfo[cfgInfoKey];
|
||
const nodeTag = cfgInfo[0];
|
||
const node = allNodes[nodeTag];
|
||
if (!node) continue;
|
||
const skillId = cfgInfo[1];
|
||
const needSp = cfgInfo[2];
|
||
let iconData = ["icon"];
|
||
if (cfgInfo.length >= 4) iconData = cfgInfo[3];
|
||
let helpMessage = "";
|
||
if (cfgInfo.length >= 5) helpMessage = cfgInfo[4];
|
||
const info = new SkillTreeNodeInfo(
|
||
actorId,
|
||
skillId,
|
||
needSp,
|
||
iconData,
|
||
helpMessage
|
||
);
|
||
node.setup(info);
|
||
}
|
||
for (const node of Object.values(allNodes)) {
|
||
if (!node.info())
|
||
throw new SkillTreeConfigLoadError(
|
||
`Node ${node.tag()} is missing node info`
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
class SkillTreeData {
|
||
constructor() {
|
||
this._actorSp = {};
|
||
this._topNodes = {};
|
||
this._allTypes = {};
|
||
}
|
||
|
||
actorIds() {
|
||
return Object.keys(this._actorSp);
|
||
}
|
||
|
||
sp(actorId) {
|
||
return this._actorSp[actorId];
|
||
}
|
||
|
||
setSp(actorId, sp) {
|
||
this._actorSp[actorId] = sp;
|
||
}
|
||
|
||
gainSp(actorId, sp) {
|
||
const nowSp = this.sp(actorId);
|
||
this.setSp(actorId, nowSp + sp);
|
||
}
|
||
|
||
topNode(type) {
|
||
return this._topNodes[type.skillTreeTag()];
|
||
}
|
||
|
||
setTopNode(type, topNode) {
|
||
this._topNodes[type.skillTreeTag()] = topNode;
|
||
}
|
||
|
||
types(actorId) {
|
||
return this._allTypes[actorId];
|
||
}
|
||
|
||
enableTypes(actorId) {
|
||
return this.types(actorId).filter((type) => type.enabled());
|
||
}
|
||
|
||
setTypes(actorId, types) {
|
||
this._allTypes[actorId] = types;
|
||
}
|
||
|
||
totalSp(type) {
|
||
let resetSp = 0;
|
||
for (const node of Object.values(this.getAllNodesByType(type))) {
|
||
if (node.isOpened()) resetSp += node.needSp();
|
||
}
|
||
return resetSp;
|
||
}
|
||
|
||
skillReset(type) {
|
||
for (const node of Object.values(this.getAllNodesByType(type))) {
|
||
if (node.isOpened()) node.close();
|
||
}
|
||
}
|
||
|
||
totalSpAllTypes(actorId) {
|
||
let resetSp = 0;
|
||
for (const type of this.enableTypes(actorId)) {
|
||
resetSp += this.totalSp(type);
|
||
}
|
||
return resetSp;
|
||
}
|
||
|
||
skillResetAllTypes(actorId) {
|
||
for (const type of this.enableTypes(actorId)) {
|
||
this.skillReset(type);
|
||
}
|
||
}
|
||
|
||
copyTree(dstType, srcType) {
|
||
const dst = this.getAllNodesByType(dstType);
|
||
const src = this.getAllNodesByType(srcType);
|
||
for (const tag in src) {
|
||
const srcNode = src[tag];
|
||
const dstNode = dst[tag];
|
||
if (srcNode && dstNode && srcNode.isOpened()) {
|
||
srcNode.close();
|
||
dstNode.open(false);
|
||
}
|
||
}
|
||
}
|
||
|
||
openNode(type, skillId) {
|
||
for (const node of this.topNode(type).getAllChilds()) {
|
||
if (node.info().skillId() === skillId && node.isOpenable()) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
forceOpenNode(type, skillId) {
|
||
for (const node of this.topNode(type).getAllChilds()) {
|
||
if (node.info().skillId() === skillId) {
|
||
node.open(false);
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
makePoint(type, mode) {
|
||
this.topNode(type).clearPointNode();
|
||
// Start point is -1 because first node is dummy.
|
||
if (mode === "wide") {
|
||
this.topNode(type).makePointNode(-1, 0, mode);
|
||
} else if (mode === "long") {
|
||
this.topNode(type).makePointNode(0, -1, mode);
|
||
} else {
|
||
throw new Error(`Unknown ${ViewMode}`);
|
||
}
|
||
}
|
||
|
||
getAllNodesByType(type) {
|
||
const nodes = {};
|
||
for (const node of this.topNode(type).getAllChilds()) {
|
||
nodes[node.tag()] = node;
|
||
}
|
||
return nodes;
|
||
}
|
||
|
||
makeSaveContents() {
|
||
let contents = {};
|
||
for (const actorId of this.actorIds()) {
|
||
contents[actorId] = { sp: this.sp(actorId) };
|
||
for (const type of this.types(actorId)) {
|
||
const openedStatus = {};
|
||
const nodes = this.getAllNodesByType(type);
|
||
for (const tag in nodes) {
|
||
openedStatus[tag] = nodes[tag].isOpened();
|
||
}
|
||
contents[type.skillTreeTag()] = {
|
||
enabled: type.enabled(),
|
||
openedStatus: openedStatus,
|
||
};
|
||
}
|
||
}
|
||
return contents;
|
||
}
|
||
|
||
loadSaveContents(contents) {
|
||
for (let actorId = 1; actorId < $dataActors.length; actorId++) {
|
||
if (!contents[actorId]) continue;
|
||
$skillTreeConfigLoader.loadConfig(actorId);
|
||
this.setSp(actorId, contents[actorId].sp);
|
||
for (const type of this.types(actorId)) {
|
||
type.setEnabled(contents[type.skillTreeTag()].enabled);
|
||
const nodes = this.getAllNodesByType(type);
|
||
for (const tag in nodes) {
|
||
nodes[tag].setOpenedStatus(
|
||
contents[type.skillTreeTag()].openedStatus[tag]
|
||
);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
class SkillTreeManager {
|
||
constructor() {
|
||
this.reset();
|
||
}
|
||
|
||
reset() {
|
||
this._actorId = null;
|
||
this._type = null;
|
||
this._selectNode = null;
|
||
}
|
||
|
||
topNode() {
|
||
return $skillTreeData.topNode(this._type);
|
||
}
|
||
|
||
selectTopNode(topNode) {
|
||
this.select(topNode.child(0));
|
||
}
|
||
|
||
type() {
|
||
return this._type;
|
||
}
|
||
|
||
actorId() {
|
||
return this._actorId;
|
||
}
|
||
|
||
setType(type) {
|
||
this._type = type;
|
||
}
|
||
|
||
setActorId(actorId) {
|
||
this._actorId = actorId;
|
||
}
|
||
|
||
selectNode() {
|
||
if (!this._selectNode) throw new Error("selectNode is null");
|
||
return this._selectNode;
|
||
}
|
||
|
||
changeChildNode() {
|
||
const nextNode = this._selectNode.child(0);
|
||
if (nextNode) {
|
||
this._selectNode = nextNode;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
changeParentNode() {
|
||
const nextNode = this._selectNode.parent(0);
|
||
if (nextNode && !(nextNode instanceof SkillTreeTopNode)) {
|
||
this._selectNode = nextNode;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
changeNextNode() {
|
||
const parent = this._selectNode.parent(0);
|
||
if (!parent) throw new Error("Unknown parent");
|
||
const i = parent.childs().indexOf(this._selectNode);
|
||
const nextNode = parent.child(i + 1);
|
||
if (nextNode !== this._selectNode) {
|
||
this._selectNode = nextNode;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
changePrevNode() {
|
||
const parent = this._selectNode.parent(0);
|
||
if (!parent) throw new Error("Unknown parent");
|
||
const i = parent.childs().indexOf(this._selectNode);
|
||
const nextNode = parent.child(i - 1);
|
||
if (nextNode !== this._selectNode) {
|
||
this._selectNode = nextNode;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
maxXY() {
|
||
let maxX = 0;
|
||
let maxY = 0;
|
||
const nodes = this.getAllNodes();
|
||
for (const node of Object.values(nodes)) {
|
||
const x = node.point.x;
|
||
const y = node.point.y;
|
||
if (x > maxX) maxX = x;
|
||
if (y > maxY) maxY = y;
|
||
}
|
||
return [maxX, maxY];
|
||
}
|
||
|
||
searchNode(xWay, yWay) {
|
||
const nodes = Object.values(this.getAllNodes());
|
||
if (xWay !== 0) {
|
||
let candidates = nodes.filter(
|
||
(node) => node.point.y === this._selectNode.point.y
|
||
);
|
||
if (candidates.length === 0) {
|
||
return null;
|
||
} else if (xWay === 1) {
|
||
candidates = candidates.filter(
|
||
(node) => node.point.x > this._selectNode.point.x
|
||
);
|
||
const fars = candidates.map(
|
||
(candidate) => candidate.point.x - this._selectNode.point.x
|
||
);
|
||
const i = fars.indexOf(Math.min(...fars));
|
||
return candidates[i];
|
||
} else if (xWay === -1) {
|
||
candidates = candidates.filter(
|
||
(node) => node.point.x < this._selectNode.point.x
|
||
);
|
||
const fars = candidates.map(
|
||
(candidate) => candidate.point.x - this._selectNode.point.x
|
||
);
|
||
const i = fars.indexOf(Math.max(...fars));
|
||
return candidates[i];
|
||
}
|
||
} else if (yWay !== 0) {
|
||
let candidates = nodes.filter(
|
||
(node) => node.point.x === this._selectNode.point.x
|
||
);
|
||
if (candidates.length === 0) {
|
||
return null;
|
||
} else if (yWay === 1) {
|
||
candidates = candidates.filter(
|
||
(node) => node.point.y > this._selectNode.point.y
|
||
);
|
||
const fars = candidates.map(
|
||
(candidate) => candidate.point.y - this._selectNode.point.y
|
||
);
|
||
const i = fars.indexOf(Math.min(...fars));
|
||
return candidates[i];
|
||
} else if (yWay === -1) {
|
||
candidates = candidates.filter(
|
||
(node) => node.point.y < this._selectNode.point.y
|
||
);
|
||
const fars = candidates.map(
|
||
(candidate) => candidate.point.y - this._selectNode.point.y
|
||
);
|
||
const i = fars.indexOf(Math.max(...fars));
|
||
return candidates[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
right() {
|
||
const node = this.searchNode(1, 0);
|
||
if (node) {
|
||
this._selectNode = node;
|
||
return true;
|
||
}
|
||
if (ViewMode === "wide") {
|
||
return this.changeChildNode();
|
||
} else if (ViewMode === "long") {
|
||
return this.changeNextNode();
|
||
}
|
||
}
|
||
|
||
left() {
|
||
const node = this.searchNode(-1, 0);
|
||
if (node) {
|
||
this._selectNode = node;
|
||
return true;
|
||
}
|
||
if (ViewMode === "wide") {
|
||
return this.changeParentNode();
|
||
} else if (ViewMode === "long") {
|
||
return this.changePrevNode();
|
||
}
|
||
}
|
||
|
||
up() {
|
||
const node = this.searchNode(0, -1);
|
||
if (node) {
|
||
this._selectNode = node;
|
||
return true;
|
||
}
|
||
if (ViewMode === "wide") {
|
||
return this.changePrevNode();
|
||
} else if (ViewMode === "long") {
|
||
return this.changeParentNode();
|
||
}
|
||
}
|
||
|
||
down() {
|
||
const node = this.searchNode(0, 1);
|
||
if (node) {
|
||
this._selectNode = node;
|
||
return true;
|
||
}
|
||
if (ViewMode === "wide") {
|
||
return this.changeNextNode();
|
||
} else if (ViewMode === "long") {
|
||
return this.changeChildNode();
|
||
}
|
||
}
|
||
|
||
select(node) {
|
||
if (node !== this._selectNode) {
|
||
this._selectNode = node;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
isSelectNodeOpenable() {
|
||
return this._selectNode.isOpenable();
|
||
}
|
||
|
||
selectNodeOpen() {
|
||
this._selectNode.open();
|
||
}
|
||
|
||
selectNodeClose() {
|
||
this._selectNode.close();
|
||
}
|
||
|
||
makePoint() {
|
||
$skillTreeData.makePoint(this._type, ViewMode);
|
||
}
|
||
|
||
getAllNodes() {
|
||
return $skillTreeData.getAllNodesByType(this._type);
|
||
}
|
||
}
|
||
|
||
class Scene_SkillTree extends Scene_MenuBase {
|
||
create() {
|
||
super.create();
|
||
this._operating = false;
|
||
this._skillTreeManager = new SkillTreeManager($skillTreeData);
|
||
this.updateActor();
|
||
this.createHelpWindow();
|
||
this.createTypeSelectWindow();
|
||
this.createActorInfoWindow();
|
||
this._windowActorInfo.activate();
|
||
this.updateSkillTree();
|
||
this.createSkillTreeNodeInfo();
|
||
this.createSKillTreeWindow();
|
||
this.createNodeOpenWindow();
|
||
this.createNodeCloseWindow();
|
||
this.createCommandSkillResetWindow();
|
||
this.applyMapDatas();
|
||
this.createSpriteset();
|
||
}
|
||
|
||
isReady() {
|
||
let ready = true;
|
||
|
||
if (!super.isReady()) ready = false;
|
||
|
||
for (const actor of $gameParty.members()) {
|
||
const faceImage = ImageManager.loadFace(actor.faceName());
|
||
if (!faceImage.isReady()) ready = false;
|
||
}
|
||
// Do not use flatMap because some browsers do not support it.
|
||
for (const actor of $gameParty.members()) {
|
||
for (const type of $skillTreeData.types(actor.actorId())) {
|
||
for (const node of Object.values(
|
||
$skillTreeData.getAllNodesByType(type)
|
||
)) {
|
||
if (!node.checkIconBitmapReady()) ready = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
const menuBackgroundSprite = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_menuBackground"
|
||
);
|
||
if (!menuBackgroundSprite.isReady()) ready = false;
|
||
|
||
return ready;
|
||
}
|
||
|
||
start() {
|
||
super.start();
|
||
this._windowTypeSelect.showHelpWindow();
|
||
this._windowTypeSelect.refresh();
|
||
this._windowTypeSelect.open();
|
||
this._windowTypeSelect.show();
|
||
this._windowActorInfo.refresh();
|
||
this._windowActorInfo.open();
|
||
this._windowActorInfo.show();
|
||
this._windowTypeSelect.deactivate();
|
||
this._windowTypeSelect.deselect();
|
||
this._windowActorInfo.activate();
|
||
this._windowSkillTree.refresh();
|
||
this._windowSkillTree.open();
|
||
this._windowSkillTree.show();
|
||
this._windowSkillTreeNodeInfo.refresh();
|
||
this._windowNodeOpen.refresh();
|
||
this._windowNodeClose.refresh();
|
||
}
|
||
|
||
update() {
|
||
super.update();
|
||
this.updateMenuHPMPbar(this.actor().actorId()); //追加 西ヤスアキ
|
||
}
|
||
|
||
nextActor() {
|
||
$gameParty.makeMenuActorNextOrPreviousWhenSkillTree(true);
|
||
this.updateActor();
|
||
this.onActorChange();
|
||
}
|
||
|
||
previousActor() {
|
||
$gameParty.makeMenuActorNextOrPreviousWhenSkillTree(false);
|
||
this.updateActor();
|
||
this.onActorChange();
|
||
}
|
||
|
||
applyMapDatas() {
|
||
for (const skillTreeName in $skillTreeMapLoaders) {
|
||
for (const actorId of $skillTreeData.actorIds()) {
|
||
const mapLoader = $skillTreeMapLoaders[skillTreeName];
|
||
const type = $skillTreeData
|
||
.types(actorId)
|
||
.find((t) => t.skillTreeName() === skillTreeName);
|
||
if (!type) continue;
|
||
mapLoader.applyMapData(type);
|
||
}
|
||
}
|
||
}
|
||
|
||
createBackground() {
|
||
super.createBackground();
|
||
this._menuBackgroundSprite = new Sprite();
|
||
this._menuBackgroundSpriteUnder = new Sprite();
|
||
this._menuBackgroundSpriteSidePic = new Sprite();
|
||
this._menuBackgroundSprite.bitmap = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_menuBackground"
|
||
);
|
||
this._menuBackgroundSpriteUnder.bitmap = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_under"
|
||
);
|
||
this._menuBackgroundSpriteSidePic.bitmap = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_sidePic"
|
||
);
|
||
this._menuBackgroundSprite.bitmap.addLoadListener(
|
||
function () {
|
||
this._menuBackgroundSprite.x = 342;
|
||
this._menuBackgroundSprite.y = 124;
|
||
}.bind(this)
|
||
);
|
||
this._menuBackgroundSpriteUnder.bitmap.addLoadListener(
|
||
function () {
|
||
this._menuBackgroundSpriteUnder.x = 97;
|
||
this._menuBackgroundSpriteUnder.y = 750;
|
||
}.bind(this)
|
||
);
|
||
this._menuBackgroundSpriteSidePic.bitmap.addLoadListener(
|
||
function () {
|
||
this._menuBackgroundSpriteSidePic.x = 79;
|
||
this._menuBackgroundSpriteSidePic.y = 570;
|
||
}.bind(this)
|
||
);
|
||
this._backgroundSprite.addChild(this._menuBackgroundSprite);
|
||
this._backgroundSprite.addChild(this._menuBackgroundSpriteUnder);
|
||
this._backgroundSprite.addChild(this._menuBackgroundSpriteSidePic);
|
||
}
|
||
|
||
createHelpWindow() {
|
||
const rect = this.helpWindowRect();
|
||
this._helpWindow = new Window_YSAKSkillTreeHelp(rect);
|
||
this.addWindow(this._helpWindow);
|
||
}
|
||
|
||
createTypeSelectWindow() {
|
||
this._windowTypeSelect = new Window_TypeSelect(
|
||
this.typeSelectWindowRect(),
|
||
this.getSkillTreeTypes()
|
||
);
|
||
this.typeSelectWindowSetupHandlers();
|
||
this._windowTypeSelect.close();
|
||
this._windowTypeSelect.deactivate();
|
||
this._windowTypeSelect.hideHelpWindow();
|
||
this._windowTypeSelect.hide();
|
||
this.addWindow(this._windowTypeSelect);
|
||
}
|
||
|
||
resetTypeSelectWindow() {
|
||
this._windowTypeSelect.reset(this.getSkillTreeTypes());
|
||
this.typeSelectWindowSetupHandlers();
|
||
this._windowTypeSelect.refresh();
|
||
this._windowTypeSelect.updateHelp();
|
||
this._windowTypeSelect.deactivate();
|
||
this._windowTypeSelect.deselect();
|
||
this._windowTypeSelect.hideHelpWindow();
|
||
this._windowTypeSelect.show();
|
||
this._windowTypeSelect.showHelpWindow();
|
||
}
|
||
|
||
typeSelectWindowSetupHandlers() {
|
||
this._windowTypeSelect.setHandler("cancel", this.typeCancel.bind(this));
|
||
this._windowTypeSelect.setHandler(
|
||
"select",
|
||
this.updateSkillTree.bind(this)
|
||
);
|
||
// this._windowTypeSelect.setHandler("pagedown", this.nextActor.bind(this));
|
||
// this._windowTypeSelect.setHandler("pageup", this.previousActor.bind(this));
|
||
this._windowTypeSelect.setHelpWindow(this._helpWindow);
|
||
for (let i = 0; i < this.getSkillTreeTypes().length; i++) {
|
||
this._windowTypeSelect.setHandler(`type${i}`, this.typeOk.bind(this));
|
||
}
|
||
this._windowTypeSelect.setHandler(
|
||
"reset",
|
||
this.commandSkillReset.bind(this)
|
||
);
|
||
}
|
||
|
||
commandSkillReset() {
|
||
let description = "Reset all acquired skills.";
|
||
this._windowTypeSelect.setHelpWindowItem({ description: description });
|
||
this._windowTypeSelect.refresh();
|
||
this._windowTypeSelect.deactivate();
|
||
//this._windowTypeSelect.hideHelpWindow();
|
||
this._commandSkillResetWindow.refresh();
|
||
this._commandSkillResetWindow.activate();
|
||
this._commandSkillResetWindow.show();
|
||
//this._commandSkillResetWindow.open();
|
||
// const actorId = this.actor().actorId();
|
||
// console.log(actorId);
|
||
// const totalSp = $skillTreeData.totalSpAllTypes(actorId);
|
||
// $skillTreeData.skillResetAllTypes(actorId);
|
||
// $skillTreeData.gainSp(actorId, totalSp);
|
||
// this._windowActorInfo.refresh();
|
||
// this._windowTypeSelect.activate();
|
||
}
|
||
|
||
createCommandSkillResetWindow() {
|
||
this._commandSkillResetWindow = new Window_CommandSkillResetWindow(
|
||
this.commandSkillResetWindowRect(),
|
||
this.actor().actorId()
|
||
);
|
||
this._commandSkillResetWindow.setHandler(
|
||
"yes",
|
||
this.commandSkillResetOk.bind(this)
|
||
);
|
||
this._commandSkillResetWindow.setHandler(
|
||
"no",
|
||
this.commandSkillResetCancel.bind(this)
|
||
);
|
||
this._commandSkillResetWindow.setHandler(
|
||
"cancel",
|
||
this.commandSkillResetCancel.bind(this)
|
||
);
|
||
//this._commandSkillResetWindow.close();
|
||
this._commandSkillResetWindow.deactivate();
|
||
this._commandSkillResetWindow.hide();
|
||
this.addWindow(this._commandSkillResetWindow);
|
||
}
|
||
|
||
commandSkillResetWindowRect() {
|
||
const wx = 520;
|
||
const wy = 364;
|
||
const ww = 503;
|
||
const wh = 112;
|
||
return new Rectangle(wx, wy, ww, wh);
|
||
}
|
||
|
||
commandSkillResetOk() {
|
||
const actorId = this.actor().actorId();
|
||
const totalSp = $skillTreeData.totalSpAllTypes(actorId);
|
||
$skillTreeData.skillResetAllTypes(actorId);
|
||
//$skillTreeData.gainSp(actorId, totalSp);
|
||
this._windowActorInfo.refresh();
|
||
this._commandSkillResetWindow.deactivate();
|
||
//this._commandSkillResetWindow.close();
|
||
this._commandSkillResetWindow.hide();
|
||
this._commandSkillResetWindow.select(0);
|
||
this._windowTypeSelect.open();
|
||
this._windowTypeSelect.showHelpWindow();
|
||
this._windowTypeSelect.activate();
|
||
AudioManager.playSe({ name: "Load1", volume: 90, pitch: 150, pan: 0 });
|
||
}
|
||
|
||
commandSkillResetCancel() {
|
||
this._windowActorInfo.refresh();
|
||
this._commandSkillResetWindow.deactivate();
|
||
//this._commandSkillResetWindow.close();
|
||
this._commandSkillResetWindow.hide();
|
||
this._commandSkillResetWindow.select(0);
|
||
this._windowTypeSelect.open();
|
||
this._windowTypeSelect.showHelpWindow();
|
||
this._windowTypeSelect.activate();
|
||
}
|
||
|
||
createActorInfoWindow() {
|
||
this._windowActorInfo = new Window_ActorInfo(
|
||
this.actorInfoWindowRect(),
|
||
this.actor().actorId()
|
||
);
|
||
//西ヤスアキ 改造
|
||
// this._windowActorInfo.close();
|
||
// this._windowActorInfo.deactivate();
|
||
// this._windowActorInfo.hide();
|
||
this._windowActorInfo.setHandler("ok", this.onActorInfoOK.bind(this));
|
||
this._windowActorInfo.setHandler("cancel", this.menuCancel.bind(this));
|
||
this._windowActorInfo.setHandler("left", this.escapeMenuLeft.bind(this));
|
||
this._windowActorInfo.setHandler(
|
||
"right",
|
||
this.escapeMenuRight.bind(this)
|
||
);
|
||
this._windowActorInfo.setHandler("down", this.mainButtonDown.bind(this));
|
||
this._windowActorInfo.setHandler("up", this.mainButtonUp.bind(this));
|
||
this.addWindow(this._windowActorInfo);
|
||
}
|
||
|
||
//追加 ここから 西ヤスアキ
|
||
onActorInfoOK() {
|
||
this._windowActorInfo.deactivate();
|
||
this._operating = true;
|
||
this._windowTypeSelect.activate();
|
||
this._windowTypeSelect.select(0);
|
||
}
|
||
|
||
menuCancel() {
|
||
let menuClose = 1902;
|
||
$gameTemp.clearCommonEventReservation();
|
||
$gameTemp.reserveCommonEvent(menuClose);
|
||
SceneManager.goto(Scene_Map);
|
||
}
|
||
|
||
escapeMenuLeft() {
|
||
let topButtonDraw = 1903; //コモンイベント 上部ボタン表示
|
||
let topButtonSelect = 1983; //変数 上部ボタン選択
|
||
let menuClose = 1902;
|
||
if (!$gameTemp._commonEventQueue.includes(menuClose)) {
|
||
//$gameTemp.clearCommonEventReservation();
|
||
AudioManager.playSe({ name: "Book1", volume: 90, pitch: 100, pan: 0 });
|
||
$gameVariables.setValue(topButtonSelect, 4); //スキルボタンへ
|
||
if (!$gameTemp._commonEventQueue.includes(topButtonDraw)) {
|
||
$gameTemp._commonEventQueue.unshift(topButtonDraw);
|
||
}
|
||
this.popScene();
|
||
}
|
||
}
|
||
|
||
escapeMenuRight() {
|
||
let topButtonDraw = 1903; //コモンイベント 上部ボタン表示
|
||
let topButtonSelect = 1983; //変数 上部ボタン選択
|
||
let menuClose = 1902;
|
||
//メニュー閉じる実行時に左右に移動するの防止
|
||
if (!$gameTemp._commonEventQueue.includes(menuClose)) {
|
||
//$gameTemp.clearCommonEventReservation();
|
||
AudioManager.playSe({ name: "Book1", volume: 90, pitch: 100, pan: 0 });
|
||
$gameVariables.setValue(topButtonSelect, 6); //データボタンへ
|
||
if (!$gameTemp._commonEventQueue.includes(topButtonDraw)) {
|
||
$gameTemp._commonEventQueue.unshift(topButtonDraw);
|
||
}
|
||
this.popScene();
|
||
}
|
||
}
|
||
|
||
mainButtonDown() {
|
||
this.nextActor();
|
||
}
|
||
|
||
mainButtonUp() {
|
||
this.previousActor();
|
||
}
|
||
//追加 ここまで西ヤスアキ
|
||
|
||
resetActorInfoWindow() {
|
||
this._windowActorInfo.reset(this.actor().actorId());
|
||
this._windowActorInfo.refresh();
|
||
this._windowActorInfo.activate();
|
||
this._windowActorInfo.show();
|
||
}
|
||
|
||
createSkillTreeNodeInfo() {
|
||
this._windowSkillTreeNodeInfo = new Window_SkillTreeNodeInfo(
|
||
this.skillTreeNodeInfoWindowRect(),
|
||
this._skillTreeManager
|
||
);
|
||
this._windowSkillTreeNodeInfo.close();
|
||
this._windowSkillTreeNodeInfo.deactivate();
|
||
this._windowSkillTreeNodeInfo.hide();
|
||
this.addWindow(this._windowSkillTreeNodeInfo);
|
||
}
|
||
|
||
createSKillTreeWindow() {
|
||
this._windowSkillTree = new Window_SkillTree(
|
||
this.skillTreeWindowRect(),
|
||
this._skillTreeManager,
|
||
this._windowTypeSelect,
|
||
this._windowSkillTreeNodeInfo,
|
||
this._windowActorInfo
|
||
);
|
||
this._windowSkillTree.setHandler("ok", this.skillTreeOk.bind(this));
|
||
this._windowSkillTree.setHandler(
|
||
"cancel",
|
||
this.skillTreeCancel.bind(this)
|
||
);
|
||
this._windowSkillTree.setHelpWindow(this._helpWindow);
|
||
this._windowSkillTree.deactivate();
|
||
this._windowSkillTree.hideHelpWindow();
|
||
this._windowSkillTree.hide();
|
||
this.addWindow(this._windowSkillTree);
|
||
}
|
||
|
||
createNodeOpenWindow() {
|
||
this._windowNodeOpen = new Window_NodeOpen(
|
||
this.nodeOpenWindowRect(),
|
||
this._skillTreeManager,
|
||
this.actor().actorId()
|
||
);
|
||
this._windowNodeOpen.setHandler("yes", this.nodeOpenOk.bind(this));
|
||
this._windowNodeOpen.setHandler("no", this.nodeOpenCancel.bind(this));
|
||
this._windowNodeOpen.setHandler("cancel", this.nodeOpenCancel.bind(this));
|
||
this._windowNodeOpen.close();
|
||
this._windowNodeOpen.deactivate();
|
||
this._windowNodeOpen.hide();
|
||
this.addWindow(this._windowNodeOpen);
|
||
}
|
||
|
||
resetNodeOpenWindow() {
|
||
this._windowNodeOpen.reset(this.actor().actorId());
|
||
this._windowNodeOpen.refresh();
|
||
}
|
||
|
||
createNodeCloseWindow() {
|
||
this._windowNodeClose = new Window_NodeClose(
|
||
this.nodeCloseWindowRect(),
|
||
this._skillTreeManager,
|
||
this.actor().actorId()
|
||
);
|
||
this._windowNodeClose.setHandler("yes", this.nodeCloseOk.bind(this));
|
||
this._windowNodeClose.setHandler("no", this.nodeCloseCancel.bind(this));
|
||
this._windowNodeClose.setHandler(
|
||
"cancel",
|
||
this.nodeCloseCancel.bind(this)
|
||
);
|
||
this._windowNodeClose.close();
|
||
this._windowNodeClose.deactivate();
|
||
this._windowNodeClose.hide();
|
||
this.addWindow(this._windowNodeClose);
|
||
}
|
||
|
||
resetNodeCloseWindow() {
|
||
this._windowNodeClose.reset(this.actor().actorId());
|
||
this._windowNodeClose.refresh();
|
||
}
|
||
|
||
isBottomHelpMode() {
|
||
if (Utils.RPGMAKER_NAME === "MZ" && EnableMZLayout)
|
||
return super.isBottomHelpMode();
|
||
return false;
|
||
}
|
||
|
||
isBottomButtonMode() {
|
||
if (Utils.RPGMAKER_NAME === "MZ" && EnableMZLayout)
|
||
return super.isBottomButtonMode();
|
||
return false;
|
||
}
|
||
|
||
isRightInputMode() {
|
||
if (Utils.RPGMAKER_NAME === "MZ" && EnableMZLayout)
|
||
return super.isRightInputMode();
|
||
return false;
|
||
}
|
||
|
||
buttonAreaTop() {
|
||
if (Utils.RPGMAKER_NAME === "MZ") return super.buttonAreaTop();
|
||
return this.isBottomButtonMode() ? Graphics.boxHeight : 0;
|
||
}
|
||
|
||
buttonAreaHeight() {
|
||
if (Utils.RPGMAKER_NAME === "MZ") return super.buttonAreaHeight();
|
||
return 0;
|
||
}
|
||
|
||
mainCommandWidth() {
|
||
if (Utils.RPGMAKER_NAME === "MZ") return super.mainCommandWidth();
|
||
return 240;
|
||
}
|
||
|
||
helpWindowRect() {
|
||
//ウィンドウのサイズ 西ヤスアキ
|
||
const wx = 340;
|
||
const wy = 130; //this.helpAreaTop();
|
||
const ww = 746; //Graphics.boxWidth;
|
||
const wh = 100; //this.helpAreaHeight();
|
||
return new Rectangle(wx, wy, ww, wh);
|
||
}
|
||
|
||
typeSelectWindowRect() {
|
||
const actorInfoWindowRect = this.actorInfoWindowRect();
|
||
const x = 340; //actorInfoWindowRect.x;
|
||
const w = 230; //actorInfoWindowRect.width;
|
||
const y = 236;
|
||
const h = 254;
|
||
// let y;
|
||
// if (this.isBottomHelpMode()) {
|
||
// if (this.isBottomButtonMode()) {
|
||
// y = 0;
|
||
// } else {
|
||
// y = this.buttonAreaBottom();
|
||
// }
|
||
// } else if (this.isBottomButtonMode()) {
|
||
// const helpWindowRect = this.helpWindowRect();
|
||
// y = helpWindowRect.y + helpWindowRect.height;
|
||
// } else {
|
||
// const helpWindowRect = this.helpWindowRect();
|
||
// y = helpWindowRect.y + helpWindowRect.height;
|
||
// }
|
||
//const h = actorInfoWindowRect.y - y;
|
||
return new Rectangle(x, y, w, h);
|
||
}
|
||
|
||
actorInfoWindowRect() {
|
||
const skillTreeNodeInfoWindowRect = this.skillTreeNodeInfoWindowRect();
|
||
const x = 340; //skillTreeNodeInfoWindowRect.x;
|
||
const w = 230; //skillTreeNodeInfoWindowRect.width;
|
||
const h = 190;
|
||
const y = 494; //skillTreeNodeInfoWindowRect.y - h;
|
||
return new Rectangle(x, y, w, h);
|
||
}
|
||
|
||
skillTreeNodeInfoWindowRect() {
|
||
const w = 230; //this.mainCommandWidth();
|
||
const h = 116;
|
||
const x = 340;
|
||
const y = 688;
|
||
// let x;
|
||
// if (this.isRightInputMode()) {
|
||
// x = Graphics.boxWidth - w;
|
||
// } else {
|
||
// x = 0;
|
||
// }
|
||
// const h = 110;
|
||
// let y;
|
||
// if (this.isBottomHelpMode()) {
|
||
// const helpWindowRect = this.helpWindowRect();
|
||
// y = helpWindowRect.y - h;
|
||
// } else {
|
||
// if (this.isBottomButtonMode()) {
|
||
// y = this.buttonAreaTop() - h;
|
||
// } else {
|
||
// y = Graphics.boxHeight - h;
|
||
// }
|
||
// }
|
||
return new Rectangle(x, y, w, h);
|
||
}
|
||
|
||
skillTreeWindowRect() {
|
||
const typeSelectWindowRect = this.typeSelectWindowRect();
|
||
const x = 574;
|
||
const y = 236;
|
||
const w = 510;
|
||
const h = 568;
|
||
// let x;
|
||
// if (this.isRightInputMode()) {
|
||
// x = 0;
|
||
// } else {
|
||
// x = typeSelectWindowRect.width;
|
||
// }
|
||
// const w = Graphics.boxWidth - typeSelectWindowRect.width;
|
||
// const y = typeSelectWindowRect.y;
|
||
// let h;
|
||
// if (this.isBottomHelpMode()) {
|
||
// const helpWindowRect = this.helpWindowRect();
|
||
// h = helpWindowRect.y - y;
|
||
// } else if (this.isBottomButtonMode()) {
|
||
// h = this.buttonAreaTop() - y;
|
||
// } else {
|
||
// h = Graphics.boxHeight - y;
|
||
// }
|
||
return new Rectangle(x, y, w, h);
|
||
}
|
||
|
||
nodeOpenWindowRect() {
|
||
const w = 640;
|
||
const h = 499; //160;
|
||
const x = 400; //Graphics.boxWidth / 2 - w / 2;
|
||
const y = 260; //Graphics.boxHeight / 2 - h / 2;
|
||
return new Rectangle(x, y, w, h);
|
||
}
|
||
|
||
nodeCloseWindowRect() {
|
||
const w = 640;
|
||
const h = 499;
|
||
const x = 400; //Graphics.boxWidth / 2 - w / 2;
|
||
const y = 260; //Graphics.boxHeight / 2 - h / 2;
|
||
return new Rectangle(x, y, w, h);
|
||
}
|
||
|
||
typeOk() {
|
||
this.change_TypeWindow_To_SkillTreeWindow();
|
||
}
|
||
|
||
typeCancel() {
|
||
// 改造ここから 西ヤスアキ
|
||
this._windowTypeSelect.select(0);
|
||
let description = "";
|
||
if (this._windowTypeSelect.type())
|
||
description = this._windowTypeSelect.type().helpMessage();
|
||
this._windowTypeSelect.setHelpWindowItem({ description: description });
|
||
this._windowTypeSelect.deactivate();
|
||
this._operating = false;
|
||
this._windowActorInfo.activate();
|
||
this.updateSkillTree();
|
||
this._windowTypeSelect.deselect();
|
||
// 改造ここまで
|
||
//this.popScene();
|
||
}
|
||
|
||
skillTreeOk() {
|
||
const selectedNode = this._skillTreeManager._selectNode;
|
||
|
||
if (selectedNode.isOpened()) {
|
||
// スキルが取得済みならリセット確認画面へ
|
||
this.change_SkillTreeWindow_To_NodeCloseWindow();
|
||
} else if (selectedNode.canCostConsumption()) {
|
||
// スキルが未取得で、かつコストが足りる場合、スキル取得確認画面へ
|
||
SoundManager.playOk();
|
||
//this._windowSkillTree.deactivate();
|
||
this.change_SkillTreeWindow_To_NodeOpenWindow();
|
||
} else {
|
||
this._windowSkillTree.playBuzzerSound();
|
||
// スキルが未取得で、かつコストが足りない場合はバザー音を鳴らすだけ
|
||
}
|
||
}
|
||
|
||
skillTreeCancel() {
|
||
this.change_SkillTreeWindow_To_TypeWindow();
|
||
}
|
||
|
||
nodeOpenOk() {
|
||
// 現在選択されているノードを取得
|
||
const selectedNode = this._skillTreeManager._selectNode;
|
||
this._skillTreeManager.selectNodeOpen(); // ここで選択されたノードを開放
|
||
this.playLearnSkillSe();
|
||
this._windowNodeOpen.select(0);
|
||
this.change_NodeOpenWindow_To_SkillTreeWindow();
|
||
this._windowSkillTree.refresh();
|
||
this._windowActorInfo.refresh();
|
||
}
|
||
|
||
nodeOpenCancel() {
|
||
this._windowNodeOpen.select(0);
|
||
this.change_NodeOpenWindow_To_SkillTreeWindow();
|
||
}
|
||
|
||
nodeCloseOk() {
|
||
// 現在選択されているノードを取得
|
||
const selectedNode = this._skillTreeManager._selectNode;
|
||
this._skillTreeManager.selectNodeClose(); // ここで選択されたノードを開放
|
||
this.playLearnSkillSe();
|
||
this._windowNodeClose.select(0);
|
||
this.change_NodeCloseWindow_To_SkillTreeWindow();
|
||
this._windowSkillTree.refresh();
|
||
this._windowActorInfo.refresh();
|
||
}
|
||
|
||
nodeCloseCancel() {
|
||
this._windowNodeClose.select(0);
|
||
this.change_NodeCloseWindow_To_SkillTreeWindow();
|
||
}
|
||
|
||
needsPageButtons() {
|
||
return false;
|
||
}
|
||
|
||
needsCancelButton() {
|
||
return false;
|
||
}
|
||
|
||
arePageButtonsEnabled() {
|
||
return this._windowTypeSelect.active;
|
||
}
|
||
|
||
getSkillTreeTypes() {
|
||
return $skillTreeData.enableTypes(this.actor().actorId());
|
||
}
|
||
|
||
updateSkillTree() {
|
||
const resetCommandSelect = this._windowTypeSelect.resetCommandSelect();
|
||
const type = this._windowTypeSelect.type();
|
||
if (resetCommandSelect) {
|
||
let description = "Reset all acquired skills."; //西ヤスアキ
|
||
this._windowSkillTree.setHelpWindowItem({ description: description });
|
||
}
|
||
if (type) {
|
||
this._skillTreeManager.reset();
|
||
this._skillTreeManager.setActorId(this.actor().actorId());
|
||
this._skillTreeManager.setType(type);
|
||
this._skillTreeManager.selectTopNode($skillTreeData.topNode(type));
|
||
if (this._windowSkillTree) {
|
||
this._windowSkillTree.setDrawState("createView");
|
||
this._windowSkillTree.refresh();
|
||
}
|
||
} else {
|
||
//ここでwindowTypeSelectのtypeがundefinedのとき非表示にしてる 西ヤスアキ
|
||
if (!this._windowActorInfo.active && this._windowSkillTree) {
|
||
this._windowSkillTree.setDrawState("undraw");
|
||
}
|
||
}
|
||
}
|
||
|
||
change_TypeWindow_To_SkillTreeWindow() {
|
||
this._windowTypeSelect.deactivate();
|
||
this._windowTypeSelect.hideHelpWindow();
|
||
this._windowSkillTreeNodeInfo.refresh();
|
||
this._windowSkillTreeNodeInfo.open();
|
||
this._windowSkillTreeNodeInfo.show();
|
||
this._windowSkillTree.refresh();
|
||
this._windowSkillTree.showHelpWindow();
|
||
this._windowSkillTree.activate();
|
||
}
|
||
|
||
change_SkillTreeWindow_To_TypeWindow() {
|
||
this._windowSkillTree.deactivate();
|
||
this._windowSkillTree.hideHelpWindow();
|
||
this._windowSkillTreeNodeInfo.close();
|
||
this._windowTypeSelect.showHelpWindow();
|
||
this._windowTypeSelect.activate();
|
||
this._windowTypeSelect.open();
|
||
}
|
||
|
||
change_SkillTreeWindow_To_NodeOpenWindow() {
|
||
this._windowSkillTree.deactivate();
|
||
this._windowNodeOpen.refresh();
|
||
this._windowNodeOpen.activate();
|
||
this._windowNodeOpen.show();
|
||
this._windowNodeOpen.open();
|
||
}
|
||
|
||
change_NodeOpenWindow_To_SkillTreeWindow() {
|
||
this._windowNodeOpen.deactivate();
|
||
this._windowNodeOpen.close();
|
||
this._windowSkillTree.open();
|
||
this._windowSkillTree.showHelpWindow();
|
||
this._windowSkillTree.activate();
|
||
}
|
||
|
||
change_NodeOpenWindow_To_SkillTreeWindow() {
|
||
this._windowNodeOpen.deactivate();
|
||
this._windowNodeOpen.close();
|
||
this._windowSkillTree.open();
|
||
this._windowSkillTree.showHelpWindow();
|
||
this._windowSkillTree.activate();
|
||
}
|
||
|
||
change_SkillTreeWindow_To_NodeCloseWindow() {
|
||
this._windowSkillTree.deactivate();
|
||
this._windowNodeClose.refresh();
|
||
this._windowNodeClose.activate();
|
||
this._windowNodeClose.show();
|
||
this._windowNodeClose.open();
|
||
}
|
||
|
||
change_NodeCloseWindow_To_SkillTreeWindow() {
|
||
this._windowNodeClose.deactivate();
|
||
this._windowNodeClose.close();
|
||
this._windowSkillTree.open();
|
||
this._windowSkillTree.showHelpWindow();
|
||
this._windowSkillTree.activate();
|
||
}
|
||
|
||
onActorChange() {
|
||
AudioManager.playSe({ name: "Book1", volume: 90, pitch: 100, pan: 0 });
|
||
this.resetActorInfoWindow();
|
||
this.resetTypeSelectWindow();
|
||
this.resetNodeOpenWindow();
|
||
this.resetNodeCloseWindow();
|
||
this._windowActorInfo.refresh();
|
||
this.updateSkillTree();
|
||
}
|
||
|
||
playLearnSkillSe() {
|
||
if (LearnSkillSeFileName === "") return;
|
||
const se = {
|
||
name: LearnSkillSeFileName,
|
||
pan: LearnSkillSePan,
|
||
pitch: LearnSkillSePitch,
|
||
volume: LearnSkillSeVolume,
|
||
};
|
||
AudioManager.playSe(se);
|
||
}
|
||
|
||
createSpriteset() {
|
||
this._spriteset = new Spriteset_YSAKmenu();
|
||
this.addChild(this._spriteset);
|
||
}
|
||
|
||
updateMenuHPMPbar() {
|
||
if (this._spriteset._YSAKmenu) {
|
||
this._spriteset._baseSprite.removeChild(this._spriteset._YSAKmenu);
|
||
//メインボタン選択中と、決定したときのスキルツリー操作中で、メインボタンの色を分ける。
|
||
const operating = this._operating;
|
||
this._spriteset.createMenuUI(this.actor().actorId(), operating);
|
||
}
|
||
}
|
||
}
|
||
|
||
//自作Window_help 西ヤスアキ
|
||
class Window_YSAKSkillTreeHelp extends Window_Base {
|
||
initialize(rect) {
|
||
super.initialize(rect);
|
||
// //追加 西ヤスアキ
|
||
this._backSprite.visible = false;
|
||
this._frameSprite.visible = false;
|
||
this.frameVisible = false;
|
||
// //追加ここまで
|
||
this._text = "";
|
||
}
|
||
|
||
setText(text) {
|
||
if (this._text !== text) {
|
||
this._text = text;
|
||
this.refresh();
|
||
}
|
||
}
|
||
|
||
clear() {
|
||
this.setText("");
|
||
}
|
||
|
||
setItem(item) {
|
||
this.setText(item ? item.description : "");
|
||
}
|
||
|
||
refresh() {
|
||
const rect = this.baseTextRect();
|
||
this.contents.clear();
|
||
this.drawTextExHelp(this._text, rect.x, rect.y, 300); //rect.width
|
||
}
|
||
}
|
||
|
||
class Window_TypeSelect extends Window_Command {
|
||
initialize(rect, types) {
|
||
this._windowRect = rect;
|
||
this._types = types;
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
super.initialize(rect);
|
||
} else {
|
||
super.initialize(0, 0);
|
||
this.updatePlacement();
|
||
}
|
||
// //追加 西ヤスアキ
|
||
this._backSprite.visible = false;
|
||
this._frameSprite.visible = false;
|
||
this.frameVisible = false;
|
||
// //追加ここまで
|
||
}
|
||
|
||
reset(types) {
|
||
this._index = 0;
|
||
this._types = types;
|
||
this._handlers = {};
|
||
}
|
||
|
||
//スキルリセット選択時にヘルプ欄を表示します。
|
||
//スキルタイプ選択欄の最後の項目をリセットだと決め打ちしてるので注意 西ヤスアキ
|
||
resetCommandSelect() {
|
||
const resetCommandSelectNum = $skillTreeData._commandListNum - 1; //indexが0から始まるので
|
||
if (this.index() == resetCommandSelectNum) {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
type() {
|
||
return this._types[this.index()];
|
||
}
|
||
|
||
select(index) {
|
||
super.select(index);
|
||
this.callHandler("select");
|
||
}
|
||
|
||
updateHelp() {
|
||
let description = "";
|
||
if (this.type()) description = this.type().helpMessage();
|
||
this.setHelpWindowItem({ description: description });
|
||
}
|
||
|
||
windowWidth() {
|
||
return this._windowRect.width;
|
||
}
|
||
|
||
windowHeight() {
|
||
return this._windowRect.height;
|
||
}
|
||
|
||
updatePlacement() {
|
||
this.x = this._windowRect.x;
|
||
this.y = this._windowRect.y;
|
||
}
|
||
|
||
makeCommandList() {
|
||
let i = 0;
|
||
//スキルリセットのヘルプウィンドウのために選択肢の数を定義します。 西ヤスアキ
|
||
$skillTreeData._commandListNum = 0;
|
||
for (const type of this._types) {
|
||
this.addCommand(type.message(), `type${i}`);
|
||
$skillTreeData._commandListNum += 1;
|
||
i++;
|
||
}
|
||
this.addCommand("Respec", "reset");
|
||
$skillTreeData._commandListNum += 1;
|
||
}
|
||
}
|
||
|
||
class Window_ActorInfo extends Window_Selectable {
|
||
initialize(rect, actorId) {
|
||
this._actorId = actorId;
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
super.initialize(rect);
|
||
} else {
|
||
super.initialize(rect.x, rect.y, rect.width, rect.height);
|
||
}
|
||
// //追加 西ヤスアキ
|
||
this._backSprite.visible = false;
|
||
this._frameSprite.visible = false;
|
||
this.frameVisible = false;
|
||
// //追加ここまで
|
||
}
|
||
|
||
reset(actorId) {
|
||
this._actorId = actorId;
|
||
}
|
||
|
||
refresh() {
|
||
if (this.contents) {
|
||
this.contents.clear();
|
||
this.draw();
|
||
}
|
||
}
|
||
|
||
actor() {
|
||
const actor = $gameActors.actor(this._actorId);
|
||
if (!actor) throw new Error(`actor id: ${this._actorId} is not found.`);
|
||
return actor;
|
||
}
|
||
|
||
draw() {
|
||
const textWidth = this.width - this.padding * 2;
|
||
this.drawActorFace(this.actor(), 0, 4, textWidth, this.height - 100);
|
||
this.drawText(
|
||
`${this.actor().name()}`,
|
||
10,
|
||
this.height - 94,
|
||
textWidth,
|
||
"left"
|
||
);
|
||
this.changeTextColor(this.systemColor());
|
||
const nowSp = $skillTreeData.sp(this._actorId);
|
||
this.drawText(SpName, 10, this.height - 62, textWidth);
|
||
this.resetTextColor();
|
||
const nowSpTextX =
|
||
this.textWidth(SpName) + (textWidth - this.textWidth(SpName)) / 2;
|
||
this.drawText(
|
||
nowSp.toString(),
|
||
10,
|
||
this.height - 62,
|
||
nowSpTextX,
|
||
"right"
|
||
);
|
||
}
|
||
|
||
systemColor() {
|
||
if (Utils.RPGMAKER_NAME === "MZ") return ColorManager.systemColor();
|
||
return super.systemColor();
|
||
}
|
||
|
||
drawActorFace(actor, x, y, width, height) {
|
||
this.drawFace(actor.faceName(), actor.faceIndex(), x, y, width, height);
|
||
}
|
||
|
||
//追加ここから 西ヤスアキ
|
||
processHandling() {
|
||
if (this.isOpenAndActive()) {
|
||
if (this.isOkEnabled() && this.isOkTriggered()) {
|
||
return this.processOk();
|
||
}
|
||
if (this.isCancelEnabled() && this.isCancelTriggered()) {
|
||
return this.processCancel();
|
||
}
|
||
if (this.isHandled("left") && Input.isTriggered("left")) {
|
||
return this.processLeft();
|
||
}
|
||
if (this.isHandled("right") && Input.isTriggered("right")) {
|
||
return this.processRight();
|
||
}
|
||
if (this.isHandled("down") && Input.isTriggered("down")) {
|
||
return this.processDown();
|
||
}
|
||
if (this.isHandled("up") && Input.isTriggered("up")) {
|
||
return this.processUp();
|
||
}
|
||
}
|
||
}
|
||
|
||
processCancel() {
|
||
//SoundManager.playCancel();
|
||
this.updateInputData();
|
||
this.deactivate();
|
||
this.callCancelHandler();
|
||
}
|
||
|
||
processLeft() {
|
||
//SoundManager.playCancel();
|
||
this.updateInputData();
|
||
this.deactivate();
|
||
this.callLeftHandler();
|
||
}
|
||
|
||
processRight() {
|
||
//SoundManager.playCancel();
|
||
this.updateInputData();
|
||
this.deactivate();
|
||
this.callRightHandler();
|
||
}
|
||
|
||
processDown() {
|
||
this.updateInputData();
|
||
this.deactivate();
|
||
this.callDownHandler();
|
||
}
|
||
|
||
processUp() {
|
||
this.updateInputData();
|
||
this.deactivate();
|
||
this.callUpHandler();
|
||
}
|
||
|
||
callLeftHandler() {
|
||
this.callHandler("left");
|
||
}
|
||
|
||
callRightHandler() {
|
||
this.callHandler("right");
|
||
}
|
||
|
||
callDownHandler() {
|
||
this.callHandler("down");
|
||
}
|
||
|
||
callUpHandler() {
|
||
this.callHandler("up");
|
||
}
|
||
//追加ここまで 西ヤスアキ
|
||
}
|
||
|
||
class Window_SkillTreeNodeInfo extends Window_Base {
|
||
initialize(rect, skillTreeManager) {
|
||
this._skillTreeManager = skillTreeManager;
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
super.initialize(rect);
|
||
} else {
|
||
super.initialize(rect.x, rect.y, rect.width, rect.height);
|
||
}
|
||
// //追加 西ヤスアキ
|
||
this._backSprite.visible = false;
|
||
this._frameSprite.visible = false;
|
||
this.frameVisible = false;
|
||
// //追加ここまで
|
||
}
|
||
|
||
refresh() {
|
||
if (this.contents) {
|
||
this.contents.clear();
|
||
if (this._skillTreeManager.type()) this.draw();
|
||
}
|
||
}
|
||
|
||
draw() {
|
||
const textWidth = this.width - this.padding * 2;
|
||
const selectNode = this._skillTreeManager.selectNode();
|
||
const skill = selectNode.info().skill();
|
||
this.drawText(skill.name, 0, 8, textWidth, "left");
|
||
const needSp = selectNode.info()._needSp;
|
||
const nowSp = $skillTreeData.sp(this._skillTreeManager.actorId());
|
||
if (selectNode.isOpened()) {
|
||
this.drawText(OpenedNodeText, 0, 48, textWidth, "left");
|
||
} else {
|
||
this.drawText(NeedSpText.format(SpName), 0, 48, textWidth, "left");
|
||
if (needSp <= nowSp) {
|
||
this.changeTextColor(this.crisisColor());
|
||
} else {
|
||
this.changePaintOpacity(false);
|
||
}
|
||
this.drawText(`${needSp}/${nowSp}`, 0, 48, textWidth, "right");
|
||
}
|
||
this.resetTextColor();
|
||
this.changePaintOpacity(true);
|
||
}
|
||
|
||
crisisColor() {
|
||
if (Utils.RPGMAKER_NAME === "MZ") return ColorManager.crisisColor();
|
||
return super.crisisColor();
|
||
}
|
||
}
|
||
|
||
class Window_SkillTree extends Window_Selectable {
|
||
initialize(
|
||
rect,
|
||
skillTreeManager,
|
||
windowTypeSelect,
|
||
windowSkillTreeNodeInfo,
|
||
windowActorInfo
|
||
) {
|
||
this._skillTreeManager = skillTreeManager;
|
||
this._windowTypeSelect = windowTypeSelect;
|
||
this._windowActorInfo = windowActorInfo;
|
||
this._windowSkillTreeNodeInfo = windowSkillTreeNodeInfo; //追加 西ヤスアキ
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
super.initialize(rect);
|
||
this._viewSprite = new Sprite(new Bitmap(1, 1));
|
||
this.addInnerChild(this._viewSprite);
|
||
} else {
|
||
super.initialize(rect.x, rect.y, rect.width, rect.height);
|
||
this._bitmapCache = null;
|
||
}
|
||
this._skillTreeView = new SkillTreeView(
|
||
skillTreeManager,
|
||
rect.width,
|
||
rect.height
|
||
);
|
||
// //追加 西ヤスアキ
|
||
this._backSprite.visible = false;
|
||
this._frameSprite.visible = false;
|
||
this.frameVisible = false;
|
||
this._canRepeat = false;
|
||
// //追加ここまで
|
||
this._drawState = "undraw";
|
||
this._touchSelected = true;
|
||
}
|
||
|
||
setDrawState(drawState) {
|
||
this._drawState = drawState;
|
||
}
|
||
|
||
update() {
|
||
super.update();
|
||
if (this._drawState === "undraw") this.updateCursor();
|
||
this.updateView();
|
||
}
|
||
|
||
updateView() {
|
||
if (this._drawState === "none") return;
|
||
this.drawView();
|
||
this._drawState = "none";
|
||
}
|
||
|
||
updateHelp() {
|
||
const skill = this._skillTreeManager.selectNode().info().skill();
|
||
this.setHelpWindowItem(skill);
|
||
if (this._windowSkillTreeNodeInfo.isOpen())
|
||
this._windowSkillTreeNodeInfo.refresh();
|
||
}
|
||
|
||
updateCursor() {
|
||
if (this.isCursorVisible() && this._skillTreeManager.type()) {
|
||
const rect = this.getCursorRect();
|
||
this.setCursorRect(rect.x, rect.y, rect.width, rect.height);
|
||
} else {
|
||
this.setCursorRect(0, 0, 0, 0);
|
||
}
|
||
}
|
||
|
||
getCursorRect() {
|
||
const rect = this._skillTreeView.getCursorRect();
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
rect.x -= this.scrollBaseX();
|
||
rect.y -= this.scrollBaseY();
|
||
} else {
|
||
const [viewX, viewY] = this._skillTreeView.viewXY();
|
||
rect.x -= viewX;
|
||
rect.y -= viewY;
|
||
}
|
||
return rect;
|
||
}
|
||
|
||
refreshCursor() {
|
||
this.updateCursor();
|
||
}
|
||
|
||
refreshCursorForAll() {}
|
||
|
||
isCursorVisible() {
|
||
const resetCommandSelectNum = $skillTreeData._commandListNum - 1; //indexが0から始まるので
|
||
if (this._windowTypeSelect.index() == resetCommandSelectNum) {
|
||
return false;
|
||
}
|
||
if (this._windowActorInfo.active) {
|
||
return false;
|
||
}
|
||
return this._skillTreeView && !this._windowTypeSelect.active;
|
||
}
|
||
|
||
refresh() {
|
||
super.refresh();
|
||
this.updateCursor();
|
||
if (this._drawState === "undraw") return;
|
||
this._drawState = "createView";
|
||
this.updateView();
|
||
}
|
||
|
||
maxScrollX() {
|
||
const x = this._viewSprite.bitmap.width + this.padding * 2 - this.width;
|
||
return x < 0 ? 0 : x;
|
||
}
|
||
|
||
maxScrollY() {
|
||
const y = this._viewSprite.bitmap.height + this.padding * 2 - this.height;
|
||
return y < 0 ? 0 : y;
|
||
}
|
||
|
||
drawView() {
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
if (this._drawState === "undraw") {
|
||
this._viewSprite.bitmap = new Bitmap(1, 1);
|
||
} else if (this._drawState === "createView") {
|
||
this._viewSprite.bitmap = this.getView();
|
||
if (this._windowTypeSelect.active) this.scrollTo(0, 0);
|
||
} else if (this._drawState === "updateScroll") {
|
||
const [viewX, viewY] = this._skillTreeView.viewXY();
|
||
this.smoothScrollTo(viewX, viewY);
|
||
}
|
||
} else {
|
||
this.contents.clear();
|
||
if (this._drawState === "undraw") return;
|
||
const view = this.getView();
|
||
const [viewX, viewY] = this._skillTreeView.viewXY();
|
||
this.contents.blt(view, viewX, viewY, this.width, this.height, 0, 0);
|
||
}
|
||
}
|
||
|
||
getView() {
|
||
if (Utils.RPGMAKER_NAME === "MZ") return this._skillTreeView.createView();
|
||
if (this._drawState === "updateScroll" && this._bitmapCache)
|
||
return this._bitmapCache;
|
||
const bitmap = this._skillTreeView.createView();
|
||
this._bitmapCache = bitmap;
|
||
return bitmap;
|
||
}
|
||
|
||
isCursorMovable() {
|
||
return this.isOpenAndActive() && !this._cursorFixed && !this._cursorAll;
|
||
}
|
||
|
||
isCurrentItemEnabled() {
|
||
return this._skillTreeManager.isSelectNodeOpenable();
|
||
}
|
||
|
||
cursorDown(wrap) {
|
||
const moved = this._skillTreeManager.down();
|
||
if (moved) {
|
||
this._drawState = "updateScroll";
|
||
this.changeSelectNode();
|
||
}
|
||
}
|
||
|
||
cursorUp(wrap) {
|
||
const moved = this._skillTreeManager.up();
|
||
if (moved) {
|
||
this._drawState = "updateScroll";
|
||
this.changeSelectNode();
|
||
}
|
||
}
|
||
|
||
cursorRight(wrap) {
|
||
const moved = this._skillTreeManager.right();
|
||
if (moved) {
|
||
this._drawState = "updateScroll";
|
||
this.changeSelectNode();
|
||
}
|
||
}
|
||
|
||
cursorLeft(wrap) {
|
||
const moved = this._skillTreeManager.left();
|
||
if (moved) {
|
||
this._drawState = "updateScroll";
|
||
this.changeSelectNode();
|
||
}
|
||
}
|
||
|
||
changeSelectNode() {
|
||
this._stayCount = 0;
|
||
SoundManager.playCursor();
|
||
this.updateCursor();
|
||
this.callUpdateHelp();
|
||
}
|
||
|
||
// This method is used when Utils.RPGMAKER_NAME is MV.
|
||
onTouch(triggered) {
|
||
if (triggered) {
|
||
this._touchSelected = true;
|
||
this.onTouchOk();
|
||
} else {
|
||
this.onTouchSelect(triggered);
|
||
}
|
||
}
|
||
|
||
onTouchSelect(trigger) {
|
||
const localPos = this.getLocalPos();
|
||
const hitNode = this.hitTest(localPos.x, localPos.y);
|
||
if (!hitNode) return;
|
||
const moved = this._skillTreeManager.select(hitNode);
|
||
if (moved) {
|
||
this._drawState = "updateScroll";
|
||
this.changeSelectNode();
|
||
this._touchSelected = false;
|
||
} else {
|
||
this._touchSelected = true;
|
||
}
|
||
}
|
||
|
||
onTouchOk() {
|
||
if (!this._touchSelected) return;
|
||
const localPos = this.getLocalPos();
|
||
const hitNode = this.hitTest(localPos.x, localPos.y);
|
||
if (!hitNode) return;
|
||
const moved = this._skillTreeManager.select(hitNode);
|
||
if (moved) {
|
||
this._drawState = "updateScroll";
|
||
this.changeSelectNode();
|
||
} else {
|
||
this.processOk();
|
||
}
|
||
}
|
||
|
||
getLocalPos() {
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
const touchPos = new Point(TouchInput.x, TouchInput.y);
|
||
return this.worldTransform.applyInverse(touchPos);
|
||
} else {
|
||
const x = this.canvasToLocalX(TouchInput.x);
|
||
const y = this.canvasToLocalY(TouchInput.y);
|
||
return { x: x, y: y };
|
||
}
|
||
}
|
||
|
||
hitTest(x, y) {
|
||
if (this.isContentsArea(x, y)) {
|
||
const cx = x - this.padding;
|
||
const cy = y - this.padding;
|
||
const nodes = this._skillTreeManager.getAllNodes();
|
||
for (const node of Object.values(nodes)) {
|
||
let [px, py] = SkillTreeView.getPixelXY(node.point);
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
px -= this.scrollX();
|
||
py -= this.scrollY();
|
||
} else {
|
||
const [viewX, viewY] = this._skillTreeView.viewXY();
|
||
px -= viewX;
|
||
py -= viewY;
|
||
}
|
||
const px2 = px + IconWidth;
|
||
const py2 = py + IconHeight;
|
||
if (px <= cx && cx < px2 && py <= cy && cy < py2) {
|
||
return node;
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
isContentsArea(x, y) {
|
||
if (Utils.RPGMAKER_NAME === "MZ") return true;
|
||
return super.isContentsArea(x, y);
|
||
}
|
||
|
||
processOk() {
|
||
if (this.isCurrentItemEnabled()) {
|
||
this.playOkSound();
|
||
this.updateInputData();
|
||
this.deactivate();
|
||
this.callOkHandler();
|
||
} else {
|
||
this.playOkSound();
|
||
this.updateInputData();
|
||
this.callOkHandler();
|
||
}
|
||
}
|
||
|
||
callOkHandler() {
|
||
this.callHandler("ok");
|
||
}
|
||
}
|
||
|
||
class Window_CommandSkillResetWindow extends Window_Command {
|
||
initialize(rect, actorId) {
|
||
this._actor = actorId;
|
||
this._windowRect = rect;
|
||
super.initialize(rect);
|
||
// //追加 西ヤスアキ
|
||
this._backSprite.visible = false;
|
||
this._frameSprite.visible = false;
|
||
this.frameVisible = false;
|
||
this._canRepeat = false;
|
||
// //追加ここまで
|
||
}
|
||
|
||
_createAllParts() {
|
||
super._createAllParts();
|
||
this._createBackImage();
|
||
}
|
||
|
||
_createBackImage() {
|
||
const sprite = new Sprite();
|
||
sprite.bitmap = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_cursorResetBackground" +
|
||
"0" +
|
||
this._actor
|
||
);
|
||
sprite.bitmap.addLoadListener(() => {
|
||
sprite.x = 0;
|
||
sprite.y = 0;
|
||
});
|
||
this._container.addChild(sprite);
|
||
}
|
||
|
||
windowWidth() {
|
||
return this._windowRect.width;
|
||
}
|
||
|
||
windowHeight() {
|
||
return this._windowRect.height;
|
||
}
|
||
|
||
numVisibleRows() {
|
||
return Math.ceil(this.maxItems() / this.maxCols());
|
||
}
|
||
|
||
updatePlacement() {
|
||
this.x = this._windowRect.x;
|
||
this.y = this._windowRect.y;
|
||
}
|
||
|
||
makeCommandList() {
|
||
this.addCommand("Cancel", "no");
|
||
this.addCommand("Reset", "yes");
|
||
}
|
||
|
||
itemRect(index) {
|
||
const rect = super.itemRect(index);
|
||
//rect.y += 48;
|
||
return rect;
|
||
}
|
||
|
||
//選択肢の文字の位置変更のため 西ヤスアキ
|
||
drawItem(index) {
|
||
const rect = this.itemLineRect(index);
|
||
const align = this.itemTextAlign();
|
||
this.resetTextColor();
|
||
this.changePaintOpacity(this.isCommandEnabled(index));
|
||
this.drawText(
|
||
this.commandName(index),
|
||
rect.x - 102,
|
||
rect.y,
|
||
rect.width,
|
||
align
|
||
);
|
||
}
|
||
|
||
refresh() {
|
||
super.refresh();
|
||
}
|
||
|
||
//選択肢のカーソルの位置大きさ 西ヤスアキ
|
||
refreshCursor() {
|
||
if (this._cursorAll) {
|
||
this.refreshCursorForAll();
|
||
} else if (this.index() >= 0) {
|
||
const rect = this.itemRect(this.index());
|
||
this.setCursorRect(rect.x + 36, rect.y, rect.width - 280, rect.height);
|
||
} else {
|
||
this.setCursorRect(0, 0, 0, 0);
|
||
}
|
||
}
|
||
|
||
playOkSound() {
|
||
if (this.currentSymbol() === "no") super.playOkSound();
|
||
}
|
||
}
|
||
|
||
class Window_NodeOpen extends Window_Command {
|
||
initialize(rect, skillTreeManager, actorId) {
|
||
this._windowRect = rect;
|
||
this._skillTreeManager = skillTreeManager;
|
||
this._actor = actorId;
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
super.initialize(rect);
|
||
} else {
|
||
super.initialize(0, 0);
|
||
this.updatePlacement();
|
||
}
|
||
// //追加 西ヤスアキ
|
||
this._backSprite.visible = false;
|
||
this._frameSprite.visible = false;
|
||
this.frameVisible = false;
|
||
this._canRepeat = false;
|
||
// //追加ここまで
|
||
}
|
||
|
||
_createAllParts() {
|
||
super._createAllParts();
|
||
this._createBackImage();
|
||
}
|
||
|
||
_createBackImage() {
|
||
this._backgroundSprite = new Sprite();
|
||
const sprite = new Sprite();
|
||
const sprite2 = new Sprite();
|
||
sprite.bitmap = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_NodeOpenBackground" +
|
||
"0" +
|
||
this._actor
|
||
);
|
||
sprite2.bitmap = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_NodeOpenBackground" + "99"
|
||
);
|
||
sprite.bitmap.addLoadListener(() => {
|
||
sprite.x = 0;
|
||
sprite.y = 0;
|
||
});
|
||
sprite2.bitmap.addLoadListener(() => {
|
||
sprite2.x = 0;
|
||
sprite2.y = 154;
|
||
});
|
||
|
||
this._container.addChild(this._backgroundSprite);
|
||
//後ろ側の方を先にaddchildする。
|
||
this._backgroundSprite.addChild(sprite2);
|
||
this._backgroundSprite.addChild(sprite);
|
||
}
|
||
|
||
reset(actorId) {
|
||
this._actor = actorId;
|
||
}
|
||
|
||
windowWidth() {
|
||
return this._windowRect.width;
|
||
}
|
||
|
||
windowHeight() {
|
||
return this._windowRect.height;
|
||
}
|
||
|
||
numVisibleRows() {
|
||
return Math.ceil(this.maxItems() / this.maxCols());
|
||
}
|
||
|
||
updatePlacement() {
|
||
this.x = this._windowRect.x;
|
||
this.y = this._windowRect.y;
|
||
}
|
||
|
||
makeCommandList() {
|
||
this.addCommand(NodeOpenYesText, "yes");
|
||
this.addCommand(NodeOpenNoText, "no");
|
||
}
|
||
|
||
itemRect(index) {
|
||
const rect = super.itemRect(index);
|
||
rect.x += 80;
|
||
rect.y += 48;
|
||
rect.width -= 320;
|
||
return rect;
|
||
}
|
||
|
||
refresh() {
|
||
super.refresh();
|
||
//背景画像のリフレッシュ
|
||
if (this._backgroundSprite) {
|
||
this._container.removeChild(this._backgroundSprite);
|
||
this._createBackImage();
|
||
}
|
||
const selectNode = this._skillTreeManager.selectNode();
|
||
if (!this._skillTreeManager.type()) return;
|
||
|
||
let sNodeParArr = [];
|
||
|
||
function addSkillNode(node) {
|
||
if (node && node._tag !== null && !sNodeParArr.includes(node)) {
|
||
sNodeParArr.push(node);
|
||
// 各親ノードを順番に辿る
|
||
if (node._parents && node._parents.length > 0) {
|
||
node._parents.forEach((parent) => {
|
||
addSkillNode(parent); // 再帰的に親ノードを辿る
|
||
});
|
||
}
|
||
}
|
||
}
|
||
//選択しているノードのスキルを渡す
|
||
addSkillNode(selectNode);
|
||
|
||
//描画対象のノードだけをフィルタリング
|
||
const openedNodes = sNodeParArr.filter((node) => !node.isOpened());
|
||
const totalSp = openedNodes.reduce(
|
||
(sum, node) => sum + node.info()._needSp,
|
||
0
|
||
);
|
||
|
||
const textWidth = this.windowWidth() - this.padding * 2 - 100;
|
||
|
||
//テキストの描画 西ヤスアキ
|
||
let message;
|
||
if (openedNodes.length === 1) {
|
||
const singleNode = openedNodes[0];
|
||
message = `${singleNode.info()._needSp} ${SpName} Spent. Learn ${
|
||
singleNode.info().skill().name
|
||
}?`;
|
||
} else {
|
||
message = `Spend ${totalSp} to learn ${SpName}?`;
|
||
}
|
||
|
||
this.drawText(message, 18, 0, textWidth, "left");
|
||
this.drawText("Skills to learn.", 28, 157, textWidth, "left");
|
||
|
||
const lineHeight = 36;
|
||
openedNodes.forEach((node, index) => {
|
||
const skillInfo = node.info().skill();
|
||
const skillIconId = skillInfo.iconIndex;
|
||
const skillName = skillInfo.name;
|
||
const needSp = node.info()._needSp;
|
||
const yPos = 200 + index * lineHeight;
|
||
|
||
this.drawIcon(skillIconId, 118, yPos);
|
||
this.drawText(skillName, 154, yPos, textWidth, "left");
|
||
this.drawText(`: ${needSp}${SpName}`, 438, yPos, textWidth, "left");
|
||
});
|
||
}
|
||
|
||
//選択肢の文字の位置変更のため 西ヤスアキ
|
||
drawItem(index) {
|
||
const rect = this.itemLineRect(index);
|
||
const align = this.itemTextAlign();
|
||
this.resetTextColor();
|
||
this.changePaintOpacity(this.isCommandEnabled(index));
|
||
this.drawText(this.commandName(index), rect.x, rect.y, rect.width, align);
|
||
}
|
||
|
||
//選択肢のカーソルの位置大きさ 西ヤスアキ
|
||
refreshCursor() {
|
||
if (this._cursorAll) {
|
||
this.refreshCursorForAll();
|
||
} else if (this.index() >= 0) {
|
||
const rect = this.itemRect(this.index());
|
||
this.setCursorRect(rect.x, rect.y, rect.width, rect.height);
|
||
} else {
|
||
this.setCursorRect(0, 0, 0, 0);
|
||
}
|
||
}
|
||
|
||
// The SE of skill learn is played, so the SE of OK is not played.
|
||
playOkSound() {
|
||
if (this.currentSymbol() === "no") super.playOkSound();
|
||
}
|
||
}
|
||
|
||
class Window_NodeClose extends Window_Command {
|
||
initialize(rect, skillTreeManager, actorId) {
|
||
this._windowRect = rect;
|
||
this._skillTreeManager = skillTreeManager;
|
||
this._actor = actorId;
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
super.initialize(rect);
|
||
} else {
|
||
super.initialize(0, 0);
|
||
this.updatePlacement();
|
||
}
|
||
// //追加 西ヤスアキ
|
||
this._backSprite.visible = false;
|
||
this._frameSprite.visible = false;
|
||
this.frameVisible = false;
|
||
this._canRepeat = false;
|
||
// //追加ここまで
|
||
}
|
||
|
||
_createAllParts() {
|
||
super._createAllParts();
|
||
this._createBackImage();
|
||
}
|
||
|
||
_createBackImage() {
|
||
this._backgroundSprite = new Sprite();
|
||
const sprite = new Sprite();
|
||
const sprite2 = new Sprite();
|
||
sprite.bitmap = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_NodeOpenBackground" +
|
||
"0" +
|
||
this._actor
|
||
);
|
||
sprite2.bitmap = ImageManager.loadPicture(
|
||
"menu/main/button/05_skillTree/05skillTree_NodeOpenBackground" + "99"
|
||
);
|
||
sprite.bitmap.addLoadListener(() => {
|
||
sprite.x = 0;
|
||
sprite.y = 0;
|
||
});
|
||
sprite2.bitmap.addLoadListener(() => {
|
||
sprite2.x = 0;
|
||
sprite2.y = 154;
|
||
});
|
||
|
||
this._container.addChild(this._backgroundSprite);
|
||
//後ろ側の方を先にaddchildする。
|
||
this._backgroundSprite.addChild(sprite2);
|
||
this._backgroundSprite.addChild(sprite);
|
||
}
|
||
|
||
reset(actorId) {
|
||
this._actor = actorId;
|
||
}
|
||
|
||
windowWidth() {
|
||
return this._windowRect.width;
|
||
}
|
||
|
||
windowHeight() {
|
||
return this._windowRect.height;
|
||
}
|
||
|
||
numVisibleRows() {
|
||
return Math.ceil(this.maxItems() / this.maxCols());
|
||
}
|
||
|
||
updatePlacement() {
|
||
this.x = this._windowRect.x;
|
||
this.y = this._windowRect.y;
|
||
}
|
||
|
||
makeCommandList() {
|
||
this.addCommand(NodeCloseYesText, "yes");
|
||
this.addCommand(NodeCloseNoText, "no");
|
||
}
|
||
|
||
itemRect(index) {
|
||
const rect = super.itemRect(index);
|
||
rect.x += 80;
|
||
rect.y += 48;
|
||
rect.width -= 320;
|
||
return rect;
|
||
}
|
||
|
||
refresh() {
|
||
super.refresh();
|
||
//背景画像のリフレッシュ
|
||
if (this._backgroundSprite) {
|
||
this._container.removeChild(this._backgroundSprite);
|
||
this._createBackImage();
|
||
}
|
||
const selectNode = this._skillTreeManager.selectNode();
|
||
if (!this._skillTreeManager.type()) return;
|
||
|
||
let sNodeParArr = [];
|
||
|
||
function addSkillNode(node) {
|
||
if (node && node._tag !== null && !sNodeParArr.includes(node)) {
|
||
// 重複チェックを追加
|
||
sNodeParArr.push(node);
|
||
// 各親ノードを順番に辿る
|
||
if (node._childs && node._childs.length > 0) {
|
||
node._childs.forEach((child) => {
|
||
addSkillNode(child); // 再帰的に親ノードを辿る
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// 選択しているノードのスキルを渡す
|
||
addSkillNode(selectNode);
|
||
|
||
//描画対象のノードだけをフィルタリング
|
||
const openedNodes = sNodeParArr.filter((node) => node.isOpened());
|
||
const totalSp = openedNodes.reduce(
|
||
(sum, node) => sum + node.info()._needSp,
|
||
0
|
||
);
|
||
|
||
const textWidth = this.windowWidth() - this.padding * 2 - 100;
|
||
const skillResetColor = ColorManager.textColor(2);
|
||
|
||
//テキストの描画 西ヤスアキ
|
||
this.resetFontSettings();
|
||
this.changeTextColor(skillResetColor);
|
||
let message;
|
||
if (openedNodes.length === 1) {
|
||
const singleNode = openedNodes[0];
|
||
message = `Reset ${singleNode.info().skill().name}? (${
|
||
singleNode.info()._needSp
|
||
}${SpName} Gained)`;
|
||
} else {
|
||
message = `Reset skills? (${totalSp} ${SpName} Gained)`;
|
||
}
|
||
|
||
this.drawText(message, 18, 0, textWidth, "left");
|
||
this.drawText("Reset Skills", 28, 157, textWidth, "left");
|
||
|
||
const lineHeight = 36;
|
||
// ループで最大8つまで描画し、8番目に "…etc" を追加
|
||
for (let index = 0; index < openedNodes.length && index < 7; index++) {
|
||
if (index === 6 && openedNodes.length > 7) {
|
||
this.drawText(
|
||
"…etc",
|
||
430,
|
||
200 + index * lineHeight,
|
||
textWidth,
|
||
"left"
|
||
);
|
||
break;
|
||
}
|
||
|
||
const node = openedNodes[index];
|
||
const skillInfo = node.info().skill();
|
||
const skillIconId = skillInfo.iconIndex;
|
||
const skillName = skillInfo.name;
|
||
const needSp = node.info()._needSp;
|
||
const yPos = 200 + index * lineHeight;
|
||
|
||
this.drawIcon(skillIconId, 118, yPos);
|
||
this.drawText(skillName, 154, yPos, textWidth, "left");
|
||
this.drawText(`: ${needSp}${SpName}`, 438, yPos, textWidth, "left");
|
||
}
|
||
this.resetFontSettings();
|
||
}
|
||
|
||
//選択肢の文字の位置変更のため 西ヤスアキ
|
||
drawItem(index) {
|
||
const rect = this.itemLineRect(index);
|
||
const align = this.itemTextAlign();
|
||
this.resetTextColor();
|
||
this.changePaintOpacity(this.isCommandEnabled(index));
|
||
this.drawText(this.commandName(index), rect.x, rect.y, rect.width, align);
|
||
}
|
||
|
||
//選択肢のカーソルの位置大きさ 西ヤスアキ
|
||
refreshCursor() {
|
||
if (this._cursorAll) {
|
||
this.refreshCursorForAll();
|
||
} else if (this.index() >= 0) {
|
||
const rect = this.itemRect(this.index());
|
||
this.setCursorRect(rect.x, rect.y, rect.width, rect.height);
|
||
} else {
|
||
this.setCursorRect(0, 0, 0, 0);
|
||
}
|
||
}
|
||
|
||
// The SE of skill learn is played, so the SE of OK is not played.
|
||
playOkSound() {
|
||
if (this.currentSymbol() === "no") super.playOkSound();
|
||
}
|
||
}
|
||
|
||
class SkillTreeView {
|
||
constructor(skillTreeManager, windowWidth, windowHeight) {
|
||
this._skillTreeManager = skillTreeManager;
|
||
this._windowWidth = windowWidth;
|
||
this._windowHeight = windowHeight;
|
||
}
|
||
|
||
static getPixelXY(point) {
|
||
const px = point.x * (IconWidth + IconSpaceWidth) + ViewBeginXOffset;
|
||
const py = point.y * (IconHeight + IconSpaceHeight) + ViewBeginYOffset;
|
||
return [px, py];
|
||
}
|
||
|
||
maxPxy() {
|
||
const [maxX, maxY] = this._skillTreeManager.maxXY();
|
||
return SkillTreeView.getPixelXY({ x: maxX, y: maxY });
|
||
}
|
||
|
||
viewXY() {
|
||
const selectNode = this._skillTreeManager.selectNode();
|
||
const [selectNodePx, selectNodePy] = SkillTreeView.getPixelXY(
|
||
selectNode.point
|
||
);
|
||
let [maxPx, maxPy] = this.maxPxy();
|
||
maxPx += IconWidth + IconSpaceWidth;
|
||
maxPy += IconHeight + IconSpaceHeight;
|
||
let viewX, viewY;
|
||
|
||
// ノードの中央を中心にビューを表示する。
|
||
const selectNodeCx = selectNodePx + IconWidth / 2;
|
||
const selectNodeCy = selectNodePy + IconHeight / 2;
|
||
|
||
if (selectNodeCx < this._windowWidth / 2) {
|
||
viewX = 0;
|
||
} else if (maxPx - selectNodeCx < this._windowWidth / 2) {
|
||
viewX = maxPx - (this._windowWidth - ViewBeginXOffset);
|
||
} else {
|
||
viewX = Math.floor(selectNodeCx - this._windowWidth / 2);
|
||
}
|
||
|
||
if (selectNodeCy < this._windowHeight / 2) {
|
||
viewY = 0;
|
||
} else if (maxPy - selectNodeCy < this._windowHeight / 2) {
|
||
viewY = maxPy - (this._windowHeight - ViewBeginYOffset);
|
||
} else {
|
||
viewY = Math.floor(selectNodeCy - this._windowHeight / 2);
|
||
}
|
||
|
||
if (viewX < 0) viewX = 0;
|
||
if (viewY < 0) viewY = 0;
|
||
return [viewX, viewY];
|
||
}
|
||
|
||
viewDrawNode(bitmap) {
|
||
for (const node of Object.values(this._skillTreeManager.getAllNodes())) {
|
||
let [px, py] = SkillTreeView.getPixelXY(node.point);
|
||
// NOTE: 強制オープンなどで選択可能でないノードがオープン済みになった場合は半透明にしない。
|
||
if (node.isSelectable() || node.isOpened()) {
|
||
this.drawIcon(bitmap, node.iconBitmap(), px, py);
|
||
} else {
|
||
this.drawIcon(bitmap, node.iconBitmap(), px, py, 96);
|
||
}
|
||
if (node.isOpened()) {
|
||
const x = px - ViewRectOfs;
|
||
const y = py - ViewRectOfs;
|
||
const width = IconWidth + ViewRectOfs * 2;
|
||
const height = IconHeight + ViewRectOfs * 2;
|
||
this.drawRect(bitmap, ViewRectColor, x, y, width, height, 2);
|
||
}
|
||
}
|
||
}
|
||
|
||
viewDrawLine(bitmap) {
|
||
for (const node of Object.values(this._skillTreeManager.getAllNodes())) {
|
||
let [px, py] = SkillTreeView.getPixelXY(node.point);
|
||
for (const child of node.childs()) {
|
||
let color;
|
||
if (node.isOpened()) {
|
||
color = ViewLineColorLearned;
|
||
} else {
|
||
color = ViewLineColorBase;
|
||
}
|
||
|
||
const [xDiff, yDiff] = this.nodeDiff(node, child);
|
||
if (ViewMode === "wide") {
|
||
const pxOfs = IconWidth;
|
||
const pyOfs = IconHeight / 2;
|
||
if (node.point.y === child.point.y) {
|
||
this.drawLine(
|
||
bitmap,
|
||
px + pxOfs,
|
||
py + pyOfs,
|
||
px + pxOfs + xDiff,
|
||
py + pyOfs,
|
||
color
|
||
);
|
||
} else {
|
||
const px1 = px + pxOfs;
|
||
const py1 = py + pyOfs;
|
||
const px2 = px1 + xDiff / 4;
|
||
const py2 = py1;
|
||
this.drawLine(bitmap, px1, py1, px2, py2, color);
|
||
const px3 = px2 + xDiff / 2;
|
||
const py3 = py2 + yDiff;
|
||
this.drawLine(bitmap, px2, py2, px3, py3, color);
|
||
const px4 = px3 + xDiff / 4;
|
||
const py4 = py3;
|
||
this.drawLine(bitmap, px3, py3, px4, py4, color);
|
||
}
|
||
} else if (ViewMode === "long") {
|
||
const pxOfs = IconWidth / 2;
|
||
const pyOfs = IconHeight;
|
||
if (node.point.x === child.point.x) {
|
||
this.drawLine(
|
||
bitmap,
|
||
px + pxOfs,
|
||
py + pyOfs,
|
||
px + pxOfs,
|
||
py + pyOfs + yDiff,
|
||
color
|
||
);
|
||
} else {
|
||
const px1 = px + pxOfs;
|
||
const py1 = py + pyOfs;
|
||
const px2 = px1;
|
||
const py2 = py1 + yDiff / 4;
|
||
this.drawLine(bitmap, px1, py1, px2, py2, color);
|
||
const px3 = px2 + xDiff;
|
||
const py3 = py2 + yDiff / 2;
|
||
this.drawLine(bitmap, px2, py2, px3, py3, color);
|
||
const px4 = px3;
|
||
const py4 = py3 + yDiff / 4;
|
||
this.drawLine(bitmap, px3, py3, px4, py4, color);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
nodeDiff(node1, node2) {
|
||
const [px1, py1] = SkillTreeView.getPixelXY(node1.point);
|
||
const [px2, py2] = SkillTreeView.getPixelXY(node2.point);
|
||
let xDiff = px2 - px1;
|
||
let yDiff = py2 - py1;
|
||
if (ViewMode === "wide") {
|
||
if (xDiff < 0) {
|
||
xDiff += IconWidth;
|
||
} else if (xDiff > 0) {
|
||
xDiff -= IconWidth;
|
||
}
|
||
} else if (ViewMode === "long") {
|
||
if (yDiff < 0) {
|
||
yDiff += IconHeight;
|
||
} else if (yDiff > 0) {
|
||
yDiff -= IconHeight;
|
||
}
|
||
}
|
||
return [xDiff, yDiff];
|
||
}
|
||
|
||
createView() {
|
||
this._skillTreeManager.makePoint();
|
||
const [maxPx, maxPy] = this.maxPxy();
|
||
let width, height;
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
width = maxPx + IconWidth + ViewBeginXOffset;
|
||
height = maxPy + IconHeight + ViewBeginYOffset;
|
||
} else {
|
||
width =
|
||
Math.ceil(maxPx / this._windowWidth) * this._windowWidth +
|
||
IconWidth +
|
||
IconSpaceWidth;
|
||
height =
|
||
Math.ceil(maxPy / this._windowHeight) * this._windowHeight +
|
||
IconHeight +
|
||
IconSpaceHeight;
|
||
}
|
||
const bitmap = new Bitmap(width, height);
|
||
this.viewDrawLine(bitmap);
|
||
this.viewDrawNode(bitmap);
|
||
return bitmap;
|
||
}
|
||
|
||
getCursorRect() {
|
||
this._skillTreeManager.makePoint();
|
||
const selectNode = this._skillTreeManager.selectNode();
|
||
const [px, py] = SkillTreeView.getPixelXY(selectNode.point);
|
||
const x = px - ViewCursorOfs * 1.5;
|
||
const y = py - ViewCursorOfs * 1.5;
|
||
const w = IconWidth + ViewCursorOfs * 3;
|
||
const h = IconHeight + ViewCursorOfs * 3;
|
||
return new Rectangle(x, y, w, h);
|
||
}
|
||
|
||
drawLine(bitmap, x1, y1, x2, y2, color) {
|
||
const ctx = bitmap._context;
|
||
ctx.beginPath();
|
||
ctx.moveTo(x1, y1);
|
||
ctx.lineTo(x2, y2);
|
||
ctx.strokeStyle = color;
|
||
ctx.lineWidth = ViewLineWidth;
|
||
ctx.closePath();
|
||
ctx.stroke();
|
||
}
|
||
|
||
drawRect(bitmap, style, x, y, width, height, rectLineWidth) {
|
||
const ctx = bitmap._context;
|
||
ctx.strokeStyle = style;
|
||
ctx.lineWidth = rectLineWidth;
|
||
ctx.strokeRect(x, y, width, height);
|
||
}
|
||
|
||
drawIcon(dstBitmap, iconBitmap, x, y, opacity = 255) {
|
||
const tmpOpacity = dstBitmap.paintOpacity;
|
||
dstBitmap.paintOpacity = opacity;
|
||
const pw = IconWidth;
|
||
const ph = IconHeight;
|
||
dstBitmap.blt(iconBitmap, 0, 0, pw, ph, x, y);
|
||
dstBitmap.paintOpacity = tmpOpacity;
|
||
}
|
||
}
|
||
|
||
// Initialize skill tree.
|
||
const _DataManager_createGameObjects = DataManager.createGameObjects;
|
||
DataManager.createGameObjects = function () {
|
||
_DataManager_createGameObjects.call(this);
|
||
$skillTreeData = new SkillTreeData();
|
||
};
|
||
|
||
const _Scene_Boot_create = Scene_Boot.prototype.create;
|
||
Scene_Boot.prototype.create = function () {
|
||
_Scene_Boot_create.call(this);
|
||
this.initSkillTreeConfig();
|
||
this.loadSkillTreeMap();
|
||
};
|
||
|
||
Scene_Boot.prototype.initSkillTreeConfig = function () {
|
||
$skillTreeConfigLoader = new SkillTreeConfigLoader();
|
||
};
|
||
|
||
Scene_Boot.prototype.loadSkillTreeMap = function () {
|
||
const skillTreeMapId = $skillTreeConfigLoader.configData().skillTreeMapId;
|
||
if (skillTreeMapId) {
|
||
for (const skillTreeName in skillTreeMapId) {
|
||
const mapId = skillTreeMapId[skillTreeName];
|
||
if (mapId === 0) continue;
|
||
const mapLoader = new SkillTreeMapLoader(mapId);
|
||
mapLoader.loadMap();
|
||
$skillTreeMapLoaders[skillTreeName] = mapLoader;
|
||
}
|
||
}
|
||
};
|
||
|
||
const _Scene_Boot_isReady = Scene_Boot.prototype.isReady;
|
||
Scene_Boot.prototype.isReady = function () {
|
||
if (!_Scene_Boot_isReady.call(this)) return false;
|
||
for (const mapLoader of Object.values($skillTreeMapLoaders)) {
|
||
if (!mapLoader.isLoaded()) return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
const _Game_Party_setupStartingMembers =
|
||
Game_Party.prototype.setupStartingMembers;
|
||
Game_Party.prototype.setupStartingMembers = function () {
|
||
_Game_Party_setupStartingMembers.call(this);
|
||
for (const actor of this.members()) {
|
||
const actorId = actor.actorId();
|
||
$skillTreeConfigLoader.loadConfig(actorId);
|
||
if (!$skillTreeData.sp(actorId)) $skillTreeData.setSp(actorId, 0);
|
||
}
|
||
};
|
||
|
||
const _Game_Party_addActor = Game_Party.prototype.addActor;
|
||
Game_Party.prototype.addActor = function (actorId) {
|
||
_Game_Party_addActor.call(this, actorId);
|
||
$skillTreeConfigLoader.loadConfig(actorId);
|
||
if (!$skillTreeData.sp(actorId)) $skillTreeData.setSp(actorId, 0);
|
||
};
|
||
|
||
// アクターのスキルツリーが存在しない場合はスキップする
|
||
Game_Party.prototype.makeMenuActorNextOrPreviousWhenSkillTree = function (
|
||
isNext
|
||
) {
|
||
let index = this.members().indexOf(this.menuActor());
|
||
if (index >= 0) {
|
||
const firstIndex = index;
|
||
do {
|
||
if (isNext) {
|
||
index = (index + 1) % this.members().length;
|
||
} else {
|
||
index = (index + this.members().length - 1) % this.members().length;
|
||
}
|
||
const actor = this.members()[index];
|
||
const types = $skillTreeData.types(actor.actorId());
|
||
if (types.length > 0) {
|
||
this.setMenuActor(actor);
|
||
break;
|
||
}
|
||
} while (firstIndex !== index);
|
||
} else {
|
||
this.setMenuActor(this.members()[0]);
|
||
}
|
||
};
|
||
|
||
// Add skill tree to menu command.
|
||
//const _Window_MenuCommand_addOriginalCommands = Window_MenuCommand.prototype.addOriginalCommands;
|
||
//Window_MenuCommand.prototype.addOriginalCommands = function() {
|
||
// _Window_MenuCommand_addOriginalCommands.call(this);
|
||
// if (MenuSkillTreeText !== "") this.addCommand(MenuSkillTreeText, "skillTree", this.isEnabledSkillTree());
|
||
//};
|
||
|
||
//Window_MenuCommand.prototype.isEnabledSkillTree = function() {
|
||
// if (EnabledSkillTreeSwitchId === 0) return true;
|
||
// return $gameSwitches.value(EnabledSkillTreeSwitchId);
|
||
//};
|
||
|
||
//const _Scene_Menu_createCommandWindow = Scene_Menu.prototype.createCommandWindow;
|
||
//Scene_Menu.prototype.createCommandWindow = function() {
|
||
// _Scene_Menu_createCommandWindow.call(this);
|
||
// this._commandWindow.setHandler("skillTree", this.commandPersonal.bind(this));
|
||
//};
|
||
|
||
//const _Scene_Menu_onPersonalOk = Scene_Menu.prototype.onPersonalOk;
|
||
//Scene_Menu.prototype.onPersonalOk = function() {
|
||
// _Scene_Menu_onPersonalOk.call(this);
|
||
// switch (this._commandWindow.currentSymbol()) {
|
||
// case "skillTree":
|
||
// SceneManager.push(Scene_SkillTree);
|
||
// break;
|
||
// }
|
||
//};
|
||
|
||
// アクターのスキルツリーが存在しない場合は、スキルツリー画面を表示しない
|
||
const _Window_MenuStatus_processOk = Window_MenuStatus.prototype.processOk;
|
||
Window_MenuStatus.prototype.processOk = function () {
|
||
const scene = SceneManager._scene;
|
||
if (
|
||
scene instanceof Scene_Menu &&
|
||
scene._commandWindow.currentSymbol() === "skillTree"
|
||
) {
|
||
// シーンがメニューでシンボルがスキルツリーの場合
|
||
const actor = this.actor(this.index());
|
||
const types = $skillTreeData.types(actor.actorId());
|
||
if (types.length > 0) {
|
||
$gameParty.setMenuActor(actor);
|
||
if (Utils.RPGMAKER_NAME === "MZ") {
|
||
Window_StatusBase.prototype.processOk.call(this);
|
||
} else {
|
||
Window_Selectable.prototype.processOk.call(this);
|
||
}
|
||
} else {
|
||
SoundManager.playBuzzer();
|
||
}
|
||
} else {
|
||
_Window_MenuStatus_processOk.call(this);
|
||
}
|
||
};
|
||
|
||
// MV compatible
|
||
const _Window_MenuStatus_actor = Window_MenuStatus.prototype.actor;
|
||
Window_MenuStatus.prototype.actor = function (index) {
|
||
if (Utils.RPGMAKER_NAME === "MZ")
|
||
return _Window_MenuStatus_actor.call(this, index);
|
||
return $gameParty.members()[index];
|
||
};
|
||
|
||
// Includes skill tree data in save data.
|
||
const _DataManager_makeSaveContents = DataManager.makeSaveContents;
|
||
DataManager.makeSaveContents = function () {
|
||
const contents = _DataManager_makeSaveContents.call(this);
|
||
contents.skillTreeData = $skillTreeData.makeSaveContents();
|
||
return contents;
|
||
};
|
||
|
||
const _DataManager_extractSaveContents = DataManager.extractSaveContents;
|
||
DataManager.extractSaveContents = function (contents) {
|
||
_DataManager_extractSaveContents.call(this, contents);
|
||
if (contents.skillTreeData)
|
||
$skillTreeData.loadSaveContents(contents.skillTreeData);
|
||
};
|
||
|
||
// Actor gain sp.
|
||
Game_Party.prototype.gainSp = function (sp) {
|
||
for (const actor of this.members()) {
|
||
actor.gainSp(sp);
|
||
}
|
||
};
|
||
|
||
Game_Actor.prototype.gainSp = function (sp) {
|
||
$skillTreeData.gainSp(this.actorId(), sp);
|
||
if ($skillTreeData.sp(this.actorId()) > MaxSp) {
|
||
$skillTreeData.setSp(this.actorId(), MaxSp);
|
||
}
|
||
};
|
||
|
||
// Get the sp when win a battle.
|
||
Game_Enemy.prototype.sp = function () {
|
||
const battleEndGainSp = this.enemy().meta.battleEndGainSp;
|
||
return battleEndGainSp ? parseInt(battleEndGainSp) : 0;
|
||
};
|
||
|
||
Game_Troop.prototype.spTotal = function () {
|
||
return this.deadMembers().reduce((r, enemy) => {
|
||
return r + enemy.sp();
|
||
}, 0);
|
||
};
|
||
|
||
const _BattleManager_makeRewards = BattleManager.makeRewards;
|
||
BattleManager.makeRewards = function () {
|
||
_BattleManager_makeRewards.call(this);
|
||
if (EnableGetSpWhenBattleEnd) this._rewards.sp = $gameTroop.spTotal();
|
||
};
|
||
|
||
const _BattleManager_gainRewards = BattleManager.gainRewards;
|
||
BattleManager.gainRewards = function () {
|
||
_BattleManager_gainRewards.call(this);
|
||
if (EnableGetSpWhenBattleEnd) this.gainSp();
|
||
};
|
||
|
||
BattleManager.gainSp = function () {
|
||
$gameParty.gainSp(this._rewards.sp);
|
||
};
|
||
|
||
const _BattleManager_displayRewards = BattleManager.displayRewards;
|
||
BattleManager.displayRewards = function () {
|
||
if (EnableGetSpWhenBattleEnd) {
|
||
this.displayExp();
|
||
this.displayGold();
|
||
this.displaySp();
|
||
this.displayDropItems();
|
||
} else {
|
||
_BattleManager_displayRewards.call(this);
|
||
}
|
||
};
|
||
|
||
BattleManager.displaySp = function () {
|
||
const sp = this._rewards.sp;
|
||
if (sp > 0) {
|
||
$gameMessage.add("\\." + BattleEndGetSpText.format(sp, SpName));
|
||
}
|
||
};
|
||
|
||
// Get the sp when level up.
|
||
const _Game_Temp_initialize = Game_Temp.prototype.initialize;
|
||
Game_Temp.prototype.initialize = function () {
|
||
_Game_Temp_initialize.call(this);
|
||
this._enableGetSpWhenLevelUp = EnableGetSpWhenLevelUp;
|
||
this._prevLevel = null;
|
||
};
|
||
|
||
Game_Temp.prototype.enableGetSpWhenLevelUp = function () {
|
||
return this._enableGetSpWhenLevelUp;
|
||
};
|
||
|
||
Game_Temp.prototype.setEnableGetSpWhenLevelUp = function (
|
||
enableGetSpWhenLevelUp
|
||
) {
|
||
return (this._enableGetSpWhenLevelUp = enableGetSpWhenLevelUp);
|
||
};
|
||
|
||
Game_Temp.prototype.prevLevel = function () {
|
||
return this._prevLevel;
|
||
};
|
||
|
||
Game_Temp.prototype.setPrevLevel = function (prevLevel) {
|
||
return (this._prevLevel = prevLevel);
|
||
};
|
||
|
||
const _Game_Actor_changeExp = Game_Actor.prototype.changeExp;
|
||
Game_Actor.prototype.changeExp = function (exp, show) {
|
||
$gameTemp.setPrevLevel(this._level);
|
||
_Game_Actor_changeExp.call(this, exp, show);
|
||
$gameTemp.setPrevLevel(null);
|
||
};
|
||
|
||
const _Game_Actor_levelUp = Game_Actor.prototype.levelUp;
|
||
Game_Actor.prototype.levelUp = function () {
|
||
_Game_Actor_levelUp.call(this);
|
||
if ($gameTemp.enableGetSpWhenLevelUp()) {
|
||
const sp = this.getLevelUpSp(this._level);
|
||
if (sp > 0) this.gainSp(sp);
|
||
}
|
||
};
|
||
|
||
const _Game_Actor_displayLevelUp = Game_Actor.prototype.displayLevelUp;
|
||
Game_Actor.prototype.displayLevelUp = function (newSkills) {
|
||
_Game_Actor_displayLevelUp.call(this, newSkills);
|
||
if ($gameTemp.enableGetSpWhenLevelUp()) {
|
||
let sp = 0;
|
||
for (
|
||
let level = $gameTemp.prevLevel() + 1;
|
||
level <= this._level;
|
||
level++
|
||
) {
|
||
sp += this.getLevelUpSp(level);
|
||
}
|
||
if (sp > 0) $gameMessage.add(LevelUpGetSpText.format(sp, SpName));
|
||
}
|
||
};
|
||
|
||
Game_Actor.prototype.getLevelUpSp = function (level) {
|
||
for (const data of $skillTreeConfigLoader.configData().levelUpGainSp) {
|
||
if (data.classId === this.currentClass().id) {
|
||
const defaultGainSp = data.default;
|
||
const sp = data[level.toString()];
|
||
return sp ? sp : defaultGainSp;
|
||
}
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
// Prevent SP from increasing due to level-up processing when changing jobs.
|
||
const _Game_Actor_changeClass = Game_Actor.prototype.changeClass;
|
||
Game_Actor.prototype.changeClass = function (classId, keepExp) {
|
||
$gameTemp.setEnableGetSpWhenLevelUp(false);
|
||
_Game_Actor_changeClass.call(this, classId, keepExp);
|
||
$gameTemp.setEnableGetSpWhenLevelUp(EnableGetSpWhenLevelUp);
|
||
};
|
||
|
||
// Define class alias.
|
||
return {
|
||
SkillTreeNodeInfo,
|
||
SkillTreeNode,
|
||
SkillTreeTopNode,
|
||
SkillDataType,
|
||
SkillTreeMapLoader,
|
||
SkillTreeConfigLoadError,
|
||
SkillTreeConfigLoader,
|
||
SkillTreeData,
|
||
SkillTreeManager,
|
||
Scene_SkillTree,
|
||
Window_TypeSelect,
|
||
Window_ActorInfo,
|
||
Window_SkillTreeNodeInfo,
|
||
Window_SkillTree,
|
||
Window_NodeOpen,
|
||
SkillTreeView,
|
||
};
|
||
})();
|