//============================================================================= // rmmz_managers.js v1.4.4 //============================================================================= //----------------------------------------------------------------------------- // DataManager // // The static class that manages the database and game objects. function DataManager() { throw new Error("This is a static class"); } $dataActors = null; $dataClasses = null; $dataSkills = null; $dataItems = null; $dataWeapons = null; $dataArmors = null; $dataEnemies = null; $dataTroops = null; $dataStates = null; $dataAnimations = null; $dataTilesets = null; $dataCommonEvents = null; $dataSystem = null; $dataMapInfos = null; $dataMap = null; $gameTemp = null; $gameSystem = null; $gameScreen = null; $gameTimer = null; $gameMessage = null; $gameSwitches = null; $gameVariables = null; $gameSelfSwitches = null; $gameActors = null; $gameParty = null; $gameTroop = null; $gameMap = null; $gamePlayer = null; $testEvent = null; DataManager._globalInfo = null; DataManager._errors = []; DataManager._databaseFiles = [ { name: "$dataActors", src: "Actors.json" }, { name: "$dataClasses", src: "Classes.json" }, { name: "$dataSkills", src: "Skills.json" }, { name: "$dataItems", src: "Items.json" }, { name: "$dataWeapons", src: "Weapons.json" }, { name: "$dataArmors", src: "Armors.json" }, { name: "$dataEnemies", src: "Enemies.json" }, { name: "$dataTroops", src: "Troops.json" }, { name: "$dataStates", src: "States.json" }, { name: "$dataAnimations", src: "Animations.json" }, { name: "$dataTilesets", src: "Tilesets.json" }, { name: "$dataCommonEvents", src: "CommonEvents.json" }, { name: "$dataSystem", src: "System.json" }, { name: "$dataMapInfos", src: "MapInfos.json" } ]; DataManager.loadGlobalInfo = function() { StorageManager.loadObject("global") .then(globalInfo => { this._globalInfo = globalInfo; this.removeInvalidGlobalInfo(); return 0; }) .catch(() => { this._globalInfo = []; }); }; DataManager.removeInvalidGlobalInfo = function() { const globalInfo = this._globalInfo; for (const info of globalInfo) { const savefileId = globalInfo.indexOf(info); if (!this.savefileExists(savefileId)) { delete globalInfo[savefileId]; } } }; DataManager.saveGlobalInfo = function() { StorageManager.saveObject("global", this._globalInfo); }; DataManager.isGlobalInfoLoaded = function() { return !!this._globalInfo; }; DataManager.loadDatabase = function() { const test = this.isBattleTest() || this.isEventTest(); const prefix = test ? "Test_" : ""; for (const databaseFile of this._databaseFiles) { this.loadDataFile(databaseFile.name, prefix + databaseFile.src); } if (this.isEventTest()) { this.loadDataFile("$testEvent", prefix + "Event.json"); } }; DataManager.loadDataFile = function(name, src) { const xhr = new XMLHttpRequest(); const url = "data/" + src; window[name] = null; xhr.open("GET", url); xhr.overrideMimeType("application/json"); xhr.onload = () => this.onXhrLoad(xhr, name, src, url); xhr.onerror = () => this.onXhrError(name, src, url); xhr.send(); }; DataManager.onXhrLoad = function(xhr, name, src, url) { if (xhr.status < 400) { window[name] = JSON.parse(xhr.responseText); this.onLoad(window[name]); } else { this.onXhrError(name, src, url); } }; DataManager.onXhrError = function(name, src, url) { const error = { name: name, src: src, url: url }; this._errors.push(error); }; DataManager.isDatabaseLoaded = function() { this.checkError(); for (const databaseFile of this._databaseFiles) { if (!window[databaseFile.name]) { return false; } } return true; }; DataManager.loadMapData = function(mapId) { if (mapId > 0) { const filename = "Map%1.json".format(mapId.padZero(3)); this.loadDataFile("$dataMap", filename); } else { this.makeEmptyMap(); } }; DataManager.makeEmptyMap = function() { $dataMap = {}; $dataMap.data = []; $dataMap.events = []; $dataMap.width = 100; $dataMap.height = 100; $dataMap.scrollType = 3; }; DataManager.isMapLoaded = function() { this.checkError(); return !!$dataMap; }; DataManager.onLoad = function(object) { if (this.isMapObject(object)) { this.extractMetadata(object); this.extractArrayMetadata(object.events); } else { this.extractArrayMetadata(object); } }; DataManager.isMapObject = function(object) { return !!(object.data && object.events); }; DataManager.extractArrayMetadata = function(array) { if (Array.isArray(array)) { for (const data of array) { if (data && "note" in data) { this.extractMetadata(data); } } } }; DataManager.extractMetadata = function(data) { const regExp = /<([^<>:]+)(:?)([^>]*)>/g; data.meta = {}; for (;;) { const match = regExp.exec(data.note); if (match) { if (match[2] === ":") { data.meta[match[1]] = match[3]; } else { data.meta[match[1]] = true; } } else { break; } } }; DataManager.checkError = function() { if (this._errors.length > 0) { const error = this._errors.shift(); const retry = () => { this.loadDataFile(error.name, error.src); }; throw ["LoadError", error.url, retry]; } }; DataManager.isBattleTest = function() { return Utils.isOptionValid("btest"); }; DataManager.isEventTest = function() { return Utils.isOptionValid("etest"); }; DataManager.isSkill = function(item) { return item && $dataSkills.includes(item); }; DataManager.isItem = function(item) { return item && $dataItems.includes(item); }; DataManager.isWeapon = function(item) { return item && $dataWeapons.includes(item); }; DataManager.isArmor = function(item) { return item && $dataArmors.includes(item); }; DataManager.createGameObjects = function() { $gameTemp = new Game_Temp(); $gameSystem = new Game_System(); $gameScreen = new Game_Screen(); $gameTimer = new Game_Timer(); $gameMessage = new Game_Message(); $gameSwitches = new Game_Switches(); $gameVariables = new Game_Variables(); $gameSelfSwitches = new Game_SelfSwitches(); $gameActors = new Game_Actors(); $gameParty = new Game_Party(); $gameTroop = new Game_Troop(); $gameMap = new Game_Map(); $gamePlayer = new Game_Player(); }; DataManager.setupNewGame = function() { this.createGameObjects(); this.selectSavefileForNewGame(); $gameParty.setupStartingMembers(); $gamePlayer.setupForNewGame(); Graphics.frameCount = 0; }; DataManager.setupBattleTest = function() { this.createGameObjects(); $gameParty.setupBattleTest(); BattleManager.setup($dataSystem.testTroopId, true, false); BattleManager.setBattleTest(true); BattleManager.playBattleBgm(); }; DataManager.setupEventTest = function() { this.createGameObjects(); this.selectSavefileForNewGame(); $gameParty.setupStartingMembers(); $gamePlayer.reserveTransfer(-1, 8, 6); $gamePlayer.setTransparent(false); }; DataManager.isAnySavefileExists = function() { return this._globalInfo.some(x => x); }; DataManager.latestSavefileId = function() { const globalInfo = this._globalInfo; const validInfo = globalInfo.slice(1).filter(x => x); const latest = Math.max(...validInfo.map(x => x.timestamp)); const index = globalInfo.findIndex(x => x && x.timestamp === latest); return index > 0 ? index : 0; }; DataManager.earliestSavefileId = function() { const globalInfo = this._globalInfo; const validInfo = globalInfo.slice(1).filter(x => x); const earliest = Math.min(...validInfo.map(x => x.timestamp)); const index = globalInfo.findIndex(x => x && x.timestamp === earliest); return index > 0 ? index : 0; }; DataManager.emptySavefileId = function() { const globalInfo = this._globalInfo; const maxSavefiles = this.maxSavefiles(); if (globalInfo.length < maxSavefiles) { return Math.max(1, globalInfo.length); } else { const index = globalInfo.slice(1).findIndex(x => !x); return index >= 0 ? index + 1 : -1; } }; DataManager.loadAllSavefileImages = function() { for (const info of this._globalInfo.filter(x => x)) { this.loadSavefileImages(info); } }; DataManager.loadSavefileImages = function(info) { if (info.characters && Symbol.iterator in info.characters) { for (const character of info.characters) { ImageManager.loadCharacter(character[0]); } } if (info.faces && Symbol.iterator in info.faces) { for (const face of info.faces) { ImageManager.loadFace(face[0]); } } }; DataManager.maxSavefiles = function() { return 20; }; DataManager.savefileInfo = function(savefileId) { const globalInfo = this._globalInfo; return globalInfo[savefileId] ? globalInfo[savefileId] : null; }; DataManager.savefileExists = function(savefileId) { const saveName = this.makeSavename(savefileId); return StorageManager.exists(saveName); }; DataManager.saveGame = function(savefileId) { const contents = this.makeSaveContents(); const saveName = this.makeSavename(savefileId); return StorageManager.saveObject(saveName, contents).then(() => { this._globalInfo[savefileId] = this.makeSavefileInfo(); this.saveGlobalInfo(); return 0; }); }; DataManager.loadGame = function(savefileId) { const saveName = this.makeSavename(savefileId); return StorageManager.loadObject(saveName).then(contents => { this.createGameObjects(); this.extractSaveContents(contents); this.correctDataErrors(); return 0; }); }; DataManager.makeSavename = function(savefileId) { return "file%1".format(savefileId); }; DataManager.selectSavefileForNewGame = function() { const emptySavefileId = this.emptySavefileId(); const earliestSavefileId = this.earliestSavefileId(); if (emptySavefileId > 0) { $gameSystem.setSavefileId(emptySavefileId); } else { $gameSystem.setSavefileId(earliestSavefileId); } }; DataManager.makeSavefileInfo = function() { const info = {}; info.title = $dataSystem.gameTitle; info.characters = $gameParty.charactersForSavefile(); info.faces = $gameParty.facesForSavefile(); info.playtime = $gameSystem.playtimeText(); info.timestamp = Date.now(); return info; }; DataManager.makeSaveContents = function() { // A save data does not contain $gameTemp, $gameMessage, and $gameTroop. const contents = {}; contents.system = $gameSystem; contents.screen = $gameScreen; contents.timer = $gameTimer; contents.switches = $gameSwitches; contents.variables = $gameVariables; contents.selfSwitches = $gameSelfSwitches; contents.actors = $gameActors; contents.party = $gameParty; contents.map = $gameMap; contents.player = $gamePlayer; return contents; }; DataManager.extractSaveContents = function(contents) { $gameSystem = contents.system; $gameScreen = contents.screen; $gameTimer = contents.timer; $gameSwitches = contents.switches; $gameVariables = contents.variables; $gameSelfSwitches = contents.selfSwitches; $gameActors = contents.actors; $gameParty = contents.party; $gameMap = contents.map; $gamePlayer = contents.player; }; DataManager.correctDataErrors = function() { $gameParty.removeInvalidMembers(); }; //----------------------------------------------------------------------------- // ConfigManager // // The static class that manages the configuration data. function ConfigManager() { throw new Error("This is a static class"); } ConfigManager.alwaysDash = false; ConfigManager.commandRemember = false; ConfigManager.touchUI = true; ConfigManager._isLoaded = false; Object.defineProperty(ConfigManager, "bgmVolume", { get: function() { return AudioManager._bgmVolume; }, set: function(value) { AudioManager.bgmVolume = value; }, configurable: true }); Object.defineProperty(ConfigManager, "bgsVolume", { get: function() { return AudioManager.bgsVolume; }, set: function(value) { AudioManager.bgsVolume = value; }, configurable: true }); Object.defineProperty(ConfigManager, "meVolume", { get: function() { return AudioManager.meVolume; }, set: function(value) { AudioManager.meVolume = value; }, configurable: true }); Object.defineProperty(ConfigManager, "seVolume", { get: function() { return AudioManager.seVolume; }, set: function(value) { AudioManager.seVolume = value; }, configurable: true }); ConfigManager.load = function() { StorageManager.loadObject("config") .then(config => this.applyData(config || {})) .catch(() => 0) .then(() => { this._isLoaded = true; return 0; }) .catch(() => 0); }; ConfigManager.save = function() { StorageManager.saveObject("config", this.makeData()); }; ConfigManager.isLoaded = function() { return this._isLoaded; }; ConfigManager.makeData = function() { const config = {}; config.alwaysDash = this.alwaysDash; config.commandRemember = this.commandRemember; config.touchUI = this.touchUI; config.bgmVolume = this.bgmVolume; config.bgsVolume = this.bgsVolume; config.meVolume = this.meVolume; config.seVolume = this.seVolume; return config; }; ConfigManager.applyData = function(config) { this.alwaysDash = this.readFlag(config, "alwaysDash", false); this.commandRemember = this.readFlag(config, "commandRemember", false); this.touchUI = this.readFlag(config, "touchUI", true); this.bgmVolume = this.readVolume(config, "bgmVolume"); this.bgsVolume = this.readVolume(config, "bgsVolume"); this.meVolume = this.readVolume(config, "meVolume"); this.seVolume = this.readVolume(config, "seVolume"); }; ConfigManager.readFlag = function(config, name, defaultValue) { if (name in config) { return !!config[name]; } else { return defaultValue; } }; ConfigManager.readVolume = function(config, name) { if (name in config) { return Number(config[name]).clamp(0, 100); } else { return 100; } }; //----------------------------------------------------------------------------- // StorageManager // // The static class that manages storage for saving game data. function StorageManager() { throw new Error("This is a static class"); } StorageManager._forageKeys = []; StorageManager._forageKeysUpdated = false; StorageManager.isLocalMode = function() { return Utils.isNwjs(); }; StorageManager.saveObject = function(saveName, object) { return this.objectToJson(object) .then(json => this.jsonToZip(json)) .then(zip => this.saveZip(saveName, zip)); }; StorageManager.loadObject = function(saveName) { return this.loadZip(saveName) .then(zip => this.zipToJson(zip)) .then(json => this.jsonToObject(json)); }; StorageManager.objectToJson = function(object) { return new Promise((resolve, reject) => { try { const json = JsonEx.stringify(object); resolve(json); } catch (e) { reject(e); } }); }; StorageManager.jsonToObject = function(json) { return new Promise((resolve, reject) => { try { const object = JsonEx.parse(json); resolve(object); } catch (e) { reject(e); } }); }; StorageManager.jsonToZip = function(json) { return new Promise((resolve, reject) => { try { const zip = pako.deflate(json, { to: "string", level: 1 }); if (zip.length >= 50000) { console.warn("Save data is too big."); } resolve(zip); } catch (e) { reject(e); } }); }; StorageManager.zipToJson = function(zip) { return new Promise((resolve, reject) => { try { if (zip) { const json = pako.inflate(zip, { to: "string" }); resolve(json); } else { resolve("null"); } } catch (e) { reject(e); } }); }; StorageManager.saveZip = function(saveName, zip) { if (this.isLocalMode()) { return this.saveToLocalFile(saveName, zip); } else { return this.saveToForage(saveName, zip); } }; StorageManager.loadZip = function(saveName) { if (this.isLocalMode()) { return this.loadFromLocalFile(saveName); } else { return this.loadFromForage(saveName); } }; StorageManager.exists = function(saveName) { if (this.isLocalMode()) { return this.localFileExists(saveName); } else { return this.forageExists(saveName); } }; StorageManager.remove = function(saveName) { if (this.isLocalMode()) { return this.removeLocalFile(saveName); } else { return this.removeForage(saveName); } }; StorageManager.saveToLocalFile = function(saveName, zip) { const dirPath = this.fileDirectoryPath(); const filePath = this.filePath(saveName); const backupFilePath = filePath + "_"; return new Promise((resolve, reject) => { this.fsMkdir(dirPath); this.fsUnlink(backupFilePath); this.fsRename(filePath, backupFilePath); try { this.fsWriteFile(filePath, zip); this.fsUnlink(backupFilePath); resolve(); } catch (e) { try { this.fsUnlink(filePath); this.fsRename(backupFilePath, filePath); } catch (e2) { // } reject(e); } }); }; StorageManager.loadFromLocalFile = function(saveName) { const filePath = this.filePath(saveName); return new Promise((resolve, reject) => { const data = this.fsReadFile(filePath); if (data) { resolve(data); } else { reject(new Error("Savefile not found")); } }); }; StorageManager.localFileExists = function(saveName) { const fs = require("fs"); return fs.existsSync(this.filePath(saveName)); }; StorageManager.removeLocalFile = function(saveName) { this.fsUnlink(this.filePath(saveName)); }; StorageManager.saveToForage = function(saveName, zip) { const key = this.forageKey(saveName); const testKey = this.forageTestKey(); setTimeout(() => localforage.removeItem(testKey)); return localforage .setItem(testKey, zip) .then(() => localforage.setItem(key, zip)) .then(() => this.updateForageKeys()); }; StorageManager.loadFromForage = function(saveName) { const key = this.forageKey(saveName); return localforage.getItem(key); }; StorageManager.forageExists = function(saveName) { const key = this.forageKey(saveName); return this._forageKeys.includes(key); }; StorageManager.removeForage = function(saveName) { const key = this.forageKey(saveName); return localforage.removeItem(key).then(() => this.updateForageKeys()); }; StorageManager.updateForageKeys = function() { this._forageKeysUpdated = false; return localforage.keys().then(keys => { this._forageKeys = keys; this._forageKeysUpdated = true; return 0; }); }; StorageManager.forageKeysUpdated = function() { return this._forageKeysUpdated; }; StorageManager.fsMkdir = function(path) { const fs = require("fs"); if (!fs.existsSync(path)) { fs.mkdirSync(path); } }; StorageManager.fsRename = function(oldPath, newPath) { const fs = require("fs"); if (fs.existsSync(oldPath)) { fs.renameSync(oldPath, newPath); } }; StorageManager.fsUnlink = function(path) { const fs = require("fs"); if (fs.existsSync(path)) { fs.unlinkSync(path); } }; StorageManager.fsReadFile = function(path) { const fs = require("fs"); if (fs.existsSync(path)) { return fs.readFileSync(path, { encoding: "utf8" }); } else { return null; } }; StorageManager.fsWriteFile = function(path, data) { const fs = require("fs"); fs.writeFileSync(path, data); }; StorageManager.fileDirectoryPath = function() { const path = require("path"); const base = path.dirname(process.mainModule.filename); return path.join(base, "save/"); }; StorageManager.filePath = function(saveName) { const dir = this.fileDirectoryPath(); return dir + saveName + ".rmmzsave"; }; StorageManager.forageKey = function(saveName) { const gameId = $dataSystem.advanced.gameId; return "rmmzsave." + gameId + "." + saveName; }; StorageManager.forageTestKey = function() { return "rmmzsave.test"; }; //----------------------------------------------------------------------------- // FontManager // // The static class that loads font files. function FontManager() { throw new Error("This is a static class"); } FontManager._urls = {}; FontManager._states = {}; FontManager.load = function(family, filename) { if (this._states[family] !== "loaded") { if (filename) { const url = this.makeUrl(filename); this.startLoading(family, url); } else { this._urls[family] = ""; this._states[family] = "loaded"; } } }; FontManager.isReady = function() { for (const family in this._states) { const state = this._states[family]; if (state === "loading") { return false; } if (state === "error") { this.throwLoadError(family); } } return true; }; FontManager.startLoading = function(family, url) { const source = "url(" + url + ")"; const font = new FontFace(family, source); this._urls[family] = url; this._states[family] = "loading"; font.load() .then(() => { document.fonts.add(font); this._states[family] = "loaded"; return 0; }) .catch(() => { this._states[family] = "error"; }); }; FontManager.throwLoadError = function(family) { const url = this._urls[family]; const retry = () => this.startLoading(family, url); throw ["LoadError", url, retry]; }; FontManager.makeUrl = function(filename) { return "fonts/" + Utils.encodeURI(filename); }; //----------------------------------------------------------------------------- // ImageManager // // The static class that loads images, creates bitmap objects and retains them. function ImageManager() { throw new Error("This is a static class"); } ImageManager.iconWidth = 32; ImageManager.iconHeight = 32; ImageManager.faceWidth = 144; ImageManager.faceHeight = 144; ImageManager._cache = {}; ImageManager._system = {}; ImageManager._emptyBitmap = new Bitmap(1, 1); ImageManager.loadAnimation = function(filename) { return this.loadBitmap("img/animations/", filename); }; ImageManager.loadBattleback1 = function(filename) { return this.loadBitmap("img/battlebacks1/", filename); }; ImageManager.loadBattleback2 = function(filename) { return this.loadBitmap("img/battlebacks2/", filename); }; ImageManager.loadEnemy = function(filename) { return this.loadBitmap("img/enemies/", filename); }; ImageManager.loadCharacter = function(filename) { return this.loadBitmap("img/characters/", filename); }; ImageManager.loadFace = function(filename) { return this.loadBitmap("img/faces/", filename); }; ImageManager.loadParallax = function(filename) { return this.loadBitmap("img/parallaxes/", filename); }; ImageManager.loadPicture = function(filename) { return this.loadBitmap("img/pictures/", filename); }; ImageManager.loadSvActor = function(filename) { return this.loadBitmap("img/sv_actors/", filename); }; ImageManager.loadSvEnemy = function(filename) { return this.loadBitmap("img/sv_enemies/", filename); }; ImageManager.loadSystem = function(filename) { return this.loadBitmap("img/system/", filename); }; ImageManager.loadTileset = function(filename) { return this.loadBitmap("img/tilesets/", filename); }; ImageManager.loadTitle1 = function(filename) { return this.loadBitmap("img/titles1/", filename); }; ImageManager.loadTitle2 = function(filename) { return this.loadBitmap("img/titles2/", filename); }; ImageManager.loadBitmap = function(folder, filename) { if (filename) { const url = folder + Utils.encodeURI(filename) + ".png"; return this.loadBitmapFromUrl(url); } else { return this._emptyBitmap; } }; ImageManager.loadBitmapFromUrl = function(url) { const cache = url.includes("/system/") ? this._system : this._cache; if (!cache[url]) { cache[url] = Bitmap.load(url); } return cache[url]; }; ImageManager.clear = function() { const cache = this._cache; for (const url in cache) { cache[url].destroy(); } this._cache = {}; }; ImageManager.isReady = function() { for (const cache of [this._cache, this._system]) { for (const url in cache) { const bitmap = cache[url]; if (bitmap.isError()) { this.throwLoadError(bitmap); } if (!bitmap.isReady()) { return false; } } } return true; }; ImageManager.throwLoadError = function(bitmap) { const retry = bitmap.retry.bind(bitmap); throw ["LoadError", bitmap.url, retry]; }; ImageManager.isObjectCharacter = function(filename) { const sign = Utils.extractFileName(filename).match(/^[!$]+/); return sign && sign[0].includes("!"); }; ImageManager.isBigCharacter = function(filename) { const sign = Utils.extractFileName(filename).match(/^[!$]+/); return sign && sign[0].includes("$"); }; ImageManager.isZeroParallax = function(filename) { return Utils.extractFileName(filename).charAt(0) === "!"; }; //----------------------------------------------------------------------------- // EffectManager // // The static class that loads Effekseer effects. function EffectManager() { throw new Error("This is a static class"); } EffectManager._cache = {}; EffectManager._errorUrls = []; EffectManager.load = function(filename) { if (filename) { const url = this.makeUrl(filename); const cache = this._cache; if (!cache[url] && Graphics.effekseer) { this.startLoading(url); } return cache[url]; } else { return null; } }; EffectManager.startLoading = function(url) { const onLoad = () => this.onLoad(url); const onError = (message, url) => this.onError(url); const effect = Graphics.effekseer.loadEffect(url, 1, onLoad, onError); this._cache[url] = effect; return effect; }; EffectManager.clear = function() { for (const url in this._cache) { const effect = this._cache[url]; Graphics.effekseer.releaseEffect(effect); } this._cache = {}; }; EffectManager.onLoad = function(/*url*/) { // }; EffectManager.onError = function(url) { this._errorUrls.push(url); }; EffectManager.makeUrl = function(filename) { return "effects/" + Utils.encodeURI(filename) + ".efkefc"; }; EffectManager.checkErrors = function() { const url = this._errorUrls.shift(); if (url) { this.throwLoadError(url); } }; EffectManager.throwLoadError = function(url) { const retry = () => this.startLoading(url); throw ["LoadError", url, retry]; }; EffectManager.isReady = function() { this.checkErrors(); for (const url in this._cache) { const effect = this._cache[url]; if (!effect.isLoaded) { return false; } } return true; }; //----------------------------------------------------------------------------- // AudioManager // // The static class that handles BGM, BGS, ME and SE. function AudioManager() { throw new Error("This is a static class"); } AudioManager._bgmVolume = 100; AudioManager._bgsVolume = 100; AudioManager._meVolume = 100; AudioManager._seVolume = 100; AudioManager._currentBgm = null; AudioManager._currentBgs = null; AudioManager._bgmBuffer = null; AudioManager._bgsBuffer = null; AudioManager._meBuffer = null; AudioManager._seBuffers = []; AudioManager._staticBuffers = []; AudioManager._replayFadeTime = 0.5; AudioManager._path = "audio/"; Object.defineProperty(AudioManager, "bgmVolume", { get: function() { return this._bgmVolume; }, set: function(value) { this._bgmVolume = value; this.updateBgmParameters(this._currentBgm); }, configurable: true }); Object.defineProperty(AudioManager, "bgsVolume", { get: function() { return this._bgsVolume; }, set: function(value) { this._bgsVolume = value; this.updateBgsParameters(this._currentBgs); }, configurable: true }); Object.defineProperty(AudioManager, "meVolume", { get: function() { return this._meVolume; }, set: function(value) { this._meVolume = value; this.updateMeParameters(this._currentMe); }, configurable: true }); Object.defineProperty(AudioManager, "seVolume", { get: function() { return this._seVolume; }, set: function(value) { this._seVolume = value; }, configurable: true }); AudioManager.playBgm = function(bgm, pos) { if (this.isCurrentBgm(bgm)) { this.updateBgmParameters(bgm); } else { this.stopBgm(); if (bgm.name) { this._bgmBuffer = this.createBuffer("bgm/", bgm.name); this.updateBgmParameters(bgm); if (!this._meBuffer) { this._bgmBuffer.play(true, pos || 0); } } } this.updateCurrentBgm(bgm, pos); }; AudioManager.replayBgm = function(bgm) { if (this.isCurrentBgm(bgm)) { this.updateBgmParameters(bgm); } else { this.playBgm(bgm, bgm.pos); if (this._bgmBuffer) { this._bgmBuffer.fadeIn(this._replayFadeTime); } } }; AudioManager.isCurrentBgm = function(bgm) { return ( this._currentBgm && this._bgmBuffer && this._currentBgm.name === bgm.name ); }; AudioManager.updateBgmParameters = function(bgm) { this.updateBufferParameters(this._bgmBuffer, this._bgmVolume, bgm); }; AudioManager.updateCurrentBgm = function(bgm, pos) { this._currentBgm = { name: bgm.name, volume: bgm.volume, pitch: bgm.pitch, pan: bgm.pan, pos: pos }; }; AudioManager.stopBgm = function() { if (this._bgmBuffer) { this._bgmBuffer.destroy(); this._bgmBuffer = null; this._currentBgm = null; } }; AudioManager.fadeOutBgm = function(duration) { if (this._bgmBuffer && this._currentBgm) { this._bgmBuffer.fadeOut(duration); this._currentBgm = null; } }; AudioManager.fadeInBgm = function(duration) { if (this._bgmBuffer && this._currentBgm) { this._bgmBuffer.fadeIn(duration); } }; AudioManager.playBgs = function(bgs, pos) { if (this.isCurrentBgs(bgs)) { this.updateBgsParameters(bgs); } else { this.stopBgs(); if (bgs.name) { this._bgsBuffer = this.createBuffer("bgs/", bgs.name); this.updateBgsParameters(bgs); this._bgsBuffer.play(true, pos || 0); } } this.updateCurrentBgs(bgs, pos); }; AudioManager.replayBgs = function(bgs) { if (this.isCurrentBgs(bgs)) { this.updateBgsParameters(bgs); } else { this.playBgs(bgs, bgs.pos); if (this._bgsBuffer) { this._bgsBuffer.fadeIn(this._replayFadeTime); } } }; AudioManager.isCurrentBgs = function(bgs) { return ( this._currentBgs && this._bgsBuffer && this._currentBgs.name === bgs.name ); }; AudioManager.updateBgsParameters = function(bgs) { this.updateBufferParameters(this._bgsBuffer, this._bgsVolume, bgs); }; AudioManager.updateCurrentBgs = function(bgs, pos) { this._currentBgs = { name: bgs.name, volume: bgs.volume, pitch: bgs.pitch, pan: bgs.pan, pos: pos }; }; AudioManager.stopBgs = function() { if (this._bgsBuffer) { this._bgsBuffer.destroy(); this._bgsBuffer = null; this._currentBgs = null; } }; AudioManager.fadeOutBgs = function(duration) { if (this._bgsBuffer && this._currentBgs) { this._bgsBuffer.fadeOut(duration); this._currentBgs = null; } }; AudioManager.fadeInBgs = function(duration) { if (this._bgsBuffer && this._currentBgs) { this._bgsBuffer.fadeIn(duration); } }; AudioManager.playMe = function(me) { this.stopMe(); if (me.name) { if (this._bgmBuffer && this._currentBgm) { this._currentBgm.pos = this._bgmBuffer.seek(); this._bgmBuffer.stop(); } this._meBuffer = this.createBuffer("me/", me.name); this.updateMeParameters(me); this._meBuffer.play(false); this._meBuffer.addStopListener(this.stopMe.bind(this)); } }; AudioManager.updateMeParameters = function(me) { this.updateBufferParameters(this._meBuffer, this._meVolume, me); }; AudioManager.fadeOutMe = function(duration) { if (this._meBuffer) { this._meBuffer.fadeOut(duration); } }; AudioManager.stopMe = function() { if (this._meBuffer) { this._meBuffer.destroy(); this._meBuffer = null; if ( this._bgmBuffer && this._currentBgm && !this._bgmBuffer.isPlaying() ) { this._bgmBuffer.play(true, this._currentBgm.pos); this._bgmBuffer.fadeIn(this._replayFadeTime); } } }; AudioManager.playSe = function(se) { if (se.name) { // [Note] Do not play the same sound in the same frame. const latestBuffers = this._seBuffers.filter( buffer => buffer.frameCount === Graphics.frameCount ); if (latestBuffers.find(buffer => buffer.name === se.name)) { return; } const buffer = this.createBuffer("se/", se.name); this.updateSeParameters(buffer, se); buffer.play(false); this._seBuffers.push(buffer); this.cleanupSe(); } }; AudioManager.updateSeParameters = function(buffer, se) { this.updateBufferParameters(buffer, this._seVolume, se); }; AudioManager.cleanupSe = function() { for (const buffer of this._seBuffers) { if (!buffer.isPlaying()) { buffer.destroy(); } } this._seBuffers = this._seBuffers.filter(buffer => buffer.isPlaying()); }; AudioManager.stopSe = function() { for (const buffer of this._seBuffers) { buffer.destroy(); } this._seBuffers = []; }; AudioManager.playStaticSe = function(se) { if (se.name) { this.loadStaticSe(se); for (const buffer of this._staticBuffers) { if (buffer.name === se.name) { buffer.stop(); this.updateSeParameters(buffer, se); buffer.play(false); break; } } } }; AudioManager.loadStaticSe = function(se) { if (se.name && !this.isStaticSe(se)) { const buffer = this.createBuffer("se/", se.name); this._staticBuffers.push(buffer); } }; AudioManager.isStaticSe = function(se) { for (const buffer of this._staticBuffers) { if (buffer.name === se.name) { return true; } } return false; }; AudioManager.stopAll = function() { this.stopMe(); this.stopBgm(); this.stopBgs(); this.stopSe(); }; AudioManager.saveBgm = function() { if (this._currentBgm) { const bgm = this._currentBgm; return { name: bgm.name, volume: bgm.volume, pitch: bgm.pitch, pan: bgm.pan, pos: this._bgmBuffer ? this._bgmBuffer.seek() : 0 }; } else { return this.makeEmptyAudioObject(); } }; AudioManager.saveBgs = function() { if (this._currentBgs) { const bgs = this._currentBgs; return { name: bgs.name, volume: bgs.volume, pitch: bgs.pitch, pan: bgs.pan, pos: this._bgsBuffer ? this._bgsBuffer.seek() : 0 }; } else { return this.makeEmptyAudioObject(); } }; AudioManager.makeEmptyAudioObject = function() { return { name: "", volume: 0, pitch: 0 }; }; AudioManager.createBuffer = function(folder, name) { const ext = this.audioFileExt(); const url = this._path + folder + Utils.encodeURI(name) + ext; const buffer = new WebAudio(url); buffer.name = name; buffer.frameCount = Graphics.frameCount; return buffer; }; AudioManager.updateBufferParameters = function(buffer, configVolume, audio) { if (buffer && audio) { buffer.volume = (configVolume * (audio.volume || 0)) / 10000; buffer.pitch = (audio.pitch || 0) / 100; buffer.pan = (audio.pan || 0) / 100; } }; AudioManager.audioFileExt = function() { return ".ogg"; }; AudioManager.checkErrors = function() { const buffers = [this._bgmBuffer, this._bgsBuffer, this._meBuffer]; buffers.push(...this._seBuffers); buffers.push(...this._staticBuffers); for (const buffer of buffers) { if (buffer && buffer.isError()) { this.throwLoadError(buffer); } } }; AudioManager.throwLoadError = function(webAudio) { const retry = webAudio.retry.bind(webAudio); throw ["LoadError", webAudio.url, retry]; }; //----------------------------------------------------------------------------- // SoundManager // // The static class that plays sound effects defined in the database. function SoundManager() { throw new Error("This is a static class"); } SoundManager.preloadImportantSounds = function() { this.loadSystemSound(0); this.loadSystemSound(1); this.loadSystemSound(2); this.loadSystemSound(3); }; SoundManager.loadSystemSound = function(n) { if ($dataSystem) { AudioManager.loadStaticSe($dataSystem.sounds[n]); } }; SoundManager.playSystemSound = function(n) { if ($dataSystem) { AudioManager.playStaticSe($dataSystem.sounds[n]); } }; SoundManager.playCursor = function() { this.playSystemSound(0); }; SoundManager.playOk = function() { this.playSystemSound(1); }; SoundManager.playCancel = function() { this.playSystemSound(2); }; SoundManager.playBuzzer = function() { this.playSystemSound(3); }; SoundManager.playEquip = function() { this.playSystemSound(4); }; SoundManager.playSave = function() { this.playSystemSound(5); }; SoundManager.playLoad = function() { this.playSystemSound(6); }; SoundManager.playBattleStart = function() { this.playSystemSound(7); }; SoundManager.playEscape = function() { this.playSystemSound(8); }; SoundManager.playEnemyAttack = function() { this.playSystemSound(9); }; SoundManager.playEnemyDamage = function() { this.playSystemSound(10); }; SoundManager.playEnemyCollapse = function() { this.playSystemSound(11); }; SoundManager.playBossCollapse1 = function() { this.playSystemSound(12); }; SoundManager.playBossCollapse2 = function() { this.playSystemSound(13); }; SoundManager.playActorDamage = function() { this.playSystemSound(14); }; SoundManager.playActorCollapse = function() { this.playSystemSound(15); }; SoundManager.playRecovery = function() { this.playSystemSound(16); }; SoundManager.playMiss = function() { this.playSystemSound(17); }; SoundManager.playEvasion = function() { this.playSystemSound(18); }; SoundManager.playMagicEvasion = function() { this.playSystemSound(19); }; SoundManager.playReflection = function() { this.playSystemSound(20); }; SoundManager.playShop = function() { this.playSystemSound(21); }; SoundManager.playUseItem = function() { this.playSystemSound(22); }; SoundManager.playUseSkill = function() { this.playSystemSound(23); }; //----------------------------------------------------------------------------- // TextManager // // The static class that handles terms and messages. function TextManager() { throw new Error("This is a static class"); } TextManager.basic = function(basicId) { return $dataSystem.terms.basic[basicId] || ""; }; TextManager.param = function(paramId) { return $dataSystem.terms.params[paramId] || ""; }; TextManager.command = function(commandId) { return $dataSystem.terms.commands[commandId] || ""; }; TextManager.message = function(messageId) { return $dataSystem.terms.messages[messageId] || ""; }; TextManager.getter = function(method, param) { return { get: function() { return this[method](param); }, configurable: true }; }; Object.defineProperty(TextManager, "currencyUnit", { get: function() { return $dataSystem.currencyUnit; }, configurable: true }); Object.defineProperties(TextManager, { level: TextManager.getter("basic", 0), levelA: TextManager.getter("basic", 1), hp: TextManager.getter("basic", 2), hpA: TextManager.getter("basic", 3), mp: TextManager.getter("basic", 4), mpA: TextManager.getter("basic", 5), tp: TextManager.getter("basic", 6), tpA: TextManager.getter("basic", 7), exp: TextManager.getter("basic", 8), expA: TextManager.getter("basic", 9), fight: TextManager.getter("command", 0), escape: TextManager.getter("command", 1), attack: TextManager.getter("command", 2), guard: TextManager.getter("command", 3), item: TextManager.getter("command", 4), skill: TextManager.getter("command", 5), equip: TextManager.getter("command", 6), status: TextManager.getter("command", 7), formation: TextManager.getter("command", 8), save: TextManager.getter("command", 9), gameEnd: TextManager.getter("command", 10), options: TextManager.getter("command", 11), weapon: TextManager.getter("command", 12), armor: TextManager.getter("command", 13), keyItem: TextManager.getter("command", 14), equip2: TextManager.getter("command", 15), optimize: TextManager.getter("command", 16), clear: TextManager.getter("command", 17), newGame: TextManager.getter("command", 18), continue_: TextManager.getter("command", 19), toTitle: TextManager.getter("command", 21), cancel: TextManager.getter("command", 22), buy: TextManager.getter("command", 24), sell: TextManager.getter("command", 25), alwaysDash: TextManager.getter("message", "alwaysDash"), commandRemember: TextManager.getter("message", "commandRemember"), touchUI: TextManager.getter("message", "touchUI"), bgmVolume: TextManager.getter("message", "bgmVolume"), bgsVolume: TextManager.getter("message", "bgsVolume"), meVolume: TextManager.getter("message", "meVolume"), seVolume: TextManager.getter("message", "seVolume"), possession: TextManager.getter("message", "possession"), expTotal: TextManager.getter("message", "expTotal"), expNext: TextManager.getter("message", "expNext"), saveMessage: TextManager.getter("message", "saveMessage"), loadMessage: TextManager.getter("message", "loadMessage"), file: TextManager.getter("message", "file"), autosave: TextManager.getter("message", "autosave"), partyName: TextManager.getter("message", "partyName"), emerge: TextManager.getter("message", "emerge"), preemptive: TextManager.getter("message", "preemptive"), surprise: TextManager.getter("message", "surprise"), escapeStart: TextManager.getter("message", "escapeStart"), escapeFailure: TextManager.getter("message", "escapeFailure"), victory: TextManager.getter("message", "victory"), defeat: TextManager.getter("message", "defeat"), obtainExp: TextManager.getter("message", "obtainExp"), obtainGold: TextManager.getter("message", "obtainGold"), obtainItem: TextManager.getter("message", "obtainItem"), levelUp: TextManager.getter("message", "levelUp"), obtainSkill: TextManager.getter("message", "obtainSkill"), useItem: TextManager.getter("message", "useItem"), criticalToEnemy: TextManager.getter("message", "criticalToEnemy"), criticalToActor: TextManager.getter("message", "criticalToActor"), actorDamage: TextManager.getter("message", "actorDamage"), actorRecovery: TextManager.getter("message", "actorRecovery"), actorGain: TextManager.getter("message", "actorGain"), actorLoss: TextManager.getter("message", "actorLoss"), actorDrain: TextManager.getter("message", "actorDrain"), actorNoDamage: TextManager.getter("message", "actorNoDamage"), actorNoHit: TextManager.getter("message", "actorNoHit"), enemyDamage: TextManager.getter("message", "enemyDamage"), enemyRecovery: TextManager.getter("message", "enemyRecovery"), enemyGain: TextManager.getter("message", "enemyGain"), enemyLoss: TextManager.getter("message", "enemyLoss"), enemyDrain: TextManager.getter("message", "enemyDrain"), enemyNoDamage: TextManager.getter("message", "enemyNoDamage"), enemyNoHit: TextManager.getter("message", "enemyNoHit"), evasion: TextManager.getter("message", "evasion"), magicEvasion: TextManager.getter("message", "magicEvasion"), magicReflection: TextManager.getter("message", "magicReflection"), counterAttack: TextManager.getter("message", "counterAttack"), substitute: TextManager.getter("message", "substitute"), buffAdd: TextManager.getter("message", "buffAdd"), debuffAdd: TextManager.getter("message", "debuffAdd"), buffRemove: TextManager.getter("message", "buffRemove"), actionFailure: TextManager.getter("message", "actionFailure") }); //----------------------------------------------------------------------------- // ColorManager // // The static class that handles the window colors. function ColorManager() { throw new Error("This is a static class"); } ColorManager.loadWindowskin = function() { this._windowskin = ImageManager.loadSystem("Window"); }; ColorManager.textColor = function(n) { const px = 96 + (n % 8) * 12 + 6; const py = 144 + Math.floor(n / 8) * 12 + 6; return this._windowskin.getPixel(px, py); }; ColorManager.normalColor = function() { return this.textColor(0); }; ColorManager.systemColor = function() { return this.textColor(16); }; ColorManager.crisisColor = function() { return this.textColor(17); }; ColorManager.deathColor = function() { return this.textColor(18); }; ColorManager.gaugeBackColor = function() { return this.textColor(19); }; ColorManager.hpGaugeColor1 = function() { return this.textColor(20); }; ColorManager.hpGaugeColor2 = function() { return this.textColor(21); }; ColorManager.mpGaugeColor1 = function() { return this.textColor(22); }; ColorManager.mpGaugeColor2 = function() { return this.textColor(23); }; ColorManager.mpCostColor = function() { return this.textColor(23); }; ColorManager.powerUpColor = function() { return this.textColor(24); }; ColorManager.powerDownColor = function() { return this.textColor(25); }; ColorManager.ctGaugeColor1 = function() { return this.textColor(26); }; ColorManager.ctGaugeColor2 = function() { return this.textColor(27); }; ColorManager.tpGaugeColor1 = function() { return this.textColor(28); }; ColorManager.tpGaugeColor2 = function() { return this.textColor(29); }; ColorManager.tpCostColor = function() { return this.textColor(29); }; ColorManager.pendingColor = function() { return this._windowskin.getPixel(120, 120); }; ColorManager.hpColor = function(actor) { if (!actor) { return this.normalColor(); } else if (actor.isDead()) { return this.deathColor(); } else if (actor.isDying()) { return this.crisisColor(); } else { return this.normalColor(); } }; ColorManager.mpColor = function(/*actor*/) { return this.normalColor(); }; ColorManager.tpColor = function(/*actor*/) { return this.normalColor(); }; ColorManager.paramchangeTextColor = function(change) { if (change > 0) { return this.powerUpColor(); } else if (change < 0) { return this.powerDownColor(); } else { return this.normalColor(); } }; ColorManager.damageColor = function(colorType) { switch (colorType) { case 0: // HP damage return "#ffffff"; case 1: // HP recover return "#b9ffb5"; case 2: // MP damage return "#ffff90"; case 3: // MP recover return "#80b0ff"; default: return "#808080"; } }; ColorManager.outlineColor = function() { return "rgba(0, 0, 0, 0.6)"; }; ColorManager.dimColor1 = function() { return "rgba(0, 0, 0, 0.6)"; }; ColorManager.dimColor2 = function() { return "rgba(0, 0, 0, 0)"; }; ColorManager.itemBackColor1 = function() { return "rgba(32, 32, 32, 0.5)"; }; ColorManager.itemBackColor2 = function() { return "rgba(0, 0, 0, 0.5)"; }; //----------------------------------------------------------------------------- // SceneManager // // The static class that manages scene transitions. function SceneManager() { throw new Error("This is a static class"); } SceneManager._scene = null; SceneManager._nextScene = null; SceneManager._stack = []; SceneManager._exiting = false; SceneManager._previousScene = null; SceneManager._previousClass = null; SceneManager._backgroundBitmap = null; SceneManager._smoothDeltaTime = 1; SceneManager._elapsedTime = 0; SceneManager.run = function(sceneClass) { try { this.initialize(); this.goto(sceneClass); Graphics.startGameLoop(); } catch (e) { this.catchException(e); } }; SceneManager.initialize = function() { this.checkBrowser(); this.checkPluginErrors(); this.initGraphics(); this.initAudio(); this.initVideo(); this.initInput(); this.setupEventHandlers(); }; SceneManager.checkBrowser = function() { if (!Utils.canUseWebGL()) { throw new Error("Your browser does not support WebGL."); } if (!Utils.canUseWebAudioAPI()) { throw new Error("Your browser does not support Web Audio API."); } if (!Utils.canUseCssFontLoading()) { throw new Error("Your browser does not support CSS Font Loading."); } if (!Utils.canUseIndexedDB()) { throw new Error("Your browser does not support IndexedDB."); } }; SceneManager.checkPluginErrors = function() { PluginManager.checkErrors(); }; SceneManager.initGraphics = function() { if (!Graphics.initialize()) { throw new Error("Failed to initialize graphics."); } Graphics.setTickHandler(this.update.bind(this)); }; SceneManager.initAudio = function() { WebAudio.initialize(); }; SceneManager.initVideo = function() { Video.initialize(Graphics.width, Graphics.height); }; SceneManager.initInput = function() { Input.initialize(); TouchInput.initialize(); }; SceneManager.setupEventHandlers = function() { window.addEventListener("error", this.onError.bind(this)); window.addEventListener("unhandledrejection", this.onReject.bind(this)); window.addEventListener("unload", this.onUnload.bind(this)); document.addEventListener("keydown", this.onKeyDown.bind(this)); }; SceneManager.update = function(deltaTime) { try { const n = this.determineRepeatNumber(deltaTime); for (let i = 0; i < n; i++) { this.updateMain(); } } catch (e) { this.catchException(e); } }; SceneManager.determineRepeatNumber = function(deltaTime) { // [Note] We consider environments where the refresh rate is higher than // 60Hz, but ignore sudden irregular deltaTime. this._smoothDeltaTime *= 0.8; this._smoothDeltaTime += Math.min(deltaTime, 2) * 0.2; if (this._smoothDeltaTime >= 0.9) { this._elapsedTime = 0; return Math.round(this._smoothDeltaTime); } else { this._elapsedTime += deltaTime; if (this._elapsedTime >= 1) { this._elapsedTime -= 1; return 1; } return 0; } }; SceneManager.terminate = function() { window.close(); }; SceneManager.onError = function(event) { console.error(event.message); console.error(event.filename, event.lineno); try { this.stop(); Graphics.printError("Error", event.message, event); AudioManager.stopAll(); } catch (e) { // } }; SceneManager.onReject = function(event) { // Catch uncaught exception in Promise event.message = event.reason; this.onError(event); }; SceneManager.onUnload = function() { ImageManager.clear(); EffectManager.clear(); AudioManager.stopAll(); }; SceneManager.onKeyDown = function(event) { if (!event.ctrlKey && !event.altKey) { switch (event.keyCode) { case 116: // F5 this.reloadGame(); break; case 119: // F8 this.showDevTools(); break; } } }; SceneManager.reloadGame = function() { if (Utils.isNwjs()) { chrome.runtime.reload(); } }; SceneManager.showDevTools = function() { if (Utils.isNwjs() && Utils.isOptionValid("test")) { nw.Window.get().showDevTools(); } }; SceneManager.catchException = function(e) { if (e instanceof Error) { this.catchNormalError(e); } else if (e instanceof Array && e[0] === "LoadError") { this.catchLoadError(e); } else { this.catchUnknownError(e); } this.stop(); }; SceneManager.catchNormalError = function(e) { Graphics.printError(e.name, e.message, e); AudioManager.stopAll(); console.error(e.stack); }; SceneManager.catchLoadError = function(e) { const url = e[1]; const retry = e[2]; Graphics.printError("Failed to load", url); if (retry) { Graphics.showRetryButton(() => { retry(); SceneManager.resume(); }); } else { AudioManager.stopAll(); } }; SceneManager.catchUnknownError = function(e) { Graphics.printError("UnknownError", String(e)); AudioManager.stopAll(); }; SceneManager.updateMain = function() { this.updateFrameCount(); this.updateInputData(); this.updateEffekseer(); this.changeScene(); this.updateScene(); }; SceneManager.updateFrameCount = function() { Graphics.frameCount++; }; SceneManager.updateInputData = function() { Input.update(); TouchInput.update(); }; SceneManager.updateEffekseer = function() { if (Graphics.effekseer && this.isGameActive()) { Graphics.effekseer.update(); } }; SceneManager.changeScene = function() { if (this.isSceneChanging() && !this.isCurrentSceneBusy()) { if (this._scene) { this._scene.terminate(); this.onSceneTerminate(); } this._scene = this._nextScene; this._nextScene = null; if (this._scene) { this._scene.create(); this.onSceneCreate(); } if (this._exiting) { this.terminate(); } } }; SceneManager.updateScene = function() { if (this._scene) { if (this._scene.isStarted()) { if (this.isGameActive()) { this._scene.update(); } } else if (this._scene.isReady()) { this.onBeforeSceneStart(); this._scene.start(); this.onSceneStart(); } } }; SceneManager.isGameActive = function() { // [Note] We use "window.top" to support an iframe. try { return window.top.document.hasFocus(); } catch (e) { // SecurityError return true; } }; SceneManager.onSceneTerminate = function() { this._previousScene = this._scene; this._previousClass = this._scene.constructor; Graphics.setStage(null); }; SceneManager.onSceneCreate = function() { Graphics.startLoading(); }; SceneManager.onBeforeSceneStart = function() { if (this._previousScene) { this._previousScene.destroy(); this._previousScene = null; } if (Graphics.effekseer) { Graphics.effekseer.stopAll(); } }; SceneManager.onSceneStart = function() { Graphics.endLoading(); Graphics.setStage(this._scene); }; SceneManager.isSceneChanging = function() { return this._exiting || !!this._nextScene; }; SceneManager.isCurrentSceneBusy = function() { return this._scene && this._scene.isBusy(); }; SceneManager.isNextScene = function(sceneClass) { return this._nextScene && this._nextScene.constructor === sceneClass; }; SceneManager.isPreviousScene = function(sceneClass) { return this._previousClass === sceneClass; }; SceneManager.goto = function(sceneClass) { if (sceneClass) { this._nextScene = new sceneClass(); } if (this._scene) { this._scene.stop(); } }; SceneManager.push = function(sceneClass) { this._stack.push(this._scene.constructor); this.goto(sceneClass); }; SceneManager.pop = function() { if (this._stack.length > 0) { this.goto(this._stack.pop()); } else { this.exit(); } }; SceneManager.exit = function() { this.goto(null); this._exiting = true; }; SceneManager.clearStack = function() { this._stack = []; }; SceneManager.stop = function() { Graphics.stopGameLoop(); }; SceneManager.prepareNextScene = function() { this._nextScene.prepare(...arguments); }; SceneManager.snap = function() { return Bitmap.snap(this._scene); }; SceneManager.snapForBackground = function() { if (this._backgroundBitmap) { this._backgroundBitmap.destroy(); } this._backgroundBitmap = this.snap(); }; SceneManager.backgroundBitmap = function() { return this._backgroundBitmap; }; SceneManager.resume = function() { TouchInput.update(); Graphics.startGameLoop(); }; //----------------------------------------------------------------------------- // BattleManager // // The static class that manages battle progress. function BattleManager() { throw new Error("This is a static class"); } BattleManager.setup = function(troopId, canEscape, canLose) { this.initMembers(); this._canEscape = canEscape; this._canLose = canLose; $gameTroop.setup(troopId); $gameScreen.onBattleStart(); this.makeEscapeRatio(); }; BattleManager.initMembers = function() { this._phase = ""; this._inputting = false; this._canEscape = false; this._canLose = false; this._battleTest = false; this._eventCallback = null; this._preemptive = false; this._surprise = false; this._currentActor = null; this._actionForcedBattler = null; this._mapBgm = null; this._mapBgs = null; this._actionBattlers = []; this._subject = null; this._action = null; this._targets = []; this._logWindow = null; this._spriteset = null; this._escapeRatio = 0; this._escaped = false; this._rewards = {}; this._tpbNeedsPartyCommand = true; }; BattleManager.isTpb = function() { return $dataSystem.battleSystem >= 1; }; BattleManager.isActiveTpb = function() { return $dataSystem.battleSystem === 1; }; BattleManager.isBattleTest = function() { return this._battleTest; }; BattleManager.setBattleTest = function(battleTest) { this._battleTest = battleTest; }; BattleManager.setEventCallback = function(callback) { this._eventCallback = callback; }; BattleManager.setLogWindow = function(logWindow) { this._logWindow = logWindow; }; BattleManager.setSpriteset = function(spriteset) { this._spriteset = spriteset; }; BattleManager.onEncounter = function() { this._preemptive = Math.random() < this.ratePreemptive(); this._surprise = Math.random() < this.rateSurprise() && !this._preemptive; }; BattleManager.ratePreemptive = function() { return $gameParty.ratePreemptive($gameTroop.agility()); }; BattleManager.rateSurprise = function() { return $gameParty.rateSurprise($gameTroop.agility()); }; BattleManager.saveBgmAndBgs = function() { this._mapBgm = AudioManager.saveBgm(); this._mapBgs = AudioManager.saveBgs(); }; BattleManager.playBattleBgm = function() { AudioManager.playBgm($gameSystem.battleBgm()); AudioManager.stopBgs(); }; BattleManager.playVictoryMe = function() { AudioManager.playMe($gameSystem.victoryMe()); }; BattleManager.playDefeatMe = function() { AudioManager.playMe($gameSystem.defeatMe()); }; BattleManager.replayBgmAndBgs = function() { if (this._mapBgm) { AudioManager.replayBgm(this._mapBgm); } else { AudioManager.stopBgm(); } if (this._mapBgs) { AudioManager.replayBgs(this._mapBgs); } }; BattleManager.makeEscapeRatio = function() { this._escapeRatio = (0.5 * $gameParty.agility()) / $gameTroop.agility(); }; BattleManager.update = function(timeActive) { if (!this.isBusy() && !this.updateEvent()) { this.updatePhase(timeActive); } if (this.isTpb()) { this.updateTpbInput(); } }; BattleManager.updatePhase = function(timeActive) { switch (this._phase) { case "start": this.updateStart(); break; case "turn": this.updateTurn(timeActive); break; case "action": this.updateAction(); break; case "turnEnd": this.updateTurnEnd(); break; case "battleEnd": this.updateBattleEnd(); break; } }; BattleManager.updateEvent = function() { switch (this._phase) { case "start": case "turn": case "turnEnd": if (this.isActionForced()) { this.processForcedAction(); return true; } else { return this.updateEventMain(); } } return this.checkAbort(); }; BattleManager.updateEventMain = function() { $gameTroop.updateInterpreter(); $gameParty.requestMotionRefresh(); if ($gameTroop.isEventRunning() || this.checkBattleEnd()) { return true; } $gameTroop.setupBattleEvent(); if ($gameTroop.isEventRunning() || SceneManager.isSceneChanging()) { return true; } return false; }; BattleManager.isBusy = function() { return ( $gameMessage.isBusy() || this._spriteset.isBusy() || this._logWindow.isBusy() ); }; BattleManager.updateTpbInput = function() { if (this._inputting) { this.checkTpbInputClose(); } else { this.checkTpbInputOpen(); } }; BattleManager.checkTpbInputClose = function() { if (!this.isPartyTpbInputtable() || this.needsActorInputCancel()) { this.cancelActorInput(); this._currentActor = null; this._inputting = false; } }; BattleManager.checkTpbInputOpen = function() { if (this.isPartyTpbInputtable()) { if (this._tpbNeedsPartyCommand) { this._inputting = true; this._tpbNeedsPartyCommand = false; } else { this.selectNextCommand(); } } }; BattleManager.isPartyTpbInputtable = function() { return $gameParty.canInput() && this.isTpbMainPhase(); }; BattleManager.needsActorInputCancel = function() { return this._currentActor && !this._currentActor.canInput(); }; BattleManager.isTpbMainPhase = function() { return ["turn", "turnEnd", "action"].includes(this._phase); }; BattleManager.isInputting = function() { return this._inputting; }; BattleManager.isInTurn = function() { return this._phase === "turn"; }; BattleManager.isTurnEnd = function() { return this._phase === "turnEnd"; }; BattleManager.isAborting = function() { return this._phase === "aborting"; }; BattleManager.isBattleEnd = function() { return this._phase === "battleEnd"; }; BattleManager.canEscape = function() { return this._canEscape; }; BattleManager.canLose = function() { return this._canLose; }; BattleManager.isEscaped = function() { return this._escaped; }; BattleManager.actor = function() { return this._currentActor; }; BattleManager.startBattle = function() { this._phase = "start"; $gameSystem.onBattleStart(); $gameParty.onBattleStart(this._preemptive); $gameTroop.onBattleStart(this._surprise); this.displayStartMessages(); }; BattleManager.displayStartMessages = function() { for (const name of $gameTroop.enemyNames()) { $gameMessage.add(TextManager.emerge.format(name)); } if (this._preemptive) { $gameMessage.add(TextManager.preemptive.format($gameParty.name())); } else if (this._surprise) { $gameMessage.add(TextManager.surprise.format($gameParty.name())); } }; BattleManager.startInput = function() { this._phase = "input"; this._inputting = true; $gameParty.makeActions(); $gameTroop.makeActions(); this._currentActor = null; if (this._surprise || !$gameParty.canInput()) { this.startTurn(); } }; BattleManager.inputtingAction = function() { return this._currentActor ? this._currentActor.inputtingAction() : null; }; BattleManager.selectNextCommand = function() { if (this._currentActor) { if (this._currentActor.selectNextCommand()) { return; } this.finishActorInput(); } this.selectNextActor(); }; BattleManager.selectNextActor = function() { this.changeCurrentActor(true); if (!this._currentActor) { if (this.isTpb()) { this.changeCurrentActor(true); } else { this.startTurn(); } } }; BattleManager.selectPreviousCommand = function() { if (this._currentActor) { if (this._currentActor.selectPreviousCommand()) { return; } this.cancelActorInput(); } this.selectPreviousActor(); }; BattleManager.selectPreviousActor = function() { if (this.isTpb()) { this.changeCurrentActor(true); if (!this._currentActor) { this._inputting = $gameParty.canInput(); } } else { this.changeCurrentActor(false); } }; BattleManager.changeCurrentActor = function(forward) { const members = $gameParty.battleMembers(); let actor = this._currentActor; for (;;) { const currentIndex = members.indexOf(actor); actor = members[currentIndex + (forward ? 1 : -1)]; if (!actor || actor.canInput()) { break; } } this._currentActor = actor ? actor : null; this.startActorInput(); }; BattleManager.startActorInput = function() { if (this._currentActor) { this._currentActor.setActionState("inputting"); this._inputting = true; } }; BattleManager.finishActorInput = function() { if (this._currentActor) { if (this.isTpb()) { this._currentActor.startTpbCasting(); } this._currentActor.setActionState("waiting"); } }; BattleManager.cancelActorInput = function() { if (this._currentActor) { this._currentActor.setActionState("undecided"); } }; BattleManager.updateStart = function() { if (this.isTpb()) { this._phase = "turn"; } else { this.startInput(); } }; BattleManager.startTurn = function() { this._phase = "turn"; $gameTroop.increaseTurn(); $gameParty.requestMotionRefresh(); if (!this.isTpb()) { this.makeActionOrders(); this._logWindow.startTurn(); this._inputting = false; } }; BattleManager.updateTurn = function(timeActive) { $gameParty.requestMotionRefresh(); if (this.isTpb() && timeActive) { this.updateTpb(); } if (!this._subject) { this._subject = this.getNextSubject(); } if (this._subject) { this.processTurn(); } else if (!this.isTpb()) { this.endTurn(); } }; BattleManager.updateTpb = function() { $gameParty.updateTpb(); $gameTroop.updateTpb(); this.updateAllTpbBattlers(); this.checkTpbTurnEnd(); }; BattleManager.updateAllTpbBattlers = function() { for (const battler of this.allBattleMembers()) { this.updateTpbBattler(battler); } }; BattleManager.updateTpbBattler = function(battler) { if (battler.isTpbTurnEnd()) { battler.onTurnEnd(); battler.startTpbTurn(); this.displayBattlerStatus(battler, false); } else if (battler.isTpbReady()) { battler.startTpbAction(); this._actionBattlers.push(battler); } else if (battler.isTpbTimeout()) { battler.onTpbTimeout(); this.displayBattlerStatus(battler, true); } }; BattleManager.checkTpbTurnEnd = function() { if ($gameTroop.isTpbTurnEnd()) { this.endTurn(); } }; BattleManager.processTurn = function() { const subject = this._subject; const action = subject.currentAction(); if (action) { action.prepare(); if (action.isValid()) { this.startAction(); } subject.removeCurrentAction(); } else { this.endAction(); this._subject = null; } }; BattleManager.endBattlerActions = function(battler) { battler.setActionState(this.isTpb() ? "undecided" : "done"); battler.onAllActionsEnd(); battler.clearTpbChargeTime(); this.displayBattlerStatus(battler, true); }; BattleManager.endTurn = function() { this._phase = "turnEnd"; this._preemptive = false; this._surprise = false; }; BattleManager.updateTurnEnd = function() { if (this.isTpb()) { this.startTurn(); } else { this.endAllBattlersTurn(); this._phase = "start"; } }; BattleManager.endAllBattlersTurn = function() { for (const battler of this.allBattleMembers()) { battler.onTurnEnd(); this.displayBattlerStatus(battler, false); } }; BattleManager.displayBattlerStatus = function(battler, current) { this._logWindow.displayAutoAffectedStatus(battler); if (current) { this._logWindow.displayCurrentState(battler); } this._logWindow.displayRegeneration(battler); }; BattleManager.getNextSubject = function() { for (;;) { const battler = this._actionBattlers.shift(); if (!battler) { return null; } if (battler.isBattleMember() && battler.isAlive()) { return battler; } } }; BattleManager.allBattleMembers = function() { return $gameParty.battleMembers().concat($gameTroop.members()); }; BattleManager.makeActionOrders = function() { const battlers = []; if (!this._surprise) { battlers.push(...$gameParty.battleMembers()); } if (!this._preemptive) { battlers.push(...$gameTroop.members()); } for (const battler of battlers) { battler.makeSpeed(); } battlers.sort((a, b) => b.speed() - a.speed()); this._actionBattlers = battlers; }; BattleManager.startAction = function() { const subject = this._subject; const action = subject.currentAction(); const targets = action.makeTargets(); this._phase = "action"; this._action = action; this._targets = targets; subject.cancelMotionRefresh(); subject.useItem(action.item()); this._action.applyGlobal(); this._logWindow.startAction(subject, action, targets); }; BattleManager.updateAction = function() { const target = this._targets.shift(); if (target) { this.invokeAction(this._subject, target); } else { this.endAction(); } }; BattleManager.endAction = function() { this._logWindow.endAction(this._subject); this._phase = "turn"; if (this._subject.numActions() === 0) { this.endBattlerActions(this._subject); this._subject = null; } }; BattleManager.invokeAction = function(subject, target) { this._logWindow.push("pushBaseLine"); if (Math.random() < this._action.itemCnt(target)) { this.invokeCounterAttack(subject, target); } else if (Math.random() < this._action.itemMrf(target)) { this.invokeMagicReflection(subject, target); } else { this.invokeNormalAction(subject, target); } subject.setLastTarget(target); this._logWindow.push("popBaseLine"); }; BattleManager.invokeNormalAction = function(subject, target) { const realTarget = this.applySubstitute(target); this._action.apply(realTarget); this._logWindow.displayActionResults(subject, realTarget); }; BattleManager.invokeCounterAttack = function(subject, target) { const action = new Game_Action(target); action.setAttack(); action.apply(subject); this._logWindow.displayCounter(target); this._logWindow.displayActionResults(target, subject); }; BattleManager.invokeMagicReflection = function(subject, target) { this._action._reflectionTarget = target; this._logWindow.displayReflection(target); this._action.apply(subject); this._logWindow.displayActionResults(target, subject); }; BattleManager.applySubstitute = function(target) { if (this.checkSubstitute(target)) { const substitute = target.friendsUnit().substituteBattler(); if (substitute && target !== substitute) { this._logWindow.displaySubstitute(substitute, target); return substitute; } } return target; }; BattleManager.checkSubstitute = function(target) { return target.isDying() && !this._action.isCertainHit(); }; BattleManager.isActionForced = function() { return !!this._actionForcedBattler; }; BattleManager.forceAction = function(battler) { this._actionForcedBattler = battler; this._actionBattlers.remove(battler); }; BattleManager.processForcedAction = function() { if (this._actionForcedBattler) { if (this._subject) { this.endBattlerActions(this._subject); } this._subject = this._actionForcedBattler; this._actionForcedBattler = null; this.startAction(); this._subject.removeCurrentAction(); } }; BattleManager.abort = function() { this._phase = "aborting"; }; BattleManager.checkBattleEnd = function() { if (this._phase) { if ($gameParty.isEscaped()) { this.processPartyEscape(); return true; } else if ($gameParty.isAllDead()) { this.processDefeat(); return true; } else if ($gameTroop.isAllDead()) { this.processVictory(); return true; } } return false; }; BattleManager.checkAbort = function() { if (this.isAborting()) { this.processAbort(); return true; } return false; }; BattleManager.processVictory = function() { $gameParty.removeBattleStates(); $gameParty.performVictory(); this.playVictoryMe(); this.replayBgmAndBgs(); this.makeRewards(); this.displayVictoryMessage(); this.displayRewards(); this.gainRewards(); this.endBattle(0); }; BattleManager.processEscape = function() { $gameParty.performEscape(); SoundManager.playEscape(); const success = this._preemptive || Math.random() < this._escapeRatio; if (success) { this.onEscapeSuccess(); } else { this.onEscapeFailure(); } return success; }; BattleManager.onEscapeSuccess = function() { this.displayEscapeSuccessMessage(); this._escaped = true; this.processAbort(); }; BattleManager.onEscapeFailure = function() { $gameParty.onEscapeFailure(); this.displayEscapeFailureMessage(); this._escapeRatio += 0.1; if (!this.isTpb()) { this.startTurn(); } }; BattleManager.processPartyEscape = function() { this._escaped = true; this.processAbort(); }; BattleManager.processAbort = function() { $gameParty.removeBattleStates(); this._logWindow.clear(); this.replayBgmAndBgs(); this.endBattle(1); }; BattleManager.processDefeat = function() { this.displayDefeatMessage(); this.playDefeatMe(); if (this._canLose) { this.replayBgmAndBgs(); } else { AudioManager.stopBgm(); } this.endBattle(2); }; BattleManager.endBattle = function(result) { this._phase = "battleEnd"; this.cancelActorInput(); this._inputting = false; if (this._eventCallback) { this._eventCallback(result); } if (result === 0) { $gameSystem.onBattleWin(); } else if (this._escaped) { $gameSystem.onBattleEscape(); } $gameTemp.clearCommonEventReservation(); }; BattleManager.updateBattleEnd = function() { if (this.isBattleTest()) { AudioManager.stopBgm(); SceneManager.exit(); } else if (!this._escaped && $gameParty.isAllDead()) { if (this._canLose) { $gameParty.reviveBattleMembers(); SceneManager.pop(); } else { SceneManager.goto(Scene_Gameover); } } else { SceneManager.pop(); } this._phase = ""; }; BattleManager.makeRewards = function() { this._rewards = { gold: $gameTroop.goldTotal(), exp: $gameTroop.expTotal(), items: $gameTroop.makeDropItems() }; }; BattleManager.displayVictoryMessage = function() { $gameMessage.add(TextManager.victory.format($gameParty.name())); }; BattleManager.displayDefeatMessage = function() { $gameMessage.add(TextManager.defeat.format($gameParty.name())); }; BattleManager.displayEscapeSuccessMessage = function() { $gameMessage.add(TextManager.escapeStart.format($gameParty.name())); }; BattleManager.displayEscapeFailureMessage = function() { $gameMessage.add(TextManager.escapeStart.format($gameParty.name())); $gameMessage.add("\\." + TextManager.escapeFailure); }; BattleManager.displayRewards = function() { this.displayExp(); this.displayGold(); this.displayDropItems(); }; BattleManager.displayExp = function() { const exp = this._rewards.exp; if (exp > 0) { const text = TextManager.obtainExp.format(exp, TextManager.exp); $gameMessage.add("\\." + text); } }; BattleManager.displayGold = function() { const gold = this._rewards.gold; if (gold > 0) { $gameMessage.add("\\." + TextManager.obtainGold.format(gold)); } }; BattleManager.displayDropItems = function() { const items = this._rewards.items; if (items.length > 0) { $gameMessage.newPage(); for (const item of items) { $gameMessage.add(TextManager.obtainItem.format(item.name)); } } }; BattleManager.gainRewards = function() { this.gainExp(); this.gainGold(); this.gainDropItems(); }; BattleManager.gainExp = function() { const exp = this._rewards.exp; for (const actor of $gameParty.allMembers()) { actor.gainExp(exp); } }; BattleManager.gainGold = function() { $gameParty.gainGold(this._rewards.gold); }; BattleManager.gainDropItems = function() { const items = this._rewards.items; for (const item of items) { $gameParty.gainItem(item, 1); } }; //----------------------------------------------------------------------------- // PluginManager // // The static class that manages the plugins. function PluginManager() { throw new Error("This is a static class"); } PluginManager._scripts = []; PluginManager._errorUrls = []; PluginManager._parameters = {}; PluginManager._commands = {}; PluginManager.setup = function(plugins) { for (const plugin of plugins) { const pluginName = Utils.extractFileName(plugin.name); if (plugin.status && !this._scripts.includes(pluginName)) { this.setParameters(pluginName, plugin.parameters); this.loadScript(plugin.name); this._scripts.push(pluginName); } } }; PluginManager.parameters = function(name) { return this._parameters[name.toLowerCase()] || {}; }; PluginManager.setParameters = function(name, parameters) { this._parameters[name.toLowerCase()] = parameters; }; PluginManager.loadScript = function(filename) { const url = this.makeUrl(filename); const script = document.createElement("script"); script.type = "text/javascript"; script.src = url; script.async = false; script.defer = true; script.onerror = this.onError.bind(this); script._url = url; document.body.appendChild(script); }; PluginManager.onError = function(e) { this._errorUrls.push(e.target._url); }; PluginManager.makeUrl = function(filename) { return "js/plugins/" + Utils.encodeURI(filename) + ".js"; }; PluginManager.checkErrors = function() { const url = this._errorUrls.shift(); if (url) { this.throwLoadError(url); } }; PluginManager.throwLoadError = function(url) { throw new Error("Failed to load: " + url); }; PluginManager.registerCommand = function(pluginName, commandName, func) { const key = pluginName + ":" + commandName; this._commands[key] = func; }; PluginManager.callCommand = function(self, pluginName, commandName, args) { const key = pluginName + ":" + commandName; const func = this._commands[key]; if (typeof func === "function") { func.bind(self)(args); } }; //-----------------------------------------------------------------------------