

//Объект, описывающий отнощение одной группы к другой
object LAi_grp_relations;
float LAi_grp_playeralarm = 0.0; // KK
bool LAi_grp_alarmactive = false;

//------------------------------------------------------------------------------------------
//Инициализация
//------------------------------------------------------------------------------------------

//Инициализация
bool LAi_group_Init()
{
	//Пока всё спокойно
	LAi_grp_playeralarm = 0.0;
	LAi_grp_alarmactive = false;
	//Создаём объект групп и загружаем параметры
	if(CreateEntity(&LAi_grp_relations, "CharactersGroups") == 0) return false;
	//Инициализация стандартной группы персонажей
	LAi_group_Register(LAI_DEFAULT_GROUP);
	//Группа игрока
	LAi_group_Register(LAI_GROUP_PLAYER);
	LAi_group_SetLookRadius(LAI_GROUP_PLAYER, LAI_GROUP_PLA_LOOK);
	LAi_group_SetHearRadius(LAI_GROUP_PLAYER, LAI_GROUP_PLA_HEAR);
	LAi_group_SetSayRadius(LAI_GROUP_PLAYER, LAI_GROUP_PLA_SAY);
	LAi_group_SetPriority(LAI_GROUP_PLAYER, LAI_GROUP_PPLAYER);
	//Группа охраников
	LAi_group_Register(LAI_GROUP_GUARDS);
	LAi_group_SetLookRadius(LAI_GROUP_GUARDS, LAI_GROUP_GRD_LOOK);
	LAi_group_SetHearRadius(LAI_GROUP_GUARDS, LAI_GROUP_GRD_HEAR);
	LAi_group_SetSayRadius(LAI_GROUP_GUARDS, LAI_GROUP_GRD_SAY);
	LAi_group_SetPriority(LAI_GROUP_PLAYER, LAI_GROUP_PGUARDS);
	// KK: Patrol
	LAi_group_Register(LAI_GROUP_PATROL);
	LAi_group_SetLookRadius(LAI_GROUP_PATROL, LAI_GROUP_PTR_LOOK);
	LAi_group_SetHearRadius(LAI_GROUP_PATROL, LAI_GROUP_PTR_HEAR);
	LAi_group_SetSayRadius(LAI_GROUP_PATROL, LAI_GROUP_PTR_SAY);
	LAi_group_SetPriority(LAI_GROUP_PLAYER, LAI_GROUP_PGUARDS);
	//Группа актёров
	LAi_group_Register(LAI_GROUP_ACTOR);
	LAi_group_SetLookRadius(LAI_GROUP_ACTOR, LAI_GROUP_ACT_LOOK);
	LAi_group_SetHearRadius(LAI_GROUP_ACTOR, LAI_GROUP_ACT_HEAR);
	LAi_group_SetSayRadius(LAI_GROUP_ACTOR, LAI_GROUP_ACT_SAY);
	LAi_group_SetPriority(LAI_GROUP_PLAYER, LAI_GROUP_PDEFAULT);
	//Группа губернатора
	LAi_group_Register(LAI_GROUP_HUBER);
	LAi_group_SetLookRadius(LAI_GROUP_HUBER, LAI_GROUP_HUB_LOOK);
	LAi_group_SetHearRadius(LAI_GROUP_HUBER, LAI_GROUP_HUB_HEAR);
	LAi_group_SetSayRadius(LAI_GROUP_HUBER, LAI_GROUP_HUB_SAY);
	LAi_group_SetPriority(LAI_GROUP_PLAYER, LAI_GROUP_PCITIZENS);
	//Группа монстров
	LAi_group_Register(LAI_GROUP_MONSTERS);
	LAi_group_SetRelation(LAI_GROUP_MONSTERS, LAI_GROUP_PLAYER, LAI_GROUP_ENEMY);
	LAi_group_SetLookRadius(LAI_GROUP_MONSTERS, LAI_GROUP_MNS_LOOK);
	LAi_group_SetHearRadius(LAI_GROUP_MONSTERS, LAI_GROUP_MNS_HEAR);
	LAi_group_SetSayRadius(LAI_GROUP_MONSTERS, LAI_GROUP_MNS_SAY);
	LAi_group_SetPriority(LAI_GROUP_PLAYER, 0);
	//Отношения	
	//guards
	LAi_group_SetRelation(LAI_GROUP_GUARDS, LAI_DEFAULT_GROUP, LAI_GROUP_FRIEND);
	LAi_group_SetAlarmReaction(LAI_GROUP_GUARDS, LAI_DEFAULT_GROUP, LAI_GROUP_FRIEND, LAI_GROUP_FRIEND);
	LAi_group_SetRelation(LAI_GROUP_GUARDS, LAI_GROUP_PATROL, LAI_GROUP_FRIEND); // KK
	LAi_group_SetAlarmReaction(LAI_GROUP_GUARDS, LAI_GROUP_PATROL, LAI_GROUP_FRIEND, LAI_GROUP_FRIEND); // KK
	LAi_group_SetRelation(LAI_GROUP_GUARDS, LAI_GROUP_HUBER, LAI_GROUP_FRIEND);
	LAi_group_SetAlarmReaction(LAI_GROUP_GUARDS, LAI_GROUP_HUBER, LAI_GROUP_FRIEND, LAI_GROUP_FRIEND);
	//huber
	LAi_group_SetRelation(LAI_GROUP_HUBER, LAI_DEFAULT_GROUP, LAI_GROUP_FRIEND);
	LAi_group_SetAlarmReaction(LAI_GROUP_HUBER, LAI_DEFAULT_GROUP, LAI_GROUP_FRIEND, LAI_GROUP_FRIEND);
	//actor
	LAi_group_SetRelation(LAI_GROUP_ACTOR, LAI_DEFAULT_GROUP, LAI_GROUP_NEITRAL);
	LAi_group_SetRelation(LAI_GROUP_ACTOR, LAI_GROUP_PLAYER, LAI_GROUP_NEITRAL);
	LAi_group_SetRelation(LAI_GROUP_ACTOR, LAI_GROUP_HUBER, LAI_GROUP_NEITRAL);
	LAi_group_SetAlarmReaction(LAI_GROUP_ACTOR, LAI_DEFAULT_GROUP, LAI_GROUP_NEITRAL, LAI_GROUP_NEITRAL);
	LAi_group_SetAlarmReaction(LAI_GROUP_ACTOR, LAI_GROUP_GUARDS, LAI_GROUP_NEITRAL, LAI_GROUP_NEITRAL);
	LAi_group_SetAlarmReaction(LAI_GROUP_ACTOR, LAI_GROUP_PATROL, LAI_GROUP_NEITRAL, LAI_GROUP_NEITRAL); // KK
	LAi_group_SetAlarmReaction(LAI_GROUP_ACTOR, LAI_GROUP_PLAYER, LAI_GROUP_NEITRAL, LAI_GROUP_NEITRAL);
	LAi_group_SetAlarmReaction(LAI_GROUP_ACTOR, LAI_GROUP_HUBER, LAI_GROUP_NEITRAL, LAI_GROUP_NEITRAL);
	//player
	LAi_group_SetRelation(LAI_GROUP_PLAYER, LAI_DEFAULT_GROUP, LAI_GROUP_NEITRAL);
	LAi_group_SetAlarmReaction(LAI_GROUP_PLAYER, LAI_DEFAULT_GROUP, LAI_GROUP_ENEMY, LAI_GROUP_NEITRAL);
	LAi_group_SetAlarmReaction(LAI_GROUP_PLAYER, LAI_GROUP_GUARDS, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);
	LAi_group_SetAlarmReaction(LAI_GROUP_PLAYER, LAI_GROUP_PATROL, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND); // KK
	LAi_group_SetAlarmReaction(LAI_GROUP_PLAYER, LAI_GROUP_HUBER, LAI_GROUP_ENEMY, LAI_GROUP_NEITRAL);
	//Востановим отношения
	SendMessage(&LAi_grp_relations, "s", "LoadDataRelations");
	//Учтём прошедшее время
	if(LAi_restoreStates)
	{
		SendMessage(&LAi_grp_relations, "s", "RestoreStates");
	}
	return true;
}

//Освобождение ресурсов
void LAi_group_Release()
{
	DeleteAttribute(&LAi_grp_relations, "quests");
	LAi_group_ClearAllTargets();
	SendMessage(&LAi_grp_relations, "s", "SaveData");
	//Удаляем объект групп
	DeleteClass(&LAi_grp_relations);
}

void LAi_group_SaveInfo()
{
	SendMessage(&LAi_grp_relations, "s", "SaveData");
}

//------------------------------------------------------------------------------------------
//Регистрация новой группы, установка общих параметров
//------------------------------------------------------------------------------------------

//Регистрация новой группы
void LAi_group_Register(string groupName)
{
	SendMessage(&LAi_grp_relations, "ss", "RegistryGroup", groupName);
	LAi_group_SetLookRadius(groupName, LAI_GROUP_DEF_LOOK);
	LAi_group_SetHearRadius(groupName, LAI_GROUP_DEF_HEAR);
	LAi_group_SetSayRadius(groupName, LAI_GROUP_DEF_SAY);
}

//Установить для группы радиус видимости
void LAi_group_SetLookRadius(string groupName, float radius)
{
	SendMessage(&LAi_grp_relations, "ssf", "SetGroupLook", groupName, radius);
}

//Установить для группы радиус слышимости
void LAi_group_SetHearRadius(string groupName, float radius)
{
	SendMessage(&LAi_grp_relations, "ssf", "SetGroupHear", groupName, radius);
}

//Установить для группы радиус сообщения
void LAi_group_SetSayRadius(string groupName, float radius)
{
	SendMessage(&LAi_grp_relations, "ssf", "SetGroupSay", groupName, radius);
}

//Установить для группы приоритет
void LAi_group_SetPriority(string groupName, int priority)
{
	SendMessage(&LAi_grp_relations, "ssl", "SetGroupPriority", groupName, priority);
}

//Установить уровень тревоги 0..1
void LAi_group_SetAlarm(string group1, string group2, float level)
{
	SendMessage(&LAi_grp_relations, "sssf", "SetAlarm", group1, group2, level);
}

//Установить скорость убывания тревоги ед/сек
void LAi_group_SetAlarmDown(string group1, string group2, float down)
{
	SendMessage(&LAi_grp_relations, "sssf", "SetAlarmDown", group1, group2, down);
}


//------------------------------------------------------------------------------------------
//Перемещение персонажа в группы
//------------------------------------------------------------------------------------------

//Переместить персонажа в новую группу
void LAi_group_MoveCharacter(ref chr, string groupName)
{
	if (CheckAttribute(chr, "chr_ai.group")) chr.old.chr_ai.group = chr.chr_ai.group; // KK
	chr.chr_ai.group = groupName;
	SendMessage(&LAi_grp_relations, "sis", "MoveChr", chr, groupName);
}

//------------------------------------------------------------------------------------------
//Отношения групп
//------------------------------------------------------------------------------------------

//Установить отношения между группами
void LAi_group_SetRelation(string group1, string group2, string curRelation)
{
	SendMessage(&LAi_grp_relations, "ssss", "SetRelation", group1, group2, curRelation);
}

//Установить отношения между группами при активации тревоги и после
void LAi_group_SetAlarmReaction(string group1, string group2, string actRelation, string relRelation)
{
	SendMessage(&LAi_grp_relations, "sssss", "SetAlarmReaction", group1, group2, actRelation, relRelation);
}

//Натравить друг на друга 2 группы
void LAi_group_FightGroups(string group1, string group2, bool asignWarriarType)
{
	LAi_group_FightGroupsEx(group1, group2, asignWarriarType, -1, -1, true, false);
}

//Натравить друг на друга 2 группы, с возможной установкой командиров
void LAi_group_FightGroupsEx(string group1, string group2, bool asignWarriarType, int commander1, int commander2, bool isStay, bool isDialog)
{
	//Укажем что обновление надо провести немедленно
	SendMessage(&LAi_grp_relations, "s", "ResetWaveTime");
	//Установим войнов типы персонажем
	if(asignWarriarType)
	{
		ref mchr = GetMainCharacter();
		for(int i = 0; i < LAi_numloginedcharacters; i++)
		{
			int idx = LAi_loginedcharacters[i];
			if(idx >= 0)
			{
				//Пропустим главного персонажа или офицера
				if(idx == GetMainCharacterIndex()) continue;
				for(int j = 1; j < 4; j++)
				{
					if(GetOfficersIndex(mchr, j) == idx) break;
				}
				if(j < 4) continue;
				//Проверяем попадание персонажа в группу
				ref chr = &Characters[idx];
				if(CheckAttribute(chr, "chr_ai.group"))
				{
					bool selected = false;
					bool isOne;
					if(chr.chr_ai.group == group1)
					{
						selected = true;
						isOne = true;
					}else{
						if(chr.chr_ai.group == group2)
						{
							selected = true;
							isOne = false;
						}
					}
					// ccc Building Kit Sep 05; next line checks that stunned & buildings don't join fights
					if(selected && chr.chr_ai.type != LAI_TYPE_BUILDING && chr.chr_ai.type != LAI_TYPE_STUNNED)
					{
						LAi_SetWarriorTypeNoGroup(chr);
						LAi_warrior_SetStay(chr, isStay);
						LAi_warrior_DialogEnable(chr, isDialog);
						if(isOne)
						{
							if(commander1 >= 0)
							{
								LAi_warrior_SetCommander(chr, &Characters[commander1]);
							}
							LAi_group_MoveCharacter(chr, group1);
						}else{
							if(commander2 >= 0)
							{
								LAi_warrior_SetCommander(chr, &Characters[commander2]);
							}
							LAi_group_MoveCharacter(chr, group2);
						}
					}
				}
			}
		}
	}
	//Настроим группы
	LAi_group_SetRelation(group1, group2, LAI_GROUP_ENEMY);
	LAi_group_SetHearRadius(group1, 40000000.0);
	LAi_group_SetSayRadius(group1, 40000000.0);
	LAi_group_SetHearRadius(group2, 40000000.0);	
	LAi_group_SetSayRadius(group2, 40000000.0);
}

//------------------------------------------------------------------------------------------
//Цели
//------------------------------------------------------------------------------------------

//Выбрать цель для данного персонажа
int LAi_group_GetTarget(aref chr)
{
	int index = -1;
	if(SendMessage(&LAi_grp_relations, "sie", "GetTrg", chr, &index) == 0)
	{
		index = -1;
	}
	return index;
}

//Проверить цель
bool LAi_group_ValidateTarget(aref chr, aref trg)
{	
	return (SendMessage(&LAi_grp_relations, "sii", "VldTrg", chr, trg) != 0);
}

//Враг ли данный персонаж
bool LAi_group_IsEnemy(aref chr, aref trg)
{
	return (SendMessage(&LAi_grp_relations, "sii", "IsEnemy", chr, trg) != 0);
}

//------------------------------------------------------------------------------------------
//Реакция на атаку
//------------------------------------------------------------------------------------------

//Реакция групп на атаку attack->hit
bool LAi_group_Attack(aref attack, aref hit)
{
	if(attack.chr_ai.group == hit.chr_ai.group)
	{
		//Своих игнорируем
		return false;
	}
	//Натравим друг на друга
	SendMessage(&LAi_grp_relations, "sss", "Attack", attack.chr_ai.group, hit.chr_ai.group);
	//Добавляем врага
	SendMessage(&LAi_grp_relations, "siif", "AddTarget", hit, attack, 10.0 + rand(10));
	return true;
}

//Обновить список врагов персонажа
void LAi_group_UpdateTargets(aref chr)
{
	SendMessage(&LAi_grp_relations, "si", "UpdChrTrg", chr);
}

//------------------------------------------------------------------------------------------
//Утилитные
//------------------------------------------------------------------------------------------

//Удалить все цели из списков
void LAi_group_ClearAllTargets()
{
	SendMessage(&LAi_grp_relations, "s", "ClearAllTargets");
}

//Получить значение тревоги для игрока
float LAi_group_GetPlayerAlarm()
{
	return LAi_grp_playeralarm;
}

//Активна ли тревога для игрока
bool LAi_group_IsActivePlayerAlarm()
{
	if(bSeaActive && bDisableMapEnter && !bQuestDisableMapEnter && !Whr_IsStorm() && !LAi_IsBoardingProcess() && !ownDeckStarted()) return true;//MAXIMUS
	return LAi_grp_alarmactive;
}

//Установить квест на убивание группы
void LAi_group_SetCheck(string groupName, string quest)
{
	//Найдём свободное поле
	aref quests;
	makearef(quests, LAi_grp_relations.quests);
	int num = GetAttributesNum(quests);
	string atr = "q";
	for(int i = 0; i < num + 10; i++)
	{
		atr = "q" + i;
		if(!CheckAttribute(quests, atr)) break;
	}
	//Заполним
	quests.(atr).group = groupName;
	if(quest!="") quests.(atr).quest = quest;//MAXIMUS
}

//Установить событие на убивание группы
void LAi_group_SetCheckEvent(string groupName)
{
	//Найдём свободное поле
	aref quests;
	makearef(quests, LAi_grp_relations.quests);
	int num = GetAttributesNum(quests);
	string atr = "q";
	for(int i = 0; i < num + 10; i++)
	{
		atr = "q" + i;
		if(!CheckAttribute(quests, atr)) break;
	}
	//Заполним
	quests.(atr).group = groupName;
}


//Убрать квест на убивание группы
void LAi_group_RemoveCheck(string groupName)
{
	//Найдём свободное поле
	aref quests;
	makearef(quests, LAi_grp_relations.quests);
	int num = GetAttributesNum(quests);
	for(int i = 0; i < num; i++)
	{
		aref atr = GetAttributeN(&quests, i);
		if(atr.group == groupName)
		{
			//Удалим
			DeleteAttribute(&quests, GetAttributeName(GetAttributeN(&quests, i)));
			i = -1;
			num = GetAttributesNum(&quests);
		}		
	}
}

//Проверить квест на убивание группы
void LAi_group_CheckGroupQuest(aref chr)
{
	//Получим ветку с квестами
	aref quests; makearef(quests, LAi_grp_relations.quests);
	if(GetAttributesNum(&quests)<=0) return;

	//Проверим остальных персонажей в данной группе
	if(!CheckAttribute(chr, "chr_ai.group"))
	{
		Trace("CheckGroupQuest: Character <" + chr.id + "> can't have field chr_ai.group");
		return;
	}

	int i;
	int num = GetAttributesNum(&quests);
	string group = chr.chr_ai.group;
	for(i=0; i<LAi_numloginedcharacters; i++)
	{
		int idx = LAi_loginedcharacters[i];
		if(idx<0) continue;
		if(idx==sti(chr.index)) continue;

		if(!CheckAttribute(&Characters[idx], "chr_ai.group")) Characters[idx].chr_ai.group = LAI_DEFAULT_GROUP;
		if(group==Characters[idx].chr_ai.group)//Есть ещё живые в этой группе
		{
			if(!CheckAttribute(&Characters[idx],"corpse")) return; // NK handling for corpses 05-07-19. Not really needed, because when we kill we set to corpse group. But this is a template for disarm...
		}
	}

	//Последний из магикан...
	for(i = 0; i < num; i++)
	{
		aref atr = GetAttributeN(&quests, i);
		if(atr.group!=group) continue;

		//Нашли квест, запустим его на исполнение
		if(CheckAttribute(atr, "quest")) LAi_QuestDelay(atr.quest, 0.000001);
// KK -->
		/*else
		{
			if (!CheckAttribute(GetMainCharacter(), "groupkill"))		// LDH - added so that this this event is posted only once
			{
					characters[GetMainCharacterIndex()].groupkill = true;
					PostEvent("LAi_event_GroupKill", 1, "s", group);
			}
		}*/
// <-- KK
		//Теперь удалим
		DeleteAttribute(&quests, GetAttributeName(GetAttributeN(&quests, i)));
		i = -1;
		num = GetAttributesNum(&quests);
	}
}


//------------------------------------------------------------------------------------------
//Ответная реакция на запросы
//------------------------------------------------------------------------------------------

//Обновление аларма, вызывается на каждом кадре
#event_handler("CharacterGroup_UpdateAlarm", "LAi_group_UpdateAlarm");
void LAi_group_UpdateAlarm()
{
	ref mchr = GetMainCharacter(); // KK
	LAi_grp_playeralarm = GetEventData();
	LAi_grp_alarmactive = GetEventData();
	Sound_OnAlarm(LAi_grp_alarmactive);

	if(CheckAttribute(GetMainCharacter(), "boardingReload")) return;
	if(LAi_grp_playeralarm || LAi_grp_alarmactive) return;
	if(LAi_boarding_process && !bMutinyDeckStarted) { PostEvent("LAi_event_boarding_EnableReload", 1000); return; } // KK
	if(!LAi_boarding_process && bMutinyDeckStarted) { PostEvent("LAi_event_boarding_EnableReload", 1000); return; } // KK
}
