Город Мастеров
IPB

Здравствуйте, гость ( Вход | Регистрация )

 Правила этого форума ПРАВИЛА РАЗДЕЛА
 
Ответить в эту темуОткрыть новую тему
> Мануалы в помощь новичкам..., Читать обязательно...
MasterMage
сообщение Mar 22 2005, 18:10
Сообщение #1


Level 8
***

Класс: Маг
Характер: Lawful Good
Раса: Полуэльф



Вот, как и сказал Айв, создаю тему, посвященную моим статьям... Написал пока две: для квестов и скриптов. Обе в Worde, так как нету у мну такой умной проги, как у Айва... =) Одна про Квесты весит 1.6Мб в архиве, а другая про Скрипты всего 90-100 Кб, посему выставляю это, вторую, а первую потом как-нить, так как на ФТП не загружается так много(пробовал, хоть убейте, ни в какую!!!)

CODE
*************************  САМА СТАТЬЯ  **********************************


Данная статья является интеллектуальной собственностью. Любое использование ее материалов допускается только с разрешения ее автора.
Скрипты
Если вы решили создать свой модуль, вам обязательно понадобятся скрипты. Это особый программный язык, разработанный для набора инструментов Aurora Toolset. Без него никак не обойтись, если вы собрались построить хороший модуль. Именно они заставляют всех персонажей в игре выполнять их действия, врагов – нападать на вас, подателей сюжет – давать вам квесты. Без них модуль будет выглядеть безжизненным.
Чтобы освоить этот язык, нужно научиться понимать функции и алгоритм их написания. Обязательно вооружитесь статьей с полным описанием всех функции на русском языке. Или на крайний случай воспользуйтесь Lexicon’ом. Найти статьи вы сможете на форуме «Город мастеров» по адресу www.wrg.ru/forums.
Создайте персонажа с тегом “NPC_1”, точку с тегом “WP_1” и поставьте их на достаточном на ваше усмотрение расстоянии.
Теперь напишем скрипт, с помощью которого можно заставить персонажа совершить переход в определенную точку на карте. Этим примером пользуются многие в своих статьях, и я не буду исключением.
Neverwinter Script Source
void main()
{
object oNPC=GetObjectByTag("NPC_1");
object oWp=GetWaypointByTag("WP_1");
AssignCommand(oNPC,ActionMoveToObject(oWp));
}


void main() – это сам скрипт. Они бываю разные по своему назначению, но этот является универсальным, по умолчанию.
{} – все, что находится внутри фигурных скобок – ваш скрипт. Если он правильно написан, он будет выполняться сверху вниз, не иначе!
Самые первые строчки скрипта – это раздача ролей актерам. Вы задаете скрипту всех, кто будет участвовать в действиях, по тегам.
object oNPC = GetObjectByTag(“NPC_1”);
Разберем эту строку! Object – это тип задаваемого объекта. Он всегда пишется с маленькой буквы и выделяется синим цветом, если вы правильно его написали. Таких типов существует несколько: effect – это эффект, который будет накладываться на какой-то объект, живой или нет; object – размещаемый объект (персонаж, сундук, точка, дверь, – все, что имеет тег и материально); string – это какая-то фраза, либо тег объекта (адрес, задаваемый вами в свойствах); int – какое-то целое число или же константа, используемая в скрипте. Есть еще несколько типов, но они не так важны как эти (location – локация, местность; vector – вектор, float – дробное число (с плавающей точкой)). Они используются редко и в специальных скриптах, сложность которых вам пока не под силу… 
oNPC – o-строчная – это опять же тип задаваемого объекта, но уже в сокращенном виде (s-string, o-object, e-effect, l-location и т.д.). Советую вам использовать их, чтобы не забыть, к какому типу относится ваша переменная. Но по желанию можно менять название. 
NPC – это ваша переменная, которая будет использована в данном скрипте. Ёе вы можете задать сами, но лучше делать это не от балды, а придерживаясь принципа объект-переменная. Так если ваш объект – персонаж, то NPC, если игрок – PC, если точка – Wp и т.д., чтобы в дальнейшем вы не запутались. А то назовете переменную персонажа oSunduk, а потом будете гадать, где же в скрипте ваш персонаж, позабыв, что назвали его в честь ящика. 
= – знак арифметического равенства. Ничего сверхъестественного. Левая часть равна правой и наоборот…
GetObjectByTag(“NPC_1”); – это уже сложнее. Перед вами одна из многочисленный, но не бесконечных (что уже радует…) функций, которые расположены в длинном столбике справа окна редактора скрипта. Каждая из них выполняет свою функцию, с которыми вы можете ознакомиться в Lexicon’е или же в статьях. В данном случае представлена функция (кстати, они пишутся слитно и каждое слово с заглавной буквы!), которая вылавливает из палитры объект с определенным тегом, который у нас указан в скобках и кавычках. Кавычки всегда используются, когда вы задаете тег объекта или же фразу. Тег вы назначаете сами, как хотите. Можете писать там имя персонажа латинскими, а можете брать из балды, как я сейчас и сделал. Только следите, чтобы тег, указанный в скрипте, совпадал с тегом самого перса, иначе скрипт не сработает (компилятор различает заглавные и строчные буквы!).
После каждой функции обязательно(!) ставьте (;), иначе строка не скомпилируется. Дело в том, что компилятор воспринимает этот знак, как конец функции, и начинает считывание следующей.
Идем далее…
object oWp = GetWaypointByTag(“WP_1”);
GetWaypointByTag(“WP_1”) – это точка, заданная специальной функцией по тегу, который мы присвоили точке маршрута.
Теперь напишем действие:
AssignCommand ( oNPC, ActionMoveToObject(oWp));
Разберем по косточкам… начнем, скажем, с конца…
ActionMoveToObject(oWp) – это само действие «идти» к точке, переменная которой указана в скобках.
AssignCommand(oNPC, – эта функция обременит действием oNPC’а.
И само собой (;)…
Теперь проверим: у нас есть функция, задающая точку и персонажа, который туда пойдет; у нас имеется само действие «идти»; после каждой ф-и стоит (;). Можно компилировать. Если вы все правильно сделали, то внизу экрана появится сообщение об удачной компиляции.
Перед следующим примером стоит дать вам еще немного теории. Разберем логические операторы, часто употребляемые в скриптах: и, или, не.
! – «не», например, (GetObjectByTag(“…”) – задать объект. (!GetObjectByTag(“…”)) – не задать объект.
|| – «или». Ставится для условия: или то, или это. Пример:
GetObjectByTag(“1”)|| GetObjectByTag(“2”), так если или объект с тегом «1» или с тегом «2».
&& – «и». Опять же: GetObjectByTag(“1”)&&GetObjectByTag(“2”), так если возьмем объекты с тегами «1» и «2», но одновременно оба.
Операторы очень важны, поэтому никогда не путайте их и не забывайте. Чтобы легче запомнить, приглядитесь к оператору &&, это же американский значок «и», ну а ||, это или | или |…
В скриптописании имеются переменные, те что вы задаете непосредственно в скрипте, и константы, которые как и функции, висят постоянно в самом редакторе. Большую часть я использую очень редко, а чаще всего те, которые определяют какой-то визуальный эффект, анимацию или управление камерой. Но есть среди них несколько очень важных констант, которые я вам сейчас перечислю.
OBJECT_SELF – это постоянная, которая при правильном вводе окрасится в синий цвет. Зачем она нужна?
Допустим, вы хотите написать не скрипт-одиночку, который подойдет только объекту с определенным тегом, а универсальный скрипт, в котором не нужно будет каждый раз менять тег, если вы хотите задать другой объект с другим тегом.
Помните строку AssignCommand(oNPC, ActionMoveToObject(oWp));? Тут команда задается объекту с тегом. Такой скрипт можно поставить куда угодно (триггер, слоты модуль, локации, персонажа и т.д.). Но этот скрипт будет действовать только на персонажа с тегом “NPC_1”. Если вы захотите написать точно такой же скрипт для другого персонажа, то просто исправите тег и сохраните под другим именем, но если у вас 10 персов нуждаются в таком скрипте? А если 100? А? Тут-то мы и прибегнем к маленькой хитрости.
AssignCommand(OBJECT_SELF, ActionMoveToObject(oWp));
Какие у нас изменения? oNPC заменили на константу OBJECT_SELF, которая означает «объект_сам». Теперь можно удалить строчку object oNPC=GetObjectByTag(“NPC_1”); за ненадобностью. После такого изменения скрипт можно использовать для любого персонажа, но(!) теперь вы сможете поместить его только в слоты самого персонажа или в слот «Совершены действия» диалога, но опять же принадлежащего данному персонажу. Это нужно для того, чтобы «объект_сам» был под постоянным наблюдением скрипта. Это не такой уж и страшный убыток по сравнению с приобретенными качествами скрипта.
OBJECT_INVALID. Что же это за фрукт? Разберемся! «Объект_недействителен», вот как можно представить эту константу. Она нужна для обозначения ценности определенного предмета. Я использую ее всего в 2-3 ф-ях с условием if, поэтому расскажу попозже о ее назначении, иначе вам будет просто не понять.
Кстати! Константы пишутся только заглавными буквами! Вы можете написать их сами по памяти, или же вызвать в правом столбике и нажать два раза на нужную. Она появится в основном окне там, где был курсор.
TRUE и FALSE. «Правда» и «Ложь» соответственно. Это нужно для определения ценности того или иного действия, истинно оно или нет. Также они означают два положения выключателя «1» и «0» соответственно. 1 – включено, 0 – выключено. Они встречаются почти во всех функциях. К примеру, в ф-и ActionMoveToObject(oWp), из нашего первого скрипта-примера, тоже есть эти константы, но мы не писали их, так как значение по умолчанию нам вполне подходит. Но по схеме функция должна быть такой: ActionMoveToObject(oWp, TRUE) – если мы хотим, чтобы непись бежала (Истинно), или же ActionMoveToObject(oWp,FALSE) – чтобы непись шла (ложно). В разных ф-ях TRUE и FALSE применяются по разному. Чтобы узнать подробно, смотрите помощь в нижней части экрана редактора скрипта, подсветив ф-ю:

Теперь следует оговорить три особо важные на мой взгляд ф-и. Лично я пользуюсь ими чаще всего, особенно когда пишу свои излюбленные CutScene.
AssignCommand(), ActionDoCommand(), DelayCommand()
Кто они? Что они? Зачем нужны? Все по порядку. 
AssignCommand() – это ф-я, которая непосредственно к объекту применяет ту ф-ю, которая прописана в ее скобках. В нашем случае AssignCommand(oNPC,ActionMoveToObject(oWp)); к объекту oNPC будет применена ф-я движения. Иначе скрипт просто не узнает, кто должен выполнить действие. Задать переменную-то мы задали, а вот как ее использовать без этой ф-и? Никак!
ActionDoCommand() – это ф-я последовательности действий. Если есть несколько ф-й, заключенных в скобки данной, то они выполнятся в строгой последовательности сверху вниз. Очередное действие начнется только после того, как закончится предыдущее. Очень важная ф-я если делать несложные CutScene.
DelayCommand() – самая важная, по крайней мере для меня, ф-я. Она распределяет все действия по времени друг за другом. Вы создаете своего рода расписание, по которому все поезда отправятся точно в указный срок.
DelayCommand(0.5, AssignCommand(oNPC,ActionMoveToObject(oWp1)));
DelayCommand(5.5, AssignCommand(oNPC,ActionMoveToObject(oWp2)));
Что же значат эти строки? Они значат, что на 0.5 секунде от начала выполнения скрипта непись направится в точку Wp1, а на 5.5 секунде непись изменит свой курс и пойдет в точке Wp2 не зависимо от того, завершил ли он предыдущий маршрут. Сложность этой ф-и состоит в том, что вам придется точно подгонять время совершения очередного действия, чтобы все они не сбились в кучу. Сначала нужно расставить всех участников CutScene, к примеру, а потом начинать писать ролик. Даже если ваш глаз превосходно наметан, все равно не обойтись без нескольких загрузок игры, чтобы проверить время выполнения каждого действия. Это очень нудно и сложно, но когда вы сделаете ролик, у вас не хватит слов описать, как здорово выглядят слаженные и настроенные действия.
Создайте непись с тегом «NPC_2» и точку с тегом «WP_2». Улучшим скрипт и сделаем его сложнее. Пусть непись совершит переход в точку, скажет фразу и проиграет анимацию.
Neverwinter Script Source
void main()
{
    object oNPC=GetObjectByTag("NPC_2");
    object oWp=GetWaypointByTag("WP_2");
    string sString="Привет!!!";
    ActionDoCommand(AssignCommand(oNPC,ActionMoveToObject(oWp,FALSE)));
    ActionDoCommand(AssignCommand(oNPC,SpeakString(sString)));
    ActionDoCommand(AssignCommand(oNPC,ActionPlayAnimation
    (ANIMATION_FIREFORGET_SALUTE,1.0,2.0)));
}


Действия произойдут по очереди, благодаря ф-и ActionDoCommand(). В строке ActionDoCommand(AssignCommand(oNPC,ActionMoveToObject(oWp,FALSE))); мы поставили FALSE, чтобы непись шла, а не бежала. Анимация будет длиться со скоростью 1,0 в течении 2,0 секунд.
Проверьте работоспособность скрипта, и приступим к изучению более сложных.
Разберем скрипты с условием IF. Здесь все скрипты будут проверяться условием «если», прежде чем выполнить или же нет какие-то действия. Зачем это нужно? А вдруг вы захотите, чтобы скрипт запустился именно таким-то человеком с таким-то тегом. Как сделать? Поставить условие. Разберем алгоритм.
Neverwinter Script Source
If (…)
{

}
return;
//Если (условие выполнения)
{
то выполнится то, что в скобках
}
//иначе возврат в начало скрипта.
//Разберем простой скрипт с условием.
void main()
{
    object oPC=GetEnteringObject();
    string sString="ГЫ!!!";
    if (GetIsPC(oPC))
    {
    AssignCommand(oPC,SpeakString(sString));
    }
    return;
}


Дело обстоит так: GetEnteringObject() – это ф-я без наличия чего-либо в скобках, так как просто-напросто хватает «за шиворот» наступившего на триггер или же вошедшего в комнату (ставится на соответствующие слоты). Если oPC (вошедший или наступивший) является игроком, управляемым вами непосредственно (GetIsPC(oPC)), то выполнится условие в скобках. Если же наступившим или вошедшим является непись, зверь или что-то еще, то скрипт не сработает и вернется в начало, т.е. будет снова боеспособным.
Теперь рассмотрим другой скрипт, но по смыслу абсолютно идентичный предыдущему.
Neverwinter Script Source
void main()
{
    object oPC=GetEnteringObject();
    string sString="ГЫ!!!";
    if (!GetIsPC(oPC))
    return;
    {
    AssignCommand(oPC,SpeakString(sString));
    }
}


Что изменилось? Положение слова “return”. И перед GetIsPC(oPC) появился «!», так если логический оператор «не». Зачем мы так сделали? Поменялся ли смысл написанного? Отвечаю: нет, не поменялся.
Читается скрипт так: если вошедший/наступивший НЕ игрок, то возврат, если же игрок, то он произнесет фразу. Понятно почему? В первом скрипте было определенное утверждение, а во втором мы поставили отрицание, следовательно поменялось положение возврата. Я лично предпочитаю писать второй вариант, но это лишь вопрос вкуса и привычки. На самом деле, повторяю, они абсолютно идентичны.
Рассмотрим еще одно условие, но с двумя телами.
Neverwinter Script Source
If (…)
{

}
else
{

}
void main()
{
    object oPC=GetEnteringObject();
    string sString1="Перед вами женщина!!!";
    string sString2="Перед вами мужчина!!!";
    if (GetGender(oPC)==GENDER_MALE)
    {
    AssignCommand(oPC,SpeakString(sString2));
    }
    else
    {
    AssignCommand(oPC,SpeakString(sString2));
    }
}


Если пол oPC – мужской, то он скажет фразу sString2, иначе sString1. Почему так? Проверка пойдет сверху. Ф-я GetGender(oPC) возьмет пол игрока и сравнит его с постоянной (мужчина и женщина, GENDER_MALE и GENDER_FEMALE, соответственно). Если пол совпадет с мужской постоянной, то пойдет выполнение действия, но если пол не совпадет с указанным, то проверка перепрыгнет через тело №1 и пойдет по телу №2, там где покоится женская фраза. В данном случае все просто, так как пола всего два. Третьего не дано от рождения… Но что если условия три, десять? К примеру проверка стоит на расу. И для каждой прописаны действия. Что тогда? Тогда идет небольшая корректировка. Тогда алгоритм будет выглядеть так:
Neverwinter Script Source
if(…)
{

}
else if //(новое условие)
{

}
return;


Если выполнится условие один, то пойдет выполнение тела №1, если задание соответствует условию 2, то пойдет выполнение тела 2. Если же действительность не совпадет ни с одним условием, произойдет возврат. Таких условий можно писать бесконечное множество, пока не надоест. 
Осталось поговорить про циклы. Что это такое, я толком так и не понял. Вроде какая-то нужная вещь, но я очень редко пользуюсь ими. Помнится, один раз написал цикл и поставил на триггер. Так как на нем стояло условие, которое начинало выполняться при загрузке модуля, у меня игра зависала еще при выборе персонажа. Так что циклы могут оказаться весьма полезными, если вы хотите подвесить ваш модуль. 
Цикл состоит из условие, проверка на которое будет происходить при запуске скрипта, и тела, внутри которого вы пишете то, что будет выполнятся. В зависимости от ваших нужд цикл может выполнятся вечно, несколько раз или же не выполниться ни разу.
Neverwinter Script Source
while (…)
{

}
// Рассмотрим простой пример по удалению эффектов с игрока скриптом с циклом.
void main()
{
    object oPC=GetEnteringObject();
    effect eEf=GetFirstEffect(oPC);
    while (GetIsEffectValid(eEf))
    {
    RemoveEffect(oPC,eEf);
    eEf=GetNextEffect(oPC);
    }
}


Цикл будет действовать так: сначала условие цикла проверит, существует ли такой эффект на персонаже. Если существует, эффект удалится, а цикл возьмется сравнивать следующий эффект (GetNextEffect(oPC)). Если же цикл больше не обнаружит наложенных эффектов, он прервется. Этот скрипт можно поставить на триггер или на вход в локацию, потому как oPC задан GetEnteringObject, но если вы зададите его по другому, то и скрипт можно будет поставить в другое место. Можете испробовать, но прежде чем наступать на триггер, наложите на себя парочку эффектов.  Кстати, если вы поставите слово break в конце тела цикла, то он выполнится только один раз. Это нужно… для чего-то, но я не пользовался такой фишкой. 
Neverwinter Script Source
void main()
{
    object oPC=GetEnteringObject();
    effect eEf=GetFirstEffect(oPC);
    while (GetIsEffectValid(eEf))
    {
    RemoveEffect(oPC,eEf);
    break;
    }
}


Существуют еще такие фишки, как Base и Switch, но у меня руки так и не дошли до их изучения, но ходят слухи среди посетителей Города Мастеров, что они сходны с циклами и условиями if.
Давайте теперь для самоконтроля разберем такой скрипт:

Neverwinter Script Source
//::///////////////////////////////////////////////
//:: Created By: MasterMage ©
//:: Created On:
//::///////////////////////////////////////////////
void main()
{
    //-----------objects---------------------------
    object oPC=GetEnteringObject();
    object oArea =GetObjectByTag("area011");
    //-----------effects---------------------------
    effect oEf=EffectVisualEffect(VFX_IMP_UNSUMMON,FALSE);
    //-----------vector----------------------------
    vector oVec=Vector(101.0f,52.0f,0.0f);
    //-----------location--------------------------
    location lLoc=Location(oArea,oVec, DIRECTION_NORTH);
    //-----------script----------------------------
    if (GetLocalInt(oPC,"ZedInt")==TRUE)
    {
    ActionDoCommand(SetCutsceneMode(oPC));
    ActionDoCommand(AssignCommand(oPC,SetCameraFacing(280.0, 8.5, 65.0, CAMERA_TRANSITION_TYPE_SLOW)));
    ActionWait(3.5);
    ActionDoCommand(ApplyEffectToObject( DURATION_TYPE_PERMANENT,oEf, oPC));
    ActionWait(3.0);
    ActionDoCommand(SetCutsceneMode(oPC,FALSE));
    ActionDoCommand(AssignCommand(oPC,ActionJumpToLocation(lLoc)));
    }
    return;
}


Что же делает этот скрипт? Его я написал специально для моего модуля. Работает он отлично и выглядит вполне эффектно. Когда вы наступаете на поверхность портала, включается экран Cutscene, после чего следует красивый визуальный эффект, который якобы перебрасывает вас в место назначения, а потом вы оказываетесь совершенно в другом месте.
Как же это делается? Отвечаю.
object oPC=GetEnteringObject(); – этой строкой задается переменная наступившего на триггер (портал).
object oArea =GetObjectByTag("area011"); – этой строкой задается локация, в которую надо перенестись.
effect oEf=EffectVisualEffect(VFX_IMP_UNSUMMON,FALSE); – визуальный эффект, который придаст картине более мистический оттенок.
vector oVec=Vector(101.0f,52.0f,0.0f); – этой строкой я задал точку, в которой появится персонаж.
location lLoc=Location(oArea,oVec, DIRECTION_NORTH); – эта строка объединяет в себе две ф-и выше и обозначает место телепортации, сторону света, куда будет смотреть персонаж.
if (GetLocalInt(oPC,"ZedInt")==TRUE) – если переменная, которую я поставил в диалоге равна TRUE, то скрипт сработает. Так если мне сказали в диалоге, что порталом можно пользоваться, и теперь скрипт будет работать постоянно.
Теперь, что касается тела скрипта. Сначала включится режим Cutscene. Затем (все происходит по очереди, благодаря ф-и ActionDoCommand) камера настраивается на персонажа, показывая его с выгодных позиций. Третья строка – ждем 3,5 секунды. Применяем эффект на персонажа. Опять ждем, но уже 3,0 секунды. Быстро отключаем режим Cutscene и переносим перса с назначенное место. 
Этот скрипт я написал сам, при помощи советов жителей Города Мастеров (не буду перечислять имена, так как они и сами знают, кто мне помогал, но если я кого-то забуду, будет не очень-то честно). Тогда я еще учился. Теперь же, когда я многое знаю по скриптописанию, то могу переписать этот скрипт вот так. Уловите разницу:
Neverwinter Script Source
void main()
{
    //-----------objects---------------------------
    object oPC=GetEnteringObject();
    object oWp=GetWaypointByTag("Wp1");
    //-----------effects---------------------------
    effect oEf=EffectVisualEffect(VFX_IMP_UNSUMMON,FALSE);
    //-----------script----------------------------
    if (GetLocalInt(oPC,"ZedInt")==TRUE)
    {
    ActionDoCommand(SetCutsceneMode(oPC));
    ActionDoCommand(AssignCommand(oPC,SetCameraFacing(280.0, 8.5, 65.0, CAMERA_TRANSITION_TYPE_SLOW)));
    ActionWait(3.5);
    ActionDoCommand(ApplyEffectToObject( DURATION_TYPE_PERMANENT,oEf, oPC));
    ActionWait(3.0);
    ActionDoCommand(SetCutsceneMode(oPC,FALSE));
    ActionDoCommand(AssignCommand(oPC,ActionJumpToLocation(GetLocation(oWp))));
    }
    return;
}


Вместо того, чтобы щепетильно высчитывать место векторами и локациями, я просто поставил туда точку с тегом “Wp1”. Теперь две строки не нужны. А если заменить ActionDoComman DelayCommand, то угадайте сколько строчек можно будет убрать? Вот вам задание, запишите этот скрипт через временную ф-ю. Ниже и предлагаю свой вариант. Можете подглядеть в него сразу, а можете проверить свои силы без моей помощи. Это на ваше усмотрение.
Neverwinter Script Source
void main()
{
    //-----------objects---------------------------
    object oPC=GetEnteringObject();
    object oWp=GetWaypointByTag("Wp1");
    //-----------effects---------------------------
    effect oEf=EffectVisualEffect(VFX_IMP_UNSUMMON);
    //-----------script----------------------------
    if (GetLocalInt(oPC,"ZedInt")==TRUE)
    {
    DelayCommand(0.1,SetCutsceneMode(oPC));
    DelayCommand(0.2,AssignCommand(oPC,SetCameraFacing(280.0, 8.5, 65.0, CAMERA_TRANSITION_TYPE_SLOW)));
    DelayCommand(3.7,ApplyEffectToObject( DURATION_TYPE_PERMANENT,oEf, oPC));
    DelayCommand(6.7,SetCutsceneMode(oPC,FALSE));
    DelayCommand(6.8,AssignCommand(oPC,ActionJumpToLocation(GetLocation(oWp))));
    }
    return;
}

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


Автор статьи: MasterMage©
Особая благодарность выражается: Aiwan’у, который закидывал меня советами и подсказками, ни разу не ответив грубо на мое постоянное нытье, что я ничего не понимаю; DBColl’у, который часто поправлял меня, наставляя «на путь истинный»; Lex’у, знания которого в области скриптописания не раз выручали меня; Lemegeton’у, который ни разу не пропустил мимо ушей мои вопросы; 2GoDoom’у, который появлялся редко, когда висели мои вопросы, но отвечал метко; Friedrich’у, за мудрые советы… Если я кого-то забыл, не серчайте.
P.S. – вы тоже можете попросить у них помощи, если посещаете Город Мастеров.


Айван: читайте и обсуждайте.


Сообщение отредактировал Aiwan - Mar 22 2005, 20:15
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Lex
сообщение Mar 22 2005, 22:11
Сообщение #2


Level 5
Иконки Групп

Класс: Обыватель
Характер: Lawful Neutral
Раса: Человек
NWN: Модмейкер
Проклятие Левора
Порядок Времени



QUOTE (MasterMage @ Mar 22 2005, 18:10)
void main() – это сам скрипт.

это основная функция, если я не ошибаюсь. Но не скрипт.

QUOTE (MasterMage @ Mar 22 2005, 18:10)
oNPC – o-строчная – это опять же тип задаваемого объекта, но уже в сокращенном виде

Лучше перефразируй. Прочитают, что oNPC это тип задаваемого объекта, что есть неверно.
oNPC это имя переменной.
QUOTE (MasterMage @ Mar 22 2005, 18:10)
location – локация

координаты лучше
QUOTE (MasterMage @ Mar 22 2005, 18:10)
NPC – это ваша переменная

oNPC
QUOTE (MasterMage @ Mar 22 2005, 18:10)
= – знак арифметического равенства. Ничего сверхъестественного. Левая часть равна правой и наоборот…

не надо наоборот. То, что слева приравнивается к тому, что справа и никак иначе.
QUOTE (MasterMage @ Mar 22 2005, 18:10)
которая вылавливает из палитры объект с определенным тегом

не из палитры. Она ищет реализованный объект (тот, что есть в модуле).
<small>Добавлено в 22:13</small>
QUOTE (MasterMage @ Mar 22 2005, 18:10)
Кавычки всегда используются, когда вы задаете тег объекта или же фразу.

QUOTE (MasterMage @ Mar 22 2005, 18:10)
string – это какая-то фраза, либо тег объекта

лучше скажи, что string это строки, а все строки даются в " ".
QUOTE (MasterMage @ Mar 22 2005, 18:10)
После каждой функции обязательно(!) ставьте (

опечался. ; надо ставить. Походу у тебя они везде в смыйлы превратились
<small>Добавлено в 22:19</small>
QUOTE (MasterMage @ Mar 22 2005, 18:10)
! – «не», например, (GetObjectByTag(“…”) – задать объект. (!GetObjectByTag(“…”)) – не задать объект.

эм...не хорощий пример. И вообще логическое "не" приминительно к функциям, возвращающим НЕ переменную типа int (причем только 0 и 1) не действует. (что логично. Найди противоположность объекта)

Просто скажи, что это логическое отрицание. В школе все логику проходят.
QUOTE (MasterMage @ Mar 22 2005, 18:10)
GetObjectByTag(“1”)|| GetObjectByTag(“2”), так если или объект с тегом «1» или с тегом «2».

не хороший пример.. логическая связка функций, возвращающий объекты ни к чему не приведет.
QUOTE (MasterMage @ Mar 22 2005, 18:10)
&& – «и». Опять же: GetObjectByTag(“1”)&&GetObjectByTag(“2”),

аналогично написанному про или. не то
QUOTE (MasterMage @ Mar 22 2005, 18:10)
OBJECT_SELF – это постоянная, которая при правильном вводе окрасится в синий цвет. Зачем она нужна?

не постоянная она.
Сам точно не знаю, как правильно сказать...это что-то переменной, которая для каждого скрипта определяется уникальная.
В отличие от констант, которые везде одно и то же значение имеют.
QUOTE (MasterMage @ Mar 22 2005, 18:10)
AssignCommand(OBJECT_SELF, ActionMoveToObject(oWp));

100 раз обсуждалось. Лишняя тут привязка.
QUOTE (MasterMage @ Mar 22 2005, 18:10)
OBJECT_INVALID. Что же это за фрукт? Разберемся! «Объект_недействителен», вот как можно представить эту константу. Она нужна для обозначения ценности

точнее для определения, а есть ли такой объект. Цена ни при чем.
QUOTE (MasterMage @ Mar 22 2005, 18:10)
ActionMoveToObject(oWp, TRUE) – если мы хотим, чтобы непись бежала (Истинно),

1. лучше во всей статье придерживайся одного правила названия. Не непись, а НПС (не все уловят связь)
2. Лучше перепиши, что второй параметр функции отвечает за бег. Если TRUE то бежит, если FALSE то идет.
<small>Добавлено в 22:32</small>
QUOTE (MasterMage @ Mar 22 2005, 18:10)
Иначе скрипт просто не узнает, кто должен выполнить действие.

узнает. OBJECT_SELF
QUOTE (MasterMage @ Mar 22 2005, 18:10)
ActionDoCommand() – это ф-я последовательности действий. Если есть несколько ф-й, заключенных в скобки данной, то они выполнятся в строгой последовательности сверху вниз.

внутри скобок только 1 функция, а не несколько.
ActionDoCommand() это постановщик действий в стек акций (команд, выполняющихся последовательно после завершения предыдущих)
<small>Добавлено в 22:36</small>
QUOTE (MasterMage @ Mar 22 2005, 18:10)
DelayCommand() – самая важная, по крайней мере для меня, ф-я. Она распределяет все действия по времени друг за другом. Вы создаете своего рода расписание, по которому все поезда отправятся точно в указный срок.

корректнее сказать, что функция задерживает на указанный срок выполнение функции. Время считается от запуска скрипта.
QUOTE (MasterMage @ Mar 22 2005, 18:10)
Что же значат эти строки? Они значат, что на 0.5 секунде от начала выполнения скрипта непись направится в точку Wp1
Во, вот так.


QUOTE (MasterMage @ Mar 22 2005, 18:10)
Они значат, что на 0.5 секунде от начала выполнения скрипта непись направится в точку Wp1, а на 5.5 секунде непись изменит свой курс и пойдет в точке Wp2 не зависимо от того, завершил ли он предыдущий маршрут.

нет. ActionMoveToObject это акция. Пока не завершена, следующая не начнется. И задержки не помогут (только если задержать). Чтобы смена курса произошла во время надо между ними вклинить строку DelayCommand(5.3, AssignCommand(oNPC,ClearAllActions());
<small>Добавлено в 22:44</small>
QUOTE (MasterMage @ Mar 22 2005, 18:10)
Действия произойдут по очереди, благодаря ф-и ActionDoCommand(). В строке ActionDoCommand(AssignCommand(oNPC,ActionMoveToObject(oWp,FALSE))); мы поставили FALSE, чтобы непись шла, а не бежала. Анимация будет длиться со скоростью 1,0 в течении 2,0 секунд.

нет. На стороннем объекте (а это на нем написан скрипт) использование такой конструкции это просто последовательное выполнение ПРИВЯЗКИ К НПС действий. Сами действия он выполнит чуть не так. А именно: фразу скажет, потом пойдет, потом анимация.



блин, все, дальше не могу. Потом допишу еще
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Friedrich
сообщение Mar 23 2005, 00:52
Сообщение #3


Level 5
**

Класс: Рейнджер
Характер: Neutral Good
Раса: Человек



QUOTE
= – знак арифметического равенства. Ничего сверхъестественного. Левая часть равна правой и наоборот…

Знак равенства, это скорее '=='.
А '=' - это оператор присваивания. Тому что слева, присваивается значение того что справа: :P
i = i+1;

И вообще, прежде чем писать такое (в смысле, мануал по скриптингу), не плохо было бы ознакомиться, например с какой-нибудь книжкой по С/С++.
Это я не наезжаю, это я советую.

Кстати, по моему, самое лучшее, что было написано для начинающих скриптеров - это уроки Celowin-а из Лексикона. Кстати, кто то переводил (возможно, Qwester - не помню, как капитализируются буквы ника :D ) на рельсах. Но рельсы канули в лету, а вместе с ними, похоже, и эти уроки. На RPG planet я, по крайней мере, их не нашел. Может написать тамошней администрации, чтоб поискали? Как думаете?


Сообщение отредактировал Friedrich - Mar 23 2005, 01:00
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Vhall
сообщение Mar 23 2005, 09:50
Сообщение #4


Level 19
Иконки Групп

Класс: Обыватель
Характер: True Neutral
Раса: Дварф
NWN: Контент



QUOTE (Friedrich @ Mar 23 2005, 00:52)
(возможно, Qwester - не помню, как капитализируются буквы ника biggrin.gif )

Точно не он! :ROFL:
Я по английски читаю и перевожу, но не понимаю...(с) QweSteR
QUOTE (Friedrich @ Mar 23 2005, 00:52)
На RPG planet я, по крайней мере, их не нашел. Может написать тамошней администрации, чтоб поискали? Как думаете?
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Lex
сообщение Mar 23 2005, 10:22
Сообщение #5


Level 5
Иконки Групп

Класс: Обыватель
Характер: Lawful Neutral
Раса: Человек
NWN: Модмейкер
Проклятие Левора
Порядок Времени



ИТОГ: в таком виде статью НИ В КОЕМ СЛУЧАЕ НЕЛЬЗЯ ПОКАЗЫВАТЬ НОВИЧКАМ.

MasterMage, без обид, но фактических ошибок и неточностей хватает.
Я продолжу их выписывать и поправлять. Мастера другие, тоже подключайтесь.
Лозунг: Приведем статью в надлежащий вид.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
slavaz
сообщение Mar 23 2005, 12:48
Сообщение #6


Пингвиноид
Иконки Групп

Класс: Обыватель
Характер: True Neutral
Раса: Человек



QUOTE (Lex @ Mar 22 2005, 23:11)
QUOTE (MasterMage @  Mar 22 2005, 18:10)

OBJECT_SELF – это постоянная, которая при правильном вводе окрасится в синий цвет. Зачем она нужна?

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

Это что-то вроде указателя this в С++
Указывает на объект, в событиях которого произведен вызов функции.
QUOTE (MasterMage @ Mar 22 2005, 19:10)
OBJECT_INVALID. Что же это за фрукт? Разберемся! «Объект_недействителен», вот как можно представить эту константу. Она нужна для обозначения ценности определенного предмета. Я использую ее всего в 2-3 ф-ях с условием if, поэтому расскажу попозже о ее назначении, иначе вам будет просто не понять.

Это аналог константы NULL в С.
Правильнее написать:
OBJECT_INVALID - это обозначение несуществующего объекта. Мало ли в какой ситуации может возникнуть. Например, нужно узнать, что находится в инвентаре какого-нибудь NPC, плэйсебла. Тогда Функция GetFirstItemInInventory вернет первый предмет в инвентаре или OBJECT_INVALID
если в инвентаре ничего нет.

Кстати, в статье неплохо было бы написать и про автодополнение по F2. Типа, написал OBJECT_ потом нажал F2 и из выпадающего списка выбрал нужную константу. Или можно написать начало какой-нибудь функции и нажать F2... типа, как в Дельфях или BC++B. Для новичков самое то.

Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
MasterMage
сообщение Mar 23 2005, 15:39
Сообщение #7


Level 8
***

Класс: Маг
Характер: Lawful Good
Раса: Полуэльф



Все учел, имеено для этого тема и создана, чтобы вы поискали неточности, да и сами что-то свое дополнили, чтобы статья стала более читабельной и понятной, да и инфы побольше.
Lex Вот оно! Спасибо за "группу разбора"! :BRAVO: Теперь я понял недочеты. Сразу говорю, что C++ я не изучал, руки не дойдут... =) Но по скриптам кой чаго понимаю...
Но в некоторых случаях ты слишком придирчив:
QUOTE (Lex @ Mar 22 2005, 22:11)
OBJECT_SELF – это постоянная, которая при правильном вводе окрасится в синий цвет. Зачем она нужна?

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

она постоянная, пока не примет значение переменной. Ты же не изменяешь ее смысл. Она всегда указывает на САМ объект.

Friedrich
QUOTE (Friedrich @ Mar 23 2005, 00:52)
QUOTE
= – знак арифметического равенства. Ничего сверхъестественного. Левая часть равна правой и наоборот…


Знак равенства, это скорее '=='.
А '=' - это оператор присваивания. Тому что слева, присваивается значение того что справа:
i = i+1;

про == особый разговор. Но упс, я забыл про это.... Допишем...
QUOTE (Lex @ Mar 23 2005, 10:22)
MasterMage, без обид, но фактических ошибок и неточностей хватает.
какая обида, я пока не выбиваюсь в мастера! Наоборот, вы мну всегда наставляли, вот и опять помогаете... Все хорошо! :yes:
Lex кстати, статью про квесты потом тоже можете разобрать по косточкам, но она с картинками, посему так не получится поместить:(
slavazпро f2 знаю, но тоже проехал мимо... Ничего, я по ночам не увлекаюсь написанием статей, посему "первый блин в коме" (Aiwan©).
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Lex
сообщение Mar 23 2005, 23:15
Сообщение #8


Level 5
Иконки Групп

Класс: Обыватель
Характер: Lawful Neutral
Раса: Человек
NWN: Модмейкер
Проклятие Левора
Порядок Времени



QUOTE (MasterMage @ Mar 22 2005, 18:10)
//Если (условие выполнения)
{
то выполнится то, что в скобках
}
//иначе возврат в начало скрипта.

return это не в начало скрипта. Это выход из него.


QUOTE (MasterMage @ Mar 22 2005, 18:10)
void main()
{
    object oPC=GetEnteringObject();
    string sString="ГЫ!!!";
    if (!GetIsPC(oPC))
    return;
    {
    AssignCommand(oPC,SpeakString(sString));
    }
}

лишние {}.


QUOTE (MasterMage @ Mar 22 2005, 18:10)
Осталось поговорить про циклы. Что это такое, я толком так и не понял. Вроде какая-то нужная вещь, но я очень редко пользуюсь ими. Помнится, один раз написал цикл и поставил на триггер. Так как на нем стояло условие, которое начинало выполняться при загрузке модуля, у меня игра зависала еще при выборе персонажа. Так что циклы могут оказаться весьма полезными, если вы хотите подвесить ваш модуль. 

мдям...вот это точно лучше убрать. Не знаешь если чего-то, то не пиши. Циклы это ОЧЕНЬ полезная и функциональная вещь.

QUOTE (MasterMage @ Mar 22 2005, 18:10)
Switch, но у меня руки так и не дошли до их изучения, но ходят слухи среди посетителей Города Мастеров, что они сходны с циклами и условиями if.

епрть..
Neverwinter Script Source
switch (Условие)
    {
     case Значение1:
            break;
     case Значение2:
            break;
    }

тут условие это обязательно какое-то число (функция, возвращающая число, андом и прочее)
В зависимости от того, какое значение примет условие будет выбрана одня из case веток.
пример:
Neverwinter Script Source
void main()
{
object oPC = GetFirstPC();
string sSpeak;
switch(GetRacialType(oPC))
    {
     case RACIAL_TYPE_HUMAN: sSpeak = "человечина";break;
     case RACIAL_TYPE_DWARF: sSpeak = "коротышка";break;
     case RACIAL_TYPE_GNOME: sSpeak = "карлик";break;
     case RACIAL_TYPE_HALFLING: sSpeak = "недомерок";break;
    }
SpeakString(sSpeak);
}

НПС будет говорить фразу согласно рассе игрока.
<small>Добавлено в 23:16</small>
это проще чем нагромождение if'ов.

<small>Добавлено в 23:18</small>
QUOTE (MasterMage @ Mar 22 2005, 18:10)
if (GetLocalInt(oPC,"ZedInt")==TRUE)

можно просто if (GetLocalInt(oPC,"ZedInt"))
И вообще return ставить в конце скрипта НЕ НУЖНО
<small>Добавлено в 23:21</small>
QUOTE (slavaz @ Mar 23 2005, 12:48)
Это что-то вроде указателя this в С++
Указывает на объект, в событиях которого произведен вызов функции.

да, OBJECT_SELF пожалуй так и надо объяснять.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
baskan
сообщение Mar 25 2005, 22:07
Сообщение #9


Level 7
**

Класс: Бард
Характер: Lawful Good
Раса: Фея



Жду след. статей. Ты до меня достучался :xz:
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
MasterMage
сообщение Mar 25 2005, 22:21
Сообщение #10


Level 8
***

Класс: Маг
Характер: Lawful Good
Раса: Полуэльф



baskan будут :D
LEX
Вот... Отредактировал, посмотри...
------
CODE
Если вы решили создать свой модуль, вам обязательно понадобятся скрипты. Это особый программный язык, разработанный для набора инструментов Aurora Toolset. Без него никак не обойтись, если вы собрались построить хороший модуль. Именно они заставляют всех персонажей в игре выполнять их действия, врагов – нападать на вас, подателей сюжет – давать вам квесты. Без них модуль будет выглядеть безжизненным.
Чтобы освоить этот язык, нужно научиться понимать функции и алгоритм их написания. Обязательно вооружитесь статьей с полным описанием всех функции на русском языке. Или на крайний случай воспользуйтесь Lexicon’ом. Найти статьи вы сможете на форуме «Город мастеров» по адресу www.wrg.ru/forums.
Создайте персонажа с тегом “NPC_1”, точку с тегом “WP_1” и поставьте их на достаточном на ваше усмотрение расстоянии.
Теперь напишем скрипт, с помощью которого можно заставить персонажа совершить переход в определенную точку на карте. Этим примером пользуются многие в своих статьях, и я не буду исключением.
void main()
{
object oNPC=GetObjectByTag("NPC_1");
object oWp=GetWaypointByTag("WP_1");
AssignCommand(oNPC,ActionMoveToObject(oWp));
}
void main() – это сама функция. Они бываю разные по своему назначению, но этот является универсальным, по умолчанию.
{} – все, что находится внутри фигурных скобок – ваш скрипт. Если он правильно написан, он будет выполняться сверху вниз, не иначе!
Самые первые строчки скрипта – это раздача ролей актерам. Вы задаете скрипту всех, кто будет участвовать в действиях, по тегам.
object oNPC = GetObjectByTag(“NPC_1”);
Разберем эту строку! Object – это тип задаваемого объекта. Он всегда пишется с маленькой буквы и выделяется синим цветом, если вы правильно его написали. Таких типов существует несколько: effect – это эффект, который будет накладываться на какой-то объект, живой или нет; object – размещаемый объект (персонаж, сундук, точка, дверь, – все, что имеет тег и материально); string – это какая-то фраза, либо тег объекта (адрес, задаваемый вами в свойствах); int – какое-то целое число или же константа, используемая в скрипте. Есть еще несколько типов, но они не так важны как эти (location – локация, местность; vector – вектор, float – дробное число (с плавающей точкой)). Они используются редко и в специальных скриптах, сложность которых вам пока не под силу… 
oNPC – здесь o-строчная – это опять же тип задаваемого объекта, но уже в сокращенном виде (s-string, o-object, e-effect, l-location и т.д.). Советую вам использовать их, чтобы не забыть, к какому типу относится ваша переменная. Но по желанию можно менять название. 
oNPC – это ваша переменная, которая будет использована в данном скрипте. Ёе вы можете задать сами, но лучше делать это не от балды, а придерживаясь принципа объект-переменная. Так если ваш объект – персонаж, то NPC, если игрок – PC, если точка – Wp и т.д., чтобы в дальнейшем вы не запутались. А то назовете переменную персонажа oSunduk, а потом будете гадать, где же в скрипте ваш персонаж, позабыв, что назвали его в честь ящика. 
= – знак арифметического равенства. Ничего сверхъестественного. Левая часть равна правой…
GetObjectByTag(“NPC_1”); – это уже сложнее. Перед вами одна из многочисленный, но не бесконечных (что уже радует…) функций, которые расположены в длинном столбике справа окна редактора скрипта. Каждая из них выполняет свою функцию, с которыми вы можете ознакомиться в Lexicon’е или же в статьях. В данном случае представлена функция (кстати, они пишутся слитно и каждое слово с заглавной буквы!), которая вылавливает объект с определенным тегом (у нас указан в скобках и кавычках), который уже заранее создан в модуле. Кавычки всегда используются, когда вы задаете тег объекта или же фразу. Тег вы назначаете сами, как хотите. Можете писать там имя персонажа латинскими, а можете брать из балды, как я сейчас и сделал. Только следите, чтобы тег, указанный в скрипте, совпадал с тегом самого перса, иначе скрипт не сработает (компилятор различает заглавные и строчные буквы!).
После каждой функции обязательно(!) ставьте;, иначе строка не скомпилируется. Дело в том, что компилятор воспринимает этот знак, как конец функции, и начинает считывание следующей.
Идем далее…
object oWp = GetWaypointByTag(“WP_1”);
GetWaypointByTag(“WP_1”) – это точка, заданная специальной функцией по тегу, который мы присвоили точке маршрута.
Теперь напишем действие:
AssignCommand ( oNPC, ActionMoveToObject(oWp));
Разберем по косточкам… начнем, скажем, с конца…
ActionMoveToObject(oWp) – это само действие «идти» к точке, переменная которой указана в скобках.
AssignCommand(oNPC, – эта функция обременит действием oNPC’а.
И само собой;…
Теперь проверим: у нас есть функция, задающая точку и персонажа, который туда пойдет; у нас имеется само действие «идти»; после каждой ф-и стоит (;). Можно компилировать. Если вы все правильно сделали, то внизу экрана появится сообщение об удачной компиляции.
Перед следующим примером стоит дать вам еще немного теории. Разберем логические операторы, часто употребляемые в скриптах: и, или, не.
! – «не» например, (GetLocalInt(oPC,”int”)==1) означает, что переменная равна 1. (GetLocalInt(oPC,”int”)!=1), а здесь говорится о том, что переменная НЕ равна 1 (чему угодно, но не 1).
|| – «или». Ставится для условия: или то, или это. Пример:
GetLocalInt(oPC,”int”)==1||GetLocalInt(oPC,”int2”)==1. Прочтем так: либо переменная с тегом «int» ==1, либо переменная с тегом «int2» равна 1.
&& – «и». Опять же: GetLocalInt(oPC,”int”)==1&&GetLocalInt(oPC,”int2”)==1. Так если обе переменные с тегами «int» и «int2» должны быть равны 1 одновременно.
Операторы очень важны, поэтому никогда не путайте их и не забывайте. Чтобы легче запомнить, приглядитесь к оператору &&, это же американский значок «и», ну а ||, это или | или |…
В скриптописании имеются переменные, те что вы задаете непосредственно в скрипте, и константы, которые как и функции, висят постоянно в самом редакторе. Большую часть я использую очень редко, а чаще всего те, которые определяют какой-то визуальный эффект, анимацию или управление камерой. Но есть среди них несколько очень важных констант, которые я вам сейчас перечислю.
OBJECT_SELF – это постоянная, которая при правильном  вводе окрасится в синий цвет. Зачем она нужна?
Допустим, вы хотите написать не скрипт-одиночку, который подойдет только объекту с определенным тегом, а универсальный скрипт, в котором не нужно будет каждый раз менять тег, если вы хотите задать другой объект с другим тегом.
Помните строку AssignCommand(oNPC, ActionMoveToObject(oWp));? Тут команда задается объекту с тегом. Такой скрипт можно поставить куда угодно (триггер, слоты модуль, локации, персонажа и т.д.). Но этот скрипт будет действовать только на персонажа с тегом “NPC_1”. Если вы захотите написать точно такой же скрипт для другого персонажа, то просто исправите тег и сохраните под другим именем, но если у вас 10 персов нуждаются в таком скрипте? А если 100? А? Тут-то мы и прибегнем к маленькой хитрости.
AssignCommand(OBJECT_SELF, ActionMoveToObject(oWp));
Какие у нас изменения? oNPC заменили на константу OBJECT_SELF, которая означает «объект_сам». Теперь можно удалить строчку object oNPC=GetObjectByTag(“NPC_1”); за ненадобностью. После такого изменения скрипт можно использовать для любого персонажа, но(!) теперь вы сможете поместить его только в слоты самого персонажа или в слот «Совершены действия» диалога, но опять же принадлежащего данному персонажу. Это нужно для того, чтобы «объект_сам» был под постоянным наблюдением скрипта. Это не такой уж и страшный убыток по сравнению с приобретенными качествами скрипта.
OBJECT_INVALID. Что же это за фрукт? Разберемся! «Объект_недействителен», вот как можно представить эту константу. Она проверяет, существует ли какой-то объект. Я использую ее всего в 2-3 ф-ях с условием if, поэтому расскажу попозже о ее назначении, иначе вам будет просто не понять.
Кстати! Константы пишутся только заглавными буквами! Вы можете написать их сами по памяти, или же вызвать в правом столбике и нажать два раза на нужную. Она появится в основном окне там, где был курсор.
TRUE и FALSE. «Правда» и «Ложь» соответственно. Это нужно для определения ценности того или иного действия, истинно оно или нет. Также они означают два положения выключателя «1» и «0» соответственно. 1 – включено, 0 – выключено. Они встречаются почти во всех функциях. К примеру, в ф-и ActionMoveToObject(oWp), из нашего первого скрипта-примера, тоже есть эти константы, но мы не писали их, так как значение по умолчанию нам вполне подходит. Но по схеме функция должна быть такой: ActionMoveToObject(oWp, TRUE) – если мы хотим, чтобы НПС бежал (TRUE), или же ActionMoveToObject(oWp,FALSE) – чтобы непись шла (FALSE). В разных ф-ях TRUE и FALSE применяются по разному. Чтобы узнать подробно, смотрите помощь в нижней части экрана редактора скрипта, подсветив ф-ю:

Теперь следует оговорить три особо важные на мой взгляд ф-и. Лично я пользуюсь ими чаще всего, особенно когда пишу свои излюбленные CutScene.
AssignCommand(), ActionDoCommand(), DelayCommand()
Кто они? Что они? Зачем нужны? Все по порядку. 
AssignCommand() – это ф-я, которая непосредственно к объекту применяет ту ф-ю, которая прописана в ее скобках. В нашем случае AssignCommand(oNPC,ActionMoveToObject(oWp)); к объекту oNPC будет применена ф-я движения.
ActionDoCommand() – это ф-я последовательности действий. Если есть несколько ф-й, заключенных в скобки данной, то они выполнятся в строгой последовательности сверху вниз. Очередное действие начнется только после того, как закончится предыдущее. Очень важная ф-я если делать несложные CutScene.
DelayCommand() – самая важная, по крайней мере для меня, ф-я. Она распределяет все действия по времени друг за другом от начала выполнения скрипта. Вы создаете своего рода расписание, по которому все поезда отправятся точно в указный срок.
DelayCommand(0.5, AssignCommand(oNPC,ActionMoveToObject(oWp1)));
DelayCommand(5.5, AssignCommand(oNPC,ActionMoveToObject(oWp2)));
Что же значат эти строки? Они значат, что на 0.5 секунде от начала выполнения скрипта непись направится в точку Wp1, а на 5.5 секунде непись изменит свой курс и пойдет в точке Wp2 не зависимо от того, завершил ли он предыдущий маршрут. Сложность этой ф-и состоит в том, что вам придется точно подгонять время совершения очередного действия, чтобы все они не сбились в кучу. Сначала нужно расставить всех участников CutScene, к примеру, а потом начинать писать ролик. Даже если ваш глаз превосходно наметан, все равно не обойтись без нескольких загрузок игры, чтобы проверить время выполнения каждого действия. Это очень нудно и сложно, но когда вы сделаете ролик, у вас не хватит слов описать, как здорово выглядят слаженные и настроенные действия.
Создайте непись с тегом «NPC_2» и точку с тегом «WP_2». Улучшим скрипт и сделаем его сложнее. Пусть непись совершит переход в точку, скажет фразу и проиграет анимацию.
void main()
{
   object oNPC=GetObjectByTag("NPC_2");
   object oWp=GetWaypointByTag("WP_2");
   string sString="Привет!!!";
   ActionDoCommand(AssignCommand(oNPC,ActionMoveToObject(oWp,FALSE)));
   ActionDoCommand(AssignCommand(oNPC,ActionSpeakString(sString)));
   ActionDoCommand(AssignCommand(oNPC,ActionPlayAnimation
   (ANIMATION_FIREFORGET_SALUTE,1.0,2.0)));
}
Действия произойдут по очереди, благодаря ф-и ActionDoCommand(). В строке ActionDoCommand(AssignCommand(oNPC,ActionMoveToObject(oWp,FALSE))); мы поставили FALSE, чтобы непись шла, а не бежала. Анимация будет длиться со скоростью 1,0 в течении 2,0 секунд.
Проверьте работоспособность скрипта, и приступим к изучению более сложных.
Разберем скрипты с условием IF. Здесь все скрипты будут проверяться условием «если», прежде чем выполнить или же нет какие-то действия. Зачем это нужно? А вдруг вы захотите, чтобы скрипт запустился именно таким-то человеком с таким-то тегом. Как сделать? Поставить условие. Разберем алгоритм.
If (…)
{

}
return;
Если (условие выполнения)
{
то выполнится то, что в скобках
}
иначе выход из скрипта без каких либо действий..
Разберем простой скрипт с условием.
void main()
{
   object oPC=GetEnteringObject();
   string sString="ГЫ!!!";
   if (GetIsPC(oPC))
   {
   AssignCommand(oPC,SpeakString(sString));
   }    
}
Дело обстоит так: GetEnteringObject() – это ф-я без наличия чего-либо в скобках, так как просто-напросто хватает «за шиворот» наступившего на триггер или же вошедшего в комнату (ставится на соответствующие слоты). Если oPC (вошедший или наступивший) является игроком, управляемым вами непосредственно (GetIsPC(oPC)), то выполнится условие в скобках. Если же наступившим или вошедшим является непись, зверь или что-то еще, то скрипт не сработает и вернется в начало, т.е. будет снова боеспособным.
Теперь рассмотрим другой скрипт, но по смыслу абсолютно идентичный предыдущему.
void main()
{
   object oPC=GetEnteringObject();
   string sString="ГЫ!!!";
   if (!GetIsPC(oPC))
   return;    
   AssignCommand(oPC,SpeakString(sString));    
}
Что изменилось? Положение слова “return”. И перед GetIsPC(oPC) появился «!», так если логический оператор «не». Зачем мы так сделали? Поменялся ли смысл написанного? Отвечаю: нет, не поменялся.
Читается скрипт так: если вошедший/наступивший НЕ игрок, то возврат, если же игрок, то он произнесет фразу. Понятно почему? В первом скрипте было определенное утверждение, а во втором мы поставили отрицание, следовательно поменялось положение возврата. Я лично предпочитаю писать второй вариант, но это лишь вопрос вкуса и привычки. На самом деле, повторяю, они абсолютно идентичны.
Рассмотрим еще одно условие, но с двумя телами.
If (…)
{

}
else
{

}
void main()
{
   object oPC=GetEnteringObject();
   string sString1="Перед вами женщина!!!";
   string sString2="Перед вами мужчина!!!";
   if (GetGender(oPC)==GENDER_MALE)
   {
   AssignCommand(oPC,SpeakString(sString2));
   }
   else
   {
   AssignCommand(oPC,SpeakString(sString2));
   }
}
Если пол oPC – мужской, то он скажет фразу sString2, иначе sString1. Почему так? Проверка пойдет сверху. Ф-я GetGender(oPC) возьмет пол игрока и сравнит его с постоянной (мужчина и женщина, GENDER_MALE и GENDER_FEMALE, соответственно). Если пол совпадет с мужской постоянной, то пойдет выполнение действия, но если пол не совпадет с указанным, то проверка перепрыгнет через тело №1 и пойдет по телу №2, там где покоится женская фраза. В данном случае все просто, так как пола всего два. Третьего не дано от рождения… Но что если условия три, десять? К примеру проверка стоит на расу. И для каждой прописаны действия. Что тогда? Тогда идет небольшая корректировка. Тогда алгоритм будет выглядеть так:
if(…)
{

}
else if(новое условие)
{

}
return;
Если выполнится условие один, то пойдет выполнение тела №1, если задание соответствует условию 2, то пойдет выполнение тела 2. Если же действительность не совпадет ни с одним условием, произойдет возврат. Таких условий можно писать бесконечное множество, пока не надоест.   
Осталось поговорить про циклы. Вещь-то это очень даже полезная. Он состоит из условия, проверка на которое будет происходить при запуске скрипта, и тела, внутри которого вы пишете то, что будет выполнятся. В зависимости от ваших нужд цикл может выполнятся вечно, несколько раз или же не выполниться ни разу.
while (…)
{

}
Рассмотрим простой пример по удалению эффектов с игрока скриптом с циклом.
void main()
{
   object oPC=GetEnteringObject();
   effect eEf=GetFirstEffect(oPC);
   while (GetIsEffectValid(eEf))
   {
   RemoveEffect(oPC,eEf);
   eEf=GetNextEffect(oPC);
   }
}
Цикл будет действовать так: сначала условие цикла проверит, существует ли такой эффект на персонаже. Если существует, эффект удалится, а цикл возьмется сравнивать следующий эффект (GetNextEffect(oPC)). Если же цикл больше не обнаружит наложенных эффектов, он прервется. Этот скрипт можно поставить на триггер или на вход в локацию, потому как oPC задан GetEnteringObject, но если вы зададите его по другому, то и скрипт можно будет поставить в другое место. Можете испробовать, но прежде чем наступать на триггер, наложите на себя парочку эффектов.  Кстати, если вы поставите слово break в конце тела цикла, то он выполнится только один раз.
void main()
{
   object oPC=GetEnteringObject();
   effect eEf=GetFirstEffect(oPC);
   while (GetIsEffectValid(eEf))
   {
   RemoveEffect(oPC,eEf);
   break;
   }
}
Существуют еще такие фишки, как Case и Switch. Разберемся, что же это такое. Скажем так: чтобы не городить слишком много if условий, можно применить эти ф-и. Разберем пример.
switch (Условие)
   {
    case Значение1:
           break;
    case Значение2:
           break;
   }
Тут условие – обязательно какое-то число (функция, возвращающая число, андом и проч.)
В зависимости от того, какое значение примет условие, будет выбрана одна из case веток.
Пример:
void main()
{
object oPC = GetFirstPC();
string sSpeak;
switch(GetRacialType(oPC))
   {
    case RACIAL_TYPE_HUMAN: sSpeak = "человечина";break;
    case RACIAL_TYPE_DWARF: sSpeak = "коротышка";break;
    case RACIAL_TYPE_GNOME: sSpeak = "карлик";break;
    case RACIAL_TYPE_HALFLING: sSpeak = "недомерок";break;
   }
SpeakString(sSpeak);
}
НПС будет говорить фразу согласно расе игрока. Посмотрите, если опробовать написать такой скрипт через if условия, нам пришлось бы применять…4 условия.
If(…)

else if(…)

else if(…)

else if(…)

Давайте теперь для самоконтроля разберем такой скрипт:
//::///////////////////////////////////////////////
//:: Created By: MasterMage ©
//:: Created On:
//::///////////////////////////////////////////////
void main()
{
   //-----------objects---------------------------
   object oPC=GetEnteringObject();
   object oArea =GetObjectByTag("area011");
   //-----------effects---------------------------
   effect oEf=EffectVisualEffect(VFX_IMP_UNSUMMON,FALSE);
   //-----------vector----------------------------
   vector oVec=Vector(101.0f,52.0f,0.0f);
   //-----------location--------------------------
   location lLoc=Location(oArea,oVec, DIRECTION_NORTH);
   //-----------script----------------------------
   if (GetLocalInt(oPC,"ZedInt")==TRUE)//для упрощения записи можно написать так: if (GetLocalInt(oPC,"ZedInt")) потому как TRUE в данном случае стоит по умолчанию (это написано в подсказке, когда подсвечиваете ф-ю). Поэтому константу можно опустить.
   {
   ActionDoCommand(SetCutsceneMode(oPC));
   ActionDoCommand(AssignCommand(oPC,SetCameraFacing(280.0, 8.5, 65.0, CAMERA_TRANSITION_TYPE_SLOW)));
   ActionWait(3.5);
   ActionDoCommand(ApplyEffectToObject( DURATION_TYPE_PERMANENT,oEf, oPC));
   ActionWait(3.0);
   ActionDoCommand(SetCutsceneMode(oPC,FALSE));
   ActionDoCommand(AssignCommand(oPC,ActionJumpToLocation(lLoc)));
   }
   return;
}
Что же делает этот скрипт? Его я написал специально для моего модуля. Работает он отлично и выглядит вполне эффектно. Когда вы наступаете на поверхность портала, включается экран Cutscene, после чего следует красивый визуальный эффект, который якобы перебрасывает вас в место назначения, а потом вы оказываетесь совершенно в другом месте. 
Как же это делается? Отвечаю.
object oPC=GetEnteringObject(); – этой строкой задается переменная наступившего на триггер (портал).
object oArea =GetObjectByTag("area011"); – этой строкой задается локация, в которую надо перенестись.
effect oEf=EffectVisualEffect(VFX_IMP_UNSUMMON,FALSE); – визуальный эффект, который придаст картине более мистический оттенок.
vector oVec=Vector(101.0f,52.0f,0.0f); – этой строкой я задал точку, в которой появится персонаж.
location lLoc=Location(oArea,oVec, DIRECTION_NORTH); – эта строка объединяет в себе две ф-и выше и обозначает место телепортации, сторону света, куда будет смотреть персонаж.
if (GetLocalInt(oPC,"ZedInt")==TRUE) – если переменная, которую я поставил в диалоге  равна TRUE, то скрипт сработает. Так если мне сказали в диалоге, что порталом можно пользоваться, и теперь скрипт будет работать постоянно.  
Теперь, что касается тела скрипта. Сначала включится режим Cutscene. Затем (все происходит по очереди, благодаря ф-и ActionDoCommand) камера настраивается на персонажа, показывая его с выгодных позиций. Третья строка – ждем 3,5 секунды. Применяем эффект на персонажа. Опять ждем, но уже 3,0 секунды. Быстро отключаем режим Cutscene и переносим перса с назначенное место. 
Этот скрипт я написал сам, при помощи советов жителей Города Мастеров (не буду перечислять имена, так как они и сами знают, кто мне помогал, но если я кого-то забуду, будет не очень-то честно). Тогда я еще учился. Теперь же, когда я многое знаю по скриптописанию, то могу переписать этот скрипт вот так. Уловите разницу:
void main()
{
   //-----------objects---------------------------
   object oPC=GetEnteringObject();
   object oWp=GetWaypointByTag("Wp1");
   //-----------effects---------------------------
   effect oEf=EffectVisualEffect(VFX_IMP_UNSUMMON,FALSE);
   //-----------script----------------------------
   if (GetLocalInt(oPC,"ZedInt")==TRUE)
   {
   ActionDoCommand(SetCutsceneMode(oPC));
   ActionDoCommand(AssignCommand(oPC,SetCameraFacing(280.0, 8.5, 65.0, CAMERA_TRANSITION_TYPE_SLOW)));
   ActionWait(3.5);
   ActionDoCommand(ApplyEffectToObject( DURATION_TYPE_PERMANENT,oEf, oPC));
   ActionWait(3.0);
   ActionDoCommand(SetCutsceneMode(oPC,FALSE));
   ActionDoCommand(AssignCommand(oPC,ActionJumpToLocation(GetLocation(oWp))));
   }
   return;
}
Вместо того, чтобы щепетильно высчитывать место векторами и локациями, я просто поставил туда точку с тегом “Wp1”. Теперь две строки не нужны. А если заменить ActionDoComman DelayCommand, то угадайте сколько строчек можно будет убрать? Вот вам задание, запишите этот скрипт через временную ф-ю. Ниже и предлагаю свой вариант. Можете подглядеть в него сразу, а можете проверить свои силы без моей помощи. Это на ваше усмотрение.
void main()
{
   //-----------objects---------------------------
   object oPC=GetEnteringObject();
   object oWp=GetWaypointByTag("Wp1");
   //-----------effects---------------------------
   effect oEf=EffectVisualEffect(VFX_IMP_UNSUMMON);
   //-----------script----------------------------
   if (GetLocalInt(oPC,"ZedInt")==TRUE)
   {
   DelayCommand(0.1,SetCutsceneMode(oPC));
   DelayCommand(0.2,AssignCommand(oPC,SetCameraFacing(280.0, 8.5, 65.0, CAMERA_TRANSITION_TYPE_SLOW)));
   DelayCommand(3.7,ApplyEffectToObject( DURATION_TYPE_PERMANENT,oEf, oPC));
   DelayCommand(6.7,SetCutsceneMode(oPC,FALSE));
   DelayCommand(6.8,AssignCommand(oPC,ActionJumpToLocation(GetLocation(oWp))));
   }
   return;
}
Надеюсь, мне удалось заронить в ваши умы искорки понимания. Если же нет, то советую вам почитать другое статьи, пообщаться со знающими людьми и, наконец, много раз пытаться самому. Когда я осваивал этот язык, я иногда часами мучился с одним маленьким скриптом, но какова была моя радость, когда мне самому удавалось понять, в чем ошибка. Конечно, поначалу ваши скрипты могут выглядеть не так уж и красиво, но это не важно. Гибкость придет со временем, а пока главное, чтобы скрипты работали. Желаю дальнейших успехов. Читайте другие мои статьи из этой серии. 
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Friedrich
сообщение Mar 26 2005, 02:31
Сообщение #11


Level 5
**

Класс: Рейнджер
Характер: Neutral Good
Раса: Человек



QUOTE (MasterMage @ Mar 25 2005, 22:21)
подателей сюжет

Может быть, подателей (чего?) сюжета.
QUOTE (MasterMage @ Mar 25 2005, 22:21)
Обязательно вооружитесь статьей с полным описанием всех функции на русском языке. Или на крайний случай воспользуйтесь Lexicon’ом.
Я бы сказал наоборот, "Обязательно вооружитесь лексиконом, или, на крайний случай воспользуйтесь статьей с описанием всех функций на русском". :lol:
QUOTE (MasterMage @ Mar 25 2005, 22:21)
void main() – это сама функция. Они бываю разные по своему назначению, но этот является универсальным, по умолчанию.
Молодой человек, что у вас какой язык родной? Уж куда я не грамотный, но в родах падежах, обычно не путаюсь.

main() { ... }

определяет функцию, названную main. Каждая программа должна
содержать функцию с именем main, и работа программы начинается с
выполнения этой функции.
Бьярн Страустрап, Введение в язык Си++

Заменить слово "программа", на слово "скрипт" (или "сценарий") и будет то, что надо... :P

QUOTE (MasterMage @ Mar 25 2005, 22:21)
После каждой функции обязательно(!) ставьте;, иначе строка не скомпилируется. Дело в том, что компилятор воспринимает этот знак, как конец функции, и начинает считывание следующей.

';' нужно ставить не после каждой функции, а после каждого выражения.
if (!GetIsObjectValid(oPC)) return;
После функции GetIsObjectValid ты ведь не ставишь ';'.

Продолжать не буду.
Добавлено в 02:34
Надо еще сказать, что вместо main скрипт может содержать функцию StartingConditional.

Сообщение отредактировал Friedrich - Mar 26 2005, 02:36
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Lex
сообщение Mar 26 2005, 03:02
Сообщение #12


Level 5
Иконки Групп

Класс: Обыватель
Характер: Lawful Neutral
Раса: Человек
NWN: Модмейкер
Проклятие Левора
Порядок Времени



QUOTE (Friedrich @ Mar 26 2005, 02:31)
Продолжать не буду.

а чего так?
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Friedrich
сообщение Mar 26 2005, 05:21
Сообщение #13


Level 5
**

Класс: Рейнджер
Характер: Neutral Good
Раса: Человек



QUOTE (Lex @ Mar 26 2005, 03:02)
а чего так?

Боюсь ЭТО может тяжело сказаться на моем рассудке... :crazy:

Однако, вдохновленный МастерМагом, решил описать все типы данных NWScript'a. Пока успел это:

Типы данных
Типы данных – это различные типы переменных, которые могут использоваться для хранения определенных значений. Так, например, строковый тип (string) используется для хранения текстовых данных, тогда как переменная целочисленного типа (int) может хранить любое число без десятичной точки. Различные типы данных используются различным образом.
Типы данных
action (действие)
Тип action используется как параметр в описаниях встроенных (engine-defined) функций DelayCommand(float, action) , AssignCommand(object, action) и ActionDoCommand(action). В качестве фактического значения параметра action может выступать только не возвращающая значение (void) функция. Проводя аналогию с C/C++, можно сказать, что action – это тип-указатель на функцию. Однако вы не можете определять переменные этого типа или свои функции с параметрами action.

Пример:
Neverwinter Script Source
void fn() {…}
action aFn = fn(); // Не будет компилироваться!

void main()

  DelayCommand(5.0f, fn()); // Правильное использование
}


command
Что бы вам не писали в «Лексиконе», в NWScript нет такого типа и Слово "command" не является ключевым.

effect (эффект)
Этот тип определяет какой-либо визуальный эффект или какое-либо воздействие (н.п. нанесение повреждения, наложение невидимости и т.д.), применяемое к объекту или локации (location /см./, не путать с area). Каждый эффект должен быть создан с помощью конструктора – специальной функции, создающей эффект определенного типа. После чего эффект накладывается на объект или локацию с помощью функций ApplyEffectToObject() или ApplyEffectAtLocation().
Замечания:
Фактически переменная типа effect в своем внутреннем представлении является структурой, содержащей, как минимум, следующие поля, значения которых могут быть получены с помощью соответствующих функций (синтаксис С++ использован мною исключительно для наглядности. Это не фрагмент какого-либо кода, а просто условность):
CODE

class effect {
int nEffectType;  // тип эффекта, константа EFFECT_TYPE_*
int nEffectSubtype;  // подтип эффекта, константа SUBTYPE_*
int nEffectDurationType; // константа DURATION_TYPE_*
int nEffectSpellID;  // ID заклинания (константа SPELL_*),
// в скрипте которого создан эффект или -1
object oEffectCreator; // указатель на объект, вызвавший скрипт,
// в котором был создан данный эффект
// ...
};


Пример:
Neverwinter Script Source
effect eConPenalty = EffectAbilityDecrease(ABILITY_CONSTITUTION, 1); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eConPenalty, oTargetPC);


event (событие)
Каждое событие, вызывающее скрипт, по идее, должно иметь свою собственную функцию создания «эвента», который вы можете послать любому объекту. В действительности же, в NWScript реализовано лишь четыре такие функции:
EventActivateItem()
EventConversation()
EventSpellCastAt()
EventUserDefined()
Последняя из них используется наиболее часто.

О внутреннем представлении этого типа можно только догадываться :)

Пример:
Neverwinter Script Source
object oNPC;
//…
event evSpecialEvent = EventUserDefined(1234);
SignalEvent(oNPC,evSpecialEvent);


float (число с плавающей точкой)
Тип float служит для представления вещественных чисел и представляет собой 32-битное число с плавающей точкой.
Минимальное значение: -3.402823e38
Максимальное значение: 3.402823e38 (3,4… умножить на 10 в 38-й степени)
По умолчанию: 0.0
Определяя константу вещественного типа вы должны обязательно поставить десятичную точку и, как минимум, одну цифру после нее, а также букву ‘f’ в нижнем регистре.

Пример:
Neverwinter Script Source
const float e = 1.271728f;


int (целое)
Целочисленный (integer) тип. Знаковое 32-битное целое. Допустимый диапазон значений:
От -2,147,483,648 (-0x80000000) до 2,147,483,647 (0x7FFFFFFF).
По умолчанию: 0

Продолжение следует…
А теперь, баиньки. :sleep:
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
MasterMage
сообщение Mar 26 2005, 10:45
Сообщение #14


Level 8
***

Класс: Маг
Характер: Lawful Good
Раса: Полуэльф



QUOTE (Friedrich @ Mar 26 2005, 02:31)
Молодой человек, что у вас какой язык родной? Уж куда я не грамотный, но в родах падежах, обычно не путаюсь.

main() { ... }

определяет функцию, названную main. Каждая программа должна
содержать функцию с именем main, и работа программы начинается с
выполнения этой функции.
Бьярн Страустрап, Введение в язык Си++
Заменить слово "программа", на слово "скрипт" (или "сценарий") и будет то, что надо...
не смешно, смысла не понял, смеяться не буду, жду
QUOTE (Friedrich @ Mar 26 2005, 02:31)
Надо еще сказать, что вместо main скрипт может содержать функцию StartingConditional.
знаю, но не написал, сеньки, допишу... Ты программер? Заметно... Это ж хорошо! Я все запомню и пропишу в статье... :BRAVO:
ЗЫ... Русский у меня отлично :this:
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Friedrich
сообщение Mar 26 2005, 12:20
Сообщение #15


Level 5
**

Класс: Рейнджер
Характер: Neutral Good
Раса: Человек



void main() – это сама функция. Они бываю (я бываю, они - бывают) разные по своему назначению, но этот (кто этот? функция?) является универсальным, по умолчанию.

Перечитывай что написал. Раньше у тебя было написано, что void main() - сам скрипт, тебе сказали, что это не скрипт - а функция. Ты просто заменил слово "скрипт" на "функция". В результате получилось черти чего (как с т.з. грамматики, так и по смыслу) и складывается впечатление, что у тебя с русским совсем не лады.

Далее я просто привел цитату из умной книжки, где объясняется, что такое main().
Соответственно, тебе надо написать, что вроде того, что
void main() - это главная функция скрипта. Слово void (англ. - пустой, не действительный) означает, что эта функция не возвращает какого-либо значения. main - имя функции. Каждая сценарий должен содержаить главную функцию. В обычных сценариях - это void main() в сценариях управления диалогом - int StartingConditional(), но это уже особый разговор. Выполнение любого сценария начинается именно с главной функции, и уже из нее вызываются все остальные функции.

Тоже, не блестяще, но надеюсь правильно и менее-более понятно. :D

QUOTE (MasterMage @ Mar 26 2005, 10:45)
Ты программер? Заметно...

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

QUOTE (MasterMage @ Mar 26 2005, 10:45)
ЗЫ... Русский у меня отлично 

А у меня 3 было.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Lex
сообщение Sep 13 2005, 16:14
Сообщение #16


Level 5
Иконки Групп

Класс: Обыватель
Характер: Lawful Neutral
Раса: Человек
NWN: Модмейкер
Проклятие Левора
Порядок Времени



поднял тему... может продолжим?
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
_kaa_
сообщение Sep 13 2005, 16:22
Сообщение #17


Level 9
Иконки Групп

Класс: Волшебник
Характер: Chaotic Good
Раса: Дракон
NWN: Скриптинг [PW]



Ага, удали все кроме самой статьи :)

p.s. с выходом НВН2 обещают, что скрипты изменятся меньше всего и даже будут совместимы. Так что учим матчасть :drag:

Сообщение отредактировал _kaa_ - Sep 13 2005, 16:23
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Lex
сообщение Sep 13 2005, 16:38
Сообщение #18


Level 5
Иконки Групп

Класс: Обыватель
Характер: Lawful Neutral
Раса: Человек
NWN: Модмейкер
Проклятие Левора
Порядок Времени



ты ее внимательно почитай.... мы ее тут правили.. когда-то.. собсна МастерМаг, ты как, продолжишь? или может кто за него?
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
_kaa_
сообщение Sep 13 2005, 16:46
Сообщение #19


Level 9
Иконки Групп

Класс: Волшебник
Характер: Chaotic Good
Раса: Дракон
NWN: Скриптинг [PW]



Для мануала сойдет перевод "первые 10 шагов", взятых с сайта биоварей. лично мне этого вполне хватило чтобы начать, правда я немного английский читаю :)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
2_advanced
сообщение Sep 13 2005, 17:27
Сообщение #20


Level 9
Иконки Групп

Класс: Вор
Характер: True Neutral
Раса: Эльф
NWN: Скриптинг [PW]



XShock (раурин тим) мутил хрень с заменой НВНовских скриптов чисто кодом на С++/С## :)
т.е. функции, доступные для скриптинга + мощи С :)
потом на это дело забили т.к. нет времени ни у кого..
биовары могли бы сделать что-то типа поддержки плагинов
им уже об этом писали =) но не доходят мольбы каких-то рашн-мод-девелоперов :swoon:

ждем НВН2, а потом матчасть уже учим.. точнее переучиваем =) как с С на С++ :crazy:

Сообщение отредактировал 2_advanced - Sep 13 2005, 17:28
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
dumbo
сообщение Sep 14 2005, 08:35
Сообщение #21


Level 9
Иконки Групп

Класс: Фея
Характер: Chaotic Evil
Раса: Тварь
NWN: Скриптинг [PW]



QUOTE (2_advanced @ Sep 13 2005, 18:27)
XShock (раурин тим) мутил хрень с заменой НВНовских скриптов чисто кодом на С++/С##
т.е. функции, доступные для скриптинга + мощи С
потом на это дело забили т.к. нет времени ни у кого..

отмазка про время здесь не канает, ибо идея бредовая изначально.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
2_advanced
сообщение Sep 17 2005, 14:10
Сообщение #22


Level 9
Иконки Групп

Класс: Вор
Характер: True Neutral
Раса: Эльф
NWN: Скриптинг [PW]



ответ напоминает этот :)
НВНХ тоже бред? а всякие SetName/SetDescription в nwnx_functions?
почему переделка НВНовской ВМ в АСМ бред?
разница в загрузке проца / времени выполнения на порядок будет отличаться :drag:
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
dumbo
сообщение Sep 19 2005, 08:55
Сообщение #23


Level 9
Иконки Групп

Класс: Фея
Характер: Chaotic Evil
Раса: Тварь
NWN: Скриптинг [PW]



QUOTE (2_advanced @ Sep 17 2005, 15:10)
ответ напоминает этот

ничего общего, ибо про возможность/невозможность я и не говорил.
QUOTE (2_advanced @ Sep 17 2005, 15:10)
НВНХ тоже бред? а всякие SetName/SetDescription в nwnx_functions? почему переделка НВНовской ВМ в АСМ бред?

во-первых, асм - это не совсем(совсем не) C++/C#(о применимости # вообще промолчу, пожалуй). почему бред? - по пунктам:
1. время, потраченное на исследование работы скриптовой системы в объеме, достаточном для ее(системы) изменения, можно сразу оценить как "долго".
2. если речь идет не о замене пары-тройки скриптов, то нужно, как минимум, делать свой линкер, причем, мягко говоря, не совсем обычный. время на разработку - "долго".
3. по-хорошему надо менять тулсет. иначе юзабилити стремится к 0.
4. утрачивается независимость от платформы. в каждом отдельном случае нужно компилить/линковать, причем для каждой платформы должны быть разработаны свои линкеры.
5. если разобрать все это по мелочам, то получится, что нужно еще немножко "долго".

в итоге: времени нужно "очень долго", непереносимость, удобство - 0(да и вообще, использовать сие скорее всего смогут очень немногие). бред.

ps. это вам не серваки кривыми пакетами ронять... ;)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Alina
сообщение Sep 21 2005, 00:18
Сообщение #24


AERIE team Leader
*

Класс: Фея
Характер: Chaotic Good
Раса: Фея



Вы меня извините, я собственно по тексту статьи хочу высказаться... ;)

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

edit - сорри, только сейчас заметила - я думала, что статья правилась по ходу поступления замечаний, но вижу, что, похоже, нет. Поэтому, возможно, мои замечания и не имеют смысла. :)

QUOTE

Object – это тип задаваемого объекта. Он всегда пишется с маленькой буквы и выделяется синим цветом, если вы правильно его написали.

По формулировке: лучше было бы, имхо, не "Он ...пишется" (не сразу понятно, кто ОН - объект или тип), а "Название типа объекта... "

QUOTE

Таких типов существует несколько: effect – это эффект, который будет накладываться на какой-то объект, живой или нет; object – размещаемый объект (персонаж, сундук, точка, дверь, – все, что имеет тег и материально); string – это какая-то фраза, либо тег объекта (адрес, задаваемый вами в свойствах); int – какое-то целое число или же константа, используемая в скрипте. Есть еще несколько типов, но они не так важны как эти (location – локация, местность; vector – вектор, float – дробное число (с плавающей точкой)). Они используются редко и в специальных скриптах, сложность которых вам пока не под силу…

есть предложение по форматированию: выровнять названия типов переменных друг под другом - удобнее будет читать.

QUOTE

В данном случае представлена функция (кстати, они пишутся слитно и каждое слово с заглавной буквы!),

Опять по формулировке - лучше будет "названия функций не содержат пробелов".

QUOTE

После каждой функции обязательно(!) ставьте ( ; ), иначе строка не скомпилируется. Дело в том, что компилятор воспринимает этот знак, как конец функции, и начинает считывание следующей.

Спорная формулировка (ну и смайлик некстати затесался...).
Не после каждой функции, а в конце каждой строки, кроме строк, начинающихся с if и прочих управляющих конструкций, а также фигурных скобок. Возможно, слишком запутанно это я написала... :crazy:
Ну и далее - компилятор воспринимает этот знак не как конец ФУНКЦИИ, а как конец строки. Конец функции - это "}" ;)

Дальше (пока что!) не прочитала.

Сообщение отредактировал Alina - Sep 21 2005, 00:24
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Aiwan
сообщение Sep 23 2005, 07:03
Сообщение #25


Миловидный Бегрюссунг
Иконки Групп

Класс: Воин
Характер: Chaotic Good
Раса: Человек
NWN: Модмейкер
Проклятие Левора
Порядок Времени



QUOTE (Alina @ Sep 21 2005, 03:18)
Я только начала читать статью - сразу хочется внести несколько замечаний и предложений.  Надеюсь, вы не сочтете это наглостью - в тулсете я новичок, но программирую уже довольно давно.

Очень будем рады. :D
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 19th April 2024 - 09:56