Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //=============================================================================
- // RPG Maker MZ - Map stitching (Zeriab_MapStitching.js)
- // Last Updated: 2020.XX.XX
- //=============================================================================
- // Copyright 2020 Zeriab
- //
- // This software is provided 'as-is', without any express or implied
- // warranty. In no event will the authors be held liable for any damages
- // arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it
- // freely, subject to the following restrictions:
- //
- // 1. The origin of this software must not be misrepresented; you must not
- // claim that you wrote the original software. If you use this software
- // in a product, an acknowledgement in the product documentation would be
- // appreciated but is not required.
- // 2. Altered source versions must be plainly marked as such, and must not be
- // misrepresented as being the original software.
- // 3. This notice may not be removed or altered from any source distribution.
- //=============================================================================
- /*:
- * @target MZ
- * @plugindesc Stitch maps together
- * @author Zeriab
- *
- * @help Zeriab_MapStitching.js
- *
- * Stitch maps together
- * TODO
- *
- * @param WarnOnOverlap
- * @text Give warnings when maps overlap
- * @desc Enable this function to get warnings in the console when stitching together maps results in some tiles overlapping
- * @default false
- * @type boolean
- *
- * @param MapDistanceLimit
- * @text Determines how far away a mapsegment from the current map to load
- * @type number
- * @min 1
- * @default 1
- *
- *
- * @command Setup Border Anchor
- * @text Anchor this event
- * @desc TODO
- *
- * @arg mapId
- * @text Map ID
- * @type number
- * @min 1
- * @max 2000
- * @default 1
- *
- * @arg eventId
- * @text Event ID
- * @type number
- * @min 1
- * @max 999
- * @default 0
- *
- * @arg direction
- * @text Direction
- * @type select
- * @default 2
- * @option Down
- * @value 2
- * @option Left
- * @value 4
- * @option Right
- * @value 6
- * @option Up
- * @value 8
- * @option Center
- * @value 5
- */
- (() => {
- 'use strict';
- const pluginName = "Zeriab_MapStitching";
- const parameters = PluginManager.parameters(pluginName);
- const warnOnOverlap = eval(parameters.WarnOnOverlap || 'false');
- const mapDistanceLimit = eval(parameters.MapDistanceLimit || 'false');
- /*
- * Plug in command
- */
- PluginManager.registerCommand(pluginName, "Setup Border Anchor", SetupBorderAnchor);
- function SetupBorderAnchor(args) {
- const fromMapId = this._mapId;
- const fromEventId = this._eventId;
- const toMapId = Number(args.mapId);
- const toEventId = Number(args.eventId);
- const direction = Number(args.direction);
- // TODO Assert direction?
- console.log("Command: Setup border anchor for [%i:%i] %i to [%i, %i]", fromMapId, fromEventId, direction, toMapId, toEventId);
- $gameMap.setupBorderAnchor(fromMapId, fromEventId, toMapId, toEventId, direction);
- $gameMap.refreshStitches();
- }
- Game_Map.prototype.setupBorderAnchor = function(fromMapId, fromEventId, toMapId, toEventId, direction) {
- console.log("Setting up border anchor for [%i:%i] %s to [%i, %i]", fromMapId, fromEventId, direction, toMapId, toEventId);
- $gameSystem.mapStitches().addEventAnchor(fromMapId, fromEventId, toMapId, toEventId, direction);
- }
- /*
- * Lazy initialization
- * Should provide compatibility to old saves
- */
- Game_System.prototype.mapStitches = function() {
- if (!this._mapStitching) {
- this._mapStitching = new MapStitches();
- }
- return this._mapStitching;
- }
- /*
- * MapManager is used as a container for any data that should not be included in the save files
- */
- function MapManager() {
- throw new Error("This is a static class");
- }
- MapManager._preloads = [];
- MapManager._preloadCount = 0;
- MapManager._preloadGoal = 0;
- MapManager.loadMap = function(id, data) {
- this._preloads[id] = data;
- this._preloadCount += 1;
- };
- MapManager.setMapCount = function(count) {
- this._preloadGoal = count;
- }
- MapManager.preloadFinished = function() {
- return this._preloadGoal > 0 && this._preloadCount === this._preloadGoal;
- }
- /**
- * Main 'class' for managing the map stitches
- * Any data belonging to this class will be included in save files
- */
- function MapStitches() {
- this.initialize(...arguments);
- }
- MapStitches.prototype.initialize = function() {
- this._anchors = {};
- this._preloads = {};
- this._segments = {};
- this.preloadMaps();
- };
- MapStitches.prototype.addEventAnchor = function(fromMapId, fromEventId, toMapId, toEventId, direction) {
- const fromSegment = this.fetchSegment(fromMapId);
- const toSegment = this.fetchSegment(toMapId);
- // TODO Use direction for anything?
- fromSegment.setupAnchor(fromEventId, toSegment, toEventId, direction);
- }
- MapStitches.prototype.preloadMaps = function() {
- var mapCount = 0;
- for (var mapInfo of $dataMapInfos) {
- if (mapInfo) {
- mapCount++;
- this.loadMapData(mapInfo.id);
- }
- }
- MapManager.setMapCount(mapCount);
- }
- MapStitches.prototype.mapLoaded = function(mapId, mapData) {
- console.log("Finished reading map " + mapId);
- MapManager.loadMap(mapId, mapData);
- this._preloads[mapId] = true;
- if (MapManager.preloadFinished()) {
- console.log("Preloading complete");
- this.postProcess();
- }
- }
- MapStitches.prototype.loadMapData = function(mapId) {
- const fileName = DataManager.makeMapName(mapId);
- //const fileName = "fh/" + DataManager.makeMapName(mapId);
- const objectName = "$tempMap%1".format(mapId.padZero(3));
- console.log("Loading " + fileName + " into " + objectName);
- DataManager.loadDataFileExt(objectName, fileName, mapData => {
- $gameSystem.mapStitches().mapLoaded(mapId, mapData);
- window[objectName] = null;
- });
- }
- MapStitches.prototype.hasSegment = function(mapId) {
- return !!this._segments[mapId];
- }
- MapStitches.prototype.fetchSegment = function(mapId) {
- if (!this.hasSegment(mapId)) {
- this._segments[mapId] = new MapSegment(mapId);
- }
- return this._segments[mapId];
- }
- MapStitches.prototype.postProcess = function() {
- for (const key in this._segments) {
- const segment = this._segments[key];
- segment.processAnchors();
- }
- $gameMap.refreshStitches();
- }
- /**
- * Encapsulates information regarding a map segments and its neighbors
- */
- class MapSegment {
- constructor(mapId) {
- this._mapId = mapId;
- this._anchors = {};
- }
- setupAnchor(fromEventId, toSegment, toEventId, direction) {
- if (direction === 0) {
- direction = 5;
- }
- this._anchors[toSegment._mapId] = {type: "event", from: fromEventId, to: toEventId, segment: toSegment, direction: direction};
- }
- processAnchors() {
- // Process event anchors
- for (const key in this._anchors) {
- // Relevant anchor information
- const anchor = this._anchors[key];
- const toSegment = anchor.segment;
- const toSegmentData = toSegment.mapData();
- const direction = anchor.direction;
- // Find coordinates
- const from = this.event(anchor.from);
- const to = toSegment.event(anchor.to);
- const offset = this.offset(direction);
- // Calculate segment starting location
- anchor.minX = from.x + offset.x - to.x;
- anchor.minY = from.y + offset.y - to.y;
- anchor.maxX = anchor.minX + toSegmentData.width;
- anchor.maxY = anchor.minY + toSegmentData.height;
- console.log("Anchored map " + key + " has top-left coordinate (" + anchor.minX + ", " + anchor.minY +")");
- }
- }
- offset(direction) {
- // 678
- // 345
- // 012
- const value = direction - 1;
- // 012
- // 012
- // 012
- const x = value % 3;
- // 222
- // 111
- // 000
- const y = 2 - Math.floor(value / 3);
- return {x: x - 1, y: y - 1};
- }
- event(eventId) {
- const data = this.mapData();
- return data.events[eventId];;
- }
- mapData() {
- return MapManager._preloads[this._mapId];
- }
- }
- /*
- * Core Game_Map integration
- */
- const _Game_Map_setup = Game_Map.prototype.setup;
- Game_Map.prototype.setup = function(mapId) {
- _Game_Map_setup.apply(this, arguments);
- this.setupStitches();
- }
- Game_Map.prototype.setupStitches = function() {
- this._segmentReady = false;
- this.minX = null;
- this.maxX = null;
- this.minY = null;
- this.maxY = null;
- // TODO
- }
- Game_Map.prototype.refreshStitches = function() {
- this.minX = 0;
- this.maxX = this.width();
- this.minY = 0;
- this.maxY = this.height();
- console.log("Starting with map span (" + this.minX + ", " + this.minY + ") <=> (" + this.maxX + ", " + this.maxY + ")");
- this.segment = $gameMap.currentStitch();
- // Process event anchors
- for (const key in this.segment._anchors) {
- // Relevant anchor information
- const anchor = this.segment._anchors[key];
- if (anchor.minX < this.minX) {
- this.minX = anchor.minX;
- }
- if (anchor.minY < this.minY) {
- this.minY = anchor.minY;
- }
- if (anchor.maxX > this.maxX) {
- this.maxX = anchor.maxX;
- }
- if (anchor.maxY > this.maxY) {
- this.maxY = anchor.maxY;
- }
- }
- this._segmentReady = true;
- console.log("Ending with map span (" + this.minX + ", " + this.minY + ") <=> (" + this.maxX + ", " + this.maxY + ")");
- }
- Game_Map.prototype.currentStitch = function() {
- return $gameSystem.mapStitches().fetchSegment(this._mapId);
- }
- // Replace
- const _Game_Map_setDisplayPos = Game_Map.prototype.setDisplayPos;
- Game_Map.prototype.setDisplayPos = function(x, y) {
- if (!this._segmentReady) {
- _Game_Map_setDisplayPos.apply(this, arguments);
- } else {
- setDisplayPosX(x);
- setDisplayPosY(y);
- }
- };
- Game_Map.prototype.setDisplayPosX = function(x) {
- if (this.isLoopHorizontal()) {
- // TODO How would looping work?
- this._displayX = x.mod(this.width());
- this._parallaxX = x;
- } else {
- this._displayX = x.clamp(this.minX, this.maxX);
- this._parallaxX = this._displayX;
- }
- }
- Game_Map.prototype.setDisplayPosY = function(y) {
- if (this.isLoopVertical()) {
- // TODO How would looping work?
- this._displayY = y.mod(this.height());
- this._parallaxY = y;
- } else {
- this._displayY = y.clamp(this.minY, this.maxY);
- this._parallaxY = this._displayY;
- }
- }
- //#region Scroll
- const _Game_Map_scrollDown = Game_Map.prototype.scrollDown;
- Game_Map.prototype.scrollDown = function(distance) {
- if (!this._segmentReady) {
- _Game_Map_scrollDown.apply(this, arguments);
- } else {
- if (this.isLoopVertical()) {
- // TODO Handle loops
- this._displayY += distance;
- this._displayY %= $dataMap.height;
- if (this._parallaxLoopY) {
- this._parallaxY += distance;
- }
- } else if (this.maxY >= this.screenTileY()) {
- const lastY = this._displayY;
- this._displayY = Math.min(
- this._displayY + distance,
- this.maxY - this.screenTileY()
- );
- this._parallaxY += this._displayY - lastY;
- }
- }
- };
- const _Game_Map_scrollLeft = Game_Map.prototype.scrollLeft;
- Game_Map.prototype.scrollLeft = function(distance) {
- if (!this._segmentReady) {
- _Game_Map_scrollLeft.apply(this, arguments);
- } else {
- if (this.isLoopHorizontal()) {
- // TODO Handle loops
- this._displayX += $dataMap.width - distance;
- this._displayX %= $dataMap.width;
- if (this._parallaxLoopX) {
- this._parallaxX -= distance;
- }
- } else if (this.maxX >= this.screenTileX()) {
- const lastX = this._displayX;
- this._displayX = Math.max(this._displayX - distance, this.minX);
- this._parallaxX += this._displayX - lastX;
- }
- }
- };
- const _Game_Map_scrollRight = Game_Map.prototype.scrollRight;
- Game_Map.prototype.scrollRight = function(distance) {
- if (!this._segmentReady) {
- _Game_Map_scrollRight.apply(this, arguments);
- } else {
- if (this.isLoopHorizontal()) {
- // TODO Handle loops
- this._displayX += distance;
- this._displayX %= $dataMap.width;
- if (this._parallaxLoopX) {
- this._parallaxX += distance;
- }
- } else if (this.maxX >= this.screenTileX()) {
- const lastX = this._displayX;
- this._displayX = Math.min(
- this._displayX + distance,
- this.maxX - this.screenTileX()
- );
- this._parallaxX += this._displayX - lastX;
- }
- }
- };
- const _Game_Map_scrollUp = Game_Map.prototype.scrollUp;
- Game_Map.prototype.scrollUp = function(distance) {
- if (!this._segmentReady) {
- _Game_Map_scrollUp.apply(this, arguments);
- } else {
- if (this.isLoopVertical()) {
- // TODO Handle loops
- this._displayY += $dataMap.height - distance;
- this._displayY %= $dataMap.height;
- if (this._parallaxLoopY) {
- this._parallaxY -= distance;
- }
- } else if (this.maxY >= this.screenTileY()) {
- const lastY = this._displayY;
- this._displayY = Math.max(this._displayY - distance, this.minY);
- this._parallaxY += this._displayY - lastY;
- }
- }
- };
- //#endregion
- const _Game_Map_isValid = Game_Map.prototype.isValid;
- Game_Map.prototype.isValid = function(x, y) {
- if (!this._segmentReady) {
- return _Game_Map_isValid.apply(this, arguments);
- } else {
- return x >= this.minX && x < this.maxX && y >= this.minY && y < this.maxY;
- }
- };
- /*
- * Sprites
- */
- Spriteset_Map.prototype.createSegmentTilemap = function(anchor, segment) {
- const tilemap = new Tilemap();
- tilemap.tileWidth = $gameMap.tileWidth();
- tilemap.tileHeight = $gameMap.tileHeight();
- const mapData = segment.mapData();
- tilemap.setData(mapData.width, mapData.height, mapData.data);
- tilemap.horizontalWrap = $gameMap.isLoopHorizontal();
- tilemap.verticalWrap = $gameMap.isLoopVertical();
- this._baseSprite.addChild(tilemap);
- this._segmentTilemap = tilemap;
- this._segment = segment;
- this._segmentAnchor = anchor;
- this.loadSegmentTileset(segment._mapId, mapData);
- };
- Spriteset_Map.prototype.loadSegmentTileset = function(mapId, mapData) {
- this._segmentTileset = $dataTilesets[mapData.tilesetId];
- if (this._segmentTileset) {
- const bitmaps = [];
- const tilesetNames = this._segmentTileset.tilesetNames;
- for (const name of tilesetNames) {
- bitmaps.push(ImageManager.loadTileset(name));
- }
- this._segmentTilemap.setBitmaps(bitmaps);
- this._segmentTilemap.flags = this._segmentTileset.flags;
- }
- };
- const _Spriteset_Map_updateTilemap = Spriteset_Map.prototype.updateTilemap;
- Spriteset_Map.prototype.updateTilemap = function() {
- _Spriteset_Map_updateTilemap.apply(this, arguments);
- if (this._segmentTilemap) {
- this._segmentTilemap.origin.x = ($gameMap.displayX() - this._segmentAnchor.minX) * $gameMap.tileWidth();
- this._segmentTilemap.origin.y = ($gameMap.displayY() - this._segmentAnchor.minY) * $gameMap.tileHeight();
- } else if ($gameMap._segmentReady) {
- console.log("TODO Setup tileset");
- this.segment = $gameMap.currentStitch();
- // Process event anchors
- for (const key in this.segment._anchors) {
- // Relevant anchor information
- const anchor = this.segment._anchors[key];
- this.createSegmentTilemap(anchor, anchor.segment);
- break;
- }
- }
- };
- /*
- * Map preload functions
- */
- DataManager.loadDataFileExt = function(name, src, func) {
- const xhr = new XMLHttpRequest();
- const url = "data/" + src;
- window[name] = null;
- xhr.open("GET", url);
- xhr.overrideMimeType("application/json");
- xhr.onload = () => this.onXhrLoadExt(xhr, name, src, url, func);
- xhr.onerror = () => this.onXhrError(name, src, url);
- xhr.send();
- };
- DataManager.onXhrLoadExt = function(xhr, name, src, url, func) {
- if (xhr.status < 400) {
- window[name] = JSON.parse(xhr.responseText);
- this.onLoadExt(window[name], func);
- } else {
- this.onXhrError(name, src, url);
- }
- };
- DataManager.onLoadExt = function(object, func) {
- DataManager.onLoad(object);
- func(object);
- };
- DataManager.makeMapName = function(mapId) {
- // Old saves without any subfolder information is considered to use the default folder
- return 'Map%1.json'.format(mapId.padZero(3));
- };
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement