Iavra

Iavra Minimap - Core

Aug 14th, 2016 (edited)
2,014
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*:
  2.  * @plugindesc v1.04 Creates a minimap based on either supplied pictures or generated from terrain tags.
  3.  * <Iavra Minimap Core>
  4.  * @author Iavra
  5.  *
  6.  * @param Switch
  7.  * @desc Optional switch, that needs to be set to ON for the map to be active.
  8.  * @default
  9.  *
  10.  * @param Notetag
  11.  * @desc Notetag used to mark maps, events and actors that should show up on the minimap.
  12.  * @default minimap
  13.  *
  14.  * @param Frame
  15.  * @desc X, Y, width and height of the minimap. Negative coordinates start at the right/bottom of the screen.
  16.  * @default 10, 10, 200, 200
  17.  *
  18.  * @param Tile Size
  19.  * @desc Size of a single tile on generated maps. Odd numbers might lead to graphical glitches. Minimum: 2
  20.  * @default 10
  21.  *
  22.  * @param Terrain Colors
  23.  * @desc Comma-separated list of <terrainTag>:<color> pairs. Colors are specified in hex format.
  24.  * @default 0:#FFF
  25.  *
  26.  * @param Background Color
  27.  * @desc Color to be used for the minimap background, in hex format.
  28.  * @default #FFF
  29.  *
  30.  * @param Background Opacity
  31.  * @desc Opacity to be used for the minimap background. 0 is fully transparent, 1 is solid.
  32.  * @default 0.3
  33.  *
  34.  * @help
  35.  * To enable the minimap for a specific map, put this tag inside the map's notebox (configurable):
  36.  *
  37.  * <minimap>
  38.  *
  39.  * The plugin will then automatically create a minimap from terrain tags, using the colors provided via the plugin
  40.  * parameter "Terrain Colors". If you want to use a custom map, instead, modify the tag like this:
  41.  *
  42.  * <minimap img:path/to/my/Image.png>
  43.  *
  44.  * The given image will be loaded and automatically scaled to fit the tile size specified in "Tile Size", so please
  45.  * make sure it has the right dimensions or you might experience graphical glitches.
  46.  *
  47.  * To display the player icon on the map, put the following tag inside the notebox of an actor:
  48.  *
  49.  * <minimap 1>
  50.  *
  51.  * This will cause the icon #1 to be displayed on the minimap, as long as that actor is the current leading player.
  52.  * Different icons can be specified for each actor, so the minimap always shows the correct one.
  53.  *
  54.  * To display an event on the map, put the following tag inside a comment:
  55.  *
  56.  * <minimap 2>
  57.  *
  58.  * As long as that page is active, the icon #2 will be shown at that event's position. This can be used to create
  59.  * marker events displaying PoIs or the current quest target.
  60.  *
  61.  * The following script calls can be used to modify the map. Please note, that parameter changes are all temporary,
  62.  * unless another plugin stores them in a persistent manner:
  63.  *
  64.  * IAVRA.MINIMAP.refresh();         Refreshes the map image loaded or created for the current map.
  65.  * IAVRA.MINIMAP.move(x, y);        Repositions the map. Negative values are counted from the right/bottom edge.
  66.  * IAVRA.MINIMAP.resize(w, h);      Resizes the map. If needed, it's repositioned to fit against the screen edge.
  67.  * IAVRA.MINIMAP.x = value;         Repositions the map. Negative values are counted from the right edge.
  68.  * IAVRA.MINIMAP.y = value;         Repositions the map. Negative values are counted from the bottom edge.
  69.  * IAVRA.MINIMAP.width = value;     Resizes the map, updating its position if needed.
  70.  * IAVRA.MINIMAP.height = value;    Resized the map, updating its position if needed.
  71.  * IAVRA.MINIMAP.center = value;    Treates the given character as the new center of the minimap.
  72.  * IAVRA.MINIMAP.zoom = value;      Changes the zoom level (doesn't effect icons, only the map itself).
  73.  * IAVRA.MINIMAP.opacity = value;   Changes the overall opacity of the map. A value of 0 or lower will disable it.
  74.  */
  75.  
  76. (function($, undefined) {
  77.     "use strict";
  78.  
  79.     /**
  80.      * Basic helper function to extend objects. Mainly used for inheritance and other prototype-related operations.
  81.      */
  82.     $._extend || ($._extend = function(b, e) { for(var k in e) { b[k] = e[k]; } return b; });
  83.  
  84.     /**
  85.      * Reading plugin parameters.
  86.      */
  87.     var _params = $plugins.filter(function(p) { return p.description.contains('<Iavra Minimap Core>'); })[0].parameters;
  88.     var _param_switch = _params['Switch']|0;
  89.     var _param_notetag = _params['Notetag'];
  90.     var _param_frame = (_params['Frame'] + ',,,').split(/\s*,\s*/).map(function(n) { return parseInt(n) || 0; });
  91.     var _param_tileSize = Math.max(_params['Tile Size']|0, 2);
  92.     var _param_bgColor = (/(#(?:[A-F0-9]{6}|[A-F0-9]{3}))/i.exec(_params['Background Color']) || [])[1];
  93.     var _param_bgOpacity = (parseFloat(_params['Background Opacity']) || 0).clamp(0, 1);
  94.     var _param_colors = _params['Terrain Colors'].split(/\s*,\s*/).reduce(function(m, $) {
  95.         if(/^(\d+)\s*:\s*(#(?:[A-F0-9]{6}|[A-F0-9]{3}))$/i.exec($)) { m[RegExp.$1|0] = RegExp.$2 } return m;
  96.     }, {});
  97.  
  98.     /**
  99.      * Regexes used to parse notetags.
  100.      */
  101.     var _regex_map = new RegExp('<' + _param_notetag + '(?:[ ]+img:[ ]*(.+?))?>');
  102.     var _regex_char = new RegExp('<' + _param_notetag + '[ ]+(\\d+)>');
  103.  
  104.     /**
  105.      * Frame used to contain the minimap, consisting of x and y coordinate, width and height.
  106.      */
  107.     var _frame = {x: 0, y: 0, w: 0, h: 0};
  108.  
  109.     /**
  110.      * Offset used to center the map. Gets updated during each update cycle.
  111.      */
  112.     var _offset = {x: 0, y: 0};
  113.  
  114.     /**
  115.      * Setting this to true will cause the minimap to reload all data.
  116.      */
  117.     var _refresh = false;
  118.  
  119.     /**
  120.      * Caches map images, so they don't have to be reloaded or recreated all the time.
  121.      */
  122.     var _mapCache = [];
  123.  
  124.     /**
  125.      * Caches the icon ids used by the map to visualize the player and events.
  126.      */
  127.     var _iconCache = [];
  128.  
  129.     /**
  130.      * The character used to center the map on, usually $gamePlayer.
  131.      */
  132.     var _center;
  133.  
  134.     /**
  135.      * Zoom used for the map. Might cause graphical glitches with picture maps.
  136.      */
  137.     var _zoom = 1.0;
  138.  
  139.     /**
  140.      * Opacity of the minimap as a whole. Setting this to 0 will effectively disable the plugin.
  141.      */
  142.     var _opacity = 1.0;
  143.  
  144.     /**
  145.      * Recalculates the boundaries of the frame by treating negative x/y coordinates as counting from the right/bottom.
  146.      */
  147.     var calculateFrame = function(x, y, w, h) {
  148.         _frame.w = w; _frame.h = h;
  149.         _frame.x = x < 0 ? SceneManager._boxWidth - w + x : x;
  150.         _frame.y = y < 0 ? SceneManager._boxHeight - h + y : y;
  151.         _refresh = true;
  152.     };
  153.     calculateFrame(_param_frame[0], _param_frame[1], _param_frame[2], _param_frame[3]);
  154.  
  155.     /**
  156.      * Sets up the map image used by the given map id. Depending on the notetag present (if any), this might either be
  157.      * a loaded image or a generated map based on the terrain tags.
  158.      */
  159.     var setupMap = function(mapId) {
  160.         if(!_regex_map.exec($dataMap.note)) { _mapCache[mapId] = null; return; }
  161.         _mapCache[mapId] = RegExp.$1 ? createMapFromImage(RegExp.$1) : createMapFromTiles();
  162.         _refresh = true;
  163.     };
  164.  
  165.     /**
  166.      * Loads a map image and scales it to fit the minimap.
  167.      */
  168.     var createMapFromImage = function(img) {
  169.         var s = _param_tileSize, w = $gameMap.width() * s, h = $gameMap.height() * s, map = new Bitmap(w, h);
  170.         var bmp = Bitmap.load(img);
  171.         bmp.addLoadListener(function() { map.blt(bmp, 0, 0, bmp.width, bmp.height, 0, 0, w, h); });
  172.         return map;
  173.     };
  174.  
  175.     /**
  176.      * Creates a map image based on the terrain tags present.
  177.      */
  178.     var createMapFromTiles = function() {
  179.         var c, s = _param_tileSize, w = $gameMap.width(), h = $gameMap.height(), map = new Bitmap(w * s, h * s);
  180.         for(var x = 0; x < w; ++x) { for(var y = 0; y < h; ++y) {
  181.             if(c = _param_colors[$gameMap.terrainTag(x, y)]) { map.fillRect(x * s, y * s, s, s, c); }
  182.         }}
  183.         return map;
  184.     };
  185.  
  186.     /**
  187.      * Parses the comments on an event's active page or the notebox of the leading actor and stores the contained icon
  188.      * index in the iconcache, so it can be grabbed by the minimap.
  189.      */
  190.     var setupCharacter = function(char) {
  191.         var id = char._eventId|0, oldIcon = _iconCache[id], icon;
  192.         if(id) {
  193.             if(!char.page()) { icon = null; } else {
  194.                 for(var i = 0, l = char.list(), note = '', cmd, max = l.length; i < max; ++i) {
  195.                     if((cmd = l[i]) && (cmd.code === 108 || cmd.code === 408)) { note += cmd.parameters[0]; }
  196.                 }
  197.                 icon = (_regex_char.exec(note) || [])[1]|0;
  198.             }
  199.         } else { icon = (_regex_char.exec($gameParty.leader().actor().note) || [])[1]|0; }
  200.         if(oldIcon !== (_iconCache[id] = icon)) { _refresh = true; }
  201.     };
  202.  
  203.     //=============================================================================
  204.     // IAVRA.MINIMAP
  205.     //=============================================================================
  206.  
  207.     $.MINIMAP = {
  208.         Container: function() { this.initialize(); },
  209.         SpriteMap: function() { this.initialize(); },
  210.         SpritePoi: function(char) { this.initialize(char); },
  211.  
  212.         /**
  213.          * Reloads the map image or recreates the generated one used for the current map.
  214.          */
  215.         refresh: function() { setupMap($gameMap.mapId()); },
  216.  
  217.         /**
  218.          * Moves the minimap to the specified position.
  219.          */
  220.         move: function(x, y) { calculateFrame(parseInt(x) || 0, parseInt(y) || 0, _frame.w, _frame.h); },
  221.  
  222.         /**
  223.          * Resizes the minimap, updating its position, if needed.
  224.          */
  225.         resize: function(w, h) { calculateFrame(_frame.x, _frame.y, w|0, h|0); }
  226.     };
  227.  
  228.     /**
  229.      * Defining properties, that can be used at runtime or by a menu plugin to alter the minimap.
  230.      */
  231.     Object.defineProperties($.MINIMAP, {
  232.         x: {
  233.             get: function() { return _frame.x; },
  234.             set: function(value) { calculateFrame(parseInt(value) || 0, _frame.y, _frame.w, _frame.h); }
  235.         },
  236.         y: {
  237.             get: function() { return _frame.y; },
  238.             set: function(value) { calculateFrame(_frame.x, parseInt(value) || 0, _frame.w, _frame.h); }
  239.         },
  240.         width: {
  241.             get: function() { return _frame.w; },
  242.             set: function(value) { calculateFrame(_frame.x, _frame.y, value|0, _frame.h); }
  243.         },
  244.         height: {
  245.             get: function() { return _frame.h; },
  246.             set: function(value) { calculateFrame(_frame.x, _frame.y, _frame.w, value|0); }
  247.         },
  248.         center: {
  249.             get: function() { return _center; },
  250.             set: function(value) { _center = value || $gamePlayer; }
  251.         },
  252.         zoom: {
  253.             get: function() { return _zoom; },
  254.             set: function(value) { _zoom = Math.max(parseFloat(value) || 0, 0.1); }
  255.         },
  256.         opacity: {
  257.             get: function() { return _opacity; },
  258.             set: function(value) { _opacity = (parseFloat(value) || 0).clamp(0, 1); }
  259.         }
  260.     });
  261.  
  262.     //=============================================================================
  263.     // IAVRA.MINIMAP.Container
  264.     //=============================================================================
  265.  
  266.     $.MINIMAP.Container.prototype = $._extend(Object.create(Sprite.prototype), {
  267.  
  268.         /**
  269.          * Initializes the map, creating a bunch of children and triggering a refresh to setup all parts.
  270.          */
  271.         initialize: function() {
  272.             Sprite.prototype.initialize.call(this);
  273.             this.mask = this.addChild(new PIXI.Graphics().beginFill());
  274.             this.addChild(this._spriteMap = new $.MINIMAP.SpriteMap());
  275.             for(var i = 0, e = $gameMap.events(), ev; ev = e[i++]; ) { this.addChild(new $.MINIMAP.SpritePoi(ev)); }
  276.             this.addChild(new $.MINIMAP.SpritePoi($gamePlayer));
  277.             _center = $gamePlayer;
  278.             _refresh = true;
  279.         },
  280.  
  281.         /**
  282.          * Signals, whether the minimap is currently active. If not, it's hidden and not being updated.
  283.          */
  284.         active: function() {
  285.             if(!this._spriteMap.bitmap) { return false; }
  286.             if(_param_switch && !$gameSwitches.value(_param_switch)) { return false; }
  287.             if((this.alpha = _opacity) <= 0) { return false; }
  288.             return true;
  289.         },
  290.  
  291.         /**
  292.          * Updates all parts and causes them to refresh, if needed. If the minimap isn't active, this is skipped.
  293.          */
  294.         update: function() {
  295.             if(_refresh) { this.refresh(); }
  296.             if(this.active()) { this.visible = true; } else { this.visible = false; return; }
  297.             this.updateOffset(_center._realX, _center._realY);
  298.             for(var i = 1, max = this.children.length; i < max; ++i) { this.children[i].update(); }
  299.         },
  300.  
  301.         /**
  302.          * Calculates the current offset depending on the given center x and y coordinate.
  303.          */
  304.         updateOffset: function(x, y) {
  305.             _offset.x = this.width / 2 - x * _param_tileSize * _zoom;
  306.             _offset.y = this.height / 2 - y * _param_tileSize * _zoom;
  307.         },
  308.  
  309.         /**
  310.          * Causes all parts to refresh, reloading the data used to display the minimap.
  311.          */
  312.         refresh: function() {
  313.             this.refreshFrame(_frame);
  314.             for(var i = 1, max = this.children.length; i < max; ++i) { this.children[i].refresh(); }
  315.             _refresh = false;
  316.         },
  317.  
  318.         /**
  319.          * Checks, whether the map's frame data has been updated, repositioning and resizing the map accordingly.
  320.          */
  321.         refreshFrame: function(f) {
  322.             if(this.x !== f.x || this.y !== f.y || this.width !== f.w || this.height !== f.h) {
  323.                 this.move(f.x, f.y);
  324.                 this.mask.clear().drawRect(0, 0, f.w, f.h);
  325.                 this.bitmap = new Bitmap(f.w, f.h);
  326.                 this.bitmap.paintOpacity = _param_bgOpacity * 255;
  327.                 if(_param_bgColor && _param_bgOpacity > 0) { this.bitmap.fillAll(_param_bgColor); }
  328.             }
  329.         }
  330.  
  331.     });
  332.  
  333.     //=============================================================================
  334.     // IAVRA.MINIMAP.SpriteMap
  335.     //=============================================================================
  336.  
  337.     $.MINIMAP.SpriteMap.prototype = $._extend(Object.create(Sprite.prototype), {
  338.  
  339.         /**
  340.          * Creates the minimap image used for the current map, if it isn't already present in the cache.
  341.          */
  342.         initialize: function() {
  343.             Sprite.prototype.initialize.call(this);
  344.             if(_mapCache[$gameMap.mapId()] === undefined) { setupMap($gameMap.mapId()); }
  345.         },
  346.  
  347.         /**
  348.          * Repositions the map image according to the offset.
  349.          */
  350.         update: function() {
  351.             this.scale.x = this.scale.y = _zoom;
  352.             this.move(_offset.x - _param_tileSize * _zoom / 2, _offset.y - _param_tileSize  * _zoom / 2);
  353.         },
  354.  
  355.         /**
  356.          * Reloads the map image.
  357.          */
  358.         refresh: function() {
  359.             this.bitmap = _mapCache[$gameMap.mapId()];
  360.         }
  361.  
  362.     });
  363.  
  364.     //=============================================================================
  365.     // IAVRA.MINIMAP.SpritePoi
  366.     //=============================================================================
  367.  
  368.     $.MINIMAP.SpritePoi.prototype = $._extend(Object.create(Sprite.prototype), {
  369.  
  370.         /**
  371.          * Initializes the character data to be used for this PoI.
  372.          */
  373.         initialize: function(char) {
  374.             Sprite.prototype.initialize.call(this, ImageManager.loadSystem('IconSet'));
  375.             this.setFrame(0, 0, Window_Base._iconWidth, Window_Base._iconHeight);
  376.             setupCharacter(this._char = char);
  377.         },
  378.  
  379.         /**
  380.          * Repositions the icon according to the offset.
  381.          */
  382.         update: function() {
  383.             this.x = _offset.x - this.width / 2 + this._char._realX * _param_tileSize * _zoom;
  384.             this.y = _offset.y - this.height / 2 + this._char._realY * _param_tileSize * _zoom;
  385.         },
  386.  
  387.         /**
  388.          * Checks, which icon to be used for the PoI and moves the image frame accordingly.
  389.          */
  390.         refresh: function() {
  391.             var icon = _iconCache[this._char._eventId|0], w = this.width, h = this.height;
  392.             this.setFrame(icon % 16 * w, Math.floor(icon / 16) * h, w, h);
  393.         }
  394.  
  395.     });
  396.  
  397.     //=============================================================================
  398.     // Scene_Map
  399.     //=============================================================================
  400.  
  401.     /**
  402.      * The minimap is displayed below the window layer, but above all map data.
  403.      */
  404.     var _sceneMap_createWindowLayer = Scene_Map.prototype.createWindowLayer;
  405.     Scene_Map.prototype.createWindowLayer = function() {
  406.         this.addChild(new $.MINIMAP.Container());
  407.         _sceneMap_createWindowLayer.call(this);
  408.     };
  409.  
  410.     //=============================================================================
  411.     // Game_Player
  412.     //=============================================================================
  413.  
  414.     /**
  415.      * On refreshing $gamePlayer, check which icon to be displayed for it.
  416.      */
  417.     var _gamePlayer_refresh = Game_Player.prototype.refresh;
  418.     Game_Player.prototype.refresh = function() {
  419.         _gamePlayer_refresh.call(this);
  420.         setupCharacter(this);
  421.     };
  422.  
  423.     //=============================================================================
  424.     // Game_Event
  425.     //=============================================================================
  426.  
  427.     /**
  428.      * On refreshing an event, check which icon to be displayed for it.
  429.      */
  430.     var _gameEvent_refresh = Game_Event.prototype.refresh;
  431.     Game_Event.prototype.refresh = function() {
  432.         _gameEvent_refresh.call(this);
  433.         setupCharacter(this);
  434.     };
  435.  
  436. })(this.IAVRA || (this.IAVRA = {}));
RAW Paste Data