//-----------------------------------------------------------------------------
//  Galv's Cam Control MZ
//-----------------------------------------------------------------------------
//  For: RPGMAKER MV
//  GALV_CamControlMZ.js
//-----------------------------------------------------------------------------
//  2020-08-26 - Version 1.0 - release
//-----------------------------------------------------------------------------
// Terms can be found at:
// galvs-scripts.com
//-----------------------------------------------------------------------------

var Imported = Imported || {};
Imported.Galv_CamControl = true;

var Galv = Galv || {};          // Galv's main object
Galv.CC = Galv.CC || {};        // This plugin object
Galv.CC.pluginName = "GALV_CamControlMZ";

//-----------------------------------------------------------------------------
/*:
 * @plugindesc (v.1.0) Allows greater control over where the game camera is focused. View documentation for plugin commands.
 * @url http://galvs-scripts.com
 * @target MZ
 * @author Galv
 *
 * @command focusCharacter
 * @text Focus Character
 * @desc Set the camera's focus to a character
 *
 * @arg charId
 * @default 0
 * @text Character Id
 * @desc Target event id for camera focus or use 0 for player
 *
 * @arg speed
 * @default 800
 * @text Scroll Speed
 * @desc The speed in which the camera scrolls to the target (higher is slower)
 *
 * @command focusXY
 * @text Focus Map Tile
 * @desc Set the camera's focus to a map tile's X,Y position
 *
 * @arg posX
 * @default 0
 * @text X Position
 * @desc The tile's X position
 *
 * @arg posY
 * @default 0
 * @text Y Position
 * @desc The tile's Y position
 *
 * @arg speed
 * @default 800
 * @text Scroll Speed
 * @desc The speed in which the camera scrolls to the target (higher is slower)
 *
 * @command disable
 * @text Disable Focus
 * @desc Remove the camera focus and back to default camera on player. Do this to use Scroll Map event commands
 *
 * @help
 *   Galv's Cam Control MZ
 * ----------------------------------------------------------------------------
 * This plugin creates a sliding movement for the camera as well as allows you
 * to set the target position of it to wherever required. (Player, event, xy)
 *
 * ----------------------------------------------------------------------------
 *   PLUGIN COMMANDS
 * ----------------------------------------------------------------------------
 *   Focus Character              // Set camera focus to a character.
 *                                // 0 for player, higher numbers for event ids
 *                                // Higher speed is slower camera
 *
 *   Focus Map Tile               // Set camera focus to an event.
 *                                // As above but instead of a character target
 *                                // you can set x,y tile position on the map
 *
 *
 *   Disable Focus                // Sets the focus on player and disables the
 *                                // sliding motion. (RPGMaker default)
 *                                // Using any command above will enable again
 *
 * NOTES: The higher the SPD value for these commands, the slower the movement.
 * Not recommended to use speeds that are too fast.
 * v# to use a variable's value in these options, where # is the variable id.
 */

//-----------------------------------------------------------------------------
//  CODE STUFFS
//-----------------------------------------------------------------------------

// PLUGIN COMMANDS
//-----------------------------------------------------------------------------

PluginManager.registerCommand(Galv.CC.pluginName, "focusCharacter", args => {
	const type = Galv.CC.getValue(args.charId) > 0 ? ["event"] : ["player"];
	const settings = type.concat(Object.values(args));
    Galv.CC.camControl(settings);  // Send an array of the setting values
});

PluginManager.registerCommand(Galv.CC.pluginName, "focusXY", args => {
	const settings = Object.values(args);
    Galv.CC.camControl(settings);  // Send an array of the setting values
});

PluginManager.registerCommand(Galv.CC.pluginName, "disable", args => {
    Galv.CC.camControl(["disable"]);  // Send an array of the setting values
});


// PLUGIN FUCNTIONS
//-----------------------------------------------------------------------------

Galv.CC.camControl = function(args) {
	let key = args[0].toLowerCase();
	let speed = 800;
	let target = $gamePlayer;
	switch (key) {
		case "player":
			if (args[1]) speed = Galv.CC.getValue(args[1]);
			break;
		case "event":
			let eId = Galv.CC.getValue(args[1]);
			target = $gameMap.event(eId);
			if (args[2]) speed = Galv.CC.getValue(args[2]);
			break;
		case "disable":
			$gameMap.camTarget = $gamePlayer;
			$gameMap.camNorm = true;
			$gameMap.savedCamTarget = null;
			return;
		default:
			let px = Galv.CC.getValue(args[0]);
			let py = Galv.CC.getValue(args[1]);
			if (args[2]) speed = Galv.CC.getValue(args[2]);
			target = {
				x: px,
				y: py,
				_realX: px,
				_realY: py,
				screenX: Game_CharacterBase.prototype.screenX,
				screenY: function() {
					let th = $gameMap.tileHeight();
					return Math.round(this.scrolledY() * th + th);
				},
				scrolledX: Game_CharacterBase.prototype.scrolledX,
				scrolledY: Game_CharacterBase.prototype.scrolledY
			};
	};
	
	$gameMap.camTargetSet(target,speed);
	$gameMap.savedCamTarget = args;
};


// OTHER
//-----------------------------------------------------------------------------

Galv.CC.getValue = function(string) {
	if (string[0].toLowerCase() === "v") {
		// Use variable
		let varId = Number(string.replace("v",""));
		return $gameVariables.value(varId);
	} else {
		return Number(string);
	};
};


// GAME PLAYER
//-----------------------------------------------------------------------------

Galv.CC.Game_Player_updateScroll = Game_Player.prototype.updateScroll;
Game_Player.prototype.updateScroll = function(lastScrolledX, lastScrolledY) {
	if ($gameMap.camNorm) return Galv.CC.Game_Player_updateScroll.call(this,lastScrolledX, lastScrolledY);
};


// GAME MAP
//-----------------------------------------------------------------------------

// OVERWRITE
Game_Map.prototype.displayX = function() {return Math.floor(this._displayX * Galv.CC.size) / Galv.CC.size};
Game_Map.prototype.displayY = function() {return Math.floor(this._displayY * Galv.CC.size) / Galv.CC.size};

Galv.CC.Game_Map_setup = Game_Map.prototype.setup;
Game_Map.prototype.setup = function(mapId) {
	Galv.CC.size = $gameMap.tileWidth();
	this.zoom = this.zoom || new PIXI.Point(1,1);
	if (!this.camNorm) {
		this.camTargetSet($gamePlayer,800);
		this.savedCamTarget = ["player"];
	};
	Galv.CC.Game_Map_setup.call(this,mapId);
};

Galv.CC.Scene_Map_onMapLoaded = Scene_Map.prototype.onMapLoaded;
Scene_Map.prototype.onMapLoaded = function() {
	Galv.CC.Scene_Map_onMapLoaded.call(this);
	if (!$gameMap.camNorm) {
		$gameMap.savedCamTarget = $gameMap.savedCamTarget || ["player"];
		Galv.CC.camControl($gameMap.savedCamTarget);
	};
};

Game_Map.prototype.camTargetSet = function(target,speed) {
    this.camTarget = target;
    this.camNorm = false;
    this.camSpeed = speed || 800;
};

Galv.CC.Game_Map_updateScroll = Game_Map.prototype.updateScroll;
Game_Map.prototype.updateScroll = function() {
	if (this.camNorm) return Galv.CC.Game_Map_updateScroll.call(this);

	this._scrollRest = 0;
    let cw = (Graphics.boxWidth / 2);
    let ch = (Graphics.boxHeight / 2); 
	let screenX = this.camTarget.screenX() * this.zoom.x;
	let screenY = this.camTarget.screenY() * this.zoom.y;
	let sx = Math.abs(screenX - cw) / this.camSpeed;
	let sy = Math.abs(screenY - ch) / this.camSpeed;
	if (sx < 0.01) (sx = 0);
	if (sy < 0.01) (sy = 0);

    let x_pos = screenX;
    let y_pos = screenY;
	
    if (y_pos < ch) {
      this.scrollUp(sy);
	} else if (y_pos > ch) {
      this.scrollDown(sy);
	};
	
    if (x_pos < cw) {
      this.scrollLeft(sx);
	} else if (x_pos > cw) {
      this.scrollRight(sx);
	};
};


// GAME PLAYER
//-----------------------------------------------------------------------------
Galv.CC.Game_Player_center = Game_Player.prototype.center;
Game_Player.prototype.center = function(x, y) {
	if ($gameMap.camTarget == $gamePlayer || $gameMap.camNorm) {
    	return Galv.CC.Game_Player_center.call(this,x,y);
	};
};

Game_Player.prototype.centerX = function() {
    return ((Graphics.width / $gameMap.tileWidth() - (1 * $gameMap.zoom.x)) / 2.0) / $gameMap.zoom.x;
};

Game_Player.prototype.centerY = function() {
    return ((Graphics.height / $gameMap.tileHeight() - 1.75 * $gameMap.zoom.y) / 2.0) / $gameMap.zoom.y;
};

