//=============================================================================
// MUR NPC v1.2
// Copyright (C) 2018,2020 MUR (https://github.com/murlab)
// BSD 3-Clause "New" or "Revised" License
// Free for use with both free and commercial RPG Maker games
//=============================================================================

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

var MUR = MUR || {};			// MUR's main object
MUR.NPC = MUR.NPC || {};		// Plugins's stuff

/*:
 * @plugindesc v1.0 NPC
 * @author MUR
 * @help 123
 *
 */

var params = PluginManager.parameters('MUR_NPC');
MUR.NPC.npc_id = 0;
MUR.NPC.npc_block_pos = {};

MUR.NPC.run = false;

MUR.NPC.newStep = false;
MUR.NPC.currentStep = 0;
MUR.NPC.balloons = " !?♪♥#^*…¤Z/o";

MUR.NPC.waitPicId = 0;

MUR.NPC.sceneMap;

MUR.NPC.relativePath = (Utils.isNwjs() && Utils.isOptionValid("test")) ? 'data' : 'www/data';

const fs = require('fs');

// Thanks Samuel Ondrek & Alexei Levenkov
var _getAllFilesFromFolder = function(dir) {

	var filesystem = require("fs");
	var results = [];
	filesystem.readdirSync(dir).forEach(function(file) {

		file = dir+'/'+file;
		var stat = filesystem.statSync(file);

		if (stat && stat.isDirectory()) {
			results = results.concat(_getAllFilesFromFolder(file))
		} else results.push(file);

	});

	return results;

};



var l = _getAllFilesFromFolder(MUR.NPC.relativePath + '/npc');
for (var i=0; i<l.length; i++) {
	var path = l[i];
	var name = path.replace(MUR.NPC.relativePath + '/npc/', '').replace('.json', '').replace(/\//g, '_');
	var src = path.replace(MUR.NPC.relativePath + '/','');

	var p = {name: "$" + name, src: src};
	DataManager._databaseFiles.push(p);
	MUR.NPC.npc_block_pos[name] = 0;
}


var _Scene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;
	Scene_Map.prototype.createAllWindows = function() {
		_Scene_Map_createAllWindows.call(this);
		MUR.NPC.sceneMap = this;
};

//------------------------------------------------------
// Восстановление (Инициализация) и Сохранение данных о позициях в данных NPC
//---------------------------------------------------
var _MurNpc_DataManager_extractSaveContents = DataManager.extractSaveContents;
DataManager.extractSaveContents = function(contents) {
	_MurNpc_DataManager_extractSaveContents.call(this, contents);
	for (var npc_id in MUR.NPC.npc_block_pos) {
		if (contents.murNpcBlockPos[npc_id]) {
			MUR.NPC.npc_block_pos[npc_id] = contents.murNpcBlockPos[npc_id];
		} else {
			MUR.NPC.npc_block_pos[npc_id] = 0;
		}
	}
};

var _DataManager_makeSaveContents = DataManager.makeSaveContents;
DataManager.makeSaveContents = function() {
	contents = _DataManager_makeSaveContents.call(this);
	contents.murNpcBlockPos = MUR.NPC.npc_block_pos;
	return contents;
};

//------------------------------------------------------
// Устанавливаем обработку ожидания
//------------------------------------------------------
var _MurNpc_Game_Interpreter_updateWaitMode = Game_Interpreter.prototype.updateWaitMode;	
Game_Interpreter.prototype.updateWaitMode = function() {
	var waiting = _MurNpc_Game_Interpreter_updateWaitMode.call(this);
	// Показ текста
	// if (MUR.NPC.textPrint) this.setWaitMode('message');
	// Перебить waiting только если он true !!!
	if (MUR.NPC.run) waiting = MUR.NPC.run;
	return waiting;
}

//------------------------------------------------------
// Устанавливаем обработку вызова команд плагина
//------------------------------------------------------
var _MurNpc_Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
	_MurNpc_Game_Interpreter_pluginCommand.call(this, command, args);
	if (command.toLowerCase() === "npc") {
		
		var map_npc = MUR.NPC.get_map_npc().replace(/\//g, '_');

		MUR.NPC.run = true;
		MUR.NPC.event_id = this._eventId;

		MUR.NPC.npc_name = '';
		MUR.NPC.npc_nick = '';
		MUR.NPC.npc_dis = '';
		MUR.NPC.npc_avatar = '';

		MUR.NPC.npc_id = map_npc + '_' + args[0];

		if (!isNaN(args[0])) {
			MUR.NPC.npc_id = 'id_'+args[0];
			MUR.NPC.npc_name = $gameActors.actor(Number(args[0]))._name;
			MUR.NPC.npc_nick = $gameActors.actor(Number(args[0]))._nickname;
			MUR.NPC.npc_dis = $gameActors.actor(Number(args[0]))._profile;
			MUR.NPC.npc_avatar = $gameActors.actor(Number(args[0]))._faceName;
		}

		MUR.NPC.leader_name = $gameParty.leader()._name;
		MUR.NPC.leader_nick = $gameParty.leader()._nickname;
		MUR.NPC.leader_dis = $gameParty.leader()._profile;
		MUR.NPC.leader_avatar = $gameParty.leader()._faceName;
		
		var npc_block_pos = MUR.NPC.npc_block_pos[MUR.NPC.npc_id];
		var npc_blocks = eval("$" + MUR.NPC.npc_id).blocks;
		var npc_block = npc_blocks[npc_block_pos];
		
		MUR.NPC.currentStep = 0;
		MUR.NPC.block_handler(npc_block, false);
	}
};


MUR.NPC.get_map_npc = function () {
	var map_id = '';
	var mapNotes = $dataMap.note.split("\n");
	for (var pId=0; pId < mapNotes.length; pId++) {
		var mNote = mapNotes[pId];
		if (mNote != "" && mNote.match(/<npc:\s*(.*)>/im)) {
			map_id = mNote.match(/npc:\s*(.*)>/im)[1];
			break;
		}
	}
	return map_id;
}

MUR.NPC.block_handler = function (data, force, aniWait=false, picWait=false) {
	
	var force_break = false;

	if (picWait) {
		if (Input.isPressed('ok')) {
			picWait = false;
			$gameScreen.erasePicture(MUR.NPC.waitPicId);

			MUR.NPC.sceneMap.children[1].removeChild(MUR.NPC.sceneMap._backgroundSprite);
		}
		setTimeout(function() { MUR.NPC.block_handler(data, false, aniWait, picWait) }, 100);

	} else if (aniWait) {
		setTimeout(function() { MUR.NPC.block_handler(data, false, ($gameMap.event(MUR.NPC.event_id)._eventAniFrames != undefined)), picWait }, 100);

	} else if ($gameMessage.isBusy() && !force) {
		setTimeout(function() { MUR.NPC.block_handler(data, false, aniWait, picWait) }, 100);
		
	} else {
		if (MUR.NPC.currentStep != -1) {
			var block_step = data[MUR.NPC.currentStep];

			force_break = (block_step.exit == true);
			
			var faceIndex = 0;
			if (block_step.faceIndex != undefined) {
				faceIndex = block_step.faceIndex;
			}

			if (block_step.type == "npc_text") {
				MUR.NPC.showText(MUR.NPC.leader_name, MUR.NPC.npc_name, MUR.NPC.npc_nick, MUR.NPC.npc_dis, MUR.NPC.npc_avatar, faceIndex, block_step.content);
				$gameMap._interpreter.setWaitMode('message');

			} else if (block_step.type == "leader_text") {
				MUR.NPC.showText(MUR.NPC.leader_name, MUR.NPC.leader_name, MUR.NPC.leader_nick, MUR.NPC.leader_dis, MUR.NPC.leader_avatar, faceIndex, block_step.content);
				$gameMap._interpreter.setWaitMode('message');
			
			} else if (block_step.type == "show_selector") {
				force_break = MUR.NPC.showSelector(block_step);
			
			} else if (block_step.type == "add_inventory") {
				MUR.NPC.add_inventory (block_step.items, false);
			
			} else if (block_step.type == "remove_inventory") {
				MUR.NPC.add_inventory (block_step.items, true);

			} else if (block_step.type == "check_switches") {
				MUR.NPC.check_switches (block_step);

			} else if (block_step.type == "set_switches") {
				MUR.NPC.set_switches (block_step.switches, block_step.global);

			} else if (block_step.type == "check_leader_sight") {
				MUR.NPC.check_leader_sight (block_step);

			} else if (block_step.type == "check_inventory") {
				MUR.NPC.check_inventory (block_step);

			} else if (block_step.type == "set_char_frame") {
				MUR.NPC.set_char_frame (block_step);

			} else if (block_step.type == "show_balloon") {
				MUR.NPC.show_balloon (block_step.target, block_step.balloon);

			} else if (block_step.type == "show_picture") {
				MUR.NPC.show_picture (block_step);

				picWait = block_step.wait;

			} else if (block_step.type == "jump") {
				MUR.NPC.jump_step (block_step.jump);

			} else if (block_step.type == "change_gold") {
				MUR.NPC.change_gold (block_step.gold);

			} else if (block_step.type == "change_inventory") {
				MUR.NPC.change_inventory (block_step);
			
			} else if (block_step.type == "actions") {
				MUR.NPC.actions (block_step.actions);

			} else if (block_step.type == "snd_play") {
				MUR.NPC.play_snd(block_step.snd, block_step.name, block_step.volume, block_step.pitch, block_step.pan);

			} else if (block_step.type == "snd_stop") {
				MUR.NPC.stop_snd(block_step.snd);

			} else if (block_step.type == "single_ani") {
				var char = $gameMap.event(MUR.NPC.event_id);
				char._eventAniFramesCurrent = block_step.start;
				char._eventAniFrames = block_step.start + block_step.frames;
				char._eventAniPause = block_step.pause;
				char._eventAniPauseCurrent = block_step.pause;
				char._eventAniReverse = false;
				char._eventAniStep = 1;
				char._eventAniSingle = true;

				aniWait = block_step.wait;

			} else if (block_step.type == "fade") {
				if (block_step.out) {
					$gameMap._interpreter.command222();
				} else {
					$gameMap._interpreter.command221();
				}
			
			} else if (block_step.type == "set_char_image") {
				if (block_step.char == "player") {
					MUR.NPC.set_player_image(block_step.actor, block_step.name, block_step.part);
				} else {
					MUR.NPC.set_npc_image(block_step.name, block_step.part);
				}
			
			} else if (block_step.type == "set_block") {
				MUR.NPC.set_block(block_step.block, block_step.autostart);

			} else if (block_step.type == "exit") {
				force_break = true;
			}

			if (MUR.NPC.newStep) {
				MUR.NPC.newStep = false;
			} else {
				MUR.NPC.currentStep++;
			}

			if (MUR.NPC.currentStep < Object.keys(data).length && !force_break) {
				setTimeout(function() { MUR.NPC.block_handler(data, (data[MUR.NPC.currentStep].type == "show_selector"), aniWait, picWait) }, 100);
			
			} else {
				MUR.NPC.run = false;
			}

			if (force_break) {
				MUR.NPC.run = false;
			}
		} else {
			MUR.NPC.run = false;
		}
	}
}

MUR.NPC.showText = function (leaderName, actorName, actorNick, actorDis, actorAvatar, actorIndex, actorTexts) {

	$gameMessage.newPage();
	$gameMessage.setFaceImage(actorAvatar, actorIndex);
	for (var i=0; i < actorTexts.length; i++) {
		var text = actorTexts[i];
		text = text.replace('%name%', actorName);
		text = text.replace('%leader_name%', leaderName);
		text = text.replace('%nick%', actorNick);
		text = text.replace('%dis%', actorDis);
		var re1 = /(%item_(\d+)+%)/;
		while(m = text.match(re1)) {
			var itemName = $dataItems[m[2]].name;
			text = text.replace(re1, itemName);
		}
		$gameMessage.add(text);
	}
}
	
MUR.NPC.showSelector = function (data) {
	var options = [];
	var actions = [];
	for (var j=0; j < data.options.length; j++) {
		var name = data.options[j].name;
		var re1 = /(%item_(\d+)+%)/;
		while(m = name.match(re1)) {
			var itemName = $dataItems[m[2]].name;
			name = name.replace(re1, itemName);
		}
		options.push(name);
		var jmp = data.options[j].jump;
		actions.push('set_step(' + jmp + ')');
	}
	$gameMessage.setChoices(options, data.option_default, data.option_cancel);
	$gameMessage.setChoiceCallback(function(responseIndex) {
		eval("MUR.NPC." + actions[responseIndex]);
	} );
}

MUR.NPC.add_inventory = function (data, remove = false) {
	for (var i=0; i < data.length; i++) {
		var type = data[i].type;
		var id = data[i].id ? data[i].id : -1;
		var amount = remove ? -data[i].amount : data[i].amount;
		if (type == "gold") {
			$gameParty.gainGold(amount);
		} else {
			var item;
			if (type == "items") {
				item = $dataItems[id];

			} else if(type == "weapons") {
				item = $dataWeapons[id];

			} else if(type == "armors") {
				item = $dataArmors[id];	
			}
			if (item != undefined) {
				$gameParty.gainItem(item, amount);
			} else {
				var cName = "add";
				if (amount < 0) {
					cName = "remove";
				}
				console.error("[" + cName + "_inventory] wrong structure!");
			}
		}
	}
}

MUR.NPC.remove_inventory = function (data) {
	MUR.NPC.add_inventory(data, true);
}

MUR.NPC.set_char_frame = function (data) {
	var f = data.frame;
	var player = data.player;
	var d = [
		[2,0], [2,1], [2,2],	// ↓
		[4,0], [4,1], [4,2],	// ←
		[6,0], [6,1], [6,2],	// →
		[8,0], [8,1], [8,2]		// ↑
	]
	if (player) {
		$gamePlayer._direction = d[f][0];
		$gamePlayer._originalPattern = d[f][1];
	} else {
		$gameMap.event(MUR.NPC.event_id)._direction = d[f][0];
		$gameMap.event(MUR.NPC.event_id)._originalPattern = d[f][1];
	}
}

MUR.NPC.check_leader_sight = function (data) {
	var jump = data.jump;
	var sight = data.sight;
	var dirs = { left:4, right:6, up:8, down:2};
	if (dirs[sight] == $gamePlayer.direction()) {
		eval("MUR.NPC.jump_step(" + jump + ")");
	}
}

MUR.NPC.check_switches = function (data) {
	var switches = data.switches;
	var jump = data.jump;
	var globalId = data.global;
	var enableJump = true;
	for (var switchName in switches) {
		if (switchName == 'G') {
			if (switches[switchName] != $gameSwitches.value(globalId)) {
				enableJump = false;
				break;
			}
		} else {
			if (switches[switchName] != $gameSelfSwitches.value([$gameMap._mapId, MUR.NPC.event_id, switchName])) {
				enableJump = false;
				break;
			}
		}
	}
	if (enableJump) {
		eval("MUR.NPC.jump_step(" + jump + ")");
	}
}

MUR.NPC.check_inventory = function (data) {

	var category = data.category;
	var id = data.id;
	var amount = data.amount;
	var jump = data.jump;
	var enableJump = false;
	var equipped = data.equipped;
	
	if (category == 'gold' && $gameParty.gold() >= amount) {
		enableJump = true;

	} else {

		var item = $dataItems[id];
		if (category == 'armors') {
			item = $dataArmors[id];
		} else if (category == 'weapons') {
			item = $dataWeapons[id];
		}

		if (equipped) {
			if ($gameParty.isAnyMemberEquipped(item)) enableJump = true;

		} else if (amount == 1) {
			if ($gameParty.hasItem(item, true)) enableJump = true;

		} else {
			if ($gameParty.numItems(item) >= amount) enableJump = true;
		}
	}

	if (enableJump) {
		eval("MUR.NPC.jump_step(" + jump + ")");
	}
}

MUR.NPC.actions = function (actions) {
	for (var i=0; i < actions.length; i++) {
		if (actions[i] && actions[i] != "") eval("MUR.NPC." + actions[i]);
	}
}

//------------------------------------------------------
// Функции для Actions
//------------------------------------------------------

MUR.NPC.open_inventory = function() {
	SceneManager.push(Scene_Equip);
}

MUR.NPC.set_switches = function(switches, globalId) {
	for (var switchName in switches) {
		var switchState = switches[switchName];
		if (switchName == 'G') {
			$gameSwitches.setValue(globalId, switchState);
		} else {
			$gameSelfSwitches.setValue([$gameMap._mapId, MUR.NPC.event_id, switchName], switchState);
		}
	}
}

MUR.NPC.change_gold = function (gold) {
	MUR.NPC.add_inventory([{type:'gold', amount:gold}]);
}

MUR.NPC.change_inventory = function (data) {
	MUR.NPC.add_inventory([{type:data.category, id:data.id, amount:data.amount}]);
}

MUR.NPC.jump_step = function (newStep) {
	MUR.NPC.newStep = true;
	MUR.NPC.currentStep = newStep;
}

MUR.NPC.set_step = function (newStep) {
	MUR.NPC.currentStep = newStep;
}

MUR.NPC.set_block = function (blockId, restart_blocks) {
	MUR.NPC.npc_block_pos[MUR.NPC.npc_id] = blockId;
}

MUR.NPC.show_picture = function (data) {

	MUR.NPC.sceneMap._backgroundSprite = new Sprite();

	if (data.blur) {
		MUR.NPC.sceneMap._windowLayer.visible = false;
		SceneManager.snapForBackground();
		MUR.NPC.sceneMap._windowLayer.visible = true;

		MUR.NPC.sceneMap._backgroundSprite.bitmap = SceneManager.backgroundBitmap();
		MUR.NPC.sceneMap.children[1].addChildAt(MUR.NPC.sceneMap._backgroundSprite, 1);
	}
	

	var pictureId = $gameScreen._pictures.length;
	if (pictureId == 0) pictureId = 1; // с нуля не отображается
	var name = data.name;
	var origin = 0;		// начало: 0 - верхний левый угол, 1- центр картинки
	var x = data.x;
	var y = data.y;
	if (data.center) {
		x = Graphics.width/2;
		y = Graphics.height/2;
		origin = 1;
	}

	var scaleX = scaleY = 100;
	var opacity = 255;
	var blendMode = 0;
	$gameScreen.showPicture(pictureId, name, origin, x, y, scaleX, scaleY, opacity, blendMode);
	MUR.NPC.waitPicId = pictureId;
}

MUR.NPC.show_balloon = function (target, type) {
	var char = $gamePlayer;
	switch (target) {
		case 'player':
			char = $gamePlayer;
			break;
		case 'npc':
			char = $gameMap.event(MUR.NPC.event_id);
			break;
		case 'boat':
			char = $gameMap.boat();
			break;
		case 'ship':
			char = $gameMap.ship();
			break;
		case 'airship':
			char = $gameMap.airship();
			break;
		default:
			char = $gamePlayer;
			break;
	}

	var num = []

	$gameMap._interpreter._character = char;
	char.requestBalloon(MUR.NPC.balloons.indexOf(type));
	$gameMap._interpreter.setWaitMode('balloon');
}

MUR.NPC.play_se = function (filename, volume, pitch, pan) {
	var soundObject = { "name": filename, "volume": volume, "pitch": pitch, "pan": pan };
	AudioManager.playSe( soundObject );
}

MUR.NPC.play_snd = function (snd, filename, volume, pitch, pan) {
	var soundObject = { "name": filename, "volume": volume, "pitch": pitch, "pan": pan };
	switch (snd) {
		case "bgm":
			AudioManager.playBgm( soundObject );
			break;
		case "bgs":
			AudioManager.playBgs( soundObject );
			break;
		case "me":
			AudioManager.playMe( soundObject );
			break;
		case "se":
			AudioManager.playSe( soundObject );
			break;
	}
}

MUR.NPC.stop_snd = function (snd) {
	switch (snd) {
		case "bgm":
			AudioManager.stopBgm();
			break;
		case "bgs":
			AudioManager.stopBgs();
			break;
		case "me":
			AudioManager.stopMe();
			break;
		case "se":
			AudioManager.stopSe();
			break;
		default:
			AudioManager.stopBgm();
			AudioManager.stopBgs();
			AudioManager.stopMe();
			AudioManager.stopSe();
			break;
	}
}

MUR.NPC.set_wait = function(wait) {
	$gameMap._interpreter.wait(wait);
}

MUR.NPC.set_player_image = function(actorId, imageName, imagePart) {
	var actor = $gameActors.actor(actorId);
	actor.setCharacterImage(imageName, imagePart);
}

MUR.NPC.set_npc_image = function(imageName, imagePart) {
	$gameMap.event(MUR.NPC.event_id).setImage(imageName, imagePart);
}
