Игроделу | Объекты | Neverwinter Nights Основной Письмена Улучшенный Список объектов
По сайту
Главная
Рыцарская сага
Файлы
Neverwinter Nights
Гостевая книга
Форум сайта

По теме
Игроделу
Редактор фракций
Редактор журнала
Редактор диалога
Редактор скрипта
Модуль и области
Двери
Монстры
Встречи
Предметы
Торговцы
Объекты
Триггеры
Звуки
Тайлы
Хак файлы
Скриптинг
Neverwinter NightsобъектИгроделу
Объекты - Neverwinter Nights


Внимание! Рисунок интерактивный, можно кликать по обведенным секторам и зеленым кнопкам.

Объекты

(плейсы) – имеют широкое применение в строительстве модуля и проработке дизайна областей. Объекты, можно разбить на несколько групп по их применению или назначению:

  1. Объекты дизайна (заборы, решетки, вазы, ковры…)
  2. Переключатели (рычаги, потайные кнопки, тяговые цепи…)
  3. Секретные объекты (двери, люки, порталы…)
  4. Контейнеры (сундуки, сумки, шкафы …)
  5. Объекты освещения (факелы, пламя, магические вспышки…)

Для начала давайте рассмотрим, за что отвечают слоты в панели “Письмена”:

  • OnClose – При закрытие
  • OnDamager – При нанесение урона
  • OnDeath – При разрушение
  • OnHeartbeat - Циклическое срабатывание, равное 6 секундам
  • OnDisturbet – При получение или утрате предмета
  • OnLock – При закрытие на замок
  • OnPhysicalAttacked – При физическом ударе
  • OnOpen – При открытие
  • OnSpellCastAt – При колдовстве заклинания на объект
  • OnUnLock – При открытие замка
  • OnUsed – При клике по объекту
  • OnUserDefined – При поступление сигнала
  • Панели “Закрыть”, “Ловушка”, “Улучшенный” такие же, как и у дверей. Не буду повторяться… т.ч. см. про это в разделе “Двери”. Лучше рассмотрим более подробно, чем же различаются эти объекты.

    Объекты дизайна

    Вообще каждый объект является элементом дизайна, и от правильной постановки и набора объектов во многом зависит атмосфера восприятия модуля. Если, поставленный вами объект, важная деталь модуля, и имеет флажок “Используемый”, то не забудьте дать ему описание и необходимое вам название. Это поможет игроку сориентироваться с данным объектом и настроит на необходимую атмосферу игры. Пример:

    Вот стандартное описание “сумки с добычей” из тулсета: “Мешок маленький и плохо сшитый”.

    А вот описание “грязного мешка”: “Грязный мешок, плохо сшитый из шкуры какого-то мелкого животного. От него исходит неприятный запах. Похоже, что в таких мешках гоблины и хранят свои "сокровища"”.

    Все такие объекты должны быть с галкой статик, иначе они переходят в разряд объектов, которые будут восприниматься движком как элементы игры, и станут видимыми для скриптов. Даже если вы не включите галку “Используемый”, то все равно этот объект будет подвержен действию массовых заклинаний, и может быть разрушен.

    Внешность плейсов и их ограниченное количество заставляют искать другие варианты “подачи” объекта. Комбинация двух-трех и более плейсов иногда дают очень интересные сочетания. Описывать их все не имеет смысла, тут каждый должен найти что-то свое. Единственное, что важно помнить – это настройки по осям “наезжающих” друг на друга плейсов. Например, вам нужна ковровая дорожка в замке. В тех местах, где ковры буту соприкасаться в игре появится эффект “дрожания” (в тулсете это не заметно). Что бы дорожка смотрелась наилучшим образом, нужно лишь немного поменять настройку по оси "Z", то есть оси, отвечающей за расположение объекта к уровню локации. То есть первый ковер, мы укладываем с 0.00 по оси "Z", а второй за ним с 0.02. И все – ковры в игре будут смотреться как один, без всякого “дрожания”.

    Внешность плейса можно поменять с помощью скрипта на OnHeartbeat. Например, черный алтарь будет смотреться действительно черным, а каменный сундук превратиться в каменный:

    void main()
    {
     effect eStone = EffectVisualEffect(VFX_DUR_PETRIFY); // КаменнаЯ кожа
     effect eEffect = GetFirstEffect(OBJECT_SELF);
    
     if (GetEffectType(eEffect) != EFFECT_TYPE_VISUALEFFECT)
      ApplyEffectToObject(DURATION_TYPE_PERMANENT, 
      SupernaturalEffect(eStone), OBJECT_SELF);
    }

    Не буду заострять внимание на размещение объектов в локации, просто хочу напомнить, что плейсы можно копировать как в одиночку, так и группой. Причем информация в буфере будет действительна для любой локации и для любого открытого модуля. Единственное, что может произойти, так это потеря координаты высоты, если плейсы стоят один на одном. Это легко компенсировать, нажав кнопку “F5” клавиатуры. Замечу еще, что при занижении координаты высоты "Z" примерно на 0.25 метра, относительно уровня локации, объект становится проходимым. Настроить координаты, можно кликнув правой кнопкой по объекту, и выбрав “Настроить Расположение”.

    плейсы

    Бывает необходимость поставить ряд объектов друг на друга, но если их много, то это просто утомительно. Например “Падший лес” очень трудно поставить один на один, т.к. при нажиме “F5” между бревнами образуется просвет, и приходится каждому бревну настраивать координаты… Тогда на помощь вам придет простой скрипт расстановки бревен. Его можно поставить, например, на ХБ триггера или невидимого объекта, с выключенной галкой “Статик”. Сам скрипт:

    void main()
    {
      object oSelf = OBJECT_SELF;
      object oArea = GetArea(oSelf);
      if (GetLocalInt(oSelf, "DESTROY") == 1)
      {DestroyObject(oSelf); return;}
      int i,r;
      object oLes = GetNearestObjectByTag("FallenTimber", oSelf, i);
      location LocLes;
      vector vLes;
      float fLes;
      float rf = IntToFloat(r);
    
        for(i; i<=6; i++) // Число базовых объектов +1
        {
          LocLes = GetLocation(oLes);
          vLes = GetPositionFromLocation(LocLes);
          fLes = GetFacing(oLes);
          for(r=1; r< 8; r++) // Число всех объектов
          {
           vector vNew = Vector(vLes.x, vLes.y, vLes.z+(0.3*rf));
           location lNew = Location(oArea, vNew, fLes);
           object oBr = CreateObject(OBJECT_TYPE_PLACEABLE,
                  "x0_fallentimber", lNew, FALSE, "Timber_new");
           SetPlotFlag(oBr, TRUE);
           rf = IntToFloat(r);
          }
          oLes = GetNearestObjectByTag("FallenTimber", oSelf, i);
        }
      SetLocalInt(oSelf,"DESTROY",1);
    }

    Переключатели

    Переключатели используют для активации других объектов или просто на совершение каких-либо событий. Обычно все они имеют только анимацию:
    ANIMATION_PLACEABLE_ACTIVATE
    ANIMATION_PLACEABLE_DEACTIVATE
    Я часто использую рычаги для открытия дверей и еще старта некоторых событий, которые снимаются с ближайшего невидимого плейса. Чтобы правильно настроить работу рычагов, по ниже приведенному скрипту, нужно поставить рычаг в режим "Активирован" и в слот "OnUsed" поставить скрипт:

    //:://////////////////////////////////////////////
    //:: Created By: Gennady   * ДЛЯ ПЕРЕКЛЮЧАТЕЛЕЙ *
    //:: Слот: OnUsed
    //:://////////////////////////////////////////////
     void main()
    {
      object oSelf = OBJECT_SELF;
      object oDoor2 = GetObjectByTag("DR_"+GetTag(OBJECT_SELF)); // ЛЮБАЯ ДВЕРЬ
      object oByTag = GetNearestObjectByTag("SCHETCHIK"); // Счетчик сигналов
      string sTag = GetTag(oSelf);
      effect eIskra1 = EffectVisualEffect(VFX_COM_SPARKS_PARRY);
      effect eIskra2 = EffectVisualEffect(VFX_IMP_LIGHTNING_S);
      string sNum = GetStringRight(sTag, 2);
      if (GetStringLeft(sNum, 1) == "_")
          sNum = GetStringRight(sTag, 1);
      string sDoor = "LEVER_DOOR_" + sNum;
      object oDoor = GetNearestObjectByTag(sDoor); // БЛИЖАЙШАЯ В ЭТОЙ ОБЛАСТИ ДВЕРЬ
    
    if (GetLocalInt(oSelf, "ACTIVATE") == 0) // первое положение ===================
     {
      ActionPlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE);
      SetLocalInt(oSelf, "ACTIVATE", 1);
      if (GetLockKeyTag(oSelf) != "") // поле KeyTag есть запись
      {
       ActionSpeakString("Сработал какой-то механизм...");
       SetLocalInt(GetModule(), sTag, 1);
       ApplyEffectToObject(DURATION_TYPE_INSTANT, eIskra2, oSelf);
       if(GetIsObjectValid(oByTag))
       SignalEvent(oByTag, EventUserDefined(333)); // Дать сигнал
      }
      else // поле KeyTag чистое
      {
       ActionSpeakString("Что-то открылось...");
       ApplyEffectToObject(DURATION_TYPE_INSTANT, eIskra1, oSelf);
       if (sTag == "LEVEL_"+ sNum) // Открываем ближайшую дверь
       {
        AssignCommand(oDoor, ActionDoCommand(SetLocked(oDoor, FALSE)));
        AssignCommand(oDoor, ActionOpenDoor(oDoor));
       }
       else // Открываем дверь "DR_" +  тeг переключатель
       {
        AssignCommand(oDoor2, ActionDoCommand(SetLocked(oDoor2, FALSE)));
        AssignCommand(oDoor2, ActionOpenDoor(oDoor2));
       }
      }
     }
    else // второе положение =======================================================
     {
      if (GetLockKeyTag(oSelf) == "1")  // поле KeyTag есть запись 1
      {
       ActionSpeakString("<cу  >МЕХАНИЗМ УЖЕ СРАБОТАЛ</c>");
       if(GetIsObjectValid(oByTag))
       SignalEvent(oByTag, EventUserDefined(333)); // Дать сигнал
       return;
      }
      ActionPlayAnimation(ANIMATION_PLACEABLE_ACTIVATE);
      SetLocalInt(oSelf, "ACTIVATE", 0);
      if (GetLockKeyTag(oSelf) != "") // поле KeyTag есть запись
      {
       ActionSpeakString("Что-то еще сработало в механизме...");
       SetLocalInt(GetModule(), sTag, 2);
       ApplyEffectToObject(DURATION_TYPE_INSTANT, eIskra2, oSelf);
       if(GetIsObjectValid(oByTag))
       SignalEvent(oByTag, EventUserDefined(333)); // Дать сигнал
      }
      else // поле KeyTag чистое
      {
       ActionSpeakString("Что-то закрылось...");
       ApplyEffectToObject(DURATION_TYPE_INSTANT, eIskra1, oSelf);
       if (sTag == "LEVEL_"+ sNum) // Открываем ближайшую дверь
       {
        AssignCommand(oDoor, ActionDoCommand(SetLocked(oDoor, TRUE)));
        AssignCommand(oDoor, ActionCloseDoor(oDoor));
       }
       else // Открываем дверь "DR_" +  тeг переключатель
       {
        AssignCommand(oDoor2, ActionDoCommand(SetLocked(oDoor2, TRUE)));
        AssignCommand(oDoor2, ActionCloseDoor(oDoor2));
       }
      }
     }
    }
    /* Тег для дверей в этой области = "LEVER_DOOR_" + номер из тeга этого переключателя
       При этом тег переключателя должен = "LEVEL_" + любая цифра или буква
       Тег для дверей в другой области = "DR_" +  тeг переключателя
       Если есть запись в поле KeyTag, то присвоится переменная модулю
       Поступит сигнал на ближайший объект-счетчик с тегом "SCHETCHIK"
       Присвоить модулю переменную равную тегу объекта (1/2)
       Если тег ключа = 1, то будет только одно срабатывание переключателя
       Переключатель в режиме "Активирован"
    */

    Секретные объекты

    Это все объекты, которые используются на секретных триггерах (см. “Триггеры”). Если это объект для перемещения, то у него обычно стоит в слоте “OnUsed” скрипт на перемещение. Если это какой-либо сундук, то у него настроены скрипты под контейнер, с определенной ценность генерируемого предмета. Эти объекты можно ставить и без секретного триггера, а также можно сменить скрипт на перемещение, сделав его более универсальным. Вот для примера скриптa для дверей и люков, годится для перехода как в одной области, так и для перехода в новую. Сам скрипт:

    //:://////////////////////////////////////////////
    //:: УНИВЕРСАЛЬНЫЙ СКРИПТ ПЕРЕМЕЩЕНИЙ
    //:: Слот: OnUsed
    //:://////////////////////////////////////////////
    
    // ТЕКСТ НАД ПЕРСОНАЖЕМ
    // object oPC - ПЕРСОНАЖ
    // string sTokenValue - ТЕКСТ НАД ПЕРСОНАЖЕМ
    void text(object oPC, string sTokenValue);
    // ПЕРЕМЕЩЕНИЕ ГЕРОЯ и всей его свиты к точке object oWP
    void JumpFirstPC(object oWP);
    
    void text(object oPC, string sTokenValue)
    {AssignCommand(oPC, SpeakString(sTokenValue)); }
     
    void JumpFirstPC(object oWP)
    {
     object oPC = GetFirstPC();
     object oNPC = GetFirstObjectInArea(oPC);
    
       AssignCommand(oPC, ClearAllActions());
       AssignCommand(oPC, JumpToObject(oWP));
     while (GetIsObjectValid(oNPC))
     {
      if (oPC==GetMaster(oNPC))
      {
       AssignCommand(oNPC, ClearAllActions());
       AssignCommand(oNPC, JumpToObject(oWP));
      }
      oNPC = GetNextObjectInArea(oPC);
     }
    }
    //////////////////////////////////////////////
    void main()
    {
     object oPC = GetFirstPC();
     object oSP = GetHenchman(oPC);
     object oPoint = GetWaypointByTag("TP_" + GetTag(OBJECT_SELF));
      if (!(GetLocked(OBJECT_SELF) == TRUE))
      {
       if(GetLocalInt(OBJECT_SELF, "OPEN_SD") == 1)
         JumpFirstPC(oPoint);
       else
       {
        SetLocalInt(OBJECT_SELF,"OPEN_SD",1);
        DelayCommand(0.1, ActionPlayAnimation(ANIMATION_PLACEABLE_OPEN));
        DelayCommand(6.6, ActionPlayAnimation(ANIMATION_PLACEABLE_CLOSE));
        DelayCommand(6.7, SetLocalInt(OBJECT_SELF,"OPEN_SD",FALSE));
       }
      }
      else
      {
       PlaySound("as_na_branchsnp3");
       FloatingTextStringOnCreature("ЗАКРЫТО!", oPC, TRUE);
       int nSkill = 20 + GetSkillRank(SKILL_OPEN_LOCK, oSP);
       if (nSkill >= GetLockUnlockDC(OBJECT_SELF))
          text(oSP, "Попробуйте открыть! Не сможешь, помогу открыть…");
       else
          text(oSP, "Мне не осилить этот замок…");
      }
    }
    // помещать в слот OnUsed OnEnter OnClick OnAreaTransitionClick
    // Точка перемещения TP_ + Тег объекта
    //Перемещение героя и спутника для размещаемых объектов

    Теперь попробуем сделать секретный портал. Базовый портал, из стандартной палитры имеет немного глюченный скрипт перехода. Его можно заменить, например на мой универсальный, из раздела “Триггеры”. Этот скрипт мы ставим в слот “OnUsed”, а в слот ХБ ставим скрипт со звуком Магического Портала. Получится, что вызвав Портал, он у вас уже будет, как положено со звуком…

    //:://////////////////////////////////////////////
    //:: ИГРАТЬ ЗВУК ПОРТАЛА
    //:: Слот: OnHeartbeat
    //:://////////////////////////////////////////////
    void main()
    {
     if(GetArea(GetFirstPC()) != GetArea(OBJECT_SELF)) 
      return; // если ПС нет в локе
      PlaySound("al_mg_portal1");
    }

    Если вы хотите сделать перемещение с диалога, т.е. поговорив с порталом, то тогда нужно поставить скрипт старта диалога, а в диалоге уж отправить героя, тем же универсальным скриптом перемещений.

    //::///////////////////////////////////////////////
    //:: НАЧАТЬ ДИАЛОГ С ОБЪЕКТОМ
    //:: Слот: OnUsed
    //:://////////////////////////////////////////////
    void main()
    {
        object oPC = GetLastUsedBy();
        ActionStartConversation(oPC);
    }

    Контейнеры

    Контейнеры это объекты, в которых есть предметы, или их можно туда положить. Контейнером может стать любой объект, достаточно просто поставить галку “Есть инвентарь”. На всех базовых контейнерах в слотах “OnDeath” и “OnOpen”, стоят скрипты генерации предметов или золота. Если вы хотите, чтобы в контейнере были только необходимые вам вещи, то удалите эти скрипты. Можно также попробовать написать генерацию своих, уникально настроенных в палитре вещей. Для примера разберем скрипт генерации вещей из инклюды раздела “Предметы”, составленной из базовых, не имеющих Фаэруновского описания вещей. Например, возьмем ценные вещи +2 и добавим к ним немного золота, а также какое-либо зелье… Получим скрипт:

    //:://////////////////////////////////////////////
    //::  ДАТЬ ВЕЩЬ +2, ДЕНЬГИ И ЗЕЛЬЕ
    //:://////////////////////////////////////////////
    #include "shmotki"
    void main()
    {
      if (GetLocalInt(OBJECT_SELF,"SM2_DO_ONCE") == 1)return;
      object oPC = GetFirstPC();
    
      CreateSecondShmotka(OBJECT_SELF);
      CreateGold(OBJECT_SELF, 100);
      CreateGold(OBJECT_SELF, 10);
      CreateGold(OBJECT_SELF, 1);
      CreateZel(OBJECT_SELF);
    
     SetLocalInt(OBJECT_SELF,"SM2_DO_ONCE", 1);
    }

    Этот скрипт можно ставить в любой слот, но предпочтительно в эти слоты: OnDeath, OnOpen, OnUsed, OnUserDefined. Золота в сундуке будет от 111 до 1110 монет, потому что количество пробито через множитель, чтобы не получить уж очень смехотворную сумму… Составив подобным образом несколько вариантов для разных случаев ценности содержимого контейнера, вы получите свою систему генерации вещей. В письменах контейнера может быть задействовано много скриптов. Чтобы не вносить каждый раз новую синьку объекта в палитру, для быстрой настройки используйте загрузку сюжета, ранее сохраненных наборов скриптов. Для этого на панели “Письмена”, есть соответствующие кнопки.

    Еще один скрипт на реакцию НПС на воровство героем предметов из контейнеров. Если НПС видит героя то подойдет и не даст забрать вещи. Чтобы забрать, нужно герою или выпить зелье невидимости, или уйти в тень… НПС обязательно должен иметь класс “Простолюдин”, не путайте с фракцией, это разные вещи! Сам скрипт:

    //::///////////////////////////////////////////////
    //:: NPC не дает забрать вещи и закрывает объект
    //:: Слот: OnUsed, OnOpen  
    //:: File Name: open_konteyner
    //:://////////////////////////////////////////////
    void main()
    {
    object oSelf = OBJECT_SELF;
    object oPC = GetFirstPC();
    object oItem = GetFirstItemInInventory(oSelf);
    int iHide = 20 + GetSkillRank(SKILL_HIDE, oPC);
    int i, iUd = 20;
    object oNPC = GetNearestObject(OBJECT_TYPE_CREATURE, oPC, i);
    
    if (oItem == OBJECT_INVALID) return; // Если уже нет предметов
     while (GetIsObjectValid(oNPC))
     {
      if (!GetObjectSeen(oPC, oNPC) || GetIsDead(oNPC)
          || GetLevelByClass(CLASS_TYPE_ANIMAL, oNPC) >= TRUE
          || GetLevelByClass(CLASS_TYPE_COMMONER, oNPC)== FALSE)
        {i++; oNPC = GetNearestObject(OBJECT_TYPE_CREATURE, oPC, i);}
      else break;
     }
    float fFas = GetFacing(oNPC);
    location Loc = GetLocation(oNPC);
    float fTime = GetDistanceBetween(oNPC, oPC);
    if (fTime < 8.0) fTime = 8.0;
    if(oNPC==OBJECT_INVALID || fTime > 15.0)
     {
      AssignCommand(oPC, SpeakString("Никто не видит... Можно брать..."));
      return;
     }
    if (GetStealthMode(oPC)==STEALTH_MODE_ACTIVATED)
    {
      if(iHide > 20) iUd = 40;
      if(iHide > 24) iUd = 60;
      if(iHide > 28) iUd = 80;
      if(iHide > 30) iUd = 100;
    if(Random(100) < iUd)
     {
      AssignCommand(oPC, SpeakString("Никто не видит... Можно брать..."));
      DelayCommand(0.5,FloatingTextStringOnCreature("<c у >Маскировка удалась!",oPC));
      return;
     }
    else
    DelayCommand(0.5,FloatingTextStringOnCreature("<cюa >Маскировка не удалась!",oPC));
    }
    
    AssignCommand(oPC, ClearAllActions());
    AssignCommand(oPC, ActionWait(fTime*2));
    AssignCommand(oPC, ActionDoCommand(SetCommandable(TRUE, oPC))); // разблокировать
    DelayCommand(0.1, SetCommandable(FALSE, oPC)); // заблокировать
    AssignCommand(oNPC, ClearAllActions());
    AssignCommand(oNPC, SetFacingPoint(GetPosition(oPC)));
    AssignCommand(oNPC, ActionDoCommand(PlayVoiceChat(VOICE_CHAT_NO, oNPC)));
    AssignCommand(oNPC, ActionSpeakString("Эй, не трогай это!"));
    AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_TALK_FORCEFUL, 1.0, 2.0));
    AssignCommand(oNPC, ActionForceMoveToObject(oPC, TRUE, 1.0, fTime/4));
    AssignCommand(oNPC, ActionDoCommand(AssignCommand(oSelf,
    ActionStartConversation(oPC, "konteyner"))));
    AssignCommand(oNPC, ActionSpeakString("Это не твое... Уходи!"));
    AssignCommand(oNPC, ActionWait(2.0));
    AssignCommand(oNPC, ActionForceMoveToLocation(Loc, FALSE, fTime/2));
    AssignCommand(oNPC, ActionDoCommand(DelayCommand(0.3, SetFacing(fFas))));
    AssignCommand(oNPC, ActionDoCommand(SetCommandable(TRUE, oNPC))); // разблокировать
    AssignCommand(oNPC, ActionDoCommand(SetCommandable(TRUE, oPC))); // разблокировать
    DelayCommand(0.1, SetCommandable(FALSE, oNPC)); // заблокировать
    }

    Объекты освещения

    В игре неплохо продумано освещение, как объектов, так и существ, посредством наложения заклинаний. Также освещение можно задать в свойствах области, где можно и полностью сделать неосвещенную локацию. В палитре объектов в разделе “Визуальные эффекты” находятся Вспышки света, Магические вспышки, Пламя и т.д.… Все эти объекты тоже дают освещение, но вот Пламя имеют еще и своих дублеров, т.е. такие же объекты, но без эффекта освещения. Это я к тому, что если вы захотите управлять освещением скриптами, то нужно кое-что знать… Если на объект наложено освещение, то даже погасив его, например базовым скриптом “nw_02_onoff”, мы при смене локации опять вернем этому объекту остаточный эффект освещения. Как раз для этого случая и нужны дублеры. На верхнем рисунке, как раз показан такой пример выбора для факела (кликать зеленую кнопочку), объекта “Факел, NoAmbient”, который не отражен в списке объектов палитры. Должен заметить, что просмотрев полный список, вы найдете там некоторые интересные объекты, которые также не отражены в списке “Раскрасить Размещаемые Объекты”. Продолжим о управлении осветительными объектами, например: Держателем Факела и Подставкой для лампы. Если вам нужно убрать днем освещение, то вам поможет простой скрипт на “OnHeartbeat” объекта:

    //:://////////////////////////////////////////////
    //:: ФОНАРЬ ОСВЕЩЕНИЯ  ДЕНЬ - НОЧЬ
    //:: Слот: OnHeartbeat
    //:://////////////////////////////////////////////
    
    //  *****  СНЯТЬ ВСЕ ЭФФЕКТЫ  *****
    void DelEffectOnPC(object oObject)
    {
     effect eOne = GetFirstEffect(oObject);
     while (GetIsEffectValid(eOne))
     {
      RemoveEffect(oObject, eOne);
      eOne = GetNextEffect(oObject);
     }
    }
    //////////////////////////////////////////////////
    void main()
    {
      object oSelf = OBJECT_SELF;
      object oZvFak = GetNearestObjectByTag("ZV_FAKEL"); // Звук огонь
      effect eLight = EffectVisualEffect(VFX_DUR_LIGHT_YELLOW_10); // Свет желтый
    
      if (GetIsNight())
       {
        if (GetLocalInt(oSelf,"NW_L_AMION") == 0)
        {
         if (GetTag(oSelf) == "LAMPA_D") // ДЛЯ ЛАМПЫ
         {
          object oLam = CreateObject(OBJECT_TYPE_PLACEABLE, "new_lampa",
                        GetLocation(oSelf)); // Фонарь ночной
          DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_PERMANENT,
          SupernaturalEffect(eLight), oLam));
          SetLocalInt(oLam,"NW_L_AMION",1);
          DestroyObject(oSelf, 2.0);
          return;
         }
         PlayAnimation(ANIMATION_PLACEABLE_ACTIVATE);
         ApplyEffectToObject(DURATION_TYPE_PERMANENT,
         SupernaturalEffect(eLight), oSelf);
         SetLocalInt(oSelf,"NW_L_AMION",1);
         if (GetDistanceBetween(oZvFak, oSelf) < 2.0)
         SoundObjectSetVolume(oZvFak, 127); // уровень звука от 0 до 127
        }
       }
     else
     {
      if (GetLocalInt(oSelf,"NW_L_AMION") != 1) return;
      {
       if (GetTag(oSelf) == "LAMPA") // ДЛЯ ЛАМПЫ
       {
        CreateObject(OBJECT_TYPE_PLACEABLE, "new_lampa_d", GetLocation(oSelf));
        DestroyObject(oSelf, 0.3);
        return;
       }
       AssignCommand(oSelf, PlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE));
       DelEffectOnPC(oSelf);
       SetLocalInt(oSelf,"NW_L_AMION",0);
       if (GetDistanceBetween(oZvFak, oSelf) < 2.0)
       SoundObjectSetVolume(oZvFak, 0); // уровень звука от 0 до 127
      }
     }
    }
    /*
     Фонарь дневной - Фонарный столб, без окружения Тэг  LAMPA_D  ResRef new_lampa_d
     Фонарь ночной  - Подставка для лампы           Тэг  LAMPA    ResRef new_lampa
     Должен стоять у новой лампы в палитре этот скрипт на ХБ
     Факел - Факел, No Ambient               
    */

    Для правильной работы скрипта, нужно создать в палитре два новых объекта без освещения, Факел и Лампу. Поставить им галку “Сюжет” и снять “Статик”, теги и ResRef см. в скрипте, причем в слоте “OnHeartbeat” должен обязательно уже стоять этот скрипт!… Для лампы нужно еще дополнительно создать одну синьку, т.к. без базового эффекта освещения, у лампы не будет огонька в фонаре. Поэтому на обычную лампу с освещением, ставим скрипт в слот «OnHeartbeat» и меняем ей тег и Res Ref. Рядом с Факелом может быть расположен звуковой объект с тегом «ZV_FAKEL». (для лампы можно тоже поставить свой звук и с тем же тегом…) Днем, когда факел погасим, мы так же уберем и звук, а ночью включим факел и врубим звук на полную. Хотя, можете уровень звука поставить другой, или сделать его случайным…

    Создав эти синьки, можно еще сделать объекты и с ручным управлением. Для этого просто уберите скрипт из слота “OnHeartbeat” и поставьте новый скрипт на “OnUsed”, причем сам объект должен тогда быть используемым. (см. верхний рисунок) Сам скрипт:

    //:://////////////////////////////
    //:: ФОНАРЬ ОСВЕЩЕНИЯ
    //:: Слот: OnUsed
    //:://////////////////////////////
    
    //  *****  СНЯТЬ ВСЕ ЭФФЕКТЫ  *****
    void DelEffectOnPC(object oObject)
    {
     effect eOne = GetFirstEffect(oObject);
     while (GetIsEffectValid(eOne))
     {
      RemoveEffect(oObject, eOne);
      eOne = GetNextEffect(oObject);
     }
    }
    //////////////////////////////////////////////////
    void main()
    {
      object oSelf = OBJECT_SELF;
      object oZvFak = GetNearestObjectByTag("ZV_FAKEL"); // Звук огонь
      effect eLight = EffectVisualEffect(VFX_DUR_LIGHT_YELLOW_10); // Свет желтый
    
      if (GetLocalInt(oSelf,"NW_L_AMION") == 0)
        {
         if (GetTag(oSelf) == "LAMPA_D") // ДЛЯ ЛАМПЫ
         {
          object oLam = CreateObject(OBJECT_TYPE_PLACEABLE, "new_lampa_used",
                        GetLocation(oSelf), FALSE, "LAMPA"); // Фонарь ночной
          DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_PERMANENT,
          SupernaturalEffect(eLight), oLam));
          SetLocalInt(oLam,"NW_L_AMION",1);
          DestroyObject(oSelf, 1.5);
          return;
         }
         PlayAnimation(ANIMATION_PLACEABLE_ACTIVATE);
         ApplyEffectToObject(DURATION_TYPE_PERMANENT,
         SupernaturalEffect(eLight), oSelf);
         SetLocalInt(oSelf,"NW_L_AMION",1);
         if (GetDistanceBetween(oZvFak, oSelf) < 2.0)
         SoundObjectSetVolume(oZvFak, 127); // уровень звука от 0 до 127
        }
     else
     {
       if (GetTag(oSelf) == "LAMPA") // ДЛЯ ЛАМПЫ
       {
        CreateObject(OBJECT_TYPE_PLACEABLE, "new_lampa_u_d", GetLocation(oSelf));
        DestroyObject(oSelf, 0.3);
        return;
       }
       AssignCommand(oSelf, PlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE));
       DelEffectOnPC(oSelf);
       SetLocalInt(oSelf,"NW_L_AMION",0);
       if (GetDistanceBetween(oZvFak, oSelf) < 2.0)
       SoundObjectSetVolume(oZvFak, 0); // уровень звука от 0 до 127
     }
    }
    /*
     Фонарь дневной - Фонарный столб, без окружения Тэг  LAMPA_D  ResRef new_lampa_d
     Фонарь ночной  - Подставка для лампы           Тэг  LAMPA    ResRef new_lampa_used
     Факел - Факел, No Ambient
     Звук убираем полностью, тэг равен   ZV_FAKEL   
    */

    Обновление: Rambler's Top100