/*:
 * @target MZ
 * @plugindesc v0.5.9 Map zoom
 * @author ScSWinter
 *
 * @help
 * =======================================================
 * Information
 * =======================================================
 * This script allows you to show maps with a default zoom.
 * When activated the zoom of the map changes. Specify the
 * map zoom using in the map notetag box the notetag
 *    Zoom:X
 * where X is a number greater than 1. If the notetag is not
 * specified the default zoom is the one at the options.
 *
 * IMPORTANT: Using zoom will free the camera on edges.
 *
 * =======================================================
 * Credits
 * =======================================================
 * Please, credit to "ScSWinter" in the credits of your game.
 *
 * =======================================================
 * License: The MIT License
 * =======================================================
 * Copyright 2020 ScSWinter
 * This plugin is released under MIT license.
 * http://opensource.org/licenses/mit-license.php
 *
 * @param Default zoom for maps
 * @type number
 * @min 1.00
 * @max 9.00
 * @decimals 2
 * @desc The default zoom when none is specified as notetag.
 * @default 1.50
 *
 * @param Always free camera
 * @type boolean
 * @parent --- General ---
 * @on Yes
 * @off No
 * @desc When activated, the camera will never be blocked by
 * the edges of the map (as it works with the zoom on).
 * @default true
 *
 * @param Fix sprite black lines
 * @type boolean
 * @on Yes
 * @off No
 * @desc Fix sprite black lines? This option will cut the
 * sprites one pixel in each side.
 * @default true
 *
 * @param Fix map encounter zoom
 * @type boolean
 * @on Yes
 * @off No
 * @desc Fix map encounter zoom? Deactivate this option if
 * you changed the default encounter zoom effect.
 * @default true
 *
 * @command Zoom
 * @text Zoom
 * @desc Custom. display and vanish without wait.
 *
 * @arg FramesToZoom
 * @text Frames to Zoom
 * @desc The number of frames needed to perform the zoom.
 * @type number
 * @default 1
 * @min 1
 * @max 300
 *
 * @arg ZoomValue
 * @text Zoom Value
 * @desc The zoom value that will be performed.
 * @type number
 * @min 1.00
 * @max 9.00
 * @decimals 2
 * @default 1.50
 *
 */
(function() {
  'use strict';
  window.ScSWinterZoom = window.ScSWinterZoom || {};
  ScSWinterZoom.params = PluginManager.parameters('Zoom');
  var s_extractNoteValue = function(notes,ntag){
    var s_tags=notes.split(/[\r\n]+/), s_val="0";
    for(var i=0;i<s_tags.length;i++){
      if(s_tags[i].indexOf(ntag)>-1){
        var id=s_tags[i].split(':')
        s_val=id[1];
      }
    };
    return s_val;
  };

  /* Optional fixes */
  ScSWinterZoom.FixSprites = (ScSWinterZoom.params['Fix sprite black lines']=="true");
  if(ScSWinterZoom.FixSprites){
    Sprite_Character.prototype.setFrame = function(x, y, width, height) {
      width=(width==0?0:width-1);
      height=(height==0?0:height-1);
      Sprite.prototype.setFrame.call(this,x+1,y+1,width,height);
    };
  }
  ScSWinterZoom.FixEncounter = (ScSWinterZoom.params['Fix map encounter zoom']=="true");
  if(ScSWinterZoom.FixEncounter){
    Scene_Map.prototype.updateEncounterEffect = function() {
        if (this._encounterEffectDuration > 0) {
            this._encounterEffectDuration--;
            const speed = this.encounterEffectSpeed();
            const n = speed - this._encounterEffectDuration;
            const p = n / speed;
            var q = ((p - 1) * 20 * p + 5) * p + 1;
            q = q * $gameMap._currentZoom;
            const zoomX = $gamePlayer.screenX();
            const zoomY = $gamePlayer.screenY() - 24;
            if (n === 2) {
                $gameScreen.setZoom(zoomX, zoomY, 1);
                this.snapForBattleBackground();
                this.startFlashForEncounter(speed / 2);
            }
            $gameScreen.setZoom(zoomX, zoomY, q);
            if (n === Math.floor(speed / 6)) {
                this.startFlashForEncounter(speed / 2);
            }
            if (n === Math.floor(speed / 2)) {
                BattleManager.playBattleBgm();
                this.startFadeOut(this.fadeSpeed());
            }
        }
    };
  }
  ScSWinterZoom.FreeCamera = (ScSWinterZoom.params['Always free camera']=="true");

  /* Game_Map */
  Game_Map.prototype.extraScreenTile = function(zoom) {
    var tw=this.tileWidth(), th=this.tileHeight();
    this._extraScreenTileX = (Graphics.width/tw - Graphics.width/(tw*zoom) )/2;
    this._extraScreenTileY = (Graphics.height/th - Graphics.height/(th*zoom) )/2;
    this._currentZoom=zoom;
  };
  Game_Map.prototype.canvasToMapX = function(x) {
    const tileWidth = this.tileWidth() * this._currentZoom;
    const originX = (this._displayX + this._extraScreenTileX) * tileWidth;
    const mapX = Math.floor((originX + x) / tileWidth);
    return this.roundX(mapX);
  };
  Game_Map.prototype.canvasToMapY = function(y) {
    console.log(this._currentZoom);
    const tileHeight = this.tileHeight() * this._currentZoom;
    const originY = (this._displayY + this._extraScreenTileY) * tileHeight;
    const mapY = Math.floor((originY + y) / tileHeight);
    return this.roundY(mapY);
  };
  /* Without a correct initial camera position, this code is not useful.
     It works only when we start in middle of a not-looped map. */
  Game_Map.prototype.scrollLeft = function(distance) {
      if (this.isLoopHorizontal()) {
          this._displayX += $dataMap.width - distance;
          this._displayX %= $dataMap.width;
          if (this._parallaxLoopX) {
              this._parallaxX -= distance;
          }
      } else if(this._currentZoom>1.0 || ScSWinterZoom.FreeCamera){
          const lastX = this._displayX;
          this._displayX -= distance;
          this._parallaxX += this._displayX - lastX;
      } else if (this.width() >= this.screenTileX()) {
          const lastX = this._displayX;
          this._displayX = Math.max(this._displayX - distance, -this._extraScreenTileX);
          this._parallaxX += this._displayX - lastX;
      }
  };
  Game_Map.prototype.scrollRight = function(distance) {
      if (this.isLoopHorizontal()) {
          this._displayX += distance;
          this._displayX %= $dataMap.width;
          if (this._parallaxLoopX) {
              this._parallaxX += distance;
          }
      } else if(this._currentZoom>1.0 || ScSWinterZoom.FreeCamera){
          const lastX = this._displayX;
          this._displayX += distance;
          this._parallaxX += this._displayX - lastX;
      } else if (this.width() >= this.screenTileX()) {
          const lastX = this._displayX;
          this._displayX = Math.min(
              this._displayX + distance,
              this.width() - this.screenTileX() + this._extraScreenTileX
          );
          this._parallaxX += this._displayX - lastX;
      }
  };
  Game_Map.prototype.scrollUp = function(distance) {
      if (this.isLoopVertical()) {
          this._displayY += $dataMap.height - distance;
          this._displayY %= $dataMap.height;
          if (this._parallaxLoopY) {
              this._parallaxY -= distance;
          }
      } else if(this._currentZoom>1.0 || ScSWinterZoom.FreeCamera){
          const lastY = this._displayY;
          this._displayY -= distance;
          this._parallaxY += this._displayY - lastY;
      } else if (this.height() >= this.screenTileY()) {
          const lastY = this._displayY;
          this._displayY = Math.max(this._displayY - distance, -this._extraScreenTileY);
          this._parallaxY += this._displayY - lastY;
      }
  };
  Game_Map.prototype.scrollDown = function(distance) {
      if (this.isLoopVertical()) {
          this._displayY += distance;
          this._displayY %= $dataMap.height;
          if (this._parallaxLoopY) {
              this._parallaxY += distance;
          }
      } else if(this._currentZoom>1.0 || ScSWinterZoom.FreeCamera){
          const lastY = this._displayY;
          this._displayY += distance;
          this._parallaxY += this._displayY - lastY;
      } else if (this.height() >= this.screenTileY()) {
          const lastY = this._displayY;
          this._displayY = Math.min(
              this._displayY + distance,
              this.height() - this.screenTileY() + this._extraScreenTileY
          );
          this._parallaxY += this._displayY - lastY;
      }
  };
  Game_Map.prototype.setDisplayPos = function(x, y) {
    console.log(this._currentZoom);
      if (this.isLoopHorizontal()) {
          this._displayX = x.mod(this.width());
          this._parallaxX = x;
      } else if(this._currentZoom>1.0 || ScSWinterZoom.FreeCamera){
          this._displayX = x;
          this._parallaxX = x;
      } else {
          const endX = this.width() - this.screenTileX();
          this._displayX = endX < 0 ? endX / 2 : x.clamp(0, endX);
          this._parallaxX = this._displayX;
      }
      if (this.isLoopVertical()) {
          this._displayY = y.mod(this.height());
          this._parallaxY = y;
      } else if(this._currentZoom>1.0 || ScSWinterZoom.FreeCamera){
          this._displayY = y;
          this._parallaxY = y;
      } else {
          const endY = this.height() - this.screenTileY();
          this._displayY = endY < 0 ? endY / 2 : y.clamp(0, endY);
          this._parallaxY = this._displayY;
      }
  };

  /* Scene_Map */
  ScSWinterZoom.DefaultZoom = parseFloat(ScSWinterZoom.params['Default zoom for maps'])||1.0;
  Scene_Map.prototype.onMapLoaded = function(){
    var s_zoom=parseFloat(s_extractNoteValue($dataMap.note,"Zoom:"))||0.0;
    if(s_zoom<0.5) s_zoom=ScSWinterZoom.DefaultZoom;
    /* Possible workaround: if(s_zoom>=1) $dataMap.scrollType=3; */
    if(s_zoom>1.0) $gameMap.extraScreenTile(s_zoom);
    else $gameMap.extraScreenTile(1);
    if (this._transfer) {
        $gamePlayer.performTransfer();
    }
    if(s_zoom>1.0){
      $gameScreen.setZoom($gamePlayer.screenX(),$gamePlayer.screenY()-$gameMap.tileWidth()/2,s_zoom);
    }else $gameScreen.clearZoom();
    this.createDisplayObjects();
  };

  /* Game_Screen */
  Game_Screen.prototype.updateZoom = function() {
      if (this._zoomDuration > 0) {
          const d = this._zoomDuration;
          const t = this._zoomScaleTarget;
          this._zoomScale = (this._zoomScale * (d - 1) + t) / d;
          $gameMap.extraScreenTile(this._zoomScale);
          this._zoomDuration--;
      }
  };

  /* PluginManager */
  PluginManager.registerCommand('Zoom', 'Zoom', args => {
    const frameToZoom = +args.FramesToZoom;
    const valueZoom = +args.ZoomValue;
    $gameMap.extraScreenTile(valueZoom);
    $gameScreen.startZoom($gamePlayer.screenX(),$gamePlayer.screenY()-$gameMap.tileWidth()/2, valueZoom, frameToZoom);
  });

})();
