//-----------------------------------------------------------------------------
// DataManager
//
// The static class that manages the database and game objects.
/**
* The static class that manages the database and game objects.
*
* @namespace
*/
function DataManager() {
throw new Error("This is a static class");
}
/**
* Array used to store the database version of the actors
*
* @global
*/
$dataActors = null;
/**
* Array used to store the database version of the classes
*
* @global
*/
$dataClasses = null;
/**
* Array used to store the database version of the skills
*
* @global
*/
$dataSkills = null;
/**
* Array used to store the database version of the items
*
* @global
*/
$dataItems = null;
/**
* Array used to store the database version of the weapons
*
* @global
*/
$dataWeapons = null;
/**
* Array used to store the database version of the armors
*
* @global
*/
$dataArmors = null;
/**
* Array used to store the database version of the enemies
*
* @global
*/
$dataEnemies = null;
/**
* Array used to store the database version of the troops
*
* @global
*/
$dataTroops = null;
/**
* Array used to store the database version of the states
*
* @global
*/
$dataStates = null;
/**
* Array used to store the database version of the animations
*
* @global
*/
$dataAnimations = null;
/**
* Array used to store the database version of the tilesets
*
* @global
*/
$dataTilesets = null;
/**
* Array used to store the database version of the common events
*
* @global
*/
$dataCommonEvents = null;
/**
* Array used to store the database version of the system tabs
*
* @global
*/
$dataSystem = null;
/**
* Stores the map infos
*
* @global
*/
$dataMapInfos = null;
/**
* Stores data about a map
*
* @global
*/
$dataMap = null;
/**
* Global reference to Game_Temp
*
* @global
*/
$gameTemp = null;
/**
* Global reference to Game_System
*
* @global
*/
$gameSystem = null;
/**
* Global reference to Game_Screen
*
* @global
*/
$gameScreen = null;
/**
* Global reference to Game_Timer
*
* @global
*/
$gameTimer = null;
/**
* Global reference to Game_Message
*
* @global
*/
$gameMessage = null;
/**
* Global reference to Game_Switches
*
* @global
*/
$gameSwitches = null;
/**
* Global reference to Game_Variables
*
* @global
*/
$gameVariables = null;
/**
* Global reference to Game_SelfSwitches
*
* @global
*/
$gameSelfSwitches = null;
/**
* Global reference to Game_Actors
*
* @global
*/
$gameActors = null;
/**
* Global reference to Game_Party
*
* @global
*/
$gameParty = null;
/**
* Global reference to Game_Troop
*
* @global
*/
$gameTroop = null;
/**
* Global reference to Game_Map
*
* @global
*/
$gameMap = null;
/**
* Global reference to Game_Player
*
* @global
*/
$gamePlayer = null;
/**
* Global reference set when testing an event
*
* @global
*/
$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" }
];
/**
* Loads the "global" object
*
* @static
*/
DataManager.loadGlobalInfo = function() {
StorageManager.loadObject("global")
.then(globalInfo => {
this._globalInfo = globalInfo;
this.removeInvalidGlobalInfo();
return 0;
})
.catch(() => {
this._globalInfo = [];
});
};
/**
* Check for and remove invalid global info if any exists
*
* @static
*/
DataManager.removeInvalidGlobalInfo = function() {
const globalInfo = this._globalInfo;
for (const info of globalInfo) {
const savefileId = globalInfo.indexOf(info);
if (!this.savefileExists(savefileId)) {
delete globalInfo[savefileId];
}
}
};
/**
* Saves the "global" object
*
* @static
*/
DataManager.saveGlobalInfo = function() {
StorageManager.saveObject("global", this._globalInfo);
};
/**
* Check if global info is loaded
*
* @static
* @return {boolean} True if global info is loaded.
*/
DataManager.isGlobalInfoLoaded = function() {
return !!this._globalInfo;
};
/**
* Loads each of the database files
*
* @static
*/
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");
}
};
/**
* Loads the database file with the given name and src
*
* @static
* @param {string} name - The name of the data object to store loaded data in
* @param {string} src - The path to the data file to load
*/
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();
};
/**
* Handling for when the xhr object is loaded
*
* @static
* @param {XMLHttpRequest} xhr - The XMLHttpRequest object
* @param {string} name - The name of the data object to store loaded data in
* @param {string} src - The path to the data file to load
* @param {string} url - The full path to the data file to load
*/
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);
}
};
/**
* Handling for when the xhr object encounters an error
*
* @static
* @param {string} name - The name of the data object to store loaded data in
* @param {string} src - The path to the data file to load
* @param {string} url - The full path to the data file to load
*/
DataManager.onXhrError = function(name, src, url) {
const error = { name: name, src: src, url: url };
this._errors.push(error);
};
/**
* Check if all of the database files are loaded
*
* @static
* @return {boolean} True if all database files are loaded
*/
DataManager.isDatabaseLoaded = function() {
this.checkError();
for (const databaseFile of this._databaseFiles) {
if (!window[databaseFile.name]) {
return false;
}
}
return true;
};
/**
* Loads a map data file by the map's id
*
* @static
* @param {number} mapId - The ID of the map to load
*/
DataManager.loadMapData = function(mapId) {
if (mapId > 0) {
const filename = "Map%1.json".format(mapId.padZero(3));
this.loadDataFile("$dataMap", filename);
} else {
this.makeEmptyMap();
}
};
/**
* Makes an empty map with no data or events, stored in $dataMap
*
* @static
*/
DataManager.makeEmptyMap = function() {
$dataMap = {};
$dataMap.data = [];
$dataMap.events = [];
$dataMap.width = 100;
$dataMap.height = 100;
$dataMap.scrollType = 3;
};
/**
* Check if the map is loaded
*
* @static
* @return {boolean} True if map data is loaded
*/
DataManager.isMapLoaded = function() {
this.checkError();
return !!$dataMap;
};
/**
* Handling for when a data object is loaded
*
* @static
* @param {*} object - The object that was loaded
*/
DataManager.onLoad = function(object) {
if (this.isMapObject(object)) {
this.extractMetadata(object);
this.extractArrayMetadata(object.events);
} else {
this.extractArrayMetadata(object);
}
};
/**
* Check if an object represents map data
*
* @static
* @param {*} object - The object to check for map info
* @return {boolean} True if the object represents a map
*/
DataManager.isMapObject = function(object) {
return !!(object.data && object.events);
};
/**
* Extract metadata from an array object
*
* @static
* @param {Array} array - The array to extract metadata from
*/
DataManager.extractArrayMetadata = function(array) {
if (Array.isArray(array)) {
for (const data of array) {
if (data && "note" in data) {
this.extractMetadata(data);
}
}
}
};
/**
* Extract metadata from an individual object
*
* @static
* @param {*} data - The data that might have a meta property in its note
*/
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;
}
}
};
/**
* Check if there are any errors, throw a retry screen error if any exist
*
* @static
* @throws Retry screen error
*/
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];
}
};
/**
* Check if the game is in battle test mode
*
* @static
* @return {boolean} True if the game is in battle test mode
*/
DataManager.isBattleTest = function() {
return Utils.isOptionValid("btest");
};
/**
* Check if the game is in event test mode
*
* @static
* @return {boolean} True if the game is in event test mode
*/
DataManager.isEventTest = function() {
return Utils.isOptionValid("etest");
};
/**
* Check if title skip option is enabled
*
* @static
* @since Version 1.7.0
* @return {boolean} True if title skip is on
*/
DataManager.isTitleSkip = function() {
return Utils.isOptionValid("tskip");
};
/**
* Check if the given object is a skill from the database
*
* @static
* @param {*} item - Item to check for inclusion in $dataSkills
* @return {boolean} True if the object is a skill
*/
DataManager.isSkill = function(item) {
return item && $dataSkills.includes(item);
};
/**
* Check if the given object is an item from the database
*
* @static
* @param {*} item - Item to check for inclusion in $dataItems
* @return {boolean} True if the object is an item
*/
DataManager.isItem = function(item) {
return item && $dataItems.includes(item);
};
/**
* Check if the given object is a weapon from the database
*
* @static
* @param {*} item - Item to check for inclusion in $dataWeapons
* @return {boolean} True if the object is a weapon
*/
DataManager.isWeapon = function(item) {
return item && $dataWeapons.includes(item);
};
/**
* Check if the given object is an armor from the database
*
* @static
* @param {*} item - Item to check for inclusion in $dataArmors
* @return {boolean} True if the object is an armor
*/
DataManager.isArmor = function(item) {
return item && $dataArmors.includes(item);
};
/**
* Creates $gameTemp and the other game objects
*
* @static
*/
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();
};
/**
* Handles setting up a new game
*
* @static
*/
DataManager.setupNewGame = function() {
this.createGameObjects();
this.selectSavefileForNewGame();
$gameParty.setupStartingMembers();
$gamePlayer.setupForNewGame();
Graphics.frameCount = 0;
};
/**
* Handles setting up a battle test
*
* @static
*/
DataManager.setupBattleTest = function() {
this.createGameObjects();
$gameParty.setupBattleTest();
BattleManager.setup($dataSystem.testTroopId, true, false);
BattleManager.setBattleTest(true);
BattleManager.playBattleBgm();
};
/**
* Handles setting up an event test
*
* @static
*/
DataManager.setupEventTest = function() {
this.createGameObjects();
this.selectSavefileForNewGame();
$gameParty.setupStartingMembers();
$gamePlayer.reserveTransfer(-1, 8, 6);
$gamePlayer.setTransparent(false);
};
/**
* Check if there are any save files
*
* @static
* @return {boolean} True if any save files exist
*/
DataManager.isAnySavefileExists = function() {
return this._globalInfo.some(x => x);
};
/**
* Gets the last used save file
*
* @static
* @return {number} The index of the last save file
*/
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;
};
/**
* Gets the earliest save file
*
* @static
* @return {number} The index of the earliest save file
*/
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;
};
/**
* Gets the index of an empty save file
*
* @static
* @return {number} The index of the empty save file
*/
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;
}
};
/**
* Loads the images needed for display in the file select screen
*
* @static
*/
DataManager.loadAllSavefileImages = function() {
for (const info of this._globalInfo.filter(x => x)) {
this.loadSavefileImages(info);
}
};
/**
* Loads the images needed for display in the file select screen from a specific save file
*
* @static
* @param {*} info - The save file info with image data to load
*/
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]);
}
}
};
/**
* Determines the maximum number of save files allowed
*
* @static
* @return {number} The maximum number of save files allowed
*/
DataManager.maxSavefiles = function() {
return 20;
};
/**
* Gets the save file info for a specific save file id
*
* @static
* @param {number} savefileId - The id of the save file to load
* @return {Object|null} Either the save file info if exists, or null
*/
DataManager.savefileInfo = function(savefileId) {
const globalInfo = this._globalInfo;
return globalInfo[savefileId] ? globalInfo[savefileId] : null;
};
/**
* Checks if a given save file exists by save file id
*
* @static
* @param {number} savefileId - The id of the save file to check
* @return {boolean} True if save data exists for that file id
*/
DataManager.savefileExists = function(savefileId) {
const saveName = this.makeSavename(savefileId);
return StorageManager.exists(saveName);
};
/**
* Tries to save the game in the given save file id slot
*
* @static
* @param {number} savefileId - The id of the save file slot to save
*/
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;
});
};
/**
* Tries to load game info from the given save file id slot
*
* @static
* @param {number} savefileId - The id of the save file slot to load
*/
DataManager.loadGame = function(savefileId) {
const saveName = this.makeSavename(savefileId);
return StorageManager.loadObject(saveName).then(contents => {
this.createGameObjects();
this.extractSaveContents(contents);
this.correctDataErrors();
return 0;
});
};
/**
* Creates the file name of the save file from the save file id slot
*
* @static
* @param {number} savefileId - The id of the save file slot
* @return {string} The save file name
*/
DataManager.makeSavename = function(savefileId) {
return "file%1".format(savefileId);
};
/**
* Selects the initial save file slot for a new game
*
* @static
*/
DataManager.selectSavefileForNewGame = function() {
const emptySavefileId = this.emptySavefileId();
const earliestSavefileId = this.earliestSavefileId();
if (emptySavefileId > 0) {
$gameSystem.setSavefileId(emptySavefileId);
} else {
$gameSystem.setSavefileId(earliestSavefileId);
}
};
/**
* Creates save file info for the file select screen
*
* @static
* @return {Object} The save file info contents
*/
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;
};
/**
* Creates save file contents
*
* @static
* @return {Object} The save file contents
*/
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;
};
/**
* Extracts the content from a save file to the various game objects
*
* @static
* @param {Object} contents - The save file 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;
};
/**
* Tries to correct any bad data
*
* @static
*/
DataManager.correctDataErrors = function() {
$gameParty.removeInvalidMembers();
};