Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Город Мастеров _ Neverwinter Nights 2 Obsidian Toolset _ Азы скриптинга NWN/NWN2

Автор: Aiwan Oct 6 2007, 19:38

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

Во первых, забудьте что скрипты это трудно непонятно и сложно. Забудьте все то что бедный ваш мозг пытается обработать безуспешно и вы не можете понять простые вещи. Это нормально. Я буду говорить не по книгам а просто, описывая ситуацию или знания необходимые вам максимально понятно и по возможности проектировать это на бытовом уровне, оперируя образными картинками. Так как именно такие схемы будут работать в вашем случае. Ведь люди с математическим умом все схватывают сами и на лету. Итак начнем.

Скрипт сам по себе это маленький файлик. Он работает как любой файл в программе. То что вы пишете в редакторе это NSS просто информация для компилятора, в игре то что написано вами не работает, а работает скомпилированный файл NSC. Поэтому написанное в редакторе и не компельнутое не работает.

Как отличить код хорошего кодера от разгильдяя? По аккуратности и описаниям-комментариям. У тех, кто понимает скрипт все правильно, кто не понимает все кидает в кучу. Поэтому сразу учитесь писать красиво и понятно. Сделайте себе шапку для скриптов и пишите в ней, давая описания. В папке скриптов через пол года вы сможете понять кто и что сделал в скрипте и элементарно для чего вам он нужен. Это важно. Аккуратность.

Пример шапки скрипта:

Neverwinter Script Source
//:://////////////////////////////////////////////
//:: Name:
//:: Copyright © 2006 WRG! Team
//:://////////////////////////////////////////////
/*
    Описание
*/

//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 06.10.2007
//:://////////////////////////////////////////////

void main()
{ }


Дальше.

Автор: Aiwan Oct 6 2007, 20:37

Все функции в движке, это какие-то действия и примерно такие же куски кода как пишете вы, но они вставлены в движок и работают когда вы ими пользуетесь: создаете предмет, дестроите его, раздаете команды и т.д. Соотвественно, движок это не идеал, а обыкновенная программа и она имеет много неучтенных, ненайденных или незапротоколированных особенностей в исполнении функций. Поэтому вы должны сразу понять, что ТО ЧТО КОМПЕЛИТСЯ НЕ ВСЕГДА РАБОТАЕТ.

В скриптинге есть определенные типы данных с которыми мы будем работать.
Object - объект. Например, НПС, локация и т.д.
Стринг String - то что пишем буквами и движок понимает это как надписи. Например в фразы, имена и т.д.
Интеджер integer - это целое значение. может быть 1, 10, 25 и т.д.
Флоат Float - НЕцелое значение может быть 1.0, 23.04 и т.д.
Локация Location - это позиция, местоположение определенная точка.
Вектор vector - вектор.
Талант talent - я сам не знаю что это prankster2.gif
Эффект effect - кто много курил и ел всякую гадость в виде наркоты в ПЛ тот знает что это.

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

Для начала мы разберем самое простое - присвоене локальной переменной.

Neverwinter Script Source
// Set oObject's local integer variable sVarName to nValue
void SetLocalInt(object oObject, string sVarName, int nValue)


Итак, что это такое? Образно, локальная переменная это строка которая вписывается в служебное место любого объекта и состоит из буквенной строки и числового значения. Видите эта функция состоит из трех частей: Объект, Стринг, Число. Попросту вы метите объект и пишете на нем слово вашей переменной писваивая к нему знацение циферкой. Это вроде как повесить на спину Лекса бумажку и написать на ней ВАНЮЧКА, 1. А у Нео повесить бумажку ВАНЮЧКА, 2 и потом по этим данным работать с этимим объектами. Нужен вам ванючка со значением 2, смотрите на спинах у кого бумажка и делаете что вам надо. Так вот. Вы часто сталкивались с такими словами как TRUE и FALSE. Так вот, что бы вам было понятно вопрос КТО ИЗ АДМИНОВ ВАНЮЧКА будет выглядеть так: Лекс - TRUE, Нео TRUE, Айван - FALSE. Но. Движок НВН считает, что если на Айване нет бумажки с надписью ВАНЮЧКА или она есть, но выглядит так "ВАНЮЧКА, 0" то это FALSE. Попросту, если стереть на Лексе 1 и поставить там 0 то результат будет FALSE хоть и табличка будет висеть. Это надо учитывать в некоторых случаях. В виде кода это будет выглядеть так:

Присвоим:
Neverwinter Script Source
void main()
{
  object oAiwan = GetObjectByTag("Aiwan ROOT Boss");
  object oLex = GetObjectByTag("LEX Administrator");
  object oNeo = GetObjectByTag("NEO Ррразгильдяй");

  SetLocalInt(oLex, "VANUCHKA", 1);
  SetLocalInt(oNeo, "VANUCHKA", 2);
}


Вот так в скрипте диалога проверить, то что я сказал.

Neverwinter Script Source
int StartingConditional()
{
  object oLex = GetObjectByTag("LEX Administrator");
  if (GetLocalInt(oLex, "VANUCHKA") == 1)
  {
      return TRUE;
  }
  return FALSE;
}


Объект может содержать только одно значение переменной. Либо не иметь ее вообще. Скриптом можно менять значение и результаты будут разные. К примеру, в модулях часто одному квесту присваивают одну локальную переменную. А вот от ее значения зависит разные концовки.

Что непонятно спрашивайте.

Автор: Ёжик Oct 7 2007, 13:03

Кто такие Интеджер и Флоат? Почему oNeo, oLex, oAiwan? Что значит object oAiwan = GetObjectByTag("Aiwan ROOT Boss")? Что такое int StartingConditional()? Зачем скобки? void main - это что?

Автор: Aiwan Oct 7 2007, 19:44

Ёжик, я могу дать все эти понятия, но то что ты поймешь что это я не уверен. Пока, мне нужно общее ваше представление. Как только ты поймешь что все то что я написал означает свою задачу я сочту выполненой. Но раз такой расклад то могу все объяснить:

Цитата(Ёжик @ Oct 7 2007, 16:03) *
void main - это что?

NWScript использует 'функции', которые сообщают программе, что нужно делать. Некоторые функции уже написаны и нам остается только поставить их в скрипт. Тем не менее, когда мы пишем скрипт, мы, фактически, пишем свои собственные функции. Эта строка - своего рода 'установка' функции.
void - Это слово сообщает скрипту, какого рода 'ответ' выдаст функция.
Слово main сообщает, что это основная часть скрипта. Мы можем написать множество функций в нашем скрипте, но 'main' - эта та часть скрипта, которая будет непосредственно выполняться. Между '(' и ')' как правило пишут входящие данные, необходимые скрипту для корректного исполнения. Наш скрипт не требует никаких входных данных, и это значит, что между скобками ничего не пишется. Всегда необходимо ставить '(' и ')', даже если нет никаких входящих данных.

Фигурные скобки необходимы, чтобы отделять блоки скрипта один от другого. В нашем случае это обозначает, что все то, что мы написали, является частью void main(). Каждая строка заканчивается знаком ';'.

Про интеджер и флоат мне опять писать или что? Что непонятно? Тебе непоянтно что такое целое число а что нет?

Так же, в скрипте все типы данных и объекты обычно представляются в начале скрипта например так:

Neverwinter Script Source
//:://////////////////////////////////////////////
//:: OnEnter [CUT_FIN_1] am_cut_final_1
//:: Copyright © 2006 WRG!
//:://////////////////////////////////////////////
/*
         ФИНАЛЬНЫЙ РОЛИК ИСТОРИИ
*/

//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 23.03.2006
//:://////////////////////////////////////////////
#include "am_inc_cutscene"
#include "am_inc_common"

void main()
{
//------------------------------- СОЗДАНИЯ -------------------------------------
   object oPC = GetFirstPC(); // Игрок
   object oBoss = GetObjectByTag("AM_CUT1_BOSS"); // Главный
   object oNpc1 = GetObjectByTag("AM_CUT1_NPC_01"); // НПС 1
   object oNpc2 = GetObjectByTag("AM_CUT1_NPC_02"); // НПС 2
   object oDog = GetObjectByTag("AM_CUT1_DOG"); // Собака
   object oDeer = GetObjectByTag("AM_CUT1_DEER"); // Олень
   object oOx = GetObjectByTag("AM_CUT1_OX_01"); // Бык (живой)
   object oOxD = GetObjectByTag("AM_CUT1_OX_02"); // Бык (мертвый)
   object oArea = GetArea(oBoss);
//-------------------------------- ОБЪЕКТЫ -------------------------------------
   object oSound = GetObjectByTag("AM_CUT1_SOUND_WOLF"); // Звук воя волков
   object oSound1 = GetObjectByTag("AM_CUT1_SOUND_WOLF1"); // Звук воя волков
   object oFlame = GetObjectByTag("AM_CUT1_FLAME"); // Костер (потухший)
   object oGate = GetObjectByTag("AM_D_EXT_HUNT_GATE"); // Ворота во двор
   object oDoor = GetObjectByTag("AM_D_EXT_HUNT_H_IN"); // Дверь домика
//------------------------ ТОЧКИ ДВИЖЕНИЯ И КАМЕРЫ -----------------------------
   object oWpCamPC1 = GetWaypointByTag("AM_WP_CUT1_CAM_PC_01"); // Точки Игрока
   object oWpCamPC2 = GetWaypointByTag("AM_WP_CUT1_CAM_PC_02");
   object oWpExit = GetWaypointByTag("AM_WP_CUT1_EXIT"); // Для ухода с карты
   object oWpIn = GetWaypointByTag("AM_WP_CUT1_IN"); // Эмитация входа в дом
   object oWpP1 = GetWaypointByTag("AM_WP_CUT1_POST_01"); // Точка НПС
//-------------------------- ВИЗУАЛЬНЫЕ ЭФФЕКТЫ --------------------------------
   effect eCutInv = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
   effect eCutPar = EffectCutsceneParalyze();
   effect eGhost = EffectVisualEffect(VFX_DUR_GHOSTLY_VISAGE);
   effect eParalyz = EffectVisualEffect(VFX_DUR_FREEZE_ANIMATION); // Заставим застынуть
   effect eFreeze = EffectVisualEffect(VFX_DUR_ICESKIN); // Заморозим
//-------------------------- Поврежедния ---------------------------------------------
   int iMax = GetMaxHitPoints(oPC);
   int iD = iMax-5;


В таком виде мы обычно представляем все объекты и данные с которыми будем работать в скрипте. В скрипте мы обращаемся к объекту, но мы должны четко дать понять какой именно объект нам нужен. Самый простой способ это указать OBJECT_SELF. Это значит тот кто содержит или исполняет скрипт написаный вами будет взят в качестве объекта. К примеру, скрипт стоящий на НПС может взять object oNpc = OBJECT_SELF; Теперь вы заметили, что мы как то структурировали наши сокращения в описании объектов. Например, зачем нам постоянно писать одно и то же десятки раз типа: GetObjectByTag("AM_CUT1_BOSS") - тут мы говорим скрипту взять объект с тегом AM_CUT1_BOSS. Скрипт ищет в модуле у кого такой тег и берет его. Каждый раз это долго и неправильно. Мы попросту в начале найдем этого НПС и объявим его сократив до минимума oBoss. Вся строка будет выглядеть так:

Neverwinter Script Source
object oBoss = GetObjectByTag("AM_CUT1_BOSS"); // Главный


в ней мы говорим, что наш object oBoss ЭТО ОБЪЕКТ это не число и не эффект. Соотвественно для удобства мы сократили и поставили впереди буковку "o" что бы мы знали, что это ОБЪЕКТ. У интеджер мы обычно ставим буковку "i" и встретив в большом скрипте такие данные oPC, iMax, fDel мы уже понимаем что первый это ОБЪЕКТ так как у него буковка о, второй это число так как у него буковка i, третий это флоат нецелое число так как перед ним буковка f. Но все это ДЛЯ УДОБСТВА и никак не влияеет на работу скриптов. Это ПРАВИЛЬНЫЙ И ХОРОШИЙ ТОН.

Внизу простой пример как все правильно описав и сократив мы накладываем на OBJECT_SELF еффект.

Neverwinter Script Source
void main()
{
   object oSelf = OBJECT_SELF;
   int iMax = GetMaxHitPoints(oSelf);
   int iD = iMax-5;
   effect eDamage = EffectDamage(iD);

   AssignCommand(oSelf, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,
Self));
}

Neverwinter Script Source
void main()
{
   int iMax = GetMaxHitPoints(OBJECT_SELF);
   int iD = iMax-5;
   effect eDamage = EffectDamage(iD);
   AssignCommand(OBJECT_SELF, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,OBJECT_SELF));
}

Neverwinter Script Source
void main()
{
   int iD = GetMaxHitPoints(OBJECT_SELF)-5;
   effect eDamage = EffectDamage(iD);
   AssignCommand(OBJECT_SELF, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,OBJECT_SELF));
}

Neverwinter Script Source
void main()
{
   effect eDamage = EffectDamage(GetMaxHitPoints(OBJECT_SELF)-5);
   AssignCommand(OBJECT_SELF, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,OBJECT_SELF));
}

Neverwinter Script Source
void main()
{
   AssignCommand(OBJECT_SELF, ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectDa
age(GetMaxHitPoints(OBJECT_SELF)-5,OBJECT_SELF)));
}

Сравните первый код и этот последний. Они идентичны, но в каждом последующем я убрал описание по одному объекту или эффекту. В результате кусок кода разобрать на порядок труднее. И это ОДНА СТРОКА! А что будет если у вас тысяча строк?

Добавлено через 2 минуты 49 секунд

Я не прошу понимать что делает этот скрипт мне важно что бы вы на каждом следующем примере видели какое изменение произошло.

Добавлено через 11 минуту 31 секунду

п.с. При переносе форум съедает одну букву в строке NSS кода. Не пинать мну, не моя вина. Нео обещал найти причину.

Автор: Ёжик Oct 8 2007, 05:31

Цитата(Aiwan @ Oct 7 2007, 19:44) *
я могу дать все эти понятия, но то что ты поймешь что это я не уверен

ну тогда вычеркни меня и всё

Автор: Aiwan Oct 8 2007, 10:21

Цитата(Ёжик @ Oct 8 2007, 08:31) *
ну тогда вычеркни меня и всё

ВЫЧЕРКИВАЮ.

Добавлено через 9 минут 34 секунды

п.с. основные понятия по объектам и прочему даны в переводах Лексикона. Кому что то неясно почитайте еще там.
http://www.wrg.ru/index.php?method=files.open&id=58&sub=vaf

Добавлено через 2056 секунд

Я ХОЧУ ЧТО БЫ ВЫ ПОНЯЛИ. Мне не надо что бы вы поняли что сделал тот или иной скрипт. В тот самый момент, когда вы сможете ответить на это и на вопросы которые описала Ёжик в первом посте МОЖНО СЧИТАТЬ ЧТО ВЫ УЖЕ НАУЧИЛИСЬ ПОНИМАТЬ СКРИПТЫ. Я не могу за вас думать, вы должны напряч свой мозг и отогнать свою лень. Без этого не получится диалога здесь. Я ПРОШУ ПОНИМАТЬ ТО ЧТО ДАЮ Я. Если я дал описание чего то то и понимать осознавать надо ЭТО а не все, что содержит мой пример кода.

Автор: Griffon Oct 8 2007, 11:11

Цитата(Aiwan @ Oct 7 2007, 20:44) *
Между '(' и ')' как правило пишут входящие данные, необходимые скрипту для корректного исполнения.


1. Это ты про () после void main? Спрашиваю поскольку на примере твоего скрипта вот это же и есть данные
Neverwinter Script Source
object oSelf = OBJECT_SELF;
  int iMax = GetMaxHitPoints(oSelf);
  int iD = iMax-5;
  effect eDamage = EffectDamage(iD);


2. Зачем так сильно сокращать? Ведь в таком виде - понятно какие данные используются и как они прописаны в команде, разве нет?
Neverwinter Script Source
void main()
{
  object oSelf = OBJECT_SELF;
  int iMax = GetMaxHitPoints(oSelf);
  int iD = iMax-5;
  effect eDamage = EffectDamage(iD);

AssignCommand(OBJECT_SELF, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage-5,OBJECT_SELF));
}


3. DURATION_TYPE_INSTANT - вроде же есть цифровое значение соответствующее данной фразе? И если да, то в данных можно указать его через int, а в команде (AssignCommand) уже прописать саму цифру, или не так?

Добавлено через 26 минут 36 секунд

Цитата(Aiwan @ Oct 8 2007, 11:21) *
п.с. основные понятия по объектам и прочему даны в переводах Лексикона. Кому что то неясно почитайте еще там.
Перевод Лексикона
Ссылка битая

Добавлено через 6 минут 49 секунд

P.S. А может сайт опять полег?

Автор: Aiwan Oct 8 2007, 12:33

Griffon, Я ПРОСТО ПОКАЗАЛ ЧТО ПОЛУЧИТСЯ если не описывать и не сокращать. и не забегай вперед. Все разберем acute.gif Я про константу.

Добавлено через 1 минуту 23 секунды

Мне важно что бы вы УВИДЕЛИ что изменилось от шага к шагу.

Добавлено через 1 час 44 секунды

Уточнение. Что бы ыбло понятно.
Представление объекта, можно сравнить с прозвищем. Мы же не говорим постоянно Иванов Иван Иванович, мы говорим просто Вано. Коротко и понятно. Вот это выглядит так:

Neverwinter Script Source
object oВано = GetObjectByTag("Иванов Иван Иванович");

Автор: Neo Oct 8 2007, 12:52

Цитата(Griffon @ Oct 8 2007, 12:11) *
DURATION_TYPE_INSTANT

есть константа, что означает - постоянно принятая величина для данного скрипта, обозначенная идентификатором
в данном случае идентификатор - DURATION_TYPE_INSTANT, а величина описана в nwmain.nss
костанты могут быть числовыми и текстовыми, да любого типа
мастера, не пинайти сильна, объяснил как асилил

Добавлено через 1 минуту 33 секунды

Цитата(Ёжик @ Oct 8 2007, 06:31) *
ну тогда вычеркни меня и всё

Цитата(Aiwan @ Oct 8 2007, 11:21) *
ВЫЧЕРКИВАЮ.

ыххыыыыхыыыыыыы, ну вы ребята даете smile.gif а я не умею скриптить как лекс, вычеркивайте меня из БАНДЫ, что за детство, ей богу

Автор: Aiwan Oct 8 2007, 16:13

Не надо сложных понятий. Не надо пытаться понять что-то что я не прошу понять. Поймите то что даю. Пусть пока вам не понятны какие то слова в скрипте. Дойдем до этого.

Добавлено через 107 секунд

Так первое домашнее задание. Откройте тулсет и из этого скрипта сделайте вот что:

Neverwinter Script Source
void main()
{
  object oSelf = OBJECT_SELF;
  int iMax = GetMaxHitPoints(oSelf);
  int iD = iMax-5;
  effect eDamage = EffectDamage(iD);

  AssignCommand(oSelf, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,
Self));
}

Каждый в скрипте имя oSelf сменит на свой ник, например oAiwan и напишет в этой теме СВОЙ КОД. ПИШИТЕ В РЕДАКТОРЕ И КОМПИЛИТЕ. ЗАТЕМ ПЕРЕНОСИТЕ СЮДА.

п.с. ЕЖИК СНОВА В ТЕМЕ. Понедельник трудный день. Извини.

Добавлено через 2 часа 45 минут 52 секунды

ЕЩЕ РАЗ ПОВОРЯЮ ДЛЯ ВСЕХ. В ЭТОЙ ТЕМЕ ТОЛЬКО МОИ ПОСТЫ И ПОСТЫ ОБУЧАЮЩИХСЯ.

Автор: Solo Oct 8 2007, 19:49

ну если я правильно понял задание, то справился с ним yahoo.gif
вот что получилось:

Neverwinter Script Source
void main()
{
  object oSolo = OBJECT_SELF;
  int iMax = GetMaxHitPoints(oSolo);
  int iD = iMax - 5;
  effect eDamage = EffectDamage(iD);

  AssignCommand( oSolo, ApplyEffectToObject( DURATION_TYPE_INSTANT, eDamage, oSolo ) );
}


вот что написал компилятор:
08.10.2007 20:40:08: 0 Ошибок. 'script1' составление успешно

Автор: Aiwan Oct 8 2007, 21:28

Да ,все правильно. Но в следующий раз юзай тег NSS на форуме. yes3.gif

Автор: Vhall Oct 8 2007, 22:47

Neverwinter Script Source
void main()
{
  object oVhall = OBJECT_SELF;
  int iMax = GetMaxHitPoints(oVhall);
  int iD = iMax-5;
  effect eDamage = EffectDamage(iD);

  AssignCommand(oVhall, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,
oVhall));
}

В итоге результатом стало понимание работы бажного nss.

Автор: Artlira Oct 9 2007, 02:22

Neverwinter Script Source
void main()
{
  object oLira = OBJECT_SELF;
  int iMax = GetMaxHitPoints(oLira);
  int iD = iMax-5;
  effect eDamage = EffectDamage(iD);

AssignCommand(oLira, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage,oLira));

}



Мне кажется, единственная ошибка, которая могла быть в этом скрипте, это если в какой-нибудь строке не поменять oSelf на другое определение объекта?

Автор: Aiwan Oct 9 2007, 09:08

Цитата(Artlira @ Oct 9 2007, 05:22) *
Мне кажется, единственная ошибка, которая могла быть в этом скрипте, это если в какой-нибудь строке не поменять oSelf на другое определение объекта?

Совершенно верно. Мне важно, что бы вы поняли что oSelf это просто имя описываемого объекта. И оно используется во многих местах.

Автор: Griffon Oct 9 2007, 11:24

Neverwinter Script Source
void main()
{
    object oGriffon = OBJECT_SELF;
    int iMax = GetMaxHitPoints(oGriffon);
    int iD = iMax-5;
    effect eDamage = EffectDamage(iD);
   
    AssignCommand(oGriffon, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage,oGriffon));
}


Результат - 0.85.nss(1): ERROR: ELLIPSIS IN IDENTIFIER

Мы в каком пишем НВНе?


Автор: Aiwan Oct 9 2007, 12:48

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

Neverwinter Script Source
object oSelf = OBJECT_SELF;


Дананя строка сосотит из двух важных частей они заключены между знаком равно. В этой строке ДВА ДЕЙСТВИЯ. Первым, мы объявили скрипту, что у нас есть объект object oSelf. Второым мы ПРИРОВНЯЛИ этот наш объявлленный объект к OBJECT_SELF. Тем самый четко дали понять скрипту кто есть ХУ. Верхний код можно написать и таким образом:

Neverwinter Script Source
void main()
{
   object oSelf; // Объявляем скрипту, что у нас используется ОБЪЕКТ oSelf
   oSelf = OBJECT_SELF; // Определяем его прировняв к OBJECT_SELF
}


То же самое мы делаем и с двумя цифровыми данными в скрипте:

Neverwinter Script Source
int iMax = GetMaxHitPoints(oSelf);
    int iD = iMax-5;


Мы их представляем скрипту и что сократить написание сразу же определяем с помощью каких либо функций. В данном случае это понимается так:

Neverwinter Script Source
void main()
{
    object oSelf; // Объявляем скрипту, что у нас используется ОБЪЕКТ
    oSelf = OBJECT_SELF; // Определяем его прировняв

    int iMax; // Объявляем, что у нас будет использоваться интеджер с именем iMax
    iMax  = GetMaxHitPoints(oSelf); // Он будет равен >>
    // Get Max Hit Points ВЗЯТЬ МАКСИМАЛЬНЫЕ ХИТ ПОИНТЫ объекта oSelf

    int iD;  // объявляем, что у нас будет еще оно число
    iD = iMax-5; // Оно будет равно от максимального числа хитпоинов отнять 5
}


В общем суть на пальцах такая. Мы говорим: "В нашей команде есть ИГРОКИ (object, int, float). У них есть своя специализация и ФАМИЛИЯ." Когда мы объявляем ИГРОК то это представление объекта. Когда говорим ИГРОК ПЕТРОВ, ВРАТАРЬ СИДОРОВ, ЗАЩИТНИК ИВАНОВ, то это представление и определение кто именно. Игроки могут меняться и наше определение объекта может меняться в скриптах тоже. ЗАЩИТНИКИ, НАПАДАЮЩИЕ могут смениться. Не важно кто защищает ворота и кто в нападении. Мы можем их сменить. Но прежде чем ввести их в игру судья объявляет что игроки поменялись! Так же можно менять в скрипте.

Neverwinter Script Source
void main()
{
    object oSelf; // Объявляем скрипту, что у нас используется ОБЪЕКТ
    oSelf = OBJECT_SELF; // Определяем его прировняв

    int iMax; // Объявляем, что у нас будет использоваться интеджер с именем iMax
    iMax  = GetMaxHitPoints(oSelf); // Он будет равен >>
    // Get Max Hit Points ВЗЯТЬ МАКСИМАЛЬНЫЕ ХИТ ПОИНТЫ объекта oSelf

    int iD;  // объявляем, что у нас будет еще оно число
    iD = iMax-5; // Оно будет равно от максимального числа хитпоинов отнять 5

    effect eDamage; // объявляем, что у нас используется эффект
    eDamage = EffectDamage(iD); // Эффект Effect Damage поврежедения равен числу iD

    if(GetIsPC(oSelf)==TRUE) // Если oSelf это РС
    {
      // Если это игрок то мы сменим определение еффекта и вылечим РС
      eDamage = EffectHeal(iMax); // на число iMax его максимальные хитпоинты
    }
    AssignCommand(oSelf, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,
Self));
}


Если есть вопросы спрашивайте.

Добавлено через 106 секунд

Мне важно, что бы вы поняли описание объектов и их определение можно менять в скрипте.

Добавлено через 54 секунды

Скажите что изменилось в скрипте?
Neverwinter Script Source
void main()
{
  object oSelf = OBJECT_SELF;
  int iMax = GetMaxHitPoints(oSelf);
  int iD = iMax-5;
  effect eDamage = EffectDamage(iD);

  if(GetIsPC(oSelf)==TRUE)
  {
      eDamage = EffectHeal(iMax);
  }
  AssignCommand(oSelf, ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,
Self));
}

Автор: Artlira Oct 9 2007, 13:18

Изменилась сама программа скрипта. Теперь он работает выборочно, то есть одному из объектов – в данном случае игроку будет явная выгода (лечение), а у всех прочих по-прежнему изымет по 5 хитов?

Автор: Aiwan Oct 9 2007, 13:19

Самое главное что мы сделали? Мы ПОМЕНЯЛИ ефекты.

Автор: Griffon Oct 9 2007, 13:32

Цитата(Artlira @ Oct 9 2007, 14:18) *
а у всех прочих по-прежнему изымет по 5 хитов

Эффекты конечно же сменились, но чуть поправлю предыдущее высказывание - оно будет верным, если скрипт не запускается единожды. В противном случае или пан или пропал. Причем оба и игрок и его соперни к на шарде (если для него) или нпс (он ведь тоже попадет под раздачу, если станет выпонять определенные действия.

Автор: Artlira Oct 9 2007, 14:38

Если я правильно понимаю, то смысл в том, что скриптом можно определить любой, необходимый в конкретном случае объект (непись, игрок, плейс). И заставить этот объект выполнить действие (серию действий) или (в этом примере) наложить на него эффект, который нужен в определенной ситуации?
Смысл не в конкретном скрипте, а в том, как и что можно заставить работать?

Автор: Griffon Oct 9 2007, 14:53

Все верно, основной смысл кода в том - кто и что будет делать.

Автор: Aiwan Oct 9 2007, 14:54

Griffon, не гони лошадей многим это будет не понять. declare.gif Сейчас важно видеть ПРОСТОЕ то что я говорю.

Автор: Griffon Oct 9 2007, 15:01

Все, передаю слово учителю. Хотя учащимся стоит понять, что такое код и что он может делать, ну конечно, при ограничениях по имеющимся функциям.

Автор: Vhall Oct 9 2007, 18:48

QUOTE(Aiwan @ Oct 9 2007, 13:48) *
Скажите что изменилось в скрипте?

Объекты, целые и эффекты задаются по-разному?

Автор: Griffon Oct 10 2007, 15:35

Цитата(Griffon @ Oct 9 2007, 12:24) *
Neverwinter Script Source
void main()
{
object oGriffon = OBJECT_SELF;
int iMax = GetMaxHitPoints(oGriffon);
int iD = iMax-5;
effect eDamage = EffectDamage(iD);

AssignCommand(oGriffon, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage,oGriffon));
}


Результат - 0.85.nss(1): ERROR: ELLIPSIS IN IDENTIFIER


Почему же пишет что ошибка? И что это за ошибка?

Автор: Aiwan Oct 10 2007, 16:05

Цитата(Griffon @ Oct 10 2007, 18:35) *
Почему же пишет что ошибка? И что это за ошибка?

Может из за НВН2 функций. Я пока компилю на первом НВН так как второй еще не ставил, карту недавно купил и винду переставил. Попробуй в первом редакторе компильнуть. Не переживайте логика и все что в первом НВн то и во втором. Но в редакторе первого НВН легче и понятней. Так что рекомендую юзать пока его.

Автор: mamuc Oct 11 2007, 10:43

Цитата
Результат - 0.85.nss(1): ERROR: ELLIPSIS IN IDENTIFIER

Griffon у тебя имя файла "0.85" ?

Автор: Griffon Oct 11 2007, 11:56

Цитата(mamuc @ Oct 11 2007, 11:43) *
Griffon у тебя имя файла "0.85" ?


Какого? Что за файл? Я не сохранял скрипт, написал и просто нажал скомпилировать. Может после перехода на след строку не нужно табуляцией сдвигать ее в право, он сам сдвинет?

Автор: mamuc Oct 11 2007, 12:12

в тулсете при компиляции обязательно создаеться файл rolleyes.gif

Цитата
Результат - 0.85.nss(1): ERROR: ELLIPSIS IN IDENTIFIER


сообщение о ошибке следует читать так
"0.85" имя файла меня здесь делает осторожным присутствие точки ( есть древнее правило неупотреблять в именах некоторые специальные симболы, в частности точка в имени файла должна отделять имя и тип файла и не использоваться никак иначе)
"nss" - это и есть тот тип файла про который я упоминал выше
"(1)" - номер строки в котором произошла ошибка
"ERROR: ...." что именно компилятору не нравиться
попробуй написать скрипт и сохранить его под каким то другим именем и потом прокопилировать

Автор: Griffon Oct 11 2007, 13:26

Уфффф..... Пока разобрался crazy.gif

2mamuc, спасибо за подсказку, помогло найти что вызывало сбой.

По порядку... та ошибка появлялась когда просто создавал новый скрипт - файл -> создать -> скрипт. Оболочка редактора у меня почему-то на русском, видно из-за региональных настроек, надо будет проверить перед очередным запуском.

Затем создал локацию -> затем новый скрипт -> написал, причем именно так без отступлений

Neverwinter Script Source
void main()
{
object oChest = OBJECT_SELF;
object oItem = GetFirstItemInInventory(oChest);
while (GetIsObjectValid(oItem))
{
DestroyObject(oItem);
oItem = GetNextItemInInventory(oChest);
}


Получил ошибку - None.nss(1): ERROR: INVALID DECLARATION TYPE □

После этого переименовал локацию с зона1 на zone1 и Скрипт1 на script1 и еще раз -> компилировать. И, о чудо! выдал ответ, что компиляция успешна, файл находится там-то и там-то. Спасибо.



Добавлено через 23 минуты 13 секунды

P.S. Сменил язык на английский и компилит без проблем file -> new -> script biggrin.gif

Автор: Lex Oct 11 2007, 13:46

Цитата(Griffon @ Oct 11 2007, 14:26) *
Скрипт1 на script1

самое важное. На русском названия скриптов низя писать. Поэтому от русификаторов в работе с тулсетом лучше держаться подальше - русские дефолтовые названия порождают проблемы.

Автор: mamuc Oct 12 2007, 08:58

to Griffon только добавь в тобой приведенном примере еще одну закрывающую скобку плз biggrin.gif

Автор: Aiwan Oct 12 2007, 10:14

Такс... Продолжаем разговор (с) Карлсон который живет на крыше.

Мы с вами уже изучили то, что объекты, еффекты и прочие данные можно и НУЖНО описывать заранее. Теперь мы немного разберем то, как определить объект? Мы взяли очень простую схему OBJECT_SELF. попросту говорим что oSelf это ты сам. Но не всегда так просто можно найти нужный объект. В тулсете полно функций, которые определяют объект, например по тегу.

Neverwinter Script Source
object oNpc = GetObjectByTag("NPC_AIWAN");


Функция Get Objec tBy Tag говорит Взять Объект С Тегом. Но вы должны учитывать, что такой объект должен быть с уникальным тегом, что бы ваш скрипт работал нормально. Либо вы должны будете описать еще условия которые позволят найти вам ваш нужный объект. К примеру, если у вас несколько одинаковых НПС и вам нужен один из них то омжно воспользоваться функцией Get Nearest Object By Tag которая говорит Взять Ближайший Объект с Тегом. Эта функция имеет несколько параметров, в ней можно задать условие ближайший объект от кого? Ведь надо точно указать точку отсчета ближайшего объекта от, например двери. По умолчанию у скрипт будет брать ближайший объект от того кто запустил скрипт. Если скрипт стоял на триггере то возьмет ближайший от него. Дети ктороые играют в салочки кричат: "Кто последний тот тухлый банан! Кто первый тот чемпион!" и бегут в дверь. Так вот, чемпион будет именно тот, кто первым добежит и он скорее всего самый ближайший объект у двери. А зачастую он и кричит такую фразу. Всем задание. Создайте в редакторе модуль. Поставьте одну внутреннюю локацию. В ней три нпс с тегами NPC_ВАШ_НИК, поставьте дверь с тегом DOOR_ВАШ_НИК. Начертите подальше от двери триггер и на сло OnEnter поставьте скрипт и настройте его в соответсвии с вашими тегами.

Neverwinter Script Source
// Поиск чемпиона канады
void main()
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag("DOOR_AIWAN_01"); // Наша дверь
  object oNpc = GetNearestObjectByTag("NPC_AIWAN", oDoor);
  object oPC = GetEnteringObject(); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последний тот тухлый банан!"; // Фраза

  if(GetIsPC(oPC)) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
  {
    AssignCommand(oNpc, ClearAllActions()); // Чистим стек команд
    AssignCommand(oNpc, SpeakString(sSpeak)); // Говорит фразу
    AssignCommand(oNpc, ActionForceMoveToObject(oDoor, TRUE)); // Бежит к двери
    // Если убрать TRUE то НПС просто пойдет пешком...
  }
}


В этом скрипте мы находим объекты как то: по тегу (Двери), по действию (Тот кто наступил на триггер), и берем ближайший с тегом. Мне важно что бы вы хотя бы попробовали и поняли как это все работает.

Для того что бы понять что я дал поставьте НПС в линейку между триггером и дверью. Потом посомтрев что происходит вы удалите в строке:
Neverwinter Script Source
object oNpc = GetNearestObjectByTag("NPC_AIWAN", oDoor); // Измените на
  object oNpc = GetNearestObjectByTag("NPC_AIWAN"); // ЭТО


Мы поменяли точку отсчета и теперь к двери побежит ближайший к ТРИГГЕРУ объект. У кого все получилось говорите. У кого что не получилось тоже. Жду...

Автор: Artlira Oct 13 2007, 02:58

[ OFFTOP ]
В первом варианте к определение объекта (oNpc) было указано, как объект с заданным тагом, ближайший к двери (oDoor). Тот из трех неписей, который был ближе всех к двери к ней и побежал и произнес фразу.
Neverwinter Script Source
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "DOOR_LIRA_01" ); // Наша дверь
  object oNpc = GetNearestObjectByTag( "NPC_LIRA", oDoor ); //Ближайший к двери объект
  object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последний тот тухлый банан!"; // Фраза

  if( GetIsPC( oPC )) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
  {
    AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
    AssignCommand( oNpc, SpeakString( sSpeak )); // Говорит фразу
    AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE )); // Бежит к двери
    // Если убрать TRUE то НПС просто пойдет пешком...
  }
}

Во втором варианте изменилось определение объекта, то есть не было указано, ближайший к чему. Наверно, поэтому, к двери побежал тот непись, который был ближе к триггеру. Сменился приоритет объекта – по отношению к которому выбирался ближайший. Еще я убрала TRUE – непись действительно не побежал, а пошел!
Neverwinter Script Source
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "DOOR_LIRA_01" ); // Наша дверь
  object oNpc = GetNearestObjectByTag( "NPC_LIRA" ); //Ближайший к триггеру объект
  object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последний тот тухлый банан!"; // Фраза

  if( GetIsPC( oPC )) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
  {
    AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
    AssignCommand( oNpc, SpeakString( sSpeak )); // Говорит фразу
    AssignCommand( oNpc, ActionForceMoveToObject( oDoor )); // Идет к двери
  }
}

Вроде все получилось.

Автор: Lex Oct 13 2007, 09:58

советую так же, как и на внеклассных занятиях, прятать скрипты, чтобы другие участники случайно не увидели. smile.gif

Автор: Vhall Oct 13 2007, 17:45

О! Побежал. -_-

[ OFFTOP ]
Neverwinter Script Source
// Поиск чемпиона канады
void main()
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag("PLC_DC_Slum01"); // Наша дверь
  object oNpc = GetNearestObjectByTag("n_watchman", oDoor);
  object oPC = GetEnteringObject(); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последний тот тухлый банан!"; // Фраза

  if(GetIsPC(oPC)) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
  {
    AssignCommand(oNpc, ClearAllActions()); // Чистим стек команд
    AssignCommand(oNpc, SpeakString(sSpeak)); // Говорит фразу
    AssignCommand(oNpc, ActionForceMoveToObject(oDoor, TRUE)); // Бежит к двери
    // Если убрать TRUE то НПС просто пойдет пешком...
  }
}


Neverwinter Script Source
// Поиск чемпиона канады
void main()
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag("PLC_DC_Slum01"); // Наша дверь
  object oNpc = GetNearestObjectByTag("n_watchman", oDoor);
  object oPC = GetEnteringObject(); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последний тот тухлый банан!"; // Фраза

  if(GetIsPC(oPC)) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
  {
    AssignCommand(oNpc, ClearAllActions()); // Чистим стек команд
    AssignCommand(oNpc, SpeakString(sSpeak)); // Говорит фразу
    AssignCommand(oNpc, ActionForceMoveToObject(oDoor)); // Идет к двери
    // Если убрать TRUE то НПС просто пойдет пешком...
  }
}

Автор: shadowdweller Oct 16 2007, 23:01

Бежит!

[ OFFTOP ]
Neverwinter Script Source
// Поиск чемпиона канады
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "DOOR_KOSHIKO" ); // Наша дверь
  object oNpc = GetNearestObjectByTag( "KOSHIKO", oDoor );
  object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последним прибежит, тот прибежит последним!!"; // Фраза ( (С ) Тигра )

  if( GetIsPC( oPC ) ) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
  {
    AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
    AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
    AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери
    // Если убрать TRUE то НПС просто пойдет пешком...
  }
}

Neverwinter Script Source
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "DOOR_KOSHIKO" ); // Наша дверь
  object oNpc = GetNearestObjectByTag( "NPC_KOSHIKO" ); //Ближайший к триггеру объект
  object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последним прибежит, тот прибежит последним!!"; // Фраза  ( (С ) Тигра )

  if( GetIsPC( oPC ) ) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
  {
    AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
    AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
    AssignCommand( oNpc, ActionForceMoveToObject( oDoor ) ); // Идет к двери
  }
}


Автор: Aiwan Oct 17 2007, 10:12

Продолжаем.
Итак, мы уже говорили о том, что объект мало описать и представить, его надо точно ОПРЕДЕЛИТЬ. В нашем скрипте про трех НПС мы находили игрока взяв любого, кто наступил на триггер, потом мы поставили условие, что только тот если он представляет из себя РС выполнить следующее.

Neverwinter Script Source

  if( GetIsPC( oPC ) ) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
  {
      // ТУТ ЛЮБОЕ ДЕЙСТВИЕ
  }


Этот кусок кода содержит функцию, которая вовращает результат в виде TRUE или FALSE. Вы напряглись и начали дико соображать. О как все сложно! Никапельки. Объясняю. Все функции в тулсете выдают какой то результат, производят действия и т.д. Результат может быть в виде любый знакомых нам данных (integer, object, string, vector и т.д.) либо ИСТИНА/ЛОЖЬ. Мы в нашей скрипте проверяли истино ли то, что тот кто наступил на триггер игрок? Но я написал эту строку сокращенно, по всем правилам она будет выглядеть так:

Neverwinter Script Source

   if( GetIsPC( oPC )==TRUE ) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ
   {
      // ТУТ ЛЮБОЕ ДЕЙСТВИЕ ЕСЛИ НАСТУПИВШИЙ == ИСТИНА
   }


Вот так правильно описать, но в написании скриптов есть свои сокращений и вам их надо будет знать. Функция GetIsPC проверяет объект на то, игрок он или нет (может он ДМ или НПС). И выдает результат в виде TRUE (ИСТИНА) FALSE (ЛОЖЬ). Если не ставить знак проверки результата что делают многие в описании своих скриптов, то результат ИСТИНА будет внутри скобок а ЛОЖЬ дальше. Теперь смотрите как выглядит сама функция:

Neverwinter Script Source

// * Returns TRUE if oCreature is a Player Controlled character.
int GetIsPC( object oCreature )


Видите, она в самом начале показывает, что результатом будет ЧИСЛОВОЕ значение в нашем случае FALSE это НОЛЬ 0 либо TRUE ЭТО ЕДИНИЦА 1. В компьютере все данные представлены именно в таком виде либо да либо нет smile.gif Если разобрать подробно, то функция будет выглядеть так:

Neverwinter Script Source

int GetIsPC( object oCreature )
// Результат либо FALSE либо TRUE ИГРОК_ЛИ( Объект, который мы проверяем )


Еще я употребил ДВА занка равенства вместе. Это проверка равенства. Вот если я употребляю один знак равно, как в описании объектов, то я ПРИРАВНИВАЮ а не проверяю. Понимаете разницу? Написав "ЛЕКС = ВАНЮЧКА" будет звучать как Лекс ЭТО ВАНЮЧКА! А "ЛЕКС == ВАНЮЧКА" будет означать "Лекс ВАНЮЧКА или нет?" Утверждение "ЛЕКС != ВАНЮЧКА" будет звучать как "Лекс НЕ ВАНЮЧКА!"

Код
= =    Тест равенства ("равняется").
!=    Тест не равенства ("не равняется").
<    Меньше чем, тест равенства
>    Больше чем, тест равенства
<=    Меньше или равно, тест равенства
>=    Больше или равно, тест равенства
&&    Логическое И.
&    Битовое И.
||    Логическое ИЛИ.
|    Битовое ИЛИ.
!    Логическое НЕ.


Вот все логические операторы. Можно не пугаться нам пока нужны основные и все примеры мы разберем подробно. Вам не надо забивать голову всеми правилами сокращений, главное, что бы вы понимали суть скрипта, а уж пишите как вам удобно и главное ПОНЯТНО. Когда вы научитесь хорошо понимать код вы сами все свои написания приведете в должный порядок.

Я сейчас покажу как можно записать один и тот же результат разными способами:

Neverwinter Script Source
   if( GetIsPC( oPC ) ) // ЕСЛИ тот кто наступил ИГРОК ТО ВЫПОЛНЯЕМ

   if( GetIsPC( oPC )==TRUE ) // ЕСЛИ тот кто наступил ИГРОК равено TRUE

   if( GetIsPC( oPC )==1 ) // ЕСЛИ тот кто наступил ИГРОК равно 1

   if( GetIsPC( oPC )!=FALSE ) // ЕСЛИ тот кто наступил ИГРОК НЕ равно ЛОЖЬ

   if( GetIsPC( oPC )!=0 ) // ЕСЛИ тот кто наступил ИГРОК НЕ равно 0


Так вот, вернемся в начало. Мы в скрипте брали того, кто наступит на триггер и проверяли это ли игрок? Это очень важно правильно задать вопрос, что бы получить на него правильны и нужный нам ответ для скрипта. В тулсете много функций которые помогают найти объект по действиям последнего: кто наступил, кто сошел, кто ближе, кто получил урон, кто умер и т.д. Естественно на слоте триггера OnEnter трудно получить результат GetLastOpenedBy() (кто последний открыл). Это одна из первых основных ошибок. Учитывайте где утсановлен скрипт и если вы взяли кусок кода из скрипта на сундуке то он может не подойти в описании РС для триггера.

Теперь задание. Ваш рабочий скрипт про трех НПС поместите в слот OnExit триггера и опишите игрока правильно при этом условие if(GetIsPC(oPC)) должно быть любым другим способом описанным выше мной. Результаты публиковать, но главное что бы был ответ и понимание того что вы сделали. Отвечать в тему. Жду.

Автор: Artlira Oct 19 2007, 11:35

Вот что получилось:

[ OFFTOP ]
В первом варианте скрипт стоял на OnEnter, поэтому игрок определялся как объект, наступивший на триггер.
Если скрипт поставить на OnExit, то надо будет поменять определение объекта, с ”того кто наступил”(GetEnteringObject()), на ”того кто сошел с триггера”(GetExitingObject())?
То есть object oPC = GetExitingObject()
И сам скрипт в таком случае будет выглядеть так:
Neverwinter Script Source
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "DOOR_LIRA_01" ); // Наша дверь
  object oNpc = GetNearestObjectByTag( "NPC_LIRA", oDoor ); //Ближайший к двери объект
  object oPC = GetExitingObject( ); // Тот кто сошел с триггера
  string sSpeak = "Кто последний тот тухлый банан!"; // Фраза

  if( GetIsPC( oPC )==TRUE ) // ЕСЛИ тот кто наступил ИГРОК равно Истина( TRUE )
  {
    AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
    AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
    AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери
  }
}

И сработать скрипт будет должен после того, как игрок сойдет с триггера, а не наступит на него.

Автор: Aiwan Oct 20 2007, 12:02

Господа и дамы. Так мы все позабываем...Давайте хотя бы перерывы большие не делать. Процесс обучения может быть только обоюдный я говорю, вы делаете простые задания. ТОЛЬКО я писать не буду, толку от этого без практики мало.

Автор: Vhall Oct 22 2007, 08:51

[ OFFTOP ]
Neverwinter Script Source
// Поиск чемпиона канады
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "PLC_DC_Slum01" ); // Наша дверь
  object oNpc = GetNearestObjectByTag( "n_watchman", oDoor );
  object oPC = GetExitingObject( ); // Тот кто СОШЕЛ с триггера
  string sSpeak = "Кто последний тот тухлый банан!"; // Фраза

if( GetIsPC( oPC )==1 ) // ЕСЛИ тот кто наступил ИГРОК равно 1
  {
    AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
    AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
    AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери
    // Если убрать TRUE то НПС просто пойдет пешком...
  }
}

Edited

Автор: Aiwan Oct 22 2007, 10:02

Vhall, ты ошибся. В какой слот ты ставил скрипт? А каким образом определял игрока? Подумай внимательно.

Добавлено через 54 минуты 24 секунды

п.с. Теперь верно. Понял что важно при условиях срабатывания скрипта, так же правильно указывать условия поиска объекта?

Автор: Vhall Oct 22 2007, 10:13

Ну как тебе сказать... -_-
Вроде бы.

Автор: Aiwan Oct 26 2007, 12:12

Так. Продолжаем.

Я уже разбирал в начале, что такое переменная. Теперь самое время применить знания на практике. Но мыдолжны сперва с вами изучить структуру постороения скрипта. Так вот, внутри скрипта все делится на блоки со своими условиями. Естественно можно обойтись простым действием без блоков, но мы разберем сложный скрипт в котором четыре блока. Вот они:

Neverwinter Script Source
void main( )
{
      if ( TRUE ) // это ПЕРВЫЙ БЛОК
      {
            if ( TRUE ) // это ВНУТРИПЕРВЫЙ БЛОК относится к первому блоку он ВЛОЖЕН в него
            {
                // выполняем какое то действие для ВНУТРИПЕРВОГО БЛОКА
            }

            // тут выполняется то что мы хотим для ПЕРВОГО БЛОКА
      }

      if ( TRUE ) // это ВТОРОЙ БЛОК
      {
            // тут выполняется то что мы хотим для ВТОРОГО БЛОКА
      }

      if ( TRUE ) // это ТРЕТИЙ БЛОК
      {
            // тут выполняется то что мы хотим для ТРЕТЬЕГО БЛОКА
      }
}


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

Neverwinter Script Source

void main( )
{
   object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
   object oDoor = GetObjectByTag( "DOOR_AIWAN_01" ); // Наша дверь
   object oNpc; // Объявим НПС но не укажем, кто он именно
   object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
   string sSpeak = "Кто последний тот тухлый банан!";

   if( GetIsPC( oPC ) == TRUE ) // Если это верно ТО выполняется то что между скобок
   { // ПЕРВАЯ открытая скобка

     /* ВТОРОЙ ВНУТРЕННИЙ БЛОК */

     if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" )== 1 ) // Если локалка РАВНА 2 ТО:
     { // ВТОРАЯ открытая скобка

        oNpc = GetNearestObjectByTag( "NPC_AIWAN" );
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 2 );
        SendMessageToPC( oPC, "Сработал второй блок" );

     } // ВТОРАЯ закрытая скбка

     /* ТРЕТИЙ ВНУТРЕННИЙ БЛОК */

     if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 0 )
     { // ТРЕТЬЯ открытая

        oNpc = GetNearestObjectByTag( "NPC_AIWAN" );
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 1 );
        SendMessageToPC( oPC, "Сработал третий блок" );
     }  // ТРЕТЬЯ закрытая

     /* ТУТ НУЖНО ДОПИСАТЬ ЕЩЕ ОДИН БЛОК*/

      SendMessageToPC( oPC, "Сработал ОСНОВНОЙ блок" );
      AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
      AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
      AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери

   } // ПЕВАЯ закрытая скобка

}


В этом скрипте, каждый раз наступая на триггер один НПС бежит к двери. Что бы вам было понятно какой кусок кода работает я работу скрипта пояснил дебаг сообщениями. Этот скрипт сработает ДВА раза. Ваша задача, сделать так, что бы все ТРИ нпс убежали, а попросту, сдобавить один блок внизу, что бы скрипт срабатывал постоянно. Название переменной содержит ВАШ ник. Для самых сообразительных задача посложнее. Сделать так, что бы каждый раз НПС говорили разные фразы.

Что неясно спрашивайте.

Автор: Artlira Oct 27 2007, 08:50

Что-то у меня не все получается…

Сделать так, что бы неписи говорили разные фразы у меня получилось. Просто скопировала вариант с определением object oNpc;
То есть string sSpeak; указала, что фраза будет, но не писала какая именно.
А потом в каждом блоке добавила строчку:
sSpeak = ”фраза”; (фраза_1, фраза_2)

А вот с четвертым блоком у меня почему-то не получается. Вроде, если рассуждать логически, то в 4 блоке необходимо сделать проверку на переменную LIRA_PC_DO_IT, 2 и дальше просто ”обнулить” ее. В этом случае скрипт должен будет постоянно работать, присваивая переменные триггеру, затем, обнуляя последнюю, возвращаться снова к 0, то есть к отсутствию переменной.
Записала так:

[ OFFTOP ]

Neverwinter Script Source
void main( )
{
   object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
   object oDoor = GetObjectByTag( "DOOR_LIRA_01" ); // Наша дверь
   object oNpc;
   object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
   string sSpeak;

   if( GetIsPC( oPC ) == TRUE )
   {

  /* ВТОРОЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" )== 1 )
     {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Тухлый банан будет следующий!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IT", 2 );
        SendMessageToPC( oPC, "Сработал второй блок" );

     }

  /* ТРЕТИЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" ) == 0 )
     {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Кто последний тот тухлый банан!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IT", 1 );
        SendMessageToPC( oPC, "Сработал третий блок" );
     }

     /* ЧЕТВЕРТЫЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" ) == 2 )
     {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Сам ты тухлый банан!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IT", 0 );
        SendMessageToPC( oPC, "Сработал четвертый блок" );
     }

      SendMessageToPC( oPC, "Сработал ОСНОВНОЙ блок" );
      AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
      AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
      AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери

   }

}



Скрипт действительно срабатывает постоянно, но сам 4 блок не работает… Нет фразы из этого блока и неписи бегут только по условиям блока 2 и 3…
Когда присваивается переменная LIRA_PC_DO_IT, 2, скрипт продолжая считывать условие, автоматически ее проверяет и тут же обнуляет в 4 блоке. Поэтому в следующий раз, когда игрок наступает на триггер, у триггера уже нет переменной LIRA_PC_DO_IT, 2 и он срабатывает при условии, что LIRA_PC_DO_IT ==0…
В модуле это хорошо видно по сообщениям:
”Сработал второй блок”
”Сработал четвертый блок”
”Сработал ОСНОВНОЙ блок”
Получается, что задание вроде бы выполнено, все три непися уходят, скрипт работает постоянно, за счет переменных на триггере, а вот с фразами не могу разобраться.
Не могу понять, как заставить работать и 4 блок?

Автор: Aiwan Oct 27 2007, 09:21

Ты написала все верно, молодец. Я не просил, что бы в блоке что то делали. Мне важно было что бы вы поняли как изменить переменную. smile.gif Молодец good.gif Что бы все блоки работали как ты говоришь, надо просто сделать задержку DelayCommand типа:

Neverwinter Script Source

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" )== 1 ) // Если локалка РАВНА 2 ТО:
    { // ВТОРАЯ открытая скобка

        oNpc = GetNearestObjectByTag( "NPC_AIWAN" );
        DelayCommand( 0.3, SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 2 ));
        SendMessageToPC( oPC, "Сработал второй блок" );

    } // ВТОРАЯ закрытая скбка


Что бы переменная присваивалась уже тогда, когда скрипт сработал. 0.3 секунды обчно хватает. В этом скрипте и 0.1 секунды хватит, он короткий. А у тебя блоки срабатывают, просто два блока вместе. Все верно. wink3.gif И фраза берется из того блока, который сработал последним.

Добавлено через 2 минуты 1 секунду

п.с. А скажи, как еще можно изменить скрипт и сделать все три блока рабочими? Даю подсказку. Ввести новую переменную...

Автор: Artlira Oct 29 2007, 04:38

Цитата
Что бы все блоки работали как ты говоришь, надо просто сделать задержку DelayCommand типа:

Понятно. Сделала через DelayCommand() - все заработало! yahoo.gif

Цитата
п.с. А скажи, как еще можно изменить скрипт и сделать все три блока рабочими? Даю подсказку. Ввести новую переменную...


Через другую переменную заставить просто работать 4 блок у меня получилось. Перенесла 4 блок наверх, что бы он не сработал сразу после присвоения переменной, и во втором блоке добавила еще одну переменную.

[ OFFTOP ]
Neverwinter Script Source
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "DOOR_LIRA_01" ); // Наша дверь
  object oNpc;
  object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
  string sSpeak;

  if( GetIsPC( oPC ) == TRUE )
  {
/* ЧЕТВЕРТЫЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IS" ) == 1 ) // Проверяю вторую переменную
    {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Сам ты тухлый банан!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IS", 2 );
        SendMessageToPC( oPC, "Сработал четвертый блок" );
    }
  /* ВТОРОЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" )== 1 )
    {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Тухлый банан будет следующий!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IS", 1 );  //Другая переменная
        SetLocalInt( oTrigger, "LIRA_PC_DO_IT", 2 );
        SendMessageToPC( oPC, "Сработал второй блок" );

    }

  /* ТРЕТИЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" ) == 0 )
    {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Кто последний тот тухлый банан!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IT", 1 );
        SendMessageToPC( oPC, "Сработал третий блок" );
    }

      SendMessageToPC( oPC, "Сработал ОСНОВНОЙ блок" );
      AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
      AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
      AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери

  }

}


Срабатывают все три блока по очереди, но по одному разу. Все попытки сделать так, что бы скрипт еще и работал постоянно на одних переменных не получается.

Автор: Aiwan Oct 29 2007, 06:56

Neverwinter Script Source

void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "DOOR_LIRA_01" ); // Наша дверь
  object oNpc;
  object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
  string sSpeak;

  if( GetIsPC( oPC ) == TRUE )
  {

  /* ВТОРОЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" )== 1 && GetLocalInt( oTrigger, "WAIT" )==FALSE )
    {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Тухлый банан будет следующий!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IT", 2 );
        SendMessageToPC( oPC, "Сработал второй блок" );
        SetLocalInt( oTrigger, "WAIT", TRUE );
    }

  /* ТРЕТИЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" ) == 0  && GetLocalInt( oTrigger, "WAIT" )==0 )
    {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Кто последний тот тухлый банан!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IT", 1 );
        SendMessageToPC( oPC, "Сработал третий блок" );
        SetLocalInt( oTrigger, "WAIT", 1 );
    }

    /* ЧЕТВЕРТЫЙ ВНУТРЕННИЙ БЛОК */

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" ) == 2  && !GetLocalInt( oTrigger, "WAIT" ))
    {

        oNpc = GetNearestObjectByTag( "NPC_LIRA" );
        sSpeak = "Сам ты тухлый банан!";
        SetLocalInt( oTrigger, "LIRA_PC_DO_IT", 0 );
        SendMessageToPC( oPC, "Сработал четвертый блок" );
        SetLocalInt( oTrigger, "WAIT", TRUE );
    }

      SetLocalInt( oTrigger, "WAIT", FALSE ); // SetLocalInt( oTrigger, "WAIT", 0 );
      SendMessageToPC( oPC, "Сработал ОСНОВНОЙ блок" );
      AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
      AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
      AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери

  }

}


В каждом блоке надо сделать проверку двух переменных сразу вот так как на скрипте:

Neverwinter Script Source

if ( GetLocalInt( oTrigger, "LIRA_PC_DO_IT" ) == 0  && GetLocalInt( oTrigger, "WAIT" )==0 )


Если есть одна переменная и (&&) нет воторй ТО. Сразу же в сработавшем блоке ставим еще ту переменную WAIT какую мы проверяем для одного раза. Теперь любой другой блок не сработает так как мы уже пометили что блок выполнен первый. Дальше скрипт идет вниз и после всех выполнений он присваивает локалку 0. Что бы наступив в следующи раз выполнился блок с переменной 1.

Neverwinter Script Source
SetLocalInt( oTrigger, "WAIT", FALSE ); // SetLocalInt( oTrigger, "WAIT", 0 );


Понятно? К тому же, я специально написал тебе три разных варианта проверки переменных. Спрашивай smile.gif

Автор: Artlira Oct 31 2007, 09:27

Цитата
Понятно? К тому же, я специально написал тебе три разных варианта проверки переменных. Спрашивай


Ой… Понятно, не догадалась проверить сразу две переменные… Надо было не над скриптом издеваться, а прочесть еще раз тему о переменных…

Двумя переменными сразу действительно легко создать такое условие, что бы оно не сработало ни на одном из блоков. Переменная WAIT при работе скрипта всегда становится равной 1? Такого условия нет ни для одного блока, и они не срабатывают, а “обнуляется” она уже тогда, когда все блоки пройдены и скрипт об нее уже не спотыкается? А при следующей работе – она уже равна 0 и не мешает работать тому из блоков, который должен сработать по условию переменной LIRA_PC_DO_IT?

Автор: Aiwan Oct 31 2007, 10:27

Да, все верно. Мы еще один вариант блоков рассмотрим. Подожденм остальных. declare.gif

Автор: Vhall Nov 2 2007, 00:22

Что-то написал. Даже компилируется. Работает или нет - сказать не могу - не понятен нужный результат.
Для чего мы ставим и проверяем локалки? Откомментировал вопросами.

[ OFFTOP ]
Neverwinter Script Source
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "DOOR_AIWAN_01" ); // Наша дверь
  object oNpc; // Объявим НПС но не укажем, кто он именно
  object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последний тот тухлый банан!";

  if( GetIsPC( oPC ) == TRUE ) // Если это верно ТО выполняется то что между скобок
  { // ПЕРВАЯ открытая скобка

    /* ВТОРОЙ ВНУТРЕННИЙ БЛОК */

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" )== 1 ) // Если локалка РАВНА 2 ТО: //почему "2"? не 1?
    { // ВТОРАЯ открытая скобка

        oNpc = GetNearestObjectByTag( "NPC_AIWAN" );
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 2 );
        SendMessageToPC( oPC, "Сработал второй блок" );

    } // ВТОРАЯ закрытая скобка

    /* ТРЕТИЙ ВНУТРЕННИЙ БЛОК */

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 0 )
    { // ТРЕТЬЯ открытая

        oNpc = GetNearestObjectByTag( "NPC_AIWAN" );
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 1 );
        SendMessageToPC( oPC, "Сработал третий блок" );
    }  // ТРЕТЬЯ закрытая

    /* четвертый внутренний блок */
   
    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 0 ) //?
    { // четвертая открытая

        oNpc = GetNearestObjectByTag( "NPC_AIWAN" );
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 3 ); //?
        SendMessageToPC( oPC, "Сработал четвертый блок" );
    }  // четвертая закрытая

      SendMessageToPC( oPC, "Сработал ОСНОВНОЙ блок" );
      AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
      AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
      AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери

  } // ПЕРВАЯ закрытая скобка

}

Автор: Aiwan Nov 6 2007, 09:27

Vhall, мы присваиваем локалки что бы блоки сработали ОДИН раз за проход скрипта сверху вниз. Посомтри внимательно.

В первом внутреннем блоке мы проверяем переменную AIWAN_PC_DO_IT равную 1. Внутри блока мы поставили эту локальную со значением 2. Тем самым мы сделали так, что бы второй раз наступив на триггер скрипт не сработал внутри этого блока.

Neverwinter Script Source

    /* ВТОРОЙ ВНУТРЕННИЙ БЛОК */

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" )== 1 ) // СРАБОТАЕТ ВО ВТОРОЙ РАЗ
    {

      // Ставим значение 2. Второй раз скрипт этот блок не запустит. Тут проверка на 1
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 2 );
    }

    /* ТРЕТИЙ ВНУТРЕННИЙ БЛОК */

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 0 ) // ОН СРАБОТАЕТ В ПЕРВЫЙ РАЗ
    {
        // Этот блок сработает САМЫЙ первый, так как проверка переменной на ноль
        // Мы присвоим значение 1. Так как блок с проверкой на 1 вверху выше, то
        // скрипт не будет ее запускать в этот раз. Мы верх уже прошли и пошлди ниже.
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 1 );
    }

    /* ТУТ НУЖНО ДОПИСАТЬ ЕЩЕ ОДИН БЛОК*/

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 2 ) // СРАБОТАЕТ ВО ВТОРОЙ РАЗ
    {
    // Смотрим здесь. Проверка идет на значение 2. Т.е. он попросту ОБНУЛЯЕТ наши
    // переменные для замкнутого круга.
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 0 );
        SendMessageToPC( oPC, "Сработал четвертый блок" );
    }


Ты предсталяешь наверное такой расклад:

Neverwinter Script Source

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 0 )
    {
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 1 );
    }

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" )== 1 )
    {

        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 2 );
    }

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 2 )
    {
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 0 );
    }


Но он не верен, так как в скрипте ЗА ОДИН раз сработают все три блока а нам надо что бы каждый работал один раз за проход. Мы сделали так:

Neverwinter Script Source

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" )== 1 )
    {

        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 2 );
    }
    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 0 )
    {
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 1 );
    }

    if ( GetLocalInt( oTrigger, "AIWAN_PC_DO_IT" ) == 2 )
    {
        SetLocalInt( oTrigger, "AIWAN_PC_DO_IT", 0 );
    }

Соотвественно у нас работает первый раз средний блок. Второй раз верхний и нижний следом за ним ОБНУЛЯЯ локалку. В третий раз сработает средний и так далее. Понятно?

Добавлено через 50

п.с. В комменте я ошибся там проверка на 1 а я написал 2. Вот ты мог и запутаться. Извини.

Автор: Vhall Nov 6 2007, 22:51

scratch_one-s_head.gif Вот так?

[ OFFTOP ]
Neverwinter Script Source
void main( )
{
  object oTrigger = OBJECT_SELF; // То на чем стоит скрипт
  object oDoor = GetObjectByTag( "PLC_DC_Slum01" ); // Наша дверь
  object oNpc; // Объявим НПС но не укажем, кто он именно
  object oPC = GetEnteringObject( ); // Тот кто НАСТУПИЛ на триггер
  string sSpeak = "Кто последний тот тухлый банан!";

  if( GetIsPC( oPC ) == TRUE ) // Если это верно ТО выполняется то что между скобок
  { // ПЕРВАЯ открытая скобка

    /* ВТОРОЙ ВНУТРЕННИЙ БЛОК */

    if ( GetLocalInt( oTrigger, "VHALL_PC_DO_IT" )== 1 ) // Если локалка РАВНА 2 ТО:
    { // ВТОРАЯ открытая скобка

        oNpc = GetNearestObjectByTag( "n_watchman" );
        SetLocalInt( oTrigger, "VHALL_PC_DO_IT", 2 );
        SendMessageToPC( oPC, "Сработал второй блок" );

    } // ВТОРАЯ закрытая скобка

    /* ТРЕТИЙ ВНУТРЕННИЙ БЛОК */

    if ( GetLocalInt( oTrigger, "VHALL_PC_DO_IT" ) == 0 )
    { // ТРЕТЬЯ открытая

        oNpc = GetNearestObjectByTag( "n_watchman" );
        SetLocalInt( oTrigger, "VHALL_PC_DO_IT", 1 );
        SendMessageToPC( oPC, "Сработал третий блок" );
    }  // ТРЕТЬЯ закрытая

    /* четвертый внутренний блок */
   
    if ( GetLocalInt( oTrigger, "VHALL_PC_DO_IT" ) == 2 )
    { // четвертая открытая

        oNpc = GetNearestObjectByTag( "n_watchman" );
        SetLocalInt( oTrigger, "VHALL_PC_DO_IT", 3 );
        SendMessageToPC( oPC, "Сработал четвертый блок" );
    }  // четвертая закрытая

      SendMessageToPC( oPC, "Сработал ОСНОВНОЙ блок" );
      AssignCommand( oNpc, ClearAllActions( ) ); // Чистим стек команд
      AssignCommand( oNpc, SpeakString( sSpeak ) ); // Говорит фразу
      AssignCommand( oNpc, ActionForceMoveToObject( oDoor, TRUE ) ); // Бежит к двери

  } // ПЕРВАЯ закрытая скобка

}

Автор: Aiwan Nov 7 2007, 16:03

Нет не верно. Если ты хочешь сделать так, то тебе твой последний блок что ты нарисовал надо поместить в самый верх. Зачем понятно или нет? Посомтри внимательно. У нас первый блок проверяет 1, второй 0, третий 2. Скрипт идет сверху вниз. Единица у нас проверяется вверху, так как в блоке на проверку 0 мы присвоили 1. Если бы блок с проверкой на 1 стоял после блока проверки на ноль, то сразу бы сработал следом за блоком проверки на 0. Что в сущности происходит и у тебя. Первый блок проверка на 1 (увеличили до 2), следом проверка на 0, скрипт его пропустит но опятть зайдет в блок проверки на 2 и там снова твои данные. Он выполнит их и присвоится 3. Так что если ты хочешь все три блока выполнить, то должен учитывать условие: ЕСЛИ СРАБОТАЛ БЛОК, ТО НИЖНИЕ БЛОКИ НЕ ДОЛЖНЫ СРАБОТАТЬ ПОСЛЕ ЕГО УСЛОВИЙ ЕСЛИ ТЕБЕ ЭТО НЕ НАДО.

В общем тебе сложно это? Если да не заморачивайся. Я немного сложновато дал для новичков. Поймешь потом.

Автор: Vhall Nov 7 2007, 20:02

Да, может давай это... дальше?

Автор: Artlira Nov 13 2007, 01:36

У меня вопрос. А занятия дальше будут? Очень хочется учиться... unsure.gif

Автор: Aiwan Nov 13 2007, 09:45

Будут!

Автор: Aiwan Dec 7 2007, 12:15

Продолжаем.

Создайте диалог в редакторе с четырмя корневыми строками:
1. Эта строка первого НПС.
2. Это строка второго НПС.
3. Это строка третьего НПС.
4. Я безымянный!

Теперь у вас три НПС было, создайте еще пару. Вставьте диалог один на всех ваших НПС.
Трем первым НПС измените теги на такие: NPC_ВАШ_НИК_01, NPC_ВАШ_НИК_02, NPC_ВАШ_НИК_03.
Создайте три скрипта в редакторе где бы проверялся ТЕГ НПС который разговаривает. Три разных НПС три разных скрипта. Пример первого:

Neverwinter Script Source

int StartingConditional( )
{
  object oSelf = OBJECT_SELF; // Тот с кем начали разговор на ком стоит скрипт

  if ( GetTag( oSelf ) == "NPC_ВАШ_НИК_01" ) // Если тег объекта РАВЕН
  {
      return TRUE; // То начало диалога этой строкой
  }
  return FALSE; // Ничего не произойдет, строка не появится
}

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



Добавлено через 2 минуты

Прятать ответы не надо. Пишите получилось у вас или нет.

Автор: Artlira Dec 9 2007, 03:32

Все получилось. Каждый из заданных неписей произносит строку в зависимости от своего тега.
1. Эта строка первого НПС.

Neverwinter Script Source
int StartingConditional( )
{
  object oSelf = OBJECT_SELF; // Тот с кем начали разговор на ком стоит скрипт

  if ( GetTag( oSelf ) == "NPC_LIRA_01" ) // Если тег объекта РАВЕН NPC_LIRA_01
  {
      return TRUE; // То начало диалога этой строкой
  }
  return FALSE;
}

2. Это строка второго НПС.
Neverwinter Script Source
int StartingConditional( )
{
  object oSelf = OBJECT_SELF; // Тот с кем начали разговор на ком стоит скрипт

  if ( GetTag( oSelf ) == "NPC_LIRA_02" ) // Если тег объекта РАВЕН NPC_LIRA_02
  {
      return TRUE; // То начало диалога этой строкой
  }
  return FALSE;
}

3. Это строка третьего НПС.
Neverwinter Script Source
int StartingConditional( )
{
  object oSelf = OBJECT_SELF; // Тот с кем начали разговор на ком стоит скрипт

  if ( GetTag( oSelf ) == "NPC_LIRA_03" ) // Если тег объекта РАВЕН NPC_LIRA_03
  {
      return TRUE; // То начало диалога этой строкой
  }
  return FALSE;
}


Автор: Aiwan Dec 9 2007, 11:18

Отлчино! Ждем еще кого нить...

Автор: Vhall Dec 9 2007, 20:03

У меня все работает. Сомневаюсь что нужно писать ответ - ведь он почти полностью идентичен.
Всё понятно.

Автор: Aiwan Dec 10 2007, 12:41

Очень радует, что вам все понятно. Продолжаем.

Мы уже разбирали что такое пременная. Теперь мы применим знания в главном составляющем грамотного мода - диалоге.

Переменная проверяется в начале корневой строки так (эта строка появится ТОЛЬКО когда переменная равна 0):

Neverwinter Script Source

//:://////////////////////////////////////////////
//:: Проверим отсутсвие переменной AIWAN_LESSON_01_DIALOG
//:: Copyright © 2007 WRG!
//:://////////////////////////////////////////////
/*
        Описание самого квеста, если нужно.
*/
//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 10.12.2007
//:://////////////////////////////////////////////
int StartingConditional( )
{
    object oPC = GetPCSpeaker( );
    int iQuest = GetLocalInt( oPC, "AIWAN_LESSON_01_DIALOG" );
//-------------------------------------------------------
    if ( iQuest == 0 ) // Если локалка равна 0.
    {
        return TRUE; // Возврат ИСТИНА, т.е. старт диалога
    }
    return FALSE; // В противном случае отбой
}


Эта строка диалога появится ТОЛЬКО когда переменная ровна 1:

Neverwinter Script Source

//:://////////////////////////////////////////////
//:: Проверим переменную AIWAN_LESSON_01_DIALOG на 1
//:: Copyright © 2007 WRG!
//:://////////////////////////////////////////////
/*
        Описание самого квеста, если нужно.
*/
//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 10.12.2007
//:://////////////////////////////////////////////
int StartingConditional( )
{
    object oPC = GetPCSpeaker( );
    int iQuest = GetLocalInt( oPC, "AIWAN_LESSON_01_DIALOG" );
//-------------------------------------------------------
    if ( iQuest == 1 ) // Если локалка равна еденице.
    {
        return TRUE; // Возврат ИСТИНА, т.е. старт диалога
    }
    return FALSE; // В противном случае отбой
}


В каждой строке вы присвоите новую переменную для продвижения по диалогу далее. Не забываем, что слоты для проверки и присваивания переменных разные.

Neverwinter Script Source

//:://////////////////////////////////////////////
//:: Присвоим переменную AIWAN_LESSON_01_DIALOG 1
//:: Copyright © 2007 WRG!
//:://////////////////////////////////////////////
/*
        Описание самого квеста, если нужно.
*/
//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 10.12.2007
//:://////////////////////////////////////////////
void main( )
{
    object oPC = GetPCSpeaker( );
//  object oPC = GetFirstPC( ); - так будет работать на любом месте для сингла
    SetLocalInt( oPC, "AIWAN_LESSON_01_DIALOG", 1 );
}


Все это скрипты для чайников. Коими мы с вами и являемя. Но я попробую вам дать один скрипт универсальный, что бы вы поняли, что мы с вами используем 1% потенциала кода. Например, что бы не писать 5 скриптов для 5 строк в которых существующая переменная увеличивается на 1, можно написать такой скрипт на все строки присвоения:
Neverwinter Script Source

//:://////////////////////////////////////////////
//:: Присвоим переменную универсально
//:: Copyright © 2007 WRG!
//:://////////////////////////////////////////////
/*
        Описание самого квеста, если нужно.
*/
//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 10.12.2007
//:://////////////////////////////////////////////
void main( )
{
    object oPC = GetPCSpeaker( );
//  object oPC = GetFirstPC( ); - так будет работать на любом месте для сингла

    int i = GetLocalInt( oPC, "AIWAN_LESSON_01_DIALOG" );
    // Проверим текущее состояние переменной

    // и прибавим к полученному результату единичку.
    SetLocalInt( oPC, "AIWAN_LESSON_01_DIALOG", i+1 );
}


Нескаторые ремарки. Вы заметили, что некоторые скрипты не содержат скобо {}. Я изначально пишу их везде что бы вы не путались и понимали блоки. НО. Если код скрипта содержит одну строку, то условие в блоки ставить не нужно. Пример:
Этот код
Neverwinter Script Source

int StartingConditional( )
{
    object oPC = GetPCSpeaker( );
    int iQuest = GetLocalInt( oPC, "ПЕРЕМЕННАЯ ОДЫН" );
//-------------------------------------------------------
    if ( iQuest == 1 ) // Если локалка равна еденице.
    {
        return TRUE; // Возврат ИСТИНА, т.е. старт диалога
    }
    return FALSE; // В противном случае отбой
}


РАВЕН этому:

Neverwinter Script Source

int StartingConditional( )
{
    object oPC = GetPCSpeaker( );
    int iQuest = GetLocalInt( oPC, "ПЕРЕМЕННАЯ ОДЫН" );
//-------------------------------------------------------
    if ( iQuest == 1 ) // Если локалка равна еденице.

        return TRUE; // Возврат ИСТИНА, т.е. старт диалога

    return FALSE; // В противном случае отбой
}

Так как после условия у нас одна строка для кода.

Теперь домашнее задание.

В аттаче что я прикрепил есть модуль с диалогом. Ваша задача выполнить то, что я недоделал двумя способами. Первый, по "крестьянски" второй используя универсальный скрипт. Задача. Все пять строк должны появиться. После выбора в диалоге "Увеличить или прировнять" переменную к числу, мы не должны получть строку ошибку. Задача простая, но на внимательность. жду ваших сообщений. У кого что не получилось.




Добавлено через 42 секунды

Да. Естественно локалку переименовать с вашим ником.

 modules.zip ( 7.61 килобайт ) : 9
 

Автор: Artlira Dec 13 2007, 03:25

У меня к сожалению не открывается модуль... Поэтому задание делаю по интуиции и возможно неправильно... unsure.gif

Сделала два одинаковых диалога на пять строк, то есть на четыре переменные и ее отсутствие (0).
1. Привет! Переменная 4.
Увеличить переменную на 1.
Все больше переменных нет...
Обнулить переменную.
Привет! Переменная 0.
Ошибка! Нет ни одной переменной!

Уйти
2. Привет! Переменная 3.
Увеличить переменную на 1.
Привет! Переменная 4.
Ошибка! Нет ни одной переменной!

Уйти
Дальше тоже самое до Привет! Переменная 0. Ветки связаны, так что можно за один раз прокрутить до 4 переменной, обнулить ее и крутить снова. Ветку про ошибку добавила для того, что бы если переменная присвоена неверно, ветка с ее проверкой не появится и появится эта про ошибку.
На каждой ветке стоит проверка в зависимости от переменной, уаказанной в диалоге.
Скрипты на проверку:

Neverwinter Script Source
int StartingConditional( )
{
    object oPC = GetPCSpeaker( );
    int iQuest = GetLocalInt( oPC, "LIRA_01_DIALOG" );

    if ( iQuest == 0 ) // Если локалка равна 0.

    return TRUE; // Возврат ИСТИНА, т.е. старт диалога

    return FALSE; // В противном случае отбой
}


Меняется только строчка - чему равна переменная 0-4.

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

Neverwinter Script Source
void main( )
{
    object oPC = GetPCSpeaker( );
    SetLocalInt( oPC, "LIRA_01_DIALOG", 1 );
}

Менялось только значение переменной от 0 до 4.
Во втором диалоге переменная менялась универсальным скриптом:
Neverwinter Script Source
void main( )
{
    object oPC = GetPCSpeaker( );

    int i = GetLocalInt( oPC, "LIRA_01_DIALOG" );

    // и прибавим к полученному результату единичку.
    SetLocalInt( oPC, "LIRA_01_DIALOG", i+1 );
}

Оба диалога нормально прокручиваются, при выходе и повторном диалоге, срабатывает ветка именно с той переменной на которой прервали диалог.
Вроде все получилось, но я не уверена, что задание сделано верно…



Автор: Aiwan Dec 13 2007, 06:35

Пришли мне на мыло свой модуль-домашнее задание. aiwan[злая собака]wrg.ru

Автор: Artlira Dec 13 2007, 08:15

Цитата
Пришли мне на мыло свой модуль-домашнее задание. aiwan[злая собака]wrg.ru


Отправила.

Автор: Aiwan Dec 13 2007, 09:00

Что то нет... Пришли на ящик aiwan[собака]ya.ru

Автор: Artlira Dec 13 2007, 09:17

На второй адрес вроде ушло без комментариев, а на wrg.ru - дважды сообщил, что такого адреса нет...

Автор: Aiwan Dec 13 2007, 11:42

Блин, у нас после переезда со старого сервера не работали мыльники smile.gif Все починил теперь на wrg шли.

Так. Ничего не правильно smile.gif Во первых. Я УЖЕ ДАЛ ШАБЛОН. В него внесите изменения. Там уже тело диалога есть. Только расставьте скрипты. и шлите мне на мыло но модуль именуйте вашим ником, что бы я не путался. Все. Жду.

п.с. Чуть позже я понял, что ты мне прислала ПЕРВОЕ задание с тремя НПС. Это другое. Возможно ошиблась?

Автор: Artlira Dec 15 2007, 12:26

Цитата
Так. Ничего не правильно Во первых. Я УЖЕ ДАЛ ШАБЛОН. В него внесите изменения. Там уже тело диалога есть. Только расставьте скрипты. и шлите мне на мыло но модуль именуйте вашим ником, что бы я не путался. Все. Жду.


Так я же и пишу – что у меня шаблон не открылся… unsure.gif Поэтому я не могу просто вставить скрипты… Я не знаю как выглядит учебный диалог, вот и набросала свой, предположив, что смысл задания это правильно присвоить переменные, что бы фразы с проверками выскакивали в определенном порядке? Как я поняла, наверно в одном диалоге присвоить нужно каждую локалку отдельно, а во втором использовать только универсальную?

Цитата
п.с. Чуть позже я понял, что ты мне прислала ПЕРВОЕ задание с тремя НПС. Это другое. Возможно ошиблась?


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

Автор: Aiwan Dec 15 2007, 20:21

Artlira, я только что скачал файлик что прикрепил, открыл его. Все открылось. Ты наверное просто не поняла что файл заархивирован зипом... Модуль внутри Aiwan Test MOD.mod. Открой, разархивируй, переименуй со своим ником Artlira Test MOD.mod, и сделай как говорю. Тот модуль что ты прислала содержал ОДИН диалог первого задания про три НПС. Жду.

Автор: Artlira Dec 16 2007, 03:41

Aiwan я наверно объяснила неправильно... Сам мод я достаю, у меня он в тулсете не открывается. Видимо версия не та. Поэтому я и не знаю, как выглядит шаблон.

А по отправленному модулю вообще ничего не понимаю... Там два диалога (совершенно одинаковые), только локалку я в первом присваиваю каждый раз отдельно, а во втором используя одну универсальную... Там 2 непися и у них даже имена (диалог с обычной переменной, и диалог с универсальной переменной). Скачала у себя из ящика то что отправила - нет там диалога 3-ех неписей, а только вот эти два...

Автор: Aiwan Dec 16 2007, 12:49

Версия 1.68. Давай качай и делай. У меня планы на эти диалоги дальше.

Автор: Vhall Dec 16 2007, 21:11

Выслал.

Автор: Artlira Dec 17 2007, 03:16

Отправила.

Автор: Aiwan Dec 17 2007, 18:11

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

Вот такая функция определяет кастомный токен.

Neverwinter Script Source

SetCustomToken( 100, "Строка для токена" );


В диалоге это вставляется так: <CUSTOM100> и вместо этого тега будет ваша нужная информация. Зачем это? пример. В диалогах есть теги для имени РС, да это мы можем найти. А вот имени НПС нет... Соотвественно задав одним из токенов имя НПС мы можем им пользоваться в диалогах. Но вы должны помнить, что токены не сохраняются ни в какой памяти и что бы они работали их надо загружать перед использованием.

Я приаттачил вам модуль, в нем два новых НПС. Один как заготовка, второй мой рабочий. Вы должны изменить ГОТОВЫЕ скрипты что бы ваш диалог работал как мой. Что бы у вас не было соблазна загляуть в мои скрипты исходники я вырезал и положил отдельно в папке. Вам надо всего то поправить три скрипта. В каждом добавляется коротенькая строка. Зато вы увидите как можно делать то что выглядело у нас чутким нагромождением диалоговых строк. Да, не забудьте посомтреть на журнал. Я сделал наподобие простого квеста. Но этот квест сделан полностью по схеме тулсета, без применения скриптовой части. Потом мы попробуем это же самое отскриптить. Но это позже. Так. Качайте, переименовывайте модули, локальные переменные и правьте диалог так, что бы он работал как у НПС "Образец". Что непонятно спрашивайте.

 aiwan_modules.rar ( 12.05 килобайт ) : 13

Автор: Artlira Dec 20 2007, 03:07

Вроде бы все получилось. По крайней мере оно работает… yahoo.gif
Рабочая строка непися должна появляться при условии, что переменная меньше или равна 5.
Строка + появляется при условии, что переменная равна 5.
Рабочая строка игрока наоборот появляется только при условии, что переменная меньше 5.
А в универсальном скрипте, необходимо было прописать условие, что если переменная меньше 5, то к ней прибавляется 1, при других условиях присваиваем переменную равную 0?

У меня только один вопрос. Почему нужно каждый раз во всех скриптах прописывать значение каждого токена? Наверно можно их прописать в отдельном скрипте и просто подключать его, когда нужен тот или иной токен?

Модуль отправила.

Автор: Lex Dec 20 2007, 09:37

достаточно в скрипте прописывать значение того токена, который будет отображен ЕСЛИ текущее значение токена не подходит. Все переприсваивать нет нужды.
Те например дали игроку кличку, записали мы ее в токен с номером 50000 и можем юзать дальше во всех диалогах до посинения, не трогая значения токена больше нигде.

Автор: Aiwan Jan 14 2008, 21:13

Artlira, я получил твое письмо и написал ответ. Занятия я продолжу. Напиши мне в приват на что сделат ьупор. Не пойму, что то наши е-майлы не проходят видно друг к другу. Если ты осталась одна, я все равно продолжу.

Автор: Aiwan Jan 27 2008, 12:03

Продолжаем разговор.

Так. В данном файле лежит модуль в котором есть один полный квест про книгу. Задача игрока принести книгу заказчику. На что я хочу обратить внимание. Я попытался сделать несколько свободных моментов в квесте, а именно. Можно принести книгу и еще не говорить с хозяйкой. Можно отказаться нести книгу но найдя отдать. Можно имея книгуна руках не отдать хозяйке прямо сказав ей об этом. Вот в сущности простой квест но он имеет много ньюансов. Я не думаю, что вы сможете сразу написать такой. Я хочу что бы вы попробовали все варианты диалога. И проследили что и как работает. Например. Если отказаться от задания и получить статус квеста с локалкой 1, то имея все же книгу на руках у нас шанс отдать ее и выполнить квест появляется.

Neverwinter Script
//:://////////////////////////////////////////////
//:: Проверим взяли мы квест или нет
//:: Copyright © 2007 WRG!
//:://////////////////////////////////////////////
/*
     Вернуть книгу девушке
*/

//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 10.12.2007
//:://////////////////////////////////////////////
#include "nw_i0_tool"

int StartingConditional( )
{
    object oPC = GetPCSpeaker( );
    int iQuest = GetLocalInt( oPC, "QUEST_BOOK" );

/* Суть этой проверки, мы могли отказаться от квеста, но потом случайно нашли
  книгу и теперь в принципе можно квест вернуть назад на точку финала. */

//-------------------------------------------------------

// Если локалка равна 1 И в сумке нет книги.
    if ( iQuest == 1 && !HasItem( oPC, "AM_IT_BOOK001" ) )
    {
        return TRUE; // Возврат ИСТИНА, т.е. старт диалога
    }
    return FALSE; // В противном случае отбой
}


Я воспользовался инклюдой биовар на проверку предмета в рюкзаке !HasItem(oPC, "AM_IT_BOOK001"). Восклицательный знак впереди говорит о том что это отрицание, т.е. НЕТ книги в рюкзаке. Вот во втором случае книга уже есть при проверке. Тут можно дать шанс игроку вернуть:
Neverwinter Script
#include "nw_i0_tool"

int StartingConditional( )
{
    object oPC = GetPCSpeaker( );
    int iQuest = GetLocalInt( oPC, "QUEST_BOOK" );

/* Суть этой проверки, мы могли отказаться от квеста, но потом случайно нашли
  книгу и теперь в принципе можно квест вернуть назад на точку финала. */

//-------------------------------------------------------

// Если локалка равна 1 И в сумке книга.
    if ( iQuest == 1 && HasItem( oPC, "AM_IT_BOOK001" ) )
    {
        return TRUE; // Возврат ИСТИНА, т.е. старт диалога
    }
    return FALSE; // В противном случае отбой
}


Обратити внимание на структуру названия скриптов. Вы можете придумать свою, но рекомендую определиться с этим ло начала работ. Например: am_sc_q01_01 АйванМодуль_StartingConditional_Quest01_переменная01. Вот примерная расстановка.

Еще. Я не использовал журнальные записи в диалогах опционально. Я все присваивал в скриптах. Почему? Дело в том, что если квесту присвоить финальную ветку, то с помощью диалога он уже не вернется на статус не выполненых. Поэтому мы можем процесс держат ьпод контролем. Сработал скрипт, сработал журнал.

В квесте, я сделал одну запись в журнале, когда мы берем книгу в свой рюкзак. Вот такой скрипт am_mod_acquired на свойствах модуля для взятия предмета в инвентарь:
Neverwinter Script
#include "nw_i0_generic"
#include "x2_inc_switches"

void main( )
{
  object oMod = GetModule( ); // Это мы определили модуль
  object oItem = GetModuleItemAcquired( ); // Сам Item объект который попал в рюкзак
  object oPC = GetModuleItemAcquiredBy( ); // Тот кто взял
  string sTagItem = GetTag( oItem ); // Таг Item-a

  if( !GetIsPC( oPC ) ) return; // Если тот кто поднял предмет не РС то возврат.

  // Для теста. Все предметы что попали в сумку опознаем атоматически.
  if( !GetIdentified( oItem ) )
  {
    SetIdentified( oItem, TRUE ); // Если предмет неопределен мы его определяем
    SendMessageToPC( oPC, ( GetName( oItem )+" - неизвестный предмет опознан." ) );
  }

//==================================================
//                               ЖУРНАЛЬНЫЕ ЗАПИСИ
//==================================================

    // -------------------------------------------------------------------------
    //                      КНИГА
    // -------------------------------------------------------------------------
    if ( sTagItem =="AM_IT_BOOK001" ) // Искомый предмет
    {
      // Если на модуле нет локалки равной тегу нашего предмета sTagItem ( см выше как он определяется )
      if( !GetLocalInt( oMod, sTagItem ) ) // Если нет на модуле то..
      {
         // Сразу присвоим модулю, что мы подняли один раз предмет
         SetLocalInt( oMod, sTagItem, TRUE );

/*
   Пометим в журнале у игрока, что мы нашли предмет. Но. Если на нашем игроке нет
   ни одной переменной  QUEST_BOOK. значит он нашел книгу случайно. Значит в журнале
   мы присвоим другую запись, о том что у нас какая то странная книга, хрен знает чья.

*/

         if( !GetLocalInt( oPC, "QUEST_BOOK" ) ) // если нет локалки то
         {
             // Добавим запись в журнал тег квеста J_QUEST_BOOK 3 - номер записи
             AddJournalQuestEntry( "J_QUEST_BOOK", 3, oPC );
         }
          else // else - ЕЩЕ выполянется если условие перед скобкой не сработало
              {
                AddJournalQuestEntry( "J_QUEST_BOOK", 4, oPC );
              }
      }
    }


//==================================================
//     СТАНДАРТНАЯ СИСТЕМА item tag - ЗАПУСК СКРИПТА равного item tag
//==================================================

     // * object oItem = GetModuleItemAcquired( );
     // * Generic Item Script Execution Code
     // * If MODULE_SWITCH_EXECUTE_TAGBASED_SCRIPTS is set to TRUE on the module,
     // * it will execute a script that has the same name as the item's tag
     // * inside this script you can manage scripts for all events by checking against
     // * GetUserDefinedItemEventNumber( ). See x2_it_example.nss
     if ( GetModuleSwitchValue( MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS ) == TRUE )
     {
        SetUserDefinedItemEventNumber( X2_ITEM_EVENT_ACQUIRE );
        int nRet =   ExecuteScriptAndReturnInt( GetUserDefinedItemEventScriptName( oItem ), OBJECT_SELF );
        if ( nRet == X2_EXECUTE_SCRIPT_END )
        {
           return;
        }

     }
}


Он присваивает две разные записи в журнал, в зависимости от того, общались мы с девушкой или нет. Я написал скртипт в нутри главноого, но НВН позволяет делать так. Создать скрипт с именем предмета, в нашем случае am_it_book001 и в него уже вписать все действия. Но мне удобнее когда все под рукой. Как вам удобнее решать самим.

Задачи: вам надо изучить все мои скрипты. Внимательно простмотреть все ветки диалогов и написать простой квест. У вас есть 2 НПС, один НПС просит игрока отдать другому НПС кольцо. Диалоги обоих НПС должны быть автономны. Все прописать в журнале, на поднятие предмета тоже.

 modules_lesson_02.rar ( 13.42 килобайт ) : 3
 

Автор: Artlira Feb 7 2008, 02:09

Вроде все получилось, хотя есть пара вопросов. Вопрос первый наверно нужно было сначала задать, а потом уже делать квест. scratch_one-s_head.gif
1. Действия должны быть следующими: 1 непись отправляет на поиски кольца (раз его нужно поднять с земли), после того как ему кольцо принесли – не забирает, а просит передать другому неписю? Ну и + все варианты? Я так сделала…
2. Обязательно ли нужно вешать на строку диалога локалку о том, что квест еще не брали, с неписем не видились? Если эту ветку кинуть в самый низ и оставить без проверок, она и должна бы 1 сработать?
3. На какой адрес отправлять задание?

Автор: Aiwan Feb 7 2008, 09:05

Выкладывай тут. Пусть народ читает. будем поправлять если, что.

Если не можешь пришли на aiwan[злая собака]wrg.ru

Автор: Artlira Feb 15 2008, 12:58

Aiwan вроде все отправила несколько дней назад. Может опять, не прошло где-то письмо? На какой еще адрес можно отправить?

Автор: Aiwan Feb 16 2008, 10:39

Почта работает. Не пойму, почему от тебя не приходят письма. Дай мне свой е-майл я отправлю с него тебе а ты ответишь.

Автор: 2_advanced Mar 1 2008, 10:40

злостный оффтоп:
в нвн2 если чар находится вне локи (грузит еще, только что зашел на шард),
то действия через AssignCommand вешать на него нет смысла ph34r.gif

фикс:

Neverwinter Script
void Delayed_OnEnter(object oPC)
{
    if(!GetIsObjectValid(oPC))
        return;

    if(!GetIsObjectValid(GetArea(oPC)))
    {
        DelayCommand(0.4, Delayed_OnEnter(oPC));
        return;
    }

    AssignCommand(oPC, JumpToLocation(...));
}


в нвн1 такого не было..

Автор: Merkuta Feb 24 2010, 23:27

Я понимаю, что просьба довольно наглая, учитывая сколько времени прошло, но нельзя ли возобновить уроки? Я прочитал всю тему, разобрал примеры, выполнил задания. Хочется двигаться дальше, но английским к сожалению владею не достаточно, чтобы учиться на других сайтах.

Автор: Aiwan Feb 25 2010, 04:35

Merkuta, боюсь, что английский придется учить в любом случае. Уроки возобновлять уже не будем.

Автор: virusman Feb 25 2010, 08:55

Merkuta, перейди к реальным задачам, а если возникнут вопросы - задавай их на этом форуме. smile.gif

Автор: Merkuta Mar 31 2010, 22:29

Такой вопрос. Можно ли сделать несколько глобальных карт (не интерактивных как в SoZ, а рисованных как в оригинале и Маске). Например нужно сделать карту мира, на которой город обозначен как одна локация, но при переходе в город открывается карта города, и можно выбрать район, куда пойти.

Автор: Kcapra Apr 2 2010, 04:29

Merkuta, можно сделать кастомный UI

Автор: Orochi May 1 2011, 14:20

Ну тут Merkuta немного про другое говорит. Как я понял, это по типу карты из Dragon age 2. Тут, я думаю, вполне можно сделать вторуб карту ( с городом), а в основной при нажатии на иконку повесить скрипт на переход к карте города. scratch_one-s_head.gif

Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)