Игроделу | Двери | Neverwinter Nights Письмена Улучшенный Основной Закрыть Ловушка Переход Местности
По сайту
Главная
Рыцарская сага
Файлы
Neverwinter Nights
Гостевая книга
Форум сайта

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


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

  1. OnAreaTransitionClick – При клике на переход
  2. OnClose – При закрытии
  3. OnDomager – При получении дверью урона
  4. OnDeath – При уничтожении двери
  5. OnFailToOpen – Запустится только при закрытой двери
  6. OnHeartbeat – Циклическое срабатывание, равное 6 секундам
  7. OnLock – При удачном закрытие замка
  8. OnPhysicalAttacked – При ударе по двери
  9. OnOpen – При открытие
  10. OnSpellCastAt – Если на дверь колдонуть заклинание
  11. OnUnLock – При удачном отрытие замка
  12. OnUserDefined – При получение дверью сигнала

Двери


- это важный атрибут игры, и от правильной настройки дверей зависит очень многое… Если это дверь перехода между областями, то она обязательно должна иметь уникальный тэг. Задать переход можно как в ручную, записав нужную точку, или дверь, а также можно на панели “Переход Местности”, кликнув соответствующею кнопку и выбрав область и нужный объект перехода. Достаточно выбрать точку, дверь или триггер и нужную область в окошке "Целевая область", как появиться список доступных для перехода объектов. Выбрав нужный, в окне схемы области этот объект выделиться зеленым цветом, кликаем кнопочку ОК и переход создан.
P.S. Подобным образом мы также создаем переходы и для триггеров…

двери

Внешность двери можно выбрать как в палитре, так и непосредственно в Свойствах дверей, открыв окошко “Характерная внешность”, и выбрав нужную (см. верхний рисунок). Дверь можно настроить на сопротивление удару, выбрав нужный параметр Прочности, т.е. сколько единиц урона дверь поглотит, а также сколько ХР она будет иметь. От разрушения заклинаниями, нужно настраивать броски на спасение… А вот если вам нужна не разбиваемая дверь, то просто поставьте галку “Сюжет”.

На панельке “Закрыть”, мы настраиваем сложность замка, а если нужно то задаем тэг ключа, которым будем открывать эту дверь. Здесь же можно поставить отбор ключа, если он больше не потребуется.

Панель “Ловушка” позволит настроить ловушку на двери, задав нужные параметры на обнаружение и обезвреживание, и выбрав саму ловушку. Строка “OnDisarm” отвечает за обезвреживание, а строка “OnTrapTriggered” за то, если герой просто тупо попадет в эту ловушку. Если вы хотите добавить получение опыта за обезвреживание ловушки, а также за взлом замка, то можно использовать универсальный скрипт:

//////////////////////////////////////////////
//:: УНИВЕРСАЛЬНЫЙ СКРИПТ
//:: РАЗДЕЛЕНИЕ ХР ЗА ОТКРЫТИЕ-ОБЕЗВРЕЖИВАНИЕ
//:: СЛОТ: OnDisarm или OnUnLock
//////////////////////////////////////////////
void main()
{
 int iZ = GetLockUnlockDC(OBJECT_SELF);
 int iL = GetTrapDisarmDC(OBJECT_SELF);
 object oDisarmed = GetLastDisarmed();
 object oUnlocked = GetLastUnlocked();
 object oPC = GetFirstPC();
 int nSkillZ = 20 + GetSkillRank(SKILL_OPEN_LOCK, oUnlocked );
 int nSkillL = 20 + GetSkillRank(SKILL_DISABLE_TRAP, oDisarmed);

//*****  ОТКРЫВАЕМ ЗАМОК  *****

  if (GetLocalInt(OBJECT_SELF, "ZAM")!=1 && oUnlocked != OBJECT_INVALID)
    {
      if (GetIsPC(oUnlocked)) // Если замок вскрыл РС
      GiveXPToCreature(oPC, (iZ+nSkillZ));
      else
      {
       GiveXPToCreature(oPC , (iZ+nSkillZ)/2);
       DelayCommand(1.0, AssignCommand(oUnlocked, SpeakString("Плевый замочек!")));
      }
      // XP = DC двери + очки броска на открывание
      SetLocalInt(OBJECT_SELF, "ZAM", 1);
    }
//***** ОБЕЗВРЕЖИВАЕМ ЛОВУШКУ  *****

  if (GetLocalInt(OBJECT_SELF, "DIS")!=1 && oDisarmed!= OBJECT_INVALID)
   {
    if (GetIsPC(oDisarmed)) // Если ловушку обезвредил РС
    GiveXPToCreature(oPC, (iL+nSkillL));
    else
    {
     GiveXPToCreature(oPC, (iL+nSkillL)/2);
     DelayCommand(1.0, AssignCommand(oDisarmed, SpeakString("Ловушка, так себе!")));
    }
    // XP = DC ловушки + очки броска на обезвреживание
    SetLocalInt(OBJECT_SELF, "DIS", 1);
   }
}

Панелька “Улучшенный” служит для выбора портрета двери при диалоге, и самого диалога, если конечно это вам нужно. Эти все настройки не вызывают особых проблем у новичков, поэтому, поговорим лучше о скриптах для разной работы дверей. Кстати, когда в модуле много дверей, то настроив скрипты, не помешает кликнуть на вкладке скриптов кнопочку «Сохранение сценария», для того, чтобы у подобной новой двери простым нажатием «Загрузка сценария», выбрать ранее сохраненный сценарий и не парится каждый раз с расстановкой скриптов.

OnAreaTransitionClick – нужно для случая, когда по каким-либо соображениям нужно отследить это событие, или запретить переход, или наоборот перейти к точке перемещения, причем это может быть не одна точка, и не обязательно пробитая в свойствах двери. Вот пример скрипта, когда, получив определенную локалку на герое, дверь перебросит героя в другую точку:

void main()
{
  object oPC = GetClickingObject();
  // БазоваЯ точка перемещениЯ двери
  object oWP = GetTransitionTarget(OBJECT_SELF); 
  if (!GetIsPC(oPC)) return;
  if (GetLocalInt(oPC, "LOCAL") == 1) // Проверить
  oWP = GetObjectByTag("TAG");
  AssignCommand(oPC, ClearAllActions());
  AssignCommand(oPC, ActionJumpToObject(oWP));
}

OnDeath – я тут подумал, может пригодиться вот для какого прикола. При разрушении дверей, у нас не пропадает курсор перехода, и можно продолжать пользоваться дверь дальше. Это недоразумение можно легко устранить, кинув на дверь невидимость кат сценки, тогда курсор перехода пропадет:

//:://///////////////////////
//:: СЛОТ: OnDeath
//:: File name: door_death
//:://///////////////////////
void main()
{
 object oSelf = OBJECT_SELF;
 // ПолнаЯ невидимость
 effect eCut = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
 ApplyEffectToObject(DURATION_TYPE_PERMANENT,SupernaturalEffect(eCut),oSelf);
}

OnFailToOpen - важный слот если вы хотите провести диалог с дверью, или дать какую-то указку игроку. Тут я написал немного мудреный скрипт, который еще позволит определить заперта ли дверь, и сможет ли ее открыть герой, плюс можно поставить рядом точку, с которой дверь прочтет имя этой точку. Получится такая фраза диалога двери, но без самого диалога:

//:://////////////////////////////////////////////
//:: File name: us_startconv_dor   ДИАЛОГ ДВЕРЕЙ
//:: Created By: Gennady
//:: Слот: OnFailToOpen
//:://////////////////////////////////////////////
void SpeakDoor(object oPC, object oWP, int iZ, object oDoor = OBJECT_SELF)
{
  if(GetIsObjectValid(oWP) && !IsInConversation(oPC) &&
      GetDistanceBetween(oWP, oDoor) < 3.0)
  SpeakString(GetName(oWP));
  if(GetLockKeyTag(oDoor)!= "") SendMessageToPC(oPC, "Вам нужен специальный ключ!");
  else
  {
   int nSkillZ = 20 + GetSkillRank(SKILL_OPEN_LOCK, oPC);
   string sZ, sOtm;
   if(iZ > nSkillZ+10) sZ = "<cу  >"; // Красный
   else if(iZ <= nSkillZ) sZ = "<c у >"; // Зеленый
   else
   {
    sZ = "<cуу >"; // Желтый
    sOtm = "<c у > Вам нужна отмычка: <cуу >"+"+"+IntToString(iZ-nSkillZ);
   }
SendMessageToPC(oPC, "<c °у>Класс cложности замка: "+sZ+IntToString(iZ)+"</c>"+sOtm);
  }
}
void main()
{
 object oPC = GetFirstPC();
 object oWP = GetNearestObjectByTag("WP_DOOR_TXT");
 int iZ = GetLockUnlockDC(OBJECT_SELF);
 string sWP, sPlot, sLock;
 if(GetPlotFlag()==TRUE) sPlot = "<c у > Тебе не взломать"; else sPlot = "";
 if(iZ==100) sLock = " и не открыть"; else sLock = "";
 if (GetLocked(OBJECT_SELF) == FALSE) return;
 if (GetIsInCombat(oPC))
   {
    if (GetDistanceBetween(oWP, OBJECT_SELF) < 3.0)
        sWP = GetName(oWP);  else sWP = "";
    SpeakString("<c °у>Бей, ни бей! </c>"+sPlot+sLock+"!</c> "+sWP);
    return;
   }
   ActionStartConversation(oPC);
   DelayCommand(1.0, SpeakDoor(oPC, oWP, iZ));
}
 // Если дверь закрыта и у нее проставлен диалог, то oн начнется c РС
 // Если есть рядом oWP, то дверь произносит имя этого oWP
 // Если дверь атакуют, то дверь произносит: "Бей, ни бей!" + имя этого oWP

OnHeartbeat – сюда можно поставить многие скрипты. Например, если вам нужно чтобы ночью эти двери были закрыты, то поставьте подобный скриптик:

//:://///////////////////////////////////////
//:: Закрытие двери: день - ночь.  Слот ХБ
//:: Created By: Gennady
//:://///////////////////////////////////////
void main()
{
  object oSelf = OBJECT_SELF;
  int T = GetTimeHour();
  int iNewT = StringToInt(GetLockKeyTag(oSelf)); // Новый час ЗАКРЫТИЯ
  int iT = 21; // БАЗОВЫЙ час ЗАКРЫТИЯ

  if (iNewT >= 1) iT = iNewT;
  if(T>=iT || T<6)
   {
    AssignCommand(oSelf, ActionCloseDoor(oSelf));
    SetLocked(oSelf, TRUE);
   }
  else
    SetLocked(oSelf, FALSE);
}
 /* Если в слоте тэга ключа стоит цифра, то это новый час закрытия этой двери */

OnPhysicalAttacked – этот слот пригодится, например, когда у двери стоит охранник или просто рядом находятся НПСы, и при атаке героем двери, они отреагируют на это. Вот для примера скрипт на реакцию, а так же появление двух стражей. По истечению определенного время, эти стражи удалятся, и герой опять может попытать счастье вышибить дверь…

void main()
{
   object oNPC = GetFirstObjectInShape(SHAPE_SPHERE, 12.0, GetLocation(OBJECT_SELF), TRUE);
   object oPC = GetFirstPC();

   if(GetLocalInt(OBJECT_SELF, "ATAKA") == 1)
   {
     AssignCommand(oPC, SpeakString("Эх, вышибу сейчас!"));
     location Loc = GetLocation(oPC);
     object oByTag = CreateObject(OBJECT_TYPE_CREATURE, "straz", Loc);
     object oByTag1 = CreateObject(OBJECT_TYPE_CREATURE, "straz", Loc);
     DestroyObject(oByTag, 120.0);
     DestroyObject(oByTag1, 120.0);
     DelayCommand(5.1, AssignCommand(oByTag, ActionAttack(oPC)));
     DelayCommand(5.1, AssignCommand(oByTag1, ActionAttack(oPC)));
     return;
   }
   while (GetIsObjectValid(oNPC))
  {
   if (GetObjectSeen(oPC, oNPC) && oNPC != oPC && oNPC !=GetMaster(oPC) &&
       GetLevelByClass(CLASS_TYPE_ANIMAL, oNPC)==FALSE)
     {
      AssignCommand(oNPC, ClearAllActions());
      PlayVoiceChat(VOICE_CHAT_NO, oNPC);
      AssignCommand(oNPC, ActionSpeakString("Эй, уйди от двери! Стража сюда…а!"));
      DelayCommand(0.1, AssignCommand(oPC, ClearAllActions()));
      DelayCommand(3.1, SetLocalInt(OBJECT_SELF,"ATAKA",1));
      DelayCommand(300.1, SetLocalInt(OBJECT_SELF,"ATAKA",2));
     }
     else if(oNPC == oPC)
      AssignCommand(oNPC, SpeakString("Эх, вышибу сейчас!"));
   oNPC = GetNextObjectInShape(SHAPE_SPHERE, 12.0, GetLocation(OBJECT_SELF), TRUE);
  }
}
/* При повторной атаке двери, если есть рядом существо не класса животное,
   появятся 2 стражa */

OnOpen – сюда можно поставить скрипт на автоматическое закрытие дверей:

// ЗАКРЫТЬ ДВЕРЬ Слот OnOpen
void main()
{
object oDoor = OBJECT_SELF;
DelayCommand(10.0, ActionCloseDoor(oDoor));
// SetLocked(oDoor, TRUE); // Если нужно закрыть замок
}

У нас получится, что открыв дверь, она через 10 секунд закроется. Если это дверь комнаты отдыха в таверне, то поставив скрит на закрытие замка, мы можем сделать эту комнату платной. Тогда заплатив хозяину таверны за ночлег и отдых, мы должны открыть эту дверь. Вот простенький универсальный скрипт на это событие. Останется только правильно поставить тэг для этой двери, и сделать переход. Дверь обязательно должна вести в другую локацию, иначе у нас герой окажется замурованным.

void main()
{
   // открытие запертой двери
   object oDoor = GetObjectByTag("D_" + GetTag(OBJECT_SELF));
   SetLocked(oDoor, FALSE);
}

Бывает необходимость, чтобы НПС подошел к закрытой на замок двери, открыл ее, а затем вернулся на свое место. Тогда вам поможет такой скрипт, который запускается с диалога НПС, годится также и для любого плейса:

//::///////////////////////////////////////////////
//:: NPC идет к двери (предмету) и открывает
//:: File Name: de_open_door_ani
//:: Created By: Gennady
//:://////////////////////////////////////////////
void main()
{
object oDoor = GetNearestObjectByTag("D_" + GetTag(OBJECT_SELF));
object oSelf = OBJECT_SELF;
object oWP = GetNearestObjectByTag("DP" + GetTag(OBJECT_SELF));
location Loc = GetLocation(oSelf);
float fFas = GetFacing(oSelf);

if (oDoor == OBJECT_INVALID) return;
if (oWP == OBJECT_INVALID)
oWP = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", Loc, FALSE, 
      "DP" + GetTag(OBJECT_SELF));
DelayCommand(0.2, SetCommandable(FALSE, oSelf)); // заблокировать очередь
SetLocked(oDoor, FALSE);
if(GetObjectType(oDoor) == OBJECT_TYPE_DOOR)
AssignCommand(oSelf, ActionOpenDoor(oDoor));
else
{
AssignCommand(oSelf, ActionForceMoveToObject(oDoor, FALSE, 1.5, 15.0));
AssignCommand(oSelf, ActionPlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 2.0));
AssignCommand(oSelf, ActionDoCommand(AssignCommand(oDoor, 
              ActionPlayAnimation(ANIMATION_PLACEABLE_OPEN))));
}
AssignCommand(oSelf, ActionForceMoveToObject(oWP, FALSE, 0.0, 15.0));
AssignCommand(oSelf, ActionDoCommand(DelayCommand(0.3, SetFacing(fFas))));
// разблокировать очередь
AssignCommand(oSelf, ActionDoCommand(SetCommandable(TRUE, oSelf))); 
}

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