moon-red-goddess-cornelia/js/plugins/TRP_EventDebugUtils.js
2025-03-31 13:21:45 -05:00

901 lines
24 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//=============================================================================
// TRP_EventDebugUtils.js
//=============================================================================
// PluginCommand
// TempSave & Load
// Debug Skip / Stop
// Reload
//=============================================================================
/*:
* @target MZ
* @plugindesc イベントデバッグ効率化ツール
* @author Thirop
* @help
* このプラグインはテストプレイでのみ有効です。
*
* 以下のプラグインより下に配置すること。
* ・TRP_CORE.js
* ・TRP_DevTools.js (もし所持&導入している場合)
*
*
* 【即時セーブ/ロードについて】
* イベントページ編集時のテストプレイでの確認を効率化する目的の機能です。
* そのため、通しのテストプレイでのメインセーブデータとして利用にはおすすめしません。
*
* 基本的に<<即時セーブデータはセーブタイミングによっては破損する>>
* 前提でご利用ください。
*
* 戦闘シーンを含め、ほとんどのシーンでセーブ/ロードが利用できますが
* マップ以外では正常に動作しない可能性が高いのでご了承ください。
*
*
*
* □おすすめの使い方
* 長いイベントシーンを作る際には、確認したい部分に
* プラグインコマンド「スキップ停止」をはさみ、
* (MVは「debugEvent stop」)
*
* 「Ctrl(MacはCmd)+0キー」で高速スキップすることで
* 確認したい部分までスキップすることができます。
*
*
* また、スキップ停止時には自動で即時セーブを行います。
* (プラグイン設定「スキップ停止時に即時セーブ」をONにしておく)
*
* テストプレイで確認後にイベントページを編集したあとに、
* 「Ctrl(MacはCmd)+2キー」で即時ロードを行うことで
* テストプレイを再起動することなく素早く編集した箇所を確認できます。
* (プラグイン設定「即時ロード後にリロード」をONにしておく)
*
* ただし、「スキップ停止」コマンドより前の部分を編集すると、
* 即時ロード後に意図しない動作になるので注意してください。
*
*
* 少しずつ「スキップ停止」コマンドの位置をずらしながら
* 短い単位のコマンドごとに確実に仕上げていくことで
* 効率的にイベントを組み上げることができるでしょう!
*
*
*
* □おすすめの使い方2
* とにかく、テストプレイで「確認したい部分」までにいかに短時間で
* セットアップできるかが効率的なテストプレイの鍵です。
*
* たとえば、特定のパーティ・装備での戦闘バランスの確認を行いたいときは
* パーティーや装備を整えた上で、「Ctrl(MacはCmd)+1キー」で即時セーブしてから
* 戦闘を開始し、次にプレイする際は即時ロードですぐにセットアップできる
* ようにするといいでしょう。
*
* テストプレイを行う際に、どの状況で保存するかが鍵です!
*
* ※戦闘シーンでの即時セーブ/ロードも一応可能です。
* 戦闘シーンを改造している場合はエラーが出たり正しく動かない場合も
* ありえますが、一度即時セーブ/ロードが使えるか試しておくのも良いでしょう。
*
*
*
*
* 【ショートカットキー】
* ・各種ショーとカットキーはCtrl(MacはCmd)を押しながら入力
* ・大文字(Shiftキー押下)もOK
* ・TRP_DevToolsに登録する際は以下のプラグインコマンドで登録
* └即時セーブ 「eventDebug save」
* └即時ロード 「eventDebug load」
* └高速スキップ「eventDebug skip」
* └リロード  「eventDebug reload」
*
*
* 【MV形式コマンド】
* □スキップ停止
* 「eventDebug stop」
*
* □高速スキップ開始
* 「eventDebug skip」
*
*
*
*
* @command stop
* @text スキップ停止
* @desc スキップ停止
*
*
*
* @command skip
* @text 高速スキップ開始
* @desc 高速スキップ開始。「スキップ停止」コマンドまたは、Enterキーを押すと解除
*
*
*
*
* ============================================================
*
*
* @param command
* @text コマンド名(MV)
* @desc MV形式でのプラグインコマンド名
* @default eventDebug
* @type string
*
* @param saveSlot
* @text セーブスロット
* @desc 即時セーブ用のスロット(-1で「最大スロット数+1」のスロット。1以上の数値で任意のスロット)
* @default -1
* @type number
* @min -1
*
* @param skipRate
* @text 高速スキップ倍率
* @desc 高速スキップ倍率
* @default 10
* @type number
* @min 1
*
* @param saveOnStop
* @text スキップ停止時に即時セーブ
* @desc ONにするとスキップ停止時に即時セーブを実行
* @type boolean
* @default true
*
* @param reloadAfterTempLoad
* @text 即時ロード後にリロード
* @desc ONとすると即時ロード後に実行中のイベントページをリロード
* @default true
* @type boolean
*
*
* @param saveKey
* @text [ショトカ]即時セーブキー
* @desc 即時セーブのショートカットキー(Ctrl/MacはCmdキーを押しながら入力)
* @type string
* @default 1
*
* @param loadKey
* @text [ショトカ]即時ロードキー
* @desc 即時ロードのショートカットキー(Ctrl/MacはCmdキーを押しながら入力)
* @type string
* @default 2
*
* @param skipKey
* @text [ショトカ]高速スキップキー
* @desc 高速スキップのショートカットキー(Ctrl/MacはCmdキーを押しながら入力)
* @type string
* @default 0
*
* @param reloadKey
* @text [ショトカ]イベントリロードキー
* @desc 実行中のイベントページを再読み込みするショートカットキー(Ctrl/MacはCmdキーを押しながら入力)
* @type string
* @default r
*
*
*
*
*
*
*/
//=============================================================================
var TRP_CORE = TRP_CORE||{};
(function(){
'use strict';
if(!Utils.isNwjs() || !Utils.isOptionValid('test'))return;
var _Dev = TRP_CORE.DevFuncs;
var isMZ = Utils.RPGMAKER_NAME === "MZ";
var devToolsImported = PluginManager._scripts.contains('TRP_DevTools')
function evalBoolean(value){
return value==='true'||value===true;
};
var pluginName = 'TRP_EventDebugUtils';
var parameters = PluginManager.parameters(pluginName);
var saveSlot = Number(parameters.saveSlot)||-1;
var saveOnStop = evalBoolean(parameters.saveOnStop);
var reloadAfterTempLoad = evalBoolean(parameters.reloadAfterTempLoad);
var EventDebugUtils = TRP_CORE.EventDebugUtils = function EventDebugUtils(){}
//=============================================================================
// PluginCommand
//=============================================================================
var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command,args){
if(command.toLowerCase() === parameters.command.toLowerCase()){
EventDebugUtils.pluginCommand(args,this);
}else{
_Game_Interpreter_pluginCommand.call(this,...arguments);
}
};
if(isMZ){
['save','load','skip','stop','reload'].forEach(command=>{
PluginManager.registerCommand(pluginName,command,function(args){
var argsArr = Object.values(args)
argsArr.unshift(command);
EventDebugUtils.pluginCommand(argsArr,this);
});
});
};
EventDebugUtils.pluginCommand = function(args,interpreter){
var name = args[0];
var command = "processCommand"+name[0].toUpperCase()+name.substring(1)
this[command](args,interpreter);
};
//=============================================================================
// TempSave & Load
//=============================================================================
EventDebugUtils.processCommandSave = function(args,interpreter){
var i = 1;
var slot = Number(args[i++])||-1;
this.tempSave(slot);
};
EventDebugUtils.tempSave = function(slot){
var scenes = SceneManager._stack.map(sceneConstructor=>sceneConstructor.name);
scenes.push(SceneManager._scene.constructor.name);
$gameSystem._trpSceneNames = scenes
$gameSystem._trpTroop = $gameTroop;
var interpreter = EventDebugUtils.activeInterpreter();
var index = 0;
$gameSystem._trpActiveList = null;
if(interpreter){
index = interpreter._index;
this.adjustActiveInterpreterIndexForSave(interpreter);
$gameSystem._trpActiveList = this.activeInterpreterListInfo(interpreter);
}
var savefileId = this.tempSaveFileId(slot);
return this.saveGameAsync(savefileId)
.then(()=>{
_Dev.showTempText('tempSave','即時セーブ完了!')
SoundManager.playSave();
if(interpreter){
interpreter._index = index;
}
delete $gameSystem._trpActiveList;
delete $gameSystem._trpSceneNames;
});
};
EventDebugUtils.saveGameAsync = async function(savefileId){
if(isMZ){
return DataManager.saveGame(savefileId);
}else{
DataManager.saveGameWithoutRescue(savefileId);
return Promise.resolve();
}
};
EventDebugUtils.adjustActiveInterpreterIndexForSave = function(interpreter){
var targetCodes = this.rewindTargetCommandCodesForSave(interpreter);
if(!targetCodes)return;
var list = interpreter._list;
var index = interpreter._index-1;
while(index>=0){
var command = list[index];
if(command && targetCodes.contains(command.code)){
break;
}
index -= 1;
}
interpreter._index = index.clamp(0,list.length-1);
};
EventDebugUtils.rewindTargetCommandCodesForSave = function(interpreter){
switch(interpreter._waitMode){
case 'message':
return [101,102,103,104,105];
case 'video':
return [261];
default:
return null;
};
}
/* load
===================================*/
EventDebugUtils.processCommandLoad = function(args,interpreter){
var i = 1;
var slot = Number(args[i++])||-1;
this.tempLoad(slot);
};
EventDebugUtils.tempLoad = function(slot){
var savefileId = this.tempSaveFileId(slot);
return EventDebugUtils.loadGameAsync(savefileId)
.then(()=>{
SoundManager.playLoad();
// Scene_Load.prototype.reloadMapIfUpdated.call(this);
//skip fadeout
var lastScene = SceneManager._scene;
lastScene.startFadeOut = function(){};
lastScene.startEncounterEffect = function(){};
//restore troop
$gameTroop = $gameSystem._trpTroop;
delete $gameSystem._trpTroop;
//restore active list
var listInfo = $gameSystem._trpActiveList;
delete $gameSystem._trpActiveList;
if(reloadAfterTempLoad){
this.tryReloadActiveList(listInfo)
}
//goto same scene
var scenes = $gameSystem._trpSceneNames;
delete $gameSystem._trpSceneNames;
scenes = scenes || ['Scene_Map'];
var nextSceneConstructor = window[scenes.pop()]||Scene_Map;
var sceneStack = [];
for(const sceneName of scenes){
var scene = window[sceneName];
if(scene){
sceneStack.push(scene);
}
}
SceneManager._stack = sceneStack;
this.trySetupBattleForTempLoad(nextSceneConstructor);
SceneManager.goto(nextSceneConstructor);
//skip fadein
var nextScene = SceneManager._nextScene;
nextScene.startFadeIn = function(){};
setTimeout(()=>{
_Dev.showTempText('tempLoad','即時ロード完了!');
},100);
});
};
EventDebugUtils.trySetupBattleForTempLoad = function(nextSceneConstructor,battleSetting){
if(!(nextSceneConstructor === Scene_Battle))return false;
if(!$gameTroop._troopId)return false;
var onlyMap = true;
var interpreter = this.activeInterpreter(onlyMap);
if(interpreter){
var lastCommand = interpreter._list[interpreter._index-1];
if(lastCommand && lastCommand.code===301){
BattleManager.setEventCallback(n => {
interpreter._branch[interpreter._indent] = n;
});
}
}
return true;
};
EventDebugUtils.loadGameAsync = async function(savefileId){
if(isMZ){
return DataManager.loadGame(savefileId);
}else{
DataManager.loadGameWithoutRescue(savefileId);
return Promise.resolve();
}
};
/* helper
===================================*/
EventDebugUtils.tempSaveFileId = function(slot=saveSlot){
var savefileId = slot;
if(savefileId<=0){
savefileId = DataManager.maxSavefiles()+1;
}
return savefileId;
}
EventDebugUtils.activeInterpreter = function(onlyMap=false){
var interpreter;
if(!onlyMap && $gameTroop.inBattle() && $gameTroop.isEventRunning()){
interpreter = $gameTroop._interpreter;
}else if($gameMap.isEventRunning()){
interpreter = $gameMap._interpreter;
}else{
return null;
}
while(interpreter._childInterpreter){
interpreter = interpreter._childInterpreter;
}
return interpreter;
};
//=============================================================================
// Debug Skip / Stop
//=============================================================================
EventDebugUtils.processCommandSkip = function(args,interpreter){
this.startDebugSkip();
};
EventDebugUtils.startDebugSkip = function(){
TRP_CORE.eventSkip = true;
};
var _Game_Interpreter_updateWaitMode = Game_Interpreter.prototype.updateWaitMode;
Game_Interpreter.prototype.updateWaitMode = function(){
if(this._waitMode==='trpSave'){
return EventDebugUtils.saving;
}else{
return _Game_Interpreter_updateWaitMode.call(this,...arguments);
}
};
EventDebugUtils.saving = false;
EventDebugUtils.processCommandStop = function(args,interpreter){
var i = 1;
var needsSave;
if(args[i]===undefined){
needsSave = saveOnStop;
}else{
needsSave = evalBoolean(args[i]);
}
i++;
this.stopSkip();
if(!needsSave)return;
//temp save
var index = interpreter._index;
interpreter._index += 1;//exceed current command for save
interpreter._waitMode = 'trpSave';
this.saving = true;
this.tempSave()
.then(()=>{
this.saving = false;
});
};
EventDebugUtils.stopSkip = function(){
TRP_CORE.eventSkip = false;
//stop extra update in frame
SceneManager._trpSkipUpdateMain = true;
};
/* TRP_CORE
===================================*/
TRP_CORE.doubleSpeed = false;
TRP_CORE.eventSkip = false;
TRP_CORE.devToolsDisabled = false;
TRP_CORE.isEventRunning = function(){
if(TRP_CORE.showingToolsWindow)return false;
return $gameParty.inBattle() ? $gameTroop.isEventRunning() : $gameMap.isEventRunning();
};
(()=>{
SceneManager._trpSkipUpdateMain = false;
if(isMZ){
var _SceneManager_determineRepeatNumber = SceneManager.determineRepeatNumber;
SceneManager.determineRepeatNumber = function(deltaTime) {
var num = _SceneManager_determineRepeatNumber.call(this,deltaTime);
if(TRP_CORE.eventSkip && TRP_CORE.isEventRunning()){
num += (Number(parameters.skipRate)||1)-1;
}else if(TRP_CORE.doubleSpeed){
num += 1;
}
return num;
};
var _SceneManager_updateMain = SceneManager.updateMain;
SceneManager.updateMain = function(){
if(this._trpSkipUpdateMain)return;
_SceneManager_updateMain.call(this,...arguments);
}
var _SceneManager_update = SceneManager.update;
SceneManager.update = function(deltaTime) {
this._trpSkipUpdateMain = false;
_SceneManager_update.call(this,...arguments);
};
}else{
var _SceneManager_updateScene = SceneManager.updateScene;
SceneManager.updateScene = function() {
_SceneManager_updateScene.call(this);
if (this._scene && this.isCurrentSceneStarted()){
var num = 0;
if(TRP_CORE.eventSkip && TRP_CORE.isEventRunning()){
num += (Number(parameters.skipRate)||1)-1;
}else if(TRP_CORE.doubleSpeed){
num += 1;
}
this._trpSkipUpdateMain = false;
for(var i=0; i<num; i=(i+1)|0){
this.updateInputData();
this._scene.update();
if(SceneManager._trpSkipUpdateMain)break;
}
}
};
}
})();
var _Window_ScrollText_isFastForward = Window_ScrollText.prototype.isFastForward;
Window_ScrollText.prototype.isFastForward = function(){
if ($gameMessage.scrollNoFast())return false;
if(TRP_CORE.eventSkip && TRP_CORE.isEventRunning())return true;
return _Window_ScrollText_isFastForward.call(this);
};
var _Window_Message_isTriggered = Window_Message.prototype.isTriggered;
Window_Message.prototype.isTriggered = function() {
if(TRP_CORE.eventSkip && TRP_CORE.isEventRunning()){
return true;
}
return _Window_Message_isTriggered.call(this,...arguments);
};
//=============================================================================
// Reload
//=============================================================================
EventDebugUtils.activeInterpreterListInfo = function(interpreter){
var listInfo = null;
if(interpreter._eventId){
listInfo = this.tryCheckCurrentMapEventList(interpreter);
if(listInfo)return listInfo;
listInfo = this.tryCheckOtherMapEventList(interpreter);
if(listInfo)return listInfo;
}
//troop
listInfo = this.tryCheckTroopEventList(interpreter);
if(listInfo)return listInfo;
//common events
listInfo = this.tryCheckCommonEventList(interpreter)
if(listInfo)return listInfo;
//any map event
listInfo = this.tryCheckAnyMapEventList(interpreter);
if(listInfo)return listInfo;
return null;
}
EventDebugUtils.reloadActiveEventPage = function(){
var interpreter = this.activeInterpreter();
if(!interpreter){
SoundManager.playBuzzer();
return;
}
//reload list
var listInfo = this.activeInterpreterListInfo(interpreter);
if(!listInfo){
_Dev.showTempAlert('実行中イベントのリストの参照元を見つけられませんでした…')
SoundManager.playBuzzer();
return;
}
this.tryReloadActiveList(listInfo);
SoundManager.playOk();
/* operate windows
===================================*/
var window = SceneManager._scene._messageWindow;
if(window && !window.isClosed()){
window.terminateMessage();
window.pause = false;
window._waitCount = 0;
}
//scrollText Window
window = SceneManager._scene._scrollTextWindow;
if(window && !window.isClosed()){
window.terminateMessage();
}
/* execute command
===================================*/
this.adjustActiveInterpreterIndexForSave(interpreter);
interpreter.executeCommand();
if(window){
// window.startMessage();
}
};
EventDebugUtils._onLoad = null;
EventDebugUtils.tryReloadActiveList = function(listInfo){
var interpreter = this.activeInterpreter();
if(!interpreter)return;
var type = listInfo.shift();
var list = null;
if(type === 'event'){
var mapId = listInfo.shift();
var eventIdx = listInfo.shift();
var pageIdx = listInfo.shift();
var dataMap = this.loadMapData(mapId);
var event = dataMap.events[eventIdx];
if(!event)return false;
var page = event.pages[pageIdx];
if(!page)return false;
list = page.list;
if(!list)return false;
if(mapId===$gameMap._mapId){
//replace list data after map load
$dataMap.events[eventIdx].pages[pageIdx].list = list;
EventDebugUtils._onLoad = EventDebugUtils._onLoad||DataManager.onLoad;
DataManager.onLoad = function(object){
if(object === $dataMap){
this.onLoad = EventDebugUtils._onLoad;
if($gameMap._mapId === mapId){
$dataMap.events[eventIdx].pages[pageIdx].list = list;
}
}
EventDebugUtils._onLoad.call(this,...arguments);
}
}
}else if(type==='troop'){
var troopId = listInfo.shift();
var pageIdx = listInfo.shift();
var troops = JSON.parse(_Dev.readFile('data/Troops.json'));
this.extractArrayMetadata(troops);
var troop = troops[troopId];
if(!troop)return false;
var page = troop.pages[pageIdx];
if(!page)return false;
list = page.list;
if(!list)return false;
$dataTroops[troopId].pages[pageIdx].list = list;
}else if(type==='commonEvent'){
var eventIdx = listInfo.shift();
var commonEvent = JSON.parse(_Dev.readFile('data/CommonEvents.json'));
var event = commonEvent[eventIdx];
if(!event)return false;
list = event.list;
if(!list)return false;
$dataCommonEvents[eventIdx].list = list;
}
if(!list)return false;
interpreter._list = list;
return true;
}
EventDebugUtils.tryCheckCurrentMapEventList = function(interpreter,proc='mark'){
if(interpreter._mapId !== $gameMap._mapId)return null;
var event = $gameMap.event(interpreter._eventId);
if(!event)return null;
var data = event.event();
var eventIdx = $dataMap.events.indexOf(data);
if(eventIdx<0)return null;
var pages = data.pages;
var pageLen = pages.length;
var pageIdx = -1;
for(var pi=0; pi<pageLen; pi=(pi+1)|0){
var page = pages[pi];
if(page.list === interpreter._list){
pageIdx = pi;
break;
}
}
if(pageIdx<0)return null
var listInfo = ['event',interpreter._mapId,eventIdx,pageIdx];
return listInfo;
};
EventDebugUtils.loadMapData = function(mapId){
var mapFilePath = TRP_CORE.mapFilePath(mapId);
var dataMap = JSON.parse(_Dev.readFile(mapFilePath));
DataManager.extractMetadata(dataMap);
this.extractArrayMetadata(dataMap.events);
return dataMap;
};
EventDebugUtils.tryCheckOtherMapEventList = function(interpreter){
if(interpreter._mapId === $gameMap._mapId)return null;
var dataMap = this.loadMapData(interpreter._mapId);
var event = dataMap.events[interpreter._eventId];
if(!event)return null;
if(event.pages.length>1){
//ページ判別不可
_Dev.showTempAlert('別マップのイベントのためリロードできませんでした…')
return null;
}
return ['event',interpreter._mapId,interpreter._eventId,0];
};
EventDebugUtils.tryCheckTroopEventList = function(interpreter){
if(!$gameTroop.isEventRunning())return null;
var troop = $gameTroop.troop();
if(!troop)return null;
var pageIdx = -1;
var pages = troop.pages;
var length = pages.length;
for(var i=0; i<length; i=(i+1)|0){
var page = pages[i];
if(interpreter._list===page.list){
pageIdx = i;
break;
}
}
if(pageIdx<0)return null;
return ['troop',$gameTroop._troopId,pageIdx]
};
EventDebugUtils.tryCheckCommonEventList = function(interpreter){
var length = $dataCommonEvents.length;
var targetIdx = -1;
for(var i=0; i<length; i=(i+1)|0){
var event = $dataCommonEvents[i];
if(!event)continue;
if(event.list === interpreter._list){
targetIdx = i;
break;
}
}
if(targetIdx<0)return null;
return ['commonEvent',targetIdx];
};
EventDebugUtils.tryCheckAnyMapEventList = function(interpreter){
var eventIdx = -1;
var pageIdx = -1;
var events = $dataMap.events;
var eventLen = events.length;
for(var ei=0; ei<eventLen; ei=(ei+1)|0){
var event = events[ei];
if(!event)continue;
var pages = event.pages;
var pageLen = pages.length;
for(var pi=0; pi<pageLen; pi=(pi+1)|0){
var page = pages[pi];
if(page.list === interpreter._list){
eventIdx = ei;
pageIdx = pi;
break;
}
}
if(eventIdx>=0)break;
}
if(eventIdx<0)return null;
return ['event',interpreter._mapId,eventIdx,pageIdx];
};
/* helper
===================================*/
EventDebugUtils.extractArrayMetadata = function(array){
for(const data of array){
if(data && data.note!==undefined){
DataManager.extractMetadata(data);
}
}
}
//=============================================================================
// onKeyDown
//=============================================================================
var _SceneManager_onKeyDown = SceneManager.onKeyDown;
SceneManager.onKeyDown = function(event){
if(TRP_CORE.eventSkip){
TRP_CORE.eventSkip = false;
}
if(event.ctrlKey||event.metaKey){
if(EventDebugUtils.onKeyDown(event)){
return;
}
}
_SceneManager_onKeyDown.call(this,event);
};
EventDebugUtils.onKeyDown = function(event){
if(_Dev.isAnyDevToolsBusy())return;
if(!event.key)return;
var key = event.key;
if(event.shiftKey){
key = key.toUpperCase();
}
if(key===parameters.saveKey){
this.tempSave();
return true;
}else if(key===parameters.loadKey){
this.tempLoad();
return true;
}else if(key===parameters.skipKey){
this.startDebugSkip();
return true;
}else if(key===parameters.reloadKey){
this.reloadActiveEventPage();
return true;
}
return false;
}
})();