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

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

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

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

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

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

    Регистрация:
    24 мар 2006
    Сообщения:
    1.566
    Благодарности:
    628
    Баллы:
    290
    // **************************************************************
    // НПС slf называет НПС oth сумму денежного выражения goldAmount
    // **************************************************************


    Открыть спойлер
    func void B_Say_Gold(var c_npc slf,var c_npc oth,var int goldAmount)
    {
    if(goldAmount == 1000) { B_Say(slf,oth,"$GOLD_1000"); };
    if(goldAmount == 950) { B_Say(slf,oth,"$GOLD_950"); };
    if(goldAmount == 900) { B_Say(slf,oth,"$GOLD_900"); };
    if(goldAmount == 850) { B_Say(slf,oth,"$GOLD_850"); };
    if(goldAmount == 800) { B_Say(slf,oth,"$GOLD_800"); };
    if(goldAmount == 750) { B_Say(slf,oth,"$GOLD_750"); };
    if(goldAmount == 700) { B_Say(slf,oth,"$GOLD_700"); };
    if(goldAmount == 650) { B_Say(slf,oth,"$GOLD_650"); };
    if(goldAmount == 600) { B_Say(slf,oth,"$GOLD_600"); };
    if(goldAmount == 550) { B_Say(slf,oth,"$GOLD_550"); };
    if(goldAmount == 500) { B_Say(slf,oth,"$GOLD_500"); };
    if(goldAmount == 450) { B_Say(slf,oth,"$GOLD_450"); };
    if(goldAmount == 400) { B_Say(slf,oth,"$GOLD_400"); };
    if(goldAmount == 350) { B_Say(slf,oth,"$GOLD_350"); };
    if(goldAmount == 300) { B_Say(slf,oth,"$GOLD_300"); };
    if(goldAmount == 250) { B_Say(slf,oth,"$GOLD_250"); };
    if(goldAmount == 200) { B_Say(slf,oth,"$GOLD_200"); };
    if(goldAmount == 150) { B_Say(slf,oth,"$GOLD_150"); };
    if(goldAmount == 100) { B_Say(slf,oth,"$GOLD_100"); };
    if(goldAmount == 90) { B_Say(slf,oth,"$GOLD_90"); };
    if(goldAmount == 80) { B_Say(slf,oth,"$GOLD_80"); };
    if(goldAmount == 70) { B_Say(slf,oth,"$GOLD_70"); };
    if(goldAmount == 60) { B_Say(slf,oth,"$GOLD_60"); };
    if(goldAmount == 50) { B_Say(slf,oth,"$GOLD_50"); };
    if(goldAmount == 40) { B_Say(slf,oth,"$GOLD_40"); };
    if(goldAmount == 30) { B_Say(slf,oth,"$GOLD_30"); };
    if(goldAmount == 20) { B_Say(slf,oth,"$GOLD_20"); };
    if(goldAmount == 10) { B_Say(slf,oth,"$GOLD_10"); };
    };

    // *******************************
    // НПС slf преветствует НПС oth
    // *******************************


    Открыть спойлер
    func void B_Say_GuildGreetings(var c_npc slf,var c_npc oth)
    {
    // если милиция приветствует милицию или паладина
    if(slf.guild == GIL_MIL) && ((oth.guild == GIL_MIL) || (oth.guild == GIL_PAL))
    {
    // звучит SVM фраза "За короля!"
    B_Say_Overlay(slf,oth,"$MILGREETINGS");
    return;
    };
    // если паладин приветствует паладина или милицию или магов огня
    if(slf.guild == GIL_PAL) && ((oth.guild == GIL_PAL) || (oth.guild == GIL_MIL) || (oth.guild == GIL_KDF))
    {
    // звучит SVM фраза "За Инноса!"
    B_Say_Overlay (slf,oth,"$PALGREETINGS");
    return;
    };
    // если маг огня приветствует паладина или мага послушника или мага огня
    if(slf.guild == GIL_KDF) && ((oth.guild == GIL_PAL) || (oth.guild == GIL_NOV) || (oth.guild == GIL_KDF))
    {
    // звучит SVM фраза "За Инноса!"
    B_Say_Overlay (slf,oth,"$PALGREETINGS");
    return;
    };
    // если приветствующий Барток и он сообщал об одиноком орке перед Хоринисом
    if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(Bartok)) && (Bartok_OrkGesagt == TRUE)
    {
    // Барток говорит об одиноком орке перед Хоринисом
    B_Bartok_ShitAnOrc();
    return;
    };
    // если приветствующий Кок
    if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(Koch))
    {
    // Кок говорит о топоре
    B_Koch_Hackebeil();
    return;
    };
    var int zufall;
    zufall = Hlp_Random(100);
    // с вероятностью 0.1 и если идет дождь
    if((zufall <= 10) && Wld_IsRaining())
    {
    // звучит SVM фраза "Ну и скверная же погода!"
    B_Say_Overlay(slf,oth,"$WEATHER");
    return;

    };
    };

    // ************************************************
    // Мини реплики НПС
    // ************************************************


    Открыть спойлер
    func void B_Say_Smalltalk()
    {
    var int random;
    random = Hlp_Random (120);
    var int Choice;
    Choice = Hlp_Random(1);
    // с вероятностью 0.04
    if(random < 5)
    {
    // НПС произносит SVM фразу "... ты, правда, так думаешь..."
    B_Say(self,self,"$SMALLTALK01");
    }
    // с вероятностью 0.04
    else if(random < 10)
    {
    // НПС произносит SVM фразу "... все возможно..."
    B_Say(self,self,"$SMALLTALK02");
    }
    // с вероятностью 0.04
    else if(random < 15)
    {
    // НПС произносит SVM фразу "... он должен больше знать об этом..."
    B_Say(self,self,"$SMALLTALK03");
    }
    // с вероятностью 0.04
    else if(random < 20)
    {
    // НПС произносит SVM фразу "... как будто у меня и так мало проблем..."
    B_Say(self,self,"$SMALLTALK04");
    }
    // с вероятностью 0.04
    else if(random < 25)
    {
    // НПС произносит SVM фразу "... кто мог рассказать такое..."
    B_Say(self,self,"$SMALLTALK05");
    }
    // с вероятностью 0.04
    else if(random < 30)
    {
    // НПС произносит SVM фразу "... все же я еще очень зол..."
    B_Say(self,self,"$SMALLTALK06");
    }
    // с вероятностью 0.04
    else if(random < 35)
    {
    // НПС произносит SVM фразу "... кое-что болтают..."
    B_Say(self,self,"$SMALLTALK07");
    }
    // с вероятностью 0.04
    else if(random < 40)
    {
    // НПС произносит SVM фразу "... я бы не делал этого..."
    B_Say(self,self,"$SMALLTALK08");
    }
    // с вероятностью 0.04
    else if(random < 45)
    {
    // НПС произносит SVM фразу "... это всего лишь запах..."
    B_Say(self,self,"$SMALLTALK09");
    }
    // с вероятностью 0.04
    else if(random < 50)
    {
    // НПС произносит SVM фразу "... нужно узнать, что они там замышляют..."
    B_Say(self,self,"$SMALLTALK10");
    }
    // с вероятностью 0.04
    else if(random < 55)
    {
    // НПС произносит SVM фразу "... а я тебе что говорил..."
    B_Say(self,self,"$SMALLTALK11");
    }
    // с вероятностью 0.04
    else if(random < 60)
    {
    // НПС произносит SVM фразу "... меня никто не спрашивал..."
    B_Say(self,self,"$SMALLTALK12");
    }
    // с вероятностью 0.04
    else if(random < 65)
    {
    // НПС произносит SVM фразу "... бедный малый может и обидеть кого-нибудь..."
    B_Say(self,self,"$SMALLTALK13");
    }
    // с вероятностью 0.04
    else if(random < 70)
    {
    // НПС произносит SVM фразу "... ничего нового..."
    B_Say(self,self,"$SMALLTALK14");
    }
    // с вероятностью 0.04
    else if(random < 75)
    {
    // НПС произносит SVM фразу "... все ясно..."
    B_Say(self,self,"$SMALLTALK15");
    }
    // с вероятностью 0.04
    else if(random < 80)
    {
    // НПС произносит SVM фразу "... меня не нужно спрашивать..."
    B_Say(self,self,"$SMALLTALK16");
    }
    // с вероятностью 0.04
    else if(random < 85)
    {
    // НПС произносит SVM фразу "... так не может дальше продолжаться..."
    B_Say(self,self,"$SMALLTALK17");
    }
    // с вероятностью 0.04
    else if(random < 90)
    {
    // НПС произносит SVM фразу "... мое мнение ты уже знаешь..."
    B_Say(self,self,"$SMALLTALK18");
    }
    // с вероятностью 0.04
    else if(random < 95)
    {
    // НПС произносит SVM фразу "... я сказал то же самое..."
    B_Say(self,self,"$SMALLTALK19");
    }
    // с вероятностью 0.04
    else if(random < 100)
    {
    // НПС произносит SVM фразу "... вряд ли что-нибудь изменится из-за этого..."
    B_Say(self,self,"$SMALLTALK20");
    }
    // с вероятностью 0.04
    else if(random < 105)
    {
    // НПС произносит SVM фразу "... почему я узнаю об этом только сейчас..."
    B_Say(self,self,"$SMALLTALK21");
    }
    // с вероятностью 0.04
    else if(random < 110)
    {
    // если НПС маг послушник или паладин или маг огня
    if(Npc_GetTrueGuild(self) == GIL_NOV) || (Npc_GetTrueGuild(self) == GIL_PAL) || (Npc_GetTrueGuild(self) == GIL_KDF)
    {
    // с вероятностью 0.5
    if(Choice == 0)
    {
    // НПС произносит SVM фразу "... так написано в священных книгах..."
    B_Say(self,self,"$SMALLTALK28");
    }
    else
    {
    // НПС произносит SVM фразу "... давайте посмотрим, что из этого выйдет..."
    B_Say(self,self,"$SMALLTALK22");
    };
    }
    // если НПС бандит или наемник или охотник на драконов или пират
    else if(Npc_GetTrueGuild(self) == GIL_BDT) || (Npc_GetTrueGuild(self) == GIL_SLD) || (Npc_GetTrueGuild(self) == GIL_DJG)
    || (Npc_GetTrueGuild(self) == GIL_PIR)
    {
    // с вероятностью 0.5
    if(Choice == 0)
    {
    // НПС произносит SVM фразу "... он был пьянючий..."
    B_Say(self,self,"$SMALLTALK25");
    }
    else
    {
    // НПС произносит SVM фразу "... давайте посмотрим, что из этого выйдет..."
    B_Say(self,self,"$SMALLTALK22");
    };
    }
    else // остальные гильдии
    {
    // НПС произносит SVM фразу "... давайте посмотрим, что из этого выйдет..."
    B_Say(self,self,"$SMALLTALK22");
    };
    }
    // с вероятностью 0.04
    else if(random < 115)
    {
    // если НПС маг послушник или паладин или маг огня
    if(Npc_GetTrueGuild(self) == GIL_NOV) || (Npc_GetTrueGuild(self) == GIL_PAL) || (Npc_GetTrueGuild(self) == GIL_KDF)
    {
    // с вероятностью 0.5
    if(Choice == 0)
    {
    // НПС произносит SVM фразу "... я действую по приказу Инноса..."
    B_Say(self,self,"$SMALLTALK29");
    }
    else
    {
    // НПС произносит SVM фразу "... некоторые проблемы решаются сами собой..."
    B_Say(self,self,"$SMALLTALK23");
    };
    }
    // если НПС бандит или наемник или охотник на драконов или пират
    else if(Npc_GetTrueGuild(self) == GIL_BDT) || (Npc_GetTrueGuild(self) == GIL_SLD) || (Npc_GetTrueGuild(self) == GIL_DJG)
    || (Npc_GetTrueGuild(self) == GIL_PIR)
    {
    // с вероятностью 0.5
    if(Choice == 0)
    {
    // НПС произносит SVM фразу "... со мной бы этот номер не прошел..."
    B_Say(self,self,"$SMALLTALK26");
    }
    else
    {
    // НПС произносит SVM фразу "... некоторые проблемы решаются сами собой..."
    B_Say(self,self,"$SMALLTALK23");
    };
    }
    else // остальные гильдии
    {
    // НПС произносит SVM фразу "... некоторые проблемы решаются сами собой..."
    B_Say(self,self,"$SMALLTALK23");
    };
    }
    // с вероятностью 0.04
    else if(random <= 120)
    {
    // если НПС маг послушник или паладин или маг огня
    if(Npc_GetTrueGuild(self) == GIL_NOV) || (Npc_GetTrueGuild(self) == GIL_PAL) || (Npc_GetTrueGuild(self) == GIL_KDF)
    {
    // с вероятностью 0.5
    if(Choice == 0)
    {
    // НПС произносит SVM фразу "... никому не позволено нарушать указания богов..."
    B_Say(self,self,"$SMALLTALK30");
    }
    else
    {
    // НПС произносит SVM фразу "... я не могу больше это слушать..."
    B_Say(self,self,"$SMALLTALK24");
    };
    }
    // если НПС бандит или наемник или охотник на драконов или пират
    else if(Npc_GetTrueGuild(self) == GIL_BDT) || (Npc_GetTrueGuild(self) == GIL_SLD) || (Npc_GetTrueGuild(self) == GIL_DJG)
    || (Npc_GetTrueGuild (self) == GIL_PIR)
    {
    // с вероятностью 0.5
    if(Choice == 0)
    {
    // НПС произносит SVM фразу "... все убежали словно зайцы, я остался один..."
    B_Say(self,self,"$SMALLTALK27");
    }
    else
    {
    // НПС произносит SVM фразу "... я не могу больше это слушать..."
    B_Say(self,self,"$SMALLTALK24");
    };
    }
    else // остальные гильдии
    {
    // НПС произносит SVM фразу "... я не могу больше это слушать..."
    B_Say(self,self,"$SMALLTALK24");
    };
    };
    };

    // ****************************************************************
    // НПС slf произносит для НПС oth быструю SVM фразу text
    // ----------------------------------------------------------------
    // От B_Say() отличается только тем, что следующие AI команды будут
    // выполняться не ожидая окончания фразы
    // ****************************************************************


    Открыть спойлер
    func void B_Say_Overlay(var c_npc slf,var c_npc oth,var string text)
    {
    AI_OutputSVM_Overlay(slf,oth,text);
    };



    // *******************************************
    // Выбор НПС оружия соответствующего цели
    // *******************************************


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС агрессор
    // oth - НПС цель
    // ======================================


    Открыть спойлер
    func void B_SelectWeapon(var c_npc slf,var c_npc oth)
    {
    // если агрессор падает или плывет или ныряет
    if(C_BodyStateContains(slf,BS_FALL)) || (C_BodyStateContains(slf,BS_SWIM)) || (C_BodyStateContains(slf,BS_DIVE))
    {
    return;
    };
    // если агрессор выбрал для использования магию
    if(B_SelectSpell(slf,oth))
    {
    return;
    };
    // если агрессор находится в режиме сражения магией
    if(Npc_IsInFightMode(slf,FMODE_MAGIC))
    {
    // если агрессор находится в боевом режиме (Примечание: не мой взгляд этот блок лишний, была проверка, что НПС использует магию)
    if(!Npc_IsInFightMode(slf,FMODE_NONE))
    {
    // агрессор прячет оружие
    AI_RemoveWeapon(slf);
    };
    // подготовка оружия ближнего радиуса поражения к бою
    AI_ReadyMeleeWeapon (slf);
    return;
    };
    // если агрессор находится в режиме сражения оружием дальнего радиуса поражения
    if(Npc_IsInFightMode(slf,FMODE_FAR))
    {
    // если расстояние от агрессора до цели > дистанции, ближе которой НПС выбирает оружие ближнего радиуса поражения или агрессор не экипирован оружием ближнего радиуса поражения
    if(Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_RANGED_INNER) || (!Npc_HasEquippedMeleeWeapon(slf))
    {
    return;
    };
    };
    // если агрессор находится в режиме сражения оружием ближнего радиуса поражения
    if(Npc_IsInFightMode(slf,FMODE_MELEE))
    {
    // если расстояние от агрессора до цели > дистанции, дальше которой НПС выбирает оружие дальнего радиуса поражения или агрессор не экипирован оружием дальнего радиуса поражения
    if(Npc_GetDistToNpc(slf,oth) <= FIGHT_DIST_RANGED_OUTER) || (!Npc_HasEquippedRangedWeapon(slf))
    {
    return;
    };
    };
    // если агрессор экипирован оружием ближнего радиуса поражения и расстояние от агрессора до цели <= дистанции, дальше которой НПС выбирает оружие дальнего радиуса поражения
    if(Npc_HasEquippedMeleeWeapon(slf)) && (Npc_GetDistToNpc(slf,oth) <= FIGHT_DIST_RANGED_OUTER)
    {
    // если агрессор находится в боевом режиме
    if(!Npc_IsInFightMode(slf,FMODE_NONE))
    {
    // агрессор прячет оружие
    AI_RemoveWeapon(slf);
    };
    // подготовка оружия ближнего радиуса поражения к бою
    AI_ReadyMeleeWeapon (slf);
    return;
    };
    // если агрессор экипирован оружием дальнего радиуса поражения и расстояние от агрессора до цели > дистанции, ближе которой НПС выбирает оружие ближнего радиуса поражения и причина атаки агрессора - убийство жертвы
    if(Npc_HasEquippedRangedWeapon(oth) > FIGHT_DIST_RANGED_INNER) && (C_NpcHasAttackReasonToKill(slf))
    {
    // если агрессор находится в боевом режиме
    if(!Npc_IsInFightMode(slf,FMODE_NONE))
    {
    // агрессор прячет оружие
    AI_RemoveWeapon(slf);
    };
    // подготовка оружия дальнего радиуса поражения к бою
    AI_ReadyRangedWeapon(slf);
    return;
    };
    // если агрессор не в боевом режиме
    if(Npc_IsInFightMode(slf,FMODE_NONE))
    {
    // если агрессор экипирован оружием ближнего радиуса поражения
    if(Npc_HasEquippedMeleeWeapon(slf))
    {
    // подготовка оружия к бою
    AI_ReadyMeleeWeapon(slf);
    return;
    };
    // если агрессор экипирован оружием дальнего радиуса поражения
    if(Npc_HasEquippedRangedWeapon(slf))
    {
    // подготовка оружия к бою
    AI_ReadyRangedWeapon(slf);
    return;
    };
    // подготовка к бою кулаками
    AI_ReadyMeleeWeapon(slf);
    return;
    };
    return;
    };





    // *********************************
    // Устанавливает отношение НПС к ГГ
    // *********************************


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС
    // att - отношение
    // ======================================


    Открыть спойлер
    func void B_SetAttitude(var c_npc slf,var int att)
    {
    // установить временное отношение НПС к ГГ
    Npc_SetAttitude(slf,att);
    // установить постояное отношение НПС к ГГ
    Npc_SetTempAttitude(slf,att);
    };





    // ********************************************
    // Инициализация переменной other для НПС self
    // ********************************************


    Открыть спойлер
    func void B_ValidateOther()
    {
    // если other отсутсвует (загрузка игры)
    if(!Hlp_IsValidNpc(other))
    {
    // other = последней цели НПС
    other = Hlp_GetNpc(self.aivar[AIV_LASTTARGET]);
    // для НПС установить цель other
    Npc_SetTarget(self,other);
    // установить флаг загрузки игры
    self.aivar[AIV_LOADGAME] = TRUE;
    }
    else // иначе (other существует)
    {
    // повторно инициализировать other целью
    Npc_GetTarget(self);
    // сохранить последнюю цель
    self.aivar[AIV_LASTTARGET] = Hlp_GetInstanceID(other);
    // сброс флага загрузки игры
    self.aivar[AIV_LOADGAME] = FALSE;
    };
    };




    Добавление от 26 марта 2005, 09:56
    Криминал ГГ

    // *******************************
    // Запоминание новостей
    // *******************************


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС, запоминающий новость
    // taeter - НПС преступник
    // crime - криминальная новость
    // ======================================


    Открыть спойлер
    func void B_MemorizePlayerCrime(var c_npc slf,var c_npc taeter,var int crime)
    {
    // если преступник не ГГ
    if(!Npc_IsPlayer(taeter))
    {
    return;
    };
    // если НПС черный маг
    if(slf.guild == GIL_DMT)
    {
    return;
    };
    // если новость более значима чем предыдущие новости
    if(crime > B_GetPlayerCrime(slf))
    {
    // удалить предыдущую новость
    B_DeletePetzCrime(slf);
    // добавить новость
    B_AddPetzCrime(slf,crime);
    };
    // если новость одного порядка с предыдущей новостью (Примечание: можно оставить ==, > было ранее)
    if(crime >= B_GetPlayerCrime(slf))
    {
    // НПС запоминает новость
    slf.aivar[AIV_NpcSawPlayerCommit] = crime;
    // НПС запоминает день преступления
    slf.aivar[AIV_NpcSawPlayerCommitDay] = Wld_GetDay();
    // НПС запоминает уровень криминала ГГ
    slf.aivar[AIV_CrimeAbsolutionLevel] = B_GetCurrentAbsolutionLevel(slf);
    };
    };





    // ************************************************************
    // Получить последнюю новость, запомненную НПС о криминале ГГ
    // ************************************************************


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС имеющий новость
    // --------------------------------------
    // Возвращаемое значение: последняя запомненная новость
    // ======================================


    Открыть спойлер
    func int B_GetPlayerCrime(var c_npc slf)
    {
    // если уровень криминала ГГ меньше воровства
    if(slf.aivar[AIV_NpcSawPlayerCommit] <= CRIME_ATTACK)
    {
    // если с момента запоминания новости прошло более двух дней
    if(slf.aivar[AIV_NpcSawPlayerCommitDay] < (Wld_GetDay()-2))
    {
    // криминала не было
    return CRIME_NONE;
    };
    };
    // если уровень криминала, запомненный НПС, < уровня криминала ГГ по локациям
    if(slf.aivar[AIV_CrimeAbsolutionLevel] < B_GetCurrentAbsolutionLevel(slf))
    {
    // криминала не было
    return CRIME_NONE;
    };
    // последний запомненный криминал
    return slf.aivar[AIV_NpcSawPlayerCommit];
    };





    // **************************************************
    // Добавить новость для соответствующей локации
    // **************************************************


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС свидетель, проживающий в локации
    // crime - криминальная новость
    // ======================================


    Открыть спойлер
    func void B_AddPetzCrime(var c_npc slf,var int crime)
    {
    // если НПС из Миненталя
    if(C_NpcBelongsToOldCamp(slf))
    {
    // если убийство
    if(crime == CRIME_MURDER)
    {
    // увеличить счетчик убийств
    PETZCOUNTER_OldCamp_Murder = PETZCOUNTER_OldCamp_Murder + 1;
    };
    // если воровство
    if(crime == CRIME_THEFT)
    {
    // увеличить счетчик воровства
    PETZCOUNTER_OldCamp_Theft = PETZCOUNTER_OldCamp_Theft + 1;
    };
    // если нападение
    if(crime == CRIME_ATTACK)
    {
    // увеличить счетчик нападений
    PETZCOUNTER_OldCamp_Attack = PETZCOUNTER_OldCamp_Attack + 1;
    };
    // если убийство овец
    if(crime == CRIME_SHEEPKILLER)
    {
    // увеличить счетчик убитых овец
    PETZCOUNTER_OldCamp_Sheepkiller = PETZCOUNTER_OldCamp_Sheepkiller + 1;
    };
    };
    // если НПС из Хориниса
    if(C_NpcBelongsToCity(slf))
    {
    if(crime == CRIME_MURDER)
    {
    PETZCOUNTER_City_Murder = PETZCOUNTER_City_Murder + 1;
    };
    if(crime == CRIME_THEFT)
    {
    PETZCOUNTER_City_Theft = PETZCOUNTER_City_Theft + 1;
    };
    if(crime == CRIME_ATTACK)
    {
    PETZCOUNTER_City_Attack = PETZCOUNTER_City_Attack + 1;
    };
    if(crime == CRIME_SHEEPKILLER)
    {
    PETZCOUNTER_City_Sheepkiller = PETZCOUNTER_City_Sheepkiller + 1;
    };
    };
    // если НПС из Монастыря
    if(C_NpcBelongsToMonastery(slf))
    {
    if(crime == CRIME_MURDER)
    {
    PETZCOUNTER_Monastery_Murder = PETZCOUNTER_Monastery_Murder + 1;
    };
    if(crime == CRIME_THEFT)
    {
    PETZCOUNTER_Monastery_Theft = PETZCOUNTER_Monastery_Theft + 1;
    };
    if(crime == CRIME_ATTACK)
    {
    PETZCOUNTER_Monastery_Attack = PETZCOUNTER_Monastery_Attack + 1;
    };
    if(crime == CRIME_SHEEPKILLER)
    {
    PETZCOUNTER_Monastery_Sheepkiller = PETZCOUNTER_Monastery_Sheepkiller + 1;
    };
    };
    // если НПС с Фермы наемников
    if(C_NpcBelongsToFarm(slf))
    {
    if(crime == CRIME_MURDER)
    {
    PETZCOUNTER_Farm_Murder = PETZCOUNTER_Farm_Murder + 1;
    };
    if(crime == CRIME_THEFT)
    {
    PETZCOUNTER_Farm_Theft = PETZCOUNTER_Farm_Theft + 1;
    };
    if(crime == CRIME_ATTACK)
    {
    PETZCOUNTER_Farm_Attack = PETZCOUNTER_Farm_Attack + 1;
    };
    if(crime == CRIME_SHEEPKILLER)
    {
    PETZCOUNTER_Farm_Sheepkiller = PETZCOUNTER_Farm_Sheepkiller + 1;
    };
    };
    // если НПС из Лагеря бандитов
    if(C_NpcBelongsToBL(slf))
    {
    if(crime == CRIME_MURDER)
    {
    PETZCOUNTER_BL_Murder = PETZCOUNTER_BL_Murder + 1;
    };
    if(crime == CRIME_THEFT)
    {
    PETZCOUNTER_BL_Theft = PETZCOUNTER_BL_Theft + 1;
    };
    if(crime == CRIME_ATTACK)
    {
    PETZCOUNTER_BL_Attack = PETZCOUNTER_BL_Attack + 1;
    };
    };
    };





    // *************************************************************
    // Удалить новость для соответствующей локации
    // *************************************************************


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС свидетель, проживающий в локации
    // ======================================


    Открыть спойлер
    func void B_DeletePetzCrime(var c_npc slf)
    {
    // если НПС из Миненталя
    if(C_NpcBelongsToOldCamp(slf))
    {
    // если последняя запомненная новость - убийство
    if(B_GetPlayerCrime(slf) == CRIME_MURDER)
    {
    // уменьшить счетчик убийств
    PETZCOUNTER_OldCamp_Murder = PETZCOUNTER_OldCamp_Murder - 1;
    };
    // если последняя запомненная новость - воровство
    if(B_GetPlayerCrime(slf) == CRIME_THEFT)
    {
    // уменьшить счетчик воровства
    PETZCOUNTER_OldCamp_Theft = PETZCOUNTER_OldCamp_Theft - 1;
    };
    // если последняя запомненная новость - нападение
    if(B_GetPlayerCrime(slf) == CRIME_ATTACK)
    {
    // уменьшить счетчик нападений
    PETZCOUNTER_OldCamp_Attack = PETZCOUNTER_OldCamp_Attack - 1;
    };
    // если последняя запомненная новость - убийство овец
    if(B_GetPlayerCrime(slf) == CRIME_SHEEPKILLER)
    {
    // уменьшить счетчик убитых овец
    PETZCOUNTER_OldCamp_Sheepkiller = PETZCOUNTER_OldCamp_Sheepkiller - 1;
    };
    };
    // если НПС из Хориниса
    if(C_NpcBelongsToCity(slf))
    {
    if(B_GetPlayerCrime(slf) == CRIME_MURDER)
    {
    PETZCOUNTER_City_Murder = PETZCOUNTER_City_Murder - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_THEFT)
    {
    PETZCOUNTER_City_Theft = PETZCOUNTER_City_Theft - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_ATTACK)
    {
    PETZCOUNTER_City_Attack = PETZCOUNTER_City_Attack - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_SHEEPKILLER)
    {
    PETZCOUNTER_City_Sheepkiller = PETZCOUNTER_City_Sheepkiller - 1;
    };
    };
    // если НПС из Монастыря
    if(C_NpcBelongsToMonastery(slf))
    {
    if(B_GetPlayerCrime(slf) == CRIME_MURDER)
    {
    PETZCOUNTER_Monastery_Murder = PETZCOUNTER_Monastery_Murder - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_THEFT)
    {
    PETZCOUNTER_Monastery_Theft = PETZCOUNTER_Monastery_Theft - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_ATTACK)
    {
    PETZCOUNTER_Monastery_Attack = PETZCOUNTER_Monastery_Attack - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_SHEEPKILLER)
    {
    PETZCOUNTER_Monastery_Sheepkiller = PETZCOUNTER_Monastery_Sheepkiller - 1;
    };
    };
    // если НПС с Фермы наемников
    if(C_NpcBelongsToFarm(slf))
    {
    if(B_GetPlayerCrime(slf) == CRIME_MURDER)
    {
    PETZCOUNTER_Farm_Murder = PETZCOUNTER_Farm_Murder - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_THEFT)
    {
    PETZCOUNTER_Farm_Theft = PETZCOUNTER_Farm_Theft - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_ATTACK)
    {
    PETZCOUNTER_Farm_Attack = PETZCOUNTER_Farm_Attack - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_SHEEPKILLER)
    {
    PETZCOUNTER_Farm_Sheepkiller = PETZCOUNTER_Farm_Sheepkiller - 1;
    };
    };
    // если НПС из Лагеря бандитов
    if(C_NpcBelongsToBL(slf))
    {
    if(B_GetPlayerCrime(slf) == CRIME_MURDER)
    {
    PETZCOUNTER_BL_Murder = PETZCOUNTER_BL_Murder - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_THEFT)
    {
    PETZCOUNTER_BL_Theft = PETZCOUNTER_BL_Theft - 1;
    };
    if(B_GetPlayerCrime(slf) == CRIME_ATTACK)
    {
    PETZCOUNTER_BL_Attack = PETZCOUNTER_BL_Attack - 1;
    };
    };
    };



    // *************************************************
    // Подсчет абсолютного уровня криминала по локациям
    // *************************************************


    Открыть спойлер
    func void B_GrantAbsolution(var int location)
    {
    // если Миненталь или все локации
    if(location == LOC_OLDCAMP) || (location == LOC_ALL)
    {
    // абсолютный уровень по локации++
    ABSOLUTIONLEVEL_OldCamp = ABSOLUTIONLEVEL_OldCamp + 1;
    // сброс счетчиков криминала по локации
    PETZCOUNTER_OldCamp_Murder = 0;
    PETZCOUNTER_OldCamp_Theft = 0;
    PETZCOUNTER_OldCamp_Attack = 0;
    PETZCOUNTER_OldCamp_Sheepkiller = 0;
    };
    // если Хоринис или все локации
    if(location == LOC_CITY) || (location == LOC_ALL)
    {
    ABSOLUTIONLEVEL_City = ABSOLUTIONLEVEL_City + 1;
    PETZCOUNTER_City_Murder = 0;
    PETZCOUNTER_City_Theft = 0;
    PETZCOUNTER_City_Attack = 0;
    PETZCOUNTER_City_Sheepkiller = 0;
    };
    // если Монастырь или все локации
    if(location == LOC_MONASTERY) || (location == LOC_ALL)
    {
    ABSOLUTIONLEVEL_Monastery = ABSOLUTIONLEVEL_Monastery + 1;
    PETZCOUNTER_Monastery_Murder = 0;
    PETZCOUNTER_Monastery_Theft = 0;
    PETZCOUNTER_Monastery_Attack = 0;
    PETZCOUNTER_Monastery_Sheepkiller = 0;
    };
    // если Ферма наемников или все локации
    if(location == LOC_FARM) || (location == LOC_ALL)
    {
    ABSOLUTIONLEVEL_Farm = ABSOLUTIONLEVEL_Farm + 1;
    PETZCOUNTER_Farm_Murder = 0;
    PETZCOUNTER_Farm_Theft = 0;
    PETZCOUNTER_Farm_Attack = 0;
    PETZCOUNTER_Farm_Sheepkiller = 0;
    };
    // если Лагерь бандитов
    if(location == LOC_BL)
    {
    ABSOLUTIONLEVEL_BL = ABSOLUTIONLEVEL_BL + 1;
    PETZCOUNTER_BL_Murder = 0;
    PETZCOUNTER_BL_Theft = 0;
    PETZCOUNTER_BL_Attack = 0;
    };
    };





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


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС, проживающий в локации
    // --------------------------------------
    // Возвращаемое значение - абсолютный уровень криминала
    // ======================================


    Открыть спойлер
    func int B_GetCurrentAbsolutionLevel(var c_npc slf)
    {
    // если НПС из Миненталя
    if(C_NpcBelongsToOldCamp(slf))
    {
    return ABSOLUTIONLEVEL_OldCamp;
    };
    // если НПС из Хориниса
    if(C_NpcBelongsToCity(slf))
    {
    return ABSOLUTIONLEVEL_City;
    };
    // если НПС из Монастыря
    if(C_NpcBelongsToMonastery(slf))
    {
    return ABSOLUTIONLEVEL_Monastery;
    };
    // если НПС с Фермы наемников
    if(C_NpcBelongsToFarm(slf))
    {
    return ABSOLUTIONLEVEL_Farm;
    };
    // если НПС из Лагеря бандитов
    if(C_NpcBelongsToBL(slf))
    {
    return ABSOLUTIONLEVEL_BL;
    };
    return 0;
    };





    // *************************************************
    // Получить суммарный уровень криминала по локациям
    // *************************************************


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС, проживающий в локации
    // --------------------------------------
    // Возвращаемое значение - суммарный уровень криминала ГГ для локации
    // ======================================


    Открыть спойлер
    func int B_GetTotalPetzCounter(var c_npc slf)
    {
    // если НПС из Миненталя
    if (C_NpcBelongsToOldCamp(slf))
    {
    // суммарный уровень криминала для локации
    return (PETZCOUNTER_OldCamp_Murder + PETZCOUNTER_OldCamp_Theft + PETZCOUNTER_OldCamp_Attack + PETZCOUNTER_OldCamp_Sheepkiller);
    };
    // если НПС из Хориниса
    if (C_NpcBelongsToCity(slf))
    {
    return (PETZCOUNTER_City_Murder + PETZCOUNTER_City_Theft + PETZCOUNTER_City_Attack + PETZCOUNTER_City_Sheepkiller);
    };
    // если НПС из Монастыря
    if (C_NpcBelongsToMonastery(slf))
    {
    return (PETZCOUNTER_Monastery_Murder + PETZCOUNTER_Monastery_Theft + PETZCOUNTER_Monastery_Attack + PETZCOUNTER_Monastery_Sheepkiller);
    };
    // если НПС с Фермы наемников
    if (C_NpcBelongsToFarm(slf))
    {
    return (PETZCOUNTER_Farm_Murder + PETZCOUNTER_Farm_Theft + PETZCOUNTER_Farm_Attack + PETZCOUNTER_Farm_Sheepkiller);
    };
    // если НПС из Лагеря бандитов
    if (C_NpcBelongsToBL(slf))
    {
    return (PETZCOUNTER_BL_Murder + PETZCOUNTER_BL_Theft + PETZCOUNTER_BL_Attack);
    };
    return 0;
    };





    // *********************************************************
    // Получить криминал ГГ по локациям и в порядке приоритетов
    // *********************************************************


    // ======================================
    // Аргументы:
    // --------------------------------------
    // slf - НПС, проживающий в локации
    // --------------------------------------
    // Возвращаемое значение - приоритетный криминал для локации
    // ======================================


    Открыть спойлер
    func int B_GetGreatestPetzCrime(var c_npc slf)
    {
    // если НПС из Миненталя
    if(C_NpcBelongsToOldCamp(slf))
    {
    // если счетчик убийств > 0
    if(PETZCOUNTER_OldCamp_Murder > 0)
    {
    // криминал - убийство
    return CRIME_MURDER;
    };
    // если счетчик воровства > 0
    if(PETZCOUNTER_OldCamp_Theft > 0)
    {
    // криминал - воровство
    return CRIME_THEFT;
    };
    // если счетчик нападений > 0
    if(PETZCOUNTER_OldCamp_Attack > 0)
    {
    // криминал - нападение
    return CRIME_ATTACK;
    };
    // если счетчик убийств овец > 0
    if(PETZCOUNTER_OldCamp_Sheepkiller > 0)
    {
    // криминал - убийство овец
    return CRIME_SHEEPKILLER;
    };
    };
    // если НПС из Хориниса
    if(C_NpcBelongsToCity(slf))
    {
    if(PETZCOUNTER_City_Murder > 0)
    {
    return CRIME_MURDER;
    };
    if(PETZCOUNTER_City_Theft > 0)
    {
    return CRIME_THEFT;
    };
    if(PETZCOUNTER_City_Attack > 0)
    {
    return CRIME_ATTACK;
    };
    if(PETZCOUNTER_City_Sheepkiller > 0)
    {
    return CRIME_SHEEPKILLER;
    };
    };
    // если НПС из Монастыря
    if(C_NpcBelongsToMonastery(slf))
    {
    if(PETZCOUNTER_Monastery_Murder > 0)
    {
    return CRIME_MURDER;
    };
    if(PETZCOUNTER_Monastery_Theft > 0)
    {
    return CRIME_THEFT;
    };
    if(PETZCOUNTER_Monastery_Attack > 0)
    {
    return CRIME_ATTACK;
    };
    if(PETZCOUNTER_Monastery_Sheepkiller > 0)
    {
    return CRIME_SHEEPKILLER;
    };
    };
    // если НПС с Фермы наемников
    if(C_NpcBelongsToFarm(slf))
    {
    if(PETZCOUNTER_Farm_Murder > 0)
    {
    return CRIME_MURDER;
    };
    if(PETZCOUNTER_Farm_Theft > 0)
    {
    return CRIME_THEFT;
    };
    if(PETZCOUNTER_Farm_Attack > 0)
    {
    return CRIME_ATTACK;
    };
    if(PETZCOUNTER_Farm_Sheepkiller > 0)
    {
    return CRIME_SHEEPKILLER;
    };
    };
    // если НПС из Лагеря бандитов
    if(C_NpcBelongsToBL(slf))
    {
    if(PETZCOUNTER_BL_Murder > 0)
    {
    return CRIME_MURDER;
    };
    if(PETZCOUNTER_BL_Theft > 0)
    {
    return CRIME_THEFT;
    };
    if(PETZCOUNTER_BL_Attack > 0)
    {
    return CRIME_ATTACK;
    };
    };
    return CRIME_NONE;
    };
     
    Ur-tRall и Валера сказали Спасибо
  2. MEG@VOLT

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

    Регистрация:
    24 мар 2006
    Сообщения:
    1.566
    Благодарности:
    628
    Баллы:
    290
    13. Вспомогательные С_ функции для людей (compare функции).

    Все С_ функции расположены в директории ..\AI\Human\С_Human\
    Следующие два файла можно удалить по причине их бесполезности: C_BanditAttackBandit.d и C_BanditHelpsStoryBandit.d
    // ********************************************************************
    // Проверка состояния тела НПС
    // --------------------------------------------------------------------
    // Примечание автора: Никогда не используйте встроенную функцию Npc_GetBodyState
    // напрямую, т.к. сравнение всегда будет ложно, если установлены дополнительные
    // флаги состояния тела. Все запросы на состояние тела выполняйте только
    // через эту функцию.
    // ********************************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС, состояние тела которого проверяется
    // bodystate - проверяемое состояние тела
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - состояние тела НПС совпадает с проверяемым, FALSE - не совпадает
    // ====================================================================


    Открыть спойлер
    func int C_BodyStateContains(var c_npc slf,var int bodystate)
    {
    // Примечание автора: Руки прочь от этой формулы!!! Я знаю точно что я делаю! (Мое примечание: с точки зрения логического анализа формула неправильна).
    // если фактическое состояние тела НПС без учета допфлагов равно запрошенному состоянию без учета допфлагов
    if((Npc_GetBodyState(slf)&(BS_MAX|BS_FLAG_INTERRUPTABLE|BS_FLAG_FREEHANDS)) == (bodystate&(BS_MAX|BS_FLAG_INTERRUPTABLE|BS_FLAG_FREEHANDS)))
    {
    return TRUE;
    };
    return FALSE;
    };





    // ********************************************************************************
    // Убивается ли НПС по окончании жизни или переводится в бессознательное состояние
    // ********************************************************************************


    // ====================================================================
    // self - проверяемый НПС
    // other - преступник, убивающий НПС
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - НПС не убивается преступником, FALSE - убивается.
    // ====================================================================


    Открыть спойлер
    func int C_DropUnconscious()
    {
    // если преступник монстр или Черный маг (Ищущий) или бандит или преступнику разрешено убить НПС
    if(other.guild > GIL_SEPERATOR_HUM) || (other.guild == GIL_DMT) || (other.guild == GIL_BDT) || (other.aivar[AIV_DropDeadAndKill] == TRUE)
    {
    // НПС будет убит
    return FALSE;
    };
    // если НПС человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // если НПС не Черный маг и не бандит и его не разрешено убивать преступнику
    if(self.guild != GIL_DMT) && (self.guild != GIL_BDT) && (self.aivar[AIV_DropDeadAndKill] == FALSE)
    {
    // НПС будет безсознания
    return TRUE;
    };
    };
    // НПС будет убит
    return FALSE;
    };





    // *****************************************************************
    // Может ли быть взят предмет, принадлежащий одному НПС, другим НПС
    // *****************************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС, которому может принадлежать предмет
    // oth - НПС берущий предмет (ГГ)
    // itm - предмет
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - предмет взять нельзя, FALSE - взять можно.
    // ====================================================================


    Открыть спойлер
    func int C_IsTakenItemMyPossession(var c_npc slf,var c_npc oth,var c_item itm)
    {
    var int portalguild;
    // получить номер гильдии, которой принадлежит помещение (-1 помещение никому не принадлежит)
    portalguild = Wld_GetPlayerPortalGuild();
    // Моё примечание: предыдущие две строки лишние и могут быть удалены.
    // если предмет принадлежит НПС владельцу
    if(Npc_OwnedByNpc(itm,slf))
    {
    // если предмет Святой молот
    if(Hlp_IsItem(itm,Holy_Hammer_MIS))
    {
    // Святой молот взят
    Hammer_Taken = TRUE;
    };
    // брать нельзя
    return TRUE;
    };
    // если предмет выброшен (просто валяется)
    if((itm.flags & ITEM_DROPPED) == ITEM_DROPPED)
    {
    // брать можно
    return FALSE;
    };
    // если ГГ находится в помещении, принадлежащем НПС или помещение публично
    // Моё примечание: правильнее вместо self написать slf, а то в некоторых случаях может быть ошибка.
    if(C_NpcIsBotheredByPlayerRoomGuild(self)) || (Wld_GetPlayerPortalGuild() == GIL_PUBLIC)
    {
    // брать нельзя
    return TRUE;
    };
    // если отношения между гильдиями НПС и гильдией, владеющей предметом, дружественные
    if(Wld_GetGuildAttitude(slf.guild,itm.ownerguild) == ATT_FRIENDLY)
    {
    // брать нельзя
    return TRUE;
    };
    // брать можно
    return FALSE;
    };





    // ****************************************************************
    // Можно ли импользовать MOB, принадлежащий одному НПС, другим НПС
    // ****************************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС, которому может принадлежать MOB
    // oth - НПС использующий MOB (ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - MOB использовать нельзя, FALSE - можно.
    // ====================================================================


    Открыть спойлер
    func int C_IsUsedMobMyPossession(var c_npc slf,var c_npc oth)
    {
    // Моё примечание: правильнее вместо self и other внутри функции написать slf и oth, а то в некоторых случаях может быть ошибка.
    // если MOB, используемый ГГ, принадлежит НПС
    if(Npc_IsDetectedMobOwnedByNpc(other,self))
    {
    // нельзя
    return TRUE;
    };
    // если ГГ находится в помещении, принадлежащем НПС или помещение публично
    if(C_NpcIsBotheredByPlayerRoomGuild(self)) || (Wld_GetPlayerPortalGuild() == GIL_PUBLIC)
    {
    // нельзя
    return TRUE;
    };
    // можно
    return FALSE;
    };



    // ********************************************************************
    // Функции проверяющие принадлежность НПС к определенной локации
    // ********************************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - принадлежит, FALSE - нет.
    // ====================================================================


    // Проверка принадлежности к Миненталю
    // --------------------------------------------------------------------

    Открыть спойлер
    func int C_NpcBelongsToOldCamp(var c_npc slf)
    {
    // если НПС значим или из окружающего народа в Минентале
    if(slf.npctype == NPCTYPE_OCMAIN) || (slf.npctype == NPCTYPE_OCAMBIENT)
    {
    // если НПС Горожанин или Милиционер или Паладин
    if(slf.guild == GIL_VLK) || (slf.guild == GIL_MIL) || (slf.guild == GIL_PAL)
    {
    return TRUE;
    };
    };
    return FALSE;
    };


    // Проверка принадлежности к Хоринису
    // --------------------------------------------------------------------

    Открыть спойлер
    func int C_NpcBelongsToCity(var c_npc slf)
    {
    // если НПС не из Миненталя
    if(!C_NpcBelongsToOldCamp(slf))
    {
    // если НПС Горожанин или Милиционер или Паладин
    if(slf.guild == GIL_VLK) || (slf.guild == GIL_MIL) || (slf.guild == GIL_PAL)
    {
    return TRUE;
    };
    };
    return FALSE;
    };


    // Проверка принадлежности к Монастырю
    // ---------------------------------------------------------------------

    Открыть спойлер
    func int C_NpcBelongsToMonastery(var c_npc slf)
    {
    // если НПС Маг огня или Маг послушник
    if(slf.guild == GIL_KDF) || (slf.guild == GIL_NOV)
    {
    return TRUE;
    };
    return FALSE;
    };


    // Проверка принадлежности к Ферме наемников
    // ---------------------------------------------------------------------

    Открыть спойлер
    func int C_NpcBelongsToFarm(var c_npc slf)
    {
    // если НПС Крестьянин или Наемник
    if(slf.guild == GIL_BAU) || (slf.guild == GIL_SLD)
    {
    return TRUE;
    };
    return FALSE;
    };


    // Проверка принадлежности к Лагерю бандитов
    // ---------------------------------------------------------------------

    Открыть спойлер
    func int C_NpcBelongsToBL(var c_npc slf)
    {
    // если НПС из окружающего народа в Лагере или Долине бандитов
    if(slf.npctype == NPCTYPE_BL_AMBIENT) || (slf.npctype == NPCTYPE_BL_MAIN)
    {
    return TRUE;
    };
    return FALSE;
    };





    // ******************************************
    // Имеет ли НПС новости об окружающей жизни
    // ******************************************


    // ==========================================
    // Аргументы:
    // ------------------------------------------
    // slf - проверяемый НПС
    // ------------------------------------------
    // Возвращаемое значение:
    // TRUE - новости есть, FALSE - нет.
    // ==========================================


    Открыть спойлер
    func int C_NpcHasAmbientNews(var c_npc slf)
    {
    // если НПС не знает никаких новостей
    if(slf.aivar[AIV_NewsOverride] == TRUE)
    {
    return FALSE;
    };
    // если ГГ не имеет криминала
    if(B_GetPlayerCrime(slf) == CRIME_NONE)
    {
    return FALSE;
    };
    // новости есть (по умолчанию)
    return TRUE;
    };





    // *****************************************
    // Является ли причиной атаки убийство цели
    // *****************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС агрессор
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - причина атаки - убийство, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_NpcHasAttackReasonToKill(var c_npc slf)
    {
    // если
    if (slf.aivar[AIV_ATTACKREASON] == AR_KILL) // ГГ убил НПС
    || (slf.aivar[AIV_ATTACKREASON] == AR_GuildEnemy) // или НПС является врагом гильдии
    || (slf.aivar[AIV_ATTACKREASON] == AR_HumanMurderedHuman) // или Человек убил человека
    || (slf.aivar[AIV_ATTACKREASON] == AR_GuardStopsIntruder) // или Охрана ворот атакует незваного гостя
    || (slf.aivar[AIV_ATTACKREASON] == AR_GuardCalledToKill) // или Вызвана охрана по факту убийства
    {
    return TRUE;
    };
    return FALSE;
    };





    // ************************************
    // Находится ли ГГ в частном помещении
    // ************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС, которому может принадлежать помещение
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - ГГ в частном помещении, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_NpcIsBotheredByPlayerRoomGuild(var c_npc slf)
    {
    var int portalguild;
    // получить номер гильдии, которой принадлежит помещение (-1 помещение никому не принадлежит)
    portalguild = Wld_GetPlayerPortalGuild();
    // если помещение принадлежит гильдии и (НПС из этой гильдии или гильдия НПС и гильдия, владеющая помещением, дружественны)
    if(portalguild > GIL_NONE) && ((slf.guild == portalguild) || (Wld_GetGuildAttitude(slf.guild,portalguild) == ATT_FRIENDLY))
    {
    return TRUE;
    };
    return FALSE;
    };





    // *****************************************************************
    // Реагирует ли цель на оружие, направленное против нее агрессором
    // *****************************************************************


    // =================================================================
    // Аргументы:
    // -----------------------------------------------------------------
    // slf - НПС цель
    // oth - НПС агрессор
    // -----------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - цель реагирует, FALSE - нет.
    // =================================================================


    Открыть спойлер
    func int C_NpcIsBotheredByWeapon(var c_npc slf,var c_npc oth)
    {
    // если цель член партии ГГ
    if(slf.aivar[AIV_PARTYMEMBER] == TRUE)
    {
    return FALSE;
    };
    // если цель друг ГГ и агрессор ГГ (Примечание: правильней вместо other написать oth)
    if(slf.npctype == NPCTYPE_FRIEND) && (Npc_IsPlayer(other))
    {
    return FALSE;
    };
    // если НПС имеет дело с "крутым парнем" и агрессор сражается оружием ближнего радиуса поражения
    if(C_NpcIsToughGuy(slf)) && (Npc_IsInFightMode(oth,FMODE_MELEE))
    {
    return FALSE;
    };
    // если отношения между агрессором и целью дружественны
    if(Npc_GetAttitude(slf,oth) == ATT_FRIENDLY)
    {
    return FALSE;
    };
    // если цель является охранником ворот
    if(C_NpcIsGateGuard(slf))
    {
    return FALSE;
    };
    // если агрессор сражается кулаками
    if(Npc_IsInFightMode(oth,FMODE_FIST))
    {
    return FALSE;
    };
    // если агрессор использует магию и категория используемого заклинания безвредна
    if(Npc_IsInFightMode(oth,FMODE_MAGIC) && (Npc_GetActiveSpellCat(oth) != SPELL_BAD))
    {
    return FALSE;
    };
    // если цель Черный маг или орк
    if((slf.guild == GIL_DMT) || (slf.guild == GIL_ORC))
    {
    return FALSE;
    };
    return TRUE;
    };



    // **********************************************
    // Находится ли НПС в бессознательном состоянии
    // **********************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - НПС в бессознательном состоянии (обездвижен), FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_NpcIsDown(var c_npc slf)
    {
    // если НПС безсознания или в магическом сне или убит
    if(Npc_IsInState(slf,ZS_Unconscious) || Npc_IsInState(slf,ZS_MagicSleep) || Npc_IsDead(slf))
    {
    return TRUE;
    };
    return FALSE;
    };





    // ***********************************
    // Является ли НПС источником зла
    // ***********************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - НПС - источник зла, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_NpcIsEvil(var c_npc slf)
    {
    // если НПС
    if (slf.guild == GIL_DMT) // Черный маг
    || (slf.guild == GIL_DRAGON) // или дракон
    || (slf.guild == GIL_ORC) // или орк
    || (slf.guild == GIL_DRACONIAN) // или ящер
    || (slf.guild == GIL_DEMON) // или демон
    || (slf.guild == GIL_SUMMONED_DEMON) // или вызванный демон
    || (slf.aivar[AIV_MM_REAL_ID] == ID_TROLL_BLACK) // или Черный троль
    || (C_NpcIsUndead(slf)) // или НПС является нежитью
    {
    return TRUE;
    };
    return FALSE;
    };





    // *************************************
    // Является ли НПС охранником ворот
    // *************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_NpcIsGateGuard(var c_npc slf)
    {
    // если НПС находится в состоянии охраны ворот
    if(Npc_IsInState(slf,ZS_Guard_Passage))
    {
    return TRUE;
    };
    return FALSE;
    };





    // *************************************
    // Является ли НПС ГГ
    // *************************************


    // =====================================
    // Аргументы:
    // -------------------------------------
    // slf - проверяемый НПС
    // -------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // =====================================


    Открыть спойлер
    func int C_NpcIsHero(var c_npc slf)
    {
    var c_npc her;
    // получить ссылку на ГГ
    her = Hlp_GetNpc(PC_Hero);
    // если идентификаторы НПС и ГГ равны
    if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(her))
    {
    return TRUE;
    };
    return FALSE;
    };





    // ***********************************************
    // Является ли НПС "крутым парнем"
    // ***********************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_NpcIsToughGuy(var c_npc slf)
    {
    // если установлен признак "крутого парня"
    if(slf.aivar[AIV_ToughGuy] == TRUE)
    {
    return TRUE;
    };
    // если НПС наемник или охотник на драконов или бандит или пират
    if(slf.guild == GIL_SLD) || (slf.guild == GIL_DJG) || (slf.guild == GIL_BDT) || (slf.guild == GIL_PIR)
    {
    return TRUE;
    };
    return FALSE;
    };





    // ***************************************
    // Является ли НПС нежитью
    // ***************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_NpcIsUndead(var c_npc slf)
    {
    // если НПС
    if (slf.guild == GIL_GOBBO_SKELETON) // Скелет гоблина
    || (slf.guild == GIL_SUMMONED_GOBBO_SKELETON) // или Вызванный скелет гоблина
    || (slf.guild == GIL_SKELETON) // или Скелет
    || (slf.guild == GIL_SUMMONED_SKELETON) // или Вызванный скелет
    || (slf.guild == GIL_SKELETON_MAGE) // или Скелет маг
    || (slf.guild == GIL_ZOMBIE) // или Зомби
    || (slf.guild == GIL_SHADOWBEAST_SKELETON) // или Скелет мракориса
    || (slf.guild == GIL_UNDEADORC) // или Орк нежить
    || (slf.aivar[AIV_MM_REAL_ID] == ID_DRAGON_UNDEAD) // или Дракон нежить
    {
    return TRUE;
    };
    return FALSE;
    };



    // ************************************************
    // Должен ли НПС обыскать тело
    // ************************************************


    // ================================================
    // Аргументы:
    // ------------------------------------------------
    // slf - обыскивающий НПС
    // неявно: other - обыскиваемый НПС (цель)
    // ------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ================================================


    Открыть спойлер
    func int C_NpcRansacksAlways(var c_npc slf)
    {
    // если НПС Гарвиг и цель имеет "Святой молот"
    if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(Garwig)) && (Npc_HasItems(other,Holy_Hammer_MIS) > 0)
    {
    return TRUE;
    };
    // если НПС Род и цель имеет "Меч Рода"
    if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(Rod)) && (Npc_HasItems(other,ItMw_2h_Rod) > 0)
    {
    return TRUE;
    };
    return FALSE;
    };





    // ********************************************************************
    // Является ли НПС членом подставной гильдии
    // ********************************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС определяющий подставу
    // oth - проверяемый НПС (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да (определяется что ГГ переодет), FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_PlayerHasFakeGuild(var c_npc slf,var c_npc oth)
    {
    var c_item itm;
    // получить доспехи ГГ
    itm = Npc_GetEquippedArmor(oth);
    // Примечание: следующие две строки не нужны при условии коррекции функции ниже
    var int NSC_CommentRangerArmor;
    NSC_CommentRangerArmor = TRUE;
    // если НПС игнорирует доспехи, в которые одет ГГ
    if(slf.aivar[AIV_IgnoresArmor] == TRUE)
    {
    return FALSE;
    };
    // если НПС игнорирует подставную гильдию
    if(slf.aivar[AIV_IgnoresFakeGuild] == TRUE)
    {
    return FALSE;
    };
    // если НПС является охранником ворот (Примечание: правильнее вместо self написать slf)
    if(C_NpcIsGateGuard(self) == TRUE)
    {
    return FALSE;
    };
    // если НПС бандит и ГГ переодетый в бандита
    if(slf.guild == GIL_BDT) && C_PlayerIsFakeBandit(slf,oth)
    {
    // если ГГ без брони
    if(Npc_HasEquippedArmor(oth) == FALSE)
    {
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если ГГ без брони
    if(Npc_HasEquippedArmor(oth) == FALSE)
    {
    return FALSE;
    }
    // если гильдии НПС и ГГ одинаковы (Примечание: else здесь лишнее)
    else if(slf.guild == oth.guild)
    {
    // если доспехи ГГ "Кольчуга 'Кольца Воды'"
    if(Hlp_IsItem(itm,ITAR_RANGER_Addon) == TRUE)
    {
    // Примечание: выполняется всегда, поэтому условие if можно удалить, оставив только return TRUE;
    if(NSC_CommentRangerArmor == TRUE)
    {
    return TRUE;
    }
    // Примечание: блок else можно удалить
    else
    {
    return FALSE;
    };
    };
    // если ГГ не принадлежит к гильдии и одет в
    if(oth.guild == GIL_NONE)
    && ((Hlp_IsItem(itm,ITAR_VLK_L) == TRUE) // "Одежду горожанина"
    || (Hlp_IsItem(itm,ITAR_VLK_M) == TRUE) // или "Одежду горожанина"
    || (Hlp_IsItem(itm,ITAR_VLK_H) == TRUE) // или "Одежду горожанина" (Примечание: кто может пояснить, чем отличаются эти одежды?)
    || (Hlp_IsItem(itm,ITAR_BAU_L) == TRUE) // или "Одежду крестьянина"
    || (Hlp_IsItem(itm,ITAR_BAU_M) == TRUE) // или "Одежду крестьянина 2"
    || (Hlp_IsItem(itm,ITAR_Leather_L) == TRUE)) // или "Кожаные доспехи"
    {
    return FALSE;
    }
    // Примечание: далее до конца блока все else можно удалить
    // если ГГ милиционер и одет в
    else if(oth.guild == GIL_MIL)
    && ((Hlp_IsItem(itm,ITAR_MIL_L) == TRUE) // "Легкие доспехи ополчения"
    || (Hlp_IsItem(itm,ITAR_MIL_M) == TRUE)) // или "Тяжелые доспехи ополчения"
    {
    return FALSE;
    }
    // если ГГ паладин и одет в
    else if(oth.guild == GIL_PAL)
    && ((Hlp_IsItem(itm,ITAR_PAL_M) == TRUE) // "Доспехи паладина"
    || (Hlp_IsItem(itm,ITAR_PAL_H) == TRUE)) // или "Доспехи паладина" (улучшенные)
    {
    return FALSE;
    }
    // если ГГ наемник и одет в
    else if(oth.guild == GIL_SLD)
    && ((Hlp_IsItem(itm,ITAR_SLD_L) == TRUE) // "Легкие доспехи наемника"
    || (Hlp_IsItem(itm,ITAR_SLD_M) == TRUE) // или "Средние доспехи наемника"
    || (Hlp_IsItem(itm,ITAR_SLD_H) == TRUE)) // или "Тяжелые доспехи наемника"
    {
    return FALSE;
    }
    // если ГГ охотник на драконов и одет в
    else if(oth.guild == GIL_DJG)
    && ((Hlp_IsItem(itm,ITAR_SLD_L) == TRUE) // "Легкие доспехи наемника"
    || (Hlp_IsItem(itm,ITAR_SLD_M) == TRUE) // или "Средние доспехи наемника"
    || (Hlp_IsItem(itm,ITAR_SLD_H) == TRUE) // или "Тяжелые доспехи наемника"
    || (Hlp_IsItem(itm,ITAR_DJG_L) == TRUE) // или "Легкие доспехи охотника на драконов"
    || (Hlp_IsItem(itm,ITAR_DJG_M) == TRUE) // или "Средние доспехи охотника на драконов"
    || (Hlp_IsItem(itm,ITAR_DJG_H) == TRUE) // или "Тяжелые доспехи охотника на драконов"
    || (Hlp_IsItem(itm,ITAR_DJG_Crawler) == TRUE)) // или "Доспехи из панцирей ползунов"
    {
    return FALSE;
    }
    // если ГГ маг послушник и одет в "Робу послушника"
    else if(oth.guild == GIL_NOV) && (Hlp_IsItem(itm,ITAR_NOV_L) == TRUE)
    {
    return FALSE;
    }
    // если ГГ маг огня и одет в
    else if(oth.guild == GIL_KDF)
    && ((Hlp_IsItem(itm,ITAR_KDF_L) == TRUE) // "Робу мага огня"
    || (Hlp_IsItem(itm,ITAR_KDF_H) == TRUE)) // или "Тяжелую робу огня"
    {
    return FALSE;
    }
    else
    {
    return TRUE;
    };
    };
    return FALSE;
    };





    // ********************************************************************
    // Является ли НПС членом гильдии бандитов
    // ********************************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС определяющий подставу
    // oth - проверяемый НПС (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да (ГГ "принадлежит" к бандитам), FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_PlayerIsFakeBandit(var c_npc slf,var c_npc oth)
    {
    var c_item itm;
    // если НПС игнорирует доспехи, в которые одет ГГ
    if(slf.aivar[AIV_IgnoresArmor] == TRUE)
    {
    return FALSE;
    };
    // если НПС игнорирует подставную гильдию
    if(slf.aivar[AIV_IgnoresFakeGuild] == TRUE)
    {
    return FALSE;
    };
    // если НПС пират
    if(slf.guild == GIL_PIR)
    {
    return FALSE;
    };
    // если ГГ одет в броню
    if(Npc_HasEquippedArmor(oth) == TRUE)
    {
    // получить доспехи ГГ
    itm = Npc_GetEquippedArmor(oth);
    // если доспехи ГГ
    if((Hlp_IsItem(itm,ITAR_BDT_M) == TRUE) // "Средняя бандитская кольчуга"
    || (Hlp_IsItem(itm,ItAR_Thorus_Addon) == TRUE) // или "Тяжелая кольчуга гардиста"
    || (Hlp_IsItem(itm,ITAR_BDT_H) == TRUE)) // или "Тяжелая бандитская кольчуга"
    {
    return TRUE;
    };
    return FALSE;
    }
    // если НПС бандит и текущий уровень - Яркендар и ГГ может разговаривать с бандитами (Равен убит)
    if(slf.guild == GIL_BDT) && (CurrentLevel == ADDONWORLD_ZEN) && (Player_HasTalkedToBanditCamp == TRUE)
    {
    return TRUE;
    };
    return FALSE;
    };





    // ********************************************************************
    // Является ли НПС членом гильдии пиратов
    // ********************************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС определяющий подставу
    // oth - проверяемый НПС (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да (ГГ "принадлежит" к пиратам), FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_PlayerIsFakePirate(var c_npc slf,var c_npc oth)
    {
    var c_item itm;
    // если НПС игнорирует доспехи, в которые одет ГГ
    if(slf.aivar[AIV_IgnoresArmor] == TRUE)
    {
    return FALSE;
    };
    // если НПС игнорирует подставную гильдию
    if(slf.aivar[AIV_IgnoresFakeGuild] == TRUE)
    {
    return FALSE;
    };
    // если ГГ одет в броню (Примечание: правильнее вместо other написать oth)
    if(Npc_HasEquippedArmor(other) == TRUE)
    {
    // получить доспехи ГГ
    itm = Npc_GetEquippedArmor(oth);
    // если доспехи ГГ
    if((Hlp_IsItem(itm,ITAR_PIR_L_Addon) == TRUE) // "Одежда пирата"
    || (Hlp_IsItem(itm,ItAR_PIR_M_Addon) == TRUE) // или "Доспехи пирата"
    || (Hlp_IsItem(itm,ITAR_PIR_H_Addon) == TRUE)) // или "Одежда капитана"
    {
    return TRUE;
    };
    };
    return FALSE;
    };



    // *************************************************
    // Отказывается ли НПС от предлагаемого разговора
    // *************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС, которому предложили разговор
    // oth - инициатор разговора (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_RefuseTalk(var c_npc slf,var c_npc oth)
    {
    // если НПС не может говорить и он охраняет ворота и он не выдавал предупреждений
    if(Npc_RefuseTalk(slf) == TRUE) && (C_NpcIsGateGuard(slf)) && (slf.aivar[AIV_Guardpassage_Status] == GP_NONE)
    {
    return TRUE;
    };

    // если НПС с ГГ не разговаривал и НПС находится от своего вайпоинта далее 5м
    if(slf.aivar[AIV_TalkedToPlayer] == FALSE) && (Npc_GetDistToWP(slf,slf.wp) > 500)
    {
    // если НПС Лотар
    if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(Lothar))
    {
    return TRUE;
    };
    };
    // если НПС определил, что ГГ член подставной гильдии и НПС неуязвимый (Примечание: необходимо self заменить на slf)
    if(C_PlayerHasFakeGuild(slf,oth) && (self.flags != NPC_FLAG_IMMORTAL)
    {
    return TRUE;
    };
    return FALSE;
    };





    // *************************************
    // Должен ли НПС атаковать убийцу
    // *************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // oth - НПС убийца (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_WantToAttackMurder(var c_npc slf,var c_npc oth)
    {
    // если НПС Черный маг или Заключенный или Охотник на драконов или Бандит
    if(slf.guild == GIL_DMT) || (slf.guild == GIL_STRF) || (slf.guild == GIL_DJG) || (slf.guild == GIL_BDT)
    {
    return FALSE;
    };
    // если НПС игнорирует убийство
    if(slf.aivar[AIV_IGNORE_Murder] == TRUE)
    {
    return FALSE;
    };
    // если убийца ГГ и НПС ему друг
    if(Npc_IsPlayer(oth) && (slf.npctype == NPCTYPE_FRIEND))
    {
    return FALSE;
    };
    // если НПС убийца должен быть убить цель
    if(C_NpcHasAttackReasonToKill(oth))
    {
    return FALSE;
    };
    // если НПС охраняет ворота
    if(C_NpcIsGateGuard(slf))
    {
    return FALSE;
    };
    return TRUE;
    };





    // ********************************************************
    // Должен ли НПС напасть на незваного гостя
    // ********************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_WantToAttackRoomIntruder(var c_npc slf)
    {
    // Примечание: необходимо во всей функции self заменить на slf.
    // если НПС Милиционер или Паладин или Наемник или Охотник на драконов или ГГ имеет совершенный криминал
    if(self.guild == GIL_MIL) || (self.guild == GIL_PAL) || (self.guild == GIL_SLD) || (self.guild == GIL_DJG) || (B_GetPlayerCrime(self) != CRIME_NONE)
    {
    return TRUE;
    };
    return FALSE;
    };





    // **************************************
    // Должен ли НПС атаковать убийцу овец
    // **************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // oth - НПС убийца (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_WantToAttackSheepKiller(var c_npc slf,var c_npc oth)
    {
    // если НПС Черный маг или Заключенный или Бандит или Охотник на драконов
    if(slf.guild == GIL_DMT) || (slf.guild == GIL_STRF) || (slf.guild == GIL_BDT) || (slf.guild == GIL_DJG)
    {
    return FALSE;
    };
    // если НРС игнорирует убийство овец
    if(slf.aivar[AIV_IGNORE_Sheepkiller] == TRUE)
    {
    return FALSE;
    };
    // если убийца ГГ и НПС ему друг
    if(Npc_IsPlayer(oth) && (slf.npctype == NPCTYPE_FRIEND))
    {
    return FALSE;
    };
    // если убийца должен был убить овцу
    if(C_NpcHasAttackReasonToKill(oth))
    {
    return FALSE;
    };
    // если убийца человек и у него была причина нападения (Примечание: необходимо other заменить на oth)
    if(other.guild < GIL_SEPERATOR_HUM) && (other.aivar[AIV_ATTACKREASON] != AR_NONE)
    {
    return FALSE;
    };
    // если НПС охраняет ворота
    if(C_NpcIsGateGuard(slf))
    {
    return FALSE;
    };
    return TRUE;
    };





    // ******************************************
    // Должен ли НПС атаковать вора
    // ******************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // oth - НПС вор (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_WantToAttackThief(var c_npc slf,var c_npc oth)
    {
    // если НПС Черный ман или Заключенный или Охотник на драконов
    if(slf.guild == GIL_DMT) || (slf.guild == GIL_STRF) || (slf.guild == GIL_DJG)
    {
    return FALSE;
    };
    // если НПС не реагирует на воровство
    if(slf.aivar[AIV_IGNORE_Theft] == TRUE)
    {
    return FALSE;
    };
    // если НПС проиграл последнее сражение с ГГ
    if(slf.aivar[AIV_LastFightAgainstPlayer] == FIGHT_LOST)
    {
    return FALSE;
    };
    // если вор ГГ и НПС ему друг
    if(Npc_IsPlayer(oth) && (slf.npctype == NPCTYPE_FRIEND))
    {
    return FALSE;
    };
    // если НПС охраняет ворота
    if(C_NpcIsGateGuard(slf))
    {
    return FALSE;
    };
    return TRUE;
    };





    // *********************************
    // Должен ли НПС убежать от цели
    // *********************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // oth - цель (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_WantToFlee(var c_npc slf,var c_npc oth)
    {
    // никогда не убегает!!!
    return FALSE;
    };





    // *********************************
    // Должен ли НПС обыскать тело
    // *********************************


    // =================================
    // Аргументы:
    // ---------------------------------
    // slf - проверяемый НПС
    // other - тело (задано неявно)
    // ---------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // =================================


    Открыть спойлер
    func int C_WantToRansack(var c_npc slf)
    {
    // если НРС друг ГГ и тело есть ГГ
    if(slf.npctype == NPCTYPE_FRIEND) && (Npc_IsPlayer(other))
    {
    return FALSE;
    };
    // если НПС Равен
    if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(Raven))
    {
    return FALSE;
    };
    // если НПС Черный маг или Орк или Паладин или Маг огня или Послушник или Маг воды
    if(slf.guild == GIL_DMT) || (slf.guild == GIL_ORC) || (slf.guild == GIL_PAL) || (slf.guild == GIL_KDF) || (slf.guild == GIL_NOV) || (slf.guild == GIL_KDW)
    {
    return FALSE;
    };
    return TRUE;
    };





    // **********************************************
    // Должен ли НПС реагировать на крадущегося ГГ
    // **********************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый НПС
    // oth - крадущийся НПС (обычно ГГ)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    Открыть спойлер
    func int C_WantToReactToSneaker(var c_npc slf,var c_npc oth)
    {
    // если расстояние между НПС и ГГ > 7м
    if(Npc_GetDistToNpc(slf,oth) > 700)
    {
    return FALSE;
    };
    // если НПС Черный маг или Заключенный или Бандит и НПС не принадлежит к Лагерю бандитов
    if(slf.guild == GIL_DMT) || (slf.guild == GIL_STRF) || ((slf.guild == GIL_BDT) && !C_NpcBelongsToBL(slf))
    {
    return FALSE;
    };
    // если НПС друг ГГ и ГГ крадется
    if(slf.npctype == NPCTYPE_FRIEND) && (Npc_IsPlayer(oth))
    {
    return FALSE;
    };
    // если отношения между НПС и крадущимся НПС дружеские
    if(Npc_GetAttitude(slf,oth) == ATT_FRIENDLY)
    {
    return FALSE;
    };
    // если НПС охраняет ворота (Примечание: необходимо self заменить на slf)
    if(C_NpcIsGateGuard(self))
    {
    return FALSE;
    };
    return TRUE;
    };
     
    Ur-tRall и Валера сказали Спасибо
  3. MEG@VOLT

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

    Регистрация:
    24 мар 2006
    Сообщения:
    1.566
    Благодарности:
    628
    Баллы:
    290
    14. Отношения между гильдиями.

    Отношения между гильдиями людей задаются в файле AI\Human\Guilds.d в виде таблицы. Ссылки в скриптах на эту таблицу вы не найдете, она используется только экзешником.
    Примечание: Таблицу необходимо смотреть в широкоформатном редакторе.
    Открыть спойлер
    // размер таблицы
    const int TAB_ANZAHL = 16 * 16;

    // таблица отношений между гильдиями людей
    const int GIL_ATTITUDES[TAB_ANZAHL] =
    {
    // ***Гильдии*** Отсутствует Паладин Милиционер Горожанин Маг огня Послушник Охотник драк. Наемник Крестьянин Бандит Заключенный Черный маг Чузеземец Пират Маг воды Публичная
    /* Отсутствует */
    ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /*******************************************************************************
    ********************************************************************************
    ********************************************************************************
    /* Паладин */
    ATT_NEUTRAL, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /* Милиционер */ ATT_NEUTRAL, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /* Горожанин */ ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /*******************************************************************************
    ********************************************************************************
    ********************************************************************************
    /* Маг огня */
    ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /* Послушник */ ATT_NEUTRAL, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /*******************************************************************************
    ********************************************************************************
    ********************************************************************************
    /* Охотник драк.*/
    ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /* Наемник */ ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /* Крестьянин */ ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /*******************************************************************************
    ********************************************************************************
    ********************************************************************************
    /* Бандит */
    ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /* Заключенный */ ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /* Черный маг */ ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_HOSTILE, ATT_NEUTRAL, ATT_HOSTILE, ATT_FRIENDLY, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL,
    /*******************************************************************************
    ********************************************************************************
    ********************************************************************************
    /* Чужеземец */
    ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_FRIENDLY, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL,
    /* Пират */ ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL,
    /* Маг воды */ ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_HOSTILE, ATT_NEUTRAL, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL, ATT_FRIENDLY, ATT_NEUTRAL,
    /* Публичная */ ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL, ATT_NEUTRAL
    };


    Отношения между гильдиями монстров и гильдиями монстров и людей задаются в файле AI\Monster\B_Monster\B_InitMonsterAttitudes.d
    Данный файл я приводить не буду, у него очень большой размер (около 160 Кб).
    Все отношения задаются через вызов функции B_InitMonsterAttitudes(), эту функцию мы и рассмотрим: она расположена в этой же директории в одноименном файле.
    // ********************************************************************
    // Устанавливает отношения между гильдиями монстров и всеми остальными
    // ********************************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // fromGuild - гильдия для которой устанавливается отношение
    // attitude - отношение
    // toGuild - гильдия с которой устанавливается отношение
    // ====================================================================


    Открыть спойлер
    func void B_SetMonsterAttitude(var int fromGuild,var int attitude,var int toGuild)
    {
    // если отношение устанавливается с людьми
    if(toGuild == GIL_SEPERATOR_HUM)
    {
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_NONE);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_PAL);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_MIL);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_VLK);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_KDF);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_NOV);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_DJG);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_SLD);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_BAU);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_BDT);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_STRF);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_OUT);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_PIR);
    Wld_SetGuildAttitude(fromGuild,attitude,GIL_KDW);
    }
    // если отношение устанавливается для людей
    else if(fromGuild == GIL_SEPERATOR_HUM)
    {
    Wld_SetGuildAttitude(GIL_NONE,attitude,toGuild);
    Wld_SetGuildAttitude(GIL_PAL, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_MIL, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_VLK, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_KDF, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_NOV, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_DJG, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_SLD, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_BAU, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_BDT, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_STRF,attitude,toGuild);
    Wld_SetGuildAttitude(GIL_OUT, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_PIR, attitude,toGuild);
    Wld_SetGuildAttitude(GIL_KDW, attitude,toGuild);
    }
    else // устанавливается отношение между монстрами
    {
    Wld_SetGuildAttitude(fromGuild,attitude,toGuild);
    };
    };
     
    Ur-tRall и Валера сказали Спасибо
  4. MEG@VOLT

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

    Регистрация:
    24 мар 2006
    Сообщения:
    1.566
    Благодарности:
    628
    Баллы:
    290
    15. Магия.

    Общие магические функции расположены в директории AI\Magic
    // ****************************************************
    // Регистрация повреждения от магии и начисление экспы
    // ****************************************************


    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - НПС кастующий заклинание
    // oth - НПС цель
    // damage - повреждение, нанесенное заклинанием
    // ====================================================================


    Открыть спойлер
    func void B_MagicHurtNpc(var c_npc slf,var c_npc oth,var int damage)
    {
    // уменьшить жизнь цели на величину повреждения
    Npc_ChangeAttribute(oth,ATR_HITPOINTS,-damage);
    // если цель мертва
    if(Npc_IsDead(oth))
    {
    // (если кастующий ГГ или кастующий член партии ГГ) и экспа за цель не была начислена
    if(Npc_IsPlayer(slf) || (slf.aivar[AIV_PARTYMEMBER]==TRUE)) && (oth.aivar[AIV_VictoryXPGiven] == FALSE)
    {
    // начисление ГГ экспы (уровень цели * 10) (Примечание: Ошибка - вместо self.level должно быть oth.level)
    B_GivePlayerXP(self.level * XP_PER_VICTORY);
    // установить НПС флаг начисления экспы
    oth.aivar[AIV_VictoryXPGiven] = TRUE;
    };
    };
    };





    // **************************************
    // Подготовка заклинания к использованию
    // **************************************


    // ================================================
    // Аргументы:
    // ------------------------------------------------
    // slf - НПС кастующий заклинание
    // spell - заклинание
    // mana - требуемое кол-во маны
    // ================================================


    Открыть спойлер
    func void B_ReadySpell(var c_npc slf,var int spell,var int mana)
    {
    // если макс. мана < требуемой
    if(slf.attribute[ATR_MANA_MAX] < mana)
    {

    // увеличить макс. ману на величину требуемой
    Npc_ChangeAttribute(slf,ATR_MANA_MAX,mana);
    };
    // если мана < требуемой
    if(slf.attribute[ATR_MANA] < mana)
    {
    // увеличить ману на величину требуемой
    Npc_ChangeAttribute(slf,ATR_MANA,mana);
    };
    // если это заклинание уже применяется
    if(Npc_IsDrawingSpell(slf) == spell)
    {
    return;
    }
    // если это заклинание уже активно
    if(Npc_GetActiveSpell(slf) == spell)
    {
    return;
    }
    // если активно другое заклинание
    else if(Npc_GetActiveSpell(slf) != -1)
    {
    // убрать старое заклинание
    AI_RemoveWeapon(slf);
    };
    // взять заклинание в руку
    AI_ReadySpell(slf,spell,mana);
    };





    // *************************************************************
    // Выбор заклинания кастующим НПС
    // *************************************************************


    // =============================================================
    // Аргументы:
    // -------------------------------------------------------------
    // slf - НПС кастующий заклинание (агрессор)
    // oth - НПС цель
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - заклинание готово, FALSE - нет.
    // =============================================================


    Открыть спойлер
    func int B_SelectSpell(var c_npc slf,var c_npc oth)
    {
    // если агрессор друг ГГ и цель ГГ и цель человек
    if(slf.npctype == NPCTYPE_FRIEND) && Npc_IsPlayer(oth) && (oth.guild < GIL_SEPERATOR_HUM)
    {
    // если агрессор Маг огня или агрессор всегда использует магию
    if(slf.guild == GIL_KDF) || (slf.aivar[AIV_MagicUser] == MAGIC_ALWAYS)
    {
    // если агрессор не имеет руны Сон
    if(Npc_HasItems(slf,ItRu_Sleep) == 0)
    {
    // создать в инвентаре агрессора руну Сон
    CreateInvItems(slf,ItRu_Sleep,1);
    };
    // подготовка заклинания Сон
    B_ReadySpell(slf,SPL_Sleep,SPL_Cost_Sleep);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если агрессор Черный маг и агрессор всегда использует магию
    if(slf.guild == GIL_DMT) && (slf.aivar[AIV_MagicUser] == MAGIC_ALWAYS)
    {
    // создать в инвентаре агрессора следующие руны, если он их не имеет
    if(Npc_HasItems(slf,ItRu_InstantFireball) == 0) {CreateInvItems(slf,ItRu_InstantFireball,1);}; // "Огненный шар"
    if(Npc_HasItems(slf,ItRu_Deathbolt) == 0) {CreateInvItems(slf,ItRu_Deathbolt,1);}; // "Deathbolt" (Примечание: название не переведено)
    if(Npc_HasItems(slf,ItRu_Deathball) == 0) {CreateInvItems(slf,ItRu_Deathball,1);}; // "Deathball"
    if(Npc_HasItems(slf,ItRu_Firerain) == 0) {CreateInvItems(slf,ItRu_Firerain,1);}; // "Огненный дождь"
    if(Npc_HasItems(slf,ItRu_Thunderstorm) == 0) {CreateInvItems(slf,ItRu_Thunderstorm,1);}; // "Шторм"
    if(Npc_HasItems(slf,ItRu_LightningFlash) == 0) {CreateInvItems(slf,ItRu_LightningFlash,1);}; // "Удар молнии"
    if(Npc_HasItems(slf,ItRu_Firestorm) == 0) {CreateInvItems(slf,ItRu_Firestorm,1);}; // "Малая огненная буря"
    if(Npc_HasItems(slf,ItRu_Skull) == 0) {CreateInvItems(slf,ItRu_Skull,1);}; // "Крик мертвых"
    // если агрессор "Черный маг" (Примечание: Маг какой-то особенный, хотя в переводе не отражено)
    if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(DMT_1299_OberDementor_DI))
    {
    // подготовка заклинания "Крик мертвых"
    B_ReadySpell(slf,SPL_Skull,SPL_Cost_Skull);
    return TRUE;
    }
    else // обычные Черные маги
    {
    // если уже есть оружие готовое к бою
    if(Npc_IsDrawingWeapon(slf))
    {
    return TRUE;
    };
    // если случайное число не задано
    if(slf.aivar[AIV_SelectSpell] <= 0)
    {
    var int dK_rnd;
    dK_rnd = Hlp_Random(10);
    // получить случайное число
    slf.aivar[AIV_SelectSpell] += dK_rnd;
    };
    // если случайное число < 10
    if(slf.aivar[AIV_SelectSpell] < 10)
    {
    // если Глава <= 3, то подготовить заклинание "Огненный шар"
    if(Kapitel <= 3) {B_ReadySpell(slf,SPL_InstantFireball,SPL_Cost_InstantFireball); return TRUE;}
    // если Глава <= 4, то подготовить заклинание "Deathbolt"
    else if (Kapitel <= 4) {B_ReadySpell(slf,SPL_DeathBolt,SPL_Cost_DeathBolt); return TRUE;}
    // иначе подготовить заклинание "Deathbаll"
    else /*Kap 5+*/ {B_ReadySpell(slf,SPL_DeathBall,SPL_Cost_DeathBall); return TRUE;};
    }
    // если случайное число == 10
    else if(slf.aivar[AIV_SelectSpell] == 10)
    {
    // случайное число = 11
    slf.aivar[AIV_SelectSpell] = 11;
    var int dK_Mega;
    dK_Mega = Hlp_Random(100);
    // с вероятностью 0.02 подготовить заклинание "Огненный дождь"
    if (dK_Mega <= 2) {B_ReadySpell(slf,SPL_Firerain,SPL_Cost_Firerain); return TRUE;}
    // с вероятностью 0.03 подготовить заклинание "Шторм"
    else if (dK_Mega <= 5) {B_ReadySpell(slf,SPL_Thunderstorm,SPL_Cost_Thunderstorm); return TRUE;}
    // с вероятностью 0.05 подготовить заклинание "Удар молнии"
    else if (dK_Mega <= 10) {B_ReadySpell(slf,SPL_LightningFlash,SPL_Cost_LightningFlash); return TRUE;}
    // с вероятностью 0.9 подготовить заклинание "Малая огненная буря"
    else {B_ReadySpell(slf,SPL_Firestorm,SPL_Cost_Firestorm); return TRUE;};
    }
    // если случайное число == 12
    else if (slf.aivar[AIV_SelectSpell] == 12)
    {
    // случайное число == 0
    slf.aivar[AIV_SelectSpell] = 0;
    };
    };
    return TRUE;
    };
    // если агрессор Маг огня или агрессор всегда использует магию
    if(slf.guild == GIL_KDF) || (slf.aivar[AIV_MagicUser] == MAGIC_ALWAYS)
    {
    // создать в инвентаре агрессора следующие руны, если он их не имеет
    if(Npc_HasItems(slf,ItRu_Concussionbolt) == 0)
    {
    CreateInvItems(slf,ItRu_Concussionbolt,1); // "Concussionbolt" (Название не переведено)
    };
    if(Npc_HasItems(slf,ItRu_InstantFireBall) == 0)
    {
    CreateInvItems(slf,ItRu_InstantFireBall,1); // "Огненный шар"
    };
    if(Npc_HasItems(slf,ItRu_Deathball) == 0)
    {
    CreateInvItems(slf,ItRu_Deathball,1); // "Deathball" (Название не переведено)
    };
    if(Npc_HasItems(slf,ItRu_FullHeal) == 0)
    {
    CreateInvItems(slf,ItRu_FullHeal,1); // "Лечить сильное ранение"
    };
    // если текущая жизнь агрессора < 100 (Примечание: здесь и далее необходимо self заменить на slf)
    if(self.attribute[ATR_HITPOINTS] < 100)
    {
    // подготовить заклинание "Лечить сильное ранение"
    B_ReadySpell(slf,SPL_FullHeal,SPL_Cost_FullHeal);
    return TRUE;
    }
    // если причина атаки агрессора убийство цели
    else if(C_NpcHasAttackReasonToKill(self))
    {
    // если цель неуязвима или цель Равен (Примечание: Ошибка - необходимо self и other заменить на oth)
    if(self.flags == NPC_FLAG_IMMORTAL) || (Hlp_GetInstanceID(other) == Hlp_GetInstanceID(Raven))
    {
    // подготовить заклинание "Deathball"
    B_ReadySpell(slf,SPL_Deathball,SPL_Cost_Deathball);
    }
    else
    {
    // подготовить заклинание "Огненный шар"
    B_ReadySpell(slf,SPL_InstantFireball,SPL_Cost_InstantFireBall);
    };
    return TRUE;
    }
    else
    {
    // подготовить заклинание "Concussionbolt"
    B_ReadySpell(slf,SPL_Concussionbolt,SPL_Cost_Concussionbolt);
    return TRUE;
    };
    };
    // если агрессор Паладин
    if(slf.guild == GIL_PAL)
    {
    // если агрессор применяет тактику сражения охраны крепостных стен
    if(slf.fight_tactic == FAI_NAILED)
    {
    return FALSE;
    };
    // если агрессор не имеет руны "Святая стрела"
    if(Npc_HasItems(slf,ItRu_PalHolyBolt) == 0)
    {
    // создать в инвентаре агрессора руну "Святая стрела"
    CreateInvItems(slf,ItRu_PalHolyBolt,1);
    };
    // если расстояние между агрессором и целью > дистанции атаки оружием ближнего радиуса действия и цель является источником зла
    if(Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_MELEE) && (C_NpcIsEvil(oth))
    {
    // подготовить заклинание "Святая стрела"
    B_ReadySpell(slf,SPL_PalHolyBolt,SPL_Cost_PalHolyBolt);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если агрессор Маг скелетов
    if(slf.guild == GIL_SKELETON_MAGE)
    {
    // создать в инвентаре агрессора следующие руны, если он их не имеет
    if(Npc_HasItems(slf,ItRu_SumSkel) == 0)
    {
    CreateInvItems(slf,ItRu_SumSkel,1); // "Вызвать скелет"
    };
    if(Npc_HasItems(slf,ItRu_IceCube) == 0)
    {
    CreateInvItems(slf,ItRu_IceCube,1); // "Ледяная глыба"
    };
    if(Npc_HasItems(slf,ItRu_Icebolt) == 0)
    {
    CreateInvItems(slf,ItRu_Icebolt,1); // "Ледяная стрела"
    };
    // если случайное число >= 6
    if(slf.aivar[AIV_SelectSpell] >= 6)
    {
    // случайное число = 1
    slf.aivar[AIV_SelectSpell] = 1;
    };
    // если цель не заморожена и случайное число == 0
    if(!Npc_IsInState(oth,ZS_MagicFreeze)) && (slf.aivar[AIV_SelectSpell] == 0)
    {
    // подготовить заклинание "Ледяная глыба"
    B_ReadySpell(slf,SPL_IceCube,SPL_Cost_IceCube);
    return TRUE;
    }
    // если случайное число == 1
    else if (slf.aivar[AIV_SelectSpell] == 1)
    {
    // подготовить заклинание "Вызвать скелет"
    B_ReadySpell(slf,SPL_SummonSkeleton,SPL_Cost_SummonSkeleton);
    return TRUE;
    }
    else
    {
    // подготовить заклинание "Ледяная стрела"
    B_ReadySpell(slf,SPL_Icebolt,SPL_Cost_Icebolt);
    return TRUE;
    };
    };
    // если агрессор Ледяной голем
    if(slf.guild == GIL_ICEGOLEM)
    {
    // если агрессор не имеет руны "Ледяная глыба"
    if(Npc_HasItems(slf,ItRu_IceCube) == 0)
    {
    // создать в инвентаре агрессора руну "Ледяная глыба"
    CreateInvItems(slf,ItRu_IceCube,1);
    };
    // если расстояние между агрессором и целью < дистанции атаки оружием ближнего радиуса действия или цель заморожена
    if(Npc_GetDistToNpc(slf,oth) < FIGHT_DIST_MELEE) || Npc_IsInState(oth,ZS_MagicFreeze)
    {
    return FALSE;
    }
    else
    {
    // подготовить заклинание "Ледяная глыба"
    B_ReadySpell(slf,SPL_IceCube,SPL_Cost_IceCube);
    return TRUE;

    };
    };
    // если агрессор Огненный голем
    if(slf.guild == GIL_FIREGOLEM)
    {
    // если агрессор не имеет руны "Огненный шар"
    if(Npc_HasItems(slf,ItRu_InstantFireball) == 0)
    {
    // создать в инвентаре агрессора руну "Огненный шар"
    CreateInvItems(slf,ItRu_InstantFireball,1);
    };
    // если расстояние между агрессором и целью > дистанции атаки оружием ближнего радиуса действия
    if(Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_MELEE)
    {
    // подготовить заклинание "Огненный шар"
    B_ReadySpell(slf,SPL_InstantFireball,SPL_Cost_InstantFireball);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если агрессор Болотный дракон
    if(slf.aivar[AIV_MM_REAL_ID] == ID_DRAGON_SWAMP)
    {
    // если агрессор не имеет руны "Огненный шар"
    if(Npc_HasItems(slf,ItRu_InstantFireball) == 0)
    {
    // создать в инвентаре агрессора руну "Огненный шар"
    CreateInvItems(slf,ItRu_InstantFireball,1);
    };
    // если расстояние между агрессором и целью > дистанции применения драконами магии
    if(Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_DRAGON_MAGIC)
    {
    // подготовить заклинание "Огненный шар"
    B_ReadySpell(slf,SPL_InstantFireball,SPL_Cost_InstantFireball);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если агрессор Каменный дракон (всё идентично Болотному дракону)
    if(slf.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ROCK)
    {
    if (Npc_HasItems(slf,ItRu_InstantFireball) == 0)
    {
    CreateInvItems(slf,ItRu_InstantFireball,1);
    };
    if (Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_DRAGON_MAGIC)
    {
    B_ReadySpell(slf,SPL_InstantFireball,SPL_Cost_InstantFireball);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если агрессор Огненный дракон (всё идентично Болотному дракону)
    if(slf.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE)
    {
    if(Npc_HasItems(slf,ItRu_InstantFireball) == 0)
    {
    CreateInvItems(slf,ItRu_InstantFireball,1);
    };
    if(Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_DRAGON_MAGIC)
    {
    B_ReadySpell(slf,SPL_InstantFireball,SPL_Cost_InstantFireball);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если агрессор Ледяной дракон (всё идентично Болотному дракону)
    if(slf.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE)
    {
    if(Npc_HasItems(slf,ItRu_InstantFireball) == 0)
    {
    CreateInvItems(slf,ItRu_InstantFireball,1);
    };
    if(Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_DRAGON_MAGIC)
    {
    B_ReadySpell(slf,SPL_InstantFireball,SPL_Cost_InstantFireball);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если агрессор Дракон нежить
    if(slf.aivar[AIV_MM_REAL_ID] == ID_DRAGON_UNDEAD)
    {
    // очистить очередь AI состояний агрессора (Примечание: заменить self на slf)
    Npc_ClearAIQueue(self);
    // если агрессор не имеет руны "Deathball"
    if(Npc_HasItems(slf,ItRu_Deathball) == 0)
    {
    // создать в инвентаре агрессора руну "Deathball"
    CreateInvItems(slf,ItRu_Deathball,1);
    };
    // если расстояние между агрессором и целью > дистанции применения драконами магии
    if(Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_DRAGON_MAGIC)
    {
    // подготовить заклинание "Deathball"
    B_ReadySpell(slf,SPL_Deathball,SPL_Cost_Deathball);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    // если агрессор Шаман орков (всё идентично Огненному голему)
    if(slf.aivar[AIV_MM_REAL_ID] == ID_ORCSHAMAN)
    {
    if(Npc_HasItems(slf,ItRu_InstantFireball) == 0)
    {
    CreateInvItems(slf,ItRu_InstantFireball,1);
    };
    if(Npc_GetDistToNpc(slf,oth) > FIGHT_DIST_MELEE)
    {
    B_ReadySpell(slf,SPL_InstantFireball,SPL_Cost_InstantFireball);
    return TRUE;
    }
    else
    {
    return FALSE;
    };
    };
    return FALSE;
    };



    // ******************************************************************
    // Действия, оказываемые заклинаниями, на НПС
    // ------------------------------------------------------------------
    // Данная функция вызывается только экзешником в состоянии НПС реакции на магию
    // self - НПС, против которого применено заклинание
    // other - НПС, применивший заклинание
    // ******************************************************************


    Открыть спойлер
    const int COLL_DONOTHING = 0; // воздействие не оказывается
    const int COLL_DOEVERYTHING = 1<<0; // полное воздействие
    const int COLL_APPLYDAMAGE = 1<<1; // только физический урон
    const int COLL_APPLYHALVEDAMAGE = 1<<2; // половинный урон
    const int COLL_APPLYDOUBLEDAMAGE = 1<<3; // удвоенный урон
    const int COLL_APPLYVICTIMSTATE = 1<<4; // в зависимости от состояния жертвы
    const int COLL_DONTKILL = 1<<5; // не убивает



    // =============================================================
    // Аргументы:
    // -------------------------------------------------------------
    // spellType - тип заклинания
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // Тип оказываемого воздействия на НПС.
    // =============================================================


    Открыть спойлер
    func int C_CanNpcCollideWithSpell(var int spellType)
    {
    // если заклинание "Смерч"
    if(spellType == SPL_Whirlwind)
    {
    // если НПС обездвижен или
    if (C_NpcIsDown(self))
    || (C_BodyStateContains(self,BS_SWIM)) // плывет
    || (C_BodyStateContains(self,BS_DIVE)) // или ныряет
    || (self.guild == GIL_STONEGOLEM) // или Каменный голем
    || (self.guild == GIL_ICEGOLEM) // или Ледяной голем
    || (self.guild == GIL_FIREGOLEM) // или Каменный голем
    || (self.guild == GIL_SUMMONED_GOLEM) // или Вызванный голем
    || (self.guild == GIL_DEMON) // или Демон
    || (self.guild == GIL_SUMMONED_DEMON) // или Вызванный демон
    || (self.guild == GIL_TROLL) // или Троль
    || (self.guild == GIL_SUMMONED_GOLEM) // повтор (убрать!)
    || (self.guild == GIL_DRAGON) // или Дракон
    || (self.guild == GIL_STONEGUARDIAN) // или Каменный страж
    || (self.flags == NPC_FLAG_IMMORTAL) // или неубиваем
    || (self.guild == GIL_SHADOWBEAST) // или Мракорис
    || (self.guild == GIL_GARGOYLE) // или Огненный дух мракориса
    {
    return COLL_DONOTHING;
    };
    // если НПС охраняет ворота
    if(C_NpcIsGateGuard(self) == TRUE)
    {
    return COLL_APPLYDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание "Ледяное копье"
    if(spellType == SPL_Icelance)
    {
    // если НПС обездвижен или плывет или ныряет
    if(C_NpcIsDown(self)) || (C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE))
    {
    return COLL_DONOTHING;
    };
    // если НПС Ледяной голем или Ледяной волк или Ледяной дракон
    if(self.guild == GIL_ICEGOLEM) || (self.aivar[AIV_MM_REAL_ID] == ID_Icewolf) || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE)
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    // если НПС Огненный голем или
    if (self.guild == GIL_FIREGOLEM)
    || (self.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN) // Огненная ящерица
    || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE) // или Огненный дракон
    || (self.guild == GIL_GARGOYLE) // или Огненный дух мракориса
    {
    return COLL_APPLYDOUBLEDAMAGE;
    };
    return COLL_APPLYDAMAGE;
    };
    // если заклинание "Шторм"
    if (spellType == SPL_Thunderstorm)
    {
    // если НПС обездвижен или плывет или ныряет
    if(C_NpcIsDown(self)) || (C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE))
    {
    return COLL_DONOTHING;
    };
    // если НПС Ледяной голем или Ледяной волк или Ледяной дракон
    if(self.guild == GIL_ICEGOLEM) || (self.aivar[AIV_MM_REAL_ID] == ID_Icewolf) || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE)
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    // если НПС Огненный голем или
    if (self.guild == GIL_FIREGOLEM)
    || (self.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN) // Огненная ящерица
    || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE) // или Огненный дракон
    || (self.guild == GIL_GARGOYLE) // или Огненный дух мракориса
    {
    return COLL_APPLYDOUBLEDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание "Гейзер"
    if(spellType == SPL_Geyser)
    {
    // если НПС обездвижен
    if (C_NpcIsDown(self))
    || (C_BodyStateContains(self,BS_SWIM)) // или плывет
    || (C_BodyStateContains(self,BS_DIVE)) // или ныряет
    || (self.guild == GIL_STONEGOLEM) // или Каменный голем
    || (self.guild == GIL_ICEGOLEM) // или Ледяной голем
    || (self.guild == GIL_FIREGOLEM) // или Огненный голем
    || (self.guild == GIL_SUMMONED_GOLEM) // или Вызванный голем
    || (self.guild == GIL_DEMON) // или Демон
    || (self.guild == GIL_SUMMONED_DEMON) // или Вызванный демон
    || (self.guild == GIL_TROLL) // или Троль
    || (self.guild == GIL_SUMMONED_GOLEM) // повтор (убрать!)
    || (self.guild == GIL_DRAGON) // или Дракон
    || (self.guild == GIL_STONEGUARDIAN) // или Каменный страж
    {
    return COLL_DONOTHING;
    };
    return COLL_APPLYDAMAGE | COLL_DONTKILL;
    };
    // если заклинание "Кулак воды"
    if(spellType == SPL_Waterfist)
    {
    // если НПС обездвижен или плывет или ныряет
    if(C_NpcIsDown(self)) || (C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE))
    {
    return COLL_DONOTHING;
    };
    // если НПС Дракон или Троль
    if(self.guild == GIL_DRAGON) || (self.guild == GIL_TROLL)
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    // если НПС Огненный голем или Огненная ящерица или Огненный дух мракориса
    if(self.guild == GIL_FIREGOLEM) || (self.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN) || (self.guild == GIL_GARGOYLE)
    {
    return COLL_APPLYDOUBLEDAMAGE;
    };
    return COLL_APPLYDAMAGE | COLL_DONTKILL;
    };
    // если заклинание "Шар энергии"
    if(spellType == SPL_EnergyBall)
    {
    // если НПС обездвижен или плывет или ныряет
    if(C_NpcIsDown(self)) || (C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE))
    {
    return COLL_DONOTHING;
    };
    // если НПС нежить
    if(C_NpcIsUndead(self))
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание "Украсть энергию"
    if(spellType == SPL_SuckEnergy)
    {
    // если НПС обездвижен или
    if (C_NpcIsDown(self))
    || (C_BodyStateContains(self,BS_SWIM)) // плывет
    || (C_BodyStateContains(self,BS_DIVE)) // или ныряет
    || (self.guild > GIL_SEPERATOR_HUM) // или монстр
    || (self.flags == NPC_FLAG_IMMORTAL) // или неубиваем
    || (Npc_GetDistToNpc(self,other) > 1000) // или расстояние между НПС > 10м
    || (self.guild == GIL_DMT) // или Черный маг
    {
    return COLL_DONOTHING;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание "Зеленые щупальца"
    if(spellType == SPL_GreenTentacle)
    {
    // если НПС обездвижен или
    if (C_NpcIsDown(self))
    || (C_BodyStateContains(self,BS_SWIM)) // плывет
    || (C_BodyStateContains(self,BS_DIVE)) // или ныряет
    || (C_NpcIsGateGuard(self)== TRUE) // или охраняет ворота
    || (self.guild == GIL_BLOODFLY) // или Кровяной шершень
    || (self.guild == GIL_DEMON) // или Демон
    || (self.guild == GIL_TROLL) // или Троль
    || (self.guild == GIL_DRAGON) // или Дракон
    || (self.guild == GIL_HARPY) // или Гарпия
    || (self.aivar[AIV_MM_REAL_ID] == ID_SKELETON_MAGE) // или Маг скелетов
    || (self.guild == GIL_Gargoyle) // или Огненный дух мракориса
    {
    return COLL_DONOTHING;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание "Рой"
    if(spellType == SPL_Swarm)
    {
    // если НПС обездвижен или
    if (C_NpcIsDown(self))
    || (C_BodyStateContains(self,BS_SWIM)) // плывет
    || (C_BodyStateContains(self,BS_DIVE)) // или ныряет
    || (self.guild == GIL_STONEGOLEM) // или Каменный голем
    || (self.guild == GIL_ICEGOLEM) // или Ледяной голем
    || (self.guild == GIL_FIREGOLEM) // или Огненный голем
    || (self.guild == GIL_SUMMONED_GOLEM) // или Вызванный голем
    || (self.guild == GIL_DEMON) // или Демон
    || (self.guild == GIL_SUMMONED_DEMON) // или Вызванный демон
    || (self.guild == GIL_TROLL) // или Троль
    || (self.guild == GIL_BLOODFLY) // или Кровяной шершень
    || (self.guild == GIL_DRAGON) // или Дракон
    || (self.guild == GIL_Gargoyle) // или Огненный дух мракориса
    || (self.guild == GIL_DMT) // или Черный маг
    || (self.guild == GIL_STONEGUARDIAN) // или Каменный страж
    || (C_NPCIsUndead(self) == TRUE) // или нежить
    {
    return COLL_DONOTHING;
    };
    // если НПС монстр или охраняет ворота
    if(self.guild > GIL_SEPERATOR_HUM) || (C_NpcIsGateGuard(self) == TRUE)
    {
    return COLL_APPLYDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание "Крик мертвых"
    if(spellType == SPL_Skull)
    {
    // если НПС обездвижен или плывет или ныряет или нежить
    if(C_NpcIsDown(self)) || (C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE)) || (C_NpcIsUndead(self))
    {
    return COLL_DONOTHING;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание "Порыв ветра"
    if(spellType == SPL_WINDFIST)
    {
    // если расстояние между НПС > 10м
    if(Npc_GetDistToNpc(other,self) >= 1000)
    {
    return COLL_DONOTHING;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание "Молния" или "Шаровая молния" или "Стрела сотрясения"
    if(spellType == SPL_Zap) || (spellType == SPL_ChargeZap) || (spellType == SPL_Concussionbolt)
    {
    // если НПС обездвижен
    if(C_NpcIsDown(self))
    {
    return COLL_DONOTHING;
    };
    return COLL_APPLYDAMAGE | COLL_DONTKILL;
    };
    // если нападающий Черный маг
    if(other.guild == GIL_DMT)
    {
    // если заклинание "Огненный дождь" или "Шторм" или "Удар молнии"
    if(spellType == SPL_Firerain) || (spellType == SPL_Thunderstorm) || (spellType == SPL_LightningFlash)
    {
    // если НПС Черный маг
    if(self.guild == GIL_DMT)
    {
    return COLL_DONOTHING;
    }
    // если НПС ГГ
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(hero))
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    };
    // если заклинание Большая огненная буря и НПС Черный маг
    if(spellType == SPL_Firestorm) && (self.guild == GIL_DMT)
    {
    return COLL_DONOTHING;
    };
    };
    // если заклинание Большой огненный шар или
    if (spellType == SPL_ChargeFireball)
    || (spellType == SPL_InstantFireball) // или Огненный шар
    || (spellType == SPL_Firerain) // или Огненный дождь
    || (spellType == SPL_Firebolt) // или Огненная стрела
    || (spellType == SPL_Firestorm) // или Большая огненная буря
    || (spellType == SPL_Pyrokinesis) // или Малая огненная буря
    || (spellType == SPL_Deathbolt) // или Стрела смерти
    || (spellType == SPL_Deathball) // или Шар смерти
    {
    // если НПС обездвижен или плывет или ныряет
    if(C_NpcIsDown(self)) || (C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE))
    {
    return COLL_DONOTHING;
    };
    // если НПС Огненный голем или
    if (self.guild == GIL_FIREGOLEM)
    || (self.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN) // Огненная ящерица
    || (self.guild == GIL_GARGOYLE) // или Огненный дух мракориса
    || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE) // или Огненный дракон
    {
    return COLL_APPLYHALVEDAMAGE;
    }
    // если НПС Ледяной голем или
    if (self.guild == GIL_ICEGOLEM)
    || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE) // Ледяной дракон
    || (self.aivar[AIV_MM_REAL_ID] == ID_ICEWOLF) // или Ледяной волк
    {
    return COLL_APPLYDOUBLEDAMAGE;
    };
    // если НПС Каменный голем или
    if (self.guild == GIL_STONEGOLEM)
    || (self.guild == GIL_SUMMONED_GOLEM) // Вызванный голем
    || (self.guild == GIL_DEMON) // или Демон
    || (self.guild == GIL_SUMMONED_DEMON) // или Вызванный демон
    || (self.guild == GIL_TROLL) // или Троль
    || (self.guild == GIL_DRAGON) // или Дракон
    {
    return COLL_APPLYDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание Ледяная глыба или Ледяная волна или Ледяная стрела
    if(spellType == SPL_IceCube) || (spellTYpe == SPL_IceWave) || (spelltype == SPL_Icebolt)
    {
    // если НПС обездвижен или плывет или ныряет
    if(C_NpcIsDown(self)) || (C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE))
    {
    return COLL_DONOTHING;
    };
    // если НПС Огненный голем или
    if (self.guild == GIL_FIREGOLEM)
    || (self.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN) // Огненная ящерица
    || (self.guild == GIL_GARGOYLE) // или Огненный дух мракориса
    || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE) // или Огненный дракон
    {
    return COLL_APPLYDOUBLEDAMAGE;
    };
    // если НПС Ледяной голем или
    if (self.guild == GIL_ICEGOLEM)
    || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE) // Ледяной дракон
    || (self.aivar[AIV_MM_REAL_ID] == ID_ICEWOLF) // или Ледяной волк
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    // если НПС Каменный голем или
    if (self.guild == GIL_STONEGOLEM)
    || (self.guild == GIL_SUMMONED_GOLEM) // Вызванный голем
    || (self.guild == GIL_DEMON) // или Демон
    || (self.guild == GIL_SUMMONED_DEMON) // или Вызванный демон
    || (self.guild == GIL_TROLL) // или Троль
    || (self.guild == GIL_DRAGON) // или Дракон
    {
    return COLL_APPLYDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание Удар молнии
    if (spellType == SPL_LightningFlash)
    {
    // если НПС обездвижен
    if(C_NpcIsDown(self))
    {
    return COLL_DONOTHING;
    };
    // если НПС плывет или ныряет
    if(C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE))
    {
    COLL_APPLYDOUBLEDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание Страх
    if(spellType == SPL_Fear)
    {
    // если НПС не Огненный голем и
    if (self.guild != GIL_FIREGOLEM)
    && (self.guild != GIL_ICEGOLEM) // не Ледяной голем
    && (self.guild != GIL_STONEGOLEM) // и не Каменный голем
    && (self.guild != GIL_SUMMONED_GOLEM) // и не Вызванный голем
    && (self.guild != GIL_SWAMPSHARK) // и не Болотный голем
    && (self.guild != GIL_TROLL) // и не Троль
    && (!C_NpcIsEvil(self)) // и не источник зла
    && (C_NpcIsGateGuard(self) == FALSE) // и не охранник ворот
    {
    return COLL_DOEVERYTHING;
    };
    return COLL_DONOTHING;
    };
    // если заклинание Уничтожить нежить
    if(spellType == SPL_DestroyUndead)
    {
    // если НПС нежить и жизнь НПС <= урону заклинания
    if(C_NpcIsUndead(self)) && (self.attribute[ATR_HITPOINTS_MAX] <= SPL_Damage_DESTROYUNDEAD)
    {
    return COLL_DOEVERYTHING;
    };
    return COLL_DONOTHING;
    };
    // если заклинание Дым смерти
    if(spellType == SPL_BreathOfDeath)
    {
    // если расстояние между НПС < 10м и НПС не нежить
    if(Npc_GetDistToNpc(other,self) < 1000) && (!C_NpcIsUndead(self))
    {
    // если НПС дракон или НПС не ГГ
    if(self.guild == GIL_DRAGON) || (Hlp_GetInstanceID(self) != Hlp_GetInstanceID(hero))
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    return COLL_DONOTHING;
    };
    // если заклинание Волна смерти
    if(spellType == SPL_MassDeath)
    {
    // если НПС не нежить
    if(!C_NpcIsUndead(self))
    {
    // если НПС дракон
    if(self.guild == GIL_DRAGON)
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    return COLL_DOEVERYTHING;
    };
    return COLL_DONOTHING;
    };
    // если заклинание Святой удар
    if(spellType == SPL_MasterOfDisaster)
    {
    // если НПС не обездвижен и не плывет и не ныряет и нежить
    if(!C_NpcIsDown(self)) && (!C_BodyStateContains(self,BS_SWIM)) && (!C_BodyStateContains(self,BS_DIVE)) && (C_NpcIsEvil(self))
    {
    return COLL_DOEVERYTHING;
    };
    return COLL_DONOTHING;
    };
    // если заклинание Уменьшить монстра
    if(spellType == SPL_Shrink)
    {
    // если НПС обездвижен или плывет или ныряет или дракон
    if(C_NpcIsDown(self)) || (C_BodyStateContains(self,BS_SWIM)) || (C_BodyStateContains(self,BS_DIVE)) || (self.guild == GIL_DRAGON)
    {
    return COLL_DONOTHING;
    };
    return COLL_DOEVERYTHING;
    };
    // если заклинание Святая стрела
    if(spellType == SPL_PalHolyBolt)
    {
    // если НПС источник зла
    if(C_NpcIsEvil(self))
    {
    return COLL_DOEVERYTHING;
    };
    return COLL_DONOTHING;
    }
    // если заклинание Разогнать дьяволов
    else if(spellType == SPL_PalRepelEvil)
    {
    // если НПС источник зла
    if(C_NpcIsEvil(self))
    {
    // если жизнь НПС <= ущербу заклинания
    if(self.attribute[ATR_HITPOINTS_MAX] <= SPL_Damage_PalRepelEvil)
    {
    return COLL_DOEVERYTHING;
    }
    else
    {
    return COLL_APPLYHALVEDAMAGE;
    };
    };
    return COLL_DONOTHING;
    }
    // если заклинание Уничтожить дьяволов
    else if(spellType == SPL_PalDestroyEvil)
    {
    // если НПС источник зла и жизнь НПС <= ущербу заклинания
    if(C_NpcIsEvil(self)) && (self.attribute[ATR_HITPOINTS_MAX] <= SPL_Damage_PalDestroyEvil)
    {
    return COLL_DOEVERYTHING;
    };
    return COLL_DONOTHING;
    };
    return COLL_DOEVERYTHING;
    };




    //**************************************************************
    //****************
    // Управление процессом инвестирования маны для всех заклинаний
    //------------------------------------------------------------------------------
    // Данная функция вызывается только экзешником
    // self - кастующий НПС (агрессор)
    // other - НПС цель
    //******************************************************************************
    //=============================================================
    // Аргументы:
    //-------------------------------------------------------------
    // manaInvested - кол-во инвестируемой маны
    // -------------------------------------------------------------
    // Возвращаемое значение:
    // Одна из констант, управляющая процессом инвестирования маны.
    // =============================================================


    Открыть спойлер
    func int Spell_ProcessMana(var int manaInvested)
    {
    var int activeSpell;
    // получить активное заклинание агрессора
    activeSpell = Npc_GetActiveSpell(self);
    // В зависимости от заклинания вызывается соответствующая функция, управляющая инвестированием маны
    if(activeSpell == SPL_PalLight ) { return Spell_Logic_PalLight (manaInvested); };
    if(activeSpell == SPL_PalLightHeal ) { return Spell_Logic_PalLightHeal (manaInvested); };
    if(activeSpell == SPL_PalHolyBolt ) { return Spell_Logic_PalHolyBolt (manaInvested); };
    if(activeSpell == SPL_PalMediumHeal ) { return Spell_Logic_PalMediumHeal (manaInvested); };
    if(activeSpell == SPL_PalRepelEvil ) { return Spell_Logic_PalRepelEvil (manaInvested); };
    if(activeSpell == SPL_PalFullHeal ) { return Spell_Logic_PalFullHeal (manaInvested); };
    if(activeSpell == SPL_PalDestroyEvil ) { return Spell_Logic_PalDestroyEvil (manaInvested); };
    if(activeSpell == SPL_PalTeleportSecret ) { return Spell_Logic_PalTeleportSecret(manaInvested); };
    if(activeSpell == SPL_TeleportSeaport ) { return Spell_Logic_TeleportSeaport (manaInvested); };
    if(activeSpell == SPL_TeleportMonastery ) { return Spell_Logic_TeleportMonastery(manaInvested); };
    if(activeSpell == SPL_TeleportFarm ) { return Spell_Logic_TeleportFarm (manaInvested); };
    if(activeSpell == SPL_TeleportXardas ) { return Spell_Logic_TeleportXardas (manaInvested); };
    if(activeSpell == SPL_TeleportPassNW ) { return Spell_Logic_TeleportPassNW (manaInvested); };
    if(activeSpell == SPL_TeleportPassOW ) { return Spell_Logic_TeleportPassOW (manaInvested); };
    if(activeSpell == SPL_TeleportOC ) { return Spell_Logic_TeleportOC (manaInvested); };
    if(activeSpell == SPL_TeleportOWDemonTower) { return Spell_Logic_TeleportOWDemonTower(manaInvested); };
    if(activeSpell == SPL_TeleportTaverne ) { return Spell_Logic_TeleportTaverne (manaInvested); };
    if(activeSpell == SPL_LIGHT ) { return Spell_Logic_Light (manaInvested); };
    if(activeSpell == SPL_Firebolt ) { return Spell_Logic_Firebolt (manaInvested); };
    if(activeSpell == SPL_Icebolt ) { return Spell_Logic_Icebolt (manaInvested); };
    if(activeSpell == SPL_Zap ) { return Spell_Logic_Zap (manaInvested); };
    if(activeSpell == SPL_LightHeal ) { return Spell_Logic_LightHeal (manaInvested); };
    if(activeSpell == SPL_SummonGoblinSkeleton) { return Spell_Logic_SummonGoblinSkeleton(manaInvested); };
    if(activeSpell == SPL_InstantFireball ) { return Spell_Logic_InstantFireball (manaInvested); };
    if(activeSpell == SPL_SummonWolf ) { return Spell_Logic_SummonWolf (manaInvested); };
    if(activeSpell == SPL_WINDFIST ) { return Spell_Logic_Windfist (manaInvested); };
    if(activeSpell == SPL_Sleep ) { return Spell_Logic_Sleep (manaInvested); };
    if(activeSpell == SPL_MediumHeal ) { return Spell_Logic_MediumHeal (manaInvested); };
    if(activeSpell == SPL_LightningFlash ) { return Spell_Logic_LightningFlash (manaInvested); };
    if(activeSpell == SPL_ChargeFireball ) { return Spell_Logic_ChargeFireball (manaInvested); };
    if(activeSpell == SPL_ChargeZap ) { return Spell_Logic_ChargeZap (manaInvested); };
    if(activeSpell == SPL_SummonSkeleton ) { return Spell_Logic_SummonSkeleton (manaInvested); };
    if(activeSpell == SPL_Fear ) { return Spell_Logic_Fear (manaInvested); };
    if(activeSpell == SPL_IceCube ) { return Spell_Logic_IceCube (manaInvested); };
    if(activeSpell == SPL_ChargeZap ) { return Spell_Logic_ChargeZap (manaInvested); };
    if(activeSpell == SPL_SummonGolem ) { return Spell_Logic_SummonGolem (manaInvested); };
    if(activeSpell == SPL_DestroyUndead ) { return Spell_Logic_DestroyUndead (manaInvested); };
    if(activeSpell == SPL_Pyrokinesis ) { return Spell_Logic_Pyrokinesis (manaInvested); };
    if(activeSpell == SPL_Firestorm ) { return Spell_Logic_Firestorm (manaInvested); };
    if(activeSpell == SPL_IceWave ) { return Spell_Logic_IceWave (manaInvested); };
    if(activeSpell == SPL_SummonDemon ) { return Spell_Logic_SummonDemon (manaInvested); };
    if(activeSpell == SPL_FullHeal ) { return Spell_Logic_FullHeal (manaInvested); };
    if(activeSpell == SPL_Firerain ) { return Spell_Logic_Firerain (manaInvested); };
    if(activeSpell == SPL_BreathOfDeath ) { return Spell_Logic_BreathOfDeath (manaInvested); };
    if(activeSpell == SPL_MassDeath ) { return Spell_Logic_MassDeath (manaInvested); };
    if(activeSpell == SPL_ArmyOfDarkness ) { return Spell_Logic_ArmyOfDarkness (manaInvested); };
    if(activeSpell == SPL_Shrink ) { return Spell_Logic_Shrink (manaInvested); };
    if(activeSpell == SPL_TrfSheep ) { return Spell_Logic_TrfSheep (manaInvested); };
    if(activeSpell == SPL_TrfScavenger ) { return Spell_Logic_TrfScavenger (manaInvested); };
    if(activeSpell == SPL_TrfGiantRat ) { return Spell_Logic_TrfGiantRat (manaInvested); };
    if(activeSpell == SPL_TrfGiantBug ) { return Spell_Logic_TrfGiantBug (manaInvested); };
    if(activeSpell == SPL_TrfWolf ) { return Spell_Logic_TrfWolf (manaInvested); };
    if(activeSpell == SPL_TrfWaran ) { return Spell_Logic_TrfWaran (manaInvested); };
    if(activeSpell == SPL_TrfSnapper ) { return Spell_Logic_TrfSnapper (manaInvested); };
    if(activeSpell == SPL_TrfWarg ) { return Spell_Logic_TrfWarg (manaInvested); };
    if(activeSpell == SPL_TrfFireWaran ) { return Spell_Logic_TrfFireWaran (manaInvested); };
    if(activeSpell == SPL_TrfLurker ) { return Spell_Logic_TrfLurker (manaInvested); };
    if(activeSpell == SPL_TrfShadowbeast ) { return Spell_Logic_TrfShadowbeast (manaInvested); };
    if(activeSpell == SPL_TrfDragonSnapper ) { return Spell_Logic_TrfDragonSnapper(manaInvested); };
    if(activeSpell == SPL_Charm ) { return Spell_Logic_Charm (manaInvested); };
    if(activeSpell == SPL_MasterOfDisaster ) { return Spell_Logic_MasterOfDisaster(manaInvested); };
    if(activeSpell == SPL_ConcussionBolt ) { return Spell_Logic_ConcussionBolt (manaInvested); };
    if(activeSpell == SPL_Deathbolt ) { return Spell_Logic_Deathbolt (manaInvested); };
    if(activeSpell == SPL_Deathball ) { return Spell_Logic_Deathball (manaInvested); };
    if(activeSpell == SPL_Thunderstorm ) { return Spell_Logic_Thunderstorm (manaInvested); };
    if(activeSpell == SPL_Waterfist ) { return Spell_Logic_Waterfist (manaInvested); };
    if(activeSpell == SPL_Whirlwind ) { return Spell_Logic_Whirlwind (manaInvested); };
    if(activeSpell == SPL_Geyser ) { return Spell_Logic_Geyser (manaInvested); };
    if(activeSpell == SPL_Inflate ) { return Spell_Logic_Inflate (manaInvested); };
    if(activeSpell == SPL_Icelance ) { return Spell_Logic_Icelance (manaInvested); };
    if(activeSpell == SPL_Swarm ) { return Spell_Logic_Swarm (manaInvested); };
    if(activeSpell == SPL_Greententacle ) { return Spell_Logic_Greententacle (manaInvested); };
    if(activeSpell == SPL_SummonGuardian ) { return Spell_Logic_SummonGuardian (manaInvested); };
    if(activeSpell == SPL_Energyball ) { return Spell_Logic_Energyball (manaInvested); };
    if(activeSpell == SPL_SuckEnergy ) { return Spell_Logic_SuckEnergy (manaInvested); };
    if(activeSpell == SPL_Skull ) { return Spell_Logic_Skull (manaInvested); };
    if(activeSpell == SPL_SummonZombie ) { return Spell_Logic_SummonZombie (manaInvested); };
    if(activeSpell == SPL_SummonMud ) { return Spell_Logic_SummonMud (manaInvested); };
    return SPL_SENDSTOP; // (Моя коррекция)
    };





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


    //=============================================================
    // Аргументы:
    //-------------------------------------------------------------
    // manaInvested - кол-во высвобождаемой маны
    //-------------------------------------------------------------
    // Возвращаемое значение:
    // Одна из констант, управляющая процессом инвестирования маны.
    //=============================================================


    Открыть спойлер
    func int Spell_ProcessMana_Release(var int manaInvested)
    {
    var int activeSpell;
    // получить активное заклинание агрессора
    activeSpell = Npc_GetActiveSpell(self);
    // эти заклинания при освобождении маны всегда срабатывают
    if (activeSpell == SPL_Pyrokinesis ) { return SPL_SENDCAST; };
    if (activeSpell == SPL_ChargeFireball) { return SPL_SENDCAST; };
    if (activeSpell == SPL_ChargeZap ) { return SPL_SENDCAST; };
    if (activeSpell == SPL_WINDFIST ) { return SPL_SENDCAST; };
    // все остальные заклинания завершаются без эффекта
    return SPL_SENDSTOP;
    };





    // ******************************************************************
    // Прототип всех заклинаний (значения по умолчанию)
    // ******************************************************************


    Открыть спойлер
    prototype C_Spell_Proto(c_spell)
    {
    time_per_mana = 500; // Время в мс, требуемое для инвестирования маны на один уровень - 500мс
    damage_per_level = 1; // Наносимый урон за уровень заклинания - 1 пункт
    damageType = DAM_MAGIC; // Тип повреждения - магия
    spellType = SPELL_BAD; // Категория заклинания - плохое
    canTurnDuringInvest = 1; // Возможность поворота во время инвестирования маны - есть
    canChangeTargetDuringInvest = 1; // Возможность выбора цели во время инвестирования маны - есть
    isMultiEffect = 0; // Возможность мультиэффектов заклинания - нет
    targetCollectAlgo = TARGET_COLLECT_FOCUS_FALLBACK_NONE; // Константа описания цели - цель визуальный объект в фокусе, при потере фокуса траектория устанавливается заклинанием
    targetCollectType = TARGET_TYPE_NPCS; // Тип цели заклинания - цель НПС
    targetCollectRange = 10000; // Дальность действия - 100м
    targetCollectAzi = 60; // Угол азимута - 60 градусов
    targetCollectElev = 60; // Угол тангажа - 60 градусов
    };
     
    Ur-tRall и Валера сказали Спасибо
  5. MEG@VOLT

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

    Регистрация:
    24 мар 2006
    Сообщения:
    1.566
    Благодарности:
    628
    Баллы:
    290
    16. Заклинания.

    Все файлы заклинаний расположены в директории ..\AI\Magic\Spells\
    Все заклинания мы рассматривать не будем, разберем только основные типы и принципы работы.

    Все заклинания состоят из следующих частей:
    1. Объявление самого заклинания типа instance Spell_ххх(C_Spell_Proto) с инициализацией требуемых переменных, где ххх - название заклинания.
    2. Функция, управляющая процессом инвестирования маны int Spell_Logic_ххх(var int manaInvested). Аргумент int manaInvested определяет кол-во инвестированной маны, функция возвращает одну из констант управления процессом инвестирования маны.
    3. Функция вызова самого заклинания void Spell_Cast_ххх() (вызывается только экзешником). Имя ххх должно строго соответствовать ххх при объявлении инстанции.
    // *******************************************
    // Заклинание Свет
    // *******************************************


    Открыть спойлер
    const int SPL_Cost_LIGHT = 10; // кол-во требуемой маны

    const int SPL_Duration_LIGHT = 5; // время действия заклинания в минутах

    // объявление заклинания с инициализацией
    instance Spell_Light(C_Spell_Proto)
    {
    time_per_mana = 500;
    spelltype = SPELL_NEUTRAL;
    targetCollectAlgo = TARGET_COLLECT_NONE;
    targetCollectRange = 0;
    targetCollectAzi = 0;
    targetCollectElev = 0;
    };

    // функция инвестирования маны
    func int Spell_Logic_Light(var int manaInvested)
    {
    // если активное заклинание свиток и есть требуемое кол-во маны
    if(Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll))
    {
    // старт заклинания
    return SPL_SENDCAST;
    }
    // иначе, если руна и есть требуемое кол-во маны
    else if (self.attribute[ATR_MANA] >= SPL_Cost_Light)
    {
    // старт заклинания
    return SPL_SENDCAST;
    }
    else // мало маны
    {
    // отмена заклинания
    return SPL_SENDSTOP;
    };
    };

    // вызов заклинания
    func void Spell_Cast_Light()
    {
    // если свиток
    if(Npc_GetActiveSpellIsScroll(self))
    {
    // уменьшение маны на стоимость свитков
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else // руна
    {
    // уменьшение маны на фактическую стоимость заклинания
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Light;
    };
    // изменить случайное число выбора заклинаний
    self.aivar[AIV_SelectSpell] += 1;
    };
    По такому принципу работают большинство заклинаний, это:
    SPL_PalLight //Святой свет, // файл Spell_Light_Alle.d
    SPL_PalLightHeal //Малое лечение паладина // файл Spell_Heal_Alle.d
    SPL_PalMediumHeal //Среднее лечение паладина
    SPL_PalFullHeal //Сильное лечение паладина
    SPL_LightHeal //Лечить легкое ранение
    SPL_MediumHeal //Лечить среднее ранение
    SPL_FullHeal //Лечить сильное ранение
    SPL_PalHolyBolt //Святая стрела // файл Spell_PalHolyBolt.d
    SPL_PalRepelEvil //Разогнать дьяволов // файл Spell_PalRepelEvil.d
    SPL_PalDestroyEvil //Уничтожить дьяволов // файл Spell_PalDestroyEvil.d
    SPL_Firebolt //Огненная стрела // файл Spell_FireBolt.d
    SPL_Zap //Молния // файл Spell_Zap.d
    SPL_Icebolt //Ледяная стрела // файл Spell_IceBolt.d
    SPL_InstantFireball //Огненный шар // файл Spell_InstantFireball.d
    SPL_LightningFlash //Удар молнии // файл Spell_LightningFlash.d
    SPL_IceCube //Ледяная глыба // файл Spell_IceCube.d
    SPL_DestroyUndead //Уничтожить нежить // файл Spell_DestroyUndead.d
    SPL_Firestorm //Малая огненная буря // файл Spell_Firestorm.d
    SPL_IceWave //Ледяная волна // файл Spell_IceWave.d
    SPL_Firerain //Огненный дождь // файл Spell_Firerain.d
    SPL_BreathOfDeath //Дым смерти // файл Spell_BreathOfDeath.d
    SPL_MassDeath //Волна смерти // файл Spell_MassDeath.d
    SPL_MasterOfDisaster //Святой удар // файл Spell_MasterOfDisaster.d
    SPL_Deathbolt //Стрела смерти // файл Spell_DeathBolt.d
    SPL_Deathball //Шар смерти // файл Spell_DeathBall.d
    SPL_ConcussionBolt //Стрела сотрясения // файл Spell_ConcussionBolt.d
    SPL_Thunderstorm //Шторм // файл Spell_Thunderstorm.d
    SPL_Whirlwind //Смерч // файл Spell_Whirlwind.d
    SPL_WaterFist //Кулак воды // файл Spell_WaterFist.d
    SPL_IceLance //Ледяное копье // файл Spell_IceLance.d
    SPL_Geyser //Гейзер // файл Spell_Geyser.d
    SPL_Swarm //Рой // файл Spell_Swarm.d
    SPL_GreenTentacle //Зеленые щупальца // файл Spell_GreenTentacle.d
    SPL_Energyball //Шар энергии // файл Spell_EnergyBall.d
    SPL_SuckEnergy //Украсть энергию // файл Spell_SuckEnergy.d
    SPL_Skull //Крик мертвых // файл Spell_Skull.d

    Телепортация.
    // *************************
    // Заклинания телепортации
    // *************************

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

    // стоимость заклинаний
    const int SPL_Cost_Teleport = 10;

    // Вывод сообщения о недоступности телепорта
    // -------------------------------------------------------
    // Level - уровень на котором находится телепорт прибытия

    func void B_PrintTeleportTooFarAway(var int Level)
    {
    // если телепортация на другой уровень
    if(Level != CurrentLevel)
    {
    // вывод сообщения "Слишком далеко"
    PrintScreen(PRINT_TeleportTooFarAway,-1,YPOS_LevelUp,FONT_ScreenSmall,2);
    };
    };

    // Инициализация заклинаний
    instance Spell_Teleport(C_Spell_Proto)
    {
    time_per_mana = 0;
    spelltype = SPELL_NEUTRAL;
    targetCollectAlgo = TARGET_COLLECT_CASTER;
    canTurnDuringInvest = 0;
    targetCollectRange = 0;
    targetCollectAzi = 0;
    targetCollectElev = 0;
    };

    // Функции инвестирования маны для всех заклинаний телепортации идентичны ранее рассмотренной
    func int Spell_Logic_PalTeleportSecret(var int manaInvested)
    {
    if (Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll))
    {
    return SPL_SENDCAST;
    }
    else if (self.attribute[ATR_MANA] >= SPL_Cost_Teleport)
    {
    return SPL_SENDCAST;
    };
    return SPL_NEXTLEVEL;
    };

    // Функции вызова заклинаний телепортации
    func void Spell_Cast_PalTeleportSecret()
    {
    // вывод сообщения о недоступности телепорта
    B_PrintTeleportTooFarAway(NEWWORLD_ZEN);
    if (Npc_GetActiveSpellIsScroll(self))
    {
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else
    {
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Teleport;
    };
    // телепортация в нужную точку
    AI_Teleport(self,"NW_PAL_SECRETCHAMBER");
    // анимация телепортации
    AI_PlayAni(self,"T_HEASHOOT_2_STAND" );
    };

    // Остальные функции вызова заклинаний телепортации идентичны приведенной

    // Вызов соответствующей функции телепортации в зависимости от активного заклинания
    func void Spell_Cast_Teleport()
    {
    if (Npc_GetActiveSpell(self) == SPL_PalTeleportSecret ) { Spell_Cast_PalTeleportSecret (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportSeaport ) { Spell_Cast_TeleportSeaport (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportMonastery ) { Spell_Cast_TeleportMonastery (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportFarm ) { Spell_Cast_TeleportFarm (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportXardas ) { Spell_Cast_TeleportXardas (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportPassNW ) { Spell_Cast_TeleportPassNW (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportPassOW ) { Spell_Cast_TeleportPassOW (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportOC ) { Spell_Cast_TeleportOC (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportOWDemonTower) { Spell_Cast_TeleportOWDemonTower (); };
    if (Npc_GetActiveSpell(self) == SPL_TeleportTaverne ) { Spell_Cast_TeleportTaverne (); };
    };

    Заклинания вызова монстров
    Рассмотрим их на примере вызова Волка:
    // **************
    // Вызов Волка
    // **************

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

    // стоимость заклинания
    const int SPL_Cost_SummonWolf = 40;

    // Инициализация заклинания
    instance Spell_SummonWolf(C_Spell_Proto)
    {
    time_per_mana = 0;
    targetCollectAlgo = TARGET_COLLECT_NONE;
    };

    // Функция инвестирования маны идентична ранее рассмотренным
    func int Spell_Logic_SummonWolf(var int manaInvested)
    {
    if(Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll))
    {
    return SPL_SENDCAST;
    }
    else if(self.attribute[ATR_MANA] >= SPL_Cost_SummonWolf)
    {
    return SPL_SENDCAST;
    }
    else
    {
    return SPL_SENDSTOP;
    };

    };

    // Вызов заклинания
    func void Spell_Cast_SummonWolf()
    {
    if(Npc_GetActiveSpellIsScroll(self))
    {
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else
    {
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_SummonWolf;
    };
    // если заклинание применяет ГГ
    if(Npc_IsPlayer(self))
    {
    // рождение Вызванного волка (1 штука на 5 минут)
    Wld_SpawnNpcRange(self,Summoned_Wolf,1,500);
    }
    else
    {
    // рождение Волка
    Wld_SpawnNpcRange(self,Wolf,1,500);
    };
    self.aivar[AIV_SelectSpell] += 1;
    };
    По такому принципу работают заклинания:
    SPL_SummonGoblinSkeleton //Вызвать скелет гоблина // файл Spell_SummonGoblinSkeleton.d
    SPL_SummonSkeleton //Вызвать скелет // файл Spell_SummonSkeleton.d
    SPL_SummonGolem //Вызвать голема // файл Spell_SummonGolem.d
    SPL_SummonDemon //Вызвать демона // файл Spell_SummonDemon.d
    SPL_ArmyOfDarkness //Армия мрака // файл Spell_ArmyOfDarkness.d
    SPL_SummonGuardian //Создать стража // файл Spell_SummonGuardian.d
    SPL_SummonZombie //Создать зомби // файл Spell_SummonZombie.d
    SPL_SummonMud //Вызвать Муда // файл Spell_SummonMud.d

    Заклинания, требующие несколько уровней инвестирования маны
    Рассмотрим их на примере заклинания "Порыв ветра":
    // ************************
    // Заклинание Порыв ветра
    // ************************

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

    const int SPL_Cost_WindFist = 80; // полная стоимость заклинания
    const int STEP_WindFist = 20; // стоимость одного уровня заклинания
    const int SPL_Damage_WindFist = 50; // ущерб наносимый заклинанием на уровень

    // объявление заклинания с инициализацией
    instance Spell_WindFist(C_Spell_Proto)
    {
    time_per_mana = 30;
    damage_per_level = SPL_Damage_WindFist;
    damageType = DAM_FLY;
    canTurnDuringInvest = TRUE;
    targetCollectAlgo = TARGET_COLLECT_FOCUS_FALLBACK_NONE;
    targetCollectRange = 1000;
    targetCollectType = TARGET_TYPE_NPCS;
    };

    // функция инвестирования маны
    func int Spell_Logic_WindFist(var int manaInvested)
    {
    // если недостаточно маны на уровень заклинания
    if(self.attribute[ATR_MANA] < STEP_WindFist)
    {
    // инвестирование маны невозможно
    return SPL_DONTINVEST;
    };
    // если инвестировано маны < 1 уровня
    if(manaInvested <= STEP_WindFist*1)
    {
    // установить уровень 1
    self.aivar[AIV_SpellLevel] = 1;
    // инвестированной маны недостаточно для перехода на следующий уровень
    return SPL_STATUS_CANINVEST_NO_MANADEC;
    }
    // если инвестировано маны > требуемой для 1 уровня и уровень не выше первого
    else if(manaInvested > (STEP_WindFist*1)) && (self.aivar[AIV_SpellLevel] <= 1)
    {
    // уменьшение маны на уровень
    self.attribute[ATR_MANA] = (self.attribute[ATR_MANA] - STEP_WindFist);
    // если мана < 0
    if(self.attribute[ATR_MANA] < 0)
    {
    // мана = 0
    self.attribute[ATR_MANA] = 0;
    };
    // установить уровень 2
    self.aivar[AIV_SpellLevel] = 2;
    // переход на следующий уровень
    return SPL_NEXTLEVEL;
    }
    // аналогично приведенному выше для следующих уровней заклинания
    else if(manaInvested > (STEP_WindFist*2)) && (self.aivar[AIV_SpellLevel] <= 2)
    {
    self.attribute[ATR_MANA] = (self.attribute[ATR_MANA] - STEP_WindFist);
    if(self.attribute[ATR_MANA] < 0)
    {
    self.attribute[ATR_MANA] = 0;
    };
    self.aivar[AIV_SpellLevel] = 3;
    return SPL_NEXTLEVEL;
    }
    else if(manaInvested > (STEP_WindFist*3)) && (self.aivar[AIV_SpellLevel] <= 3)
    {
    self.attribute[ATR_MANA] = (self.attribute[ATR_MANA] - STEP_WindFist);
    if(self.attribute[ATR_MANA] < 0)
    {
    self.attribute[ATR_MANA] = 0;
    };
    self.aivar[AIV_SpellLevel] = 4;
    return SPL_NEXTLEVEL;
    }
    // если достигнут последний уровень
    else if(manaInvested > (STEP_WindFist*3)) && (self.aivar[AIV_SpellLevel] == 4)
    {
    // дальнейшее инвестирование маны невозможно
    return SPL_DONTINVEST;
    };
    // инвестированной маны недостаточно для перехода на следующий уровень
    return SPL_STATUS_CANINVEST_NO_MANADEC;
    };

    // вызов заклинания
    // где spellLevel - достигнутый уровень заклинания

    func void Spell_Cast_WindFist(var int spellLevel)
    {
    // уменьшение маны для последнего уровня
    self.attribute[ATR_MANA] = (self.attribute[ATR_MANA] - STEP_WindFist);
    if(self.attribute[ATR_MANA] < 0)
    {
    self.attribute[ATR_MANA] = 0;
    };
    // изменить случайное число выбора заклинаний
    self.aivar[AIV_SelectSpell] += 1;
    };
    По такому принципу работают следующие заклинания:
    SPL_ChargeFireball //Большой огненный шар // файл Spell_ChargeFireball.d
    SPL_ChargeZap //Шаровая молния // файл Spell_ChargeZap.d
    SPL_Pyrokinesis //Большая огненная буря // файл Spell_Pyrokinesis.d

    Трансформация
    // **************************
    // Заклинания трансформации
    // **************************

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

    // стоимости заклинаний
    const int SPL_Cost_TrfSheep = 10;
    const int SPL_Cost_TrfScavenger = 10;
    const int SPL_Cost_TrfGiantRat = 10;
    const int SPL_Cost_TrfGiantBug = 10;
    const int SPL_Cost_TrfWolf = 10;
    const int SPL_Cost_TrfWaran = 10;
    const int SPL_Cost_TrfSnapper = 10;
    const int SPL_Cost_TrfWarg = 10;
    const int SPL_Cost_TrfFireWaran = 10;
    const int SPL_Cost_TrfLurker = 10;
    const int SPL_Cost_TrfShadowbeast = 10;
    const int SPL_Cost_TrfDragonSnapper = 10;

    // общая инициализация для всех заклинаний
    instance Spell_Transform(C_Spell_Proto)
    {
    time_per_mana = 0;
    spelltype = SPELL_NEUTRAL;
    targetCollectAlgo = TARGET_COLLECT_NONE;
    canTurnDuringInvest = 0;
    };

    // Функции инвестирования маны у всех заклинаний трансформации практически одинаковы, рассмотрим одну их них
    func int Spell_Logic_TrfSheep(var int manaInvested)
    {
    // если заклинание свиток и маны достаточно для свитка или маны достаточно для руны
    if((Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll)))
    || (self.attribute[ATR_MANA] >= SPL_Cost_TrfSheep)
    {
    // уменьшить ману на стоимость заклинания для руны
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_TrfSheep;
    // ссылка на объявление (инстанцию) зверюшки, в которую превращаемся
    Npc_SetActiveSpellInfo(self,Sheep);
    // старт заклинания
    return SPL_SENDCAST;
    }
    else
    {
    // заклинание невозможно
    return SPL_SENDSTOP;
    };
    };

    Прочие заклинания
    // ****************
    // Заклинание Сон
    // ****************

    Открыть спойлер
    // self - кастующий НПС
    // other - НПС цель


    const int SPL_Cost_Sleep = 30; // стоимость маны
    const int SPL_TIME_Sleep = 30; // время сна в сек

    // Инициализация заклинания
    instance Spell_Sleep(C_Spell_Proto)
    {
    time_per_mana = 0;
    spelltype = SPELL_NEUTRAL;
    targetCollectAlgo = TARGET_COLLECT_FOCUS;
    };

    // Функция инвестирования маны
    func int Spell_Logic_Sleep(var int manaInvested)
    {
    // если заклинание свиток и маны достаточно для свитка или маны достаточно для руны
    if((Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll)))
    || (self.attribute[ATR_MANA] >= SPL_Cost_Sleep)
    {
    // если свиток
    if(Npc_GetActiveSpellIsScroll(self))
    {
    // израсходовать ману
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else // руна
    {
    // израсходовать ману
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Sleep;
    };
    // если цель не плывет и не ныряет и не обездвижена и
    if (!C_BodyStateContains(other,BS_SWIM)) && (!C_BodyStateContains(other,BS_DIVE)) && (!C_NpcIsDown(other))
    && (other.guild < GIL_SEPERATOR_HUM) // человек
    && (other.flags != NPC_FLAG_IMMORTAL) // и уязвима
    && (Npc_GetDistToNpc(self,other) <= 1000) // и расстояние между кастующим и целью < 10м
    && (other.guild != GIL_KDF) // и цель не Маг огня
    && (other.guild != GIL_DMT) // и не Черный маг
    && (other.guild != GIL_PAL) // и не Паладин
    {
    // очистить очередь AI состояний цели
    Npc_ClearAIQueue(other);
    // очистить восприятия цели
    B_ClearPerceptions(other);
    // перевести цель в состояние Магического сна
    AI_StartState(other,ZS_MagicSleep,0,"");
    };
    return SPL_SENDCAST;
    }
    else
    {
    return SPL_SENDSTOP;
    };
    };

    // Вызов заклинания
    func void Spell_Cast_Sleep()
    {
    // изменить случайное число выбора заклинаний
    self.aivar[AIV_SelectSpell] += 1;
    };





    // *****************************
    // Заклинание Уменьшить монстра
    // *****************************

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

    const int SPL_Cost_Shrink = 300; // стоимость маны

    // Инициализация заклинания
    instance Spell_Shrink(C_Spell_Proto)
    {
    time_per_mana = 0;
    spelltype = SPELL_NEUTRAL;
    targetCollectAlgo = TARGET_COLLECT_FOCUS;
    targetCollectRange = 1000;
    };

    // Функция инвестирования маны (аналогична ранее рассмотренным)
    func int Spell_Logic_Shrink(var int manaInvested)
    {
    if(Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll))
    {
    return SPL_SENDCAST;
    }
    else if(self.attribute[ATR_MANA] >= SPL_Cost_Shrink)
    {
    return SPL_SENDCAST;
    }
    else
    {
    return SPL_SENDSTOP;
    };
    };

    // Вызов заклинания
    func void Spell_Cast_Shrink()
    {
    // если свиток
    if(Npc_GetActiveSpellIsScroll(self))
    {
    // израсходовать ману для свитка
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else
    {
    // израсходовать ману для руны
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Shrink;
    };
    // если цель уязвима и не обездвижена и монстр и не уменьшена
    if(other.flags != NPC_FLAG_IMMORTAL) && (!C_NpcIsUndead(other)) && (other.guild > GIL_SEPERATOR_HUM) && (other.aivar[AIV_MM_ShrinkState] == 0)
    {
    // очистить очередь AI состояний цели
    Npc_ClearAIQueue(other);
    // очистить восприятия цели
    B_ClearPerceptions(other);
    // перевести цель в состояние уменьшения
    AI_StartState(other,ZS_MagicShrink,0,"");
    };
    // изменить случайное число выбора заклинаний
    self.aivar[AIV_SelectSpell] += 1;
    };





    // *******************
    // Заклинание Раздуть
    // *******************

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

    const int SPL_Cost_Inflate = 10; // стоимость маны
    const int SPL_Inflate_Damage = 5; // ущерб от заклинания
    const int SPL_TIME_Inflate = 19; // время действия 19 сек

    // Инициализация заклинания
    instance Spell_Inflate(C_Spell_Proto)
    {
    time_per_mana = 0;
    targetCollectAlgo = TARGET_COLLECT_FOCUS;
    };

    // Функция инвестирования маны
    func int Spell_Logic_Inflate(var int manaInvested)
    {
    // если заклинание свиток и маны достаточно для свитка или маны достаточно для руны
    if ((Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll)))
    || (self.attribute[ATR_MANA] >= SPL_Cost_Inflate)
    {
    // если свиток
    if(Npc_GetActiveSpellIsScroll(self))
    {
    // израсходовать ману для свитка
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else
    {
    // израсходовать ману для руны
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Inflate;
    };
    // если цель не плывет и не ныряет и не обездвижена и
    if(!C_BodyStateContains(other,BS_SWIM)) && (!C_BodyStateContains(other,BS_DIVE)) && (!C_NpcIsDown(other))
    && (other.guild < GIL_SEPERATOR_HUM) // человек
    && (other.flags != NPC_FLAG_IMMORTAL) // и уязвима
    && (Npc_GetDistToNpc(self,other) <= 1000) // и расстояние между кастующим и целью < 10м
    && (other.guild != GIL_KDF) // и цель не Маг огня
    && (other.guild != GIL_DMT) // и не Черный маг
    && (other.guild != GIL_PAL) // и не Паладин
    {
    // очистить очередь AI состояний цели
    Npc_ClearAIQueue(other);
    // очистить восприятия цели
    B_ClearPerceptions(other);
    // перевести цель в состояние Раздутия
    AI_StartState(other,ZS_Inflate,0,"");
    };
    return SPL_SENDCAST;
    }
    else
    {
    return SPL_SENDSTOP;
    };
    };

    // Вызов заклинания
    func void Spell_Cast_Inflate()
    {
    // изменить случайное число выбора заклинаний
    self.aivar[AIV_SelectSpell] += 1;
    };





    // ******************
    // Заклинание Страх
    // ******************

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

    const int SPL_Cost_Fear = 50; // стоимость маны
    const int SPL_TIME_Fear = 5; // время действия 5 сек

    // Инициализация заклинания
    instance Spell_Fear(C_Spell_Proto)
    {
    time_per_mana = 0;
    damage_per_level = 0;
    targetCollectAlgo = TARGET_COLLECT_NONE;
    };

    // Функция инвестирования маны (аналогична рассмотренным)
    func int Spell_Logic_Fear(var int manaInvested)
    {
    if(Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll))
    {
    return SPL_SENDCAST;
    }
    else if(self.attribute[ATR_MANA] >= SPL_Cost_Fear)
    {
    return SPL_SENDCAST;
    }
    else
    {
    return SPL_SENDSTOP;
    };
    };

    // Вызов заклинания
    func void Spell_Cast_Fear()
    {
    // если цель не Дракон
    if(other.guild != GIL_DRAGON)
    {
    // перевести всех НПС, находящихся на расстоянии 10м от кастующего, в состояние страха
    AI_SetNpcsToState(self,ZS_MagicFlee,1000);
    };
    // израсходовать ману (аналогично рассмотренным заклинаниям)
    if(Npc_GetActiveSpellIsScroll(self))
    {
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else
    {
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Fear;
    };
    self.aivar[AIV_SelectSpell] += 1;
    };





    // ******************
    // Заклинание Забыть
    // ******************

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

    const int SPL_Cost_Charm = 50; // стоимость маны
    const int SPL_Damage_Charm = 0; // причиняемый ущерб

    // Инициализация заклинания
    instance Spell_Charm(C_Spell_Proto)
    {
    time_per_mana = 0;
    spelltype = SPELL_NEUTRAL;
    damage_per_level = SPL_Damage_Charm;
    damageType = DAM_MAGIC;
    };

    // Функция инвестирования маны
    func int Spell_Logic_Charm(var int manaInvested)
    {
    // если заклинание свиток и маны достаточно для свитка или маны достаточно для руны
    if ((Npc_GetActiveSpellIsScroll(self) && (self.attribute[ATR_MANA] >= SPL_Cost_Scroll)))
    || (self.attribute[ATR_MANA] >= SPL_Cost_Charm)
    {
    // если НПС цель видел криминал ГГ и квест Игназа в стадии выполнения
    if(other.aivar[AIV_NpcSawPlayerCommit] != CRIME_NONE) && (MIS_Ignaz_Charm == LOG_RUNNING)
    {
    // тест заклинания проведен
    Charm_Test = TRUE;
    };
    // удалить криминал ГГ для соответствующей локации
    B_DeletePetzCrime(other);
    // очистить что цель видела криминал
    other.aivar[AIV_NpcSawPlayerCommit] = CRIME_NONE;
    // последнего сражения с ГГ не было
    other.aivar[AIV_LastFightAgainstPlayer] = FIGHT_NONE;
    // если гильдии цели и кастующего не враги
    if(Wld_GetGuildAttitude(other.guild,self.guild) != ATT_HOSTILE)
    {
    // если отношение цели и кастующего враждебно
    if(Npc_GetAttitude(other,self) == ATT_HOSTILE)
    {
    // установить отношение цели к кастующему равное отношению их гильдий
    Npc_SetTempAttitude(other,Wld_GetGuildAttitude(other.guild,self.guild));

    };
    };
    return SPL_SENDCAST;
    }
    else
    {
    return SPL_SENDSTOP;
    };
    };

    // Вызов заклинания (идентичен ранее рассмотренным)
    func void Spell_Cast_Charm()
    {
    if(Npc_GetActiveSpellIsScroll(self))
    {
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Scroll;
    }
    else
    {
    self.attribute[ATR_MANA] = self.attribute[ATR_MANA] - SPL_Cost_Charm;
    };
    self.aivar[AIV_SelectSpell] += 1;
    };
     
    Ur-tRall и Валера сказали Спасибо
  6. MEG@VOLT

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

    Регистрация:
    24 мар 2006
    Сообщения:
    1.566
    Благодарности:
    628
    Баллы:
    290
    17. Обработчики состояний заклинаний.

    Все обработчики расположены в директории скриптов ..\AI\Magic\ZS_Magic в одноименных файлах.
    //****************************************************
    // Обработчик состояния заклинания Зеленые щупальца
    //****************************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // ----------------------------------------------------


    // Функция реакции на локальное восприятие магии (заклинания)
    func void B_RestartGreententacle()
    {
    // если последнее примененное заклинание Зеленые щупальца
    if(Npc_GetLastHitSpellID(self) == SPL_Greententacle)
    {
    // сбросить время нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    };
    };

    // Закончить действие заклинания
    func void B_StopGreententacle()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если НПС человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    };
    };

    // Инициализация состояния
    func void ZS_Greententacle()
    {
    // установить локальное восприятие на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_RestartGreententacle);
    // разрешить восприятие повреждения
    Npc_PercEnable(self,PERC_ASSESSDAMAGE,B_AssessDamage);
    // остановить проигрывание файлов анимации заклинания
    Npc_StopAni(self,"s_GreententacleA_Victim");
    Npc_StopAni(self,"s_GreententacleB_Victim");
    Npc_StopAni(self,"s_GreententacleC_Victim");
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp (self);
    // если НПС находится не в бессознательном состоянии
    if(!C_BodyStateContains(self,BS_UNCONSCIOUS))
    {
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    var int randy;
    //randy = Hlp_Random(3);
    // проигрывается анимация бессознательного состояния (Примечание: т.к. предыдущая строка в скрипте закрыта, то randy всегда имеет значение 0)
    if(randy == 0) { AI_PlayAniBS(self,"T_STAND_2_GREENTENTACLEA_VICTIM",BS_UNCONSCIOUS); };
    if(randy == 1) { AI_PlayAniBS(self,"T_STAND_2_GREENTENTACLEB_VICTIM",BS_UNCONSCIOUS); };
    if(randy == 2) { AI_PlayAniBS(self,"T_STAND_2_GREENTENTACLEC_VICTIM",BS_UNCONSCIOUS); };
    }
    else
    {
    // анимация бессознательного состояния
    AI_PlayAniBS(self,"T_STAND_2_FREEZE_VICTIM",BS_UNCONSCIOUS);
    };
    };
    };

    // Функция цикла состояния
    func int ZS_Greententacle_Loop ()
    {
    // если время в состоянии > времени действия заклинания
    if(Npc_GetStateTime(self) > SPL_TIME_Greententacle)
    {
    // остановить действие заклинания
    B_StopGreententacle();
    return LOOP_END;
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_GreenTentacle_End()
    {
    }
    ;





    // ****************************************
    // Обработчик состояния заклинания Раздуть
    // ****************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Функция реакции на локальное восприятие магии (заклинания)
    func void B_RestartInflate()
    {
    // если последнее примененное заклинание Раздуть
    if(Npc_GetLastHitSpellID(self) == SPL_Inflate)
    {
    // сбросить время нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    };
    };

    // Закончить действие заклинания
    func void B_StopInflate()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    };
    };

    // Инициализация состояния
    func void ZS_Inflate()
    {
    // установить локальное восприятие на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_RestartInflate);
    // остановить проигрывание файла анимации заклинания
    Npc_StopAni(self,"S_INFLATE_VICTIM");
    // если НПС находится не в бессознательном состоянии
    if(!C_BodyStateContains(self,BS_UNCONSCIOUS))
    {
    // анимация бессознательного состояния
    AI_PlayAniBS(self,"T_STAND_2_INFLATE_VICTIM",BS_UNCONSCIOUS);
    };
    // сброс времени цикла
    self.aivar[AIV_InflateStateTime] = 0;
    };

    // Функция цикла состояния
    func int ZS_Inflate_Loop ()
    {
    // если время в состоянии > времени действия заклинания
    if(Npc_GetStateTime(self) > SPL_TIME_Inflate)
    {
    // остановить действие заклинания
    B_StopInflate();
    return LOOP_END;
    };
    // если текущее время состояния не равно времени цикла
    if(Npc_GetStateTime(self) != self.aivar[AIV_InflateStateTime])
    {
    // в зависимости от времени состояния установить жирность (объем) фигуры жертвы
    // как видим по коэффициентам объема сначала идет раздутие фигуры, а затем возвращение к нормальному состоянию
    if(Npc_GetStateTime(self) == 1) { Mdl_SetModelFatness(self,1); }
    else if(Npc_GetStateTime(self) == 2) { Mdl_SetModelFatness(self,3); }
    else if(Npc_GetStateTime(self) == 3) { Mdl_SetModelFatness(self,8 ); }
    else if(Npc_GetStateTime(self) == 4) { Mdl_SetModelFatness(self,12); }
    else if(Npc_GetStateTime(self) == 5)
    {
    Mdl_SetModelFatness(self,9);
    // жертва говорит агрессору (SVM фраза) "Ууух!"
    B_Say(self,other,"$Aargh_1");
    }
    else if(Npc_GetStateTime(self) == 6) { Mdl_SetModelFatness (self,15); }
    else if(Npc_GetStateTime(self) == 7) { Mdl_SetModelFatness (self,18 ); }
    else if(Npc_GetStateTime(self) == 8 )
    {
    Mdl_SetModelFatness(self,11);
    // жертва говорит агрессору (SVM фраза) "Ууух!"
    B_Say (self, other, "$Aargh_2");
    }
    else if(Npc_GetStateTime(self) == 9) { Mdl_SetModelFatness(self,15); }
    else if(Npc_GetStateTime(self) == 10) { Mdl_SetModelFatness(self,13); }
    else if(Npc_GetStateTime(self) == 11) { Mdl_SetModelFatness(self,12); }
    else if(Npc_GetStateTime(self) == 12) { Mdl_SetModelFatness(self,10); }
    else if(Npc_GetStateTime(self) == 13) { Mdl_SetModelFatness(self,8 ); }
    else if(Npc_GetStateTime(self) == 14)
    {
    Mdl_SetModelFatness(self,5);
    // жертва говорит агрессору (SVM фраза) "Ууух!"
    B_Say(self,other,"$Aargh_3");
    }
    else if(Npc_GetStateTime(self) == 15) { Mdl_SetModelFatness(self,6); }
    else if(Npc_GetStateTime(self) == 16) { Mdl_SetModelFatness(self,4); }
    else if(Npc_GetStateTime(self) == 17) { Mdl_SetModelFatness(self,2); }
    else if(Npc_GetStateTime(self) == 18 ) { Mdl_SetModelFatness(self,1); }
    else if(Npc_GetStateTime(self) == 19) { Mdl_SetModelFatness(self,1); };
    // установить время уикла на текущее время
    self.aivar[AIV_InflateStateTime] = Npc_GetStateTime(self);
    // если жизнь жертвы > ущерба заклинания
    if(self.attribute[ATR_HITPOINTS] > SPL_Inflate_DAMAGE)
    {
    // нанести ужерб жертве
    B_MagicHurtNpc(other,self,SPL_Inflate_DAMAGE);
    }
    else
    {
    // нанести полный ужерб жертве (смерть)
    B_MagicHurtNpc(other,self,self.attribute[ATR_HITPOINTS] - 1);
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Inflate_End()
    {
    }
    ;





    // ***********************************************************
    // Обработчик состояния магического горения
    // -----------------------------------------------------------

    Открыть спойлер
    // В это состояние НПС переводится экзешником, а не скриптами
    // ***********************************************************


    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    const int SPL_MAGICBURN_DAMAGE_PER_SEC = 1; // ущерб в сек от заклинания

    // Закончить действие заклинания
    func void B_StopMagicBurn()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    // продолжить распорядок дня НПС (т.к. не было принудительного перевода НПС в это состояние из скриптов и завершение этого состояния выполняется не из цикла состояния)
    AI_ContinueRoutine(self);
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    // продолжить распорядок дня НПС
    AI_ContinueRoutine(self);
    };
    };

    // Функция реакции на локальное восприятие магии (заклинания)
    func void B_RestartBurn()
    {
    // если последнее примененное заклинание
    if (Npc_GetLastHitSpellID(self) == SPL_Firerain) // Огненный дождь
    || (Npc_GetLastHitSpellID(self) == SPL_ChargeFireball) // или Большой огненный шар
    || (Npc_GetLastHitSpellID(self) == SPL_InstantFireball) // или Огненный шар
    || (Npc_GetLastHitSpellID(self) == SPL_Firebolt) // или Огненная стрела
    {
    // сбросить время нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    return;
    };
    // если последнее примененное заклинание
    if (Npc_GetLastHitSpellID(self) == SPL_IceWave) // Ледяная волна
    || (Npc_GetLastHitSpellID(self) == SPL_IceCube) // или Ледяная глыба
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // очистить восприятия
    B_ClearPerceptions(self);
    // перевести жертву в состояние Магической заморозки
    AI_StartState(self,ZS_MagicFreeze,0,"");
    };
    };

    // Инициализация состояния
    func void ZS_MagicBurn()
    {
    // установить восприятие прекращения действия магии
    Npc_PercEnable(self,PERC_ASSESSSTOPMAGIC,B_StopMagicBurn);
    // если состояние тела НПС не прерываемо
    if(!Npc_HasBodyFlag(self,BS_FLAG_INTERRUPTABLE))
    {
    // НПС встает
    AI_StandUp(self);
    }
    else
    {
    // НПС быстро встает
    AI_StandUpQuick(self);
    };
    };

    // Функция цикла состояния
    func int ZS_MagicBurn_Loop()
    {
    // разрешить локальное восприятие на воздействие магии
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_RestartBurn);
    // если прошла 1 секунда
    if(Npc_GetStateTime(self) == 1)
    {
    // сбросить время состояния
    Npc_SetStateTime(self,0);
    // нанести жертве секундный урон
    B_MagicHurtNpc(other,self,SPL_MAGICBURN_DAMAGE_PER_SEC);
    };
    // если жизнь жертвы кончилась
    if(self.attribute[ATR_HITPOINTS] <= 0)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    return LOOP_END;
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_MagicBurn_End()
    {
    }
    ;



    // ****************************************************
    // Обработчик состояния Короткого магического горения
    // ****************************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    const int SPL_MAGICBURNSHORT_DAMAGE_PER_SEC = 1; // ущерб в сек от заклинания

    // Закончить действие заклинания
    func void B_StopMagicBurnShort()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    // продолжить распорядок дня НПС (т.к. завершение этого состояния выполняется не из цикла состояния)
    AI_ContinueRoutine(self);
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    // продолжить распорядок дня НПС
    AI_ContinueRoutine(self);
    };
    };

    // Функция реакции на локальное восприятие магии (заклинания)
    func void B_RestartBurnShort()
    {
    // если последнее примененное заклинание
    if (Npc_GetLastHitSpellID(self) == SPL_ChargeFireball) // Большой огненный шар
    || (Npc_GetLastHitSpellID(self) == SPL_Firestorm) // или Малая огненная буря
    {
    // сбросить время нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    return;
    };
    // если последнее примененное заклинание
    if (Npc_GetLastHitSpellID(self) == SPL_IceWave) // Ледяная волна
    || (Npc_GetLastHitSpellID(self) == SPL_IceCube) // или Ледяная глыба
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // очистить восприятия
    B_ClearPerceptions(self);
    // перевести жертву в состояние Магической заморозки
    AI_StartState(self,ZS_MagicFreeze,0,"");
    };
    };

    // Инициализация состояния
    func void ZS_MagicBurnShort()
    {
    // установить восприятие прекращения действия магии
    Npc_PercEnable(self,PERC_ASSESSSTOPMAGIC,B_StopMagicBurnShort);
    // если состояние тела НПС не прерываемо
    if(!Npc_HasBodyFlag(self,BS_FLAG_INTERRUPTABLE))
    {
    // НПС встает
    AI_StandUp (self);
    }
    else
    {
    // НПС быстро встает
    AI_StandUpQuick (self);
    };
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // анимация горения
    Npc_PlayAni(self,"S_FIRE_VICTIM");
    };
    };

    // Функция цикла состояния
    func int ZS_MagicBurnShort_Loop()
    {
    // разрешить локальное восприятие на воздействие магии
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_RestartBurnShort);
    // если прошла 1 секунда
    if(Npc_GetStateTime(self) == 1)
    {
    // сбросить время состояния
    Npc_SetStateTime(self,0);
    // нанести жертве секундный урон
    B_MagicHurtNpc(other,self,SPL_MAGICBURNSHORT_DAMAGE_PER_SEC);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    return LOOP_END;
    };
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // анимация горения
    Npc_PlayAni(self,"S_FIRE_VICTIM");
    };
    // если жизнь жертвы кончилась
    if(self.attribute[ATR_HITPOINTS] <= 0)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    return LOOP_END;
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_MagicBurnShort_End()
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    };





    // **************************************
    // Обработчик состояния страха
    // **************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Закончить действие заклинания
    func void B_StopMagicFlee()
    {
    // запретить восприятие повреждений
    Npc_PercDisable(self,PERC_ASSESSDAMAGE);
    // восстановить other на агрессора
    Npc_SetTarget(self,other);
    // переход в состояние убегания от агрессора
    AI_StartState(self,ZS_Flee,0,"");
    };

    // Инициализация состояния
    func void ZS_MagicFlee ()
    {
    // если жертва Дракон
    if(self.guild == GIL_DRAGON)
    {
    // продолжить распорядок дня НПС (нет реакции на магию)
    AI_ContinueRoutine(self);
    };
    var int randy;
    // установить восприятие прекращения действия магии
    Npc_PercEnable(self,PERC_ASSESSDAMAGE,B_StopMagicFlee);
    // разрешить восприятие магии
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // сбросить статус предупреждений охраны
    self.aivar[AIV_Guardpassage_Status] = GP_NONE;
    // сбросить счетчик отказа от диалога
    Npc_SetRefuseTalk(self,0);
    // установить временное отношение между жертвой и ГГ равное постоянному
    Npc_SetTempAttitude(self,Npc_GetPermAttitude(self,hero));
    // НПС и ГГ перестают смотреть друг на друга
    B_StopLookAt(self);
    // НПС прекращает на что-либо указывать
    AI_StopPointAt(self);
    // если состояние тела НПС не прерываемо
    if(!Npc_HasBodyFlag(self,BS_FLAG_INTERRUPTABLE))
    {
    // НПС встает
    AI_StandUp(self);
    }
    else
    {
    // НПС быстро встает
    AI_StandUpQuick(self);
    };
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    randy = Hlp_Random (3);
    // проигрывается анимация
    if(randy == 0) { AI_PlayAniBS(self,"T_STAND_2_FEAR_VICTIM1",BS_STAND); };
    if(randy == 1) { AI_PlayAniBS(self,"T_STAND_2_FEAR_VICTIM2",BS_STAND); };
    if(randy == 2) { AI_PlayAniBS(self,"T_STAND_2_FEAR_VICTIM3",BS_STAND); };
    };
    };

    // Функция цикла состояния
    func int ZS_MagicFlee_Loop()
    {
    // если время в состоянии > времени действия заклинания
    if(Npc_GetStateTime(self) > SPL_Time_Fear)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // закончить действие обработчика
    B_StopMagicFlee();
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_MagicFlee_End()
    {
    }
    ;





    // *******************************************
    // Обработчик состояния Магической заморозки
    // *******************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Функция реакции на локальное восприятие магии (заклинания)
    func void B_RestartFreeze()
    {
    // если последнее примененное заклинание
    if (Npc_GetLastHitSpellID(self) == SPL_IceCube) // Ледяная глыба
    || (Npc_GetLastHitSpellID(self) == SPL_IceWave) // или Ледяная волна
    {
    // сбросить время нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    };
    };

    // Закончить действие заклинания
    func void B_StopMagicFreeze()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    };
    };

    // Инициализация состояния
    func void ZS_MagicFreeze()
    {
    // разрешить локальное восприятие на воздействие магии
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_RestartFreeze);
    // прекратить анимацию
    Npc_StopAni(self,"S_FIRE_VICTIM");
    // если состояние тела НПС не прерываемо
    if(!C_BodyStateContains(self,BS_UNCONSCIOUS))
    {
    // анимация заморозки
    AI_PlayAniBS(self,"T_STAND_2_FREEZE_VICTIM",BS_UNCONSCIOUS);
    };
    // сброс времени заморозки
    self.aivar[AIV_FreezeStateTime] = 0;
    };

    // Функция цикла состояния
    func int ZS_MagicFreeze_Loop()
    {
    // если время в состоянии > времени действия заклинания
    if(Npc_GetStateTime(self) > SPL_TIME_FREEZE)
    {
    // закончить действие обработчика
    B_StopMagicFreeze();
    return LOOP_END;
    };
    // если время в состоянии не равно времени заморозки
    if(Npc_GetStateTime(self) != self.aivar[AIV_FreezeStateTime])
    {
    // время заморозки = времени состояния
    self.aivar[AIV_FreezeStateTime] = Npc_GetStateTime(self);
    // если жизнь жертвы > ущерба от заклинания
    if(self.attribute[ATR_HITPOINTS] > (self.attribute[ATR_HITPOINTS] - SPL_FREEZE_DAMAGE))
    {
    // если жертва Огненный голем или
    if (self.guild == GIL_FIREGOLEM)
    || (self.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN) // Огненная ящерица
    || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE) // или Огненный дракон
    {
    // нанести удвоенное повреждение в сек
    B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE*2);
    return LOOP_CONTINUE;
    };
    // если жертва Ледяной голем или Ледяной дракон
    if(self.guild == GIL_ICEGOLEM) || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE)
    {
    // нанести половинное порреждение в сек
    B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE/2);
    return LOOP_CONTINUE;
    };
    // нанести обычное повреждение в сек
    B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE);
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_MagicFreeze_End()
    {
    }
    ;





    // ***************************************
    // Обработчик состояния Уменьшить монстра
    // ***************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Инициализация состояния
    func void ZS_MagicShrink()
    {
    // если состояние тела НПС не прерываемо
    if(!Npc_HasBodyFlag(self,BS_FLAG_INTERRUPTABLE))
    {
    // НПС встает
    AI_StandUp(self);
    }
    else
    {
    // НПС быстро встает
    AI_StandUpQuick(self);
    };
    // сброс времени уменьшения
    self.aivar[AIV_MM_ShrinkState] = 0;
    };

    // Функция цикла состояния
    func int ZS_MagicShrink_Loop()
    {
    // за 13 секунд плавно уменьшить жертву
    if (self.aivar[AIV_MM_ShrinkState] == 0) { Mdl_SetModelScale(self,0.90,0.90,0.90); self.aivar[AIV_MM_ShrinkState] = 1; }
    else if(self.aivar[AIV_MM_ShrinkState] == 1) { Mdl_SetModelScale(self,0.85,0.85,0.85); self.aivar[AIV_MM_ShrinkState] = 2; }
    else if(self.aivar[AIV_MM_ShrinkState] == 2) { Mdl_SetModelScale(self,0.80,0.80,0.80); self.aivar[AIV_MM_ShrinkState] = 3; }
    else if(self.aivar[AIV_MM_ShrinkState] == 3) { Mdl_SetModelScale(self,0.75,0.75,0.75); self.aivar[AIV_MM_ShrinkState] = 4; }
    else if(self.aivar[AIV_MM_ShrinkState] == 4) { Mdl_SetModelScale(self,0.70,0.70,0.70); self.aivar[AIV_MM_ShrinkState] = 5; }
    else if(self.aivar[AIV_MM_ShrinkState] == 5) { Mdl_SetModelScale(self,0.65,0.65,0.65); self.aivar[AIV_MM_ShrinkState] = 6; }
    else if(self.aivar[AIV_MM_ShrinkState] == 6) { Mdl_SetModelScale(self,0.60,0.60,0.60); self.aivar[AIV_MM_ShrinkState] = 7; }
    else if(self.aivar[AIV_MM_ShrinkState] == 7) { Mdl_SetModelScale(self,0.55,0.55,0.55); self.aivar[AIV_MM_ShrinkState] = 8; }
    else if(self.aivar[AIV_MM_ShrinkState] == 8) { Mdl_SetModelScale(self,0.50,0.50,0.50); self.aivar[AIV_MM_ShrinkState] = 9; }
    else if(self.aivar[AIV_MM_ShrinkState] == 9) { Mdl_SetModelScale(self,0.45,0.45,0.45); self.aivar[AIV_MM_ShrinkState] = 10;}
    else if(self.aivar[AIV_MM_ShrinkState] == 10) { Mdl_SetModelScale(self,0.40,0.40,0.40); self.aivar[AIV_MM_ShrinkState] = 11;}
    else if(self.aivar[AIV_MM_ShrinkState] == 11) { Mdl_SetModelScale(self,0.35,0.35,0.35); self.aivar[AIV_MM_ShrinkState] = 12;}
    else if(self.aivar[AIV_MM_ShrinkState] == 12) { Mdl_SetModelScale(self,0.30,0.30,0.30); self.aivar[AIV_MM_ShrinkState] = 13;}
    // если жертва уменьшена
    else if(self.aivar[AIV_MM_ShrinkState] == 13)
    {
    // уменьшить жизнь жертвы
    Npc_ChangeAttribute(self,ATR_HITPOINTS,-((self.attribute[ATR_HITPOINTS]*9)/10));
    // уменьшить макс. жизнь жертвы
    Npc_ChangeAttribute(self,ATR_HITPOINTS_MAX,-((self.attribute[ATR_HITPOINTS_MAX]*9)/10));
    // уменьшить силу жертвы
    Npc_ChangeAttribute(self,ATR_STRENGTH,-((self.attribute[ATR_STRENGTH]*9)/10));
    // уменьшить защиту от тупого оружия
    self.protection[PROT_BLUNT] = self.protection[PROT_BLUNT]/10;
    // уменьшить защиту от острого оружия
    self.protection[PROT_EDGE] = self.protection[PROT_EDGE]/10;
    // уменьшить защиту от огня
    self.protection[PROT_FIRE] = self.protection[PROT_FIRE]/10;
    // защита от нокаута = 0
    self.protection[PROT_FLY] = 0;
    // уменьшить защиту от магии
    self.protection[PROT_MAGIC] = self.protection[PROT_MAGIC]/10;
    // уменьшить защиту от тотечного оружия
    self.protection[PROT_POINT] = self.protection[PROT_POINT]/10;
    // переход на следующую фазу состояния
    self.aivar[AIV_MM_ShrinkState] = 14;
    }
    // если достигнута последняя фаза состояния
    else if(self.aivar[AIV_MM_ShrinkState] == 14)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // установить обработчик поведения в уменьшенном состоянии
    self.start_aistate = ZS_MagicShrunk;
    // переход в новый обработчик
    AI_StartState(self,ZS_MagicShrunk,1,"");
    return LOOP_END;
    };
    // задержка перед последней фазой состояния
    AI_Wait(self,0.38 );
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_MagicShrink_End()
    {
    }
    ;


    // ********************************************
    // Обработчик поведения уменьшенного монстра
    // ********************************************

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

    // Инициализация состояния
    func void ZS_MagicShrunk()
    {
    // установить целью ГГ
    Npc_SetTarget(self,hero);
    };

    // Функция цикла состояния
    func int ZS_MagicShrunk_Loop()
    {
    // монстр убегает от ГГ
    AI_Flee(self);
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_MagicShrunk_End()
    {
    };



    // **************************************
    // Обработчик состояния Магический сон
    // **************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Локальное восприятие повреждения (окончание действия заклинания)
    func int B_StopMagicSleep()
    {
    // запретить восприятие повреждений
    Npc_PercDisable(self,PERC_ASSESSDAMAGE);
    // жертва говорит агрессору (SVM фраза) "(сам с собою, просыпаясь) Что это было!?" (Примечание: Ошибка слово $WHATWASSTHAT надо заменить на $WHATWASTHAT, а то фраза не будет сказана)
    B_Say_Overlay(self,other,"$WHATWASSTHAT");
    // анимация перехода в нормальное состояние
    AI_PlayAni(self,"T_VICTIM_SLE_2_STAND");
    };

    // Локальное восприятие разговора
    func void B_AssessMagicSleepTalk()
    {
    // жертва говорит агрессору (SVM фраза) "(просыпаясь) Черт, что случилось?"
    B_Say(self,other,"$YOUDISTURBEDMYSLUMBER");
    // жертва переходит в состояние наблюдения за ГГ
    AI_StartState(self,ZS_ObservePlayer,1,"");
    };

    // Инициализация состояния
    func void ZS_MagicSleep()
    {
    // установить локальное восприятие повреждения
    Npc_PercEnable(self,PERC_ASSESSDAMAGE,B_StopMagicSleep);
    // разрешить восприятие магии
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // установить локальное восприятие разговора
    Npc_PercEnable(self,PERC_ASSESSTALK,B_AssessMagicSleepTalk);
    // Сбросить статус предупреждений охраной
    self.aivar[AIV_Guardpassage_Status] = GP_NONE;
    // сбросить счетчик отказа от диалога
    Npc_SetRefuseTalk(self,0);
    // установить временное отношение между жертвой и ГГ равное постоянному
    Npc_SetTempAttitude(self,Npc_GetPermAttitude(self,hero));
    // НПС и ГГ перестают смотреть друг на друга
    B_StopLookAt(self);
    // НПС прекращает на что-либо указывать
    AI_StopPointAt(self);
    // если состояние тела НПС не прерываемо
    if(!Npc_HasBodyFlag(self,BS_FLAG_INTERRUPTABLE))
    {
    // НПС встает
    AI_StandUp(self);
    }
    else
    {
    // НПС быстро встает
    AI_StandUpQuick(self);
    };
    // проигрывается анимация перехода в Магический сон
    AI_PlayAniBS(self,"T_STAND_2_VICTIM_SLE",BS_LIE );
    };

    // Функция цикла состояния
    func int ZS_MagicSleep_Loop()
    {
    // если время в состоянии > времени действия заклинания
    if(Npc_GetStateTime(self) > SPL_Time_Sleep)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // закончить действие обработчика
    B_StopMagicSleep();
    return LOOP_END;
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_MagicSleep_End()
    {
    }
    ;





    // ***********************************************************
    // Обработчик состояния Большой огненной бури
    // -----------------------------------------------------------

    Открыть спойлер
    // В это состояние НПС переводится экзешником, а не скриптами
    // ***********************************************************


    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Закончить действие заклинания
    func void B_StopPyro()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    // продолжить распорядок дня НПС (т.к. не было принудительного перевода НПС в это состояние из скриптов и завершение этого состояния выполняется не из цикла состояния)
    AI_ContinueRoutine(self);
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    // продолжить распорядок дня НПС
    AI_ContinueRoutine(self);
    };
    };

    // Инициализация состояния
    func void ZS_Pyro()
    {
    // установить восприятие прекращения действия магии
    Npc_PercEnable(self,PERC_ASSESSSTOPMAGIC,B_StopPyro);
    // если состояние тела НПС не прерываемо
    if(!Npc_HasBodyFlag(self, BS_FLAG_INTERRUPTABLE))
    {
    // НПС встает
    AI_StandUp(self);
    }
    else
    {
    // НПС быстро встает
    AI_StandUpQuick(self);
    };
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // проиграть анимацию входа в состояние
    AI_PlayAni(self,"T_STAND_2_LIGHTNING_VICTIM");
    };
    };

    // Функция цикла состояния
    func int ZS_Pyro_Loop()
    {
    // если прошла 1 секунда
    if(Npc_GetStateTime(self) >= 1)
    {
    // сбросить время состояния
    Npc_SetStateTime(self,0);
    // нанести жертве секундный урон
    B_MagicHurtNpc(other,self,SPL_PYRO_DAMAGE_PER_SEC);
    // если жизнь жертвы кончилась
    if(self.attribute[ATR_HITPOINTS] <= 0)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    return LOOP_END;
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Pyro_End()
    {
    }
    ;





    // ************************************************
    // Обработчик состояния реакции на Шаровую молнию
    // ************************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Закончить действие заклинания
    func void B_StopShortZapped()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    // продолжить распорядок дня НПС (т.к. завершение этого состояния выполняется не из цикла состояния)
    AI_ContinueRoutine(self);
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    // продолжить распорядок дня НПС
    AI_ContinueRoutine(self);
    };
    };

    // Инициализация состояния
    func void ZS_ShortZapped()
    {
    // установить восприятие прекращения действия магии
    Npc_PercEnable(self,PERC_ASSESSSTOPMAGIC,B_StopShortZapped);
    // если состояние тела НПС не прерываемо
    if(!Npc_HasBodyFlag(self,BS_FLAG_INTERRUPTABLE))
    {
    // НПС встает
    AI_StandUp(self);
    }
    else
    {
    // НПС быстро встает
    AI_StandUpQuick(self);
    };
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // проиграть анимацию входа в состояние
    AI_PlayAni(self,"T_STAND_2_LIGHTNING_VICTIM");
    };
    };

    // Функция цикла состояния
    func int ZS_ShortZapped_Loop()
    {
    // если время в состоянии > времени действия заклинания
    if(Npc_GetStateTime(self) > SPL_TIME_SHORTZAPPED)
    {
    // закончить действие обработчика
    B_StopShortZapped();
    return LOOP_END;
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_ShortZapped_End()
    {
    }
    ;





    // *************************************
    // Обработчик состояния Украсть энергию
    // *************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    var int Temp_SuckEnergy_DistToPlayer; // расстояние между жертвой и ГГ

    // Функция реакции на локальное восприятие магии (заклинания)
    func void B_RestartSuckEnergy()
    {
    // если последнее примененное заклинание Украсть энергию
    if(Npc_GetLastHitSpellID(self) == SPL_SuckEnergy)
    {
    // сбросить время нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    // анимация состояния
    AI_PlayAni(self,"T_STAND_2_SUCKENERGY_VICTIM");
    };
    };

    // Закончить действие заклинания
    func void B_StopSuckEnergy()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    };
    };

    // Инициализация состояния
    func void ZS_SuckEnergy()
    {
    // установить локальное восприятие на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_RestartSuckEnergy);
    // остановить проигрывание файла анимации заклинания
    Npc_StopAni(self, "S_SUCKENERGY_VICTIM");
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // сброс времени цикла
    self.aivar[AIV_SuckEnergyStateTime] = 1;
    // запомнить расстояние между жертвой и ГГ
    Temp_SuckEnergy_DistToPlayer = Npc_GetDistToPlayer(self);
    };

    // Функция цикла состояния
    func int ZS_SuckEnergy_Loop()
    {
    // если время в состоянии > времени действия заклинания или расстояние между ГГ и жертвой увеличилось на более 10м
    if(Npc_GetStateTime(self) > SPL_TIME_SuckEnergy) || (Temp_SuckEnergy_DistToPlayer >= Npc_GetDistToPlayer(self) + 100)
    {
    // остановить действие заклинания
    B_StopSuckEnergy();
    return LOOP_END;
    };
    // если текущее время состояния не равно времени цикла
    if(Npc_GetStateTime(self) != self.aivar[AIV_SuckEnergyStateTime])
    {
    // если первая фаза состояния
    if(Npc_GetStateTime(self) == 0)
    {
    // если состояние тела НПС не прерываемо
    if(!C_BodyStateContains(self, BS_UNCONSCIOUS))
    {
    // анимация перехода в бессознательное состояние
    AI_PlayAniBS(self,"T_STAND_2_SUCKENERGY_VICTIM",BS_UNCONSCIOUS);
    };
    // эффект высасывания энергии
    Wld_PlayEffect("spellFX_SuckEnergy_BloodFly",self,hero,0,0,0,FALSE);
    };
    // обновить время цикла
    self.aivar[AIV_SuckEnergyStateTime] = Npc_GetStateTime(self);
    // если жизнь жертвы > ущерба от заклинания
    if(self.attribute[ATR_HITPOINTS] > SPL_SuckEnergy_DAMAGE)
    {
    // нанести жертве урон
    B_MagicHurtNpc(other,self,SPL_SuckEnergy_DAMAGE);
    // добавить украденную жизнь агрессору
    Npc_ChangeAttribute(other,ATR_HITPOINTS,SPL_SuckEnergy_DAMAGE);
    }
    else
    {
    // убить жертву
    B_MagicHurtNpc(other,self,self.attribute[ATR_HITPOINTS] - 1);
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_SuckEnergy_End()
    {
    }
    ;



    // *************************************
    // Обработчик состояния заклинания Рой
    // *************************************

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Функция реакции на локальное восприятие магии
    func void B_RestartSwarm()
    {
    // если последнее примененное заклинание Рой
    if(Npc_GetLastHitSpellID(self) == SPL_Swarm)
    {
    // сбросить время нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    };
    };

    // Закончить действие заклинания
    func void B_StopSwarm()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if (self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    };
    };

    // Инициализация состояния
    func void ZS_Swarm()
    {
    // установить локальное восприятие на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_RestartSwarm);
    // остановить проигрывание файла анимации заклинания
    Npc_StopAni(self,"S_SWARM_VICTIM");
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если состояние тела НПС не прерываемо
    if(!C_BodyStateContains(self,BS_UNCONSCIOUS))
    {
    // анимация перехода в бессознательное состояние
    AI_PlayAniBS(self,"T_STAND_2_SWARM_VICTIM",BS_UNCONSCIOUS);
    };
    // сброс времени цикла
    self.aivar[AIV_SwarmStateTime] = 0;
    };

    // Функция цикла состояния
    func int ZS_Swarm_Loop ()
    {
    // если время в состоянии > времени действия заклинания
    if(Npc_GetStateTime(self) > SPL_TIME_Swarm)
    {
    // остановить действие заклинания
    B_StopSwarm();
    return LOOP_END;
    };
    // если прошла 1 сек
    if(Npc_GetStateTime(self) != self.aivar[AIV_SwarmStateTime])
    {
    // если жертва находится в состоянии 2 сек
    if(Npc_GetStateTime(self) == 2)
    {
    // жертва говорит агрессору (SVM фраза) "Ах, черт!"
    B_Say(self,other,"$RunAway");
    }
    // через 6 сек
    else if(Npc_GetStateTime(self) == 6)
    {
    // жертва говорит агрессору (SVM фраза) "Ууух!"
    B_Say(self,other,"$Aargh_2");
    }
    // через 7 сек
    else if(Npc_GetStateTime(self) == 7)
    {
    // жертва говорит агрессору (SVM фраза) "Ууух!"
    B_Say (self,other,"$Aargh_3");
    }
    // через 8 сек
    else if(Npc_GetStateTime(self) == 8 )
    {
    // жертва говорит агрессору (SVM фраза) "Ууух!"
    B_Say(self,other,"$Aargh_1");
    };
    // установить счетчик цикла на текущее время
    self.aivar[AIV_SwarmStateTime] = Npc_GetStateTime(self);
    // если жизнь жертвы > ущерба от заклинания
    if(self.attribute[ATR_HITPOINTS] > SPL_Swarm_DAMAGE)
    {
    // нанести жертве урон
    B_MagicHurtNpc(other,self,SPL_Swarm_DAMAGE);
    }
    else
    {
    // убить жертву
    B_MagicHurtNpc(other,self,self.attribute[ATR_HITPOINTS] - 1);
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Swarm_End()
    {
    }
    ;





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

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

    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Функция реакции на локальное восприятие магии
    func void B_RestartWhirlwind()
    {
    // если последнее примененное заклинание Смерч
    if(Npc_GetLastHitSpellID(self) == SPL_Whirlwind)
    {
    // сбросить время нахождения НПС в этом состоянии
    Npc_SetStateTime(self,0);
    };
    };

    // Закончить действие заклинания
    func void B_StopWhirlwind()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    };
    };

    // Инициализация состояния
    func void ZS_Whirlwind()
    {
    // установить локальное восприятие на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_RestartWhirlwind);
    // остановить проигрывание файла анимации заклинания
    Npc_StopAni(self,"S_WHIRLWIND_VICTIM");
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если состояние тела НПС не прерываемо
    if(!C_BodyStateContains(self, BS_UNCONSCIOUS))
    {
    // анимация перехода в бессознательное состояние
    AI_PlayAniBS(self,"T_STAND_2_WHIRLWIND_VICTIM",BS_UNCONSCIOUS);
    };
    // сброс счетчика цикла
    self.aivar[AIV_WhirlwindStateTime] = 0;
    };

    // Функция цикла состояния
    func int ZS_Whirlwind_Loop ()
    {
    // если время в состоянии > времени действия заклинания
    if(Npc_GetStateTime(self) > SPL_TIME_WHIRLWIND)
    {
    // остановить действие заклинания
    B_StopWhirlwind();
    return LOOP_END;
    };
    // если прошла 1 сек
    if(Npc_GetStateTime(self) != self.aivar[AIV_WhirlwindStateTime])
    {
    // установить счетчик цикла на текущее время
    self.aivar[AIV_WhirlwindStateTime] = Npc_GetStateTime(self);
    // если жизнь жертвы > ущерба от заклинания
    if(self.attribute[ATR_HITPOINTS] > SPL_Whirlwind_DAMAGE)
    {
    // нанести жертве урон
    B_MagicHurtNpc(other,self,SPL_Whirlwind_DAMAGE);
    }
    else
    {
    // убить жертву
    B_MagicHurtNpc(other,self,self.attribute[ATR_HITPOINTS] - 1);
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Whirlwind_End()
    {
    }
    ;





    // ***********************************************************
    // Обработчик состояния Удар молнии
    // -----------------------------------------------------------

    Открыть спойлер
    // В это состояние НПС переводится экзешником, а не скриптами
    // ***********************************************************


    // ----------------------------------------------------
    // self - жертва заклинания
    // other - кастующий НПС (агрессор)
    // ----------------------------------------------------


    // Закончить действие заклинания
    func void B_StopZapped()
    {
    // возвратить общую функцию состояния реакции на магию
    Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // реакция НПС на повреждение
    B_AssessDamage();
    // продолжить распорядок дня НПС (т.к. не было принудительного перевода НПС в это состояние из скриптов и завершение этого состояния выполняется не из цикла состояния)
    AI_ContinueRoutine(self);
    }
    else
    {
    // установить временно враждебное отношение НПС к ГГ
    Npc_SetTempAttitude(self,ATT_HOSTILE);
    // продолжить распорядок дня НПС
    AI_ContinueRoutine(self);
    };
    };

    // Инициализация состояния
    func void ZS_Zapped()
    {
    // установить восприятие прекращения действия магии
    Npc_PercEnable(self,PERC_ASSESSSTOPMAGIC,B_StopZapped);
    // если состояние тела НПС не прерываемо
    if(!Npc_HasBodyFlag(self,BS_FLAG_INTERRUPTABLE))
    {
    // НПС встает
    AI_StandUp(self);
    }
    else
    {
    // НПС быстро встает
    AI_StandUpQuick(self);
    };
    // если жертва человек
    if(self.guild < GIL_SEPERATOR_HUM)
    {
    // включить анимацию действия заклинания
    AI_PlayAni(self,"T_STAND_2_LIGHTNING_VICTIM");
    };
    };

    // Функция цикла состояния
    func int ZS_Zapped_Loop()
    {
    // если прошла 1 секунда
    if(Npc_GetStateTime(self) >= 1)
    {
    // сбросить время состояния
    Npc_SetStateTime(self,0);
    // нанести жертве секундный урон
    B_MagicHurtNpc(other,self,SPL_ZAPPED_DAMAGE_PER_SEC);
    // если жизнь жертвы кончилась
    if(self.attribute[ATR_HITPOINTS] <= 0)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    return LOOP_END;
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Zapped_End()
    {
    }
    ;
     
    Поблагодарили Ur-tRall, Валера и hell9999.
  7. MEG@VOLT

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

    Регистрация:
    24 мар 2006
    Сообщения:
    1.566
    Благодарности:
    628
    Баллы:
    290
    18. Разные AI функции.

    // ***********************************************
    // Функция обновления снаряжения при респавне НПС
    // -----------------------------------------------

    Открыть спойлер
    // Вызывается только экзешником
    // ***********************************************


    // -----------------------------------------------
    // self - возрождаемый НПС
    // -----------------------------------------------


    func void B_RefreshAtInsert()
    {
    // если НПС мертв
    if(self.attribute[ATR_HITPOINTS] <= 0)
    {
    return;
    };
    var c_npc her;
    // получить ссылку на ГГ
    her = Hlp_GetNpc(PC_Hero);
    // если НПС человек и НПС не ГГ
    if(self.guild < GIL_SEPERATOR_HUM) && (Hlp_GetInstanceID(self) != Hlp_GetInstanceID(her))
    {
    // установить текущую жизнь равной максимальной
    self.attribute[ATR_HITPOINTS] = self.attribute[ATR_HITPOINTS_MAX];
    // если НПС не имеет никакого оружия
    if(Npc_HasEquippedWeapon(self) == FALSE)
    {
    // если НПС милиционер
    if(self.guild == GIL_MIL)
    {
    // создать в инвентаре Тяжелую палку
    CreateInvItems(self,ItMw_1h_Bau_Mace,1);
    };
    // если НПС паладин
    if(self.guild == GIL_PAL)
    {
    CreateInvItems(self,ItMw_1h_Bau_Mace,1);
    };
    // если НПС наемник
    if(self.guild == GIL_SLD)
    {
    CreateInvItems(self,ItMw_1h_Bau_Mace,1);
    };
    // если НПС крестьянин
    if(self.guild == GIL_BAU)
    {
    CreateInvItems(self,ItMw_1h_Bau_Mace,1);
    };
    // если НПС маг послушник
    if(self.guild == GIL_NOV)
    {
    CreateInvItems(self,ItMw_1h_Bau_Mace,1);
    };
    };
    };
    };
    Эта функция расположена в директории ..\AI\AI_Intern в одноименном файле.


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

    Открыть спойлер
    // Вызывается только экзешником
    // ***********************************************************


    // -----------------------------------------------
    // self - обыскивающий НПС
    // -----------------------------------------------


    func void PLAYER_PLUNDER_IS_EMPTY()
    {
    var int rnd;
    rnd = Hlp_Random(100);
    // с вероятностью 0.4
    if(rnd <= 40)
    {
    // напечатать текст по цетру экрана "здесь ничего нет..."
    Print(PRINT_NOTHINGTOGET);
    // произносится SVM фраза "Здесь нечего унести ..."
    B_Say_Overlay(self,self,"$NOTHINGTOGET");
    }
    // с вероятностью 0.4
    else if(rnd <= 80)
    {
    // напечатать текст по цетру экрана "Нечего унести..."
    Print(PRINT_NOTHINGTOGET02);
    // произносится SVM фраза "нечего унести ..."
    B_Say_Overlay(self,self,"$NOTHINGTOGET02");
    }
    // с вероятностью 0.2
    else if(rnd <= 99)
    {
    // напечатать текст по цетру экрана "Нечего грабить..."
    Print(PRINT_NOTHINGTOGET03);
    // произносится SVM фраза "нечего украсть ..."
    B_Say_Overlay(self,self,"$NOTHINGTOGET03");
    };
    };
    Эта функция расположена в директории ..\AI\AI_Intern в одноименном файле.


    //**************************************************************
    //*****
    // Функция обновления доспехов НПС
    // -------------------------------------------------------------------

    Открыть спойлер
    // Вызывается только экзешником (пока пуста)
    // *******************************************************************


    func void B_RefreshArmor()
    {
    }
    ;
    Эта функция расположена в директории ..\AI\Human в одноименном файле.

    B_ функции монстров расположены в директории ..\AI\Monster\B_Monster
    // ***********************************
    // Функция задержки реакции монстров
    // ***********************************


    func void B_MM_DeSynchronize()
    {
    var int msec;
    msec = Hlp_Random(1000);
    // случайная задержка от 0 до 1 сек
    AI_Waitms(self,msec);
    };





    // *******************************************
    // Выполнение Огоньком заданий
    // *******************************************

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

    // ----------------------------------------------------
    // self - Огонек
    // item - предмет
    // ----------------------------------------------------


    // Реакция Огонька на найденный предмет
    func void B_GetWispDetectedItem()
    {
    // если предмет не существует
    if(!Hlp_IsValidItem(item))
    {
    return;
    };
    // если расстояние между Огоньком и предметом > 5м
    if(Npc_GetHeightToItem(self,item) > 500)
    {
    return;
    };
    var int randy;
    randy = Hlp_Random(100);
    // Огонек движется к предмету
    AI_GotoItem(self,item);
    // если расстояние между Огоньком и предметом < 1м и вероятность <= 0.01
    if(Npc_GetDistToItem(self,item) < 1000) && (randy <= 1)
    {
    // проигрывается анимация выкапывания предмета
    Wld_PlayEffect("spellFX_ItemAusbuddeln",item,item,0,0,0,FALSE );
    };
    };

    // Поиск Огоньком предметов
    //----------------------------------------------------------------
    // Возвращаемое значение: что нашел Огонек (в принципе не нужно)

    func int B_WispDetectedItem()
    {
    // если Огонек ничего не ищет
    if(WispSearching == WispSearch_Follow)
    {
    }
    else // иначе (режим поиска)
    {
    var int WispSearchFlags;
    // флаг поиска
    WispSearchFlags = 0;
    // если Огонек обучен искать оружие ближнего радиуса поражения и
    if ((PLAYER_TALENT_WISPDETECTOR[WISPSKILL_NF] == TRUE)
    // (режим поиска - искать всё или оружие ближнего радиуса поражения)
    && ((WispSearching == WispSearch_ALL) || (WispSearching == WispSearch_NF)))
    {
    // установить соответствующий флаг
    WispSearchFlags = WispSearchFlags | ITEM_KAT_NF;
    };
    // если Огонек обучен искать оружие дальнего радиуса поражения и
    if ((PLAYER_TALENT_WISPDETECTOR[WISPSKILL_FF] == TRUE)
    // (режим поиска - искать всё или оружие дальнего радиуса поражения)
    && ((WispSearching == WispSearch_ALL) || (WispSearching == WispSearch_FF)))
    {
    WispSearchFlags = WispSearchFlags | ITEM_KAT_FF | ITEM_KAT_MUN;
    };
    // если Огонек обучен искать деньги, ключи, предметы обихода и
    if ((PLAYER_TALENT_WISPDETECTOR[WISPSKILL_NONE] == TRUE)
    // (режим поиска - искать всё или указанные вещи)
    && ((WispSearching == WispSearch_ALL) || (WispSearching == WispSearch_NONE)))
    {
    WispSearchFlags = WispSearchFlags | ITEM_KAT_NONE | ITEM_KAT_KEYS | ITEM_KAT_LIGHT | ITEM_KAT_ARMOR;
    };
    // если Огонек обучен искать руны и свитки и
    if ((PLAYER_TALENT_WISPDETECTOR[WISPSKILL_RUNE] == TRUE)
    // (режим поиска - искать всё или указанные вещи)
    && ((WispSearching == WispSearch_ALL) || (WispSearching == WispSearch_RUNE)))
    {
    WispSearchFlags = WispSearchFlags | ITEM_KAT_RUNE | ITEM_KAT_DOCS;
    };
    // если Огонек обучен искать кольца и амулеты и
    if ((PLAYER_TALENT_WISPDETECTOR[WISPSKILL_MAGIC] == TRUE)
    // (режим поиска - искать всё или указанные вещи)
    && ((WispSearching == WispSearch_ALL) || (WispSearching == WispSearch_MAGIC)))
    {
    WispSearchFlags = WispSearchFlags | ITEM_KAT_MAGIC;
    };
    // если Огонек обучен искать пропитание и
    if ((PLAYER_TALENT_WISPDETECTOR[WISPSKILL_FOOD] == TRUE)
    // (режим поиска - искать всё или указанные вещи)
    && ((WispSearching == WispSearch_ALL) || (WispSearching == WispSearch_FOOD)))
    {
    WispSearchFlags = WispSearchFlags | ITEM_KAT_FOOD;
    };
    // если Огонек обучен искать напитки и
    if ((PLAYER_TALENT_WISPDETECTOR[WISPSKILL_POTIONS] == TRUE)
    // (режим поиска - искать всё или указанные вещи)
    && ((WispSearching == WispSearch_ALL) || (WispSearching == WispSearch_POTIONS)))
    {
    WispSearchFlags = WispSearchFlags | ITEM_KAT_POTIONS;
    };
    // если Огонек способен что-то найти
    if(WispSearchFlags != 0)
    {
    // если найден предмет с указанными флагами
    if(Wld_DetectItem(self,WispSearchFlags))
    {
    // реакция Огонька на найденный предмет
    B_GetWispDetectedItem();
    };
    };
    return WispSearchFlags;
    };
    return 0;
    };

    // Выполнение Огоньком заданий
    func int B_MM_WispDetect()
    {
    // если self (вызванный монстр) есть Огонек
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Wisp_Detector))
    {
    // разрешить Огоньку воспринимать все объекты в зоне действия восприятия
    Npc_PerceiveAll(self);
    // если найден другой Огонек (other инициализирован Огоньком)
    if(Wld_DetectNpc(self,Wisp_Detector,NOFUNC,-1)
    {
    // удалить Огонек
    B_RemoveNpc(self);
    };
    // если расстояние между Огоньком и ГГ меньше 20м и установлен флаг близости
    if(Npc_GetDistToNpc(self,hero) < 2000) && (self.aivar[AIV_TAPOSITION] == ISINPOS)
    {
    // сброс времени жизни монстра
    self.aivar[AIV_SummonTime] = 0;
    // выполнение поиска Огоньком
    B_WispDetectedItem();
    return LOOP_END;
    }
    else
    {
    // если расстояние между Огоньком и ГГ меньше 5м
    if(Npc_GetDistToNpc(self,hero) < 500)
    {
    // установить флаг близости
    self.aivar[AIV_TAPOSITION] = ISINPOS;
    }
    else
    {
    // установить флаг удаленности
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    // очистка очереди AI состояний Огонька
    Npc_ClearAIQueue(self);
    // Огонек движется к ГГ
    AI_GotoNpc(self,hero);
    };
    return LOOP_END;
    };
    };
    return LOOP_CONTINUE;
    };
    C_ функции монстров расположены в директории ..\AI\Monsrer\C_Monster

    // ********************************************************************
    // Является ли монстр магом
    // ********************************************************************

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

    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый монстр
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    func int C_NpcIsMonsterMage(var c_npc slf)
    {
    // если монстр Маг скелетов или
    if (slf.guild == GIL_SKELETON_MAGE)
    || (slf.guild == GIL_FIREGOLEM) // Огненный голем
    || (slf.guild == GIL_ICEGOLEM) // или Ледяной голем
    || (slf.guild == GIL_DRAGON) // или Дракон
    {
    return TRUE;
    };
    return FALSE;
    };





    // ********************************************************************************
    //*****
    // Устраивает ли монстра добыча в виде жертвы (на кого охотяться монстры)
    // ********************************************************************************
    //*****

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

    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый монстр (охотник)
    // oth - НПС добыча
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    func int C_PredatorFoundPrey(var c_npc slf,var c_npc oth)
    {
    // если охотник волк, но не кабан
    if(slf.guild == GIL_WOLF) && (slf.aivar[AIV_MM_REAL_ID] != ID_Keiler)
    {
    // если добыча овца
    if(oth.guild == GIL_SHEEP) { return TRUE; };
    // если добыча крыса
    if(oth.guild == GIL_GIANT_RAT) { return TRUE; };
    // если добыча кротокрыс
    if(oth.guild == GIL_MOLERAT) { return TRUE; };
    // если добыча падальщик, но не зубастик
    if(oth.guild == GIL_SCAVENGER) && (oth.aivar[AIV_MM_REAL_ID] != ID_ORCBITER) { return TRUE; };
    };
    // если охотник шныг
    if(slf.guild == GIL_LURKER)
    {
    // если добыча гоблин
    if (oth.guild == GIL_GOBBO) { return TRUE; };
    };
    // если охотник глорх
    if(slf.guild == GIL_SNAPPER)
    {
    // если добыча человек
    if(oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    // если добыча гоблин
    if(oth.guild == GIL_GOBBO) { return TRUE; };
    // если добыча овца
    if(oth.guild == GIL_SHEEP) { return TRUE; };
    // если добыча крыса
    if(oth.guild == GIL_GIANT_RAT) { return TRUE; };
    // если добыча кротокрыс
    if(oth.guild == GIL_MOLERAT) { return TRUE; };
    // если добыча падальщик, но не зубастик
    if(oth.guild == GIL_SCAVENGER) && (oth.aivar[AIV_MM_REAL_ID] != ID_ORCBITER) { return TRUE; };
    };
    // если охотник мракорис
    if(slf.guild == GIL_SHADOWBEAST)
    {
    // если добыча человек
    if(oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    // если добыча орк
    if(oth.guild > GIL_SEPERATOR_ORC) { return TRUE; };
    // если добыча овца
    if(oth.guild == GIL_SHEEP) { return TRUE; };
    // если добыча крыса
    if(oth.guild == GIL_GIANT_RAT) { return TRUE; };
    // если добыча кротокрыс
    if(oth.guild == GIL_MOLERAT) { return TRUE; };
    // если добыча падальщик, но не зубастик
    if(oth.guild == GIL_SCAVENGER) && (oth.aivar[AIV_MM_REAL_ID] != ID_ORCBITER) { return TRUE; };
    };
    return FALSE;
    };





    // ***********************************
    // Пожирает ли монстр труп добычи
    // ***********************************

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

    // ====================================================================
    // Аргументы:
    // --------------------------------------------------------------------
    // slf - проверяемый монстр (охотник)
    // oth - НПС добыча (труп)
    // --------------------------------------------------------------------
    // Возвращаемое значение:
    // TRUE - да, FALSE - нет.
    // ====================================================================


    func int C_WantToEat(var c_npc slf,var c_npc oth)
    {
    // если монстр член партии ГГ
    if(slf.aivar[AIV_PARTYMEMBER] == TRUE)
    {
    return FALSE;
    };
    // если охотник падальщик
    if(slf.guild == GIL_SCAVENGER)
    {
    // если труп человек или орк
    if(oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    if(oth.guild > GIL_SEPERATOR_ORC) { return TRUE; };
    // если труп овца или полевые хищники
    if(oth.guild == GIL_SHEEP) { return TRUE; };
    if(oth.guild == GIL_GIANT_RAT) { return TRUE; };
    if(oth.guild == GIL_MOLERAT) { return TRUE; };
    // если труп гарпия
    if(oth.guild == GIL_HARPY) { return TRUE; };
    // если труп волки
    if(oth.guild == GIL_WOLF) { return TRUE; };
    if(oth.guild == GIL_SUMMONED_WOLF) { return TRUE; };
    // если труп мракорис
    if(oth.guild == GIL_SHADOWBEAST) { return TRUE; };
    // если труп рептилий
    if(oth.guild == GIL_GOBBO) { return TRUE; };
    if(oth.guild == GIL_WARAN) { return TRUE; };
    if(oth.guild == GIL_LURKER) { return TRUE; };
    if(oth.guild == GIL_SNAPPER) { return TRUE; };
    // в принципе здесь все понятно и без комментариев
    if(oth.guild == GIL_MEATBUG) { return TRUE; };
    if(oth.guild == GIL_GIANT_BUG) { return TRUE; };
    if(oth.guild == GIL_BLOODFLY) { return TRUE; };
    if(oth.guild == GIL_MINECRAWLER) { return TRUE; };
    };
    // если охотник крыса
    if(slf.guild == GIL_GIANT_RAT)
    {
    if(oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    if(oth.guild > GIL_SEPERATOR_ORC) { return TRUE; };
    if(oth.guild == GIL_SHEEP) { return TRUE; };
    if(oth.guild == GIL_GIANT_RAT) { return TRUE; };
    if(oth.guild == GIL_MOLERAT) { return TRUE; };
    if(oth.guild == GIL_SCAVENGER) { return TRUE; };
    if(oth.guild == GIL_HARPY) { return TRUE; };
    if(oth.guild == GIL_WOLF) { return TRUE; };
    if(oth.guild == GIL_SUMMONED_WOLF) { return TRUE; };
    if(oth.guild == GIL_SHADOWBEAST) { return TRUE; };
    if(oth.guild == GIL_GOBBO) { return TRUE; };
    if(oth.guild == GIL_WARAN) { return TRUE; };
    if(oth.guild == GIL_LURKER) { return TRUE; };
    if(oth.guild == GIL_SNAPPER) { return TRUE; };
    if(oth.guild == GIL_MEATBUG) { return TRUE; };
    if(oth.guild == GIL_GIANT_BUG) { return TRUE; };
    if(oth.guild == GIL_BLOODFLY) { return TRUE; };
    if(oth.guild == GIL_MINECRAWLER) { return TRUE; };
    };
    // если охотник полевой жук
    if(slf.guild == GIL_GIANT_BUG)
    {
    if(oth.guild == GIL_MEATBUG) { return TRUE; };
    if(oth.guild == GIL_BLOODFLY) { return TRUE; };
    if(oth.guild == GIL_MINECRAWLER) { return TRUE; };
    };
    // если охотник ящерица
    if(slf.guild == GIL_WARAN)
    {
    if(oth.guild == GIL_SCAVENGER) { return TRUE; };
    if(oth.guild == GIL_HARPY) { return TRUE; };
    if(oth.guild == GIL_GOBBO) { return TRUE; };
    };
    // если охотник волк, но не кабан
    if(slf.guild == GIL_WOLF) && (slf.aivar[AIV_MM_REAL_ID] != ID_Keiler)
    {
    if(oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    if(oth.guild == GIL_SHEEP) { return TRUE; };
    if(oth.guild == GIL_GIANT_RAT) { return TRUE; };
    if(oth.guild == GIL_MOLERAT) { return TRUE; };
    };
    // если охотник вызванный волк
    if(slf.guild == GIL_SUMMONED_WOLF)
    {
    if(oth.guild == GIL_SHEEP) { return TRUE; };
    if(oth.guild == GIL_GIANT_RAT) { return TRUE; };
    if(oth.guild == GIL_MOLERAT) { return TRUE; };
    };
    // если охотник ползун
    if(slf.guild == GIL_MINECRAWLER)
    {
    if(oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    if(oth.guild > GIL_SEPERATOR_ORC) { return TRUE; };
    if(oth.guild == GIL_MEATBUG) { return TRUE; };
    if(oth.guild == GIL_GIANT_BUG) { return TRUE; };
    if(oth.guild == GIL_BLOODFLY) { return TRUE; };
    };
    // если охотник шныг
    if(slf.guild == GIL_LURKER)
    {
    if (oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    if (oth.guild > GIL_SEPERATOR_ORC) { return TRUE; };
    if (oth.guild == GIL_GOBBO) { return TRUE; };
    };
    // если охотник зомби
    if (slf.guild == GIL_ZOMBIE)
    {
    if (oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    if (oth.guild > GIL_SEPERATOR_ORC) { return TRUE; };
    };
    // если охотник глорх
    if (slf.guild == GIL_SNAPPER)
    {
    if (oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    if (oth.guild > GIL_SEPERATOR_ORC) { return TRUE; };
    if (oth.guild == GIL_SHEEP) { return TRUE; };
    if (oth.guild == GIL_GIANT_RAT) { return TRUE; };
    if (oth.guild == GIL_MOLERAT) { return TRUE; };
    if (oth.guild == GIL_SCAVENGER) { return TRUE; };
    if (oth.guild == GIL_HARPY) { return TRUE; };
    if (oth.guild == GIL_WOLF) { return TRUE; };
    if (oth.guild == GIL_SUMMONED_WOLF) { return TRUE; };
    if (oth.guild == GIL_SHADOWBEAST) { return TRUE; };
    if (oth.guild == GIL_GOBBO) { return TRUE; };
    if (oth.guild == GIL_WARAN) { return TRUE; };
    if (oth.guild == GIL_LURKER) { return TRUE; };
    };
    // если охотник мракорис
    if (slf.guild == GIL_SHADOWBEAST)
    {
    if (oth.guild < GIL_SEPERATOR_HUM) { return TRUE; };
    if (oth.guild > GIL_SEPERATOR_ORC) { return TRUE; };
    if (oth.guild == GIL_SHEEP) { return TRUE; };
    if (oth.guild == GIL_GIANT_RAT) { return TRUE; };
    if (oth.guild == GIL_MOLERAT) { return TRUE; };
    if (oth.guild == GIL_SCAVENGER) { return TRUE; };
    if (oth.guild == GIL_HARPY) { return TRUE; };
    if (oth.guild == GIL_WOLF) { return TRUE; };
    if (oth.guild == GIL_SUMMONED_WOLF) { return TRUE; };
    if (oth.guild == GIL_GOBBO) { return TRUE; };
    if (oth.guild == GIL_WARAN) { return TRUE; };
    if (oth.guild == GIL_LURKER) { return TRUE; };
    if (oth.guild == GIL_SNAPPER) { return TRUE; };
    };
    return FALSE;
    };
     
    Ur-tRall и Валера сказали Спасибо
  8. MEG@VOLT

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

    Регистрация:
    24 мар 2006
    Сообщения:
    1.566
    Благодарности:
    628
    Баллы:
    290
    19. Обработчики состояний функций распорядка дня для людей.

    Все обработчики расположены в директории ..\AI\Human\TA_Human
    // ******************************************
    // Объявления Герольда
    // ------------------------------------------

    Открыть спойлер
    // self - герольд, hero - ГГ
    // ******************************************


    // Функция инициализации состояния
    func void ZS_Announce_Herold()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // разрешить восприятие тихих звуков (шаги, звон падающего предмета)
    Npc_PercDisable(self,PERC_ASSESSQUIETSOUND);
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    // выравнивание на вайпоинте
    AI_AlignToWP(self);
    // сброс флага цикла
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };

    // Функция цикла состояния
    func int ZS_Announce_Herold_loop()
    {
    // если время цикла > 70 сек и ГГ ни с кем не разговаривает
    if(Npc_GetStateTime(self) >= 70) && (hero.aivar[AIV_INVINCIBLE] == FALSE)
    {
    // анимация перехода в состояние чтения
    AI_PlayAni(self,"T_HGUARD_2_STAND");
    // сброс флага
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    // зачитывание приказов
    B_Announce_Herold();
    // сброс времени цикла
    Npc_SetStateTime(self, 0);
    };
    // если флаг сброшен
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS)
    {
    // анимация перехода в обычное состояние
    AI_PlayAni (self,"T_STAND_2_HGUARD");
    // установка флага
    self.aivar[AIV_TAPOSITION] = ISINPOS;
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Announce_Herold_end()
    {
    }
    ;





    // ***************************************
    // Обработчик поведения бандита
    // ***************************************

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

    // Функция инициализации состояния
    func void ZS_Bandit()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если расстояние между бандитом и его вайпоинтом > дистанции выполнения функций
    if(Npc_GetDistToWP(self,self.wp) > TA_DIST_SELFWP_MAX)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // сброс флага цикла
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };

    // Функция цикла состояния
    func int ZS_Bandit_loop()
    {
    // если флаг сброшен
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS)
    {
    // если бандит не у костра и костер имеется (Примечание: "костер" это ближайший свободный фрипоинт с именем FP_CAMPFIRE_xx, в дальнейшем буду использовать только сокращенное описание)
    if(!Npc_IsOnFP(self,"CAMPFIRE")) && (Wld_IsFPAvailable(self,"CAMPFIRE"))
    {
    // бандит идет к костру
    AI_GotoFP(self,"CAMPFIRE");
    // выравнивается
    AI_AlignToFP(self);
    // садится
    AI_PlayAniBS(self,"T_STAND_2_SIT",BS_SIT);
    }
    // если бандит не на своем месте и место имеется (свободно)
    else if(!Npc_IsOnFP(self,"STAND")) && (Wld_IsFPAvailable(self,"STAND"))
    {
    // бандит идет к месту
    AI_GotoFP(self,"STAND");
    // выравнивается
    AI_AlignToFP(self);
    // охраняет
    AI_PlayAni(self,"T_STAND_2_HGUARD");
    }
    else // иначе
    {
    // выравнивается
    AI_AlignToWP(self);
    // охраняет
    AI_PlayAni(self,"T_STAND_2_HGUARD");
    };
    // установка флага
    self.aivar[AIV_TAPOSITION] = ISINPOS;
    };
    // если прошло 5 сек и флаг установлен и бандит не сидит
    if(Npc_GetStateTime(self) > 5) && (self.aivar[AIV_TAPOSITION] == ISINPOS) && (!C_BodyStateContains(self,BS_SIT))
    {
    var int random;
    random = Hlp_Random(3);
    // с вероятностью 0.33
    if(random == 0)
    {
    // анимация осмотра
    AI_PlayAni(self,"T_HGUARD_LOOKAROUND");
    };
    // сброс времени цикла
    Npc_SetStateTime (self, 0);
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Bandit_end()
    {
    // если бандит сидит
    if(C_BodyStateContains(self,BS_SIT))
    {
    // встает
    AI_PlayAniBS(self,"T_SIT_2_STAND",BS_STAND);
    }
    else // иначе
    {
    // просто стоит
    AI_PlayAni(self,"T_HGUARD_2_STAND");
    };
    };





    // ************************************
    // Обработчик ритуала в Круге солнца
    // ************************************

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

    // Функция инициализации состояния
    func void ZS_Circle()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить время реакции на восприятия 0.3 сек
    Npc_SetPercTime(self,0.3);
    // НПС встает
    AI_StandUp(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // движение в Круг солнца
    AI_GotoWP(self,self.wp);
    // выравнивание
    AI_AlignToWP(self);
    };

    // Функция цикла состояния
    func int ZS_Circle_Loop ()
    {
    var int randy;
    var int randyKDW;
    var int randyKDW_Lightstar;
    // если НПС черный маг
    if(self.guild == GIL_DMT)
    {
    randy = Hlp_Random(3000);
    // случайное время
    if(Npc_GetStateTime(self) > randy)
    {
    // анимация "Дрожь земли"
    Wld_PlayEffect("FX_EarthQuake",self,self,0,0,0,FALSE);
    // сброс времени цикла
    Npc_SetStateTime(self,0);
    // анимация красного экрана
    Wld_PlayEffect("spellFX_INCOVATION_RED",self,self,0,0,0,FALSE);
    // упражнение в магии
    AI_PlayAni(self,"T_PRACTICEMAGIC5");
    };
    }
    // если НПС маг воды
    else if(self.guild == GIL_KDW)
    {
    randyKDW = Hlp_Random(2500);
    randyKDW_Lightstar= Hlp_Random(2);
    // случайное время
    if(Npc_GetStateTime(self) > randyKDW)
    {
    // выравнивание
    AI_AlignToWP(self);
    // сброс времени цикла
    Npc_SetStateTime(self,0);
    // анимация "Дрожь земли"
    Wld_PlayEffect("FX_EarthQuake",self,self,0,0,0,FALSE );
    // упражнение в магии
    AI_PlayAni(self,"T_PRACTICEMAGIC5");
    // далее какие-то эффекты, кто знает, что делают маги воды в Круге солнца, может написать
    Wld_PlayEffect("spellFX_RingRitual2",ItMi_AmbossEffekt_Addon,ItMi_AmbossEffekt_Addon,0,0,0,FALSE);
    if(randyKDW_Lightstar == 0)
    {
    Wld_PlayEffect("spellFX_RingRitual1",ItMi_AmbossEffekt_Addon,ItMi_AmbossEffekt_Addon,0,0,0,FALSE);
    }
    else if(randyKDW_Lightstar == 1)
    {
    Wld_PlayEffect("spellFX_LIGHTSTAR_RingRitual",ItMi_AmbossEffekt_Addon,ItMi_AmbossEffekt_Addon,0,0,0,FALSE);
    };
    };
    }
    // если квест по восстановлению Глаза Инноса не завершен
    else if(MIS_RitualInnosEyeRepair != LOG_SUCCESS)
    {
    randy = Hlp_Random(1000);
    // случайное время
    if(Npc_GetStateTime(self) > randy)
    {
    // сброс времени цикла
    Npc_SetStateTime(self,0);
    // анимация "Дрожь земли"
    Wld_PlayEffect("FX_EarthQuake",self,self,0,0,0,FALSE);
    // упражнение в магии
    AI_PlayAni(self,"T_PRACTICEMAGIC5");
    // если НПС Ксардас
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Xardas))
    {
    // анимация фиолетового экрана
    Wld_PlayEffect("spellFX_INCOVATION_VIOLET",self,self,0,0,0,FALSE);
    }
    // если НПС Пирокар
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Pyrokar))
    {
    // анимация красного экрана
    Wld_PlayEffect("spellFX_INCOVATION_RED",self,self,0,0,0,FALSE);
    }
    else // иначе Ватрас
    {
    // анимация голубого экрана
    Wld_PlayEffect("spellFX_INCOVATION_BLUE",self,self,0,0,0,FALSE);
    };
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Circle_End()
    {
    }
    ;





    // ***************************************
    // Обработчик концерта InExtremo в аддоне
    // ***************************************

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

    // Функция инициализации состояния
    func void ZS_Concert()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если расстояние между НПС и его вайпоинтом > дистанции выполнения функций
    if (Npc_GetDistToWP(self,self.wp) > TA_DIST_SELFWP_MAX)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // сброс флага цикла
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };

    // Функция цикла состояния
    func int ZS_Concert_Loop ()
    {
    // если флаг сброшен
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS)
    {
    // если НПС "Yellow Pfeiffer"
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1394_Addon_InExtremo_YellowPfeiffer))
    {
    // использует Желтую волынку
    AI_UseItemToState(self,ItMi_IEDudelGelb,1);
    }
    // если НПС "Dr. Pymonte"
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1390_Addon_InExtremo_DrPymonte))
    {
    // использует Арфу
    AI_UseItemToState(self,ItMi_IEHarfe,1);
    }
    // если НПС "The Flail"
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1391_Addon_InExtremo_TheFlail))
    {
    // использует Drum
    AI_UseItemToState(self,ItMi_iedrum,1);
    }
    // если НПС "Thomas the forger"
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1392_Addon_InExtremo_ThomasTheForger))
    {
    // использует Виолончель
    AI_UseItemToState(self,ItMi_IECello,1);
    }
    // если НПС "Unicorn"
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1393_Addon_InExtremo_Unicorn))
    {
    // использует Лютню
    AI_UseItemToState(self,ItMi_IELaute,1);
    }
    // если НПС "Lutter"
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1395_Addon_InExtremo_Lutter))
    {
    // использует Drumscheit
    AI_UseItemToState(self,ItMi_IEDrumscheit,1);
    }
    // если НПС "Flex"
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1396_Addon_InExtremo_Flex))
    {
    // использует Голубую волынку
    AI_UseItemToState(self,ItMi_IEDudelBlau,1);
    }
    else
    {
    // Танцы пиратов?
    };
    // установка флага
    self.aivar[AIV_TAPOSITION] = ISINPOS;
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Concert_End()
    {
    // шестерка музыкантов, кроме Flexа, убирают свои инструменты
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1394_Addon_InExtremo_YellowPfeiffer))
    {
    AI_UseItemToState(self,ItMi_IEDudelGelb,-1);
    }
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1390_Addon_InExtremo_DrPymonte))
    {
    AI_UseItemToState(self,ItMi_IEHarfe,-1);
    }
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1391_Addon_InExtremo_TheFlail))
    {
    AI_UseItemToState(self,ItMi_iedrum,-1);
    }
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1392_Addon_InExtremo_ThomasTheForger))
    {
    AI_UseItemToState(self,ItMi_IECello,-1);
    }
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1393_Addon_InExtremo_Unicorn))
    {
    AI_UseItemToState(self,ItMi_IELaute,-1);
    }
    else if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PIR_1395_Addon_InExtremo_Lutter))
    {
    AI_UseItemToState(self,ItMi_IEDrumscheit,-1);
    };
    };



    // ***************************************
    // Обработчик приготовления пищи в котле
    // ***************************************

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

    // Функция инициализации состояния
    func void ZS_Cook_Cauldron()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если НПС расположен не на своем вайпоинте
    if(Hlp_StrCmp(Npc_GetNearestWP(self),self.wp) == FALSE)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // если НПС не имеет ложки
    if(Npc_HasItems(self,ItMi_Scoop) == 0)
    {
    // создать в инвентаре НПС ложку
    CreateInvItem(self,ItMi_Scoop);
    };
    };

    // Функция цикла состояния
    func int ZS_Cook_Cauldron_Loop()
    {
    // если действие с МОВом не прерываемо и котел имеется
    if(!C_BodyStateContains(self,BS_MOBINTERACT_INTERRUPT)) && (Wld_IsMobAvailable(self,"CAULDRON"))
    {
    // мешать ложкой в котле
    AI_UseMob(self,"CAULDRON",1);
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Cook_Cauldron_End()
    {
    // прекратить использовать котел
    AI_UseMob(self,"CAULDRON",-1);
    };





    // *******************************************
    // Обработчик приготовления пищи на сковороде
    // *******************************************

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

    // Функция инициализации состояния
    func void ZS_Cook_Pan()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если НПС расположен не на своем вайпоинте
    if(Hlp_StrCmp(Npc_GetNearestWP(self),self.wp) == FALSE)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // если НПС не имеет Сырого мяса
    if(Npc_HasItems(self,ItFoMuttonRaw) == 0)
    {
    // создать в инвентаре НПС Сырое мясо
    CreateInvItem(self,ItFoMuttonRaw);
    };
    };

    // Функция цикла состояния
    func int ZS_Cook_Pan_Loop()
    {
    // если действие с МОВом не прерываемо и сковорода имеется
    if(!C_BodyStateContains(self,BS_MOBINTERACT_INTERRUPT)) && (Wld_IsMobAvailable(self,"PAN"))
    {
    // жарить мясо
    AI_UseMob(self,"PAN",1);
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Cook_Pan_End()
    {
    // прекратить использовать котел
    AI_UseMob(self,"PAN",-1);
    // съесть жареное мясо
    AI_UseItem(self,ItFoMutton);
    };





    // *************************************
    // Обработчик приготовления пищи в печи
    // *************************************

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

    // Функция инициализации состояния
    func void ZS_Cook_Stove()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если НПС расположен не на своем вайпоинте
    if(Hlp_StrCmp(Npc_GetNearestWP(self),self.wp) == FALSE)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // если НПС не имеет Сырого мяса
    if(Npc_HasItems(self,ItFoMuttonRaw) == 0)
    {
    // создать в инвентаре НПС Сырое мясо
    CreateInvItem(self,ItFoMuttonRaw);
    };
    };

    // Функция цикла состояния
    func int ZS_Cook_Stove_Loop()
    {
    // если действие с МОВом не прерываемо и печь имеется
    if(!C_BodyStateContains(self,BS_MOBINTERACT_INTERRUPT)) && (Wld_IsMobAvailable(self,"STOVE"))
    {
    // жарить мясо
    AI_UseMob(self,"STOVE",1);
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Cook_Stove_End()
    {
    // прекратить использовать печь
    AI_UseMob(self,"STOVE",-1);
    // если НПС имеет больше 1 куска жареного мяса
    if(Npc_HasItems(self,ItFoMutton) >=1 )
    {
    // удалить из инветаря НПС 1 кусок жареного мяса
    Npc_RemoveInvItems(self,ItFoMutton,1);
    };
    };





    // ***********************
    // Обработчик танцев НПС
    // ***********************

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

    // Функция инициализации состояния
    func void ZS_Dance()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если расстояние между НПС и его вайпоинтом > дистанции выполнения функций
    if(Npc_GetDistToWP(self,self.wp) > TA_DIST_SELFWP_MAX)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    // выравнивание
    AI_AlignToWP(self);
    };
    };

    // Функция цикла состояния
    func int ZS_Dance_Loop()
    {
    var int danceStyle;
    danceStyle = Hlp_Random(9);
    // случайная анимация фаз танца
    if(danceStyle == 0)
    {
    AI_PlayAni(self,"T_DANCE_01");
    };
    if(danceStyle == 1)
    {
    AI_PlayAni(self,"T_DANCE_02");
    };
    if(danceStyle == 2)
    {
    AI_PlayAni(self,"T_DANCE_03");
    };
    if(danceStyle == 3)
    {
    AI_PlayAni(self,"T_DANCE_04");
    };
    if(danceStyle == 4)
    {
    AI_PlayAni(self,"T_DANCE_05");
    };
    if(danceStyle == 5)
    {
    AI_PlayAni(self,"T_DANCE_06");
    };
    if(danceStyle == 6)
    {
    AI_PlayAni(self,"T_DANCE_07");
    };
    if(danceStyle == 7)
    {
    AI_PlayAni(self,"T_DANCE_08");
    };
    if(danceStyle == 8 )
    {
    AI_PlayAni(self,"T_DANCE_09");
    };
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    // выравнивание
    AI_AlignToWP(self);
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Dance_End()
    {
    // танцор останавливается
    AI_StandUp(self);
    };





    // **************************************
    // Обработчик убегания НПС на свою точку
    // **************************************

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

    // Функция инициализации состояния
    func void ZS_FleeToWp()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // если НПС Корнелиус
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Cornelius))
    {
    // закрыть восприятие входа в помещение
    Npc_PercDisable(self,PERC_ASSESSENTERROOM);
    };
    // установить режим передвижения бегом
    AI_SetWalkmode(self,NPC_RUN);
    // включить модель убегающего человека
    Mdl_ApplyOverlayMds(self,"HUMANS_FLEE.MDS");
    // если расстояние между НПС и его вайпоинтом > дистанции выполнения функций
    if(Npc_GetDistToWP (self,self.wp) > TA_DIST_SELFWP_MAX)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // выравнивание
    AI_AlignToWP(self);
    // анимация состояния охраны
    AI_PlayAni(self,"T_STAND_2_HGUARD");
    };

    // Функция цикла состояния
    func int ZS_FleeToWp_Loop()
    {
    // если время в состоянии > 5 сек
    if(Npc_GetStateTime(self) > 5)
    {
    var int random;
    random = Hlp_Random(2);
    // с вероятностью 0.5
    if(random == 0)
    {
    // осмотреть окресности
    AI_PlayAni(self,"T_HGUARD_LOOKAROUND");
    };
    // сброс времени состояния
    Npc_SetStateTime(self,0);
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func int ZS_FleeToWp_End()
    {
    };



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

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

    // Функция локального восприятия НПС на ГГ
    func void B_AssessFollowPlayer()
    {
    // если НПС Диего в Минентале
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(DiegoOW))
    {
    // расстояние между НПС и ГГ < дистанции следования и флаг сброшен (НПС движется)
    if(Npc_GetDistToNpc(self,hero) < self.aivar[AIV_FollowDist]) && (self.aivar[AIV_TAPOSITION] == FALSE)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает (ждет действий ГГ)
    AI_StandUp(self);
    // установить флаг (НПС остановился)
    self.aivar[AIV_TAPOSITION] = TRUE;
    }
    // если Диего слишком далеко и флаг сброшен
    else if(C_DiegoTooFar(0)) && (self.aivar[AIV_TAPOSITION] == FALSE)
    {
    // очистить очередь AI состояний Диего
    Npc_ClearAIQueue(self);
    // Диего встает (ждет действий ГГ)
    AI_StandUp(self);
    // установить флаг
    self.aivar[AIV_TAPOSITION] = TRUE;
    // если расстояние между Диего и ГГ > дистанции начала разговора
    if(Npc_GetDistToNpc(self,hero) > PERC_DIST_DIALOG)
    {
    // Диего говорит ГГ (SVM фраза) "Подожди!" (Примечание: правильней other заменить на hero)
    B_Say(self,other,"$SC_HEYWAITASECOND");
    };
    }
    else // иначе
    {
    // обычная реакция НПС на ГГ
    B_AssessPlayer();
    };
    return;
    };
    // расстояние между НПС и ГГ < дистанции следования и флаг сброшен
    if(Npc_GetDistToNpc(self,hero) < self.aivar[AIV_FollowDist]) && (self.aivar[AIV_TAPOSITION] == FALSE)
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает (ждет действий ГГ)
    AI_StandUp(self);
    // установить флаг
    self.aivar[AIV_TAPOSITION] = TRUE;
    }
    else
    {
    // обычная реакция НПС на ГГ
    B_AssessPlayer();
    };
    };

    // Функция локального восприятия НПС на звук сражения
    func void B_AssessFollowFightSound()
    {
    // если other (нападающий) есть ГГ или victim (жертва) есть ГГ или
    if(Npc_IsPlayer(other)) || (Npc_IsPlayer(victim))
    || (other.aivar[AIV_PARTYMEMBER] == TRUE) // other - член партии ГГ
    || (victim.aivar[AIV_PARTYMEMBER] == TRUE) // или victim - член партии ГГ
    {
    // обычная реакция НПС на звук сражения
    B_AssessFightSound();
    };
    };

    // Данная функция не используется и может быть удалена.
    func void B_MoveFollowNpc()
    {
    }
    ;

    // Функция инициализации состояния
    func void ZS_Follow_Player()
    {
    // разрешить НПС все чувства
    self.senses = SENSE_SEE|SENSE_HEAR|SENSE_SMELL;
    // установить дальность чувств 20 метров
    self.senses_range = 2000;
    // установить время реакции на восприятия 0.3 сек
    Npc_SetPercTime(self,0.3);
    // разрешить минимальный набор восприятий
    Perception_Set_Minimal();
    // установить локальное восприятие НПС на ГГ
    Npc_PercEnable(self,PERC_ASSESSPLAYER,B_AssessFollowPlayer);
    // разрешить восприятие врага
    Npc_PercEnable(self,PERC_ASSESSENEMY,B_AssessEnemy);
    // разрешить восприятие разговора
    Npc_PercEnable(self,PERC_ASSESSTALK,B_AssessTalk);
    // разрешить восприятие перемещения МОВа
    Npc_PercEnable(self,PERC_MOVEMOB,B_MoveMob);
    // установить локальное восприятие звуков сражения
    Npc_PercEnable(self,PERC_ASSESSFIGHTSOUND,B_AssessFollowFightSound);
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // НПС встает
    AI_StandUp(self);
    // установить режим передвижения бегом
    AI_SetWalkmode(self,NPC_RUN);
    // если дистанция между НПС не задана
    if(self.aivar[AIV_FollowDist] == 0)
    {
    // задать дистанцию 5м
    self.aivar[AIV_FollowDist] = 500;
    };
    };

    // Функция цикла состояния
    func int ZS_Follow_Player_Loop()
    {
    // расстояние между НПС и ГГ > дистанции следования
    if(Npc_GetDistToNpc(self,hero) > self.aivar[AIV_FollowDist])
    {
    // если НПС Диего в Минентале
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(DiegoOW))
    {
    // если Диего слишком далеко
    if(C_DiegoTooFar(0))
    {
    // если прошло > 1 сек
    if(Npc_GetStateTime(self) > 1)
    {
    // Диего поворачивается к ГГ
    B_TurnToNpc(self,hero);
    // сброс времени цикла
    Npc_SetStateTime(self,0);
    };
    return LOOP_CONTINUE;
    };
    };
    // если НПС не плывет
    if(!C_BodyStateContains(self,BS_SWIM))
    {
    // установить режим передвижения бегом
    AI_SetWalkmode(self,NPC_RUN);
    };
    // НПС движется к ГГ
    AI_GotoNpc(self,hero);
    // сброс флага (НПС в движении)
    self.aivar[AIV_TAPOSITION] = FALSE;
    }
    else // расстояние < дистанции следования
    {
    // если прошло > 1 сек
    if(Npc_GetStateTime(self) > 1)
    {
    // НПС поворачивается к ГГ
    B_TurnToNpc(self,hero);
    // сброс времени цикла
    Npc_SetStateTime(self,0);
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Follow_Player_End()
    {
    }
    ;





    // **********************************
    // Обработчик поведения призраков
    // **********************************

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

    // Функция инициализации состояния
    func void ZS_Ghost()
    {
    var c_npc Quarho;
    // получить ссылку на Куарходрона
    Quarho = Hlp_GetNpc(NONE_ADDON_111_Quarhodron);
    // если НПС Куарходрон
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Quarho))
    {
    // если информация о "Камерах Аданоса" не известна
    if(Ghost_SCKnowsHow2GetInAdanosTempel == FALSE)
    {
    // разрешить восприятие разговора
    Npc_PercEnable(self,PERC_ASSESSTALK,B_AssessTalk);
    };
    }
    else
    {
    // разрешить восприятие разговора
    Npc_PercEnable(self,PERC_ASSESSTALK,B_AssessTalk);
    };
    // разрешить восприятие повреждения
    Npc_PercEnable(self,PERC_ASSESSDAMAGE,B_AssessDamage);
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить время реакции на восприятия 0.1 сек
    Npc_SetPercTime(self,0.1);
    // НПС встает
    AI_StandUp(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // движение на свой вайпоинт
    AI_GotoWP(self, self.wp);
    // выравнивание
    AI_AlignToWP(self);
    };

    // Функция цикла состояния
    func int ZS_Ghost_Loop()
    {
    // если прошло >= 5 сек
    if(Npc_GetStateTime(self) >= 5)
    {
    // если расстояние между НПС и ГГ > дистанции начала диалога
    if(Npc_GetDistToNpc(self,hero) > PERC_DIST_DIALOG)
    {
    // выравнивание
    AI_AlignToWP(self);
    // сброс времени состояния
    Npc_SetStateTime(self,0);
    };
    // удалить призрака
    B_RemoveGhost();
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Ghost_End()
    {
    }
    ;


    // ******************************
    // Обработчик поведения Радемеса
    // ******************************

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

    // Функция инициализации состояния
    func void ZS_GhostWusel()
    {
    // разрешить восприятие разговора
    Npc_PercEnable(self,PERC_ASSESSTALK,B_AssessTalk);
    // разрешить восприятие повреждения
    Npc_PercEnable(self,PERC_ASSESSDAMAGE,B_AssessDamage);
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // НПС встает
    AI_StandUp(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если НПС расположен не на своем вайпоинте
    if(Hlp_StrCmp(Npc_GetNearestWP(self),self.wp) == FALSE)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // движение на свободный фрипоинт
    AI_GotoFP(self,"FP_ROAM");
    };

    // Функция цикла состояния (Радемес бродит по фрипоинтам)
    func int ZS_GhostWusel_Loop()
    {
    // если прошло >= 3 сек
    if(Npc_GetStateTime(self) >= 3)
    {
    // если Радемес находится на фрипоинте
    if(Npc_IsOnFP(self,"FP_ROAM"))
    {
    // если есть свободный следующий фрипоинт
    if(Wld_IsNextFPAvailable(self,"FP_ROAM"))
    {
    // очистка очереди AI ссостояний НПС
    Npc_ClearAIQueue(self);
    // переход на следующий фрипоинт
    AI_GotoNextFP(self,"FP_ROAM");
    };
    }
    else // не на фрипоинте
    {
    // если НПС не передвигается
    if(!C_BodyStateContains(self,BS_WALK)) && (!C_BodyStateContains(self,BS_RUN))
    {
    // перейти на фрипоинт
    AI_GotoFP(self,"FP_ROAM");
    };
    };
    // сброс времени состояния
    Npc_SetStateTime(self,0);
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_GhostWusel_End()
    {
    }
    ;




    // **********************************
    // Охрана Святого молота Гарвигом
    // **********************************

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

    // Функция инициализации состояния
    func void ZS_Guard_Hammer()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если расстояние между НПС и его вайпоинтом > дистанции выполнения функций
    if(Npc_GetDistToWP(self,self.wp) > TA_DIST_SELFWP_MAX)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // сброс флага цикла
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };

    // Функция цикла состояния
    func int ZS_Guard_Hammer_loop()
    {
    // если НПС находится на фрипоинте охраны
    if(Npc_IsOnFP(self,"STAND"))
    {
    // выравнивание
    AI_AlignToFP(self);
    // если НПС шел на фрипоинт
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS_WALK)
    {
    // сброс флага
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };
    }
    // если фрипоинт существует и свободен
    else if(Wld_IsFPAvailable(self,"STAND"))
    {
    // идти на фрипоинт
    AI_GotoFP(self,"STAND");
    // встать
    AI_StandUp(self);
    // выровняться
    AI_AlignToFP(self);
    // установить флаг перемещения
    self.aivar[AIV_TAPOSITION] = NOTINPOS_WALK;
    }
    else // фрипоинт занят
    {
    // выровняться на вайпоинте
    AI_AlignToWP(self);
    // если НПС шел в точку
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS_WALK)
    {
    // сброс флага
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };
    };
    // если флаг сброшен
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS)
    {
    // анимация перехода в режим охраны
    AI_PlayAni(self,"T_STAND_2_HGUARD");
    // установить флаг охраны
    self.aivar[AIV_TAPOSITION] = ISINPOS;
    };
    // если НПС имеет Святой молот и расстояние до места хранения молота < 5м
    if(Npc_HasItems(self,Holy_Hammer_MIS) == 1) && (Npc_GetDistToWP(self,"NW_MONASTERY_SANCTUM_01") <= 500)
    {
    // изъять из инвентаря НПС Святой молот
    Npc_RemoveInvItems(self,Holy_Hammer_MIS,1);
    // положить молот в точку хранения
    Wld_InsertItem(Holy_Hammer_MIS,"FP_HAMMER");
    };
    // если прошло > 5 сек и НПС находится в режиме охраны
    if((Npc_GetStateTime(self) > 5) && (self.aivar[AIV_TAPOSITION] == ISINPOS))
    {
    var int random;
    random = Hlp_Random(10);
    // с вероятностью 0.1
    if(random == 0)
    {
    // осмотреть окрестности
    AI_PlayAni(self,"T_HGUARD_LOOKAROUND");
    };
    // сброс времени цикла
    Npc_SetStateTime(self,0);
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Guard_Hammer_end()
    {
    // анимация перехода из состояния охраны в стоячее
    AI_PlayAni(self,"T_HGUARD_2_STAND");
    };





    // ************************
    // Охрана прохода НПС
    // ************************

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

    // Функция инициализации состояния
    func void ZS_Guard_Passage()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll (self);
    // установить время реакции на восприятия 0.1 сек
    Npc_SetPercTime(self,0.1);
    // НПС встает
    AI_StandUp(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    // если расстояние между НПС и ГГ > дистанции диалога
    if(Npc_GetDistToNpc(self,hero) > PERC_DIST_DIALOG)
    {
    // выровняться
    AI_AlignToWP(self);
    };
    };

    // Функция цикла состояния
    func int ZS_Guard_Passage_Loop()
    {
    // если прошло >= 3 сек
    if (Npc_GetStateTime(self) >= 3)
    {
    // если расстояние между НПС и ГГ > дистанции диалога
    if(Npc_GetDistToNpc(self,hero) > PERC_DIST_DIALOG)
    {
    // выровняться
    AI_AlignToWP(self);
    // сброс времени цикла
    Npc_SetStateTime(self,0);
    };
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Guard_Passage_End ()
    {
    }
    ;





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

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

    // Функция локального восприятия НПС на ГГ
    func void B_AssessGuidePlayer()
    {
    // если расстояние между НПС и ГГ > 8м
    if(Npc_GetDistToNpc(self,hero) > 800)
    {
    // если расстояние от НПС до его вайпоинта < расстояния от ГГ до этого же вайпоинта
    if(Npc_GetDistToWP(self,self.wp) < Npc_GetDistToWP(hero,self.wp))
    {
    // очистить очередь AI состояний НПС
    Npc_ClearAIQueue(self);
    // НПС встает
    AI_StandUp(self);
    // НПС поворачивается к ГГ
    B_TurnToNpc(self,hero);
    };
    // если расстояние между НПС и ГГ > 12м и враги у НПС есть и отношения между НПС и ГГ враждебные
    if(Npc_GetDistToNpc(self,hero) > 1200) && (self.aivar[AIV_EnemyOverride] == TRUE) && (Npc_GetAttitude(self,hero) == ATT_HOSTILE)
    {
    // сброс флага врагов (врагов и НПС нет)
    self.aivar[AIV_EnemyOverride] = FALSE;
    };
    }
    else
    {
    // обычная реакция НПС на ГГ
    B_AssessPlayer();
    };
    };

    // Функция локального восприятия НПС на звук сражения
    func void B_AssessGuideFightSound()
    {
    // если other (нападающий) есть ГГ или victim (жертва) есть ГГ
    if(Npc_IsPlayer(other)) || (Npc_IsPlayer(victim))
    {
    // обычная реакция НПС на звук сражения
    B_AssessFightSound();
    };
    };

    // Функция инициализации состояния
    func void ZS_Guide_Player()
    {
    // разрешить минимальный набор восприятий
    Perception_Set_Minimal();
    // перевод НПС в исходное состояние
    B_ResetAll (self);
    // разрешить НПС все чувства
    self.senses = SENSE_SEE | SENSE_HEAR | SENSE_SMELL;
    // установить дальность чувств 20 метров
    self.senses_range = 2000;
    // установить время реакции НПС на восприятия 1 сек
    Npc_SetPercTime(self,1);
    // установить локальное восприятие НПС на ГГ
    Npc_PercEnable(self,PERC_ASSESSPLAYER,B_AssessGuidePlayer);
    // разрешить восприятие врага
    Npc_PercEnable(self,PERC_ASSESSENEMY,B_AssessEnemy);
    // разрешить восприятие разговора
    Npc_PercEnable(self,PERC_ASSESSTALK,B_AssessTalk);
    // разрешить восприятие перемещения МОВа
    Npc_PercEnable(self,PERC_MOVEMOB,B_MoveMob);
    // установить локальное восприятие звуков сражения
    Npc_PercEnable(self,PERC_ASSESSFIGHTSOUND,B_AssessGuideFightSound);
    };

    // Функция цикла состояния
    func int ZS_Guide_Player_Loop()
    {
    // если расстояние между НПС и ГГ > 8м и расстояние от НПС до его вайпоинта < расстояния от ГГ до этого же вайпоинта
    if(Npc_GetDistToNpc(self,hero) > 800) && (Npc_GetDistToWP(self,self.wp) < Npc_GetDistToWP(hero,self.wp))
    {
    // локальная реакция НПС на ГГ
    B_AssessGuidePlayer();
    }
    // если расстояние между НПС и его вайпоинтом > 3м
    else if(Npc_GetDistToWP(self,self.wp) > 300)
    {
    // если НПС не плывет
    if(!C_BodyStateContains(self,BS_SWIM))
    {
    // установить режим передвижения бегом
    AI_SetWalkmode(self,NPC_RUN);
    };
    // движение НПС на вайпоинт
    AI_GotoWP(self,self.wp);
    }
    else
    {
    // НПС поворачивается к ГГ
    B_TurnToNpc(self,hero);
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func int ZS_Guide_Player_End()
    {
    };





    // *****************************
    // НПС справляет малую нужду
    // *****************************

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

    // Функция инициализации состояния
    func void ZS_Pee()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(self,NPC_WALK);
    // если расстояние между НПС и его вайпоинтом > дистанции выполнения функций
    if(Npc_GetDistToWP(self,self.wp) > TA_DIST_SELFWP_MAX)
    {
    // движение на свой вайпоинт
    AI_GotoWP(self,self.wp);
    };
    // сброс флага цикла
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };

    // Функция цикла состояния
    func int ZS_Pee_loop()
    {
    // если НПС на нужном фрипоинте
    if(Npc_IsOnFP(self,"PEE"))
    {
    // выравнивание
    AI_AlignToFP(self);
    // если НПС шел на фрипоинт
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS_WALK)
    {
    // сброс флага
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };
    }
    // если фрипоинт существует и свободен
    else if(Wld_IsFPAvailable(self,"PEE"))
    {
    // идти на фрипоинт
    AI_GotoFP(self,"PEE");
    // встать
    AI_StandUp(self);
    // выровняться
    AI_AlignToFP(self);
    // установить флаг перемещения
    self.aivar[AIV_TAPOSITION] = NOTINPOS_WALK;
    }
    else // фрипоинт занят
    {
    // выровняться на вайпоинте
    AI_AlignToWP(self);
    // если НПС шел в точку
    if(self.aivar[AIV_TAPOSITION] == NOTINPOS_WALK)
    {
    // сброс флага
    self.aivar[AIV_TAPOSITION] = NOTINPOS;
    };
    };
    // если флаг сброшен и НПС на нужном фрипоинте
    if((self.aivar[AIV_TAPOSITION] == NOTINPOS) && (Npc_IsOnFP(self,"PEE")))
    {
    // выровняться
    AI_AlignToFP(self);
    // встать
    AI_StandUp(self);
    // анимация мочеиспускания
    AI_PlayAni(self,"T_STAND_2_PEE");
    // установить флаг выполнения нужной функции
    self.aivar[AIV_TAPOSITION] = ISINPOS;
    };
    return LOOP_CONTINUE;
    };

    // Функция завершения состояния
    func void ZS_Pee_end()
    {
    // прекратить мочеиспускание
    AI_PlayAni(self,"T_PEE_2_STAND");
    };



    // *********************************************************
    // НПС бродит по PICK фрипоинтам (что-то ищет или собирает)
    // *********************************************************

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

    // Функция инициализации состояния
    func void ZS_Pick_FP()
    {
    // установить нормальный набор восприятий
    Perception_Set_Normal();
    // перевод НПС в исходное состояние
    B_ResetAll(self);
    // установить режим передвижения шагом
    AI_SetWalkmode(