#include "dialog_func.c"


#define EVENT_DIALOG_START		"evntDialogStart"
#define EVENT_DIALOG_EXIT		"evntDialogExit"

#event_handler("dlgReady", "StartDialogWithMainCharacter");
#event_handler("EmergencyDialogExit","DialogExit");

extern void ProcessDialogEvent();

bool dialogDisable = false;
object	Dialog;
ref		CharacterRef;
bool	dialogRun = false;
bool	dialogSelf = false;
bool	FightDisable; // PB

string  FullDialogPath;
string	PathDlgLngExtn;

//Инициализация
void DialogsInit()
{
	Quest_Init();				//Инициализация начального состояния слухов и информации об NPC ------- Ренат
}

//Начать диалог
bool DialogMain(ref Character)
{
	if(CheckAttribute(Character, "condition") && Character.condition=="reload") return false;//MAXIMUS: prevents from dialogs start during reload -->
	if(CheckAttribute(GetMainCharacter(), "condition") && Characters[GetMainCharacterIndex()].condition=="reload") return false;//MAXIMUS: prevents from dialogs start during reload <--
	//Если диалог запущен, выходим
	if(dialogRun != false) return false;
	//Ссылка на главного персонажа
	ref mainChr = GetMainCharacter();
	//Если когото не заведено, выходим
	if(!IsEntity(mainChr)) return false;
	if(!IsEntity(Character)) return false;
	if(LAi_IsDead(mainChr)) return false;
	if(LAi_IsDead(Character)) return false;
	//Проверим на существование текущего нода
	if(!CheckAttribute(Character, "Dialog.CurrentNode"))
	{
		Trace("Dialog: Character <" + Character.id + "> can't have field Dialog.CurrentNode, exit from dialog!")
		return false;
	}
	//Если персонаж не готов говорить выходим
	if(!LAi_Character_CanDialog(mainChr, Character)) return false;
	//Если персонаж не готов говорить выходим
	if(!LAi_Character_CanDialog(Character, mainChr)) return false;
// added by MAXIMUS -->
	if(CheckAttribute(Character,"corpse"))//MAXIMUS: was [if(Character.Dialog.Filename == "corpse_dialog.c")]
	{//MAXIMUS: dialog with Maltese-corpse will be started by looting only -->
		bool bMaltese = false;
		if(CheckAttribute(Character,"lootDialog")) { bMaltese = true; }
		if(!bMaltese)
		{
			Log_SetStringToLog(TranslateString("","Gamlet"));
			return false;
		}
	}//MAXIMUS: dialog with Maltese-corpse will be started by looting only <--
// added by MAXIMUS <--
	//Сохраняем ссыклу на того с кем говорим
	CharacterRef = Character;
	// Попытка загрузить текст дилога
	if( !LoadDialogFiles(Character.Dialog.Filename) ) {
		// имеем ошибочный диалог
		if( !LoadDialogFiles("error_dialog.c") ) {
			return false;
		}
	}
	//Можем начинать диалог
	dialogRun = true;
	dialogSelf = false;
	LAi_Character_StartDialog(mainChr, Character);
	LAi_Character_StartDialog(Character, mainChr);
	if(CheckAttribute(Character,"corpse")==true) mainChr.IsInDialog = 1;		// LDH - To prevent corpses from disappearing while talking to them

// PB: No fights during dialog -->
	FightDisable = false;
	if(!CheckAttribute( &Locations[FindLocation(mainChr.location)],"noFight" )) {LAi_LocationFightDisable(&Locations[FindLocation(mainChr.location)], true);}
	// if LocationFightDisable is not on, set LocationFightDisable on
	else {FightDisable = true;}
	// if LocationFightDisable is already on, set FightDisable true so that LocationFightDisable will remain on after the dialog is closed
// PB: No fights during dialog <--

// ccc building kit, keeps first person view for building dialogs
	if(Character.chr_ai.type != LAI_TYPE_BUILDING) SendMessage(mainChr, "lsl", MSG_CHARACTER_EX_MSG, "InDialog", 1);
	SendMessage(Character, "lsl", MSG_CHARACTER_EX_MSG, "InDialog", 1);	
	//Запускаем диалог
	//Trace("Dialog: dialog path for character <" + Character.id + "> = " + FullDialogPath);
	Dialog.CurrentNode = CharacterRef.Dialog.CurrentNode;
	startDialogMainCounter = 0;
	SetEventHandler("frame", "StartDialogMain", 1);
	SetTimeScale(0.0);
	return true;	
}

int startDialogMainCounter = 0;
// KK int dialogWaitGreetingSound = 0;
// KK string dialogGreetingSound = "";

void StartDialogMain()
{
	if(CheckAttribute(CharacterRef, "condition") && CharacterRef.condition=="reload") return;//MAXIMUS: prevents from dialogs start during reload -[here too (to be sure)]->
	if(CheckAttribute(GetMainCharacter(), "condition") && Characters[GetMainCharacterIndex()].condition=="reload") return;//MAXIMUS: prevents from dialogs start during reload <--

	startDialogMainCounter++;
	if(startDialogMainCounter < 3) return;

	if(DIALOG_CAMERA>0.0)
	{
		float size = 3.0+DIALOG_CAMERA;
		ref curLocation = &Locations[FindLoadedLocation()];
		if(HasSubStr(curLocation.id,"Tutorial_Deck") || HasSubStr(curLocation.id,"Seadog")) size = 0.8+DIALOG_CAMERA;
		if(CheckAttribute(curLocation,"models.back") || HasSubStr(curLocation.id,"House")) size = 0.5+DIALOG_CAMERA;
		if(HasSubStr(curLocation.id,"Cabin")) size = 0.3+DIALOG_CAMERA;
		if(HasSubStr(curLocation.id,"Small")) size = 0.2+DIALOG_CAMERA;
		if(CheckAttribute(CharacterRef,"chr_ai.type") && CharacterRef.chr_ai.type==LAI_TYPE_LAY) size = 0.2+DIALOG_CAMERA;
		DialogCamera(GetMainCharacter(), size, true);
	}
	
	DelEventHandler("frame", "StartDialogMain");

	// KK -->
	if(NEW_DIALOG_INTERFACE) CreateEntity(&Dialog, "dialg2");
	else CreateEntity(&Dialog, "dialog")
	// KK <--

	Log_SetActiveAction("Nothing");//MAXIMUS
	SendMessage(&ILogAndActions,"ll",LI_SET_VISIBLE,false);//MAXIMUS
	if(FindFile("resource\models\Heads\", "*.gm", CharacterRef.headModel+".gm")=="")
	{
		if(CharacterRef.headModel!="h_"+CharacterRef.Model) CharacterRef.headModel = "h_"+CharacterRef.Model;//MAXIMUS: prevents some errors (I'm wondering: sometimes we have models-names, like 23iu432523h)
//		else Dialog.headModel = "h_Skel4";//MAXIMUS: temporary (for excluding errors). Maybe someone can make heads???
	}
	if(FindFile("resource\models\Heads\", "*.gm", CharacterRef.headModel+".gm")!="") Dialog.headModel = CharacterRef.headModel;
	Dialog.gender = CharacterRef.sex;

	DeleteAttribute(&Dialog,"Links");
	DeleteAttribute(&Dialog,"Text");

// KK -->
	SetEventHandler("PlayDialogGreeting", "DialogPlayGreeting", 0);
	if(CheckAttribute(CharacterRef, "greeting") == true && CharacterRef.greeting != "")
	{
		//dialogGreetingSound = CharacterRef.greeting;
		//dialogWaitGreetingSound = 0;
		PostEvent("PlayDialogGreeting", 100.0);
	}
// <-- KK

	object persRef = GetCharacterModel(Characters[GetMainCharacterIndex()]);
	SendMessage(&Dialog, "lii", 0, &Characters[GetMainCharacterIndex()], &persRef);

	object charRef = GetCharacterModel(Characters[makeint(CharacterRef.index)]);
	SendMessage(&Dialog, "lii", 1, &Characters[makeint(CharacterRef.index)], &charRef);

	LayerCreate("realize",1);
	LayerSetRealize("realize",1);
	LayerAddObject("realize",Dialog,-256);
	Set_inDialog_Attributes();
	// KK ProcessDialogEvent();

	// NK 05-07-19 fix for corpses, where segment unloaded before following event handlers can execute.
	if (CheckAttribute(CharacterRef, "dlgover")) {
		DeleteAttribute(&CharacterRef, "dlgover");
	} else {
		SetEventHandler("DialogEvent","ProcessDialogText",0);
	//SetEventHandler("DialogCancel","DialogExit",0);

		ProcessDialogText(); // KK
		Event(EVENT_DIALOG_START,"");
	} // FYI this will hide the BLI. NK 05-07-19
	ResetTimeToNormal();//MAXIMUS
}

// KK -->
#event_handler("PlayDialogGreeting", "DialogPlayGreeting");
void DialogPlayGreeting()
{
	//dialogWaitGreetingSound++;
	//if(dialogWaitGreetingSound < 10) return;
	//dialogWaitGreetingSound = 0;
	DelEventHandler("PlayDialogGreeting", "DialogPlayGreeting");
	//Dialog.greeting = CharacterRef.greeting;
	PlayGreeting(CharacterRef);
}
// <-- KK

//Начать диалог с самим собой
void SelfDialog(ref Character)
{
	//Если диалог запущен, выходим
	if(dialogRun != false) return; //MAXIMUS: void function return value (was "return false")
	//Если когото не заведено, выходим
	if(!IsEntity(Character) && !CheckAttribute(Character,"SailHo") && !CheckAttribute(Character,"DirectSail.messenger")) return false;//changed by MAXIMUS: for new "Sail Ho" and DirectSail-Mod
	//Проверим на существование текущего нода
	if(!CheckAttribute(Character, "Dialog.CurrentNode"))
	{
		Trace("SelfDialog: Character <" + Character.id + "> can't have field Dialog.CurrentNode, exit from dialog!")
		return false;
	}
	//Сохраняем ссылку на того с кем говорим
	CharacterRef = Character;
	// Попытка загрузить текст дилога
	if(!LoadDialogFiles(Character.Dialog.Filename))
	{
		// имеем ошибочный диалог
		if(!LoadDialogFiles("error_dialog.c")) return; //MAXIMUS: void function return value (was "return false")
	}
	//Если персонаж не готов говорить выходим
	LAi_Character_CanDialog(Character, Character);
	//Можем начинать диалог
	dialogRun = true;
	dialogSelf = true;
	SendMessage(Character, "lsl", MSG_CHARACTER_EX_MSG, "InDialog", 1);
	//Запускаем диалог
	Dialog.CurrentNode = CharacterRef.Dialog.CurrentNode;
	//Trace("SelfDialog: dialog path for self character <" + Character.id + "> = " + FullDialogPath);
	CreateEntity(&Dialog, "dialog");
	Log_SetActiveAction("Nothing");//MAXIMUS
	SendMessage(&ILogAndActions,"ll",LI_SET_VISIBLE,false);//MAXIMUS
	if(FindFile("resource\models\Heads\", "*.gm", CharacterRef.headModel+".gm")=="")
	{
		if(CharacterRef.headModel!="h_"+CharacterRef.Model) CharacterRef.headModel = "h_"+CharacterRef.Model;//MAXIMUS: prevents some errors (I'm wondering: sometimes we have models-names, like 23iu432523h)
//		else Dialog.headModel = "h_Skel4";//MAXIMUS: temporary (for excluding errors). Maybe someone can make heads???
	}
	if(FindFile("resource\models\Heads\", "*.gm", CharacterRef.headModel+".gm")!="") Dialog.headModel = CharacterRef.headModel;
	Dialog.gender = Character.sex;

	object persRef = GetCharacterModel(Characters[GetMainCharacterIndex()]);
	SendMessage(&Dialog, "lii", 0, Character, &persRef);
	SendMessage(&Dialog, "lii", 1, Character, &persRef);
	
//changed by MAXIMUS: for new "Sail Ho" and DirectSail-Mod -->
	if(!bSeaActive)
	{
		LayerCreate("realize",1);
		LayerSetRealize("realize",1);
	}
	if(bSeaActive && !IsEntity(&worldMap)) { SendMessage(&BattleInterface,"ll",BI_SET_VISIBLE,false); LayerAddObject(SEA_EXECUTE, Dialog, -256); LayerAddObject(SEA_REALIZE, Dialog, -256); }
	else { LayerAddObject("realize",Dialog,-256); }
//changed by MAXIMUS: for new "Sail Ho" and DirectSail-Mod <--
	Set_inDialog_Attributes();
	// KK ProcessDialogEvent();

	SetEventHandler("DialogEvent","ProcessDialogText",0);
	//SetEventHandler("DialogCancel","DialogExit",0);	

	ProcessDialogText(); // KK
	Event(EVENT_DIALOG_START,"");
	ResetTimeToNormal();//MAXIMUS
}

//Закончить диалог
void DialogExit()
{
	//Ссылка на главного персонажа
	ref mainChr = GetMainCharacter(); // KK
	//Если диалога уже не ведётся, выйдем
	if(dialogRun == false) return;
	DelEventHandler("PlayDialogGreeting", "DialogPlayGreeting"); // KK
	DelEventHandler("DialogEvent","ProcessDialogText"); // KK
	//Освобождаем ресурсы
	DeleteClass(&Dialog);
	SendMessage(&ILogAndActions,"ll",LI_SET_VISIBLE,true);//MAIMUS
	CheckCharacterAction();//MAIMUS
	if(FullDialogPath!="") UnloadSegment(FullDialogPath);
	if(PathDlgLngExtn!="") UnloadSegment(PathDlgLngExtn);
	if(dialogSelf == false)
	{
		//Отметим, что персонажи освободились от диалога
		LAi_Character_EndDialog(mainChr, CharacterRef);
		LAi_Character_EndDialog(CharacterRef, mainChr);
		SendMessage(mainChr, "lsl", MSG_CHARACTER_EX_MSG, "InDialog", 0);
		SendMessage(CharacterRef, "lsl", MSG_CHARACTER_EX_MSG, "InDialog", 0);
		DeleteAttribute(mainChr, "IsInDialog");	// LDH - Used for problems with corpses disappearing.
	}else{
		LAi_Character_EndDialog(CharacterRef, CharacterRef);
		SendMessage(CharacterRef, "lsl", MSG_CHARACTER_EX_MSG, "InDialog", 0);
	}
	DeleteAttribute(GetMainCharacter(), "forcedlg"); // NK 05-07-13 to allow for dlg in fight mode
	dialogRun = false;
	//Сообщим об окончании диалога
	PostEvent(EVENT_DIALOG_EXIT, 1, "l", sti(CharacterRef.index));
	// PB: No fights during dialog -->
	if(FightDisable == false) {LAi_LocationFightDisable(&Locations[FindLocation(mainChr.location)], false);}
	// if FightDisable has not been set true, set LocationFightDisable off again (resets original LocationFightDisable setting from before the dialog)
	// PB: No fights during dialog <--
	locCameraFollow(); //a simple virtual sailor
	ClearScreenShoter();//MAXIMUS: used for QuickSave
}

//Это событие приходит от Player
void StartDialogWithMainCharacter()
{
	// NK disable this to allow dlg in boarding 05-07-12 - if(LAi_IsBoardingProcess()) return;
	if(dialogDisable) return;
	//С кем хотим говорить
	int person = GetEventData();
	//Сими с собой не беседуем
	if(person == GetMainCharacterIndex()) return;
	//С непрогруженными персонажами не беседуем
	if(!IsEntity(&Characters[person])) return;
	//Начинаем диалог
	DialogMain(&Characters[person]);	
	//Trace("Dialog: start dialog " + person + " whith main character");
}

bool LoadDialogFiles(string dialogFile)
{
	// Выбор директории с языковыми файлами
	string sDialogDir = GetStorylineDir(FindCurrentStoryline()) + "dialogs\"; // KK
	FullDialogPath = sDialogDir + dialogFile; // KK
	string sLanguageDir = LanguageGetLanguage(); // KK
	//Путь до текста диалога
	int iTmp = strlen(dialogFile);
	if(iTmp<3)
	{
		Trace("Dialog: Missing dialog file: " + dialogFile);
		return false;
	}
// KK -->
	if (FindFile("PROGRAM\\" + sDialogDir, "*.c", dialogFile) == "") {
		sDialogDir = "dialogs\";
		FullDialogPath = sDialogDir + dialogFile;
	}

	string DialogTextFile = strcut(dialogFile,0,iTmp-2) + "h";
	PathDlgLngExtn = sDialogDir + sLanguageDir + "\" + DialogTextFile;

	bool retVal = false;
	if (FindFile("PROGRAM\" + sDialogDir + sLanguageDir, "*.h", DialogTextFile) == "") {
		//Trace("LoadDialogFiles: Missing PROGRAM\" + sLanguageDir + "\" + DialogTextFile + " language file - loading ENGLISH.");
		sLanguageDir = "dialogs\ENGLISH";
		PathDlgLngExtn = sLanguageDir + "\" + DialogTextFile;
		if (FindFile("PROGRAM\" + sLanguageDir, "*.h", DialogTextFile)) {
			PathDlgLngExtn = "";
			return false;
		}
		retVal = LoadSegment(PathDlgLngExtn);
	} else {
		retVal = LoadSegment(PathDlgLngExtn);
	}
// <-- KK

	if( !LoadSegment(FullDialogPath) )
	{
		Trace("Dialog: Missing dialog file: " + FullDialogPath);
		retVal = false;
		UnloadSegment(PathDlgLngExtn);
	} else {
		if(!retVal) {
			retVal = true;
			PathDlgLngExtn = "";
		}
	}

	return retVal;
}

// KK -->
string GetHostileNations(int iNation)
{
	int nat = 0;
	int ellen = 0;
	string elist = "";
	string st = "";
	for (nat = 0; nat < MAX_NATIONS; nat++) {
		if (nat != PIRATE && GetNationRelation(iNation, nat) == RELATION_ENEMY) elist += nat;
	}
	if (elist != "") {
		ellen = strlen(elist);
		st = XI_ConvertString(GetNationNameByType(sti(strcut(elist, 0, 0))));
		for (nat = 1; nat < ellen - 1; nat++)
			st += ", " + XI_ConvertString(GetNationNameByType(sti(strcut(elist, nat, nat))));
		if (ellen > 1) st += " " + XI_ConvertString("and") + " " + XI_ConvertString(GetNationNameByType(sti(strcut(elist, ellen - 1, ellen - 1))));
	}
	return st;
}

int LotHostileNation(int iNation)
{
	int nat;
	nat = Rand(MAX_NATIONS - 1);
	while (GetNationRelation(iNation, nat) != RELATION_ENEMY) {
		nat = Rand(MAX_NATIONS - 1);
	}
	return nat;
}

string RouteForGood(int our_town_idx, int good)
{
	if (our_town_idx < 0 || good < 0) return "nowhere";
	float dist = 0.0;
	int curtown = -1;
	for (int n = 0; n < TOWNS_QUANTITY; n++) {
		if (n == our_town_idx) continue;
		if (Towns[n].id == "Smugglers Lair") continue;
		if (GetTownStoreIndex(Towns[n].id) == -1) continue;
		if (!CheckAttribute(Islands[FindIsland(Towns[n].island)], "Trade.Import")) continue;
		aref import;
		makearef(import, Islands[FindIsland(Towns[n].island)].Trade.Import);
		int i = 1;
		string id = "id" + i;
		while (CheckAttribute(import, id)) {
			if (sti(import.(id)) == good) {
				float cdist = GetTownDistance2D(GetTownByIndex(n), GetTownByIndex(our_town_idx));
				if (cdist < dist || dist == 0.) {
					dist = cdist;
					curtown = n;
				}
				break;
			}
			i++;
			id = "id" + i;
		}
	}
	if (curtown >= 0) return XI_ConvertString(FindTownName(Towns[curtown].id));
	return "nowhere";
}

void FindProfitableRoute(ref good1, ref town1, ref good2, ref town2)
{
	good1 = "";
	town1 = "";
	good2 = "";
	town2 = "";
	string our_town_id = GetCurrentTownID();
	if (!TownExist(our_town_id)) return;
	int our_town_idx = GetTownIndex(our_town_id);
	if (our_town_idx == -1) return;
	if (!CheckAttribute(Islands[FindIsland(Towns[our_town_idx].island)], "Trade.Export")) return;
	aref export;
	makearef(export, Islands[FindIsland(Towns[our_town_idx].island)].Trade.Export);
	int n = 0;
	string id = "id" + (n + 1);
	while (CheckAttribute(export, id)) {
		n++;
		id = "id" + (n + 1);
	}
	n--;
	int idx1 = Rand(n) + 1;
	int idx2 = idx1;
	while (idx2 == idx1) idx2 = Rand(n) + 1;
	id = "id" + idx1;
	int good = sti(export.(id));
	good1 = XI_ConvertString(Goods[good].Name);
	town1 = RouteForGood(our_town_idx, good);
	id = "id" + idx2;
	good = sti(export.(id));
	good2 = XI_ConvertString(Goods[good].Name);
	town2 = RouteForGood(our_town_idx, good);
}

void ProcessDialogText()
{
	ProcessDialogEvent();

	Dialog.Text = PreprocessText(Dialog.Text);
	aref links; makearef(links, Dialog.Links);
	int lnum = GetAttributesNum(links);
	for (int l = 0; l < lnum; l++) {
		string curlink = GetAttributeName(GetAttributeN(links, l));
		Dialog.Links.(curlink) = PreprocessText(Dialog.Links.(curlink));
	}
	Preprocessor_Clear(false);
}
// <-- KK
