FOnline
Взаимодействие между персонажами

Взаимодействие между НПЦ и другими персонажами

Для взаимодействия между персонажами используется метод – Critter::SendMessage. В параметрах функции необходимо указать:

Когда персонаж принимает сообщение, у него происходит событие CRITTER_EVENT_MESSAGE. При инициализации персонажа необходимо задать функцию, срабатываемую при данном событии, в ней необходимо выполнять ответные действия. Сообщение принимается в момент его отправки.

При организации сложной ситуации, в которой участвует множество персонажей и у каждого есть своя роль, используйте поле Critter::NpcRole.

Пример написания скрипта с использованием функции Critter::SendMessage. В этом примере организован диалог между двумя НПЦ, который будет происходить каждый день ровно в 12 часов.

// Один скрипт на обоих НПЦ, в принципе, можно посадить на него и большее количество НПЦ
#include "_macros.fos"
#define NUM_OF_MSG (300) // Номер сообщения
#define ROLE_NPCA (150)
#define ROLE_NPCB (151)
// StatBase[ST_VAR0] - Индекс фразы
// StatBase[ST_VAR1] - Callback для подтверждения готовности к разговору
// Фразы для обоих НПЦ
// В идеале, это должны были быть массивы номеров фраз, которые находятся в файле с текстами
string[] DialogsForNpcA = {"О! Привет.","Как дела?","А чего так?","Уууу...",
"Да уж, бывает...", "Ну ладно, пойду я."};
string[] DialogsForNpcB = {"Привет.","Ой, плохи мои дела. Совсем плохи.",
"Да опять в казино все свои деньги продул.","","", "Пока."};
bool DialogsProcess = false;
void _CritterAInit(Critter& npc, bool firstTime)
{
npc.StatBase[ST_NPC_ROLE] = ROLE_NPCA;
npc.SetEvent(CRITTER_EVENT_MESSAGE, "_NpcOnMessage");
// Начинаем через минуту после инициализации
CreateTimeEvent(__FullSecond+REAL_MINUTE(1), "e_StartDialog", npc, false);
}
void _CritterBInit(Critter& npc, bool firstTime)
{
npc.StatBase[ST_NPC_ROLE] = ROLE_NPCB;
npc.SetEvent(CRITTER_EVENT_MESSAGE, "_NpcOnMessage");
}
void _NpcOnMessage(Critter& npcB, Critter& npcA, int num, int val)
{
// Если принятое сообщение не относится к диалогу, то завершаем выполнение функции
if(num != NUM_OF_MSG) return;
// Проверяем, совпадают ли роли обоих НПЦ
if(npcA.StatBase[ST_NPC_ROLE] != ROLE_NPCA || npcB.StatBase[ST_NPC_ROLE] != ROLE_NPCB) return;
// Проверяем готов ли NPC "B" произнести фразу
if(not npcB.IsLife() || not npcB.IsNoPlanes()) return;
// Начинаем вести беседу
npcA.StatBase[ST_VAR1] = 0; // Callback НПЦ_A что бы понял что все нормально
npcA.StatBase[ST_VAR0] = 0;
npcB.StatBase[ST_VAR0] = 0;
DialogsProcess = true;
// Создаем события в которых и будем общаться
CreateTimeEvent(__FullSecond+REAL_SECOND(2), "e_SayDialog", npcA, false);
CreateTimeEvent(__FullSecond+REAL_SECOND(4), "e_SayDialog", npcB, false);
}
uint e_StartDialog(uint[]@ values)
{
Critter@ npcA = GetCritter(values[0]);
if(not valid(npcA)) return 0; // НПЦ больше не существует, удаляем событие
// Если НПЦ_А не готов к началу диалога, то откладываем событие на 20 игровых минут
if(not npcA.IsLife() || not npcA.IsNoPlanes()) return 20*60;
// Перед началом диалога проверяем, готов ли собеседник к диалогу
npcA.StatBase[ST_VAR1] = -1;
npcA.SendMessage(NUM_OF_MSG, 0, MESSAGE_TO_I_SEE);
// Если после отправки сообщения НПЦ_B не поменял значение переменной StatBase[ST_VAR1],
// то это значит что он не готов к диалогу
if(npcA.StatBase[ST_VAR1] == -1) return 20*60;
// Переносим событие на следующие 12 часов
return 12*60*60;
}
uint e_SayDialog(uint[]@ values)
{
// Смотрим не прекратился ли диалог досрочно
Critter@ npc = GetCritter(values[0]);
if(not valid(npc)) return 0;
if(not DialogsProcess) return 0;
// Проверим, не появились ли новые планы у НПЦ
if(not npc.IsNoPlanes())
{
DialogsProcess=false;
return 0;
}
// Выберем нужные строки диалога
string[]@ dialogs;
if(npc.StatBase[ST_NPC_ROLE] == ROLE_NPCA) @dialogs = @DialogsForNpcA;
else if(npc.StatBase[ST_NPC_ROLE] == ROLE_NPCB) @dialogs = @DialogsForNpcB;
else return 0;
// Проверим до и после на предмет окончания диалогов, между этим говорим
if(uint(npc.StatBase[ST_VAR0]) >= dialogs.length()) return 0;
if(dialogs[npc.StatBase[ST_VAR0]] != "") npc.Say(SAY_NORM_ON_HEAD, dialogs[npc.StatBase[ST_VAR0]]);
npc.StatBase[ST_VAR0]++;
if(uint(npc.StatBase[ST_VAR0]) >= dialogs.length()) return 0;
// Следующая фраза произойдет через 4 секунды (через 2 секунды будет говорить оппонент)
return REAL_SECOND(4);
}

При этом, диалог между НПЦ будет выглядеть так:
A: О! Привет.
B: Привет.
A: Как дела?
B: Ой, плохи мои дела. Совсем плохи.
A: А чего так?
B: Да опять в казино все свои деньги продул.
A: Уууу...
A: Да уж, бывает...
A: Ну ладно, пойду я.
B: Пока.

Диалог будет происходить при условии, что:

Если во время начала диалога оба NPC будут мертвы или будут выполнять запланированные действия, то начало диалога будет отложено на 20 игровых минут.

Converted from CHM to HTML with chm2web Pro 2.85 (unicode)