1. Уважаемые гости и новички, приветствуем Вас на нашем форуме
    Здесь вы можете найти ответы практически на все свои вопросы о серии игр «Готика» (в том числе различных модах на нее), «Ведьмак», «Ризен», «Древние свитки», «Эра дракона» и о многих других играх. Можете также узнать свежие новости о разработке новых проектов, сыграть в увлекательные ФРПГ, восхититься творчеством наших форумчан, либо самим показать, что вы умеете. Ну и наконец, можете обсудить общие увлечения или просто весело пообщаться с посетителями «Таверны».

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!
    Скрыть объявление
  2. Форум аддона "Возвращение" 2.0:
    — Обсудить игру, почитать о прохождениях и/или разрешить свои вопросы по игре вы можете в одной из тем одноименного форума. Посетить...
    — Прочитать историю изменения и/или скачать последнюю версию аддона "Возвращение", вы можете на страницах наших ресурсов. Скачать...
    Скрыть объявление

Важно Уроки скриптологии by VAM

Тема в разделе "Скриптинг", создана пользователем MEG@VOLT, 8 дек 2014.

Статус темы:
Закрыта.
  1. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Тема первая: Типы переменных.

    В скриптах используется всего несколько типов переменных:
    void - пустой тип
    int - целое число
    float - число с плавающей точкой
    string - строка текста
    class - структура с внутренними типами и функциями
    prototype - обычно инициализация класса, но возможно и другое использование
    instance - пока сказать нечего.
    вот, кажется, и все типы.
     
    Последнее редактирование: 10 дек 2014
  2. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Тема вторая: Операции над данными.

    Существует несколько типов операций: арифметические, присваивания, отношения, логические, побитовые, над массивами, операции с членами классов.
    В основном, все операции применимы только к простым типам, за исключением типа string.

    1. Арифметические операции.

    + - простое сложение
    - - простое вычитание
    * - простое умножение
    / - простое деление (результат целая часть)
    % - простое деление (результат остаток)

    2. Операции присваивания.

    = - простое присваивание
    += - сложение с приваиванием
    -= - вычитание с присваиванием
    *= - умножение с присваиванием
    /= - деление с приваиванием (целая часть)

    3. Операции отношения.

    < - истина, если меньше
    > - истина, если больше
    <=- истина, если меньше или равно
    >= - истина, если больше или равно
    == - истина, если равно
    != - истина, если не равно

    4. Логические операции.

    ! - истина, если выражение ложно
    || - истина, если истинно значение первого или второго операнда
    && - истина, если истинно значение первого и второго операнда
    Операция ! является только префиксной операцией (пример !операнд)

    5. Побитовые операции.

    ~ - инверсия операнда (префиксная операция)
    >> - логический сдвиг вправо операнда1 на величину операнда2
    << - логический сдвиг влево операнда1 на величину операнда2
    | - побитовая операция ИЛИ
    & - побитовая операция И
    ^ - побитовая операция исключающее ИЛИ

    6. Операции над массивами.

    [] - получение или задание элемента массива по индексу (при инициализации массива задание его размерности)

    7. Операции с членами классов.

    . - обращение к элементу класса
    Пример: аа.бб , где аа - имя класса, бб - имя переменной класса

    8. Другие операции.

    () - вызов функции с аргументами
     
    Последнее редактирование: 10 дек 2014
  3. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Тема третья: Операторы и идентификаторы типа.

    1. Операторы.

    Операторов в скриптах реализовано очень мало:
    { выражение (я) };- оператор блок, после закрывающей фигурной скобки обязательна точка с запятой.
    Блоки допускают вложения друг в друга.
    if (условие(я)) блок - оператор условного выполнения. Если условие истина, то выполняется блок, исли условие ложно, то блок пропускается. Возможна и другая реализация:
    if (условие(я)) блок else блок - если условие истина, выполняется только блок if, если условие ложь, то выполняется только блок else. Возможно вложение операторов if друг в друга.
    return - оператор выхода из функции, может возвращать значение.

    2. Идентификаторы типа.

    Существуют два идентификатора типа:
    const- определяет тип константы
    var - определяет тип переменной
    Оба идентификатора типа применимы к следующим типам: int, float, string, func.
    Идентификатор var может использоваться только внутри блока.
     
    Последнее редактирование: 10 дек 2014
  4. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Тема четвертая: Грамматика скриптов.

    Текст скриптов состоит из файлов с расширением .D, файлы желательно располагать по определенным темам, согласно директорий, можно создавать любое кол-во файлов и директорий с произвольными именами.
    Процесс компиляции начинается с файла с расширением .SRC, в нем записывается порядок, в котором будут компилироваться файлы .D. Допускается вложенность файлов .SRC.

    Одно общее правило: прежде чем использовать какую-либо переменную, она должна быть декларирована. Декларация переменной с определенным именем во всех скриптах должна быть одна. Декларация (объявление) может быть с инициализацией или без нее.
    Формат .D файла прост: любая декларация должна начинаться с одного из ключевых слов: const, var, func, class, instance, prototype. Идентификатор var, как говорилось ранее, может быть использован только в блоке.
    Компилятор одинаково распознает как заглавные буквы, так и строчные буквы, поэтому имена Аааа и аааа - это одно и то же.
    Комментарии могут быть любые и в любом месте файла, они начинаются с // и до конца строки, или выделяются конструкцией /* комментарий */ и могуть включать несколько строк.

    Существует несколько главных файлов .SRC, их имена изменять нельзя. Это в папке Content - gothic.src и fight.src, а в папке System - camera.src, menu.src, music.src, sfx.src, visualfx.src и particlefx.src -из них компилируются соответствующие *.dat файлы.
    Дальше будем рассматривать базовые классы и функции. Все конкретные классы и функции будут относиться только к скриптам gothic.src. Остальные скрипты пока рассматривать не будем, может потом в этом появится необходимость.
    Небольшое замечание: В скриптах кол-во локальных переменных в блоке и размерность любого массива ограничены числом 255.
     
    Последнее редактирование: 10 дек 2014
  5. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Тема пятая: Классы.

    Все классы описаны в файле ..\_intern\Classes.d

    1. Класс параметров НПС.
    Открыть спойлер
    const int MAX_CHAPTER = 5; //Макс. количество глав в игре (не используется)
    const int MAX_MISSIONS = 5; //Макс. количество одновременно выполняемых миссий
    const int MAX_HITCHANCE = 5; //Макс. размерность массива способностей владения видами оружия
    class c_npc
    {
    var int id; //Однозначный идентификатор, связывающий конкретного НПС с его параметрами
    var string name[5]; //Имя НПС, оно появляется на экране, если НПС находится в фокусе
    var string slot; //(не используется) Можно использовать для хранения какой-нибудь строки текста!
    var string effect; //Имя визуального эффекта, привязанного к НПС
    var int npcType; //Тип НПС (описывается в файле ..AI\AI_Intern\AI_Constants.d)
    var int flags; //Флаги НПС (NPC_FLAG_IMMORTAL, NPC_FLAG_GHOST)
    var int attribute[ATR_INDEX_MAX]; //Массив значений атрибутов (ATR_HITPOINTS, ATR_MANA, ATR_STRENGTH и т.д.)
    var int HitChance[MAX_HITCHANCE]; //Способность владения НПС определенным оружием
    var int protection[PROT_INDEX_MAX]; //Массив значений защиты от определенных повреждений
    var int damage[DAM_INDEX_MAX]; //Массив значений наносимых повреждений
    var int damagetype; //Тип повреждения (НПС наносит в данный момент)
    var int guild; //Принадлежность к гильдии
    var int level; //Уровень НПС
    var func mission[MAX_MISSIONS]; //(не используется)
    var int fight_tactic; //Тактика сражения (описывается в файле ..AI\AI_Intern\AI_Constants.d)
    var int weapon; //(не используется)
    var int voice; //Номер голоса в диалогах
    var int voicePitch; //Тональность голоса
    var int bodymass; //(не используется)
    var func daily_routine; //Функция распорядка дня
    var func start_aistate; //Функция начального AI состояния (ZS_ функции)
    var string spawnPoint; //Имя Waypoint, в котором рождается НПС
    var int spawnDelay; //Задержка в секундах между смертью и возрождением НПС
    var int senses; //Чувства (зрение, слух, обоняние)
    var int senses_range; //Диапазон чувств в см.
    var int aivar[100]; //Массив значений AI переменных (описывается в файле ..AI\AI_Intern\AI_Constants.d), неиспользуемые индексы могут использоваться для собственных целей. Для Готики 2.
    // Для Готики 1 var int aivar[50];

    var string wp; //Текущий Waypoint, в котором находится НПС (отслеживается Gothic.exe)
    var int exp; //Количество полученной экспы (только для ГГ)
    var int exp_next; //Количество экспы оставшееся до следующего уровня (только для ГГ)
    var int lp; //Свободные очки обучения (только для ГГ)
    var int bodyStateInterruptableOverride; //Флаг возможности прерывания действия НПС (если TRUE - НПС прервать нельзя)
    var int noFocus; //Флаг, отвечающий за фокус (если TRUE и НПС находится в фокусе, то у НПС не показывается имя и количество жизни)
    };

    2. Класс миссий (не используется).
    Открыть спойлер
    class c_mission
    {
    var string name;
    var string description;
    var int duration;
    var int important;
    var func offerConditions;
    var func offer;
    var func successConditions;
    var func success;
    var func failureConditions;
    var func failure;
    var func obsoleteConditions;
    var func obsolete;
    var func running;
    };

    3. Класс параметров предмета.
    Открыть спойлер
    class c_item
    {
    var int id; //Однозначный идентификатор, связывающий конкретный предмет с его параметрами
    var string name; //Имя предмета, оно появляется на экране, если предмет находится в фокусе
    var string nameID; //(не используется) Можно использовать для хранения какой-нибудь строки текста!
    var int hp,hp_max; //???
    var int mainflag; //Флаги категории предмета
    var int flags; //Остальные флаги предметов
    var int weight,value; //Вес и стоимость предмета
    var int damageType; //Тип наносимого повреждения (используется для оружия)
    var int damageTotal; //Суммарное повреждение (используется для оружия)
    var int damage[DAM_INDEX_MAX]; //Величина ущерба по типам повреждений (используется для оружия)
    var int wear; //Флаги ношения предмета
    var int protection[PROT_INDEX_MAX]; //Величина защиты от конкретных повреждений (используется для брони)
    var int nutrition; //(не используется)
    var int cond_atr[3]; //Массив атрибутов, требуемых для применения
    var int cond_value[3]; //Массив значений атрибутов, требуемых для применения
    var int change_atr[3]; //(не используется)
    var int change_value[3]; //(не используется)
    var func magic; //(не используется)
    var func on_equip; //Функция вызываемая при экипировке
    var func on_unequip; //Функция вызывается, когда предмет снимается или убирается в инвентарь
    var func on_state[4]; //Функции вызываемые при использовании предмета по видам состояний (видов состояний не обнаружил ???)
    var func owner; //Владелец предмета, записывается ID НПС (не понятен тип переменной FUNC ???)
    var int ownerGuild; //Какой гильдии принадлежит предмет
    var int disguiseGuild; //(не используется)
    var string visual; //Имя .3DS файла текстур предмета
    var string visual_change; //Имя .ASC файла визуальных эффектов при получении этого предмета
    var string effect; //Имя визуального эффекта, привязанного к предмету
    var int visual_skin; //Вариация текстуры для .3DS файла текстур предмета
    var string scemeName; //Внутреннее имя предмета
    var int material; //Материал предмета
    var int munition; //Тип заряда для оружия дальнего радиуса поражения
    var int spell; //Номер заклинания, которое вызывает данный предмет
    var int range; //Радиус поражения оружием ближнего боя
    var int mag_circle; //Круг магии, к которому принадлежит предмет
    var string description; //Название предмета в инвентаре
    var string text[ITM_TEXT_MAX]; //Массив строк описания предмета в инвентаре
    var int count[ITM_TEXT_MAX]; //Массив значений характеристик предмета в инвентаре (соответствует определенной текстовой строке)
    // Характеристики изображения предмета в инвентаре
    var int inv_zbias; //Масштаб предмета в инвентаре
    var int inv_rotx; //Поворот предмета в инвентаре относительно оси X
    var int inv_roty; //Поворот предмета в инвентаре относительно оси Y
    var int inv_rotz; //Поворот предмета в инвентаре относительно оси Z
    var int inv_animate; //Вращение предмета в инвентаре
    };

    4. Класс параметров фокуса.
    Открыть спойлер
    class c_focus
    {
    // для НПС
    var float npc_longrange; //Ширина
    var float npc_range1,npc_range2; //Диапазон дальности
    var float npc_azi; //Азимут
    var float npc_elevdo,npc_elevup; //Тангаж
    var int npc_prio; //Приоритет
    // для предметов
    var float item_range1,item_range2; //Диапазон дальности
    var float item_azi; //Азимут
    var float item_elevdo,item_elevup; //Тангаж
    var int item_prio; //Приоритет
    // для MOB's
    var float mob_range1,mob_range2; //Диапазон дальности
    var float mob_azi; //Азимут
    var float mob_elevdo,mob_elevup; //Тангаж
    var int mob_prio; //Приоритет
    };

    5. Класс параметров диалогов.
    Открыть спойлер
    class c_info
    {
    var int npc; //ID НПС, которому принадлежит диалог
    var int nr; //Опция диалога с большим nr будет отображаться в списке ниже
    var int important; //Флаг начала диалога (TRUE - диалог начинаешь ты, FALSE - с тобой)
    var func condition; //Функция проверки условий начала диалога (пока функция не возвратит TRUE, диалог не начнется)
    var func information; //Функция управления диалогом
    var string description; //Строка, которая выводится в окно выбора вариантов ответов
    var int trade; //Возможность торговли (TRUE - возможно торговать, FALSE - нет)
    var int permanent; //Постоянность диалога (TRUE - диалог повторяется при каждом обращении, FALSE - однократный)
    };

    6. Класс реакций на предметы (не используется).
    Открыть спойлер
    class c_itemreact
    {
    var int npc;
    var int trade_item;
    var int trade_amount;
    var int requested_cat;
    var int requested_item;
    var int requested_amount;
    var func reaction;
    };

    7. Класс параметров заклинаний.
    Открыть спойлер
    class c_spell
    {
    var float time_per_mana; //Время в мс, требуемое для инвестирования маны на один уровень
    var int damage_per_level; //Наносимый урон за уровень заклинания
    var int damageType; //Тип повреждения
    var int spellType; //Категория заклинания
    var int canTurnDuringInvest; //Возможность поворота во время инвестирования маны (TRUE - возможно)
    var int canChangeTargetDuringInvest; //Возможность выбора цели во время инвестирования маны (TRUE - возможно)
    var int isMultiEffect; //Возможность мультиэффектов заклинания (множественные цели и др.)
    var int targetCollectAlgo; //Константа описания цели
    var int targetCollectType; //Тип цели заклинания
    var int targetCollectRange; //Дальность действия
    var int targetCollectAzi; //Угол азимута
    var int targetCollectElev; //Угол тангажа
    };

    8. Глобальные ссылки на классы.
    Открыть спойлер
    instance self,other(c_npc); // Сам НПС и Другой НПС
    instance victim(c_npc); // НПС - жертва определенного действия (3ий в действии)
    instance item(c_item); // Сам предмет
    instance hero(c_npc); // Сам ГГ (игрок)
     
    Последнее редактирование: 22 дек 2014
  6. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Тема шестая: Функции.

    Несколько общих замечаний:
    1. Функции могут возвращать значения только этих типов: void, int, float, string, instance.
    2. Рассматривать будем пока только базовые функции, которые реализованы в екзешнике.
    3. Большинство базовых функций описано в файле externals.d, но в нем есть ошибки (этот файл приведен только для справки, он не компилируется), о них буду говорить по мере разбора функций, и отмечать значком ***.
    4. Идентификаторы func (при объявлении функции) и var (как идентификатор аргументов) для простоты приводить не буду.

    1. Функции вывода текста.

    Открыть спойлер
    void Print (string s0); - выводит на экран строку текста s0, как OutputUnits текст (аналогично выводу из OU файла).
    void PrintMulti (string s0, string s1, string s2, string s3, string s4); - выводит текст на экран, объединяя строки параметров s0- s 4 в одну строку.
    int PrintScreen (string msg, int posx, int posy, string font, int timeSec); - выводит на экран строку текста msg (имя шрифта – font) с координатами posx, posy (диапазон от 0 до 99% размера экрана, -1 означает вывод по центру соответствующей оси экрана) на время timeSec (в секундах). Возвращаемое значение всегда = 0.***
    void PrintDebug (string s); - выводит текст строки s через zSpy или в лог. файл, работает только в отладочном режиме (включается (Alt+D))
    void PrintDebugInst (string text); - выводит текст строки text через zSpy или в лог. файл для ссылки self в отладочном режиме.
    void PrintDebugInstCh (int ch, string text); - выводит текст строки text через zSpy или в лог. Файл для ссылки self канала ch в отладочном режиме (каналы определены в файле PrintDebug. d).
    void PrintDebugCh (int ch, string text); - выводит текст строки text через zSpy или в лог. файл для канала ch в отладочном режиме
    int PrintDialog (int dialogNr, string msg, int posx, int posy, string font, int timeSec); - работает аналогично функции PrintScreen, только вывод осуществляется в окно диалога c номером dialogNr (координаты в % действуют внутри окна диалога).***


    2. Функции преобразования типов.

    Открыть спойлер
    string IntToString (int x); - преобразовывает целое число x в строку.
    string floatToString (float x); - преобразовывает число с плавающей точкой x в строку.***
    int floatToInt (float x); - преобразовывает число с плавающей точкой x в целое число.
    float IntTofloat (int x); - преобразовывает целое число х в число с плавающей точкой.
    string ConcatStrings (string str1, string str2); - результирующей строкой является объединение двух строк str1 и str2.


    3. Функции работы со звуком.

    Открыть спойлер
    void Snd_Play (string s0); - воспроизвести звуковой файл с именем s0.
    void Snd_Play3D (c_npc n0, string s1); - воспроизвести звуковой файл с именем s0 для НПС n0.
    int Snd_IsSourceNpc (c_npc self); - проверить, является ли НПС self источником звука (return > 0) и установить ссылку other на этого НПС.
    int Snd_IsSourceItem (c_npc self); - проверить, является ли у НПС self предмет источником звука (return > 0) и установить ссылку item на этот предмет
    int Snd_GetDistToSource (c_npc self); - выдать расстояние в сантиметрах до источника звука от НПС self.


    4. Вспомогательные функции.

    Открыть спойлер
    int Hlp_Random (int n0); - сгенерировать случайное целое число в диапазоне от 0 до n0 - 1.
    int Hlp_StrCmp (string s1, string s2); - сравнивает две строки s1 и s2, возвращает TRUE при равенстве строк или FALSE при неравенстве.
    int Hlp_IsValidNpc (c_npc self); - если ссылка на НПС self существует, то возвращает TRUE, иначе – FALSE.
    int Hlp_IsValidItem (c_item item); - если ссылка на предмет item существует, то возвращает TRUE, иначе – FALSE.
    int Hlp_IsItem (c_item item, int instanceName); - проверяет принадлежность предмета item к соответствующему типу instanceName, возвращает TRUE при соответствии, иначе – FALSE.
    c_npc Hlp_GetNpc (int instanceName); - возвращает ссылку на НПС, принадлежащему к типу instanceName.
    int Hlp_GetInstanceID (c_npc npc); - получить ID номер npc по ссылке на класс npc.
    int Hlp_GetInstanceID (c_item item); - получить ID номер предмета по ссылке на класс item.


    5. Функции работы с документами (свитки, книги, записки, карты).

    Открыть спойлер
    int Doc_Create (); - создает новый документ и возвращает номер его обработчика.
    int Doc_CreateMap (); - создает новую карту и возвращает номер её обработчика. ***
    void Doc_SetLevel (int handle, string world); - устанавливает уровень world (формат ZEN) для документа handle.*** (Не знаю, что конкретно делает эта функция).
    void Doc_SetPages (int handle, int pages); - задает кол-во отображаемых страниц pages для документа handle.
    void Doc_SetPage (int handle, int page, string pageimage, int scale); - устанавливает параметры страницы page (если параметр page = -1, то применяется ко всем страницам) документа handle: pageimage – имя файла изображения страницы в формате TGA, scale = 0 - применять масштабируемось, scale = 1 - не использовать масштабируемость (применяется для карт).
    void Doc_SetFont (int handle, int page, string fontname); - задать шрифт для страницы page документа handle, где fontname – имя файла шрифта в формате TGA.
    void Doc_SetMargins (int handle, int page, int leftMargin, int topMargin, int rightMargin, int bottomMargin, int pixel); - установить границы вывода текста на странице page документа handle, где leftMargin, topMargin, rightMargin, bottomMargin – соответственно левая, верхняя, правая и нижняя границы, pixel – кол-во пикселей на единицу границы.
    void Doc_PrintLine (int handle, int page, string text); - выводит строку текста text на странице page документа handle.
    void Doc_PrintLines (int handle, int page, string text); - выводит текст text в несколько строк на странице page документа handle.
    void Doc_Show (int handle); - выводит созданный документ handle на экран.
    void Doc_Open (string picName); - открывает документ с именем picName, как рисунок на заднем плане (в скриптах не используется).
    void Doc_Font (string fontName); - задает для документа шрифт fontName (в скриптах не используется).
    void Doc_Print (string text); - выводит текст text документа на экран (в скриптах не используется).
    void Doc_MapCoordinates (string levelName, float gamex1, float gamey1, float pixelx1, float pixely1, float gamex2, float gamey2, float pixelx2, float pixely2); - инициализирует карту с именем уровня levelName, где gamex1, gamey1, gamex2, gamey2 – координаты углов карты, соответствующие координатам уровня, а pixelx1, pixely1, pixelx2, pixely2 – соответственно коодинаты пикселей углов карты (в скриптах не используется).


    6. Функции работы с журналом квестов.

    Открыть спойлер
    void Log_CreateTopic (string name, int section); - создать в журнале тему с именем name в разделе section (предопределены два раздела LOG_MISSION или LOG_NOTE).
    void Log_SetTopicStatus (string name, int status); - установить статус status темы с именем name (предопределены следующие статусы - LOG_RUNNING, LOG_SUCCESS, LOG_FAILED, LOG_OBSOLETE).
    void Log_AddEntry (string topic, string entry); - записать в тему topic текст из строки entry.


    7. Функции работы с миссиями.

    Открыть спойлер
    void Mis_SetStatus (int missionName, int newStatus); - установить статус newStatus миссии missionName (предопределены следующие статусы RUNNING, SUCCESS, FAILED и т.д.)
    int Mis_GetStatus (int missionName); - получить статус миссии missionName.
    int Mis_OnTime (int missionName); - проверка миссии, возвращает TRUE, если миссия активна, т.е. не завершена. Примечание: данная функция в экзешнике реализована неверно, она ничего не возвращает (лучше ее не использовать).
    void Mis_AddMissionEntry (c_mission miss, string name); - добавить в список миссий новую миссию miss под именем name.***
    void Mis_RemoveMission (c_mission miss); - удалить из списка миссий миссию miss. ***


    8. Функции работы с инвентарем.

    Открыть спойлер
    void CreateInvItem (c_npc n0, int n1); - создает в инвентаре НПС n0 предмет с ID n1.
    void CreateInvItems (c_npc n0, int n1, int n2); - создает в инвентаре НПС n0 предметы с ID n1 количеством n2.
    void EquipItem (c_npc n0, int n1); - экипировать НПС n0 предметом с ID n1.
    void Mob_CreateItems (string mobName, int itemInstance, int amount); - создает в контейнере с именем mobName (например сундук) предметы с ID itemInstance количеством amount.
    int Mob_HasItems (string mobName, int itemInstance); - получить количество предметов с ID itemInstance, находящихся в контейнере с именем mobName.


    9. Функции анимации.

    Открыть спойлер
    void Mdl_ApplyOverlayMds (c_npc n0, string s1); - запустить файл анимации s1 с расширением mds для НПС n0.
    void Mdl_RemoveOverlayMDS (c_npc self, string overlayName); - отключить от НПС self файл анимации overlayName.
    void Mdl_ApplyOverlayMDSTimed (c_npc self, string overlayname, int timeTicks); - запустить файл анимации overlayname для НПС self на время timeTicks.***
    void Mdl_ApplyRandomAni (c_npc n0, string s1, string s2); - запустить случайные анимации s1 для НПС n0 в последовательности анимационных состояний s2.
    void Mdl_ApplyRandomAniFreq (c_npc n0, string s1, float f2); - устанавливает частоту выборки f2 случайных анимационных состояний s1 для НПС n0.
    void Mdl_StartFaceAni (c_npc self, string name, float intensity, float holdTime); - запускает файл name анимации лица для НПС self с интенсивностью intensity (в %, 1100%) и временем удержания holdTime (1 – постоянно).
    void Mdl_ApplyRandomFaceAni (c_npc self, string name, float timeMin, float timeMinVar, float timeMax, float timeMaxVar, float probMin); - запускает файл случайной анимации лица name для НПС self со следующими параметрами : timeMin, timeMax – диапазон времени воспроизведения анимации в сек, timeMinVar, timeMaxVar – отклонения от значений timeMin, timeMax в сек, probMin – вероятность использования отклонения (от 0 до 1) от нижней до верхней границы.
    void Mdl_SetVisual (c_npc self, string fileMds); - задать для НПС self файл изображения с именем fileMds (формат MDS).***
    void Mdl_SetVisualBody (c_npc self, string body, int bodytex, int color, string head, int htex, int ttex, int armor); - установить параметры изображения НПС self, где : body – имя mesh файла изображения тела, bodytex – номер текстуры тела, color – номер палитры цвета кожи, head – имя MMS файла изображения головы, htex – номер текстуры головы, ttex – номер текстуры зубов, armor – номер одетой брони (- 1 – брони нет).***
    void Mdl_SetModelScale (c_npc self, float x, float y, float z); - установить масштаб mesh изображения модели НПС self по координатам x, y, z в % (1 -100%).
    void Mdl_SetModelFatness (c_npc self, float fatness); - установить жирность mesh изображения модели НПС self в % (1 - 100%). Может кто-нибудь пояснить, что это за функция?


    10. Функции распорядка дня.

    Открыть спойлер
    void TA_Min (c_npc self, int start_h, int start_m, int stop_h, int stop_m, func state, string waypoint); - для НПС self задается функция распорядка дня state, где start_h и start_m – время в часах и минутах начала выполнения функции, stop_h и stop_m – соответственно время окончания функции, waypoint – имя точки, в которой выполняется функция.
    void TA (c_npc self, int start_h, int stop_h, func state, string waypoint); - выполняет все то, что и предыдущая функция, только без привязки к минутам.
    void TA_CS (c_npc self, string csName, string roleName); - функция, выполняемая последней в списке функций распорядка дня для НПС self, где csName – имя файла CS (Cutscene), roleName – роль НПС, которая должна выполняться. (частично не понял)
    void TA_BeginOverlay (c_npc self); - начать выполнять заявленный распорядок дня для НПС self.
    void TA_EndOverlay (c_npc self); - закончить выполнять заявленный распорядок дня для НПС self.
    void TA_RemoveOverlay (c_npc self); - удалить заявленный распорядок дня для НПС self.


    11. Функции работы с диалогами.

    Открыть спойлер
    int InfoManager_HasFinished (); - показывает, завершен ли диалог (возвращает 0 во время диалога и 1 после окончания диалога).***
    void Info_AddChoice (c_info menu, string text, func fn); - добавляет в меню диалога menu строку выбора действия text, fn – функция, которая активируется при выборе данного пункта меню.***
    void Info_ClearChoices (c_info menu); - удалить тему диалога menu.***


    12. Функции различного назначения.

    Открыть спойлер
    void ExitGame (); - просто закончить игру.***
    int PlayVideo (string video); - показать видео файл video (c расширением BIK), возвращает 1, если видео показано, 0 – в случае ошибки.***
    void SetPercentDone (int perc); - установить процент perc отображения полоски в окне загрузки (ProgressBar), значение от 0 до 100.***
    void IntroduceChapter (string chapter, string name, string file, string sound, int time); - вывести на экран окно новой главы, где chapter – номер главы, name – название главы, file – файл заставки главы (формат TGA), sound – звуковой файл (формат WAV), time – время показа заставки.***
    void Tal_Configure (int tal, int value); - переопределить значение таланта value для константы tal (например, определены константы NPC_TALENT_PICKLOCK, NPC_TALENT_MAGE и т.д.).***
    void Perc_SetRange (int percID, int range); - устанавливает дальность действия range пассивного восприятия percID в сантиметрах.
    void Rtn_Exchange (string oldRoutine, string newRoutine); - заменяет функции oldRoutine распорядка дня НПС self на новые функции newRoutine. (Имя функции должно начинаться с RTN_ и заканчиваться идентификатором НПС скрипта).
    int Hlp_CutscenePlayed (string csName); - информирует, игралась ли Cutscene с именем csName (0 – нет, 1 – да).


    13. Функции работы с миром Готики.

    Открыть спойлер
    int Wld_DetectNpc (c_npc self, int instance, func aiState, int guild); - эта функция инициализирует глобальную переменную скриптов other, отличную от НПС self, где instance – производная от класса c_npc, которая должна быть найдена и проинициализирована (-1 – любая производная), guild – гильдия, членом которой должен быть искомый НПС (-1 – любая гильдия), aiState – функция AI состояния, в котором должен находится искомый НПС (NOFUNC – любое AI состояние). Функция возвращает 1 в случае успешного завершения (other инициализирован найденным НПС), 0 – неудача (other не определен).
    int Wld_DetectNpcEx (c_npc self, int instance, func aiState, int guild, int detectPlayer); - выполняет все тоже, что и предыдущая функция, дополнительный параметр detectPlayer указывает, исключить ли игрока (ГГ) из поиска (0 – исключить, 1 – нет).
    int Wld_DetectItem (c_npc self, int flags); - эта функция инициализирует глобальную переменную скриптов item предметом, возможно находящимся у НПС self и имеющим флаг flags, возвращает 1 при успешном поиске и инициализации, иначе – 0.
    int Wld_DetectPlayer (c_npc self); - возвращает 1, если ГГ есть НПС self, иначе – 0.
    void Wld_SetGuildAttitude (int guild1, int attitude, int guild2); - установить отношение между гильдиями, где guild1, guild2 – гильдии, между которыми устанавливается отношение, attitude – отношение между гильдиями (определены отношения ATT_HOSTILE, ATT_FRIENDLY, ATT_NEUTRAL, ATT_ANGRY).
    int Wld_GetGuildAttitude (int guild1, int guild2); - получить отношение между гильдиями guild1 и guild2.
    int Wld_IsMobAvailable (c_npc self, string schemeName); - проверяет, есть ли MOB с именем schemeName в окрестности 10 метров от НПС self, возвращает TRUE, если MOB существует и свободен, иначе FALSE.
    int Wld_GetMobState (c_npc self, string schemeName); - определяет состояние MOB с именем schemeName для НПС self, возвращает состояние или -1, если MOB не найден.
    int Wld_IsFPAvailable (c_npc self, string fpName); - проверяет, есть ли FP (Freepoint) с именем fpName в окрестности 20 метров от НПС self, возвращает TRUE, если FP существует и свободна, иначе FALSE.
    int Wld_IsNextFPAvailable (c_npc self, string fpName); - работает аналогично предыдущей функции, но проверится ближайшая точка, если fpName блокирована.
    int Wld_GetDay (); - получить текущий день, отсчет дней идет от дня старта (Gamestart) = 0.
    int Wld_IsTime (int hour1, int min1, int hour2, int min2); - возвращает 1, если текущее время находится между границами (hour1, min1 – нижняя граница, hour2, min2 – верхняя граница в часах и минутах), иначе возвращает 0.
    void Wld_SetTime (int hour, int min); - установить текущее время в часах hour и минутах min.***
    void Wld_InsertNpc (int npcInstance, string spawnPoint); - разместить в мире одного НПС, где npcInstance – ссылка на НПС, spawnPoint – имя точки размещения (может быть как WP, так и FP).
    void Wld_InsertNpcAndRespawn (int instance, string spawnPoint, int spawnDelay); - выполняется аналогично предыдущей функции, только НПС после смерти будет оживлен в заданной точке через spawnDelay секунд.***
    void Wld_SpawnNpcRange (c_npc self, int npcInstance, int number, float time); - НПС self около себя создает НПС (ссылка на него npcInstance) количеством number на время жизни time. Используется в заклинаниях вызова.***
    void Wld_RemoveNpc (int npcInstance); - удалить из мира НПС (ссылке на него npcInstance).***
    void Wld_InsertItem (int itemInstance, string spawnPoint); - разместить в мире один предмет, где itemInstance – ссылка на предмет, spawnPoint – имя точки размещения (может быть как WP, так и FP). В примечании к функции написано: «Осторожно, не функционирует! Предмет будет вставлен в центр мира.» В скриптах данная функция используется, осталось выяснить, как она работает.
    int Wld_RemoveItem (c_item item); - удалить из мира предмет по item ссылке на него, возвращает 1 – успешное удаление, иначе – 0.
    void Wld_InsertObject (string name, string point); - разместить в мире визуальный объект name в точке с именем point (может быть как WP, так и FP).***
    void Wld_SetObjectRoutine (int hour1, int min1, string objName, int state); -объект с именем objName (VOB объект) перейдет в состояние state в момент времени hour1, min1 (часы и минуты).
    void Wld_SetMobRoutine (int hour1, int min1, string objName, int state); - выполняется как и предыдущая функция, только для MOB объекта.
    void Wld_SendTrigger (string name); - активировать функцию VOB объекта с именем name. (Я не знаю где где прописаны эти функции).***
    void Wld_SendUntrigger (string name); - деактивировать функцию VOB объекта с именем name.***
    void Wld_ExchangeGuildAttitudes (string name); - установить взаимоотношения между гильдиями, где name – имя таблицы заданных отношений.
    void Wld_AssignRoomToGuild (string s0, int guild); - размещает гильдию guild на пространстве s0.
    void Wld_AssignRoomToNpc (string s0, c_npc roomowner); - размещает НПС roomowner на пространстве s0.
    c_npc Wld_GetPlayerPortalOwner ();
    int Wld_GetPlayerPortalGuild ();
    c_npc Wld_GetFormerPlayerPortalOwner ();
    int Wld_GetFormerPlayerPortalGuild ();
    Какие-то четыре функции, определяющие положение игрока в пространстве, большего сказать, увы, не могу.
    void Wld_PlayEffect (string ???, instance ???, instance ???, int ???, int ???, int ???, int ???); - данная функция абсолютно нигде не применяется и не описана, поэтому ее действие и аргументы мне не известны.***


    14. Функции работы с НПС.

    Открыть спойлер
    int Npc_GetTRUEGuild (c_npc npc); - возвращает номер гильдии, к которой принадлежит НПС npc.
    int Npc_SetTRUEGuild (c_npc npc, int guildID); - установить принадлежность НПС npc к гильдии guildID.
    void Npc_SetAttitude (c_npc self, int att); - установить постояноое отношение att НПС self ко всем остальным НПС.
    void Npc_SetTempAttitude (c_npc self, int att); - установить временное отношение att НПС self ко всем остальным НПС.
    int Npc_GetAttitude (c_npc self, c_npc other); - получить любое отношение НПС self к НПС other.
    int Npc_GetPermAttitude (c_npc self, c_npc other); - получить постоянное отношение НПС self к НПС other.
    int Npc_GetGuildAttitude (c_npc self, c_npc other); - получить отношение НПС self к НПС other, как отношение между гильдиями, а не личностями.
    void Npc_SetKnowsPlayer (c_npc self, c_npc player) ; - эта функция задает, что НПС self знаком с НПС player (ГГ).
    int Npc_KnowsPlayer (c_npc self, c_npc player); - проверить, знаком ли НПС self с НПС player, возвращает TRUE, если знаком, иначе FALSE.
    int Npc_OwnedByNpc (c_item item, c_npc npc); - проверить, принадлежит ли предмет item npc, возвращает 1, если принадлежит, иначе - 0.
    int Npc_OwnedByGuild (c_item item, int guild); - - проверить, принадлежит ли предмет item гильдии guild, возвращает 1, если принадлежит, иначе - 0.
    string Npc_GetNearestWP (c_npc self); - возвращает название WP, в которой расположен НПС self.
    string Npc_GetNextWP (c_npc self); - возвращает название соседней точки WP, рядом с которой расположен НПС self.
    int Npc_IsWayBlocked (c_npc self); - возвращает 1, если путь НПС self прегражден препятствием, иначе – 0.
    int Npc_IsOnFP (c_npc self, string name); - проверяет, находится ли НПС self в точке FP с именем name, возвращает 1 – да, иначе – 0.
    int Npc_IsDead (c_npc n0); - возвращает 1, если НПС n0 мертв, иначе – 0.
    int Npc_KnowsInfo (c_npc self, int infoInstance); - возвращает TRUE, если НПС self уже получил информацию infoInstance, иначе FALSE.
    int Npc_CheckInfo (c_npc npc, int important); - проверяет, имеет ли НПС npc действительную информацию для игрока, в этом случае возвращается 1 и начинается диалог, иначе 0, где important – важность информации (1 – важная, 0 – обычная).
    int Npc_GiveInfo (c_npc npc, int important); - работает аналогично предыдущей функции, есть какое-то отличие, но я его не понял.
    int Npc_CheckAvailableMission (c_npc npc, int missionState, int important); - проверяет, имеет ли npc миссию в состоянии missionState (AVAILABLE, RUNNING) с важностью important, возвращает 1, если имеет, иначе – 0.
    int Npc_CheckRunningMission (c_npc npc, int important); - работает аналогично предыдущей функции, только проверяется миссия в состоянии текущего выполнения.
    int Npc_CheckOfferMission (c_npc npc, int important); - работает аналогично предыдущей функции, только проверяется миссия в которой НПС npc может что-то предложить игроку.
    int Npc_GetStateTime (c_npc self); - возвращает кол-во секунд, которые НПС self находится в текущем состоянии, заданном в " Loop " цикле.
    void Npc_SetStateTime (c_npc self, int seconds); - установить кол-во секунд seconds, как долго НПС self может находится в этом состоянии.
    int Npc_GetBodyState (c_npc self); - возвращает состояние, в котором находится НПС self (BS_константы).
    int Npc_HasBodyFlag (c_npc self, int bodyFlag); - проверяет, установлен ли у НПС self флаг состояния bodyFlag, возвращает 1, если установлен, иначе – 0.
    int Npc_IsPlayer (c_npc player); - возвращает 1, если проверяемый НПС player является ГГ.
    int Npc_HasDetectedNpc (c_npc self, c_npc other); - возвращает 1, если НПС self чувствует (видит, сышит и т.д.) НПС other, иначе – 0.
    int Npc_IsInState (c_npc self, func state); - запрос на текущее состояние фигуры НПС self, где state – функция состояния фигуры, возвращает TRUE, если НПС находится в этом состоянии, иначе – FALSE.
    int WasInState (c_npc self, func state); - аналогично предыдущей функции, только запрос на предыдущее состояние фигуры НПС.
    int Npc_IsInRoutine (c_npc self, func state); - проверяет, находится ли НПС self в функции state, возвращает TRUE если находится, иначе – FALSE.
    void Npc_ExchangeRoutine (c_npc self, string routineName); - поменять у НПС self распорядок дня routineName.
    int Npc_IsInCutscene (c_npc self); - возвращает 1, если НПС self находится во время проигрывания Cutscene, иначе – 0.
    int Npc_IsVoiceActive (c_npc self); - возвращает 1, если НПС self разговаривает, иначе – 0.***
    void Npc_ClearAIQueue (c_npc self); - удаляет все команды для НПС self из очереди AI_Queue.
    void Npc_PlayAni (c_npc self, string file); - воспроизвести файл анимации file для НПС self.***
    void Npc_SetRefuseTalk (c_npc self, int timeSec); - установить счетчик отказа от диалога для НПС self на timeSec секунд.
    int Npc_RefuseTalk (c_npc self); - проверить, истек ли счетчик отказа от диалога для НПС self, возвращает TRUE, если счетчик не истек, иначе – FALSE.
    int Npc_IsNear (c_npc self, c_npc other); - возвращает 1, если НПС other находится на расстоянии не менее 3 метров от НПС self, иначе – 0.
    int Npc_GetDistToNpc (c_npc npc1, c_npc npc2); - возвращает расстояние в см. между npc1 и npc2.
    int Npc_GetDistToWP (c_npc self, string wpName); - возвращает расстояние в см. между НПС self и WP wpName.
    int Npc_GetDistToItem (c_npc self, c_item item); - возвращает расстояние в см. между НПС self и предметом item.
    int Npc_GetDistToPlayer (c_npc npc1); - возвращает расстояние в см. между npc1 и ГГ.
    void Npc_MemoryEntry (c_npc self, int source, c_npc offender, int newsid, c_npc victim); - данная функция записывает для НПС self новости, где source – источник новостей (определено два источника: NEWS_SOURCE_WITNESS – есть свидетель произошедшего, NEWS_SOURCE_GOSSIP – сплетня), newsid – идентификатор новости (определены новости: NEWS_MURDER - убийство, NEWS_ATTACK – атака, NEWS_THEFT – воровство, NEWS_DEFEAT – поражение, NEWS_NERVE – переживание, NEWS_INTERFERE – вмешательство, NEWS_HASDEFEATED – победа), offender – НПС преступник, victim – НПС жертва.
    void Npc_MemoryEntryGuild (c_npc self, int source, c_npc offender, int newsid, c_npc victimguild); - работает аналогично предыдущей функции, только жертвой является вся гильдия.
    int Npc_HasNews (c_npc self, int newsID, c_npc offender, c_npc victim); - эта функция проверяет, имеет ли НПС self новость с идентификатором newsID о жертве victim и преступнике offender, возвращает 1, если имеет, иначе – 0. (Вместо ненужных параметров можно записать 0).
    int Npc_IsNewsGossip (c_npc self, int newsNumber); - возвращает 1, если новость для НПС self является сплетней, иначе – 0.
    c_npc Npc_GetNewsWitness (c_npc self, int newsNumber); - возвращает ссылку на свидетеля в новости newsNumber для НПС self.
    c_npc Npc_GetNewsVictim (c_npc self, int newsNumber); - возвращает ссылку на жертву в новости newsNumber для НПС self.
    c_npc Npc_GetNewsOffender (c_npc self, int newsNumber); - возвращает ссылку на преступника в новости newsNumber для НПС self.
    int Npc_DeleteNews (c_npc self, int newsNumber); - удаляет новость newsNumber для НПС self, возвращает 1, исли удаление успешно, иначе – 0.***
    void Npc_ChangeAttribute (c_npc self, int atr, int value); - изменяет значение атрибута atr на кол-во единиц value для НПС self.
    void Npc_CreateSpell (c_npc self, int spellnr); - НПС self создает заклинание spellnr, оно становится активным, но еще не применяется.
    void Npc_LearnSpell (c_npc self, int spellnr); - НПС self выучил заклинание spellnr и может его использовать.
    int Npc_GetActiveSpell (c_npc self); - возвращает номер заклинания, которое имеет активным НПС self, иначе - -1.
    int Npc_GetActiveSpellCat (c_npc self); - возвращает номер категории активного заклинания у НПС self. Существуют три категории заклинаний:SPELL_GOOD, SPELL_NEUTRAL, SPELL_BAD.
    int Npc_SetActiveSpellInfo (c_npc npc, int i1); - задает любое значение i1 для активного заклинания у НПС npc, это значение может использоваться в скриптах, экзешник на него не реагирует. Возвращаемое значение неизвестно.
    int Npc_GetActiveSpellLevel (c_npc self); - возвращает уровень активного заклинания у НПС self.
    int Npc_HasSpell (c_npc self, int spellID); - возвращает 1, если НПС self может использовать заклинание spellID, иначе – 0.
    void Npc_PercEnable (c_npc self, int percID, func function); - функция активации восприятия percID у НПС self, где function – функция обработки восприятия.
    void Npc_PercDisable (c_npc self, int percID); - функция деактивации восприятия percID у НПС self.
    void Npc_SetPercTime (c_npc self, float seconds); - установка времени реакции в секундах seconds НПС self на событие для активного восприятия.
    void Npc_SendPassivePerc (c_npc npc1, int Perc_type, c_npc npc2, c_npc npc3); - функция посылки пассивного восприятия Perc_type от npc1, где npc2 – жертва, npc3 – преступник.
    void Npc_SendSinglePerc (c_npc self, c_npc target, int percID); - функция посылки восприятия percID от НПС self к НПС target.
    void Npc_PerceiveAll (c_npc self); - разрешает НПС self воспринимать все объекты в зоне действия восприятия, затем можно использовать функции Wld_DetectNpc и Wld_DetectItem.
    string Npc_GetDetectedMob (c_npc self); - возвращает имя MOB (Move Object) объекта, который распознал НПС self. Например: если имя MOB объекта " DOOR_OCR _135", то функция возвратит " DOOR ".
    int Npc_CanSeeNpc (c_npc npc1, c_npc npc2); - возвращает TRUE, если npc1 может видеть npc2, иначе – FALSE.
    int Npc_CanSeeNpcFreeLOS (c_npc self, c_npc other); - возвращает TRUE, если НПС self может видеть НПС other по прямой, без учета угла обзора, иначе – FALSE.
    int Npc_CanSeeItem (c_npc npc1, c_item item); - возвращает TRUE, если npc1 может видеть предмет item, иначе – FALSE.
    int Npc_CanSeeSource (c_npc self); - возвращает TRUE, если НПС self может видеть источник звука, иначе – FALSE.
    int Npc_IsPlayerInMyRoom (c_npc npc); - возвращает TRUE, если НПС npc находится в своем помещении или в помещении своей гильдии, иначе – FALSE.
    int Npc_WasPlayerInMyRoom (c_npc npc); - возвращает TRUE, если НПС npc находился в своем помещении или в помещении своей гильдии перед изменением своего положения, иначе – FALSE.
    int Npc_GetComrades (c_npc npc); - возвращает 1, если НПС npc имеет друзей, иначе – 0. ***
    int Npc_IsDetectedMobOwnedByNpc (c_npc user, c_npc owner); - возвращает значение > 0, если НПС owner является владельцем MOB а, который использует НПС user.
    int Npc_IsDetectedMobOwnedByGuild (c_npc user, int ownerguild); - возвращает значение > 0, если гильдия ownerguild является владельцем MOB а, который использует НПС user.
    void Npc_GiveItem (c_npc self, c_item item, c_npc other); - НПС self получает предмет item от НПС other.
    int Npc_StartItemReactModules (c_npc self, c_npc other, c_item item); - проверяет все модули ItemReact реакции на предмет item, полученный НПС self от НПС other, запускает соответствующую функцию Reaction и возвращает TRUE, если находит модуль, иначе – FALSE.
    int Npc_HasOffered (c_npc self, c_npc other, int itemInstance); - проверяет, имеет ли НПС other предмет itemInstance для передачи НПС self, возвращает TRUE, если предмет имеется, иначе – FALSE.
    c_item Npc_GetInvItem (c_npc self, int itemInstance); - получить ссылку на предмет, который имеет НПС self с номером itemInstance.
    int Npc_HasItems (c_npc n0, int itemInstance); - возвращает количетво предметов itemInstance у НПС n0.
    int Npc_GetInvItemBySlot (c_npc self, int category, int slotNr); - возвращает кол- во предметов, которые находятся у НПС self, где category – категория инвентаря (INV_WEAPON, INV_ARMOR, INV_RUNE, INV_MAGIC, INV_FOOD, INV_POTION, INV_DOC, INV_MISC), slotNr – номер слота предмета.
    void Npc_RemoveInvItem (c_npc owner, int itemInstance); - предмет itemInstance удаляется из инвентаря НПС owner и из игры.
    void Npc_RemoveInvItems (c_npc owner, int itemInstance, int amount); - указанное кол-во amount предметов itemInstance удаляется из инвентаря НПС owner и из игры.
    c_item Npc_GetEquippedMeleeWeapon (c_npc n0); - возвращает оружие ближнего радиуса поражения, которым экипирован НПС n0.
    c_item Npc_GetEquippedRangedWeapon (c_npc n0); - возвращает оружие дальнего радиуса поражения, которым экипирован НПС n0.
    c_item Npc_GetEquippedArmor (c_npc n0); - возвращает доспехи, которыми экипирован НПС n0.
    int Npc_HasEquippedWeapon (c_npc self); - возвращает 1, если НПС self экипирован оружием, иначе - 0.
    int Npc_HasEquippedMeleeWeapon (c_npc self); - возвращает 1, если НПС self экипирован оружием ближнего радиуса поражения, иначе - 0.
    int Npc_HasEquippedRangedWeapon (c_npc self); - возвращает 1, если НПС self экипирован оружием дальнего радиуса поражения, иначе - 0.
    int Npc_HasEquippedArmor (c_npc self); - возвращает 1, если НПС self экипирован доспехами, иначе - 0.
    void Npc_SetToFistMode (c_npc self); - ставит НПС self в режим кулачного боя.
    void Npc_SetToFightMode (c_npc self, int weapon); - ставит НПС self в режим боя с соответствующим оружием weapon.
    int Npc_IsInFightMode (c_npc self, int fmode); - возвращает 1, если НПС self находится в боевом режиме fmode, иначе - 0. Заданы следующие боевые режимы: FMODE_NONE – небоевой режим, FMODE_FIST – режим кулачного боя, FMODE_MELEE – боевой режим с оружием ближнего радиуса поражения, FMODE_FAR - боевой режим с оружием дальнего радиуса поражения, FMODE_MAGIC – боевой режим с магией.
    c_item Npc_GetReadiedWeapon (c_npc n0); - возвращает ссылку на оружие, которое НПС n0 держит в руке.
    int Npc_HasReadiedWeapon (c_npc self); - возвращает 1, если НПС self держит любое оружие в руке, иначе - 0.
    int Npc_HasReadiedMeleeWeapon (c_npc self); - возвращает 1, если НПС self держит в руке оружие ближнего радиуса поражения, иначе - 0.
    int Npc_HasReadiedRangedWeapon (c_npc self); - возвращает 1, если НПС self держит в руке оружие дальнего радиуса поражения, иначе - 0.
    int Npc_HasRangedWeaponWithAmmo (c_npc npc); - возвращает 1, если НПС npc держит в руке или имеет в инвентаре оружие дальнего радиуса поражения с боеприпасами, иначе - 0.
    int Npc_GetTarget (c_npc self); - возвращает TRUE, если НПС self имеет цель для поражения (в качестве цели выступает НПС other), иначе – FALSE.
    int Npc_GetNextTarget (c_npc self); - выполняется активный поиск цели для НПС self. Если цель находится, то она становится внутренней целью и записывается в переменную
    other, если цель не найдена, то внутренняя цель удаляется и other становится недействительным. Критерий поиска цели - в качестве цели возмется враждебный противник, который не мертв или находится не в бессознательном состоянии. Возвращает TRUE, если цель найдена, иначе – FALSE. Внимание: Поиск основывается на активном восприятии НПС self, поэтому, если активное восприятие не установлено, то сначала следует применять функцию Npc_PerceiveAll ().
    int Npc_IsNextTargetAvailable (c_npc self); - работает аналогично предыдущей функции, только ни внутренняя цель, ни переменная other не инициализируются.
    void Npc_SetTarget (c_npc self, c_npc other); - устанавливает для НПС self в качестве внутренней цели для поражения НПС other.
    int Npc_AreWeStronger (c_npc self, c_npc other); - выявляет более сильного НПС среди self и other по следующему алгоритму: если сумма уровней всех НПС (людей и монстров), которые враждебны к self и дружелюбны к other, более чем в два раза превышает сумму уровней всех НПС (людей и монстров), которые дружелюбны к self и враждебны к other, то other сльнее и возвращается FALSE, иначе сильнее self и возвращается TRUE. Замечания: 1. НПС, которые враждебны к обоим, не учитываются. 2. НПС, который враждебен к одному и дружелюбен к другому, будет участвовать в подсчете два раза.
    int Npc_IsAiming (c_npc self, c_npc other); - возвращает 1, если НПС other целится в НПС self из оружия дальнего радиуса поражения или магией, иначе – 0.
    int Npc_GetTalentSkill (c_npc self, int talent); - возвращает уровень навыка talent, который имеет НПС self.*** Определены следующие способности: NPC_TALENT _1 H – владение одноручником, NPC_TALENT _2 H – владение двуручником, NPC_TALENT_BOW – владение луком, NPC_TALENT_CROSSBOW – владение арбалетом, NPC_TALENT_PICKLOCK – умение вскрывать замки, NPC_TALENT_PICKPOCKET – карманная кража, NPC_TALENT_MAGE – владение магией, NPC_TALENT_SNEAK – умение подкрадываться, NPC_TALENT_REGENERATE – способность восстанавливать здоровье, NPC_TALENT_FIREMASTER – способность мастерски обращаться с огнем, NPC_TALENT_ACROBAT – акробатика.
    int Npc_GetTalentValue (c_npc self, int talent); - возвращает кол-во единиц навыка talent, которые имеет НПС self.***
    void Npc_SetTalentSkill (c_npc self, int talent, int level); - установить уровень level навыка talent, которым владеет НПС self.***
    void Npc_SetTalentValue (c_npc self, int talent, int value); - установить кол-во единиц value навыка talent, которым владеет НПС self.***
    Вот мы и закончили рассмотрение большого раздела – функции работы с НПС.


    15. Функции искусственного интеллекта (AI_ функции).

    Открыть спойлер
    void AI_Wait (c_npc n0, float n1); - НПС n0 переводится на n1 секунд в состояние ожидания, в этом состоянии он не делает ничего, но наносимый ущерб регистрируется и работает пассивное восприятие.
    void AI_PlayAni (c_npc n0, string s0); - для НПС n0 проигрывается файл анимации s0 (имя файла s0 обязательно пишется заглавными буквами).
    void AI_StandUp (c_npc self); - если НПС self находится в состоянии анимации, то проигрывается соответствующее движение, если НПС self находится на MOBSI объекте (стул, кровать и т.д.), то он встает.
    void AI_StandUpQuick (c_npc self); - в отличии от предыдущей функции никаких движений не проигрывается, НПС self сразу переводится в стоячее состояние.
    void AI_QuickLook (c_npc self, c_npc other); - НПС self быстро бросает взгляд на НПС other. Выполняется только движение головой в течение 2 секунд.
    void AI_LookAt (c_npc self, string name); - НПС self смотрит на определенную точку на местности или на объект, где name – имя точки местности или имя VOB объекта.
    void AI_LookAtNpc (c_npc self, c_npc other); - НПС self смотрит на НПС other.
    void AI_StopLookAt (c_npc self); - НПС self снова смотрит прямо перед собой.
    void AI_PointAt (c_npc self, string name); - НПС self указывает на определенную точку на местности или на объект, где name – имя точки местности или имя VOB объекта.
    void AI_PointAtNpc (c_npc self, c_npc other); - НПС self указывает на НПС other.
    void AI_StopPointAt (c_npc self); - НПС self прекращает указывать на что-нибудь или кого-нибудь.
    void AI_TakeItem (c_npc self, c_item item); - НПС self берет (принимает) предмет item.
    void AI_DropItem (c_npc self, int itemid); - НПС self выбрасывает на землю или на пол предмет itemid.
    void AI_UseItem (c_npc self, int itemInstance); - НПС self использует предмет itemInstance.
    void AI_UseItemToState (c_npc self, int itemInstance, int state); - НПС self использует предмет itemInstance до указанного состояния state (-1 – используется полностью).
    void AI_TakeMob (c_npc self, string name); - НПС self берет (принимает) MOB (рюкзак, корзину и т.д.) с именем name.***
    void AI_DropMob (c_npc self); - НПС self выбрасывает на землю или на пол имеющийся MOB.***
    int AI_UseMob (c_npc self, string schemeName, int targetState); - НПС self использует MOB с именем schemeName до указанного состояния targetState. Если указанное состояние у MOBа уже имеется, НПС self приближается к нему, но ничего не делает.
    void AI_Waitms (c_npc self, int msec); - НПС self переводится на msec миллисекунд в состояние ожидания, в этом состоянии он не делает ничего, но наносимый ущерб регистрируется и работает пассивное восприятие.***
    void AI_CanSeeNpc (c_npc self, c_npc other, func see); - НПС self может увидеть НПС other, где see – какая-то функция (описания не нашел).***
    void AI_SetWalkmode (c_npc n, int n0); - установить режим передвижения n0 для НПС n. Определены следующие режимы: NPC_RUN – бег, NPC_WALK – ходьба шагом, NPC_SNEAK – подкрадывание, NPC_RUN_WEAPON – бег с оружием, NPC_WALK_WEAPON – ходьба с оружием, NPC_SNEAK_WEAPON – подкрадывание с оружием.
    void AI_GotoWP (c_npc n0, string s0); - НПС n0 перемещается в указанную WP s0.
    void AI_GotoFP (c_npc self, string fpName); - НПС n0 перемещается в указанную FP fpName, расположенную в пределах 20 метров. Критерий поиска FP аналогичен используемому в функции Wld_IsFPAvailable.
    void AI_GotoNextFP (c_npc self, string fpName); - работает аналогично предыдущей функции, только критерий поиска FP аналогичен используемому в функции Wld_IsNextFPAvailable.
    void AI_GotoNpc (c_npc self, c_npc other); - НПС self перемещается к НПС other.
    void AI_GotoItem (c_npc self, c_item item); - НПС self перемещается к предмету item.
    void AI_GotoSound (c_npc n0); - НПС self перемещается к источнику звука.
    void AI_Teleport (c_npc self, string waypoint); - телепортирует НПС self в новую локацию waypoint.
    void AI_TurnToNpc (c_npc n0, c_npc n1); - НПС n0 поварачивается к НПС n1 лицом.
    void AI_TurnAway (c_npc n0, c_npc n1); - НПС n0 поварачивается к НПС n1 спиной.
    void AI_WhirlAround (c_npc self, c_npc other); - НПС self быстро поварачивается к НПС other лицом. (Делает оборот).
    void AI_WhirlAroundToSource (c_npc self); - НПС self быстро поварачивается лицом к какому-то источнику.*** (Описания не нашел).
    void AI_TurnToSound (c_npc self); - НПС self поварачивается лицом к источнику звука.
    void AI_AlignToWP (c_npc self); - НПС self выравнивается в WP точке по направлению стрелки, заданной в Spacer.
    void AI_AlignToFP (c_npc self); - НПС self выравнивается в FP точке по направлению стрелки, заданной в Spacer.***
    void AI_Dodge (c_npc npc); - НПС npc отклоняется назад. (Способ защиты при атаке противника).
    void AI_PlayAniBS (c_npc npc, string aniname, int bodystate); - для НПС npc проигрывается файл анимации aniname для определенного состояния тела bodystate.
    void AI_PlayCutscene (c_npc self, string csName); - для НПС self проигрывается Cutscene с именем csName, заданная в скриптах.
    void AI_DrawWeapon (c_npc n0); - НПС n0 вытаскивает оружие, которым экипирован.
    void AI_RemoveWeapon (c_npc n0); - НПС n0 прячет оружие.
    void AI_ReadyMeleeWeapon (c_npc self); - НПС self готовит оружие ближнего радиуса поражения к бою.
    void AI_ReadyRangedWeapon (c_npc self); - НПС self готовит оружие дальнего радиуса поражения к бою.
    void AI_Attack (c_npc self); - НПС self начинает сражение (эта функция должна вызываться внутри ZS_Attack_Loop). Атакуется внутренняя цель, которая была задана функцией Npc_SetTarget или Npc_GetNextTarget.
    void AI_FinishingMove (c_npc self, c_npc other); - логическое завершение операции приближения (поворота) НПС self к НПС other.
    void AI_Defend (c_npc self); - НПС self парирует удар противника (защищается). Выполняется только во время атаки противника.
    void AI_Flee (c_npc self); - НПС self убегает от противника (эта функция должна вызываться внутри ZS_Loop). Предварительно функцией Npc_SetTarget должна быть установлена внутренняя цель, от которой НПС self должен убежать.
    void AI_AimAt (c_npc attacker, c_npc target); - НПС attacker целится из оружия дальнего радиуса поражения в НПС target.
    void AI_StopAim (c_npc attacker); - НПС attacker прекращает целиться из оружия дальнего радиуса поражения.
    void AI_ShootAt (c_npc attacker, c_npc target); - НПС attacker стреляет из оружия дальнего радиуса поражения в НПС target.
    void AI_CombatReactToDamage (c_npc self); - реакция НПС self на повреждение во время боя.***
    void AI_LookForItem (c_npc self, int instance); - функция показывает определенный предмет instance, который имеется у НПС self. (Например: золотой меч разрушения).
    void AI_EquipBestMeleeWeapon (c_npc self); - в инвентаре НПС self ищется самое лучшее оружие ближнего радиуса поражения и вешается на пояс.
    void AI_EquipBestRangedWeapon (c_npc self); - в инвентаре НПС self ищется самое лучшее оружие дальнего радиуса поражения и вешается на спину.
    void AI_EquipBestArmor (c_npc self); - в инвентаре НПС self ищутся и одеваются самые лучшие доспехи.
    void AI_UnequipWeapons (c_npc self); - все экипированное оружие НПС self убирается в инвентарь.
    void AI_UnequipArmor (c_npc self); - одетые доспехи НПС self убираются в инвентарь.
    void AI_EquipArmor (c_npc self, int armor); - НПС self одевает доспехи armor, которые должны находиться в его инвентаре.***
    void AI_ReadySpell (c_npc self, int spellID, int investMana); - НПС self берет в руку заклинание spellID со стоимостью маны investMana.
    void AI_UnreadySpell (c_npc self); - НПС self прячет в инвентарь заклинание, которое имеет в руке.
    void AI_Output (c_npc self, c_npc target, string outputName); - данная функция реализует диалог, НПС self говорит фразу outputName для НПС target. Текст фразы должен располагаться в скриптах в виде комментария к функции. (например: AI_Output () //текст фразы).
    void AI_OutputSVM (c_npc self, c_npc target, string svmname); - данная функция реализует SVM (Standart Voice Module) диалог, НПС self говорит фразу svmname для НПС target. Текст фразы должен располагаться в скриптах в файле svm.d (в одном из соответствующих SVM_ модулей) в виде комментария к строке с именем svmname. (например: StopMagic = svmname; //текст фразы).
    void AI_OutputSVM_Overlay (c_npc self, c_npc target, string svmname); -выполняется аналогично предыдущей функции, фраза выдается быстро, нет ожидания при разговоре следующей AI_ команды. Используется для комментариев перед сражением и во время сражения.
    void AI_WaitTillEnd (c_npc self, c_npc other); - НПС self ждет от НПС other ответа на свою фразу. (Не выполняется перед функцией AI_OutputSVM_Overlay).
    void AI_Ask (c_npc self, func answerYes, func answerNo); - определяет, как НПС self будет отвечать на сказанную фразу, при выборе ответа «Да» - выполняется функция answerYes, иначе – функция answerNo. Эти функции должны быть описаны заранее.
    void AI_AskText (c_npc self, func funcYes, func funcNo, string strYes, string strNo); - работает аналогично предыдущей функции, только для вариантов ответов (кроме функций) могут быть заданы фразы ответов strYes, strNo.
    void AI_WaitForQuestion (c_npc self, func scriptFunc); - НПС self ждет ответа или вопроса в течение 20 секунд, если в это время он поступает, то выполняется функция scriptFunc.
    void AI_ProcessInfos (c_npc self); - эта функция запускает диалог для НПС self с возможностью выбора вариантов ответов/вопросов.***
    void AI_StopProcessInfos (c_npc npc); - режим диалога НПС npc, начатый предыдущей функцией, заканчивается.
    void AI_StartState (c_npc self, func what, int stateBehaviour, string wpName); - переводит НПС self в соответствующее состояние, описанное функцией what, где stateBehaviour = 0 – выполняется последовательность состояний, 1 – выполняется только функция конечного состояния, wpName – имя WP точки (если "", то состояние изменяется на месте расположения НПС).
    void AI_SetNpcsToState (c_npc self, func aiStateFunc, int radius); - переводит всех НПС, находящихся от НПС self на расстоянии radius сантиметров, в соответствующее состояние, описанное функцией aiStateFunc.
    void AI_ContinueRoutine (c_npc self); - продолжает выполнение распорядка дня НПС self.
     
    Последнее редактирование: 10 дек 2014
  7. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Тема седьмая: Встроенные функции Готики 2.

    В основном в Готике 2 используются функции Готики 1, но есть несколько дополнительных функций, их мы и рассмотрим.
    int AI_PrintScreen (string msg, int posx, int posy, string font, int timeSec); - выводит на экран строку текста msg (имя шрифта – font) с координатами posx, posy (диапазон от 0 до 99% размера экрана, -1 означает вывод по центру соответствующей оси экрана) на время timeSec (в секундах).
    void AI_Snd_Play (c_npc self, string s0); - воспроизвести звуковой файл с именем s0 для НПС self.
    void AI_Snd_Play3D (c_npc self, c_npc n0, string s0); - воспроизвести звуковой файл с именем s0 для НПС self.
    void AI_PlayFX (c_npc self, c_npc n0, string s0); - воспроизвести видео-файл с именем s0 для НПС self.
    void AI_StopFX (c_npc self, string s0); - остановить воспроизведение видео-файла с именем s0 для НПС self.
    int PlayVideoEx (string video, int aa, int bb); - показать видео файл video (c расширением BIK), возвращает 1, если видео показано, 0 – в случае ошибки. Трактование параметров aa и bb не знаю, в скриптах они имеют значение TRUE и FALSE.
    void ExitSession () – используется вместо функции ExitGame (), хотя она тоже сохранена.
    int GameInitGerman () – просто всегда возвращает 1.
    В английской версии экзешника еще есть функции - int GameInitEnglish () и int GameInitEngintl (), их назначение мне неизвестно.
    int Wld_DetectNpcExAtt (c_npc self, int instance, func aiState, int guild, int detectPlayer, int xxx); - эта функция инициализирует глобальную переменную скриптов other, отличную от НПС self, где instance – производная от класса c_npc, которая должна быть найдена и проинициализирована (-1 – любая производная), guild – гильдия, членом которой должен быть искомый НПС (-1 – любая гильдия), aiState – функция AI состояния, в котором должен находится искомый НПС (NOFUNC – любое AI состояние). Функция возвращает 1 в случае успешного завершения (other инициализирован найденным НПС), 0 – неудача (other не определен), параметр detectPlayer указывает, исключить ли игрока (ГГ) из поиска (0 – исключить, 1 – нет). В этой функции, по сравнению с Wld_DetectNpcEx, добавлен параметр ххх, к сожалению мне про него ничего не известно (возможно это какой-нибудь атрибут).
    int Wld_IsRaining (); – возвращает 1, если идет дождь, иначе – 0.
    void Wld_StopEffect (string name); - останавливает проигрывание эффекта с именем name, запущенного функцией Wld_PlayEffect.
    void Doc_SetLevelCoords (int Document, int Left, int Top, int Right, int Bottom); - устанавливает границы области, отображаемой на карте (границы задаются в абсолютных координатах уровня), где: Document – обрабатываемый документ, Left, Top, Right и Bottom – задаваемые границы.
    int Npc_GetLastHitSpellID (c_npc self); - возвращает номер заклинания, которое НПС self применил последним.
    int Npc_GetLastHitSpellCat (c_npc self); - возвращает категорию заклинания, которое НПС self применил последним.
    int Npc_GetActiveSpellIsScroll (c_npc self); - проверяет, является ли активное заклинание у НПС self свитком, если да – возвращает 1, иначе – 0.
    void Npc_ClearInventory (c_npc self); - очищает весь инвентарь у НПС self.
    int Npc_GetHeightToNpc (c_npc npc1, c_npc npc2); - возвращает расстояние в см. по высоте между НПС npc1 и npc2.
    int Npc_GetHeightToItem (c_npc self, c_item item); - возвращает расстояние в см. по высоте между НПС self и предметом item.
    c_npc Npc_GetLookAtTarget (c_npc self); - инициализирует глобальную переменную target ссылкой на НПС, на которого смотрит НПС self.
    void Npc_StopAni (c_npc self, string name); - остановить проигрывание файла анимации с именем name для НПС self.
    int Npc_IsDrawingWeapon (c_npc self); - возвращает номер оружия, которое НПС self держит в руках, иначе – 0.
    int Npc_IsDrawingSpell (c_npc self); - возвращает номер заклинания, которое применяет НПС self, иначе – 0.
    int Npc_IsInPlayersRoom (c_npc self); - возвращает 1, если НПС self находится в помещении, которое принадлежит ГГ, иначе – 0.
    c_npc Npc_GetPortalOwner (c_npc self); - возвращает НПС-владельца помещения (области), в котором находится НПС self.
    int Npc_GetPortal Guild (c_npc self); - возвращает номер гильдии владельца помещения (области), в котором находится НПС self.
     
  8. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Уроки скриптологии, часть 2.
    Тема первая: Глобальные константы.

    Практически все глобальные константы описаны в файле ..\_intern\constants.d
    // Шрифты для функции PrintScreen
    Открыть спойлер
    const string FONT_Screen = "FONT_OLD_20_WHITE.TGA"; //обычный экранный шрифт
    const string FONT_ScreenSmall = "FONT_OLD_10_WHITE.TGA"; //мелкий экранный шрифт
    const string FONT_Book = "FONT_10_BOOK.TGA"; //шрифт текста документов
    const string FONT_BookHeadline = "FONT_20_BOOK.TGA"; //шрифт заголовков документов

    // Стоимость маны для всех свитков заклинаний
    const int SPL_Cost_Scroll = 5;
    // Индексы атрибутов НПС
    Открыть спойлер
    const int ATR_HITPOINTS = 0; //Текущая жизнь
    const int ATR_HITPOINTS_MAX = 1; //Макс. жизнь
    const int ATR_MANA = 2; //Текущая мана
    const int ATR_MANA_MAX = 3; //Макс. мана
    const int ATR_STRENGTH = 4; //Сила
    const int ATR_DEXTERITY = 5; //Ловкость
    const int ATR_REGENERATEHP = 6; //Регенерация жизни в секунду
    const int ATR_REGENERATEMANA = 7; //Регенерация маны в секунду
    const int ATR_INDEX_MAX = 8; //Макс. размерность массива атрибутов НПС

    // Флаги НПС
    Открыть спойлер
    const int NPC_FLAG_FRIEND = 1 << 0; //Друг (не используется, заменен на aivar[])
    const int NPC_FLAG_IMMORTAL = 1 << 1; //Неуязвимый
    const int NPC_FLAG_GHOST = 1 << 2; //Полупрозрачный (эквивалентен флагу 'GhostAlpha' в Gothic.ini секция [INTERNAL])

    // Режимы борьбы
    Открыть спойлер
    const int FMODE_NONE = 0; //Выключен
    const int FMODE_FIST = 1; //Кулачный бой
    const int FMODE_MELEE = 2; //Оружие ближнего радиуса поражения
    const int FMODE_FAR = 5; //Оружие дальнего радиуса поражения
    const int FMODE_MAGIC = 7; //Магия

    // Режимы передвижения
    Открыть спойлер
    const int NPC_RUN = 0; //Бег
    const int NPC_WALK = 1; //Ходьба
    const int NPC_SNEAK = 2; //Подкрадывание
    const int NPC_RUN_WEAPON = 0 + 128; //Бег с оружием
    const int NPC_WALK_WEAPON = 1 + 128; //Ходьба с оружием
    const int NPC_SNEAK_WEAPON = 2 + 128; //Подкрадывание с оружием

    // Флаги брони
    Открыть спойлер
    const int WEAR_TORSO = 1; //Верхняя часть туловища (Доспехи)
    const int WEAR_HEAD = 2; //Голова (Шлем)
    const int WEAR_EFFECT = 16; //Оказывает эффект при ношении

    // Категории инвентаря
    Открыть спойлер
    const int INV_WEAPON = 1; //Оружие
    const int INV_ARMOR = 2; //Броня
    const int INV_RUNE = 3; //Руны
    const int INV_MAGIC = 4; //Магия
    const int INV_FOOD = 5; //Продукты питания
    const int INV_POTION = 6; //Напитки
    const int INV_DOC = 7; //Документы
    const int INV_MISC = 8; //Разное
    const int INV_CAT_MAX = 9; //Макс. размерность категорий инвентаря

    // Вместимость инвентаря (программой игнорируется, инвентарь неограниченный!)
    Открыть спойлер
    const int INV_MAX_WEAPONS = 6;
    const int INV_MAX_ARMORS = 2;
    const int INV_MAX_RUNES = 1000;
    const int INV_MAX_FOOD = 15;
    const int INV_MAX_DOCS = 1000;
    const int INV_MAX_POTIONS = 1000;
    const int INV_MAX_MAGIC = 1000;
    const int INV_MAX_MISC = 1000;

    // Кол-во строк текста описания предметов
    const int ITM_TEXT_MAX = 6;
    // Флаги предметов
    // (категории)

    Открыть спойлер
    const int ITEM_KAT_NONE = 1 << 0; //Прочее
    const int ITEM_KAT_NF = 1 << 1; //Оружие ближнего радиуса поражения
    const int ITEM_KAT_FF = 1 << 2; //Оружие дальнего радиуса поражения
    const int ITEM_KAT_MUN = 1 << 3; //Боеприпасы (мульти)
    const int ITEM_KAT_ARMOR = 1 << 4; //Броня
    const int ITEM_KAT_FOOD = 1 << 5; //Продукты питания (мульти)
    const int ITEM_KAT_DOCS = 1 << 6; //Документы
    const int ITEM_KAT_POTIONS = 1 << 7; //Напитки
    const int ITEM_KAT_LIGHT = 1 << 8; //Источники света
    const int ITEM_KAT_RUNE = 1 << 9; //Руны/Свитки заклинаний
    const int ITEM_KAT_MAGIC = 1 << 31; //Кольца/Амулеты/Пояса
    const int ITEM_KAT_KEYS = ITEM_KAT_NONE; //Ключи

    // (типы оружия)
    Открыть спойлер
    const int ITEM_DAG = 1 << 13; //Клинок (не используется)
    const int ITEM_SWD = 1 << 14; //Меч
    const int ITEM_AXE = 1 << 15; //Топор
    const int ITEM_2HD_SWD = 1 << 16; //Друручный меч
    const int ITEM_2HD_AXE = 1 << 17; //Двуручный топор
    const int ITEM_SHIELD = 1 << 18; //Щит (не используется)
    const int ITEM_BOW = 1 << 19; //Лук
    const int ITEM_CROSSBOW = 1 << 20; //Арбалет

    // (типы магических предметов)
    Открыть спойлер
    const int ITEM_RING = 1 << 11; //Кольцо
    const int ITEM_AMULET = 1 << 22; //Амулет
    const int ITEM_BELT = 1 << 24; //Пояс

    // (атрибуты предметов)
    Открыть спойлер
    const int ITEM_DROPPED = 1 << 10; //Выброшенный предмет (внутренний флаг!)
    const int ITEM_MISSION = 1 << 12; //Предмет миссии
    const int ITEM_MULTI = 1 << 21; //Складываемый по несколько штук
    const int ITEM_NFOCUS = 1 << 23; //Не в фокусе (внутренний флаг!)
    const int ITEM_CREATEAMMO = 1 << 25; //Боеприпасы производятся сами (магически)
    const int ITEM_NSPLIT = 1 << 26; //Неделимый предмет
    const int ITEM_DRINK = 1 << 27; //Можно пить (не используется)
    const int ITEM_TORCH = 1 << 28; //Факел
    const int ITEM_THROW = 1 << 29; //Можно бросить (не используется)
    const int ITEM_ACTIVE = 1 << 30; //Активный (внутренний флаг!)

    // Типы наносимых повреждений
    Открыть спойлер
    const int DAM_INVALID = 0; //(применения не нашел)
    const int DAM_BARRIER = 1; //(применения не нашел)
    const int DAM_BLUNT = DAM_BARRIER << 1; //Повреждение тупым оружием (молоты, дубины, кулаки)
    const int DAM_EDGE = DAM_BLUNT << 1; //Повреждение острым оружием (мечи, шпаги, топоры)
    const int DAM_FIRE = DAM_EDGE << 1; //Повреждение огнем
    const int DAM_FLY = DAM_FIRE << 1; //Повреждение нокаутом (после удара НПС отлетает и падает)
    const int DAM_MAGIC = DAM_FLY << 1; //Повреждение магией
    const int DAM_POINT = DAM_MAGIC << 1; //Точечное повреждение (луки, арбалеты)
    const int DAM_FALL = DAM_POINT << 1; //Повреждение от падения

    // Индексы значений массива наносимых повреждений (имена индексов соответствуют именам типов)
    Открыть спойлер
    const int DAM_INDEX_BARRIER = 0;
    const int DAM_INDEX_BLUNT = DAM_INDEX_BARRIER + 1;
    const int DAM_INDEX_EDGE = DAM_INDEX_BLUNT + 1;
    const int DAM_INDEX_FIRE = DAM_INDEX_EDGE + 1;
    const int DAM_INDEX_FLY = DAM_INDEX_FIRE + 1;
    const int DAM_INDEX_MAGIC = DAM_INDEX_FLY + 1;
    const int DAM_INDEX_POINT = DAM_INDEX_MAGIC + 1;
    const int DAM_INDEX_FALL = DAM_INDEX_POINT + 1;
    const int DAM_INDEX_MAX = DAM_INDEX_FALL + 1; //Макс. размерность массива наносимых повреждений

    // Другие константы наносимых повреждений
    Открыть спойлер
    const int NPC_ATTACK_FINISH_DISTANCE = 180; //???
    const int NPC_BURN_TICKS_PER_DAMAGE_POINT = 1000; //???
    const int NPC_BURN_DAMAGE_POINTS_PER_INTERVALL = 50; //???
    const int DAM_CRITICAL_MULTIPLIER = 2; //Коэффициент умножения для критического повреждения (не употребляется)
    const int BLOOD_SIZE_DIVISOR = 1000; //???
    const int BLOOD_DAMAGE_MAX = 200; //???
    const int DAMAGE_FLY_CM_MAX = 2000; //???
    const int DAMAGE_FLY_CM_MIN = 300; //???
    const int DAMAGE_FLY_CM_PER_POINT = 5; //???
    const int NPC_DAM_DIVE_TIME = 100; //???
    const int IMMUNE = -1; //Иммунитет к повреждению

    // На каком расстоянии НПС перестают сражаться
    // Коэффициент к дистанции (BASE + дистанция поражения оружием)

    const float NPC_COLLISION_CORRECTION_SCALER = 0.75;
    // Типы защиты (имена соответствуют типам наносимых повреждений)
    Открыть спойлер
    const int PROT_BARRIER = DAM_INDEX_BARRIER;
    const int PROT_BLUNT = DAM_INDEX_BLUNT;
    const int PROT_EDGE = DAM_INDEX_EDGE;
    const int PROT_FIRE = DAM_INDEX_FIRE;
    const int PROT_FLY = DAM_INDEX_FLY;
    const int PROT_MAGIC = DAM_INDEX_MAGIC;
    const int PROT_POINT = DAM_INDEX_POINT;
    const int PROT_FALL = DAM_INDEX_FALL;
    const int PROT_INDEX_MAX = DAM_INDEX_MAX; //Макс. размерность массива защиты

    // Активные восприятия
    Открыть спойлер
    const int PERC_ASSESSPLAYER = 1; //Восприятие ГГ
    const int PERC_ASSESSENEMY = 2; //Восприятие врага
    const int PERC_ASSESSFIGHTER = 3; //Восприятие в сражении
    const int PERC_ASSESSBODY = 4; //Восприятие тела
    const int PERC_ASSESSITEM = 5; //Восприятие предмета

    // Чувства
    Открыть спойлер
    const int SENSE_SEE = 1 << 0; //Зрение
    const int SENSE_HEAR = 1 << 1; //Слух
    const int SENSE_SMELL = 1 << 2; //Обоняние

    // Пассивные восприятия
    Открыть спойлер
    const int PERC_ASSESSMURDER = 6; //Восприятие убийства
    const int PERC_ASSESSDEFEAT = 7; //Восприятие поражения
    const int PERC_ASSESSDAMAGE = 8; //Восприятие повреждения
    const int PERC_ASSESSOTHERSDAMAGE = 9; //Восприятие других повреждений
    const int PERC_ASSESSTHREAT = 10; //Восприятие угрозы
    const int PERC_ASSESSREMOVEWEAPON = 11; //Восприятие от "зачехления" оружия
    const int PERC_OBSERVEINTRUDER = 12; //Восприятие наблюдения злоумышленника
    const int PERC_ASSESSFIGHTSOUND = 13; //Восприятие звука сражения
    const int PERC_ASSESSQUIETSOUND = 14; //Восприятие тихих звуков
    const int PERC_ASSESSWARN = 15; //Восприятие предупреждения
    const int PERC_CATCHTHIEF = 16; //Восприятие выгоды воровства
    const int PERC_ASSESSTHEFT = 17; //Восприятие воровства
    const int PERC_ASSESSCALL = 18; //Восприятие обращения (речь)
    const int PERC_ASSESSTALK = 19; //Восприятие разговора
    const int PERC_ASSESSGIVENITEM = 20; //Восприятие торговли
    const int PERC_ASSESSFAKEGUILD = 21; //Восприятие "поддельной гильдии" (посылается при превращении НПС)
    const int PERC_MOVEMOB = 22; //Восприятие передвижения объекта (не НПС)
    const int PERC_MOVENPC = 23; //Восприятие передвижения НПС
    const int PERC_DRAWWEAPON = 24; //Восприятие вытаскивания оружия
    const int PERC_OBSERVESUSPECT = 25; //Восприятие наблюдения подозреваемого
    const int PERC_NPCCOMMAND = 26; //Восприятие команды НПС
    const int PERC_ASSESSMAGIC = 27; //Восприятие магии
    const int PERC_ASSESSSTOPMAGIC = 28; //Восприятие прекращения колдовства
    const int PERC_ASSESSCASTER = 29; //Восприятие колдующего (посылается при изменении маны)
    const int PERC_ASSESSSURPRISE = 30; //Восприятие неожиданности
    const int PERC_ASSESSENTERROOM = 31; //Восприятие входа в помещение (область)
    const int PERC_ASSESSUSEMOB = 32; //Восприятие использования объекта (открытие двери, сундука)

    // Способы распространения новостей
    Открыть спойлер
    const int NEWS_DONT_SPREAD = 0; //Новости не распространяются
    const int NEWS_SPREAD_NPC_FRIENDLY_TOWARDS_VICTIM = 1; //Друзьями жертвы
    const int NEWS_SPREAD_NPC_FRIENDLY_TOWARDS_WITNESS = 2; //Друзьями свидетеля
    const int NEWS_SPREAD_NPC_FRIENDLY_TOWARDS_OFFENDER = 3; //Друзьями обидчика
    const int NEWS_SPREAD_NPC_SAME_GUILD_VICTIM = 4; //Гильдией жертвы

    // Константы новостей
    const int IMPORTANT = 1; //Важная новость
    // Статусы информации

    const int INF_TELL = 0; //Сказанная информация
    const int INF_UNKNOWN = 2; //Источник информации неизвестен
    // Статусы миссий

    Открыть спойлер
    const int LOG_RUNNING = 1; //Миссия выполняется
    const int LOG_SUCCESS = 2; //Миссия успешно завершена
    const int LOG_FAILED = 3; //Миссия провалена
    const int LOG_OBSOLETE = 4; //Миссия завершена в другом направлении (был выбор вариантов завершения)

    // Отношения
    Открыть спойлер
    const int ATT_FRIENDLY = 3; //Друг
    const int ATT_NEUTRAL = 2; //Нейтральный
    const int ATT_ANGRY = 1; //Сердитый, злой
    const int ATT_HOSTILE = 0; //Враг

    // Гильдии
    Открыть спойлер
    const int GIL_NONE = 0; //Отсутствует
    const int GIL_HUMAN = 1; //Люди (специальная гильдия, набор констант для этой гильдии описан в файле Species.d)
    const int GIL_PAL = 1; //Паладины
    const int GIL_MIL = 2; //Милиционеры
    const int GIL_VLK = 3; //Горожане
    const int GIL_KDF = 4; //Маги огня
    const int GIL_NOV = 5; //Маги послушники
    const int GIL_DJG = 6; //Охотники на драконов
    const int GIL_SLD = 7; //Ополчение
    const int GIL_BAU = 8; //Крестьяне
    const int GIL_BDT = 9; //Бандиты
    const int GIL_STRF = 10; //Заключенные
    const int GIL_DMT = 11; //Черные маги
    const int GIL_OUT = 12; //Чужеземцы
    const int GIL_PIR = 13; //Пираты
    const int GIL_KDW = 14; //Маги воды
    const int GIL_EMPTY_D = 15; //(пусто)

    //-----------------------------------------------
    const int GIL_PUBLIC = 15; //Публичная гильдия
    //-----------------------------------------------

    Открыть спойлер
    const int GIL_SEPERATOR_HUM = 16; //Разделитель между людьми и животными
    const int GIL_MEATBUG = 17; //Мясной жук
    const int GIL_SHEEP = 18; //Овца
    const int GIL_GOBBO = 19; //Гоблин / Черный гоблин
    const int GIL_GOBBO_SKELETON = 20; //Скелет гоблина
    const int GIL_SUMMONED_GOBBO_SKELETON = 21; //Вызванный Скелет гоблина
    const int GIL_SCAVENGER = 22; //Падальщик / Зубастик
    const int GIL_GIANT_RAT = 23; //Крыса
    const int GIL_GIANT_BUG = 24; //Полевой жук
    const int GIL_BLOODFLY = 25; //Кровяной шершень
    const int GIL_WARAN = 26; //Ящерица / Огненная ящерица
    const int GIL_WOLF = 27; //Волк / Варг
    const int GIL_SUMMONED_WOLF = 28; //Вызванный Волк
    const int GIL_MINECRAWLER = 29; //Ползун / Воин ползунов
    const int GIL_LURKER = 30; //Шныг
    const int GIL_SKELETON = 31; //Скелет
    const int GIL_SUMMONED_SKELETON = 32; //Вызванный Скелет
    const int GIL_SKELETON_MAGE = 33; //Маг скелетов
    const int GIL_ZOMBIE = 34; //Зомби
    const int GIL_SNAPPER = 35; //Глорх / Остер / Расчленитель
    const int GIL_SHADOWBEAST = 36; //Мракорис
    const int GIL_SHADOWBEAST_SKELETON = 37; //Скелет мракориса
    const int GIL_HARPY = 38; //Гарпия
    const int GIL_STONEGOLEM = 39; //Каменный голем
    const int GIL_FIREGOLEM = 40; //Огненный голем
    const int GIL_ICEGOLEM = 41; //Ледяной голем
    const int GIL_SUMMONED_GOLEM = 42; //Вызванный Голем
    const int GIL_DEMON = 43; //Демон / Лорд демонов
    const int GIL_SUMMONED_DEMON = 44; //Вызванный Демон
    const int GIL_TROLL = 45; //Троль / Черный троль
    const int GIL_SWAMPSHARK = 46; //Болотожор
    const int GIL_DRAGON = 47; //Дракон
    const int GIL_MOLERAT = 48; //Кротокрыс
    const int GIL_ALLIGATOR = 49; //Алигатор
    const int GIL_SWAMPGOLEM = 50; //Болотный голем
    const int GIL_Stoneguardian = 51; //Каменный сторож
    const int GIL_Gargoyle = 52; //Пантера / Огненный дух мракориса
    const int GIL_Empty_A = 53; //(пусто)
    const int GIL_SummonedGuardian = 54; //Вызванный Каменный сторож
    const int GIL_SummonedZombie = 55; //Вызванный Зомби
    const int GIL_EMPTY_B = 56; //(пусто)
    const int GIL_EMPTY_C = 57; //(пусто)
    const int GIL_SEPERATOR_ORC = 58; //Разделитель животных от орков
    const int GIL_ORC = 59; //Орк / Шаман орков / Воин орков
    const int GIL_FRIENDLY_ORC = 60; //Ур-Шак
    const int GIL_UNDEADORC = 61; //Орк нежить
    const int GIL_DRACONIAN = 62; //Ящер
    const int GIL_EMPTY_X = 63; //(пусто)
    const int GIL_EMPTY_Y = 64; //(пусто)
    const int GIL_EMPTY_Z = 65; //(пусто)
    const int GIL_MAX = 66; //Макс. количество гильдий

    // Класс описания гильдий
    Открыть спойлер
    class c_gilvalues
    {
    var int WATER_DEPTH_KNEE [GIL_MAX]; //Глубина воды до колена
    var int WATER_DEPTH_CHEST [GIL_MAX]; //Глубина воды до груди
    var int JUMPUP_HEIGHT [GIL_MAX]; //Высота прыжка
    // var int JUMPUP_FORCE [GIL_MAX];

    var int SWIM_TIME [GIL_MAX]; //Время плавания
    var int DIVE_TIME [GIL_MAX]; //Время пребывания под водой
    var int STEP_HEIGHT [GIL_MAX]; //Ширина шага
    var int JUMPLOW_HEIGHT [GIL_MAX]; //Высота низкого прыжка
    var int JUMPMID_HEIGHT [GIL_MAX]; //Высота среднего прыжка
    var int SLIDE_ANGLE [GIL_MAX]; //Угол начала скольжения на наклонной плоскости
    var int SLIDE_ANGLE2 [GIL_MAX]; //???
    var int DISABLE_AUTOROLL [GIL_MAX]; //???
    var int SURFACE_ALIGN [GIL_MAX]; //???
    var int CLIMB_HEADING_ANGLE [GIL_MAX]; //Какие-то углы подъема
    var int CLIMB_HORIZ_ANGLE [GIL_MAX]; //
    var int CLIMB_GROUND_ANGLE [GIL_MAX]; //
    var int FIGHT_RANGE_BASE [GIL_MAX]; //Какие-то диапазоны борьбы
    var int FIGHT_RANGE_FIST [GIL_MAX]; //
    var int FIGHT_RANGE_G [GIL_MAX]; //
    var int FIGHT_RANGE_1HS [GIL_MAX]; //
    var int FIGHT_RANGE_1HA [GIL_MAX]; //
    var int FIGHT_RANGE_2HS [GIL_MAX]; //
    var int FIGHT_RANGE_2HA [GIL_MAX]; //
    var int FALLDOWN_HEIGHT [GIL_MAX]; //Высота падения без повреждения
    var int FALLDOWN_DAMAGE [GIL_MAX]; //Повреждение от падения с высоты
    var int BLOOD_DISABLED [GIL_MAX]; //Уровень показа крови
    var int BLOOD_MAX_DISTANCE [GIL_MAX]; //Макс. радиус брызг крови в см.
    var int BLOOD_AMOUNT [GIL_MAX]; //Количество крови
    var int BLOOD_FLOW [GIL_MAX]; //???
    var string BLOOD_EMITTER [GIL_MAX]; //Источник крови
    var string BLOOD_TEXTURE [GIL_MAX]; //Текстура крови
    var int TURN_SPEED [GIL_MAX]; //Скорость разворота
    };

    // Типы звуков
    Открыть спойлер
    const int NPC_SOUND_DROPTAKE = 1; //Звук капель
    const int NPC_SOUND_SPEAK = 3; //Звук разговора
    const int NPC_SOUND_STEPS = 4; //Звук шагов
    const int NPC_SOUND_THROWCOLL = 5; //Звук летящей стрелы, болта
    const int NPC_SOUND_DRAWWEAPON = 6; //Звук доставаемого оружия
    const int NPC_SOUND_SCREAM = 7; //Звук крика
    const int NPC_SOUND_FIGHT = 8; //Звук сражения

    // Типы материалов
    Открыть спойлер
    const int MAT_WOOD = 0; //Деревянный
    const int MAT_STONE = 1; //Каменный
    const int MAT_METAL = 2; //Металлический
    const int MAT_LEATHER = 3; //Кожаный
    const int MAT_CLAY = 4; //Глиняный
    const int MAT_GLAS = 5; //Стеклянный

    // Записи дневника
    Открыть спойлер
    const int LOG_MISSION = 0; //Миссии
    const int LOG_NOTE = 1; //Заметки

    // Другие константы
    Открыть спойлер
    const int TIME_INFINITE = -1000000 / 1000; //Бесконечное время ???
    const int NPC_VOICE_VARIATION_MAX = 10; //Макс. кол-во голосов НПС
    const float TRADE_VALUE_MULTIPLIER = 0.15; //Коэффициент стоимости предмета, которую платит торговец
    const string TRADE_CURRENCY_INSTANCE = "ITMI_GOLD"; //Имя валюты для расчетов

    //************************************
    // Заклинания
    //************************************
    // Константы категорий

    Открыть спойлер
    const int SPELL_GOOD = 0; //Хорошее
    const int SPELL_NEUTRAL = 1; //Нейтральное
    const int SPELL_BAD = 2; //Плохое

    // Константы управления
    Открыть спойлер
    const int SPL_DONTINVEST = 0; //Дальнейшее инвестирование маны на зарядку заклинания невозможно (мало или нет маны)
    const int SPL_RECEIVEINVEST = 1; //Нужное количество маны израсходовано на зарядку (заклинание готово к действию)
    const int SPL_SENDCAST = 2; //Старт заклинания с действием
    const int SPL_SENDSTOP = 3; //Заклинание заканчивается без эффекта (мало маны)
    const int SPL_NEXTLEVEL = 4; //Переход на следующий уровень зарядки заклинания
    const int SPL_STATUS_CANINVEST_NO_MANADEC = 8; //Инвестированного количества маны недостаточно для перехода на следующий уровень
    const int SPL_FORCEINVEST = 1 << 16; //Какой-то флаг управляющий инвестированием маны ???

    // Константы цели
    Открыть спойлер
    const int TARGET_COLLECT_NONE = 0; //Цель определяется самим заклинанием
    const int TARGET_COLLECT_CASTER = 1; //Цель - кастующий
    const int TARGET_COLLECT_FOCUS = 2; //Цель - визуальный объект в фокусе
    const int TARGET_COLLECT_ALL = 3; //Цель - все объекты в радиусе поражения
    const int TARGET_COLLECT_FOCUS_FALLBACK_NONE = 4; //Цель - визуальный объект в фокусе, при потере фокуса траектория устанавливается заклинанием
    const int TARGET_COLLECT_FOCUS_FALLBACK_CASTER = 5; //Цель - визуальный объект в фокусе, при потере фокуса целью становится кастующий
    const int TARGET_COLLECT_ALL_FALLBACK_NONE = 6; //Цель - все объекты в радиусе поражения, если объектов нет траектория устанавливается заклинанием
    const int TARGET_COLLECT_ALL_FALLBACK_CASTER = 7; //Цель - все объекты в радиусе поражения, если объектов нет целью становится кастующий
    const int TARGET_TYPE_ALL = 1; //Цель - все и всё
    const int TARGET_TYPE_ITEMS = 2; //Цель - предмет
    const int TARGET_TYPE_NPCS = 4; //Цель - НПС
    const int TARGET_TYPE_ORCS = 8; //Цель - орк
    const int TARGET_TYPE_HUMANS = 16; //Цель - человек
    const int TARGET_TYPE_UNDEAD = 32; //Цель - неуязвимый

    // Идентификаторы заклинаний (ID)
    // Руны Паладинов

    Открыть спойлер
    const int SPL_PalLight = 0; //Святой свет
    const int SPL_PalLightHeal = 1; //Малое лечение
    const int SPL_PalHolyBolt = 2; //Святая стрела
    const int SPL_PalMediumHeal = 3; //Среднее лечение
    const int SPL_PalRepelEvil = 4; //Разогнать дьяволов
    const int SPL_PalFullHeal = 5; //Сильное лечение
    const int SPL_PalDestroyEvil = 6; //Уничтожить дьяволов

    // Руны Телепортации
    Открыть спойлер
    const int SPL_PalTeleportSecret = 7; //Телепорт
    const int SPL_TeleportSeaport = 8; //Телепорт в гавань
    const int SPL_TeleportMonastery = 9; //Телепорт к монастырю
    const int SPL_TeleportFarm = 10; //Телепорт к помещику
    const int SPL_TeleportXardas = 11; //Телепорт к Ксардасу
    const int SPL_TeleportPassNW = 12; //Телепорт к проходу в Хоринисе
    const int SPL_TeleportPassOW = 13; //Телепорт к проходу в рудниковой долине
    const int SPL_TeleportOC = 14; //Телепорт в замок
    const int SPL_TeleportOWDemonTower = 15; //Телепорт в старую башню демонов
    const int SPL_TeleportTaverne = 16; //Телепорт к таверне
    const int SPL_Teleport_3 = 17; //(не используется)

    // Круг 1
    Открыть спойлер
    const int SPL_Light = 18; //Свет
    const int SPL_Firebolt = 19; //Огненная стрела
    const int SPL_LightHeal = 21; //Лечить легкое ранение
    const int SPL_SummonGoblinSkeleton = 22; //Вызвать скелет гоблина
    const int SPL_Zap = 24; //Молния

    // Круг 2
    Открыть спойлер
    const int SPL_Icebolt = 20; //Ледяная стрела
    const int SPL_InstantFireball = 23; //Огненный шар
    const int SPL_SummonWolf = 25; //Вызвать волка
    const int SPL_WindFist = 26; //Порыв ветра
    const int SPL_Sleep = 27; //Сон

    // Круг 3
    Открыть спойлер
    const int SPL_MediumHeal = 28; //Лечить среднее ранение
    const int SPL_LightningFlash = 29; //Удар молнии
    const int SPL_ChargeFireball = 30; //Большой огненный шар
    const int SPL_SummonSkeleton = 31; //Вызвать скелет
    const int SPL_Fear = 32; //Страх
    const int SPL_IceCube = 33; //Ледяная глыба

    // Круг 4
    Открыть спойлер
    const int SPL_ChargeZap = 34; //Шаровая молния
    const int SPL_SummonGolem = 35; //Вызвать голема
    const int SPL_DestroyUndead = 36; //Уничтожить нежить
    const int SPL_Pyrokinesis = 37; //Большая огненная буря (ошибка перевода ???)

    // Круг 5
    Открыть спойлер
    const int SPL_Firestorm = 38; //Малая огненная буря (ошибка перевода ???)
    const int SPL_IceWave = 39; //Ледяная волна
    const int SPL_SummonDemon = 40; //Вызвать демона
    const int SPL_FullHeal = 41; //Лечить сильное ранение

    // Круг 6
    Открыть спойлер
    const int SPL_Firerain = 42; //Огненный дождь
    const int SPL_BreathOfDeath = 43; //Дым смерти
    const int SPL_MassDeath = 44; //Волна смерти
    const int SPL_ArmyOfDarkness = 45; //Армия мрака
    const int SPL_Shrink = 46; //Уменьшить монстра

    // Свитки
    Открыть спойлер
    const int SPL_TrfSheep = 47; //Превращение в овцу
    const int SPL_TrfScavenger = 48; //Превращение в падальщика
    const int SPL_TrfGiantRat = 49; //Превращение в крысу
    const int SPL_TrfGiantBug = 50; //Превращение в полевого жука
    const int SPL_TrfWolf = 51; //Превращение в волка
    const int SPL_TrfWaran = 52; //Превращение в ящерицу
    const int SPL_TrfSnapper = 53; //Превращение в глорха
    const int SPL_TrfWarg = 54; //Превращение в варга
    const int SPL_TrfFireWaran = 55; //Превращение в огненную ящерицу
    const int SPL_TrfLurker = 56; //Превращение в шныга
    const int SPL_TrfShadowbeast = 57; //Превращение в мракориса
    const int SPL_TrfDragonSnapper = 58; //Превращение в остера
    const int SPL_Charm = 59; //Забыть

    // Круг 5
    const int SPL_MasterOfDisaster = 60; //Святой удар
    // ???

    Открыть спойлер
    const int SPL_Deathbolt = 61; //Стрела смерти
    const int SPL_Deathball = 62; //Шар смерти
    const int SPL_ConcussionBolt = 63; //Стрела сотрясения
    const int SPL_Reserved_64 = 64; //
    const int SPL_Reserved_65 = 65; //
    const int SPL_Reserved_66 = 66; //
    const int SPL_Reserved_67 = 67; //
    const int SPL_Reserved_68 = 68; //
    const int SPL_Reserved_69 = 69; //

    // Заклинания магов воды
    Открыть спойлер
    const int SPL_Thunderstorm = 70; //Шторм
    const int SPL_Whirlwind = 71; //Смерч
    const int SPL_WaterFist = 72; //Кулак воды
    const int SPL_IceLance = 73; //Ледяное копье
    const int SPL_Inflate = 74; //Раздуть
    const int SPL_Geyser = 75; //Гейзер
    const int SPL_Waterwall = 76; //Водяная стена
    const int SPL_Reserved_77 = 77;
    const int SPL_Reserved_78 = 78;
    const int SPL_Reserved_79 = 79;

    // Заклинания Майя
    Открыть спойлер
    const int SPL_Plague = 80; //Чума
    const int SPL_Swarm = 81; //Рой
    const int SPL_GreenTentacle = 82; //Зеленые щупальца
    const int SPL_Earthquake = 83; //Землетрясение
    const int SPL_SummonGuardian = 84; //Создать стража
    const int SPL_Energyball = 85; //Шар энергии
    const int SPL_SuckEnergy = 86; //Украсть энергию
    const int SPL_Skull = 87; //Крик мертвых
    const int SPL_SummonZombie = 88; //Создать зомби
    const int SPL_SummonMud = 89; //Вызвать Муда

    // ...
    Открыть спойлер
    const int SPL_Reserved_90 = 90;
    const int SPL_Reserved_91 = 91;
    const int SPL_Reserved_92 = 92;
    const int SPL_Reserved_93 = 93;
    const int SPL_Reserved_94 = 94;
    const int SPL_Reserved_95 = 95;
    const int SPL_Reserved_96 = 96;
    const int SPL_Reserved_97 = 97;
    const int SPL_Reserved_98 = 98;
    const int SPL_Reserved_99 = 99;
    const int MAX_SPELL = 100; //59 (Gothic),68 (Gothic2),100 (G2Addon)

    // Массив имен классов заклинаний
    Открыть спойлер
    const string spellFxInstanceNames[MAX_SPELL] =
    {
    "PalLight", // 0 SPL_PalLight
    "PalHeal", // 1 SPL_PalLightHeal
    "PalHolyBolt", // 2 SPL_PalHolyBolt
    "PalHeal", // 3 SPL_PalMediumHeal
    "PalRepelEvil", // 4 SPL_PalRepelEvil
    "PalHeal", // 5 SPL_PalFullHeal
    "PalDestroyEvil", // 6 SPL_PalDestroyEvil
    "Teleport", // 7 SPL_PalTeleportSecret
    "Teleport", // 8 SPL_TeleportSeaport
    "Teleport", // 9 SPL_TeleportMonastery
    "Teleport", // 10 SPL_TeleportFarm
    "Teleport", // 11 SPL_TeleportXardas
    "Teleport", // 12 SPL_TeleportPassNW
    "Teleport", // 13 SPL_TeleportPassOW
    "Teleport", // 14 SPL_TeleportOC
    "Teleport", // 15 SPL_TeleportOWDemonTower
    "Teleport", // 16 SPL_TeleportTaverne
    "Teleport", // 17 SPL_Teleport_3
    "Light", // 18 SPL_Light
    "Firebolt", // 19 SPL_Firebolt
    "Icebolt", // 20 SPL_Icebolt
    "Heal", // 21 SPL_LightHeal
    "SummonGoblinSkeleton", // 22 SPL_SummonGoblinSkeleton
    "InstantFireball", // 23 SPL_InstantFireball
    "Zap", // 24 SPL_Zap
    "SummonWolf", // 25 SPL_SummonWolf
    "WindFist", // 26 SPL_WindFist
    "Sleep", // 27 SPL_Sleep
    "Heal", // 28 SPL_MediumHeal
    "LightningFlash", // 29 SPL_LightningFlash
    "ChargeFireball", // 30 SPL_ChargeFireball
    "SummonSkeleton", // 31 SPL_SummonSkeleton
    "Fear", // 32 SPL_Fear
    "Icecube", // 33 SPL_IceCube
    "ChargeZap", // 34 SPL_ChargeZap
    "SummonGolem", // 53 SPL_SummonGolem
    "DestroyUndead", // 36 SPL_DestroyUndead
    "Pyrokinesis", // 37 SPL_Pyrokinesis
    "Firestorm", // 38 SPL_Firestorm
    "Icewave", // 39 SPL_IceWave
    "SummonDemon", // 40 SPL_SummonDemon
    "Heal", // 41 SPL_FullHeal
    "Firerain", // 42 SPL_Firerain
    "BreathOfDeath", // 43 SPL_BreathOfDeath
    "MassDeath", // 44 SPL_MassDeath
    "ArmyOfDarkness", // 45 SPL_ArmyOfDarkness
    "Shrink", // 46 SPL_Shrink
    "Transform", // 47 SPL_TrfSheep
    "Transform", // 48 SPL_TrfScavenger
    "Transform", // 49 SPL_TrfGiantRat
    "Transform", // 50 SPL_TrfGiantBug
    "Transform", // 51 SPL_TrfWolf
    "Transform", // 52 SPL_TrfWaran
    "Transform", // 53 SPL_TrfSnapper
    "Transform", // 54 SPL_TrfWarg
    "Transform", // 55 SPL_TrfFireWaran
    "Transform", // 56 SPL_TrfLurker
    "Transform", // 57 SPL_TrfShadowbeast
    "Transform", // 58 SPL_TrfDragonSnapper
    "Charm", // 59 SPL_Charm
    "MasterOfDisaster", // 60 SPL_MasterOfDisaster
    "Deathbolt", // 61 SPL_Deathbolt
    "Deathball", // 62 SPL_Deathball
    "Concussionbolt", // 63 SPL_Concussionbolt
    "Light", // 64 SPL_Reserved_64
    "Light", // 65 SPL_Reserved_65
    "Light", // 66 SPL_Reserved_66
    "Light", // 67 SPL_Reserved_67
    "Light", // 68 SPL_Reserved_68
    "Light", // 69 SPL_Reserved_69
    "Thunderstorm", // 70 SPL_Thunderstorm
    "Whirlwind", // 71 SPL_Whirlwind
    "Waterfist", // 72 SPL_WaterFist
    "IceLance", // 73 SPL_IceLance
    "Sleep", // 74 SPL_Inflate
    "Geyser", // 75 SPL_Geyser
    "Firerain", // 76 SPL_Waterwall
    "Light", // 77 SPL_Reserved_77
    "Light", // 78 SPL_Reserved_78
    "Light", // 79 SPL_Reserved_79
    "Fear", // 80 SPL_Plague
    "Swarm", // 81 SPL_Swarm
    "Greententacle", // 82 SPL_GreenTentacle
    "Firerain", // 83 SPL_Earthquake
    "SummonGuardian", // 84 SPL_SummonGuardian
    "Energyball", // 85 SPL_Energyball
    "SuckEnergy", // 86 SPL_SuckEnergy
    "Skull", // 87 SPL_Skull
    "SummonZombie", // 88 SPL_SummonZombie
    "SummonMud", // 89 SPL_SummonMud
    "Light", // 90 SPL_Reserved_90
    "Light", // 91 SPL_Reserved_91
    "Light", // 92 SPL_Reserved_92
    "Light", // 93 SPL_Reserved_93
    "Light", // 94 SPL_Reserved_94
    "Light", // 95 SPL_Reserved_95
    "Light", // 96 SPL_Reserved_96
    "Light", // 97 SPL_Reserved_97
    "Light", // 98 SPL_Reserved_98
    "Light" // 99 SPL_Reserved_99
    };

    // Массив имен анимаций заклинаний
    Открыть спойлер
    const string spellFxAniLetters[MAX_SPELL] =
    {
    "SLE", // 0 SPL_PalLight
    "HEA", // 1 SPL_PalLightHeal
    "FBT", // 2 SPL_PalHolyBolt
    "HEA", // 3 SPL_PalMediumHeal
    "FBT", // 4 SPL_PalRepelEvil
    "HEA", // 5 SPL_PalFullHeal
    "FIB", // 6 SPL_PalDestroyEvil
    "HEA", // 7 SPL_PalTeleportSecret
    "HEA", // 8 SPL_TeleportSeaport
    "HEA", // 9 SPL_TeleportMonastery
    "HEA", // 10 SPL_TeleportFarm
    "HEA", // 11 SPL_TeleportXardas
    "HEA", // 12 SPL_TeleportPassNW
    "HEA", // 13 SPL_TeleportPassOW
    "HEA", // 14 SPL_TeleportOC
    "HEA", // 15 SPL_TeleportOWDemonTower
    "HEA", // 16 SPL_TeleportTaverne
    "HEA", // 17 SPL_Teleport_3
    "SLE", // 18 SPL_Light
    "FBT", // 19 SPL_Firebolt
    "FBT", // 20 SPL_Icebolt
    "HEA", // 21 SPL_LightHeal
    "SUM", // 22 SPL_SummonGoblinSkeleton
    "FBT", // 23 SPL_InstantFireball
    "FBT", // 24 SPL_Zap
    "SUM", // 25 SPL_SummonWolf
    "WND", // 26 SPL_WindFist
    "SLE", // 27 SPL_Sleep
    "HEA", // 28 SPL_MediumHeal
    "WND", // 29 SPL_LightningFlash
    "FIB", // 30 SPL_ChargeFireball
    "SUM", // 31 SPL_SummonSkeleton
    "FEA", // 32 SPL_Fear
    "FRZ", // 33 SPL_IceCube
    "FIB", // 34 SPL_ChargeZap
    "SUM", // 35 SPL_SummonGolem
    "FIB", // 36 SPL_DestroyUndead
    "FIB", // 37 SPL_Pyrokinesis
    "FIB", // 38 SPL_Firestorm
    "FEA", // 39 SPL_IceWave
    "SUM", // 40 SPL_SummonDemon
    "HEA", // 41 SPL_FullHeal
    "FEA", // 42 SPL_Firerain
    "FIB", // 43 SPL_BreathOfDeath
    "MSD", // 44 SPL_MassDeath
    "SUM", // 45 SPL_ArmyOfDarkness
    "SLE", // 46 SPL_Shrink
    "TRF", // 47 SPL_TrfSheep
    "TRF", // 48 SPL_TrfScavenger
    "TRF", // 49 SPL_TrfGiantRat
    "TRF", // 50 SPL_TrfGiantBug
    "TRF", // 51 SPL_TrfWolf
    "TRF", // 52 SPL_TrfWaran
    "TRF", // 53 SPL_TrfSnapper
    "TRF", // 54 SPL_TrfWarg
    "TRF", // 55 SPL_TrfFireWaran
    "TRF", // 56 SPL_TrfLurker
    "TRF", // 57 SPL_TrfShadowbeast
    "TRF", // 58 SPL_TrfDragonSnapper
    "FIB", // 59 SPL_Charm
    "FIB", // 60 SPL_MasterOfDisaster
    "FBT", // 61 SPL_Deathbolt
    "FBT", // 62 SPL_Deathball
    "FBT", // 63 SPL_Concussionbolt
    "XXX", // 64 SPL_Reserved_64
    "XXX", // 65 SPL_Reserved_65
    "XXX", // 66 SPL_Reserved_66
    "XXX", // 67 SPL_Reserved_67
    "XXX", // 68 SPL_Reserved_68
    "XXX", // 69 SPL_Reserved_69
    "STM", // 70 SPL_Thunderstorm
    "WHI", // 71 SPL_Whirlwind
    "WND", // 72 SPL_WaterFist
    "FBT", // 73 SPL_IceLance
    "SLE", // 74 SPL_Inflate
    "WND", // 75 SPL_Geyser
    "FEA", // 76 SPL_Waterwall
    "XXX", // 77 SPL_Reserved_77
    "XXX", // 78 SPL_Reserved_78
    "XXX", // 79 SPL_Reserved_79
    "FBT", // 80 SPL_Plague
    "FBT", // 81 SPL_Swarm
    "FRZ", // 82 SPL_GreenTentacle
    "FEA", // 83 SPL_Earthquake
    "SUM", // 84 SPL_SummonGuardian
    "WND", // 85 SPL_Energyball
    "WND", // 86 SPL_SuckEnergy
    "WND", // 87 SPL_Skull
    "SUM", // 88 SPL_SummonZombie
    "SUM", // 89 SPL_SummonMud
    "XXX", // 90 SPL_Reserved_90
    "XXX", // 91 SPL_Reserved_91
    "XXX", // 92 SPL_Reserved_92
    "XXX", // 93 SPL_Reserved_93
    "XXX", // 94 SPL_Reserved_94
    "XXX", // 95 SPL_Reserved_95
    "XXX", // 96 SPL_Reserved_96
    "XXX", // 97 SPL_Reserved_97
    "XXX", // 98 SPL_Reserved_98
    "XXX" // 99 SPL_Reserved_99
    };

    // Таланты
    Открыть спойлер
    const int NPC_TALENT_UNKNOWN = 0; //Отсутствует
    const int NPC_TALENT_1H = 1; //Владение одноручным оружием
    const int NPC_TALENT_2H = 2; //Владение двуручным оружием
    const int NPC_TALENT_BOW = 3; //Владение луком
    const int NPC_TALENT_CROSSBOW = 4; //Владение арбалетом
    const int NPC_TALENT_PICKLOCK = 5; //Умение вскрывать замки

    //const int NPC_TALENT_PICKPOCKET = 6; //Карманная кража (из Готики 1, не используется)
    Открыть спойлер
    const int NPC_TALENT_MAGE = 7; //Маг
    const int NPC_TALENT_SNEAK = 8; //Подкрадывание
    const int NPC_TALENT_REGENERATE = 9; //Регенерация
    const int NPC_TALENT_FIREMASTER = 10; //Владение огнем
    const int NPC_TALENT_ACROBAT = 11; //Акробатика
    const int NPC_TALENT_PICKPOCKET = 12; //Карманная кража
    const int NPC_TALENT_SMITH = 13; //Кузнечное дело
    const int NPC_TALENT_RUNES = 14; //Изготовление рун
    const int NPC_TALENT_ALCHEMY = 15; //Алхимия
    const int NPC_TALENT_TAKEANIMALTROPHY = 16; //Разделка животных
    const int NPC_TALENT_FOREIGNLANGUAGE = 17; //Изучение иностранных языков
    const int NPC_TALENT_WISPDETECTOR = 18; //Поиск предметов
    const int NPC_TALENT_C = 19; //(пусто)
    const int NPC_TALENT_D = 20; //(пусто)
    const int NPC_TALENT_E = 21; //(пусто)
    const int NPC_TALENT_MAX = 22; //Макс. число талантов

    // Массив талантов изготовления рун
    var int PLAYER_TALENT_RUNES[MAX_SPELL];
    // Уровни знаний иностранных языков
    Открыть спойлер
    const int LANGUAGE_1 = 0;
    const int LANGUAGE_2 = 1;
    const int LANGUAGE_3 = 2;
    const int MAX_LANGUAGE = 3;
    var int PLAYER_TALENT_FOREIGNLANGUAGE[MAX_LANGUAGE];

    // Уровни поиска предметов
    Открыть спойлер
    const int WISPSKILL_NF = 0; //Поиск оружия ближнего радиуса поражения
    const int WISPSKILL_FF = 1; //Поиск оружия дальнего радиуса поражения
    const int WISPSKILL_NONE = 2; //Поиск денег, ключей, предметов обихода
    const int WISPSKILL_RUNE = 3; //Поиск рун и свитков
    const int WISPSKILL_MAGIC = 4; //Поиск колец и амулетов
    const int WISPSKILL_FOOD = 5; //Поиск питания и растений
    const int WISPSKILL_POTIONS = 6; //Поиск напитков всех видов
    const int MAX_WISPSKILL = 7; //Макс. количество уровней поиска
    var int PLAYER_TALENT_WISPDETECTOR[MAX_WISPSKILL];

    // Режимы поиска предметов
    Открыть спойлер
    var int WispSearching;
    const int WispSearch_Follow = 1; //Огонек следует за вами
    const int WispSearch_ALL = 2; //Ищет все, что может найти
    const int WispSearch_POTIONS = 3; //Ищет напитки
    const int WispSearch_MAGIC = 4; //Ищет магические предметы
    const int WispSearch_FOOD = 5; //Ищет питание
    const int WispSearch_NF = 6; //Ищет оружия ближнего радиуса поражения
    const int WispSearch_FF = 7; //Ищет оружия дальнего радиуса поражения
    const int WispSearch_NONE = 8; //Ищет деньги
    const int WispSearch_RUNE = 9; //Ищет руны

    // Алхимия
    Открыть спойлер
    const int POTION_Health_01 = 0; //Лечебная эссенция
    const int POTION_Health_02 = 1; //Лечебный экстракт
    const int POTION_Health_03 = 2; //Лечебный эликсир
    const int POTION_Mana_01 = 3; //Эссенция маны
    const int POTION_Mana_02 = 4; //Экстракт маны
    const int POTION_Mana_03 = 5; //Эликсир маны
    const int POTION_Speed = 6; //Напиток ускорения
    const int POTION_Perm_STR = 7; //Эликсир силы
    const int POTION_Perm_DEX = 8; //Эликсир ловкости
    const int POTION_Perm_Mana = 9; //Постоянный напиток маны
    const int POTION_Perm_Health = 10; //Постоянный лечебный напиток
    const int POTION_MegaDrink = 11; //Эмбарла Фиргасто
    const int CHARGE_Innoseye = 12; //Зарядить Глаз
    const int POTION_Mana_04 = 13; //Чистая мана
    const int POTION_Health_04 = 14; //Чистая жизненная энергия
    const int MAX_POTION = 15; //Макс. количество видов алхимии
    var int PLAYER_TALENT_ALCHEMY[MAX_POTION];

    // Кузнечное дело
    Открыть спойлер
    const int WEAPON_Common = 0; //Простой самокованный меч
    const int WEAPON_1H_Special_01 = 1; //Рудный длинный клинок
    const int WEAPON_2H_Special_01 = 2; //Рудный двуручник
    const int WEAPON_1H_Special_02 = 3; //Рудный клинок чудовища
    const int WEAPON_2H_Special_02 = 4; //Тяжелый рудный двуручник
    const int WEAPON_1H_Special_03 = 5; //Рудный боевой клинок
    const int WEAPON_2H_Special_03 = 6; //Тяжелый рудный боевой клинок
    const int WEAPON_1H_Special_04 = 7; //Рудный потрошитель драконов
    const int
    WEAPON_2H_Special_04 = 8; //Большой рудный потрошитель драконов
    const int WEAPON_1H_Harad_01 = 9; //Благородный меч
    const int
    WEAPON_1H_Harad_02 = 10; //Благородный длинный меч
    const int
    WEAPON_1H_Harad_03 = 11; //Рубиновый клинок
    const int WEAPON_1H_Harad_04 = 12; //Благородный меч чудовища
    const int MAX_WEAPONS = 13; //Макс. количество видов создаваемого оружия
    var int
    PLAYER_TALENT_SMITH[MAX_WEAPONS]; // Разделка животных
    const int TROPHY_Teeth = 0; //Взять зубы
    const int
    TROPHY_Claws = 1; //Взять когти
    const int TROPHY_Fur = 2; //Взять шкуру
    const int
    TROPHY_Heart = 3; //Взять сердце
    const int
    TROPHY_ShadowHorn = 4; //Взять рог мракориса
    const int TROPHY_FireTongue = 5; //Взять огненный язык
    const int
    TROPHY_BFWing = 6; //Взять крылья кровяного шершня
    const int TROPHY_BFSting = 7; //Взять жало кровяного шершня
    const int TROPHY_Mandibles = 8; //Взять жвало
    const int TROPHY_CrawlerPlate = 9; //Взять панцирь ползуна
    const int TROPHY_DrgSnapperHorn = 10; //Взять рог остера
    const int TROPHY_DragoNPCale = 11; //Взять чешую дракона
    const int TROPHY_DragonBlood = 12; //Взять кровь дракона
    const int
    TROPHY_ReptileSkin = 13; //Взять кожу рептилии
    const int
    MAX_TROPHIES = 14; //Макс. количество трофеев
    var int PLAYER_TALENT_TAKEANIMALTROPHY[MAX_TROPHIES];


    //**************************************** // Шрифты для движка //****************************************

    Открыть спойлер
    const string TEXT_FONT_20 = "Font_old_20_white.tga";
    const string TEXT_FONT_10 = "Font_old_10_white.tga";
    const string TEXT_FONT_DEFAULT = "Font_old_10_white.tga";
    const string
    TEXT_FONT_Inventory = "Font_old_10_white.tga";


    //**************************************** // Задержка текста при выводе в режиме диалога в мс на символ //****************************************
    const float
    VIEW_TIME_PER_CHAR = 550;
    //**************************************** // Области игрового мира //****************************************
    Открыть спойлер
    const int NEWWORLD_ZEN = 1; //Хоринис с окрестностями
    const int OLDWORLD_ZEN = 2; //Весь Миненталь
    const int DRAGONISLAND_ZEN = 3; //Остров Драконов
    const int
    ADDONWORLD_ZEN = 4; //Яркендар


    //****************************************
    // Параметры камеры для показа предметов инвентаря
    //****************************************

    Открыть спойлер
    const int INVCAM_ENTF_RING_STANDARD = 400;
    const int INVCAM_ENTF_AMULETTE_STANDARD = 150;
    const int
    INVCAM_ENTF_MISC_STANDARD = 200;
    const int INVCAM_ENTF_MISC2_STANDARD = 250;
    const int INVCAM_ENTF_MISC3_STANDARD = 500;
    const int INVCAM_ENTF_MISC4_STANDARD = 650;
    const int INVCAM_ENTF_MISC5_STANDARD = 850;
    const int INVCAM_X_RING_STANDARD = 25;
    const int
    INVCAM_Z_RING_STANDARD = 45;
     
    Последнее редактирование: 10 дек 2014
    Orc Hunter, Ur-tRall и Валера поблагодарили.
  9. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    Тема вторая: Искусственный интеллект.

    Все функции, константы и переменные искусственного интеллекта находятся в папке ..\AI

    1. Константы AI.

    Они описаны в файле ..\AI_Intern\AI_Constants.d
    //**************************
    // AIVAR - Константы для людей
    //**************************


    // ------ Новости и память ---------------------

    Открыть спойлер
    const int AIV_LastFightAgainstPlayer = 0; //Параметры последнего сражения с ГГ
    const int FIGHT_NONE = 0; //Сражения с ГГ не было
    const int FIGHT_LOST = 1; //Сражение проиграно (победа ГГ)
    const int FIGHT_WON = 2; //Сражение выиграно (победа НПС)
    const int FIGHT_CANCEL = 3; //Сражение прервано

    const int AIV_NpcSawPlayerCommit = 1; //НПС видел какой криминал совершил ГГ
    const int CRIME_NONE = 0; //Криминала не было
    const int CRIME_SHEEPKILLER = 1; //ГГ убил овцу
    const int CRIME_ATTACK = 2; //ГГ сражался с НПС (параметры в AIV_LastFightAgainstPlayer)
    const int CRIME_THEFT = 3; //ГГ занимался воровством
    const int CRIME_MURDER = 4; //ГГ совершил убийство

    const int AIV_NpcSawPlayerCommitDay = 2; //День, когда ГГ совершил криминал


    // ------ Восприятие диалога -------------------
    const int AIV_NpcStartedTalk = 3; //Устанавливается в TRUE, если НПС с важной информацией обращается к другому НПС

    // ------ Диалог -------------------------------
    const int AIV_INVINCIBLE = 4; //Устанавливается в TRUE в начале диалога для обоих НПС
    const int AIV_TalkedToPlayer = 5; //Устанавливается в TRUE, если НПС уже разговаривал с ГГ

    // ------ Карманная кража ----------------------
    const int AIV_PlayerHasPickedMyPocket = 6; //Устанавливается в TRUE, если ГГ залезал в карман НПС

    // ------ Сражение -----------------------------
    const int AIV_LASTTARGET = 7; //Ссылка на последнего атакованного НПС
    const int AIV_PursuitEnd = 8; //Устанавливается в TRUE, если НПС закончил преследование

    // ------ Причина нападения ------------
    Открыть спойлер
    const int AIV_ATTACKREASON = 9; //Причина нападения (по приоритетам)
    const int AR_NONE = 0; //Причины нет
    const int AR_LeftPortalRoom = 1; //ГГ находится в помещении с ограниченным доступом
    const int AR_ClearRoom = 2; //ГГ находится в помещении другого НПС
    const int AR_GuardCalledToRoom = 3; //Вызвана охрана для защиты помещения
    const int AR_MonsterVsHuman = 4; //Монстр сражается с человеком, ГГ помогает человеку
    const int AR_MonsterMurderedHuman = 5; //Монстр убил человека
    const int AR_SheepKiller = 6; //Овца была атакована и убита (человеком или монстром)
    const int AR_Theft = 7; //ГГ что-то украл
    const int AR_UseMob = 8; //ГГ использовал МОВ с флагом принадлежности другому НПС
    const int AR_GuardCalledToThief = 9; //Вызвана стража по факту воровства ГГ
    const int AR_ReactToWeapon = 10; //Преступник не убрал оружие после двукратного пердупреждения или пустился в бега
    const int AR_ReactToDamage = 11; //Преступник ранил НПС
    const int AR_GuardStopsFight = 12; //Охрана прекращает атаковать преступника
    const int AR_GuardCalledToKill = 13; //Вызвана охрана по факту убийства
    const int AR_GuildEnemy = 14; //НПС является врагом гильдии (человек или монстр)
    const int AR_HumanMurderedHuman = 15; //Человек убил человека
    const int AR_MonsterCloseToGate = 16; //Охрана ворот атакует враждебного монстра
    const int AR_GuardStopsIntruder = 17; //Охрана ворот атакует незваного гостя
    const int AR_SuddenEnemyInferno = 18; //Немедленная атака противника (невзирая на блокировку)
    const int AR_KILL = 19; //ГГ убил НПС


    // ------ Обыскивание трупов --------------------
    const int AIV_RANSACKED = 10; //Устанавливается TRUE, если труп обыскивается

    // ------ Смерть --------------------------------
    const int AIV_DeathInvGiven = 11; //Устанавливается TRUE, если труп обыскан

    // ------ Охрана --------------------------------
    Открыть спойлер
    const int AIV_Guardpassage_Status = 12; //Статус предупреждений охраны
    const int GP_NONE = 0; //Нет предупреждений
    const int GP_FirstWarnGiven = 1; //НПС получил первое предупреждение
    const int GP_SecondWarnGiven = 2; //НПС получил второе предупреждение
    const int AIV_LastDistToWP = 13; //Расстояние от WP охраны до точки, в которой НПС получил предупреждение
    const int AIV_PASSGATE = 14; //TRUE - проход возможен, FALSE - проход запрещен


    // ------ Предоставление экспы ------------------
    const int AIV_PARTYMEMBER = 15; //Если TRUE, то экспа за убитых монстров сопровождавшим идет ГГ.
    const int AIV_VictoryXPGiven = 16; //Устанавливается TRUE, когда экспа за победу начислена

    // ------ Пол -----------------------------------
    const int AIV_Gender = 17; //Пол НПС
    const int MALE = 0; //Мужской
    const int FEMALE = 1; //Женский

    // ------ Пища ----------------------------------
    Открыть спойлер
    const int AIV_Food = 18; //Употребляемая пища
    const int FOOD_Apple = 0; //Яблоко
    const int FOOD_Cheese = 1; //Сыр
    const int FOOD_Bacon = 2; //Бекон
    const int FOOD_Bread = 3; //Хлеб


    // ------ Вспомогательные параметры для ТА ------
    Открыть спойлер
    const int AIV_TAPOSITION = 19; //Позиции выполненния ТА
    const int ISINPOS = 0; //НПС в позиции выполнения ТА
    const int NOTINPOS = 1; //НПС не в позиции выполнения ТА
    const int NOTINPOS_WALK = 2; //НПС идет к точке выполнения ТА


    // ------ Выбор заклинания ----------------------
    const int AIV_SelectSpell = 20; //Случайное число, соответствующее заклинанию, выбранному НПС

    // ------ Наблюдение ----------------------------
    const int AIV_SeenLeftRoom = 21; //TRUE, если НПС наблюдает за своим помещением

    //////////////////////////////////// //Переменные использующиеся при комментариях действий ГГ
    Открыть спойлер
    var int Player_SneakerComment; //ГГ крадется
    var int Player_LeftRoomComment; //ГГ зашел в чужое помещение
    var int Player_DrawWeaponComment; //ГГ вытащил оружие
    var int Player_GetOutOfMyBedComment; //ГГ лег на чужую кровать

    ////////////////////////////////////

    // ------ Сражение со вторым противником --------
    const int AIV_HitByOtherNpc = 22; //Расстояние до другого НПС
    const int AIV_WaitBeforeAttack = 23; //Если != 0, то вводится задержка перед атакой
    const int AIV_LastAbsolutionLevel = 24; //Репутация ГГ для конкретной локации

    // ----------------------------------------------
    const int AIV_ToughGuyNewsOverride = 25; //НПС не имеет новостей о "жестком парне" (ГГ)


    //***************************
    // AIVAR - Константы для монстров
    //***************************

    Открыть спойлер

    const int AIV_MM_ThreatenBeforeAttack = 26; //Монстр угрожает перед атакой
    const int AIV_MM_FollowTime = 27; //Время преследования монстром в сек.
    const int FOLLOWTIME_SHORT = 5; //Короткое преследование
    const int FOLLOWTIME_MEDIUM = 10; //Среднее преследование
    const int FOLLOWTIME_LONG = 20; //Длительное преследование
    const int AIV_MM_FollowInWater = 28; //Полезет ли монстр за НПС в воду? (относится и к людям)

    // ----------------------------------------------
    const int AIV_MM_PRIORITY = 29; //Приоритет поведения монстра
    const int PRIO_EAT = 0; //Пожирание падали
    const int PRIO_ATTACK = 1; //Нападение на жертву
    // ----------------------------------------------

    Открыть спойлер
    const int AIV_MM_SleepStart = 30; //Время отхода монстра ко сну (час)
    const int AIV_MM_SleepEnd = 31; //Время пробуждения
    const int AIV_MM_RestStart = 32; //Время начала отдыха
    const int AIV_MM_RestEnd = 33; //Время окончания отдыха
    const int AIV_MM_RoamStart = 34; //Время начала брожения
    const int AIV_MM_RoamEnd = 35; //Время окончания брожения
    const int AIV_MM_EatGroundStart = 36; //Время начала кормежки
    const int AIV_MM_EatGroundEnd = 37; //Время окончания кормежки
    const int AIV_MM_WuselStart = 38; //Время начала активности
    const int AIV_MM_WuselEnd = 39; //Время окончания активности
    const int AIV_MM_OrcSitStart = 40; //Время, когда орк садится
    const int AIV_MM_OrcSitEnd = 41; //Время, когда орк встает
    const int OnlyRoutine = -1; //Время контролируется программой поведения монстра

    // ----------------------------------------------
    const int AIV_MM_ShrinkState = 42; //Состояние уменьшения монстра (коэффициент сжатия)
    // ----------------------------------------------

    Открыть спойлер
    const int AIV_MM_REAL_ID = 43; //Идентификатор монстра
    const int ID_MEATBUG = 1; //Мясной жук
    const int ID_SHEEP = 2; //Овца
    const int ID_GOBBO_GREEN = 3; //Гоблин
    const int ID_GOBBO_BLACK = 4; //Черный гоблин
    const int ID_GOBBO_SKELETON = 5; //Скелет гоблина
    const int ID_SUMMONED_GOBBO_SKELETON = 6; //Вызванный Скелет гоблина
    const int ID_SCAVENGER = 7; //Падальщик
    const int ID_SCAVENGER_DEMON = 8; //Зубастик
    const int ID_GIANT_RAT = 8; //Крыса
    const int ID_GIANT_BUG = 9; //Полевой жук
    const int ID_BLOODFLY = 10; //Кровяной шершень
    const int ID_WARAN = 11; //Ящерица
    const int ID_FIREWARAN = 12; //Огненная ящерица
    const int ID_WOLF = 13; //Волк
    const int ID_WARG = 14; //Варг
    const int ID_SUMMONED_WOLF = 15; //Вызванный Волк
    const int ID_MINECRAWLER = 16; //Ползун
    const int ID_MINECRAWLERWARRIOR = 17; //Воин ползунов
    const int ID_LURKER = 18; //Шныг
    const int ID_SKELETON = 19; //Скелет
    const int ID_SUMMONED_SKELETON = 20; //Вызванный Скелет
    const int ID_SKELETON_MAGE = 21; //Маг скелетов
    const int ID_ZOMBIE = 22; //Зомби
    const int ID_SNAPPER = 23; //Глорх
    const int ID_DRAGONSNAPPER = 24; //Остер
    const int ID_SHADOWBEAST = 25; //Мракорис
    const int ID_SHADOWBEAST_SKELETON = 26; //Скелет мракориса
    const int ID_HARPY = 27; //Гарпия
    const int ID_STONEGOLEM = 28; //Каменный голем
    const int ID_FIREGOLEM = 29; //Огненный голем
    const int ID_ICEGOLEM = 30; //Ледяной голем
    const int ID_SUMMONED_GOLEM = 31; //Вызванный Голем
    const int ID_DEMON = 32; //Демон
    const int ID_SUMMONED_DEMON = 33; //Вызванный Демон
    const int ID_DEMON_LORD = 34; //Лорд демонов
    const int ID_TROLL = 35; //Троль
    const int ID_TROLL_BLACK = 36; //Черный троль
    const int ID_SWAMPSHARK = 37; //Болотожор
    const int ID_DRAGON_FIRE = 38; //Огненный дракон
    const int ID_DRAGON_ICE = 39; //Ледяной дракон
    const int ID_DRAGON_ROCK = 40; //Каменный дракон
    const int ID_DRAGON_SWAMP = 41; //Болотный дракон
    const int ID_DRAGON_UNDEAD = 42; //Дракон нежить
    const int ID_MOLERAT = 43; //Кротокрыс
    const int ID_ORCWARRIOR = 44; //Воин орков
    const int ID_ORCSHAMAN = 45; //Шаман орков
    const int ID_ORCELITE = 46; //Элитный воин орков
    const int ID_UNDEADORCWARRIOR = 47; //Орк нежить
    const int ID_DRACONIAN = 48; //Ящер
    const int ID_WISP = 49; //Огонек


    //-----Addon ------

    Открыть спойлер
    const int ID_Alligator = 50; //Аллигатор
    const int ID_Swampgolem = 51; //Болотный голем
    const int ID_Stoneguardian = 52; //Каменный сторож
    const int ID_Gargoyle = 53; //Огненный дух мракориса
    const int ID_Bloodhound = 54; //Кровяная собака
    const int ID_Icewolf = 55; //Ледяной волк
    const int ID_OrcBiter = 56; //Зубастик
    const int ID_Razor = 57; //Расчленитель
    const int ID_Swarm = 58; //Рой
    const int ID_Swamprat = 59; //Болотная крыса
    const int ID_BLATTCRAWLER = 60; //Богомол
    const int ID_SummonedGuardian = 61; //Вызванный Каменный страж
    const int ID_SummonedZombie = 62; //Вызванный Зомби
    const int ID_Keiler = 63; //Кабан
    const int ID_SWAMPDRONE = 64; //Болотная вонючка


    // ----------------------------------------------
    const int AIV_LASTBODY = 44; //Ссылка на последнего сожранного монстра


    //**********************
    // Дальнейшие человеческие AIVARы
    //**********************


    // ------ Сражение с Альриком -------------------
    Открыть спойлер
    const int AIV_ArenaFight = 45; //Параметры сражения
    const int AF_NONE = 0; //Сражения не было
    const int AF_RUNNING = 1; //В процессе сражения
    const int AF_AFTER = 2; //После сражения
    const int AF_AFTER_PLUS_DAMAGE = 3; //ГГ нечестно выиграл сражение


    // ------ Криминал ------------------------------
    const int AIV_CrimeAbsolutionLevel = 46; //Абсолютный уровень криминальной репутации ГГ

    // ------ Атака ---------------------------------
    const int AIV_LastPlayerAR = 47; //Причина последнего нападения ГГ

    // ------ Без сознания --------------------------
    const int AIV_DuelLost = 48; //TRUE, если НПС из ополчения был побит ГГ

    // ------ Торговля ------------------------------
    const int AIV_ChapterInv = 49; //Отвечает за обновление товаров у торговцев в начале главы

    // ------ Стая монстров -------------------------
    const int AIV_MM_Packhunter = 50; //TRUE, если монстры одного вида охотятся и атакуют стаей

    // ------ Магия ---------------------------------
    const int AIV_MagicUser = 51; //Использует ли НПС магию
    const int MAGIC_NEVER = 0; //Не использует
    const int MAGIC_ALWAYS = 1; //Всегда использует

    // ------ Послушники ----------------------------
    const int AIV_DropDeadAndKill = 52; //TRUE, если этого НПС разрешено убить

    // ------ Магия заморозки -----------------------
    const int AIV_FreezeStateTime = 53; //Время начала действия заклинаний заморозки

    // ------ Игнорирование криминала ---------------
    const int AIV_IGNORE_Murder = 54; //Игнорирование убийства
    const int AIV_IGNORE_Theft = 55; //Игнорирование воровства
    const int AIV_IGNORE_Sheepkiller = 56; //Игнорирование убийства овцы

    // ------ Крутой парень -------------------------
    const int AIV_ToughGuy = 57; //TRUE, если НПС имеет дело с "крутым парнем"

    // ------ Отвергнутые новости -------------------
    const int AIV_NewsOverride = 58; //TRUE, если НПС не знает никаких новостей

    // ------ Атака монстров ------------------------
    const int AIV_MaxDistToWp = 59; //Макс. дистанция, на которой монстр начинает атаковать
    const int AIV_OriginalFightTactic = 60; //Тактика нападения монстра

    // ------ Оценка врага --------------------------
    const int AIV_EnemyOverride = 61; //TRUE, если врагов у НПС нет

    // ------ Вызванные монстры ---------------------
    const int AIV_SummonTime = 62; //Время от начала вызова монстра

    // ------ Атака ---------------------------------
    const int AIV_FightDistCancel = 63; //Дистанция, на которой прекращается сражение
    const int AIV_LastFightComment = 64; //TRUE, если НПС комментировал последнее сражение

    // ----------------------------------------------
    const int AIV_LOADGAME = 65; //TRUE, если была загрузка игры (other не инициализирован)

    // ------ Без сознания --------------------------
    const int AIV_DefeatedByPlayer = 66; //TRUE, если НПС побежден ГГ

    // ------ Смерть --------------------------------
    const int AIV_KilledByPlayer = 67; //TRUE, если НПС убит ГГ

    // ------ Различные функции ---------------------
    const int AIV_StateTime = 68; //Время нахождения НПС в конкретном состоянии

    // ----------------------------------------------
    Открыть спойлер
    const int AIV_Dist = 69; //Дистанция между НПС
    const int AIV_IgnoresFakeGuild = 70; //TRUE, если НПС игнорирует поддельную гильдию
    const int AIV_NoFightParker = 71; //TRUE, если НПС не может атаковать
    const int AIV_NPCIsRanger = 72; //TRUE, если НПС принадлежит к "Кольцу Воды"
    const int AIV_IgnoresArmor = 73; //НПС не носит броню
    const int AIV_StoryBandit = 74; //Бандиты, с которыми можно сражаться
    const int AIV_StoryBandit_Esteban = 75; //НПС является охранником Эстебана


    // ------ Смерч ---------------------------------
    const int AIV_WhirlwindStateTime = 76; //Время начала запуска смерча

    // ------ Вздутие -------------------------------
    const int AIV_InflateStateTime = 77; //Время начала запуска вздутия

    // ------ Рой -----------------------------------
    const int AIV_SwarmStateTime = 78; //Время начала запуска роя

    // ------ Опустошение ---------------------------
    const int AIV_SuckEnergyStateTime = 79; //Время начала запуска опустошения

    // ------ Пираты --------------------------------
    const int AIV_FollowDist = 80; //Дистанция следования НПС друг за другом

    // ------ Реальные атрибуты НПС -----------------
    Открыть спойлер
    const int REAL_STRENGTH = 81; //Сила
    const int REAL_DEXTERITY = 82; //Ловкость
    const int REAL_MANA_MAX = 83; //Мана
    const int REAL_TALENT_1H = 84; //Владение одноручником
    const int REAL_TALENT_2H = 85; //Владение двуручником
    const int REAL_TALENT_BOW = 86; //Владение луком
    const int REAL_TALENT_CROSSBOW = 87; //Владение арбалетом

    const int AIV_SpellLevel = 88; //Круг магии



    //***************************************************
    // Глобальные переменные для системы Доносов/Абсолютных уровней/Новостей
    //***************************************************


    // Абсолютные уровни
    Открыть спойлер
    var int ABSOLUTIONLEVEL_OldCamp; //Миненталь
    var int ABSOLUTIONLEVEL_City; //Хоринис
    var int ABSOLUTIONLEVEL_Monastery; //Монастырь
    var int ABSOLUTIONLEVEL_Farm; //Поместье Онара
    var int ABSOLUTIONLEVEL_BL; //Лагерь бандитов


    // Кол-во криминала в Минентале
    Открыть спойлер
    var int PETZCOUNTER_OldCamp_Murder; //Убийства
    var int PETZCOUNTER_OldCamp_Theft; //Воровство
    var int PETZCOUNTER_OldCamp_Attack; //Нападения
    var int PETZCOUNTER_OldCamp_Sheepkiller; //Убийство овец


    // Кол-во криминала в Хоринисе
    Открыть спойлер
    var int PETZCOUNTER_City_Murder;
    var int PETZCOUNTER_City_Theft;
    var int PETZCOUNTER_City_Attack;
    var int PETZCOUNTER_City_Sheepkiller;


    // Кол-во криминала в Монастыре
    Открыть спойлер
    var int PETZCOUNTER_Monastery_Murder;
    var int PETZCOUNTER_Monastery_Theft;
    var int PETZCOUNTER_Monastery_Attack;
    var int PETZCOUNTER_Monastery_Sheepkiller;


    // Кол-во криминала в Поместье Онара
    Открыть спойлер
    var int PETZCOUNTER_Farm_Murder;
    var int PETZCOUNTER_Farm_Theft;
    var int PETZCOUNTER_Farm_Attack;
    var int PETZCOUNTER_Farm_Sheepkiller;


    // Кол-во криминала в Лагере бандитов
    Открыть спойлер
    var int PETZCOUNTER_BL_Murder;
    var int PETZCOUNTER_BL_Theft;
    var int PETZCOUNTER_BL_Attack;


    //*******************************
    // Константы локаций
    //*******************************


    Открыть спойлер
    const int LOC_NONE = 0; //Вне локаций
    const int LOC_OLDCAMP = 1; //Миненталь
    const int LOC_CITY = 2; //Хоринис
    const int LOC_MONASTERY = 3; //Монастырь
    const int LOC_FARM = 4; //Поместье Онара
    const int LOC_BL = 5; //Лагерь бандитов
    const int LOC_ALL = 6; //Все локации


    //*******************************
    // Константы Хориниса (кварталы)
    //*******************************


    Открыть спойлер
    const int Q_KASERNE = 1; //Казарма
    const int Q_GALGEN = 2; //Виселица
    const int Q_MARKT = 3; //Рынок
    const int Q_TEMPEL = 4; //Замок
    const int Q_UNTERSTADT = 5; //Нижний город
    const int Q_HAFEN = 6; //Гавань
    const int Q_OBERSTADT = 7; //Верхний город


    //******************************
    // Активное восприятие монстров
    //******************************
    //---------------------------------------------

    Открыть спойлер
    const int PERC_DIST_SUMMONED_ACTIVE_MAX = 2000; //Макс. дальность действия активного восприятия вызываемых монстров
    const int PERC_DIST_MONSTER_ACTIVE_MAX = 1500; //Макс. дальность действия активного восприятия других монстров
    const int PERC_DIST_ORC_ACTIVE_MAX = 2500; //Макс. дальность действия активного восприятия орков
    const int PERC_DIST_DRAGON_ACTIVE_MAX = 3500; //Макс. дальность действия активного восприятия драконов
    //---------------------------------------------

    const int FIGHT_DIST_MONSTER_ATTACKRANGE = 700; //Дистанция, с которой монстры начинают атаковать
    const int FIGHT_DIST_MONSTER_FLEE = 300; //Дистанция, с которой монстр начинает преследование
    const int FIGHT_DIST_DRAGON_MAGIC = 700; //Дистанция применения драконами магии
    //---------------------------------------------

    const int MONSTER_THREATEN_TIME = 4; //Кол-во секунд, которые монстр угрожает перед атакой
    const int MONSTER_SUMMON_TIME = 60; //Время, на которое вызываются монстры


    //************************************
    // Константы дистанций для человека
    //************************************
    // --------------------------------------------

    Открыть спойлер
    const int TA_DIST_SELFWP_MAX = 500; //Дистанция до объекта, на которой начинают выполняться функции распорядка дня
    // --------------------------------------------

    const int PERC_DIST_ACTIVE_MAX = 2000; //Макс. дальность действия активного восприятия
    //---------------------------------------------

    const int PERC_DIST_INTERMEDIAT = 1000; //Макс. дальность действия пассивного восприятия
    const int PERC_DIST_DIALOG = 500; //Дистанция начала диалога
    const int PERC_DIST_HEIGHT = 1000; //С какой разницы высот НПС не реагируют друг на друга
    const int PERC_DIST_INDOOR_HEIGHT = 250; //Дистанция игнорирования через закрытые двери
    //---------------------------------------------

    const int FIGHT_DIST_MELEE = 600; //Дистанция атаки оружием ближнего радиуса действия
    const int FIGHT_DIST_RANGED_INNER = 900; //Дистанция, ближе которой НПС выбирает оружие ближнего радиуса поражения
    const int FIGHT_DIST_RANGED_OUTER = 1000; //Дистанция, дальше которой НПС выбирает оружие дальнего радиуса поражения
    const int FIGHT_DIST_CANCEL = 3500; //На этой дистанции НПС перестают преследовать
    //---------------------------------------------

    const int WATCHFIGHT_DIST_MIN = 300 ; //Мин. дистанция наблюдения сражения между двумя НПС другим НПС (не милицией)
    const int WATCHFIGHT_DIST_MAX = 2000; //Мах. дистанция наблюдения сражения между двумя НПС другим НПС (не милицией)
    //---------------------------------------------

    const int ZivilAnquatschDist = 400; //Дистанция, с которой к ГГ начинают обращаться граждане
    //---------------------------------------------

    const float RANGED_CHANCE_MINDIST = 1500; // (не используется)
    const float RANGED_CHANCE_MAXDIST = 4500; // (не используется)


    //*************************************
    // Константы времени
    //*************************************

    Открыть спойлер
    const int NPC_ANGRY_TIME = 120; // (не используется)
    // -------------------------------------------

    const int HAI_TIME_UNCONPCIOUS = 20; //Время нахождения в бессознательном состоянии
    // -------------------------------------------

    const int NPC_TIME_FOLLOW = 10; //Время преследования монстрами


    //*************************************
    // Минимальные повреждения
    //*************************************

    Открыть спойлер
    const int NPC_MINIMAL_DAMAGE = 5; // (не используется)
    const int NPC_MINIMAL_PERCENT = 10; // (не используется)


    //*************************************
    // AI константы сражения
    //*************************************


    //Тактика сражения
    Открыть спойлер
    const int FAI_HUMAN_COWARD = 2; //Трус
    const int FAI_HUMAN_NORMAL = 42; //Нормальный
    const int FAI_HUMAN_STRONG = 3; //Сильный
    const int FAI_HUMAN_MASTER = 4; //Мастер
    //-----------------------------------------------

    const int FAI_MONSTER_COWARD = 10; //Монстр трус
    //-----------------------------------------------

    const int FAI_NAILED = 1; //Тактика сражения охранников крепостных стен

    //-----------------------------------------------
    // Тактика атаки монстрами

    Открыть спойлер
    const int FAI_GOBBO = 7; //Гоблины
    const int FAI_SCAVENGER = 15; //Падальщики
    const int FAI_GIANT_RAT = 11; //Крыса
    const int FAI_GIANT_BUG = 31; //Полевой жук
    const int FAI_BLOODFLY = 24; //Кровяной шершень
    const int FAI_WARAN = 21; //Ящерицы
    const int FAI_WOLF = 22; //Волк
    const int FAI_MINECRAWLER = 5; //Ползуны
    const int FAI_LURKER = 9; //Шныг
    const int FAI_ZOMBIE = 23; //Зомби
    const int FAI_SNAPPER = 18; //Глорх
    const int FAI_SHADOWBEAST = 16; //Мракорис
    const int FAI_HARPY = 36; //Гарпия
    const int FAI_STONEGOLEM = 8; //Големы
    const int FAI_DEMON = 6; //Демоны
    const int FAI_TROLL = 20; //Троль
    const int FAI_SWAMPSHARK = 19; //Болотожор
    const int FAI_DRAGON = 39; //Драконы
    const int FAI_MOLERAT = 40; //Кротокрыс
    //-----------------------------------------------

    const int FAI_ORC = 12; //Орки
    const int FAI_DRACONIAN = 41; //Ящер

    const int FAI_Alligator = 43; //Аллигатор
    const int FAI_Gargoyle = 44; //Огненный дух мракориса
    const int FAI_Bear = 45; //Медведь
    const int FAI_Stoneguardian = 46; //Каменный сторож


    //*************************************
    // Общие константы
    //*************************************

    Открыть спойлер
    const int TRUE = 1; //Значение TRUE
    const int FALSE = 0; //Значение FALSE

    const int LOOP_CONTINUE = 0; //Значение продолжения цикла
    const int LOOP_END = 1; //Значение выхода из цикла

    const int DEFAULT = 0; //Значение по умолчанию


    //*************************************
    // Константы ГГ
    //*************************************


    Открыть спойлер
    const int LP_PER_LEVEL = 10; //Кол-во пунктов обучения за уровень
    const int HP_PER_LEVEL = 12; //Кол-во пунктов жизни за уровень

    const int XP_PER_VICTORY = 10; //Ко-во экспы за уровень побежденного противника


    //*************************************
    // Типы НПС
    //*************************************


    Открыть спойлер
    const int NPCTYPE_AMBIENT = 0; //Окружающий народ
    const int NPCTYPE_MAIN = 1; //Значимые НПС
    const int NPCTYPE_FRIEND = 2; //Друзья
    const int NPCTYPE_OCAMBIENT = 3; //Окружающий народ в Минентале
    const int NPCTYPE_OCMAIN = 4; //Значимые НПС в Минентале
    const int NPCTYPE_BL_AMBIENT = 5; //Окружающий народ в Лагере бандитов
    const int NPCTYPE_TAL_AMBIENT = 6; //Окружающий народ в Долине бандитов
    const int NPCTYPE_BL_MAIN = 7; //Значимые НПС в Лагере бандитов


    //**************************************
    // MOBsi константы
    //**************************************


    Открыть спойлер
    const int MOBSI_NONE = 0; //Нет
    const int MOBSI_SmithWeapon = 1; //Ковать оружие
    const int MOBSI_SleepAbit = 2; //Способность спать
    const int MOBSI_MakeRune = 3; //Изготовление рун
    const int MOBSI_PotionAlchemy = 4; //Алхимия
    const int MOBSI_PRAYSHRINE = 5; //Молитва
    const int MOBSI_GOLDHACKEN = 6; //Милостыня
    const int MOBSI_PRAYIDOL = 7; //Молитва идолу

    var int PLAYER_MOBSI_PRODUCTION; //Переменная для значений MOBsi


    //**************************************
    // Константы текстур
    //**************************************


    // Для мужчин и женщин (по 4 штуки)
    Открыть спойлер
    const int BodyTex_P = 0; //Бледнокожий
    const int BodyTex_N = 1; //Европеец
    const int BodyTex_L = 2; //Латиноамериканец
    const int BodyTex_B = 3; //Негр
    const int BodyTexBabe_P = 4; //Бледнокожая
    const int BodyTexBabe_N = 5; //Европейка
    const int BodyTexBabe_L = 6; //Латиноамериканка
    const int BodyTexBabe_B = 7; //Негритянка
    const int BodyTex_Player = 8; //ГГ

    const int BodyTex_T = 10; //Татуированный мужик
    const int BodyTexBabe_F = 11; //Татуированная женщина
    const int BodyTexBabe_S = 12; //Чернокожий ребенок

    const int NO_ARMOR = -1; //Без доспехов


    // Лица мужчин
    Открыть спойлер
    const int Face_N_Gomez = 0;
    const int Face_N_Scar = 1;
    const int Face_N_Raven = 2;
    const int Face_N_Bullit = 3;
    const int Face_B_Thorus = 4;
    const int Face_N_Corristo = 5;
    const int Face_N_Milten = 6;
    const int Face_N_Bloodwyn = 7;
    const int Face_L_Scatty = 8;
    const int Face_N_YBerion = 9;
    const int Face_N_CoolPock = 10;
    const int Face_B_CorAngar = 11;
    const int Face_B_Saturas = 12;
    const int Face_N_Xardas = 13;
    const int Face_N_Lares = 14;
    const int Face_L_Ratford = 15;
    const int Face_N_Drax = 16;
    const int Face_B_Gorn = 17;
    const int Face_N_Player = 18;
    const int Face_P_Lester = 19;
    const int Face_N_Lee = 20;
    const int Face_N_Torlof = 21;
    const int Face_N_Mud = 22;
    const int Face_N_Ricelord = 23;
    const int Face_N_Horatio = 24;
    const int Face_N_Richter = 25;
    const int Face_N_Cipher_neu = 26;
    const int Face_N_Homer = 27;
    const int Face_B_Cavalorn = 28;
    const int Face_L_Ian = 29;
    const int Face_L_Diego = 30;
    const int Face_N_MadPsi = 31;
    const int Face_N_Bartholo = 32;
    const int Face_N_Snaf = 33;
    const int Face_N_Mordrag = 34;
    const int Face_N_Lefty = 35;
    const int Face_N_Wolf = 36;
    const int Face_N_Fingers = 37;
    const int Face_N_Whistler = 38;
    const int Face_P_Gilbert = 39;
    const int Face_L_Jackal = 40;


    // Бледнолицые
    Открыть спойлер
    const int Face_P_ToughBald = 41;
    const int Face_P_Tough_Drago = 42;
    const int Face_P_Tough_Torrez = 43;
    const int Face_P_Tough_Rodriguez = 44;
    const int Face_P_ToughBald_Nek = 45;
    const int Face_P_NormalBald = 46;
    const int Face_P_Normal01 = 47;
    const int Face_P_Normal02 = 48;
    const int Face_P_Normal_Fletcher = 49;
    const int Face_P_Normal03 = 50;
    const int Face_P_NormalBart01 = 51;
    const int Face_P_NormalBart_Cronos = 52;
    const int Face_P_NormalBart_Nefarius = 53;
    const int Face_P_NormalBart_Riordian = 54;
    const int Face_P_OldMan_Gravo = 55;
    const int Face_P_Weak_Cutter = 56;
    const int Face_P_Weak_Ulf_Wohlers = 57;


    // Европейцы
    Открыть спойлер
    const int Face_N_Important_Arto = 58;
    const int Face_N_ImportantGrey = 59;
    const int Face_N_ImportantOld = 60;
    const int Face_N_Tough_Lee_ähnlich = 61;
    const int Face_N_Tough_Skip = 62;
    const int Face_N_ToughBart01 = 63;
    const int Face_N_Tough_Okyl = 64;
    const int Face_N_Normal01 = 65;
    const int Face_N_Normal_Cord = 66;
    const int Face_N_Normal_Olli_Kahn = 67;
    const int Face_N_Normal02 = 68;
    const int Face_N_Normal_Spassvogel = 69;
    const int Face_N_Normal03 = 70;
    const int Face_N_Normal04 = 71;
    const int Face_N_Normal05 = 72;
    const int Face_N_Normal_Stone = 73;
    const int Face_N_Normal06 = 74;
    const int Face_N_Normal_Erpresser = 75;
    const int Face_N_Normal07 = 76;
    const int Face_N_Normal_Blade = 77;
    const int Face_N_Normal08 = 78;
    const int Face_N_Normal14 = 79;
    const int Face_N_Normal_Sly = 80;
    const int Face_N_Normal16 = 81;
    const int Face_N_Normal17 = 82;
    const int Face_N_Normal18 = 83;
    const int Face_N_Normal19 = 84;
    const int Face_N_Normal20 = 85;
    const int Face_N_NormalBart01 = 86;
    const int Face_N_NormalBart02 = 87;
    const int Face_N_NormalBart03 = 88;
    const int Face_N_NormalBart04 = 89;
    const int Face_N_NormalBart05 = 90;
    const int Face_N_NormalBart06 = 91;
    const int Face_N_NormalBart_Senyan = 92;
    const int Face_N_NormalBart08 = 93;
    const int Face_N_NormalBart09 = 94;
    const int Face_N_NormalBart10 = 95;
    const int Face_N_NormalBart11 = 96;
    const int Face_N_NormalBart12 = 97;
    const int Face_N_NormalBart_Dexter = 98;
    const int Face_N_NormalBart_Graham = 99;
    const int Face_N_NormalBart_Dusty = 100;
    const int Face_N_NormalBart16 = 101;
    const int Face_N_NormalBart17 = 102;
    const int Face_N_NormalBart_Huno = 103;
    const int Face_N_NormalBart_Grim = 104;
    const int Face_N_NormalBart20 = 105;
    const int Face_N_NormalBart21 = 106;
    const int Face_N_NormalBart22 = 107;
    const int Face_N_OldBald_Jeremiah = 108;
    const int Face_N_Weak_Ulbert = 109;
    const int Face_N_Weak_BaalNetbek = 110;
    const int Face_N_Weak_Herek = 111;
    const int Face_N_Weak04 = 112;
    const int Face_N_Weak05 = 113;
    const int Face_N_Weak_Orry = 114;
    const int Face_N_Weak_Asghan = 115;
    const int Face_N_Weak_Markus_Kark = 116;
    const int Face_N_Weak_Cipher_alt = 117;
    const int Face_N_NormalBart_Swiney = 118;
    const int Face_N_Weak12 = 119;


    // Латиноамериканцы
    Открыть спойлер
    const int Face_L_ToughBald01 = 120;
    const int Face_L_Tough01 = 121;
    const int Face_L_Tough02 = 122;
    const int Face_L_Tough_Santino = 123;
    const int Face_L_ToughBart_Quentin = 124;
    const int Face_L_Normal_GorNaBar = 125;
    const int Face_L_NormalBart01 = 126;
    const int Face_L_NormalBart02 = 127;
    const int Face_L_NormalBart_Rufus = 128;


    // Негры
    Открыть спойлер
    const int Face_B_ToughBald = 129;
    const int Face_B_Tough_Pacho = 130;
    const int Face_B_Tough_Silas = 131;
    const int Face_B_Normal01 = 132;
    const int Face_B_Normal_Kirgo = 133;
    const int Face_B_Normal_Sharky = 134;
    const int Face_B_Normal_Orik = 135;
    const int Face_B_Normal_Kharim = 136;


    // Лица женщин
    Открыть спойлер
    const int FaceBabe_N_BlackHair = 137;
    const int FaceBabe_N_Blondie = 138;
    const int FaceBabe_N_BlondTattoo = 139;
    const int FaceBabe_N_PinkHair = 140;
    const int FaceBabe_L_Charlotte = 141;
    const int FaceBabe_B_RedLocks = 142;
    const int FaceBabe_N_HairAndCloth = 143;
    const int FaceBabe_N_WhiteCloth = 144;
    const int FaceBabe_N_GreyCloth = 145;
    const int FaceBabe_N_Brown = 146;
    const int FaceBabe_N_VlkBlonde = 147;
    const int FaceBabe_N_BauBlonde = 148;
    const int FaceBabe_N_YoungBlonde = 149;
    const int FaceBabe_N_OldBlonde = 150;
    const int FaceBabe_P_MidBlonde = 151;
    const int FaceBabe_N_MidBauBlonde = 152;
    const int FaceBabe_N_OldBrown = 153;
    const int FaceBabe_N_Lilo = 154;
    const int FaceBabe_N_Hure = 155;
    const int FaceBabe_N_Anne = 156;
    const int FaceBabe_B_RedLocks2 = 157;
    const int FaceBabe_L_Charlotte2 = 158;


    // Лицо Фортуно
    const int Face_N_Fortuno = 159;

    // Лица пиратов
    const int Face_P_Greg = 160;
    const int Face_N_Pirat01 = 161;
    const int Face_N_ZombieMud = 162;
     
    Последнее редактирование: 10 дек 2014
    Orc Hunter, Ur-tRall и Валера поблагодарили.
  10. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    2. Состояния тела НПС, фокусы камеры и параметры гильдий.

    Все состояния тела НПС описаны в файле ..\AI_Intern\BodyStates.d, правда многие из них в игре не используются.
    //*************************************************
    // Состояния тела
    //*************************************************
    // Флаги прерываний

    const int BS_FLAG_INTERRUPTABLE = 32768; //Состояние прерываемо
    const int BS_FLAG_FREEHANDS = 65536; //Свободные руки
    //******************************************
    // Флаги состояние тела
    //******************************************

    Открыть спойлер
    const int BS_STAND = 0 | BS_FLAG_INTERRUPTABLE | BS_FLAG_FREEHANDS; //Стоит
    const int BS_WALK = 1 | BS_FLAG_INTERRUPTABLE; //Идет
    const int BS_SNEAK = 2 | BS_FLAG_INTERRUPTABLE; //Подкрадывается
    const int BS_RUN = 3; //Бежит
    const int BS_SPRINT = 4; //Быстро бежит
    const int BS_SWIM = 5; //Плывет
    const int BS_CRAWL = 6; //Ползет
    const int BS_DIVE = 7; //Ныряет
    const int BS_JUMP = 8; //Прыгает
    const int BS_CLIMB = 9 | BS_FLAG_INTERRUPTABLE; //Взбирается
    const int BS_FALL = 10; //Падает
    const int BS_SIT = 11 | BS_FLAG_FREEHANDS; //Сидит
    const int BS_LIE = 12; //Лежит
    const int BS_INVENTORY = 13; //Открывает инвентарь
    const int BS_ITEMINTERACT = 14 | BS_FLAG_INTERRUPTABLE; //Действие с предметом
    const int BS_MOBINTERACT = 15; //Действие с MOBом
    const int BS_MOBINTERACT_INTERRUPT = 16 | BS_FLAG_INTERRUPTABLE; //Прерываемое действие с MOBом
    const int BS_TAKEITEM = 17; //Берет предмет
    const int BS_DROPITEM = 18; //Выкидывает предмет
    const int BS_THROWITEM = 19; //Бросает предмет
    const int BS_PICKPOCKET = 20 | BS_FLAG_INTERRUPTABLE; //Карманная кража
    const int BS_STUMBLE = 21; //(не используется)
    const int BS_UNCONPCIOUS = 22; //Без сознания
    const int BS_DEAD = 23; //Мертвый
    const int BS_AIMNEAR = 24; //Близкая цель
    const int BS_AIMFAR = 25; //Далекая цель
    const int BS_HIT = 26 | BS_FLAG_INTERRUPTABLE; //Удар
    const int BS_PARADE = 27; //(не используется)

    // Магия
    const int BS_CASTING = 28; //Кастует
    const int BS_PETRIFIED = 29; //Ошеломленный
    const int BS_CONTROLLING = 30 | BS_FLAG_INTERRUPTABLE; //Управляемый
    const int BS_MAX = 31; //Макс. кол-во состояний тела
    // Модификаторы состояний

    const int BS_MOD_HIDDEN = 128; //Скрытый
    const int BS_MOD_DRUNK = 256; //Пьяный
    const int BS_MOD_NUTS = 512; //???
    const int BS_MOD_BURNING = 1024; //Горящий
    const int BS_MOD_CONTROLLED = 2048; //Управляемый
    const int BS_MOD_TRANSFORMED = 4096; //Трансформируемый
    // имена MOBов

    const string MOB_SIT = "BENCH,CHAIR,GROUND,THRONE";
    const string MOB_LIE = "BED,BEDHIGH,BEDLOW";
    const string MOB_CLIMB = "CLIMB,LADDER,RANKE";
    const string MOB_NOTINTERRUPTABLE = "DOOR,LEVER,TOUCHPLATE,TURNSWITCH,VWHEEL,CHESTBIG,CHESTSMALL,HERB,IDOL,PAN,SMOKE,INNOS";
    // Все другие MOBы, здесь не приведенные, являются прерываемыми, это:
    // BOOK,BSANVIL,BSCOOL,BSFIRE,BSSHARP,CAULDRON,DRUM,GRAVE,LAB,ORE,REPAIR,RMAKER,BAU,MSAEGE,STOVE,SDW(Stein des Wissens)

    В файле ..\AI_Intern\Focus.d описываются фокусы камеры (производные instance от класса c_focus) для следующих ситуаций:
    Focus_Normal - обычный фокус камеры
    Focus_Melee - фокус камеры при сражении оружием ближнег радиуса поражения
    Focus_Ranged - фокус камеры при сражении оружием дальнего радиуса поражения
    Focus_Throw_Item - фокус камеры при броске (метании) предмета
    Focus_Throw_Mob - фокус камеры при броске (метании) МОВа
    Focus_Magic - фокус камеры при кастовании заклинания

    В файле ..\AI_Intern\Species.d описывается значение параметров всех гильдий
    (производная instance gil_values от класса c_gilvalues)
     
    Последнее редактирование: 10 дек 2014
    Orc Hunter, Ur-tRall и Валера поблагодарили.
  11. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    3. Вывод отладочной информации.

    Функции, ответственные за вывод отладочной информации, находятся в файле ..\AI_Intern\PrintDebug.d
    К сожалению, все эти функции выводят информацию в окно zSpy с идентификатором определенного канала. На мой взгляд их применение очень проблематично и пользы от него мало. В скриптах по понятной причине вызов этих функций отсутствует, поэтому мы их рассматривать не будем.
    В файле ..\AI_Intern\PrintPlus.d приведена функция вывода на экран строки текста со случайным числом в диапазоне от 0 до 100 в следующем формате: <text><random value 0-100>. Хоть эта функция и вызывается из одного файла, смысла ее применения я не вижу.
    Эти файлы можно вообще исключить из компиляции.

    Есть еще один файл ..\AI_Intern\NPC_SetToMad.d, правда он к отладке отношения не имеет, но заслуживает удаления по причине его бесполезности.

    P.S. В скриптах очень много неиспользуемой и ненужной информации, для убыстрения работы игры и минимизации памяти все неиспользуемые функции и переменные можно удалить.
    ВНИМАНИЕ!!! Нельзя удалять неиспользуемые поля в классах, а также добавлять новые, это потребует переделки экзешника!
     
    Orc Hunter, Ur-tRall и Валера поблагодарили.
  12. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    4. Инициализация восприятий.

    Функции инициализации восприятий описаны в файле ..\AI_Intern\Perception.d
    //**************************************************
    // Устанавливается дальность действия восприятий НПС
    //**************************************************

    Открыть спойлер
    func void InitPerceptions()
    {
    // Дальность действия всех активных восприятий определена константой PERC_DIST_ACTIVE_MAX, которая записывается в поле senses_range производной от класса c_npc.
    // PERC_ASSESSPLAYER - восприятие ГГ другими НПС
    // PERC_ASSESSENEMY - восприятие одного НПС другим НПС, у которого установлен флаг ATT_HOSTILE (враг), если Temp_Att != GilAtt, то возмется Temp_Att.
    // PERC_ASSESSBODY - восприятие НПС мертвого тела, в настоящее время используется только в Monster-AI функциях.
    // PERC_ASSESSFIGHTER - восприятие НПС ГГ с поднятым оружием или восприятие НПС всех монстров (они всегда находятся в режиме Fightmode)
    // PERC_ASSESSITEM - восприятие НПС предметов
    //*** ВНИМАНИЕ *** Активное восприятие работает только в случае, если у НПС активированы одно или несколько чувств. Зона действия активных восприятий 180° перед НПС по радиусу PERC_DIST_ACTIVE_MAX.
    //*** ВНИМАНИЕ *** Зона действия пассивных восприятий 360° вокруг НПС на заданное расстояние.
    // Сражение
    Perc_SetRange(PERC_ASSESSDAMAGE,9999); //Посылается НПС, получившему повреждение. Дальность действия не используется.
    Perc_SetRange(PERC_ASSESSOTHERSDAMAGE,PERC_DIST_INTERMEDIAT); //Посылается всем другим (other) НПС, если НПС получил повреждение
    Perc_SetRange(PERC_ASSESSDEFEAT,WATCHFIGHT_DIST_MAX); //Посылается всем другим НПС, если НПС находится в бессознательном состоянии
    Perc_SetRange(PERC_ASSESSMURDER,PERC_DIST_ACTIVE_MAX); //Посылается всем другим НПС, если НПС умер
    Perc_SetRange(PERC_ASSESSTHREAT,PERC_DIST_INTERMEDIAT); //Посылается НПС в течении 2 секунд, если в него целится ГГ
    Perc_SetRange(PERC_DRAWWEAPON,PERC_DIST_DIALOG); //Посылается всем другим НПС, если ГГ достает оружие
    // Слух
    Perc_SetRange(PERC_ASSESSFIGHTSOUND,3000); //Посылается всем другим НПС, если НПС на кого-то нападает с оружием
    Perc_SetRange(PERC_ASSESSQUIETSOUND,PERC_DIST_INTERMEDIAT); //Посылается раз в секунду всем другим НПС, если ГГ идет или бежит, а также когда выброшен (уронен) какой-либо предмет
    // Воровство
    Perc_SetRange(PERC_ASSESSTHEFT,PERC_DIST_INTERMEDIAT); //Посылается всем другим НПС, если ГГ украл какой-либо предмет. При карманной краже обворованному не посылается. При телекинезе посылается всем.
    Perc_SetRange(PERC_ASSESSUSEMOB,PERC_DIST_INTERMEDIAT); //Посылается всем другим НПС, если ГГ использует MOBsi
    Perc_SetRange(PERC_ASSESSENTERROOM,PERC_DIST_INTERMEDIAT); //Посылается всем другим НПС, если ГГ входит в помещение
    // Магия
    Perc_SetRange(PERC_ASSESSMAGIC,9999); //Посылается НПС, против которого применена магия
    Perc_SetRange(PERC_ASSESSSTOPMAGIC,9999); //Посылается НПС (жертве), если магия прекращает свое действие
    // Разговор
    Perc_SetRange(PERC_ASSESSTALK,PERC_DIST_DIALOG); //Посылается НПС, если у ГГ есть важная информация для разговора
    // Взаимодействие НПС
    Perc_SetRange(PERC_ASSESSWARN,PERC_DIST_INTERMEDIAT); //Чисто скриптовое восприятие, кому посылаем, тот и реагирует
    // Открытие дверей
    Perc_SetRange(PERC_MOVEMOB,PERC_DIST_DIALOG); //Посылается всем другим НПС, если ГГ открывает дверь (сундук)
    // Превращение
    Perc_SetRange(PERC_ASSESSSURPRISE,FIGHT_DIST_CANCEL); //Посылается всем другим НПС, если ГГ превращается в себя из животного
    // Не используются!
    Perc_SetRange(PERC_OBSERVEINTRUDER,100); //Посылается всем другим НПС, если ГГ останавливается (кроме режима подкрадывания)
    Perc_SetRange(PERC_ASSESSREMOVEWEAPON,100); //Посылается всем другим НПС, если ГГ прячет оружие
    Perc_SetRange(PERC_CATCHTHIEF,100); //Посылается всем другим НПС, если ГГ пойман на карманной краже
    Perc_SetRange(PERC_ASSESSCALL,100); //Посылается НПС, если ГГ призывает его к разговору (дальняя дистанция)
    Perc_SetRange(PERC_MOVENPC,100); //Посылается всем другим НПС, если ГГ идет вместе с НПС
    Perc_SetRange(PERC_ASSESSCASTER,100); //Посылается всем другим НПС, если ГГ инвестирует ману
    Perc_SetRange(PERC_NPCCOMMAND,100); //Чисто скриптовое восприятие, можно использовать по своему усмотрению
    Perc_SetRange(PERC_OBSERVESUSPECT,100); //Посылается всем другим НПС, если ГГ подкрадывается (в движении)
    //Мной не обнаружены упоминания о следующих восприятиях: PERC_ASSESSGIVENITEM, PERC_ASSESSFAKEGUILD
    };

    //*************************************************************
    // Установка функций реакций НПС на нормальный набор восприятий для людей
    //*************************************************************

    Открыть спойлер
    func void Perception_Set_Normal()
    {
    // Активные чувства при каждом состоянии активизируются по-новому, т.к. они изменяются в функции ZS_Guide_Player
    self.senses = SENSE_HEAR | SENSE_SEE;
    self.senses_range = PERC_DIST_ACTIVE_MAX;
    // Частота проверки активных восприятий
    if(Npc_KnowsInfo(self,1) || C_NpcIsGateGuard(self)) //если НПС имеет важную информацию или НПС охраняет вход
    {
    Npc_SetPercTime(self,0.3); //восприятия проверяются раз в 0.3 секунды
    }
    else
    {
    Npc_SetPercTime(self,1); //иначе восприятия проверяются раз в секунду
    };
    // Активные восприятия (приоритет наивысший)
    Npc_PercEnable(self,PERC_ASSESSPLAYER, B_AssessPlayer);
    Npc_PercEnable(self,PERC_ASSESSENEMY, B_AssessEnemy);
    // Пассивные восприятия (приоритет задается последовательностью регистрации)
    Npc_PercEnable(self,PERC_ASSESSMAGIC, B_AssessMagic);
    Npc_PercEnable(self,PERC_ASSESSDAMAGE, B_AssessDamage);
    Npc_PercEnable(self,PERC_ASSESSMURDER, B_AssessMurder);
    Npc_PercEnable(self,PERC_ASSESSTHEFT, B_AssessTheft);
    Npc_PercEnable(self,PERC_ASSESSUSEMOB, B_AssessUseMob);
    Npc_PercEnable(self,PERC_ASSESSENTERROOM, B_AssessPortalCollision);
    Npc_PercEnable(self,PERC_ASSESSTHREAT, B_AssessThreat);
    Npc_PercEnable(self,PERC_DRAWWEAPON, B_AssessDrawWeapon);
    Npc_PercEnable(self,PERC_ASSESSFIGHTSOUND, B_AssessFightSound);
    Npc_PercEnable(self,PERC_ASSESSQUIETSOUND, B_AssessQuietSound);
    Npc_PercEnable(self,PERC_ASSESSWARN, B_AssessWarn);
    Npc_PercEnable(self,PERC_ASSESSTALK, B_AssessTalk);
    Npc_PercEnable(self,PERC_MOVEMOB, B_MoveMob);
    };

    //********************************************************************
    // Установка функций реакций НПС на минимальный набор восприятий для людей (всегда должны быть активны)
    //********************************************************************

    Открыть спойлер
    func void Perception_Set_Minimal()
    {
    self.senses = SENSE_HEAR | SENSE_SEE;
    self.senses_range = PERC_DIST_ACTIVE_MAX;
    Npc_PercEnable(self,PERC_ASSESSMAGIC, B_AssessMagic);
    Npc_PercEnable(self,PERC_ASSESSDAMAGE, B_AssessDamage);
    Npc_PercEnable(self,PERC_ASSESSMURDER, B_AssessMurder);
    Npc_PercEnable(self,PERC_ASSESSTHEFT, B_AssessTheft);
    Npc_PercEnable(self,PERC_ASSESSUSEMOB, B_AssessUseMob);
    Npc_PercEnable(self,PERC_ASSESSENTERROOM, B_AssessPortalCollision);
    };

    //************************************************************
    // Закрытие реакций НПС slf на восприятия для людей и монстров
    //************************************************************

    Открыть спойлер
    func void B_ClearPerceptions(var c_npc slf)
    {
    Npc_PercDisable(slf,PERC_ASSESSPLAYER);
    Npc_PercDisable(slf,PERC_ASSESSENEMY);
    Npc_PercDisable(slf,PERC_ASSESSBODY);
    Npc_PercDisable(slf,PERC_ASSESSMAGIC);
    Npc_PercDisable(slf,PERC_ASSESSDAMAGE);
    Npc_PercDisable(slf,PERC_ASSESSMURDER);
    Npc_PercDisable(slf,PERC_ASSESSTHEFT);
    Npc_PercDisable(slf,PERC_ASSESSUSEMOB);
    Npc_PercDisable(slf,PERC_ASSESSENTERROOM);
    Npc_PercDisable(slf,PERC_ASSESSTHREAT);
    Npc_PercDisable(slf,PERC_DRAWWEAPON);
    Npc_PercDisable(slf,PERC_ASSESSFIGHTSOUND);
    Npc_PercDisable(slf,PERC_ASSESSQUIETSOUND);
    Npc_PercDisable(slf,PERC_ASSESSWARN);
    Npc_PercDisable(slf,PERC_ASSESSTALK);
    Npc_PercDisable(slf,PERC_MOVEMOB);
    Npc_PercDisable(slf,PERC_ASSESSOTHERSDAMAGE);
    Npc_PercDisable(slf,PERC_ASSESSSTOPMAGIC);
    Npc_PercDisable(slf,PERC_ASSESSSURPRISE);
    };

    //*********************************************************
    // Установка функций реакций монстров и орков на восприятия
    //*********************************************************

    Открыть спойлер
    func void Perception_Set_Monster_Rtn()
    {
    Npc_SetPercTime(self,1); //частота проверки восприятия раз в секунду
    Npc_PercEnable(self,PERC_ASSESSENEMY, B_MM_AssessEnemy);
    Npc_PercEnable(self,PERC_ASSESSBODY, B_MM_AssessBody);
    Npc_PercEnable(self,PERC_ASSESSMAGIC, B_AssessMagic);
    Npc_PercEnable(self,PERC_ASSESSDAMAGE, B_MM_AssessDamage);
    Npc_PercEnable(self,PERC_ASSESSOTHERSDAMAGE, B_MM_AssessOthersDamage);
    Npc_PercEnable(self,PERC_ASSESSMURDER, B_MM_AssessOthersDamage);
    Npc_PercEnable(self,PERC_ASSESSWARN, B_MM_AssessWarn);
    };
     
    Последнее редактирование: 10 дек 2014
    Orc Hunter, Ur-tRall и Валера поблагодарили.
  13. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    5. Функции обработки восприятий людей.

    //*******************************************************
    // Функция реакции НПС (людей) на ГГ (обработка активного восприятия PERC_ASSESSPLAYER).
    // ГГ должен быть в поле зрения НПС (люди не имеют чувства обоняния)
    // Макс. дистанция реакции на ГГ - PERC_DIST_ACTIVE_MAX.
    //*******************************************************

    Открыть спойлер
    func void B_AssessPlayer()
    {
    // other в функции - ГГ, self - НПС
    // Тестовый режим: Игнорирование Инспектора уровня
    var c_npc PCL;
    PCL = Hlp_GetNpc(PC_Levelinspektor);
    // Если ГГ является Инспектором уровня
    if(Hlp_GetInstanceID(other) == Hlp_GetInstanceID(PCL))
    {
    return;
    };
    // Если ГГ находится в режиме диалога
    if(other.aivar[AIV_INVINCIBLE] == TRUE)
    {
    return;
    };
    // Если ГГ мертв, без сознания или в магическом сне
    if(C_NpcIsDown(other))
    {
    return;
    };
    // Если ГГ превращен в монстра
    if(other.guild > GIL_SEPERATOR_HUM)
    {
    // Если НПС охранник, то он должен задержать любого монстра
    if(C_NpcIsGateGuard(self))
    {
    // НПС встает
    AI_StandUpQuick(self);
    // вызов функции сражения
    B_Attack(self,other,AR_MonsterCloseToGate,0);
    return;
    }
    // если гильдии ГГ и НПС враждебны
    else if(Wld_GetGuildAttitude(self.guild,other.guild) == ATT_HOSTILE)
    {
    // если НПС не сопровождает ГГ и НПС не является другом ГГ
    if(self.aivar[AIV_PARTYMEMBER] == FALSE) && (self.npctype != NPCTYPE_FRIEND)
    {
    // вызов функции сражения
    B_Attack(self,other,AR_GuildEnemy,0);
    return;
    };
    };
    };
    // Если ГГ враг
    if(B_AssessEnemy())
    {
    return;
    };
    // Если ГГ бандит и НПС не бандит
    if(C_PlayerIsFakeBandit(self,other) && (self.guild != GIL_BDT))
    {
    // вызов функции сражения
    B_Attack(self,other,AR_GuildEnemy,0);
    };
    // Если ГГ убийца и НПС должен атаковать убийцу и расстояние между ГГ и НПС <= PERC_DIST_INTERMEDIAT
    if(B_GetPlayerCrime(self) == CRIME_MURDER) && C_WantToAttackMurder(self,other) && (Npc_GetDistToNpc(self,other) <= PERC_DIST_INTERMEDIAT)
    {
    // вызов функции сражения
    B_Attack(self,other,AR_HumanMurderedHuman,0);
    return;
    };
    // Если ГГ вошел в помещение, ему не принадлежащее
    if(B_AssessEnterRoom())
    {
    return;
    };
    // Если оружие ГГ обнажено
    if(B_AssessDrawWeapon())
    {
    return;
    }
    else // сброс флага комментирования обнаженного оружия
    {
    Player_DrawWeaponComment = FALSE;
    };
    // Если ГГ подкрадывается
    if(C_BodyStateContains(other,BS_SNEAK))
    {
    // если НПС не наблюдает за ГГ и НПС должен реагировать на крадущегося ГГ
    if(!Npc_IsInState(self,ZS_ObservePlayer) && C_WantToReactToSneaker(self,other))
    {
    // очистка AI команд НПС
    Npc_ClearAIQueue(self);
    // очистка восприятий НПС
    B_ClearPerceptions(self);
    // перевод НПС в состояние наблюдения за ГГ
    AI_StartState(self,ZS_ObservePlayer,1,"");
    return;
    };
    }
    else // ГГ не подкрадывается
    {
    // если ГГ не стоит
    if(!C_BodyStateContains(other,BS_STAND))
    {
    // сброс флага комментирования крадущегося ГГ
    Player_SneakerComment = FALSE;
    };
    };
    // Если ГГ не лежит
    if(!C_BodyStateContains(other,BS_LIE))
    {
    // сброс флага комментирования, что ГГ лег на чужую кровать
    Player_GetOutOfMyBedComment = FALSE;
    };
    // Важная информация для окружающих черных магов (я так понимаю, что это ищущие)
    B_AssignDementorTalk(self);

    //*********** Диалог*************
    // Если расстояние между ГГ и НПС <= дистанции начала разговора и НПС имеет важную информацию
    Открыть спойлер
    if(Npc_GetDistToNpc(self,other) <= PERC_DIST_DIALOG) && (Npc_CheckInfo(self,1))
    {
    // Если НПС охраняет ворота
    if(C_NpcIsGateGuard(self))
    {
    // установка флага для НПС при обращении с важной информацией к ГГ
    self.aivar[AIV_NpcStartedTalk] = TRUE;
    // функция диалога
    B_AssessTalk();
    return;
    }
    else //для других НПС
    {
    // если ГГ не падает и не плывет и не ныряет
    if(!C_BodyStateContains(other,BS_FALL)) && (!C_BodyStateContains(other,BS_SWIM)) && (!C_BodyStateContains(other,BS_DIVE))
    // и ГГ не занимается криминалом
    && (B_GetPlayerCrime(self) == CRIME_NONE)
    // и ГГ не отказался от разговора с НПС
    && (C_RefuseTalk(self,other) == FALSE)
    // и ГГ не является членом подставной гильдии
    && (C_PlayerHasFakeGuild(self,other) == FALSE)
    {
    // установка флага для НПС при обращении с важной информацией к ГГ
    self.aivar[AIV_NpcStartedTalk] = TRUE;
    // функция диалога
    B_AssessTalk();
    return;
    };
    };
    };

    //*********** Приветствие*************
    // если НПС идет и расстояние между ГГ и НПС <= дистанции начала разговора

    Открыть спойлер
    if (C_BodyStateContains(self,BS_WALK)) && (Npc_GetDistToNpc(self,other) <= PERC_DIST_DIALOG)
    // и ГГ не отказался от диалога и НПС не охранник
    && (Npc_RefuseTalk(other) == FALSE) && (!C_NpcIsGateGuard(self))
    // и ГГ не является членом подставной гильдии
    && (C_PlayerHasFakeGuild(self,other) == FALSE)
    {
    // НПС и ГГ смотрят друг на друга
    B_LookAtNpc(self,other);
    // звучит приветственная фраза
    B_Say_GuildGreetings(self,other);
    // НПС и ГГ перестают смотреть друг на друга
    B_StopLookAt(self);
    // отказ ГГ от диалога на 20 секунд
    Npc_SetRefuseTalk(other,20);
    };
    //*********** Сброс предупреждений охраной*************
    // если НПС охранник и расстояние между ГГ и НПС > дистанции начала разговора
    if(C_NpcIsGateGuard(self)) && (Npc_GetDistToNpc(self,other) > PERC_DIST_DIALOG)
    {
    // Статус предупреждений охраны = Нет предупреждений
    self.aivar[AIV_Guardpassage_Status] = GP_NONE;
    };
    return;
    };



    // ********************************************************************************
    // Функция реакции НПС (людей) на врага (обработка активного восприятия PERC_ASSESSENEMY).
    // враг должен быть в поле зрения НПС (люди не имеют чувства обоняния)
    // Макс. дистанция реакции на врага - PERC_DIST_ACTIVE_MAX.
    // ********************************************************************************
    // Возвращает TRUE, если реакция НПС на врага закончилась сражением
    // ********************************************************************************


    Открыть спойлер
    func int B_AssessEnemy()
    {
    // other в функции - враг, self - НПС
    // Тестовый режим: Игнорирование Инспектора уровня
    var c_npc PCL;
    PCL = Hlp_GetNpc(PC_Levelinspektor);
    // Если враг является Инспектором уровня
    if(Hlp_GetInstanceID(other) == Hlp_GetInstanceID(PCL))
    {
    return FALSE;
    };
    // Аддон
    // Если (враг не ГГ и враг человек)
    if((Hlp_GetInstanceID(other) != Hlp_GetInstanceID(hero)) && (other.guild < GIL_SEPERATOR_HUM)
    // и (НПС не может атаковать или враг не может атаковать))
    && ((self.aivar[AIV_NoFightParker] == TRUE) || (other.aivar[AIV_NoFightParker] == TRUE)))
    // или (враг монстр и враг не может атаковать)
    || ((other.guild > GIL_SEPERATOR_HUM) && (other.aivar[AIV_NoFightParker] == TRUE))
    {
    return FALSE;
    };
    // Аддон
    // Если (враг плывет или враг ныряет) и НПС не хочет лезть в воду
    if(C_BodyStateContains(other,BS_SWIM) || C_BodyStateContains(other,BS_DIVE)) && (self.aivar[AIV_MM_FollowInWater] == FALSE)
    {
    return FALSE;
    };
    // Если расстояние по высоте между НПС и врагом > дистанции реагирования по высоте
    if(Npc_GetHeightToNpc(self,other) > PERC_DIST_HEIGHT)
    {
    return FALSE;
    };
    // Если НПС член партии
    if(self.aivar[AIV_PARTYMEMBER] == TRUE)
    {
    // если дистанция между НПС и врагом > 1.5 метра
    if(Npc_GetDistToNpc(self,other) > 1500)
    {
    return FALSE;
    };
    // если НПС не видит врага
    if(!Npc_CanSeeNpc(self, other))
    {
    return FALSE;
    };
    };
    // Если враг является переодетым бандитом и НПС бандит
    if(C_PlayerisFakeBandit(self,other)) && (self.guild == GIL_BDT)
    {
    return FALSE;
    };
    // Магический Голем
    var c_npc MGO; MGO = Hlp_GetNpc(MagicGolem);
    // Ларес
    var c_npc LAR; LAR = Hlp_GetNpc(VLK_449_Lares);
    // Если НПС есть Ларес и враг есть Магический Голем
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(LAR)) && (Hlp_GetInstanceID(other) == Hlp_GetInstanceID(MGO))
    {
    return FALSE;
    };
    // Если (врагов у НПС нет или врагов у врага нет) и враг человек
    if((self.aivar[AIV_EnemyOverride] == TRUE) || (other.aivar[AIV_EnemyOverride] == TRUE)) && (other.guild < GIL_SEPERATOR_HUM)
    {
    return FALSE;
    };
    // Если отношения между НПС и врагом не вражеские
    if(Npc_GetAttitude(self,other) != ATT_HOSTILE)
    {
    return FALSE;
    };
    // Если НПС охраняет ворота
    if(C_NpcIsGateGuard(self))
    {
    return FALSE;
    };

    // Если враг есть ГГ и НПС ему друг
    if(Npc_IsPlayer(other) && (self.npctype == NPCTYPE_FRIEND))
    {
    return FALSE;
    };
    // Если гильдии НПС и врага не враждуют между собой
    if(Wld_GetGuildAttitude(self.guild,other.guild) != ATT_HOSTILE)
    {
    // Если НПС враждебен к врагу [Примечание, далее врагом может быть только ГГ, т.к. прочие НПС не имеют temp_att к другим НПС]
    if(Npc_GetAttitude(self,other) == ATT_HOSTILE)
    // и (НПС находится в текущем состоянии > 2 секунд или НПС наблюдает за ГГ)
    && ((Npc_GetStateTime(self) > 2) || Npc_IsInState(self,ZS_ObservePlayer))
    // и дистанция между НПС и ГГ <= дальности действия пассивного восприятия
    && (Npc_GetDistToNpc(self,other) <= PERC_DIST_INTERMEDIAT)
    {
    // вызов функции сражения
    B_Attack(self, other, self.aivar[AIV_LastPlayerAR], 0);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // В любом другом случае вызов функции сражения
    B_Attack(self,other,AR_GuildEnemy,0);
    return TRUE;
    };



    // ****************************************************************
    // Функция реакции людей на повреждение
    // ****************************************************************


    Открыть спойлер
    func void B_AssessDamage()
    {
    // self - жертва, other - агрессор
    var c_npc Quarho;
    // Куарходрон
    Quarho = Hlp_GetNpc(NONE_ADDON_111_Quarhodron);
    var c_npc Rhadem;
    // Радемес
    Rhadem = Hlp_GetNpc(NONE_ADDON_112_Rhademes);
    // Если жертва Куарходрон или Радемес
    if((Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Quarho))) || ((Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Rhadem)))
    {
    // вызов функции реакции на повреждение для призраков
    B_GhostSpecialDamage(other,self);
    return;
    };
    // вызов функции реакции на повреждение "Когтем Белиара"
    B_BeliarsWeaponSpecialDamage(other,self);
    // если жертва Альрик получает повреждение после того, как он сдался
    if(self.aivar[AIV_ArenaFight] == AF_AFTER)
    {
    // ГГ нечестно выиграл сражение с Альриком
    self.aivar[AIV_ArenaFight] = AF_AFTER_PLUS_DAMAGE;
    };
    // если у жертвы врагов не было
    if(self.aivar[AIV_EnemyOverride] == TRUE)
    {
    var c_npc RAV;
    // Равен
    RAV = Hlp_GetNpc(BDT_1090_Addon_Raven);
    // если Равен жертва
    if(Hlp_GetInstanceID(self) == (Hlp_GetInstanceID(RAV)))
    {
    // теперь у Равена есть враг
    self.aivar[AIV_EnemyOverride] = FALSE;
    };
    };
    // если жертва находится в состоянии атаки
    if(Npc_IsInState(self,ZS_Attack))
    {
    // если ГГ агрессор и жертва друг ГГ (Примечание: защита от нанесения повреждений ГГ своему другу, если они вместе с кем-то сражаются)
    if(Npc_IsPlayer(other)) && (self.npctype == NPCTYPE_FRIEND)
    {
    return;
    };
    // если ГГ агрессор и жертва член партии ГГ
    if(Npc_IsPlayer(other)) && (self.aivar[AIV_PARTYMEMBER] == TRUE)
    {
    return;
    };
    // если НПС агрессор не является НПС, атакованным жертвой
    if(Hlp_GetInstanceID(other) != self.aivar[AIV_LASTTARGET])
    {
    // если удар жертве нанесен агрессором не первый раз или агрессор не ГГ
    if(self.aivar[AIV_HitByOtherNpc] == Hlp_GetInstanceID(other)) || (Hlp_GetInstanceID(other) != Hlp_GetInstanceID(hero))
    {
    // смена цели (жертва будет атаковать агрессора)
    Npc_SetTarget(self,other);
    }
    else
    {
    // при первом ударе жертве записывается ID агрессора
    self.aivar[AIV_HitByOtherNpc] = Hlp_GetInstanceID(other);
    };
    };
    return;
    };
    // реакция жертвы на врага
    if(B_AssessEnemy())
    {
    return;
    };
    // если НПС агрессор не ГГ и причины нападать у него не было
    if(!Npc_IsPlayer(other)) && (other.aivar[AIV_ATTACKREASON] == AR_NONE)
    {
    // жертва атакует НПС агрессора
    B_Attack(self,other,AR_NONE,0);
    return;
    };
    // если агрессор нападает с мечом или с кулаками или вышел из режима нападения (спрятал оружие)
    if(Npc_IsInFightMode(other,FMODE_MELEE)) || (Npc_IsInFightMode(other,FMODE_FIST)) || (Npc_IsInFightMode(other,FMODE_NONE))
    {
    // если отношения между агрессором и жертвой дружеские или жертва является другом агрессора ГГ
    if(Npc_GetAttitude(self,other) == ATT_FRIENDLY) || ((self.npctype == NPCTYPE_FRIEND) && Npc_IsPlayer(other))
    {
    // если жертва не находится в состоянии реакции на повреждение
    if(!Npc_IsInState(self,ZS_ReactToDamage))
    {
    // очистка очереди состояний жертвы
    Npc_ClearAIQueue(self);
    // очистка восприятий жертвы
    B_ClearPerceptions(self);
    // перевод жертвы в состояние реакции на повреждение
    AI_StartState(self,ZS_ReactToDamage,0,"");
    return;
    };
    };
    };
    // жертва атакует агрессора
    B_Attack(self,other,AR_ReactToDamage,0);
    return;
    };



    // ****************************************************
    // Функция реакции людей на убийство
    // ****************************************************


    Открыть спойлер
    func void B_AssessMurder()
    {
    // self - свидетель убийства, other - преступник (убийца), victim - жертва (труп)
    // если свидетель убийца
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(other))
    {
    return;
    };
    // если расстояния между (свидетелем и преступником) и (свидетелем и жертвой) > макс. дальности действия восприятия
    if(Npc_GetDistToNpc(self,other) > PERC_DIST_INTERMEDIAT) && (Npc_GetDistToNpc(self,victim) > PERC_DIST_INTERMEDIAT)
    {
    return;
    };
    // если расстояния по высоте между (свидетелем и преступником) и (свидетелем и жертвой) > дальности реакций НПС
    if(Npc_GetHeightToNpc(self,other) > PERC_DIST_HEIGHT) && (Npc_GetHeightToNpc(self,victim) > PERC_DIST_HEIGHT)
    {
    return;
    };
    // если свидетель не видит преступника и свидетель не видит жертву
    if(!Npc_CanSeeNpcFreeLOS(self,other)) && (!Npc_CanSeeNpcFreeLOS(self,victim))
    {
    return;
    };
    // вызов функции реакции свидетеля на преступника (врага)
    if(B_AssessEnemy())
    {
    return;
    };
    // если жертва овца и она убита не "крутым парнем"
    if(victim.guild == GIL_SHEEP) && (victim.aivar[AIV_ToughGuy] == FALSE)
    {
    // если есть причина свидетелю атаковать преступника
    if(C_WantToAttackSheepKiller(self,other))
    {
    // вызов функции атаки
    B_Attack(self,other,AR_SheepKiller,0);
    return;
    }
    else // в противном случае
    {
    // если свидетель является охранником ворот
    if(C_NpcIsGateGuard(self))
    {
    // свидетель запоминает новость, что преступник убил овцу
    B_MemorizePlayerCrime(self,other,CRIME_SHEEPKILLER);
    };
    };
    };
    // если преступник монстр и жертва монстр
    if(other.guild > GIL_SEPERATOR_HUM) && (victim.guild > GIL_SEPERATOR_HUM)
    {
    return;
    };
    // если преступник монстр
    if(other.guild > GIL_SEPERATOR_HUM)
    {
    // свидетель атакует монстра
    B_Attack(self,other,AR_MonsterMurderedHuman,0);
    return;
    };
    // если жертва монстр
    if(victim.guild > GIL_SEPERATOR_HUM)
    {
    return;
    };
    // если у свидетеля врагов не было
    if(self.aivar[AIV_EnemyOverride] == TRUE)
    {
    // теперь у свидетеля есть враг
    self.aivar[AIV_EnemyOverride] = FALSE;
    // свидетелю разрешено воспринимать все объекты в зоне действия восприятия
    Npc_PerceiveAll(self);
    // поиск свидетелем цели
    Npc_GetNextTarget(self);
    // если преступник существует и он не бессознателен
    if(Hlp_IsValidNpc(other)) && (!C_NpcIsDown(other))
    {
    // свидетель атакует преступника
    B_Attack(self,other,AR_GuildEnemy,0);
    return;
    };
    return;
    };
    // если (свидетель враждебен к жертве или свидетель зол на жертву)
    if((Npc_GetAttitude(self,victim) == ATT_HOSTILE) || (Npc_GetAttitude(self,victim) == ATT_ANGRY))
    // и (свидетель друг преступника или свидетель нейтрален к преступнику)
    && ((Npc_GetAttitude(self,other) == ATT_FRIENDLY) || (Npc_GetAttitude(self,other) == ATT_NEUTRAL))
    {
    return;
    };
    // если преступник ГГ и свидетель его друг
    if(Npc_IsPlayer(other) && (self.npctype == NPCTYPE_FRIEND))
    {
    return;
    };
    // если свидетель не должен реагировать на убийство
    if(!C_WantToAttackMurder(self,other))
    {
    // если свидетель является охранником ворот
    if(C_NpcIsGateGuard(self))
    {
    // свидетель запоминает новость, что преступник убийца
    B_MemorizePlayerCrime(self,other,CRIME_MURDER);
    };
    return;
    };
    // если преступник и жертва являются НПС, которым разрешено убить друг друга
    if(other.aivar[AIV_DropDeadAndKill] == TRUE) || (victim.aivar[AIV_DropDeadAndKill] == TRUE)
    {
    return;
    };
    // если жертва черный маг (ищущий) или (жертва бандит и он не из Лагеря бандитов)
    if(victim.guild == GIL_DMT) || ((victim.guild == GIL_BDT) && !C_NpcBelongsToBL(victim))
    {
    return;
    };
    // свидетель атакует преступника
    B_Attack(self,other,AR_HumanMurderedHuman,0);
    return;
    };



    // ***********************************************************
    // Функция реакции людей на воровство
    // ***********************************************************
    // Вызывается в качестве реакции на пассивное восприятие PERC_ASSESSTHEFT
    // в зоне действия PERC_DIST_INTERMEDIAT когда НПС поднимает какой-либо предмет
    // ***********************************************************


    Открыть спойлер
    func void B_AssessTheft()
    {
    // other - вор, self - свидетель
    // если вор не ГГ
    if(!Npc_IsPlayer(other))
    {
    return;
    };
    // если ГГ находится в доме, принадлежащим любой гильдии, и расстояние между свидетелем и вором > дистанции реакции через закрытые двери
    if(Wld_GetPlayerPortalGuild() >= GIL_NONE) && (Npc_GetHeightToNpc(self,other) > PERC_DIST_INDOOR_HEIGHT)
    {
    return;
    };
    // если гильдии вора и свидетеля дружественны
    if(Wld_GetGuildAttitude(self.guild,other.guild) == ATT_FRIENDLY)
    {
    // если предмет существует и он принадлежит свидетелю
    if(Hlp_IsValidItem(item)) && (Npc_OwnedByNpc(item,self))
    {
    // продолжаем анализ ситуации дальше
    }
    else
    {
    return;
    };
    };
    // если предмет принадлежал ГГ ранее
    if(!C_IsTakenItemMyPossession(self,other,item))
    {
    return;
    };
    // если свидетель не видит вора
    if(!Npc_CanSeeNpc(self,other))
    {
    // если свидетель и ГГ находится в одном помещении и если (свидетель наблюдает за ГГ или свидетель находится в состоянии "незваного гостя")
    if(Npc_IsInPlayersRoom(self)) && ((Npc_IsInState(self,ZS_ObservePlayer)) || (Npc_IsInState(self,ZS_ClearRoom)))
    {
    // продолжаем анализ ситуации дальше
    }
    else
    {
    return;
    };
    };
    // если свидетель игнорирует вора
    if(!C_WantToAttackThief(self,other))
    {
    // если свидетель является охранником ворот
    if(C_NpcIsGateGuard(self))
    {
    // свидетель запоминает новость, что ГГ вор
    B_MemorizePlayerCrime(self,other,CRIME_THEFT);
    };
    return;
    };
    // свидетель атакует вора
    B_Attack(self,other,AR_Theft,0);
    return;
    };



    // ****************************************************
    // Функция реакции людей на использование МОB's
    // ****************************************************


    Открыть спойлер
    func void B_AssessUseMob()
    {
    // other - пользователь, self - свидетель
    // если пользователь не ГГ
    if(!Npc_IsPlayer(other))
    {
    return;
    };
    // если ГГ находится в доме, принадлежащим любой гильдии
    if(Wld_GetPlayerPortalGuild() >= GIL_NONE)
    {
    // если расстояние между свидетелем и пользователем > дистанции реакции через закрытые двери
    if (Npc_GetHeightToNpc(self,other) > PERC_DIST_INDOOR_HEIGHT)
    {
    return;
    };
    };
    // если гильдии пользователя и свидетеля дружественны
    if(Wld_GetGuildAttitude(self.guild,other.guild) == ATT_FRIENDLY)
    {
    // если МОВ принадлежит свидетелю
    if(Npc_IsDetectedMobOwnedByNpc(other,self))
    {
    // продолжаем анализ ситуации дальше
    }
    else
    {
    return;
    };
    };
    // если МОВ принадлежал ГГ ранее
    if(!C_IsUsedMobMyPossession(self,other))
    {
    return;
    };
    // если свидетель не видит пользователя
    if(!Npc_CanSeeNpc(self,other))
    {
    // если свидетель и ГГ находятся в одном помещении и если (свидетель наблюдает за ГГ или свидетель находится в состоянии "незваного гостя")
    if(Npc_IsInPlayersRoom(self)) && ((Npc_IsInState(self,ZS_ObservePlayer)) || (Npc_IsInState(self,ZS_ClearRoom)))
    {
    // продолжаем анализ ситуации дальше
    }
    else
    {
    return;
    };
    };
    var string detMob;
    // получить название МОВа, используемого ГГ
    detMob = Npc_GetDetectedMob(other);
    // если МОВ не "Большой сундук" и МОВ не "Маленький сундук"
    if(Hlp_StrCmp(detMob,"CHESTBIG") == FALSE) && (Hlp_StrCmp(detMob,"CHESTSMALL") == FALSE)
    {
    return;
    };
    // если свидетель игнорирует пользователя
    if(!C_WantToAttackThief(self,other))
    {
    // если свидетель является охранником ворот
    if (C_NpcIsGateGuard(self))
    {
    // свидетель запоминает новость, что ГГ вор
    B_MemorizePlayerCrime(self,other,CRIME_THEFT);
    };
    return;
    };
    // свидетель атакует пользователя
    B_Attack(self,other,AR_UseMob,0);
    return;
    };



    // ********************************************************************************
    // Функция реакции людей на вход НПС в помещение
    // ----------------------------------------
    // Возвращает TRUE при реакции на вошедшего или FALSE, когда на вошедшего не реагируют
    // ********************************************************************************


    Открыть спойлер
    func int B_AssessEnterRoom()
    {
    // other - вошедший, self - свидетель
    var int portalguild;
    // получить номер гильдии, которой принадлежит помещение (-1 помещение никому не принадлежит)
    portalguild = Wld_GetPlayerPortalGuild();
    // если вошедший ГГ и комментарий входа уже был и помещение принадлежит какой-либо гильдии и помещение не публичное
    if(Npc_IsPlayer(other)) && (Player_LeftRoomComment == TRUE) && (portalguild > GIL_NONE) && (portalguild != GIL_PUBLIC)
    {
    // сброс комментария входа
    Player_LeftRoomComment = FALSE;
    };
    // если расстояние между вошедшим и свидетелем > 10м
    if(Npc_GetDistToNpc(self,other) > 1000)
    {
    return FALSE;
    };
    // если свидетель и вошедший (ГГ) находятся не в одном помещении и свидетель находится не снаружи помещения
    if(!Npc_IsInPlayersRoom(self)) && (!(Npc_GetPortalGuild(self) < GIL_NONE))
    {
    return FALSE;
    };
    // если свидетель находится в состоянии атаки
    if(Npc_IsInState(self,ZS_Attack))
    {
    return FALSE;
    };
    // если свидетель является охранником ворот
    if(C_NpcIsGateGuard(self))
    {
    return FALSE;
    };
    // если вошедший не ГГ
    if(!Npc_IsPlayer(other))
    {
    return FALSE;
    };
    // если свидетель друг ГГ
    if(self.npctype == NPCTYPE_FRIEND)
    {
    return FALSE;
    };
    // если отношения между свидетелем и ГГ дружеские
    if(Npc_GetAttitude(self,other) == ATT_FRIENDLY)
    {
    return FALSE;
    };
    // если ГГ крадется или ГГ стоит
    if(C_BodyStateContains(other,BS_SNEAK)) || (C_BodyStateContains(other,BS_STAND))
    {
    // если свидетель не видит ГГ и свидетель не наблюдает за ГГ
    if(!Npc_CanSeeNpc(self,other)) && (!Npc_IsInState(self,ZS_ObservePlayer))
    {
    return FALSE;
    };
    };
    // если свидетель не принадлежит к гильдии
    if(self.guild == GIL_NONE)
    {
    return FALSE;
    };
    // если свидетель и ГГ находятся не в одном помещениии и свидетель спит
    if(!Npc_IsInPlayersRoom(self)) && (Npc_IsInState(self,ZS_Sleep))
    {
    return FALSE;
    };
    // если помещение публично и свидетель находится в одном помещении с ГГ
    if(portalguild == GIL_PUBLIC) && (Npc_IsInPlayersRoom(self))
    {
    // если свидетель наблюдает за ГГ
    if(Npc_IsInState(self,ZS_ObservePlayer))
    {
    return FALSE;
    };
    // если свидетель лежит
    if(C_BodyStateContains(self,BS_LIE))
    {
    // свидетель встает (Примечание: мне непонятно как он это делает)
    B_MM_DeSynchronize();
    };
    // если свидетель
    if(Npc_IsInState(self,ZS_Potion_Alchemy)) // занимается алхимией
    || (Npc_IsInState(self,ZS_Read_Bookstand)) // или читает книгу
    || (Npc_IsInState(self,ZS_Sit_Bench)) // или сидит на скамье
    || (Npc_IsInState(self,ZS_Sit_Campfire)) // или сидит у костра
    || (Npc_IsInState(self,ZS_Sit_Chair)) // или сидит на стуле
    || (Npc_IsInState(self,ZS_Sit_Throne)) // или сидит на троне
    || (Npc_IsInState(self,ZS_Sleep)) // или спит
    || (Npc_IsInState(self,ZS_Smalltalk)) // или ведет светскую беседу
    || (Npc_IsInState(self,ZS_Smoke_Joint)) // или курит
    || (Npc_IsInState(self,ZS_Stand_ArmsCrossed)) // или стоит со скрещенными руками
    || (Npc_IsInState(self,ZS_Stand_Drinking)) // или пьет
    || (Npc_IsInState(self,ZS_Stand_Eating)) // или ест
    || (Npc_IsInState(self,ZS_Stand_Guarding)) // или охраняет
    || (Npc_IsInState(self,ZS_Stand_WP)) // или стоит на вайпоинте
    {
    // очистка очереди состояний свидетеля
    Npc_ClearAIQueue(self);
    // очистка восприятий свидетеля
    B_ClearPerceptions(self);
    // если свидетель сидит
    if(C_BodyStateContains(self,BS_SIT))
    {
    // перевод свидетеля в состояние наблюдения за ГГ
    AI_StartState(self,ZS_ObservePlayer,0,"");
    }
    else
    {
    // перевод свидетеля в состояние наблюдения за ГГ (выполняется только функция конца состояния)
    AI_StartState(self,ZS_ObservePlayer,1,"");
    };
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если ГГ находится в частном помещении
    if(C_NpcIsBotheredByPlayerRoomGuild(self))
    {
    Npc_ClearAIQueue(self);
    B_ClearPerceptions(self);
    // перевод свидетеля в состояние "защиты помещения"
    AI_StartState(self,ZS_ClearRoom,1,"");
    return TRUE;
    };
    return FALSE;
    };


    // *************************************************************
    // Функция реакции людей на вход НПС в помещение
    // ------------------------------------------------
    // Вызывается как реакция на пассивное восприятие PERC_ASSESSENTERROOM
    // *************************************************************


    Открыть спойлер
    func void B_AssessPortalCollision()
    {
    // other - вошедший, self - свидетель
    var int formerportalguild;
    // получить номер гильдии, которой принадлежит помещение в котором прежде находился ГГ (-1 помещение никому не принадлежит)
    formerportalguild = Wld_GetFormerPlayerPortalGuild();
    // если есть реакция на вошедшего в помещение
    if(B_AssessEnterRoom())
    {
    return;
    };
    // если свидетель не видит вошедшего и (вошедший крадется или вошедший стоит)
    if(!Npc_CanSeeNpc(self,other)) && (C_BodyStateContains(other,BS_SNEAK) || C_BodyStateContains(other,BS_STAND))
    {
    return;
    };
    // свидетелю разрешено воспринимать все объекты в зоне действия восприятия
    Npc_PerceiveAll(self);
    // если свидетель находит другого НПС в состоянии "защиты помещения"
    if(Wld_DetectNpcEx(self,-1,ZS_ClearRoom,-1,FALSE))
    {
    return;
    };
    // если покинутое ГГ помещение принадлежит гильдии свидетеля или свидетель друг гильдии, которой принадлежит помещение
    if(self.guild == formerportalguild) || (Wld_GetGuildAttitude(self.guild,formerportalguild) == ATT_FRIENDLY)
    {
    // если отношения между гильдиями ГГ и свидетеля дружеские или (вошедший ГГ и друг свидетеля)
    if(Wld_GetGuildAttitude(self.guild,other.guild) == ATT_FRIENDLY) || (Npc_IsPlayer(other) && (self.npctype == NPCTYPE_FRIEND))
    {
    return;
    };
    // если свидетель не принадлежит к гильдии
    if(self.guild == GIL_NONE)
    {
    return;
    };
    // если (помещение принадлежит милиции или ополчению) и свидетель является другом этих гильдии
    if((formerportalguild == GIL_MIL) || (formerportalguild == GIL_SLD)) && (Wld_GetGuildAttitude(self.guild,formerportalguild) == ATT_FRIENDLY)
    {
    // свидетель атакует ГГ
    B_Attack(self,other,AR_LeftPortalRoom,0);
    return;
    }
    else // иначе
    {
    // свидетель наблюдает за помещением
    self.aivar[AIV_SeenLeftRoom] = TRUE;
    // очистка очереди состояний свидетеля
    Npc_ClearAIQueue(self);
    // очистка восприятий свидетеля
    B_ClearPerceptions(self);
    // перевод свидетеля в состояние наблюдения за ГГ
    AI_StartState(self,ZS_ObservePlayer,0,"");
    return;
    };
    };
    };



    // *****************************************************************
    // Функция реакции НПС, когда в него целится ГГ оружием дальнего радиуса поражения
    // ----------------------------------------------------
    // Вызывается как реакция на пассивное восприятие PERC_ASSESSTHREAT
    // *****************************************************************


    Открыть спойлер
    func void B_AssessThreat()
    {
    // other - ГГ, self - НПС цель
    // если расстояние между ГГ и целью > макс. дальности действия пассивного восприятия
    if(Npc_GetDistToNpc(self,other) > PERC_DIST_INTERMEDIAT)
    {
    return;
    };
    // если цель не видит ГГ
    if(!Npc_CanSeeNpc(self,other))
    {
    return;
    };
    // если оружие, из которого целится ГГ, не может нанести урон цели
    if(!C_NpcIsBotheredByWeapon(self,other))
    {
    return;
    };
    // очистка очереди состояний цели
    Npc_ClearAIQueue(self);
    // очистка восприятий цели
    B_ClearPerceptions(self);
    // переход цели в состояние реакции на оружие ГГ
    AI_StartState(self,ZS_ReactToWeapon,0,"");
    return;
    };



    // ***************************************************************
    // Функция реакции НПС, когда ГГ достает оружие
    // ---------------------------------------------------------------
    // Вызывается как реакция на пассивное восприятие PERC_DRAWWEAPON и в некоторых других функциях
    // ---------------------------------------------------------------
    // Возвращает FALSE, если НПС не реагирует на оружие ГГ, в противном случае - TRUE.
    // ***************************************************************


    Открыть спойлер
    func int B_AssessDrawWeapon()
    {
    // other - ГГ, self - НПС
    // если ГГ вышел из режима нападения (убрал оружие)
    if(Npc_IsInFightMode(other,FMODE_NONE))
    {
    return FALSE;
    };
    // если расстояние между ГГ и НПС > дистанции начала диалога
    if(Npc_GetDistToNpc(self,other) > PERC_DIST_DIALOG)
    {
    return FALSE;
    };
    // если оружие ГГ не может нанести урон НПС
    if(!C_NpcIsBotheredByWeapon(self,other))
    {
    return FALSE;
    };
    // если НПС уже находится в состоянии реакции на оружие ГГ
    if(Npc_IsInState(self,ZS_ReactToWeapon))
    {
    return FALSE;
    };
    // если НПС находится в состоянии наблюдения за ГГ и предыдущее состояние НПС было наблюдение за сражением ГГ
    if(Npc_IsInState(self,ZS_ObservePlayer)) && (Npc_WasInState(self,ZS_WatchFight))
    {
    return FALSE;
    };
    // если НПС не видит ГГ
    if(!Npc_CanSeeNpc(self,other))
    {
    return FALSE;
    };
    // очистка очереди состояний НПС
    Npc_ClearAIQueue(self);
    // очистка восприятий НПС
    B_ClearPerceptions(self);
    // переход НПС в состояние реакции на оружие ГГ
    AI_StartState(self,ZS_ReactToWeapon,0,"");
    return TRUE;
    };



    // ************************************************************
    // Функция реакции НПС, наблюдающего сражение двух других НПС
    // ------------------------------------------------------------
    // Вызывается как реакция на пассивное восприятие PERC_ASSESSFIGHTSOUND
    // ************************************************************


    Открыть спойлер
    func void B_AssessFightSound()
    {
    // self - свидетель, other - нападающий, victim - жертва
    // если жертва отсутствует
    if(!Hlp_IsValidNpc(victim))
    {
    return;
    };
    // если расстояния между (свидетелем и жертвой) и (свидетелем и нападающим) > макс. дальности действия пассивного восприятия
    if(Npc_GetDistToNpc(self,victim) > PERC_DIST_INTERMEDIAT) && (Npc_GetDistToNpc(self,other) > PERC_DIST_INTERMEDIAT)
    {
    // если (свидетель чужеземец или бандит) и (гильдии жертвы и свидетеля одинаковы или гильдии нападающего и свидетеля одинаковы)
    if((self.guild == GIL_OUT) || (self.guild == GIL_BDT)) && ((victim.guild == self.guild) || (other.guild == self.guild))
    {
    // продолжение анализа
    }
    else
    {
    return;
    };
    };
    // если свидетель боится воды
    if(self.aivar[AIV_MM_FollowInWater] == FALSE)
    {
    // если нападающий плывет или ныряет или жертва плывет или ныряет
    if(C_BodyStateContains(other,BS_SWIM) || C_BodyStateContains(other,BS_DIVE)
    || C_BodyStateContains(victim,BS_SWIM) || C_BodyStateContains(victim,BS_DIVE))
    {
    return;
    };
    };
    // если нападающий или жертва являются охранниками крепостных стен
    if(other.fight_tactic == FAI_NAILED) || (victim.fight_tactic == FAI_NAILED)
    {
    return;
    };
    // если расстояние по высоте между свидетелем и нападающим и свидетелем и жертвой > расстояния реакции по высоте
    if(Npc_GetHeightToNpc(self,other) > PERC_DIST_HEIGHT) && (Npc_GetHeightToNpc(self,victim) > PERC_DIST_HEIGHT)
    {
    return;
    };
    // если расстояние по высоте между свидетелем и нападающим > 5м и свидетель находится не более чем в 30м от "NW_MONASTERY_PLACE_04" (точка перед входом в главное здание монастыря)
    if(Npc_GetHeightToNpc(self,other) > 500) && (Npc_GetDistToWP(self,"NW_MONASTERY_PLACE_04") <= 3000)
    {
    return;
    };
    // если жертва - наблюдатель или нападающий - наблюдатель (мое примечание: если это условие перенести вторым в теле функции, то общее быстродействие увеличится)
    if(Hlp_GetInstanceID(victim) == Hlp_GetInstanceID(self)) || (Hlp_GetInstanceID(other) == Hlp_GetInstanceID(self))
    {
    return;
    };
    // если жертва овца и она атакована не "крутым парнем"
    if(victim.guild == GIL_SHEEP) && (victim.aivar[AIV_ToughGuy] == FALSE)
    {
    // если есть причина свидетеля атаковать нападающего на овец
    if(C_WantToAttackSheepKiller(self,other))
    {
    // свидетель атакует нападающего на овец
    B_Attack(self,other,AR_SheepKiller,0);
    return;
    }
    else // в противном случае
    {
    // если свидетель охранник ворот
    if(C_NpcIsGateGuard(self))
    {
    // свидетель запоминает новость, что было нападение на овцу
    B_MemorizePlayerCrime(self,other,CRIME_SHEEPKILLER);
    return;
    };
    };
    return;
    };
    // если свидетель охранник ворот
    if(C_NpcIsGateGuard(self))
    {
    return;
    };
    // если нападающий и жертва монстры
    if(other.guild > GIL_SEPERATOR_HUM) && (victim.guild > GIL_SEPERATOR_HUM)
    {
    return;
    };
    // если нападающий монстр и свидетель не враг жертве
    if(other.guild > GIL_SEPERATOR_HUM) && (Npc_GetAttitude(self,victim) != ATT_HOSTILE)
    {
    // свидетель атакует монстра
    B_Attack(self,other,AR_MonsterVsHuman,0);
    return;
    };
    // если жертва монстр и свидетель не враг нападающему и жертва жива
    if(victim.guild > GIL_SEPERATOR_HUM) && (Npc_GetAttitude(self,other) != ATT_HOSTILE) && (!Npc_IsDead(victim))
    {
    // свидетель атакует жертву (помогает нападающему)
    B_Attack(self,victim,AR_MonsterVsHuman,0);
    return;
    };
    // если у свидетеля врагов не было
    if(self.aivar[AIV_EnemyOverride] == TRUE)
    {
    // теперь у свидетеля есть враг
    self.aivar[AIV_EnemyOverride] = FALSE;
    // свидетелю разрешено воспринимать все объекты в зоне действия восприятия
    Npc_PerceiveAll(self);
    // поиск свидетелем цели
    Npc_GetNextTarget(self);
    // если нападающий существует и он не бессознателен
    if(Hlp_IsValidNpc(other)) && (!C_NpcIsDown(other))
    {
    // свидетель атакует нападающего
    B_Attack(self,other,AR_GuildEnemy,0);
    return;
    };
    return;
    };

    // --------------------------------------------------
    // Дальше нападающий и жертва являются только людьми!
    // --------------------------------------------------
    // если нападающий ГГ является переодетым бандитом или жертва ГГ является переодетым бандитом
    Открыть спойлер
    if((C_PlayerIsFakeBandit(self,other) == TRUE) || (C_PlayerIsFakeBandit(self,victim) == TRUE))
    // и (нападающий бандит или жертва бандит)
    && ((other.guild == GIL_BDT) || (victim.guild == GIL_BDT))
    {
    // если свидетель бандит
    if(self.guild == GIL_BDT)
    {
    // если свидетель и нападающий являются охранниками Эстебана
    if(self.aivar[AIV_STORYBANDIT_ESTEBAN] == TRUE) && (other.aivar[AIV_STORYBANDIT_ESTEBAN] == TRUE)
    {
    // свидетель атакует жертву
    B_Attack(self,victim,AR_NONE,0);
    return;
    };
    // если свидетель и жертва являются охранниками Эстебана
    if(self.aivar[AIV_STORYBANDIT_ESTEBAN] == TRUE) && (victim.aivar[AIV_STORYBANDIT_ESTEBAN] == TRUE)
    {
    // свидетель атакует нападающего
    B_Attack(self,other,AR_NONE,0);
    return;
    };
    // если нападающий и жертва не имели причины для сражения
    if(other.aivar[AIV_ATTACKREASON] == AR_NONE) && (victim.aivar[AIV_ATTACKREASON] == AR_NONE)
    {
    // очистка очереди состояний свидетеля
    Npc_ClearAIQueue(self);
    // очистка восприятий свидетеля
    B_ClearPerceptions(self);
    // перевод свидетеля в состояние наблюдения на сражением
    AI_StartState(self,ZS_WatchFight,0,"");
    return;
    };
    // если нападающий или жертва являются свободными (с которыми можно сражаться) бандитами
    if(other.aivar[AIV_StoryBandit] == TRUE) || (victim.aivar[AIV_StoryBandit] == TRUE)
    {
    Npc_ClearAIQueue(self);
    B_ClearPerceptions(self);
    // перевод свидетеля в состояние наблюдения на сражением
    AI_StartState(self,ZS_WatchFight,0,"");
    return;
    };
    }
    else // иначе (свидетель не бандит)
    {
    // продолжение анализа
    };
    };
    // если нападающий имел причину для сражения
    if((other.aivar[AIV_ATTACKREASON] == AR_GuardStopsIntruder) // охрана ворот атакует незваного гостя
    || (other.aivar[AIV_ATTACKREASON] == AR_MonsterCloseToGate) // охрана ворот атакует враждебного монстра
    || (other.aivar[AIV_ATTACKREASON] == AR_HumanMurderedHuman) // человек убил человека
    || (other.aivar[AIV_ATTACKREASON] == AR_GuildEnemy) // НПС является врагом гильдии
    || (other.aivar[AIV_ATTACKREASON] == AR_GuardCalledToKill)) // охрана вызвана по факту убийства
    // и свидетель друг нападающему
    && (Npc_GetAttitude(self,other) == ATT_FRIENDLY)
    {
    // свидетель атакует жертву
    B_Attack(self,victim,AR_GuardCalledToKill,0);
    return;
    };
    // тоже самое, что и выше, только свидетель помогает жертве
    if((victim.aivar[AIV_ATTACKREASON] == AR_GuardStopsIntruder)
    || (victim.aivar[AIV_ATTACKREASON] == AR_MonsterCloseToGate)
    || (victim.aivar[AIV_ATTACKREASON] == AR_HumanMurderedHuman)
    || (victim.aivar[AIV_ATTACKREASON] == AR_GuildEnemy)
    || (victim.aivar[AIV_ATTACKREASON] == AR_GuardCalledToKill))
    && (Npc_GetAttitude(self,victim) == ATT_FRIENDLY)
    {
    B_Attack(self,other,AR_GuardCalledToKill,0);
    return;
    };
    // если нападающий имел причину для сражения
    if((other.aivar[AIV_ATTACKREASON] == AR_GuardStopsFight) // охрана прекратила атаковать преступника
    || (other.aivar[AIV_ATTACKREASON] == AR_ReactToDamage) // преступник ранил НПС
    || (other.aivar[AIV_ATTACKREASON] == AR_ReactToWeapon)) // преступник не убрал оружие после двукратного предупреждения или пустился в бега
    // свидетель друг нападающему
    && (Npc_GetAttitude(self,other) == ATT_FRIENDLY)
    {
    // если нападающий ополченец или охотник на драконов или не принадлежит к гильдиям
    if((other.guild == GIL_SLD) || (other.guild == GIL_DJG) || (other.guild == GIL_NONE))
    // и если жертва ополченец или охотник на драконов или не принадлежит к гильдиям
    && ((victim.guild == GIL_SLD) || (victim.guild == GIL_DJG) || (victim.guild == GIL_NONE))
    {
    // продолжение анализа
    }
    // иначе, если нападающий и жертва не ГГ
    else if(!Npc_IsPlayer(other)) && (!Npc_IsPlayer(victim))
    {
    // продолжение анализа
    }
    else // иначе
    {
    // свидетель атакует жертву
    B_Attack(self,victim,AR_GuardStopsFight,0);
    return;
    };
    };
    // тоже самое, что и предыдущий if, только свидетель помогает жертве
    if((victim.aivar[AIV_ATTACKREASON] == AR_GuardStopsFight)
    || (victim.aivar[AIV_ATTACKREASON] == AR_ReactToDamage)
    || (victim.aivar[AIV_ATTACKREASON] == AR_ReactToWeapon))
    && (Npc_GetAttitude(self,victim) == ATT_FRIENDLY)
    {
    if((other.guild == GIL_SLD) || (other.guild == GIL_DJG) || (other.guild == GIL_NONE))
    && ((victim.guild == GIL_SLD) || (victim.guild == GIL_DJG) || (victim.guild == GIL_NONE))
    {
    }
    else if(!Npc_IsPlayer(other)) && (!Npc_IsPlayer(victim))
    {
    }
    else
    {
    // свидетель атакует нападающего
    B_Attack(self,other,AR_GuardStopsFight,0);
    return;
    };
    };
    // если нападающий не имел причины к нападению или причиной было убийство НПС ГГ
    if((other.aivar[AIV_ATTACKREASON] == AR_NONE) || (other.aivar[AIV_ATTACKREASON] == AR_KILL))
    // и если жертва не имела причины к нападению или причиной было убийство НПС ГГ
    && ((victim.aivar[AIV_ATTACKREASON] == AR_NONE) || (victim.aivar[AIV_ATTACKREASON] == AR_KILL))
    // и свидетель милиция
    && (self.guild == GIL_MIL)
    {
    // если свидетель друг нападающему и свидетель не друг жертве
    if(Npc_GetAttitude(self,other) == ATT_FRIENDLY) && (Npc_GetAttitude(self,victim) != ATT_FRIENDLY)
    {
    // свидетель атакует жертву
    B_Attack(self,victim,AR_GuardStopsFight,0);
    return;
    }
    // иначе, если свидетель друг жертве и свидетель не друг нападающему
    else if(Npc_GetAttitude(self,victim) == ATT_FRIENDLY) && (Npc_GetAttitude(self,other) != ATT_FRIENDLY)
    {
    // свидетель атакует нападающего
    B_Attack(self,other,AR_GuardStopsFight,0);
    return;
    }
    else // иначе (или оба друга или оба не друга)
    {
    // если нападающий ГГ
    if(Npc_IsPlayer(other))
    {
    // свидетель атакует жертву
    B_Attack(self,victim,AR_GuardStopsFight,0);
    return;
    }
    // иначе, если жертва ГГ
    else if(Npc_IsPlayer(victim))
    {
    // свидетель атакует нападающего
    B_Attack(self,other,AR_GuardStopsFight,0);
    return;
    }
    else // иначе
    {
    // свидетель атакует нападающего
    B_Attack(self,other,AR_GuardStopsFight,0);
    return;
    };
    };
    };
    // ***** помощь нападающему, сражающемуся с вором *****
    // если нападающий имел причину для сражения
    if((other.aivar[AIV_ATTACKREASON] == AR_UseMob) // использование чужого МОВа
    || (other.aivar[AIV_ATTACKREASON] == AR_Theft) // воровство
    || (other.aivar[AIV_ATTACKREASON] == AR_LeftPortalRoom)) // вход в чужое помещение
    // и свидетель друг нападающему
    && (Npc_GetAttitude(self,other) == ATT_FRIENDLY)
    {
    // если у свидетеля есть причина атаковать вора жертву
    if(C_WantToAttackThief(self,victim))
    {
    // свидетель атакует жертву
    B_Attack(self,victim,AR_GuardCalledToThief,0);
    };
    return;
    };
    // ***** помощь жертве, сражающейся с вором *****
    // аналогично предыдущему if
    if((victim.aivar[AIV_ATTACKREASON] == AR_UseMob)
    || (victim.aivar[AIV_ATTACKREASON] == AR_Theft)
    || (victim.aivar[AIV_ATTACKREASON] == AR_LeftPortalRoom))
    && (Npc_GetAttitude(self,victim) == ATT_FRIENDLY)
    {
    if(C_WantToAttackThief(self,other))
    {
    B_Attack(self,other,AR_GuardCalledToThief,0);
    };
    return;
    };
    // если нападающий имел причину для сражения как защита своего помещения и свидетель друг нападающему
    if(other.aivar[AIV_ATTACKREASON] == AR_ClearRoom) && (Npc_GetAttitude(self,other) == ATT_FRIENDLY)
    {
    // свидетель атакует жертву
    B_Attack(self,victim,AR_GuardCalledToRoom,0);
    return;
    };
    // аналогично предыдущему, только свидетель помогает жертве
    if(victim.aivar[AIV_ATTACKREASON] == AR_ClearRoom) && (Npc_GetAttitude(self,victim) == ATT_FRIENDLY)
    {
    B_Attack(self,other,AR_GuardCalledToRoom,0);
    return;
    };
    // если расстояния между (свидетелем и жертвой) и (свидетелем и нападающим) > макс. дальности действия пассивного восприятия
    if(Npc_GetDistToNpc(self,other) > PERC_DIST_INTERMEDIAT) && (Npc_GetDistToNpc(self,victim) > PERC_DIST_INTERMEDIAT)
    {
    return;
    };
    // если свидетель враг нападающему или жертве
    if(Npc_GetAttitude(self,other) == ATT_HOSTILE) || (Npc_GetAttitude(self,victim) == ATT_HOSTILE)
    {
    // если свидетель бандит
    if(self.guild == GIL_BDT)
    {
    // продолжение анализа
    }
    else
    {
    return;
    };
    };
    // если свидетель не видит по прямой жертву
    if(!Npc_CanSeeNpcFreeLOS(self,victim))
    {
    return;
    };
    // очистка очереди состояний свидетеля
    Npc_ClearAIQueue(self);
    // очистка восприятий свидетеля
    B_ClearPerceptions(self);
    // перевод свидетеля в состояние наблюдения на сражением
    AI_StartState(self,ZS_WatchFight,0,"");
    return;
    };



    // *****************************************************************
    // Функция реакции НПС на звук шагов ГГ или на звук упавшего предмета
    // -----------------------------------------------------------------
    // Вызывается в качестве реакции на пассивное восприятие PERC_ASSESSQUIETSOUND
    // *****************************************************************


    Открыть спойлер
    func void B_AssessQuietSound()
    {
    // other - НПС источник шума (ГГ), self - свидетель
    // если источник шума отсутствует
    if(!Hlp_IsValidNpc(other))
    {
    return;
    };
    // если расстояние по высоте между источником шума и свидетелем > дистанции реагирования по высоте
    if(Npc_GetHeightToNpc(self,other) > PERC_DIST_HEIGHT)
    {
    return;
    };
    // если ГГ находится в доме, принадлежащим любой гильдии, и расстояние по высоте между свидетелем и ГГ > дистанции реакции через закрытые двери
    if(Wld_GetPlayerPortalGuild() >= GIL_NONE) && (Npc_GetHeightToNpc(self,other) > PERC_DIST_INDOOR_HEIGHT)
    {
    return;
    };
    };
    // если есть реакция на вошедшего в помещение
    if(B_AssessEnterRoom())
    {
    return;
    };
    // если свидетель является охранником ворот
    if(C_NpcIsGateGuard(self))
    {
    return;
    };
    // если ГГ и свидетель не враги и свидетель не имеет для ГГ важной информации
    if(Npc_GetAttitude(self,other) != ATT_HOSTILE) && (Npc_CheckInfo(self,1) == FALSE)
    {
    return;
    };
    // если ГГ и свидетель враги
    if(Npc_GetAttitude(self,other) == ATT_HOSTILE)
    // и (у свидетеля личных врагов не было или (ГГ переодетый бандит и свидетель бандит))
    && ((self.aivar[AIV_EnemyOverride] == TRUE) || (C_PlayerIsFakeBandit(self,other) && (self.guild == GIL_BDT)))
    {
    return;
    };
    // если свидетель видит источник звука (моё примечание: возможно здесь ошибка, необходимо поменять условие на противоположное???)
    if(Npc_CanSeeSource(self))
    {
    return;
    };
    // очистка очереди AI команд свидетеля
    Npc_ClearAIQueue(self);
    // очистка восприятий свидетеля
    B_ClearPerceptions(self);
    // перевод свидетеля в состояние наблюдения за ГГ
    AI_StartState(self,ZS_ObservePlayer,1,"");
    return;
    };



    // **************************************************************
    // Функция реакции НПС на предупреждение
    // ---------------------------------------
    // Предупреждение посылается только скриптами (вызов функции Npc_SendPassivePerc), ядром не испоьзуется
    // **************************************************************


    Открыть спойлер
    func void B_AssessWarn()
    {
    // self - свидетель, other - преступник, victim - жертва
    // если свидетель жертва
    if(Hlp_GetInstanceID(victim) == Hlp_GetInstanceID(self))
    {
    return;
    };
    // если свидетель находится в состоянии реакции на обнаженное оружие или наблюдает за ГГ
    if(Npc_IsInState(self,ZS_ReactToWeapon)) || (Npc_IsInState(self,ZS_ObservePlayer))
    {
    return;
    };
    // если преступник монстр
    if(other.guild > GIL_SEPERATOR_HUM)
    {
    return;
    };
    // если свидетель охранник ворот
    if(C_NpcIsGateGuard(self))
    {
    return;
    };
    // очистка очереди AI команд свидетеля
    Npc_ClearAIQueue(self);
    // очистка восприятий свидетеля
    B_ClearPerceptions(self);
    // перевод свидетеля в состояние наблюдения за ГГ
    AI_StartState(self,ZS_ObservePlayer,0,"");
    return;
    };



    // ****************************************************
    // Функция реакции НПС на важную информацию для разговора
    // ----------------------------------------------------
    // Вызывается в качестве реакции на пассивное восприятие PERC_ASSESSTALK
    // ****************************************************


    Открыть спойлер
    func void B_AssessTalk()
    {
    // other - НПС приемник информации (обычно ГГ), self - НПС источник информации

    // Тестовый кусок (можно выкинуть из скрипта) [не рассматриваю]
    var c_npc PCL;
    // Инспектор уровня
    PCL = Hlp_GetNpc(PC_Levelinspektor);
    var c_npc PCR;
    // Рокфеллер
    PCR = Hlp_GetNpc(PC_Rockefeller);
    // если приемник информации Инспектор уровня или Рокфеллер
    if(Hlp_GetInstanceID(other) == Hlp_GetInstanceID(PCL)) || (Hlp_GetInstanceID(other) == Hlp_GetInstanceID(PCR))
    {
    PrintScreen(ConcatStrings("Stimme: ",IntToString(self.voice)),-1,70,FONT_Screen,2);
    PrintScreen("KEIN HERO!",-1,-1,FONT_Screen,2);
    PrintScreen(IntToString(self.aivar[AIV_FollowDist]),-1,70,FONT_Screen,2);
    if(C_NpcIsInQuarter(self) == Q_KASERNE)
    {
    PrintScreen("Q_KASERNE",-1,30,FONT_Screen,2);
    };
    if(C_NpcIsInQuarter(self) == Q_GALGEN)
    {
    PrintScreen("Q_GALGEN",-1,30,FONT_Screen,2);
    };
    if(C_NpcIsInQuarter(self) == Q_MARKT)
    {
    PrintScreen("Q_MARKT",-1,30,FONT_Screen,2);
    };
    if(C_NpcIsInQuarter(self) == Q_TEMPEL)
    {
    PrintScreen("Q_TEMPEL",-1,30,FONT_Screen,2);
    };
    if(C_NpcIsInQuarter(self) == Q_UNTERSTADT)
    {
    PrintScreen("Q_UNTERSTADT",-1,30,FONT_Screen,2);
    };
    if(C_NpcIsInQuarter(self) == Q_HAFEN)
    {
    PrintScreen("Q_HAFEN",-1,30,FONT_Screen,2);
    };
    if(C_NpcIsInQuarter(self) == Q_OBERSTADT)
    {
    PrintScreen("Q_OBERSTADT",-1,30,FONT_Screen,2);
    };
    return;
    };

    // Нормальное начала функции
    // если источник информации монстр
    if(self.guild > GIL_SEPERATOR_HUM)
    {
    // если монстр не имеет важной информации
    if(Npc_CheckInfo(self,1) == FALSE)
    {
    // если монстру вообще нечего сказать
    if(Npc_CheckInfo(self,0) == FALSE)
    {
    return;
    };
    };
    };
    // если источник информации человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {

    // если НПС источник информации враг ГГ
    if(B_AssessEnemy())
    {
    return;
    };
    // если НПС источник информации знает, что ГГ убийца и у него есть причина атакоывать убийцу
    if(B_GetPlayerCrime(self) == CRIME_MURDER) && (C_WantToAttackMurder(self,other))
    {
    // источник информации атакует ГГ убийцу
    B_Attack(self,other,AR_HumanMurderedHuman,0);
    return;
    };
    // если ГГ переодетый бандит и источник информации не бандит
    if(C_PlayerIsFakeBandit(self,other) == TRUE) && (self.guild != GIL_BDT)
    {
    // источник информации атакует ГГ
    B_Attack(self,other,AR_GuildEnemy,0);
    return;
    };
    // если ГГ отказался от разговора
    if(C_RefuseTalk(self,other))
    {
    // если ГГ член подставной гильдии
    if(C_PlayerHasFakeGuild(self,other)
    {
    // очистка очереди AI состояний источника информации
    Npc_ClearAIQueue(self);
    // источник информации переходит в конечное состояние комментирования подставной гильдии
    AI_StartState(self,ZS_CommentFakeGuild,1,"");
    return;
    }
    else
    {
    // источник информации произносит SVM фразу "Оставь меня в покое!"
    B_Say(self,other,"$NOTNOW");
    return;
    };
    };
    };
    // если ГГ еще не говорил с источником информации
    if(self.aivar[AIV_NpcStartedTalk] == FALSE)
    {
    // если источник идет или бежит
    if(C_BodyStateContains(self,BS_WALK) || C_BodyStateContains(self,BS_RUN))
    {
    // ГГ произносит SVM фразу "Подожди!"
    B_Say(other,self,"$SC_HEYWAITASECOND");
    }
    // иначе, если источник информации не видит ГГ
    else if(!Npc_CanSeeNpc(self,other))
    {
    var int rnd;
    // генерация случайного числа от 0 до 99
    rnd = Hlp_Random(100);
    // ГГ призносит фразу
    if(rnd <= 25) { B_Say(other,self,"$SC_HEYTURNAROUND"); } // звучит SVM фраза "Эй ты!"
    else if (rnd <= 50) { B_Say(other,self,"$SC_HEYTURNAROUND02"); } // звучит SVM фраза "Эй ты!"
    else if (rnd <= 75) { B_Say(other,self,"$SC_HEYTURNAROUND03"); } // звучит SVM фраза "Эй!"
    else if (rnd <= 99) { B_Say(other,self,"$SC_HEYTURNAROUND04"); }; // звучит SVM фраза "Эй!"
    };
    };
    // очистка очереди AI состояний источника информации
    Npc_ClearAIQueue(self);
    // очистка восприятий источника информации
    B_ClearPerceptions(self);
    // если источник информации сидит
    if(C_BodyStateContains(self,BS_SIT))
    {
    // если ГГ заговорил с источником информации
    if(self.aivar[AIV_NpcStartedTalk] == TRUE)
    {
    // ГГ быстро останавливается
    AI_StandUpQuick(other);
    }
    else // иначе
    {
    // ГГ останавливается
    AI_StandUp(other);
    };
    // если источник информации видит ГГ
    if(Npc_CanSeeNpc(self,other))
    {
    // источник информации переходит в состояние разговора, оставаясь сидеть
    AI_StartState(self,ZS_Talk,0,"");
    }
    else // иначе (не видит ГГ)
    {
    // если источник информации наблюдал за ГГ
    if(Npc_IsInState(self,ZS_ObservePlayer))
    {
    // источник информации встает
    AI_StandUp(self);
    };
    // источник информации переходит в состояние разговора
    AI_StartState(self,ZS_Talk,1,"");
    };
    return;
    }
    else // иначе (не сидит)
    {
    // если ГГ заговорил с источником информации
    if(self.aivar[AIV_NpcStartedTalk] == TRUE)
    {
    // оба быстро останавливаются
    AI_StandUpQuick(self);
    AI_StandUpQuick(other);
    }
    else
    {
    // оба останавливаются
    AI_StandUp(self);
    AI_StandUp(other);
    };
    // источник информации переходит в состояние разговора
    AI_StartState(self,ZS_Talk,0,"");
    return;
    };
    };



    // **************************************
    // Функция реакции НПС на перемещение МОВа
    // --------------------------------------
    // Вызывается ядром системы как реакция на пассивное восприятие PERC_MOVEMOB
    // **************************************


    Открыть спойлер
    func void B_MoveMob()
    {
    // self - НПС перемещающий МОВ (ГГ)
    var string door;
    // получить имя перемещаемого МОВа
    door = Npc_GetDetectedMob(self);
    // если МОВ дверь
    if(Hlp_StrCmp(door,"DOOR"))
    {
    // если дверь закрыта
    if(Wld_GetMobState(self,door) == 0)
    {
    // очистка очереди AI состояний ГГ
    Npc_ClearAIQueue (self);
    // ГГ открывает дверь
    AI_UseMob(self,door,1);
    // зафиксировать состояние двери
    AI_UseMob(self,door,-1);
    };
    }
    else // иначе
    {
    return;
    };
    // ГГ продолжает свои дела
    AI_ContinueRoutine(self);
    };

    Конец 5 параграфа.
    Вот и все основные восприятия, на которые реагируют люди, есть еще дополнительные восприятия, которые инициализируются в функциях состояний, их мы рассмотрим позже.
    Все файлы активных и пассивных восприятий людей находятся в директории ..\AI\Human\B_Human\ и имеют имена эквивалентные функциям восприятий. Файл восприятия магии находится в директории ..\AI\Magic\
    Примечание: Файл ..\AI\Human\B_Human\B_AssessObserveSuspect.d можно удалить из скриптов, по причине его абсолютной бесполезности.
     
    Последнее редактирование: 10 дек 2014
    Valik, Orc Hunter, Ur-tRall и ещё 1 пользователь поблагодарили.
  14. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    6. Функции обработки восприятий монстров.
    // **************************************************
    // Функция реакции монстров на врага.
    // --------------------------------------------------
    // Вызывается ядром системы в качестве реакции на активное восприятие PERC_ASSESSENEMY.
    // **************************************************


    Открыть спойлер
    func void B_MM_AssessEnemy()
    {
    // self - НПС монстр, other - враг
    // если монстр дракон и ГГ имеет "Заряженный глаз Инноса"
    if(self.guild == GIL_DRAGON) && (Npc_HasItems(hero,ItMi_InnosEye_Mis) >= 1)
    {
    return;
    };
    // если монстр или враг не могут атаковать
    if((self.aivar[AIV_NoFightParker] == TRUE) || (other.aivar[AIV_NoFightParker] == TRUE))
    {
    return;
    };
    // если личных врагов у монстра нет и враг человек
    if(self.aivar[AIV_EnemyOverride] == TRUE) && (other.guild < GIL_SEPERATOR_HUM)
    {
    return;
    };
    // ------- TESTMODE: Levelinspektor wird ignoriert ------
    var c_npc PCL;
    // "Инспектор уровня"
    PCL = Hlp_GetNpc(PC_Levelinspektor);
    // если враг "Инспектор уровня"
    if(Hlp_GetInstanceID(other) == Hlp_GetInstanceID(PCL))
    {
    return;
    };
    var c_npc MGO;
    // Магический голем
    MGO = Hlp_GetNpc(MagicGolem);
    var c_npc LAR;
    // Ларес
    LAR = Hlp_GetNpc(VLK_449_Lares);
    // если враг Ларес и монстр Магический голем
    if(Hlp_GetInstanceID(other) == Hlp_GetInstanceID(LAR)) && (Hlp_GetInstanceID(self) == Hlp_GetInstanceID(MGO))
    {
    return;
    };
    // если монстр находится не далее 5м от точки "OC_RAMP_07"
    if(Npc_GetDistToWP(self,"OC_RAMP_07") <= 500)
    {
    return;
    };
    // если враг находится в режиме диалога
    if(other.aivar[AIV_INVINCIBLE] == TRUE)
    {
    return;
    };
    // если враг (плывет или ныряет) и монстр не полезет в воду
    if(C_BodyStateContains(other,BS_SWIM) || C_BodyStateContains(other,BS_DIVE)) && (self.aivar[AIV_MM_FollowInWater] == FALSE)
    {
    return;
    };
    // если расстояние по высоте между монстром и врагом > расстояния реакции по высоте
    if(Npc_GetHeightToNpc(self,other) > PERC_DIST_HEIGHT)
    {
    return;
    };
    // если ГГ враг и он превращен в монстра
    if(Npc_IsPlayer(other)) && (other.guild > GIL_SEPERATOR_HUM)
    {
    // если гильдии монстра и превращенного ГГ не враждебны
    if(Wld_GetGuildAttitude(self.guild,other.guild) != ATT_HOSTILE)
    {
    return;
    };
    };
    // если дальность обоняния монстра > макс. дальности действия активного восприятия монстров
    if(self.senses_range > PERC_DIST_MONSTER_ACTIVE_MAX)
    {
    // если расстояние между монстром и врагом > макс. дальности действия активного восприятия монстров
    if(Npc_GetDistToNpc(self,other) > PERC_DIST_MONSTER_ACTIVE_MAX)
    {
    // если монстр не видит врага
    if(!Npc_CanSeeNpc(self,other))
    {
    return;
    };
    };
    };
    // если монстр орк или дружественный орк
    if(self.guild == GIL_ORC) || (self.guild == GIL_FRIENDLY_ORC)
    {
    // если враг подкрадавается или стоит
    if(C_BodyStateContains(other,BS_SNEAK)) || (C_BodyStateContains(other,BS_STAND))
    {
    // если монстр не видит врага
    if(!Npc_CanSeeNpc(self,other))
    {
    return;
    };
    };
    };
    // если монстр не видит врага по прямой (например, враг за стеной)
    if(!Npc_CanSeeNpcFreeLOS(self,other))
    {
    return;
    };
    // если монстр является членом партии (вызванный)
    if(self.aivar[AIV_PARTYMEMBER] == TRUE)
    {
    // если враг монстра является другом НПС
    if(other.npctype == NPCTYPE_FRIEND)
    {
    return;
    };
    // очистка очереди AI состояний монстра
    Npc_ClearAIQueue(self);
    // монстр выбирает цель
    Npc_SetTarget(self,other);
    // очистка восприятий монстра
    B_ClearPerceptions(self);
    // переход монстра в состояние атаки
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    // если монстр не угрожает перед атакой (атакует сразу)
    if(self.aivar[AIV_MM_ThreatenBeforeAttack] == FALSE)
    {
    Npc_ClearAIQueue(self);
    Npc_SetTarget(self,other);
    B_ClearPerceptions(self);
    // переход монстра в состояние атаки
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    // если монстр находится в состоянии "пожирания падали"
    if(Npc_IsInState(self,ZS_MM_EatBody))
    {
    // если расстояние между монстром и врагом <= дистанции атаки монстров
    if(Npc_GetDistToNpc(self,other) <= FIGHT_DIST_MONSTER_ATTACKRANGE)
    {
    Npc_ClearAIQueue(self);
    Npc_SetTarget(self,other);
    B_ClearPerceptions(self);
    // переход монстра в состояние атаки
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    return;
    };
    // если монстр находится в соостоянии охоты
    if(Npc_IsInState(self,ZS_MM_Hunt))
    {
    // если расстояние между монстром и врагом <= дистанции атаки монстров
    if(Npc_GetDistToNpc(self,other) <= FIGHT_DIST_MONSTER_ATTACKRANGE)
    {
    Npc_ClearAIQueue(self);
    Npc_SetTarget(self,other);
    B_ClearPerceptions(self);
    // переход монстра в состояние атаки
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    }
    else
    {
    return;
    };
    };
    // если монстра устраивает добыча в виде врага
    if(C_PredatorFoundPrey(self,other))
    {
    Npc_ClearAIQueue(self);
    Npc_SetTarget(self,other);
    B_ClearPerceptions(self);
    // переход монстра в состояние охоты на врага
    AI_StartState(self,ZS_MM_Hunt,0,"");
    return;
    };
    // если врага устраивает добыча в виде монстра
    if(C_PredatorFoundPrey(other,self))
    {
    // если враг находится в соостоянии охоты и если расстояние между монстром и врагом <= дистанции преследования
    if(!Npc_IsInState(other,ZS_MM_Hunt)) && (Npc_GetDistToNpc(self,other) <= FIGHT_DIST_MONSTER_FLEE)
    {
    Npc_ClearAIQueue(self);
    Npc_SetTarget(self,other);
    B_ClearPerceptions(self);
    // переход монстра в состояние преследования
    AI_StartState(self,ZS_MM_Flee,0,"");
    return;
    }
    else
    {
    return;
    };
    };
    // очистка очереди AI состояний монстра
    Npc_ClearAIQueue(self);
    // очистка восприятий монстра
    B_ClearPerceptions(self);
    // переход монстра в состояние угрозы
    AI_StartState(self,ZS_MM_ThreatenEnemy,0,"");
    return;
    };



    // ******************************************
    // Функция реакции монстров на мертвое тело
    // ------------------------------------------
    // Вызывается ядром системы в качестве реакции на пассивное восприятие PERC_ASSESSBODY
    // ******************************************


    Открыть спойлер
    func void B_MM_AssessBody()
    {
    // self - монстр, other - труп
    // если монстр принадлежит к оркам
    if(self.guild > GIL_SEPERATOR_ORC)
    {
    return;
    };
    // если расстояние по высоте между монстром и трупом > расстояния реакции по высоте
    if(Npc_GetHeightToNpc(self,other) > PERC_DIST_HEIGHT)
    {
    return;
    };
    // если приоритетом монстра является нападение
    if(self.aivar[AIV_MM_PRIORITY] == PRIO_ATTACK)
    {
    return;
    };
    // если труп не нравится монстру
    if(!C_WantToEat(self,other))
    {
    return;
    };
    // если монстр находится в состоянии атаки
    if(Npc_IsInState(self,ZS_MM_Attack))
    {
    var c_npc stoerenfried;
    // последний атакованный НПС
    stoerenfried = Hlp_GetNpc(self.aivar[AIV_LASTTARGET]);
    // если расстояние между атакованным НПС и трупом <= дистанции атаки монстров
    if(Npc_GetDistToNpc(stoerenfried,other) <= FIGHT_DIST_MONSTER_ATTACKRANGE)
    {
    return;
    };
    };
    // очистка очереди AI состояний монстра
    Npc_ClearAIQueue(self);
    // очистка восприятий монстра
    B_ClearPerceptions(self);
    // переход в состояние пожирания трупа
    AI_StartState(self,ZS_MM_EatBody,0,"");
    return;
    };



    // ********************************************************
    // Функция реакции монстра на повреждение
    // --------------------------------------------------------
    // Вызывается ядром системы в качестве реакции на пассивное восприятие PERC_ASSESSDAMAGE
    // ********************************************************


    Открыть спойлер
    func void B_MM_AssessDamage()
    {
    // self - монстр жертва, other - НПС агрессор
    // установить монстру приоритет на атаку
    self.aivar[AIV_MM_PRIORITY] = PRIO_ATTACK;
    // вызов функции реакции на повреждение "Когтем Белиара"
    B_BeliarsWeaponSpecialDamage(other,self);
    // если агрессор имеет "Святой молот"
    if(Npc_HasItems(other,Holy_Hammer_MIS) > 0)
    {
    var c_npc MagGol;
    // Магический голем
    MagGol = Hlp_GetNpc(MagicGolem);
    // проинициализировать глобальную переменную item "Святым молотом"
    Npc_GetInvItem(other,Holy_Hammer_MIS);
    var c_item OthWeap;
    // оружие, которое агрессор держит в руке
    OthWeap = Npc_GetReadiedWeapon(other);
    // если жертва Магический голем и оружие у агрессора в руке "Святой молот"
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(MagGol)) && (Hlp_GetInstanceID(OthWeap) == Hlp_GetInstanceID(item))
    {
    // Жизнь Магического голема -= 1000 LP
    Npc_ChangeAttribute(self,ATR_HITPOINTS,-1000);
    return;
    };
    };
    // если жертва Каменный сторож и у него нет врагов
    if(self.guild == GIL_STONEGUARDIAN) && (self.aivar[AIV_EnemyOverride] == TRUE)
    {
    // пробуждение Каменного сторожа
    B_AWAKE_STONEGUARDIAN(self);
    };
    // если агрессора устраивает добыча в виде жертвы
    if(C_PredatorFoundPrey(other,self))
    {
    // очистка очереди AI состояний жертвы
    Npc_ClearAIQueue(self);
    // установка цели для жертвы
    Npc_SetTarget(self,other);
    // очистка восприятий жертвы
    B_ClearPerceptions(self);
    // жертва убегает от агрессора
    AI_StartState(self,ZS_MM_Flee,0,"");
    return;
    };
    // если жертва находится в состоянии атаки
    if(Npc_IsInState(self,ZS_MM_Attack))
    {
    // если агрессор ГГ и жертва член партии
    if(Npc_IsPlayer(other)) && (self.aivar[AIV_PARTYMEMBER] == TRUE)
    {
    return;
    };
    // если жертва скелет и агрессор маг скелетов
    if(self.aivar[AIV_MM_REAL_ID] == ID_SKELETON) && (other.aivar[AIV_MM_REAL_ID] == ID_SKELETON_MAGE)
    {
    return;
    };
    // если агрессор не является НПС, атакованным жертвой
    if(Hlp_GetInstanceID(other) != self.aivar[AIV_LASTTARGET])
    {
    // если удар жертве нанесен агрессором не первый раз
    if(self.aivar[AIV_HitByOtherNpc] == Hlp_GetInstanceID(other))
    {
    // смена цели (жертва будет атаковать агрессора)
    Npc_SetTarget(self,other);
    }
    else
    {
    // при первом ударе жертве записывается ID агрессора
    self.aivar[AIV_HitByOtherNpc] = Hlp_GetInstanceID(other);
    };
    };
    return;
    };
    // очистка очереди AI состояний жертвы
    Npc_ClearAIQueue(self);
    // установка цели для жертвы
    Npc_SetTarget(self,other);
    // очистка восприятий жертвы
    B_ClearPerceptions(self);
    // жертва атакует агрессора
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };



    // ****************************************************************
    // Функция реакции монстра на убийство и на повреждение других НПС
    // ----------------------------------------------------------------
    // Вызывается в качестве реакции на пассивные восприятия PERC_ASSESSOTHERSDAMAGE и PERC_ASSESSMURDER
    // ****************************************************************


    Открыть спойлер
    func void B_MM_AssessOthersDamage()
    {
    // self - монстр наблюдатель, other - агрессор, victim - жертва (труп)
    // если расстояния между (наблюдателем и жертвой) и (наблюдателем и агрессором) > макс. дальности действия восприятия
    if(Npc_GetDistToNpc(self,victim) > PERC_DIST_INTERMEDIAT) && (Npc_GetDistToNpc(self,other) > PERC_DIST_INTERMEDIAT)
    {
    return;
    };
    // если наблюдатель не видит жертву
    if(!Npc_CanSeeNpcFreeLOS(self,victim))
    {
    return;
    };
    // если наблюдатель член партии
    if(self.aivar[AIV_PARTYMEMBER] == TRUE)
    {
    // если жертва ГГ
    if(Npc_IsPlayer(victim))
    {
    // очистка очереди AI состояний наблюдателя
    Npc_ClearAIQueue(self);
    // очистка восприятий наблюдателя
    B_ClearPerceptions(self);
    // установка в качестве цели агрессора
    Npc_SetTarget(self,other);
    // монстр наблюдатель атакует агрессора
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    // если агрессор ГГ и жертва жива
    if(Npc_IsPlayer(other)) && (!Npc_IsDead(victim))
    {
    // очистка очереди AI состояний наблюдателя
    Npc_ClearAIQueue(self);
    // очистка восприятий наблюдателя
    B_ClearPerceptions(self);
    // установка в качестве цели жертвы
    Npc_SetTarget(self,victim);
    // монстр наблюдатель атакует жертву
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    };
    // если наблюдатель волк
    if(self.guild == GIL_WOLF)
    {
    // если жертва волк и агрессор волк и волк агрессор есть ГГ и жертва убита
    if(victim.guild == GIL_WOLF) && (other.guild == GIL_WOLF) && Npc_IsPlayer(other) && Npc_IsDead(victim)
    {
    Npc_ClearAIQueue(self);
    B_ClearPerceptions(self);
    // перевод наблюдателя в состояние вызванного монстра
    self.start_aistate = ZS_MM_Rtn_Summoned;
    AI_StartState(self,ZS_MM_Rtn_Summoned,0,"");
    return;
    };
    };
    // если наблюдатель каменный страж и жертва каменный страж и у наблюдателя нет врагов
    if(self.guild == GIL_STONEGUARDIAN) && (victim.guild == GIL_STONEGUARDIAN) && (self.aivar[AIV_EnemyOverride] == TRUE)
    {
    // пробуждение каменного стража наблюдателя
    B_AWAKE_STONEGUARDIAN(self);
    };
    // если гильдии наблюдателя и жертвы дружественны и гильдии наблюдателя и агрессора не дружественные
    if(Wld_GetGuildAttitude(self.guild,victim.guild) == ATT_FRIENDLY) && (Wld_GetGuildAttitude(self.guild,other.guild) != ATT_FRIENDLY)
    {
    Npc_ClearAIQueue(self);
    B_ClearPerceptions(self);
    Npc_SetTarget(self,other);
    // наблюдатель атакует агрессора
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    // если гильдии наблюдателя и агрессора дружественны и гильдии наблюдателя и жертвы не дружественные
    if(Wld_GetGuildAttitude(self.guild,other.guild) == ATT_FRIENDLY) && (Wld_GetGuildAttitude(self.guild,victim.guild) != ATT_FRIENDLY)
    // и жертва не мертва
    && (!Npc_IsDead(victim))
    {
    Npc_ClearAIQueue(self);
    B_ClearPerceptions(self);
    Npc_SetTarget(self,victim);
    // наблюдатель атакует жертву
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    };



    // ******************************************************
    // Функция реакции монстров на предупреждение
    // ------------------------------------------------------
    // Предупреждение посылается только скриптами (вызов функции Npc_SendPassivePerc), ядром не испоьзуется
    // ******************************************************


    Открыть спойлер
    func void B_MM_AssessWarn()
    {
    // self - наблюдатель, other - агрессор, victim - жертва
    // если наблюдатель орк
    if(self.guild > GIL_SEPERATOR_ORC)
    {
    // если наблюдатель находится в состоянии атаки
    if(Npc_IsInState(self,ZS_MM_Attack))
    {
    return;
    };
    // если гильдия наблюдателя дружественна гильдии агрессора
    if(Wld_GetGuildAttitude(self.guild,other.guild) == ATT_FRIENDLY)
    {
    // очистка очереди AI команд наблюдателя
    Npc_ClearAIQueue(self);
    // установка жертвы в качестве цели наблюдателю
    Npc_SetTarget(self,victim);
    // очистка восприятий наблюдателя
    B_ClearPerceptions(self);
    // наблюдатель атакует жертву
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    return;
    };
    // если агрессор человек
    if(other.guild < GIL_SEPERATOR_HUM)
    {
    return;
    };
    // если расстояние по высоте между наблюдателем и агрессором > дистанции реагирования по высоте
    if(Npc_GetHeightToNpc(self,other) > PERC_DIST_HEIGHT)
    {
    return;
    };
    // если наблюдатель находится в состоянии атаки
    if(Npc_IsInState(self,ZS_MM_Attack))
    {
    // если наблюдателя устраивает добыча в виде агрессора и приоритет наблюдателя "пожирание падали"
    if(C_PredatorFoundPrey(self,other)) && (self.aivar[AIV_MM_PRIORITY] == PRIO_EAT)
    {
    // очистка очереди AI команд наблюдателя
    Npc_ClearAIQueue(self);
    // установка агрессора в качестве цели наблюдателю
    Npc_SetTarget(self,other);
    }
    else // иначе цель не меняется
    {
    // возврат цели для наблюдателя (последняя бывшая цель)
    other = Hlp_GetNpc(self.aivar[AIV_LASTTARGET]);
    };
    return;
    };
    // если гильдии наблюдателя и агрессора одинаковы и наблюдатель охотится стаей
    if(self.guild == other.guild) && (self.aivar[AIV_MM_Packhunter] == TRUE)
    {
    // если наблюдатель волк и жертва волк и жертва ГГ (превращенный в волка)
    if(self.guild == GIL_WOLF) && (victim.guild == GIL_WOLF) && Npc_IsPlayer(victim)
    {
    return;
    };
    // если агрессор находится в состоянии атаки
    if(Npc_IsInState(other,ZS_MM_Attack))
    {
    Npc_ClearAIQueue(self);
    Npc_SetTarget(self,victim);
    B_ClearPerceptions(self);
    // наблюдатель атакует жертву
    AI_StartState(self,ZS_MM_Attack,0,"");
    return;
    };
    // если агрессор находится в состоянии угрозы врагу
    if(Npc_IsInState(other,ZS_MM_ThreatenEnemy))
    {
    // агрессор бежит
    AI_SetWalkmode(self,NPC_RUN);
    // к жертве
    AI_GotoNpc(self,victim);
    return;
    };
    };
    return;
    };



    // ********************************************************
    // Функция реакции монстров на ГГ
    // --------------------------------------------------------
    // Вызывается ядром системы в качестве реакции на активное восприятие PERC_ASSESSPLAYER
    // Используется только конкретными монстрами
    // ********************************************************


    Открыть спойлер
    func void B_MM_AssessPlayer()
    {
    // other - ГГ, self - монстр
    // если ГГ в состоянии диалога
    if(other.aivar[AIV_INVINCIBLE] == TRUE)
    {
    return;
    };
    // если ГГ мертв, без сознания и т.д. (обездвижен)
    if(C_NpcIsDown(other))
    {
    return;
    };
    // подготовка разговора ГГ с драконами
    B_AssignDragonTalk(self);
    // если расстояние между ГГ и монстром < 7м и монстр имеет важную информацию
    if(Npc_GetDistToNpc(self,other) <= 700) && (Npc_CheckInfo(self,1))
    {
    // если монстр дракон или (монстр не дракон и расстояние между монстром и ГГ <= дистанции начала диалога)
    if(self.guild == GIL_DRAGON) || ((self.guild != GIL_DRAGON) && (Npc_GetDistToNpc(self,other) <= PERC_DIST_DIALOG))
    {
    // если ГГ не падает и не плывет и не ныряет
    if(!C_BodyStateContains(other,BS_FALL)) && (!C_BodyStateContains(other,BS_SWIM)) && (!C_BodyStateContains(other,BS_DIVE))
    {
    // у монстра устанавливается флаг начала разговора
    self.aivar[AIV_NpcStartedTalk] = TRUE;
    // реакция ГГ на предлагаемый разговор
    B_AssessTalk();
    return;
    };
    };
    };
    // если монстр член партии ГГ
    if(self.aivar[AIV_PARTYMEMBER] == TRUE)
    {
    // если расстояние между ГГ и монстром < 5м и монстр не стоит
    if(Npc_GetDistToNpc(self,hero) < 500) && (!C_BodyStateContains(self,BS_STAND))
    {
    // очистка очереди AI состояний монстра
    Npc_ClearAIQueue(self);
    // монстр останавливается
    AI_StandUp(self);
    // и поворачивается к ГГ
    AI_TurnToNpc(self,hero);
    };
    };
    };

    Все файлы активных и пассивных восприятий монстров находятся в директории ..\AI\Monster\B_Monster\ и имеют имена, эквивалентные функциям восприятий.
     
    Последнее редактирование: 10 дек 2014
    Orc Hunter, Ur-tRall и Валера поблагодарили.
  15. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    7. Описание обработчиков состояний НПС.

    Все имена функций состояний должны начинаться с ZS_.
    Каждый процесс обработки соответствующего состояния состоит из 3х функций: ZS_xxx, ZS_xxx-Loop, ZS_xxx_End, где ххх - имя соответствующего состояния.
    Этим функциям соответствуют 3 фазы одного состояния НПС.
    1 фаза - Begin: инициализация состояния НПС.
    2 фаза - Loop: цикл выполнения последовательности действий НПС. Функция 2 фазы должна возвращать или LOOP_CONTINUE - продолжение фазы или LOOP_END - конец фазы.
    3 фаза - End: завершение состояния НПС.
    Системная функция AI_StartState может управлять последовательностью выполнения фаз состояний, за это отвечает параметр stateBehaviour, если он = 0, то выполняются все фазы состояния последовательно, если он = 1, то выполняется только заключительная фаза 3.
    Эта функция подробно описана в соответствующей теме.
     
    Orc Hunter и Валера поблагодарили.
  16. MEG@VOLT

    MEG@VOLT ★★★★★★★
    Модератор

    Регистрация:
    24 мар 2006
    Сообщения:
    1.604
    Благодарности:
    647
    Баллы:
    290
    8. Функции состояний людей.

    Все файлы состояний людей расположены в директории ..AI\Human\ZS_Human
    // ******************************
    // Состояние атаки
    // ******************************


    Открыть спойлер
    // Функция обработки вспомогательного восприятия PERC_ASSESSSURPRISE
    // Вызывается ядром системы когда ГГ превращается в человека из животного

    func void B_AssessSurprise()
    {
    // self - наблюдатель, other - ГГ
    // целью наблюдателя становится ГГ
    Npc_SetTarget(self,other);
    // причина нападения наблюдателя на ГГ - ГГ враг гильдии
    self.aivar[AIV_ATTACKREASON] = AR_GuildEnemy;
    };

    // Функция инициализации состояния атаки
    func void ZS_Attack()
    {
    // установить минимальный набор восприятий НПС
    Perception_Set_Minimal();
    // установить дополнительное восприятие на превращение
    Npc_PercEnable(self,PERC_ASSESSSURPRISE,B_AssessSurprise);
    // инициализировать переменную other (последняя цель)
    B_ValidateOther();
    // записать НПС id последней цели
    self.aivar[AIV_LASTTARGET] = Hlp_GetInstanceID(other);
    // если НПС должен убегать от цели
    if(C_WantToFlee(self,other))
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    // очистка восприятий НПС
    B_ClearPerceptions(self);
    // установка цели для НПС
    Npc_SetTarget(self,other);
    // НПС убегает от цели
    AI_StartState(self,ZS_Flee,0,"");
    return;
    };
    // если загрузки игры во время атаки не было
    if(self.aivar[AIV_LOADGAME] == FALSE)
    {
    // НПС называет причину атаки
    B_Say_AttackReason();
    };
    // если режим сражения у НПС выключен
    if(Npc_IsInFightMode(self,FMODE_NONE))
    {
    // НПС достает лучшее оружие дальнего радиуса поражения
    AI_EquipBestRangedWeapon(self);
    // НПС достает лучшее оружие ближнего радиуса поражения
    AI_EquipBestMeleeWeapon(self);
    };
    // НПС встает
    AI_StandUp(self);
    // перестает смотреть на других
    B_StopLookAt(self);
    // поворачивается к цели
    B_TurnToNpc(self,other);
    // бежит к цели
    AI_SetWalkmode(self,NPC_RUN);
    // сброс статуса предупреждений охраной
    self.aivar[AIV_Guardpassage_Status] = GP_NONE;
    // получить репутацию ГГ для конкретной локации
    self.aivar[AIV_LastAbsolutionLevel] = B_GetCurrentAbsolutionLevel(self);
    // сброс флага окончания преследования
    self.aivar[AIV_PursuitEnd] = FALSE;
    // сброс времени нахождения в состоянии
    self.aivar[AIV_StateTime] = 0;
    // сброс переменной вызова охраны (переменная AIV_TAPOSITION переопределена в этом состоянии)
    self.aivar[AIV_TAPOSITION] = 0;
    // сброс флага первого удара
    self.aivar[AIV_HitByOtherNpc] = 0;
    // сброс выбранного заклинания
    self.aivar[AIV_SelectSpell] = 0;
    };

    // Функция цикла атаки
    func int ZS_Attack_Loop()
    {
    // Грег идет к Декстеру
    B_Greg_ComesToDexter();
    // повторно инициализировать other целью
    Npc_GetTarget(self);
    // если расстояние между НПС и целью > дистанции прекращения сражения
    if(Npc_GetDistToNpc(self,other) > self.aivar[AIV_FightDistCancel])
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // НПС закончил преследование
    self.aivar[AIV_PursuitEnd] = TRUE;
    return LOOP_END;
    };
    // если время преследования превышает допустимое и НПС преследует
    if(Npc_GetStateTime(self) > self.aivar[AIV_MM_FollowTime]) && (self.aivar[AIV_PursuitEnd] == FALSE)
    {
    Npc_ClearAIQueue(self);
    AI_StandUp(self);
    // НПС закончил преследование
    self.aivar[AIV_PursuitEnd] = TRUE;
    // получить дистанцию до цели
    self.aivar[AIV_Dist] = Npc_GetDistToNpc(self,other);
    // обновить время состояния НПС
    self.aivar[AIV_StateTime] = Npc_GetStateTime(self);
    // если цель человек
    if(other.guild < GIL_SEPERATOR_HUM)
    {
    // НПС говорит цели "Беги, трус!" (SVM фраза)
    B_Say(self,other,"$RUNCOWARD");
    };
    };
    // если НПС завершил преследование цели
    if(self.aivar[AIV_PursuitEnd] == TRUE)
    {
    // если расстояние между НПС и целью > диапазона чувствительности НПС
    if(Npc_GetDistToNpc(self,other) > (self.senses_range))
    {
    return LOOP_END;
    };
    // если текущее время > предыдущего времени (прошла как минимум секунда)
    if(Npc_GetStateTime(self) > self.aivar[AIV_StateTime])
    {
    // если расстояние между НПС и целью меньше дистанции, когда НПС прекратил преследование
    if(Npc_GetDistToNpc(self,other) < self.aivar[AIV_Dist])
    // или (цель не бежит и не прыгает)
    || ((!C_BodyStateContains(other,BS_RUN)) && (!C_BodyStateContains(other,BS_JUMP)))
    {
    // сброс флага окончания преследования
    self.aivar[AIV_PursuitEnd] = FALSE;
    // сброс времени нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    // сброс времени нахождения в состоянии
    self.aivar[AIV_StateTime] = 0;
    }
    else
    {
    // НПС поворачивается к цели
    B_TurnToNpc(self,other);
    // получить дистанцию до цели
    self.aivar[AIV_Dist] = Npc_GetDistToNpc(self,other);
    // обновить время состояния НПС
    self.aivar[AIV_StateTime] = Npc_GetStateTime(self);
    };
    };
    return LOOP_CONTINUE;
    };
    // если уровень достигнутый ГГ в сражении > первоначального уровня
    if(B_GetCurrentAbsolutionLevel(self) > self.aivar[AIV_LastAbsolutionLevel])
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // прекращение атаки
    return LOOP_END;
    };
    // если (цель плывет или ныряет) и НПС не преследует цель в воде
    if(C_BodyStateContains(other,BS_SWIM) || C_BodyStateContains(other,BS_DIVE)) && (self.aivar[AIV_MM_FollowInWater] == FALSE)
    {
    Npc_ClearAIQueue(self);
    AI_StandUp(self);
    // НПС закончил преследование
    self.aivar[AIV_PursuitEnd] = TRUE;
    return LOOP_END;
    };
    // если НПС выжидает перед атакой
    if(self.aivar[AIV_WaitBeforeAttack] >= 1)
    {
    // ожидание 0.8 сек
    AI_Wait(self,0.8 );
    // сброс флага задержки
    self.aivar[AIV_WaitBeforeAttack] = 0;
    };
    // если дистанция атаки > 0
    if(self.aivar[AIV_MaxDistToWp] > 0)
    {
    // если расстояние между НПС и вайпоинтом НПС > дистанции атаки и расстояние между целью и вайпоинтом НПС > дистанции акаки
    if(Npc_GetDistToWP(self,self.wp) > self.aivar[AIV_MaxDistToWp]) && (Npc_GetDistToWP(other,self.wp) > self.aivar[AIV_MaxDistToWp])
    {
    // установить НПС тактику защитников крепостных стен
    self.fight_tactic = FAI_NAILED;
    }
    else // иначе (если НПС или цель близка к вайпоинту НПС)
    {
    // установить НПС родную тактику сражения
    self.fight_tactic = self.aivar[AIV_OriginalFightTactic];
    };
    };
    // если цель не бежит и не прыгает
    if((!C_BodyStateContains(other,BS_RUN)) && (!C_BodyStateContains(other,BS_JUMP)))
    {
    // сброс времени текущего состояния
    Npc_SetStateTime(self,0);
    };
    // если время в состоянии > 2 сек (от последнего сброса) и охрана не вызывалась
    if(Npc_GetStateTime(self) > 2) && (self.aivar[AIV_TAPOSITION] == 0)
    {
    // вызов охраны
    B_CallGuards();
    // установка следующей фазы вызова охраны
    self.aivar[AIV_TAPOSITION] = 1;
    };
    // если время в состоянии > 8 сек и охрана вызывалась
    if(Npc_GetStateTime(self) > 8 ) && (self.aivar[AIV_TAPOSITION] == 1)
    {
    // вызов охраны
    B_CallGuards();
    // установка следующей фазы вызова охраны (было 2 вызова)
    self.aivar[AIV_TAPOSITION] = 2;
    };
    // подготовка НПС боезапаса
    B_CreateAmmo(self);
    // выбор соответствующего цели оружия
    B_SelectWeapon(self,other);
    // если цель существует и не обездвижена
    if((Hlp_IsValidNpc(other)) && (C_NpcIsDown(other) == FALSE))
    {
    // если цель не в состоянии разговора
    if(other.aivar[AIV_INVINCIBLE] == FALSE)
    {
    // НПС атакует цель (Примечание: функция AI_Attack работает только когда очередь AI состояний НПС пуста)
    AI_Attack(self);
    }
    else
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    };
    // запись НПС id последней цели
    self.aivar[AIV_LASTTARGET] = Hlp_GetInstanceID(other);
    return LOOP_CONTINUE;
    }
    else // иначе (если цель отсутствует или обездвижена)
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    // если цель существует и цель ГГ и ГГ обездвижен
    if(Hlp_IsValidNpc(other)) && (Npc_IsPlayer(other)) && (C_NpcIsDown(other))
    {
    // замена временного отношения НПС к ГГ на постоянное
    Npc_SetTempAttitude(self,Npc_GetPermAttitude(self,hero));
    };
    // если причина атаки НПС не убийство цели
    if(self.aivar[AIV_ATTACKREASON] != AR_KILL)
    {
    // НПС разрешено воспринимать все объекты
    Npc_PerceiveAll(self);
    // НПС ищет новую цель other
    Npc_GetNextTarget(self);
    };
    // если цель существует и она не обездвижена
    if(Hlp_IsValidNpc(other)) && (!C_NpcIsDown(other))
    // и (расстояние от НПС до цели < дистанции восприятия или цель ГГ)
    && ((Npc_GetDistToNpc(self,other) < PERC_DIST_INTERMEDIAT) || (Npc_IsPlayer(other)))
    // и расстояние между НПС и целью по высоте < дистанции восприятия по высоте
    && (Npc_GetHeightToNpc(self,other) < PERC_DIST_HEIGHT)
    // и цель не в разговоре
    && (other.aivar[AIV_INVINCIBLE] == FALSE)
    // и цель ГГ не является переодетым бандитом и НПС бандит
    && (!(C_PlayerIsFakeBandit(self,other) && (self.guild == GIL_BDT)))
    {
    // если гильдии НПС и цели враждебны
    if(Wld_GetGuildAttitude(self.guild,other.guild) == ATT_HOSTILE)
    {
    // причина атаки - враждебная гильдия
    self.aivar[AIV_ATTACKREASON] = AR_GuildEnemy;
    // если цель ГГ
    if(Npc_IsPlayer(other))
    {
    // установить причину последнего нападения на ГГ
    self.aivar[AIV_LastPlayerAR] = AR_GuildEnemy;
    // параметр последнего сражения с ГГ - прервано
    self.aivar[AIV_LastFightAgainstPlayer] = FIGHT_CANCEL;
    // сброс комментария сражения
    self.aivar[AIV_LastFightComment] = FALSE;
    };
    }
    // иначе, если сам НПС является врагом цели
    else if(Npc_GetAttitude(self,other) == ATT_HOSTILE)
    {
    // причина атаки = причину последнего нападения на ГГ
    self.aivar[AIV_ATTACKREASON] = self.aivar[AIV_LastPlayerAR];
    };
    return LOOP_CONTINUE;
    }
    else
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    // если последнее сражение с ГГ прервано и последняя цель не ГГ
    if(self.aivar[AIV_LastFightAgainstPlayer] == FIGHT_CANCEL) && (self.aivar[AIV_LASTTARGET] != Hlp_GetInstanceID(hero))
    {
    // комментировать сражение не нужно
    self.aivar[AIV_LastFightComment] = TRUE;
    };
    return LOOP_END;
    };
    };
    };

    //Функция завершения состояния атаки
    func void ZS_Attack_End()
    {
    // установить other на последнюю цель
    other = Hlp_GetNpc(self.aivar[AIV_LASTTARGET]);
    // усли преследование было прекращено
    if(self.aivar[AIV_PursuitEnd] == TRUE)
    {
    // если цель существует и цель ГГ и НПС не друг цели
    if(Hlp_IsValidNpc(other)) && (Npc_IsPlayer(other)) && (self.npctype != NPCTYPE_FRIEND)
    {
    // установить временное отношение НПС к ГГ на враждебное
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    };
    // если НПС сражался на арене (состояние - в процессе сражения)
    if(self.aivar[AIV_ArenaFight] == AF_RUNNING)
    {
    // установить состояние после сражения
    self.aivar[AIV_ArenaFight] = AF_AFTER;
    };
    };
    // если преследования не было
    if(self.aivar[AIV_PursuitEnd] == FALSE)
    {
    // если уровень достигнутый ГГ в сражении > первоначального уровня
    if(B_GetCurrentAbsolutionLevel(self) > self.aivar[AIV_LastAbsolutionLevel])
    {
    // НПС говорит цели "Умный малый!" (SVM фраза)
    B_Say(self,other,"$WISEMOVE");
    }
    else
    {
    // обычная фраза завершения атаки
    B_Say_AttackEnd();
    };
    };
    // если цель убита ГГ и отношения гильдий НПС и ГГ не враждебные
    if(other.aivar[AIV_KilledByPlayer] == TRUE) && (Wld_GetGuildAttitude(self.guild,hero.guild) != ATT_HOSTILE)
    {
    // НПС становится другом ГГ
    B_SetAttitude(self,ATT_FRIENDLY);
    };
    // если цель находится без сознания и причиной атаки было убийство цели
    if(Npc_IsInState(other,ZS_UncoNPCious)) && (C_NpcHasAttackReasonToKill(self))
    {
    // НПС добивает цель
    B_FinishingMove(self,other);
    };
    // НПС прячет оружие
    AI_RemoveWeapon(self);
    // если цель обездвижена и НПС может обыскать цель и (цель не обыскивалась или должна быть обыскана)
    if(C_NpcIsDown(other)) && (C_WantToRansack(self)) && ((other.aivar[AIV_RANSACKED] == FALSE) || C_NpcRansacksAlways(self))
    // и расстояние между НПС и целью < дистанции восприятия
    && (Npc_GetDistToNpc(self,other) < PERC_DIST_INTERMEDIAT)
    {
    // установка флага, что цель обыскана
    other.aivar[AIV_RANSACKED] = TRUE;
    // цель человек
    if(other.guild < GIL_SEPERATOR_HUM)
    {
    // переход НПС в состояние грабежа цели
    AI_StartState(self,ZS_RansackBody,0,"");
    return;
    }
    else // (не человек)
    {
    // если НПС "Аллигатор Джек" и цель имеет "Сырое мясо"
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(AlligatorJack)) && (Npc_HasItems(other,ItFoMuttonRaw) > 0)
    {
    // Джек ест мясо
    AI_StartState(self,ZS_GetMeat,0,"");
    return;
    };
    };
    };
    // если жизнь НПС меньше половинной
    if(self.attribute[ATR_HITPOINTS] < (self.attribute[ATR_HITPOINTS_MAX]/2))
    {
    // НПС лечит себя
    AI_StartState(self,ZS_HealSelf,0,"");
    return;
    };
    };



    // *******************************************************
    // Состояние защиты своего помещения
    // *******************************************************
    // Здесь: self - НПС хозяин помещения, other - "незванный гость" (ГГ)
    // *******************************************************


    Открыть спойлер
    // Функция обработки восприятия разговора (вызывается когда ГГ обращается к НПС хозяину)
    func void B_ClearRoomTalk()
    {
    // если НПС хочет напасть на "гостя"
    if(C_WantToAttackRoomIntruder(self))
    {
    // НПС предупреждает "гостя" (SVM фраза "Пошел вон!")
    B_Say(self,other,"$GETOUTOFHERE");
    }
    else
    {
    // НПС спрашивает "гостя" (SVM фраза "Что ты тут ищешь!?")
    B_Say(self,other,"$WHYAREYOUINHERE");
    };
    };

    // Функция обработки восприятия выхода ГГ из помещения
    // Возвращает TRUE если ГГ покинул помещение, иначе - FALSE

    func int B_ExitIfRoomLeft()
    {
    var int portalguild;
    // получить номер гильдии, которой принадлежит помещение (-1 помещение никому не принадлежит)
    portalguild = Wld_GetPlayerPortalGuild();
    // если ГГ покинул помещение или помещение публичное
    if(!C_NpcIsBotheredByPlayerRoomGuild(self)) || (portalguild == GIL_PUBLIC)
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // НПС перестает смотреть на ГГ
    B_StopLookAt(self);
    // если НПС хочет напасть на "гостя"
    if(C_WantToAttackRoomIntruder(self))
    {
    // НПС говорит "гостю" (SVM фраза "Да, иди прочь!")
    B_Say(self,other,"$YESGOOUTOFHERE");
    }
    else
    {
    // НПС говорит "гостю" (SVM фраза "Умный малый!")
    B_Say(self,other,"$WISEMOVE");
    };
    // НПС продолжает выполнение распорядка дня
    AI_ContinueRoutine(self);
    return TRUE;
    };
    return FALSE;
    };

    // Инициализация состояния защиты помещения
    func void ZS_ClearRoom()
    {
    // установить минимальный набор восприятий НПС
    Perception_Set_Minimal();
    // заменить восприятие входа в помещение на восприятие выхода "гостя" из помещения
    Npc_PercEnable(self,PERC_ASSESSENTERROOM,B_ExitIfRoomLeft);
    // включить восприятие на перемещение МОВа
    Npc_PercEnable(self,PERC_MOVEMOB,B_MoveMob);
    // заменить восприятие разговора НПС
    Npc_PercEnable(self,PERC_ASSESSTALK,B_ClearRoomTalk);
    // НПС встает
    AI_StandUp(self);
    // НПС смотрит на "гостя"
    B_LookAtNpc(self,other);
    // НПС бежит к "гостю"
    AI_SetWalkmode(self,NPC_RUN);
    // если НПС находится вне помещения
    if(!Npc_IsInPlayersRoom(self))
    {
    // НПС бежит в точку, ближайшую к ГГ
    AI_GotoWP(self,Npc_GetNearestWP(other));
    };
    // установка признака входа в цикл
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };

    // Функция цикла защиты помещения
    func int ZS_ClearRoom_Loop()
    {
    // если осуществен первый вход в цикл
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS)
    {
    // НПС поворачивается к "гостю"
    B_TurnToNpc(self,other);
    // если НПС хочет напасть на "гостя"
    if(C_WantToAttackRoomIntruder(self))
    {
    // НПС выбирает соответствующее "гостю" оружие
    B_SelectWeapon(self,other);
    // НПС предупреждает "гостя" (SVM фраза "Пошел вон!")
    B_Say(self,other,"$GETOUTOFHERE");
    }
    else
    {
    // если НПС не является другом "гостя"
    if(Npc_GetAttitude(other,self) != ATT_FRIENDLY)
    {
    // НПС спрашивает "гостя" (SVM фраза "Что ты тут ищешь!?")
    B_Say(self,other,"$WHYAREYOUINHERE");
    };
    };
    // сброс времени нахождения НПС в этом состоянии
    Npc_SetStateTime(self, 0);
    // закрытие первого входа в цикл
    self.aivar[AIV_TAPOSITION] = ISINPOS;
    };
    // если ГГ покинул помещение
    if(B_ExitIfRoomLeft())
    {
    return LOOP_END;
    };
    // если НПС хочет напасть на "гостя"
    if(C_WantToAttackRoomIntruder(self))
    {
    // если с момента входа в помещение прошло > 5 сек
    if(Npc_GetStateTime(self) > 5)
    {
    // НПС атакует "гостя"
    B_Attack(self,other,AR_ClearRoom,0);
    return LOOP_END;
    };
    }
    else // НПС не хочет нападать (повторяется каждые две секунды)
    {
    // если с момента входа в помещение прошло >= 2 сек
    if(Npc_GetStateTime(self) >= 2)
    {
    // если НПС не видит "гостя" по прямой
    if(!Npc_CanSeeNpcFreeLOS(self,other))
    {
    // НПС бежит в точку, ближайшую к ГГ
    AI_GotoWP(self,Npc_GetNearestWP(other));
    // НПС поворачивается к "гостю"
    B_TurnToNpc(self,other);
    }
    // иначе, если НПС вообще не видит "гостя"
    else if(!Npc_CanSeeNpc(self,other))
    {
    // НПС поворачивается в направлении "гостя"
    B_TurnToNpc(self,other);
    };
    // сброс времени состояния
    Npc_SetStateTime(self,0);
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция выхода из состояния защиты помещения
    func void ZS_ClearRoom_End()
    {
    // НПС перестает смотреть на "гостя"
    B_StopLookAt (self);
    };



    // ****************************************************
    // Обработчик состояния когда НПС убегает от агрессора
    // ----------------------------------------------------
    // self - убегающий НПС, other - агрессор
    // ****************************************************


    Открыть спойлер
    // Функция инициализации состояния
    func void ZS_Flee()
    {
    // разрешить восприятие примененной магии
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // получить other - агрессор
    B_ValidateOther();
    // если загрузки игры не было
    if(self.aivar[AIV_LOADGAME] == FALSE)
    {
    // НПС кричит агрессору (SVM фраза "Я сматываюсь!")
    B_Say_Overlay(self,other,"$RUNAWAY");
    };
    // НПС прячет оружие
    AI_RemoveWeapon(self);
    // НПС переходит на бег
    AI_SetWalkmode(self,NPC_RUN);
    // проигрывается анимация убегающего человека
    Mdl_ApplyOverlayMds(self,"HUMANS_FLEE.MDS");
    };

    // Цикл состояния убегания
    func int ZS_Flee_Loop()
    {
    // получить для НПС цель (инициализировать other агрессором)
    Npc_GetTarget(self);
    // если расстояние между НПС и агрессором > дистанции преследования
    if(Npc_GetDistToNpc(self,other) > FIGHT_DIST_CANCEL)
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    return LOOP_END;
    };
    // если агрессор обездвижен (мертв, без сознания и т.д.)
    if(C_NpcIsDown(other))
    {
    // очистка очереди AI состояний НПС
    Npc_ClearAIQueue(self);
    return LOOP_END;
    };
    // НПС продолжает убегать
    AI_Flee(self);
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния убегания
    func void ZS_Flee_End()
    {
    // прекратить проигрывание анимации убегающего человека
    Mdl_RemoveOverlayMDS(self,"HUMANS_FLEE.MDS");
    // НПС останавливается
    AI_StandUp(self);
    // вызов функции завершения состояния лечения НПС
    AI_StartState(self,ZS_HealSelf,1,"");
    return;
    };



    // *********************************
    // Обработчик состояния лечения НПС
    // *********************************


    Открыть спойлер
    //