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

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

 Правила этого форума ПРАВИЛА РАЗДЕЛА
9 страниц V   1 2 3 > »   
Ответить в эту темуОткрыть новую тему
> ПОСТРОЕНИЕ СКРИПТОВЫХ СЦЕН, Основы написания Cutscene
Aiwan
сообщение May 9 2004, 14:27
Сообщение #1


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

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



Здравствуйте, мы продолжаем знакомство с основами работы в BioWare Aurora Neverwinter Nights Toolset. В этот раз мы разберем изготовление скриптовых сценок на движке игры.

ВСТУПЛЕНИЕ
Давайте немного поговорим о том, как работают скриптовые команды. Это важно в том аспекте, что для успешного построения сценки, необходимо понимать то, что вы делаете и видеть в строках кода все примерные движения объектов и события. Звучит несколько странно, похоже на фильм “Матрица” где, глядя на экран мониторов, их герои видели код и понимали то, что он представляет, вместо ползущих цифр по экрану. Но построить сценку, не понимая что происходит, а только наугад невозможно.
В скриптовых роликах основная задача вас, как режиссера, поставить все команды, из которых состоит ваш ролик в строгую последовательность, и задать жесткие временные рамки их исполнения. Больше всего времени при построении скриптовых сцен уходит на доводку исполнения той или иной команды в секундах и долях секунды. Поэтому изготовлять сам скрипт и тестить его, я рекомендую в отдельном, модуле. Так вот, что бы понять, как объект запоминает ту или иную команду, просто представьте, что у него есть специальный стек, в котором помещаются в очереди 75 команд. Цифра 75 критичный предел, больше NPC не запомнит за один раз. Для того, что бы построить сценку с командами, превышающими эту цифру, надо писать скрипт с задержкой исполнения команд. Но об этом чуть позже. Ну что, начнем?

ФУНКЦИИ
Наверняка вы уже смотрели в редакторе скриптов огромный список функций. Разберем основное различие между ActionSpeakString и SpeakString. Я специально выбрал эти две функции, которые выполняют одну и ту же задачу, только разными путями. На этом примере вы поймете, в чем их функциональное отличие. Например, у нас задача подойти к объекту и во время движения произнести фразу:

Пример 1.
ActionMoveToObject(oWp);
ActionSpeakString(“Произнесенная фраза”);

Наш объект, получив такую задачу, выполнит две команды по очереди. Эти команды будут загружены в его стек-команд в той последовательности, что вы видите. На деле мы получим вид: объект подошел, произнес фразу. А если нам надо во время пути, произнести фразу? Тогда мы воспользуемся функцией типа void():

Пример 2.
ActionMoveToObject(oWp);
ActionWait (3.0);
SpeakString(“Произнесенная фраза”);

Теперь наш объект, направляясь в точку oWp, во время следования (если она далеко) через три секунды произнесет фразу. Но не все функции имеют два вида, поэтому существует способ ставить команды типа void() в стек команд:

Пример 3.
ActionMoveToObject(oWp);
ActionDoCommand(SpeakString(“Произнесенная фраза”));

В итоге получаем, что пример один равен по функциональности примеру три.

ПРОСТЫЕ СЦЕНКИ
Я классифицировал сцены по сложности. Это не значит, что они в реальности существуют в таком виде, просто нам так будет легче разобраться. Вот код скрипта полностью (смотри модуль).
Neverwinter Script Source
//::///////////////////////////////////////////////
//:: Copyright © 2004 WRG!
//:://////////////////////////////////////////////
/*
           СЦЕНА №1
*/

//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 30.07.2004
//:://////////////////////////////////////////////
void main()
{
object oPC = GetEnteringObject();  // Берем того, кто наступил на триггер
object oDoor = GetObjectByTag("AM_DOOR_START"); // Наша дверь
object oNPC = GetObjectByTag("NPC_01"); // НПС в закрытой локации
object oWPpc = GetWaypointByTag("WP_PC_01"); // Точка, куда подойдет игрок

// Проверим: Если тот, кто наступил на триггер не игрок ИЛИ на триггере есть
// переменн. TRIGGER, то скрипту последует команда "return", т.е. ВОЗВРАТ
if (!GetIsPC(oPC) || GetLocalInt(OBJECT_SELF, "TRIGGER") == 1)
    return;
   {
   SetLocalInt(OBJECT_SELF, "TRIGGER", 1); // Сценка уже произошла
   SetCutsceneMode(oPC); // Переведем РС в режим Cutscene
   AssignCommand(oNPC, ClearAllActions()); // Почистим все Action_ у НПС
   AssignCommand(oPC, ClearAllActions()); // Почистим все Action_ у РС
/*
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  Все команды ниже, это последовательные команды ТРИГГЕРУ, что бы он "ЗАПОМНИЛ" и "РАЗАДAЛ"
  задачи по адресам (Игроку, НПС и т.д.) в нужный момент времени. Количество этих команд не должно
  превышать цифру 75 - это максимальное количество запоминаемых действий одного объекта.
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*/

   ActionDoCommand(AssignCommand(oPC, ActionMoveToObject(oWPpc))); // Игрока отправим нужную точку
   ActionDoCommand(AssignCommand(oPC, SetFacingPoint(GetPosition(oDoor)))); // Повернем лицом к двери
   ActionDoCommand(AssignCommand(oPC, SetCameraFacing(280.0, 20.0, 45.0, CAMERA_TRANSITION_TYPE_MEDIUM)));
   // Установим камеру в том положение, что нам надо
   ActionWait(5.5); // Сделаем паузу
   ActionDoCommand(AssignCommand(oNPC, ActionJumpToObject(oDoor))); // Отправим НПС к нам
   ActionDoCommand(AssignCommand(oNPC, SetFacingPoint(GetPosition(oPC)))); // Повернем его в нашу сторону
   ActionWait(2.0);
   ActionDoCommand(AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_FIREFORGET_SALUTE, 1.0, 3.0)));
   // Заставим проиграть анимацию САЛЮТ. Он нам помашет рукой
   ActionDoCommand(AssignCommand(oNPC, PlayVoiceChat(VOICE_CHAT_HELLO))); // Проиграет звук привета
   ActionDoCommand(AssignCommand(oNPC, SpeakString("Привет!"))); // Произнесет фразу
   ActionDoCommand(AssignCommand(oPC, SetCameraFacing(280.0, 7.0, 45.0, CAMERA_TRANSITION_TYPE_SLOW)));
   //Изменим положение камеры
   ActionWait(3.5);
   ActionDoCommand(AssignCommand(oNPC, ActionMoveToObject(oPC))); // Отправим НПС к игроку
   ActionDoCommand(AssignCommand(oNPC, ActionDoCommand(SetCutsceneMode(oPC, FALSE))));
   // Убираем режим сцен у игрока
   ActionDoCommand(AssignCommand(oNPC, ActionStartConversation(oPC))); // НПС начинает разговор с игроком
   }
}


Этот скрипт обязательно ставится на триггер, или на вход в локацию и т.д. И все действия поставлены в строгую очередь на стеке этого объекта, в данном случае триггера. Убедительно прошу не ставить скрипты роликов на OnEnter стартовой локации при начале модуля! Если у вас большая необходимость в этом, то просто напишите задержку на несколько секунд для выполнения вашей скриптовой сценки. Дело в том, что при старте модуля движок игры выполняет внутренние команды необходимые для старта и ваш скрипт пройдет при неуправляемой камере, которая упрется в пол или еще куда.

Вернемся к нашему скрипту. Вы заметили, что с точки зрения программирования я его написал неверно? Точнее он перегружен лишними функциями. Это верно, но я хочу, что бы вы поняли, почему я это сделал.
ActionDoCommand() в нашем случае, ставит все остальные команды в очередь стека триггера. В противном случае, все наши команды мгновенно ушли бы по адресам: игроку, NPC, и они выполнили все это в той последовательности что получили. Но мы сделали так, что триггер запомнил все нужные действия для каждого объекта у себя и просто раздал их каждому в нужный момент. Этим мы освободили себя от ненужного отслеживания выполнения команд каждым участником сценки. Попросту, мы сделали триггер нашим командиром. И в этом случае, выполнение команд можно просто отделить друг от друга командой ActionWait() для триггера.

Я советую не уничтожать вам этот триггер в конце, как делают многие, так как он может уничтожиться раньше завершения акций и ваш ролик не успеет завершиться. Советую NPC при таких сценках уже готового из синьки ставить в закрытую локацию, специально изготовленную для таких нужд. Дело в том, что при одиночной игре при команде CreateObject() компьютер ваш будет немного тормозить. Это связано с тем, что в случае одиночной игры он и сервер и клиент одновременно. Поэтому на вашей супер тачке Р-IV 3000 и мозгами 1 Гб может виден слегка заметное подергивание. И чем больше вы создаете объектов, тем больше тормозов. Для шардов это не актуально, у них клиент и сервер на разных машинах.

Разберем некоторые части скрипта подробно.

Neverwinter Script Source
if (!GetIsPC(oPC) || GetLocalInt(OBJECT_SELF, "TRIGGER") == 1)
  return;

Этот строчка не даст запускаться скрипту если на триггер наступил не РС или скрипт уже один раз сработал.

SetCutsceneMode(oPC); Переводит РС в режим сцены, убирает панель и делает его недоступным для управления игроком.

Neverwinter Script Source
ActionDoCommand(AssignCommand(oPC, SetFacingPoint(GetPosition(oDoor))));

Эта строчка поворачивает оРС в сторону, в данном случае лицом на дверь из которой появится NPC.

Команда SetCameraFacing() установит камеру в то положение, которое вам нужно для комфортного просмотра вашей сценки. Я разберу на примере параметров нашего скрипта:

CAMERA_TRANSITION_TYPE_SNAP немедленно переместит камеру на новую позицию, тогда как другие типы, перемещают постепенно в позицию.
CAMERA_TRANSITION_TYPE_MEDIUM - переместит камеру в то положение, которое мы укажем из исходного.
250.0 - градусы относительно оси.
(0.0f=East, 90.0f=North, 180.0f=West, 270.0f=South) начертите на бумаге схему с градусами и сторонами света, вам будет удобнее ориентироваться.
20.0 удаление от игрока. (Мин 5 мах 20)
45.0 наклон (1 - вертикально, 50.0 мах почти в горизонт)

Neverwinter Script Source
ActionDoCommand(AssignCommand(oCaet, PlayVoiceChat(VOICE_CHAT_HELLO)));

Это наша дама выкрикнет приветствие. Запомните, что это будет действовать, только если установлен звук у NPC с такой возможностью. Этого звука нет у монстров и прочих неважных NPC. Такие звуки есть у стандартных комплексов звуков РС или хеньчманов. Так что если вы примените PlayVoiceChat() и у вас не будет звука в скрипте, просто смените у NPC набор звуков в свойствах. Но стоит знать одну особенность стандартных скриптов от BioWare. Если вы пользуетесь PlayVoiceChat(), то параллельно звуку будет SpeakString() фразы из скриптов по умолчанию. Что бы не появлялись английские фразы в сценке надо поставить следом за функцией PlayVoiceChat() строку с какой-нибудь фразой из сценки, причем время срабатывания должно быть одно и то же, и лишь порядок функций должен быть такой: звук и сразу фраза. Мы просто накладываем одну строку сразу на другую, скрывая иностранные буквы и фразы.

Neverwinter Script Source
ActionDoCommand(AssignCommand(oCaet, ActionDoCommand(SetCutsceneMode(oPC, FALSE))));


Снимает режим скриптовых сцен у РС.

Сделайте одну две НЕЙТРАЛЬНУЮ КО ВСЕМ фракцию, специально для SetCutsceneMod(). Дело в том, что врагов РС трудно будет заставить не убивать вас, а если у него будет нейтральная фракция, то можно ее сменить прямо в скрипте с одной на другую. Но об этом позже.

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


СЛОЖНЫЕ СЦЕНКИ
В понятие “Сложные”, я вкладываю управление игроком при перемещении, обработку помощников и использование команд больше чем может вместить стек одного объекта. К тому же вам, наверное, хотелось бы переместить камеру и показать с разных ракурсов одну и ту же сцену. Спешу сразу вас разочаровать, “Aurora Engine” не позволяет отрывать камеру от игрока, но это не повод для того, что бы ни пользоваться перемещением камеры. Реализуется это следующим образом: делаем затухание экрана, на игрока накладываем невидимость, перемещаем его в нужную точку с нужным ракурсом, убираем затухание, пошла сценка.


Neverwinter Script Source
//::///////////////////////////////////////////////
//:: Copyright © 2004 WRG!
//:://////////////////////////////////////////////
/*
           СЦЕНА №2
*/

//:://////////////////////////////////////////////
//:: Created By: Aiwan
//:: Created On: 7.08.2004
//:://////////////////////////////////////////////

void main()
{
object oPC = GetPCSpeaker(); // Это наш любимый персонаж =)
object oNPC = GetObjectByTag("NPC_02"); // Подлый воришка!
object oDoor = GetNearestObjectByTag("AM_DOOR_START"); // Дверь, нужна как ориентир (IMG:style_emoticons/kolobok_light/wink3.gif)
object oLuk = GetNearestObjectByTag("AM_LUK"); // Секретный люк в полу
object oSec = OBJECT_SELF; // Это наш собеседник
object oWPpc = GetWaypointByTag("WP_PC_02"); // Точка, куда "прыгает" игрок в первый раз второй
object oWPpc2 = GetWaypointByTag("WP_PC_03"); // Точка, куда  "прыгает" игрок во второй раз
object oWP1 = GetWaypointByTag("WP_SC02_01"); // Точки вора
object oWP2 = GetWaypointByTag("WP_SC02_02");
object oWP3 = GetWaypointByTag("WP_SC02_03");
object oWP4 = GetWaypointByTag("WP_SC02_04");
object oWP5 = GetWaypointByTag("WP_SC02_05");
//::::::::::::::::::::::: ПОМОЩНИКИ ИГРОКА. Определим ::::::::::::::::::::::::::
object oAnimal = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC);
object oDominated = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC);
object oFamiliar = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC);
object oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC);
object oSummoned = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC);
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
effect eCutInv = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY); // Невидимость в сценке
effect eCutPar = EffectCutsceneParalyze(); // Неподвижность нашим спутникам (чтоб чего не выкинули...)
    {
    SetLocalInt(oPC, "CUT_SCEN_02", TRUE); // Сценка была (проверка в диалоге)
    SetLocalLocation(oPC,"START_POINT", GetLocation(oPC)); // Заппомним КООРДИНАТЫ Игрока
    AssignCommand(oSec, ActionPauseConversation()); // Сделаем паузу в диалоге с НПС
    AssignCommand(oNPC, ClearAllActions());  // Почистим все Action_ у НПС
    AssignCommand(oNPC, ActionJumpToObject(oWP1)); // Отправим НПС к нам
    AssignCommand(oNPC, ActionDoCommand(SetFacingPoint(GetPosition(oDoor))));
    // Повернем НПС в сторону двери, т.е. к нам лицом
    FadeToBlack(oPC, FADE_SPEED_FASTEST); // Занавес из черного экрана (ОЧЕНЬ быстро)
    AssignCommand(oPC, ClearAllActions()); // Почистим все Action_ у РС
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oPC, 41.0); // Делаем игрока невидимым
    SetCutsceneMode(oPC);  // Переведем РС в режим Cutscene
    SetAILevel(oNPC, AI_LEVEL_HIGH);
    // Изменим AI у нашего вора ВЫСОКИМ, так он лучше будет соображать =)
//:::::::::::::  ОБРАБОТКА ФАМИЛЬЯРОВ - Нивидимость и неподвижность  :::::::::::
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oAnimal, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oAnimal, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oHenchman, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oHenchman, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oDominated, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oDominated, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oFamiliar, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oFamiliar, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oSummoned, 40.5);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oSummoned, 40.5);
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    DelayCommand(1.0, AssignCommand(oPC, JumpToObject(oWPpc))); // Отправим Игрока в нужную точку
    DelayCommand(1.5, AssignCommand(oPC, SetCameraFacing(10.0, 12.0, 40.0, CAMERA_TRANSITION_TYPE_SNAP)));
    // Камеру поставим в нужный ракурс
    DelayCommand(2.0, FadeFromBlack(oPC, FADE_SPEED_MEDIUM)); // Уберем занавес из черного экрана (МЕДЛЕННО)
    DelayCommand(2.5, AssignCommand(oPC, ClearAllActions()));
    DelayCommand(3.0, AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR, 0.9, 5.0)));
    // Наш вор смотрит в даль...
    DelayCommand(3.5, AssignCommand(oPC, SetCameraFacing(10.0, 20.0, 40.0, CAMERA_TRANSITION_TYPE_SLOW)));
    // Повернем ракурс камеры
    DelayCommand(4.0, AssignCommand(oNPC, SpeakString("Сваливать пора..."))); // Воришка сдрейфил =)
    DelayCommand(5.0, AssignCommand(oNPC, ActionMoveToObject(oWP2))); // Пошел в точку 2
    DelayCommand(7.0, AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_GET_MID, 0.9, 3.0)));
    // Полез открывать замок и шарить руками
    DelayCommand(8.0, AssignCommand(oNPC, SpeakString("Еще пару вещичек..."))); // Жадность фраера сгубила =)
    DelayCommand(9.5, AssignCommand(oNPC, ActionForceMoveToObject(oWP3, TRUE, 1.0, 7.0)));
    // Бежит в точку 3
    DelayCommand(10.0, AssignCommand(oNPC, ActionDoCommand(SetFacingPoint(GetPosition(oWP3)))));
    // Повернем его рыльцем в сторону нужную нам (IMG:style_emoticons/kolobok_light/smile.gif)
    DelayCommand(11.0, AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_GET_MID, 0.9, 5.0)));
    // Полез открывать замок и шарить руками

//================== ПЕРЕМЕСТИМ ИГРОКА В ДРУГУЮ ТОЧКУ НЕЗАМЕТНО ================
    DelayCommand(12.0, AssignCommand(oPC, ClearAllActions()));
    DelayCommand(12.5, FadeToBlack(oPC, FADE_SPEED_FASTEST)); // Занавес из черного экрана (ОЧЕНЬ быстро)
    DelayCommand(13.5, AssignCommand(oPC, JumpToObject(oWPpc2)));// Отправим Игрока в точку 2
    DelayCommand(13.6, AssignCommand(oPC, SetCameraFacing(130.0, 20.0, 40.0, CAMERA_TRANSITION_TYPE_SNAP)));
    // Повернем ракурс камеры
    DelayCommand(14.5, FadeFromBlack(oPC, FADE_SPEED_MEDIUM)); // Уберем занавес из черного экрана (МЕДЛЕННО)
//==============================================================================
    DelayCommand(17.0, AssignCommand(oNPC, ActionDoCommand(SetFacingPoint(GetPosition(oDoor)))));
    DelayCommand(19.0, AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR, 0.9, 3.0)));
    DelayCommand(20.0, AssignCommand(oNPC, SpeakString("Понабежало разных зевак. Уроды...")));
    DelayCommand(21.0, AssignCommand(oNPC, ActionForceMoveToObject(oWP4, FALSE, 1.0, 15.0)));
    DelayCommand(24.0, AssignCommand(oNPC, ActionDoCommand(SetFacingPoint(GetPosition(oWP5)))));
    DelayCommand(25.0, AssignCommand(oPC, ClearAllActions()));
    DelayCommand(25.6, AssignCommand(oPC, SetCameraFacing(130.0, 10.0, 40.0, CAMERA_TRANSITION_TYPE_SLOW)));
    DelayCommand(25.0, AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 0.9, 3.0)));
    DelayCommand(30.0, AssignCommand(oLuk, ActionPlayAnimation(ANIMATION_PLACEABLE_OPEN, 1.0)));
    // Даем команду люку открыть крышку
    DelayCommand(33.5, AssignCommand(oNPC, ClearAllActions()));
    DelayCommand(30.0, AssignCommand(oNPC, ActionMoveToObject(oWP5))); // Говорим НПС стать в люк
    DelayCommand(36.5, AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 3.0, 1.0)));
    DelayCommand(37.5, AssignCommand(oNPC, ClearAllActions()));
    DelayCommand(37.8, AssignCommand(oNPC, ActionDoCommand(DestroyObject(oNPC)))); // Говорим НПС убить СЕБЯ (IMG:style_emoticons/kolobok_light/wink3.gif)
    DelayCommand(38.5, AssignCommand(oLuk, ActionPlayAnimation(ANIMATION_PLACEABLE_CLOSE, 2.0)));
//=========================  ВЕРНЕМ ИГРОКА НАЗАД В РАЗГОВОР  ===================
    DelayCommand(39.0, AssignCommand(oPC, ClearAllActions())); // Почистим все Action_ у РС
    DelayCommand(39.5, FadeToBlack(oPC, FADE_SPEED_FASTEST));// Занавес из черного экрана (ОЧЕНЬ быстро)
    DelayCommand(40.5, AssignCommand(oPC, ActionJumpToLocation(GetLocalLocation(oPC,"START_POINT"))));
    // Отправим игрока в ту точку, что мы ЗАПОМНИЛИ в начале скрипта
    DelayCommand(41.5, FadeFromBlack(oPC, FADE_SPEED_MEDIUM)); // Уберем занавес из черного экрана (МЕДЛЕННО)
    DelayCommand(42.5, AssignCommand(oSec, ActionResumeConversation())); // "Продолжаем разговор!" (с) Карлсон
    DelayCommand(43.0, SetCutsceneMode(oPC, FALSE)); // Убираем режим сцен у игрока
    }
}


Основное отличие от кода первого скрипта здесь будет наличие такой функции как DelayCommand(). Эта функция позволяет задержать выполнение той или иной команды на требуемый отрезок времени от начала отчета, которое равно запуску скрипта. Наше построение команд тоже несколько изменится, теперь мы не будем вешать все на один объект, заполняя его стек-команд, соответственно отпала нужда в ActionDoCommand().

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

Теперь я определил спутников игрока, будь то: животное, фамильяр или хеньчман. И для того, что бы наш спутник вел себя адекватно, а вернее не мешал и не болтался под ногами, мы его просто-напросто парализовали специальным эффектом EffectCutsceneParalyze(). Теперь он точно не кинется за нами вдогонку при перемещении камеры и не станет на пути NPC.
Еще один момент. Я несколько усложнил задачу в скрипте и сделал его на диалоге, который переходит в паузу и продолжается с той же строки после прохождения сценки. Для того чтобы мы взяв игрока из точки диалога могли, точно его вернуть назад, воспользуемся этой функцией:
Neverwinter Script Source
SetLocalLocation(oPC,"START_POINT", GetLocation(oPC));
В ней мы запомнили координаты игрока и в конце скрипта вернем его назад в исходную точку.

Еще момент. Если мы хотим что бы игрок участвовал в каком то эпизоде в сценке, но перед этим он был невидим то подбираем для него время при котором он будет скрыт от нас, затем эффект заканчивается, мы его показываем, после опять накладываем эффект невидимости и т.д. Все это естественно с затуханием экрана, или если у вас свои планы то не делайте. Тут выбор за вами.

Neverwinter Script Source
SetAILevel(oNPC, AI_LEVEL_HIGH);
Этой строкой мы сделали AI у нашего NPC высоким, для того, что бы он лучше искал путь до нужного объекта, пользовался разными зельями в общем, что бы не “тупил”. Однако это сильно нагружает систему, ведь по умолчанию стоит AI_LEVEL_DEFAULT. После того, как пройдет сценка, верните этот параметр на место, если вы не уничтожаете NPC.

Neverwinter Script Source
effect eSlow = EffectSlow();
В игре нет возможности заставить игрока идти к цели, а не бежать. Если мы можем отправить NPC пешком, то игрока мы можем заставить идти только при помощи такого эффекта.

Иногда, для того, что бы показать появление NPC, не обязательно его брать из закрытой локации или создавать скриптом. Можно просто поставить его в нужную точку или в укромное место и при запуске скрипта сделать его невидимым несколько секунд и снять эффект когда нужно. Он как бы появился из неоткуда, а сам на самом деле, будет стоять все это время парализованный и невидимый за рядышком. Я этим очень часто пользуюсь, чего советую и вам.

Так как наши участники сценки все с одной или двумя нейтральными фракциями, то изменить в конце нашего ролика фракцию можно командой:
Neverwinter Script Source
ChangeToStandardFaction(oNPC, STANDARD_FACTION_HOSTILE);
Если необходима другая фракция, не стандартная, то это тоже можно сделать
Neverwinter Script Source
ChangeFaction()
(смотрите функции).

ЗАКЛЮЧЕНИЕ
Я хотел написать еще одну сценку, но потом подумал, что вам будет интересней увидеть не бутафорскую, а настоящую сцену. Так вот, я выкладываю вместе с модулем скрипт финальной сцены в модуле “Проклятие Левора – Пламя Флегетоса”. Это третий модуль первой части нашей команды, его можно взять с диска журнала “Навигатор Игрового Мира” за июнь месяц или с нашего сайта www.wrg.ru. Просто сделайте экспорт этого скрипта в модуль и посмотрите, какой объект что делает и как себя ведет. Я сделал необходимые комментарии, поэтому если вы разобрались с первыми двумя скриптами, то этот поймете без проблем. Не гарантирую, что в той версии модуля, которая в журнале, он будет работать как часы, так как я его дорабатывал, но для вас главное будет посмотреть код.
Код скриптов, что я вам привожу, не обременен дополнительными условиями. Например, можно присвоить переменную и при наличии таковой сделать разные фразы или финал сценки. Но все это уже на ваше личное усмотрение. Моя задача научить вас азам.

Neverwinter Script Source
//:://////////////////////////////////////////////
//:: Copyright © 2004 WRG!  www.wrg.ru
//:: am_scen_warr_01
//:://////////////////////////////////////////////
/*
         СЦЕНА ФИНАЛЬНОГО БОЯ С ВОИНОМ ОРДЫ
             ДЕЙСТВИЕ В ЧЕТЫРЕХ АКТАХ
     (СПЕЦИАЛЬНАЯ РЕДАКЦИЯ ДЛЯ ОБУЧАЮЩЕГО МОДУЛЯ)

Комментарии сделаны либо сбоку, либо сразу же под
нужной строкой кода. На отладку этой сценки ушло
времени больше недели.

*/

//:://////////////////////////////////////////////
//:: Created By: Aiwan    Aiwan@e-mail.ru
//:: Created On: 21.02.2004
//:://////////////////////////////////////////////
#include "am_libcutscen"

void main()
{
//================  Буква Я в стрингах (Сделал Lex) ============================
string ya = GetName(GetObjectByTag("YA")); // "+ya+"
//===============================  СОЗДАНИЯ  ===================================

object oPC = GetEnteringObject(); // Игрок
object oDallik = GetNearestObjectByTag("DALLIK_STEADFAST"); // Даллик
object oWord = GetObjectByTag("AM_WARRIOR_HORDE"); // Воин Орды
object oMag = GetObjectByTag("AM_MAG_WARRIOR"); // Маг
object oTrone = GetObjectByTag("AM_TRONE_WARRIOR"); // Трон [creatur_]
object oSlave1 = GetObjectByTag("AM_SKELLETON_SLAVE_01"); // Скелет - Раб 1
object oSlave2 = GetObjectByTag("AM_SKELLETON_SLAVE_02"); // Скелет - Раб 2
object oSlave3 = GetObjectByTag("AM_SKELLETON_SLAVE_03"); // Скелет - Раб 3
object oSlave4 = GetObjectByTag("AM_SKELLETON_SLAVE_04"); // Скелет - Раб 4

//----------------------------- ПОМОЩНИКИ ИГРОКА  ------------------------------

object oAnimal = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC);
object oDominated = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC);
object oFamiliar = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC);
object oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC);
object oSummoned = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC);

//------------------ АРМИЯ ТЬМЫ В ЗАКРЫТОЙ ЛОКАПЦИИ ----------------------------
object oSk1 = GetObjectByTag("AM_SKEL_01"); // Скелет - воин 1
object oSk2 = GetObjectByTag("AM_SKEL_02"); // Скелет - воин 2
object oSk3 = GetObjectByTag("AM_SKEL_03"); // Скелет - воин 3
object oSk4 = GetObjectByTag("AM_SKEL_04"); // Скелет - воин 4
object oSk5 = GetObjectByTag("AM_SKEL_05"); // Скелет - воин 5
object oSk6 = GetObjectByTag("AM_SKEL_06"); // Скелет - маг  6
object oSk7 = GetObjectByTag("AM_SKEL_07"); // Скелет - маг  7
object oSk8 = GetObjectByTag("AM_SKEL_08"); // Скелет - воин 8
object oSk9 = GetObjectByTag("AM_SKEL_09"); // Скелет - клер 9
object oSk10 = GetObjectByTag("AM_SKEL_10"); // Скелет - воин 10
object oSk11 = GetObjectByTag("AM_SKEL_11"); // Скелет - воин 11
object oSk12 = GetObjectByTag("AM_SKEL_12"); // Скелет - клер 12
object oSkBoss = GetObjectByTag("AM_SKEL_BOSS"); // Скелет - Boss

//===============================  ОБЪЕКТЫ  ====================================

object oMlrR = GetObjectByTag("AM_FLEG_MISTLAR_R"); // Мистлар левый
object oMlrL = GetObjectByTag("AM_FLEG_MISTLAR_L"); // Мистлар правый
object oInvis = GetObjectByTag("AM_INVIS_PORTAL"); // Невидимый объект ДЛЯ атаки по нему
object oPlsTrone = GetObjectByTag("AM_PLS_TRON_WARRIOR"); // Трон [pls_]
object oDoor = GetObjectByTag("AM_D_BAATOR_OUT1"); // Дверь портала
object oGate = GetObjectByTag("AM_DOOR_WAR_ORD_T"); // Ворота сверху

//==============================  ЛОКАЦИИ  =====================================

location lClose = GetLocation(GetObjectByTag("AIWAN_CLOSE_ARENA")); //Скрыт.арена Aiwan'a
location lTrone = GetLocation(oPlsTrone); //

//===============================  ТОЧКИ ПУТИ  =================================
//----------- Точки Воинa Орды  ---------------
object oWPWar1 = GetObjectByTag("WP_WARRIOR_01");
object oWPWar2 = GetObjectByTag("WP_WARRIOR_02");
object oWPWar3 = GetObjectByTag("WP_WARRIOR_03");
//---------------- Портал ---------------------
object oWPport = GetObjectByTag("WP_WARRIOR_PORTAL");
//-------------- Место трона ------------------
object oWPTrone = GetObjectByTag("WP_TRONE_WARRIOR");
//-------------- Точки спавна -----------------
object oWPSpawn = GetObjectByTag("WP_FLEG_SPAWN");
//----------- Центр зала камеры ---------------
object oWPCent = GetObjectByTag("WP_FLEG_PC_CENTRE");
//------------- Точки игрока ------------------
object oWPC1 = GetObjectByTag("WP_FLEG_PC_01");
object oWPC2 = GetObjectByTag("WP_FLEG_PC_02");
object oWPC3 = GetObjectByTag("WP_FLEG_PC_03");
object oWPC4 = GetObjectByTag("WP_FLEG_PC_04");
//-------------- Точки стражи -----------------
object oWPnpc1 = GetObjectByTag("WP_FLEG_NPC_01");
object oWPnpc2 = GetObjectByTag("WP_FLEG_NPC_02");
object oWPnpc3 = GetObjectByTag("WP_FLEG_NPC_03");
object oWPnpc4 = GetObjectByTag("WP_FLEG_NPC_04");
object oWPnpc5 = GetObjectByTag("WP_FLEG_NPC_05");
object oWPnpc6 = GetObjectByTag("WP_FLEG_NPC_06");
//--------------- Охрана у трона ---------------
object oWPSlave1 = GetObjectByTag("WP_TRONE_SLAVE_01");
object oWPSlave2 = GetObjectByTag("WP_TRONE_SLAVE_02");
//--------------  Север - Юг  -----------------
object oSouth = GetWaypointByTag("WP_SOUTH"); // Юг
object oNorth = GetWaypointByTag("WP_NORTH"); // Север
//-------------- Точки спавна скелетов -----------------
object oWPSpsk1  = GetObjectByTag("WP_FLEG_SPAWN_01");
object oWPSpsk2  = GetObjectByTag("WP_FLEG_SPAWN_02");
object oWPSpsk3  = GetObjectByTag("WP_FLEG_SPAWN_03");
object oWPSpsk4  = GetObjectByTag("WP_FLEG_SPAWN_04");
object oWPSpsk5  = GetObjectByTag("WP_FLEG_SPAWN_05");
object oWPSpsk6  = GetObjectByTag("WP_FLEG_SPAWN_06");
object oWPSpsk7  = GetObjectByTag("WP_FLEG_SPAWN_07");
object oWPSpsk8  = GetObjectByTag("WP_FLEG_SPAWN_08");
object oWPSpsk9  = GetObjectByTag("WP_FLEG_SPAWN_09");
object oWPSpsk10 = GetObjectByTag("WP_FLEG_SPAWN_10");
object oWPSpsk11 = GetObjectByTag("WP_FLEG_SPAWN_11");
object oWPSpsk12 = GetObjectByTag("WP_FLEG_SPAWN_12");
object oWPSpBoss = GetObjectByTag("WP_FLEG_SPAWN_BOSS");
//-------------- Точка Даллика Стидфаста ---------------
object oWPd = GetObjectByTag("WP_DALLIK_IN_FLEG");

//===============================  ВИЗУАЛЬНЫЕ ЭФФЕКТЫ  =========================

effect eGhost = EffectVisualEffect(VFX_DUR_GHOSTLY_VISAGE); // Эффект духа
effect eCutInv = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY); // Невидимость в сценке
effect eCutPar = EffectCutsceneParalyze();// Неподвижность нашим спутникам (чтоб чего не выкинули...)
effect eSpawn = EffectVisualEffect(VFX_IMP_DEATH_L);
effect eSpawnD = EffectVisualEffect(VFX_IMP_RAISE_DEAD);
effect eLighS = EffectVisualEffect(VFX_IMP_LIGHTNING_S);
effect eLighM = EffectVisualEffect(VFX_IMP_LIGHTNING_M);
// Разные визуальные эффекты, если хотите их смениить, то наведите на них курсор и нажмите F2

effect eHaste = EffectHaste();
effect eSlow = EffectSlow(); // Замедление движений у игрока. Игрок ИДТИ не может,
                             // он только бежит, это движковое ограничение.

//++++++++++++++++++++++  МОТОР! КАМЕРА! СНИМАЕМ! ++++++++++++++++++++++++++++++

if (GetIsPC(oPC) && !GetLocalInt(OBJECT_SELF, "TRIGGER"))
{
//=======================   ПОДГОТОВКА К ПЕРВОМУ АКТУ  =========================
        SetLocalInt(OBJECT_SELF, "TRIGGER", TRUE);
        SetLocked(oGate, FALSE);
        SetCutsceneMode(oPC);
        FadeToBlack(oPC, FADE_SPEED_FASTEST);
//------------------------- ОБРАБОТКА ФАМИЛЬЯРОВ -------------------------------
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oAnimal, 355.5);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oAnimal, 354.0);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oHenchman, 355.5);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oHenchman, 354.0);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oDominated, 355.5);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oDominated, 354.0);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oFamiliar, 355.5);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oFamiliar, 354.0);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutPar, oSummoned, 355.5);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oSummoned, 354.0);
//------------------------------------------------------------------------------
        ActionCreate(OBJECT_TYPE_CREATURE, "am_dallik", GetLocation(oWPSpawn));
        // Создаем нашего НПС тут же, недалеко и "ПРЯЧЕМ" его просто сделав невидимым (IMG:style_emoticons/kolobok_light/wink3.gif)
        object oDallik = GetNearestObjectByTag("DALLIK_STEADFAST"); // Даллик
        // Определим его как oDallik, если вы это сделаете выше, то скрипт
        // просто не найдет такой объект, ведь его еще не было! Поэтому делайте так.
        location lClose;
        SetPlotFlag(oDallik, FALSE); // Убираем галочку СЮЖЕТНОГО НПС скриптом, теперь его можно убить
        AssignCommand(oSlave1, ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, 5.0, 5.0));
        AssignCommand(oSlave2, ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, 5.0, 7.0));
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oMag, 85.5);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oPC, 354.0);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSlow, oPC, 354.0);
        // Делаем игрока способным идти шагом
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oDallik, 200.5);
        // "ПРЯЧЕМ" NPC просто сделав невидимым
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCutInv, oWord, 11.5);
        // "ПРЯЧЕМ" NPC просто сделав невидимым
        SetAILevel(oWord, AI_LEVEL_HIGH); // Добавим прачку извилин (IMG:style_emoticons/kolobok_light/smile.gif)
        AssignCommand(oDallik, ClearAllActions());
        AssignCommand(oWord, ClearAllActions());
        AssignCommand(oPC, ClearAllActions());
        AssignCommand(oMag, ClearAllActions());
        DelayCommand(0.9, AssignCommand(oPC, ActionJumpToObject(oWPC2)));
        AssignCommand(oWord, ActionJumpToObject(oWPport));
        // Теперь как буд-то он прибыл из бездны (IMG:style_emoticons/kolobok_light/smile.gif) А сам стоит за углом
        MusicBackgroundChangeNight(GetArea(OBJECT_SELF), 43); // Сменим музыку на более устращающую
        MusicBackgroundChangeDay(GetArea(OBJECT_SELF), 43);  // Сменим музыку на более устращающую
        DelayCommand(2.0, FadeFromBlack(oPC, FADE_SPEED_MEDIUM));
//==========================  НАЧАЛО - АКТ ПЕРВЫЙ  =============================


ПРОДОЛЖЕНИЕ СКРИПТА СМОТРИТЕ В МОДУЛЕ!
Прикрепленные файлы
Прикрепленный файл  Cutscene.rar ( 0 байт ) Кол-во скачиваний: 40
 
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Tarre Talliorne
сообщение May 12 2004, 20:54
Сообщение #2


Level 8
***

Класс: Псионик
Характер: Chaotic Good
Раса: Человек
NWN: Скриптинг [Sn]



Aiwan, могу выложить базу, ЗНАЧИТЕЛЬНО облегчающую создания катсцен (IMG:style_emoticons/kolobok_light/good.gif) . Команды НАМНОГО проще в обращнии, чем *официальные*. По крайней мере мне этот инлюд сэкономил достаточно много времени.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
2GoDoom
сообщение May 12 2004, 21:40
Сообщение #3


Level 11
***

Класс: Обыватель
Характер: True Neutral
Раса: Человек
NWN: Маппинг



Tarre, выложи плиз! (IMG:style_emoticons/kolobok_light/smile.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Aiwan
сообщение May 12 2004, 23:40
Сообщение #4


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

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



// Tarre я не понял, ты чего старый ник не юзаешь?
Выложи в тему скриптов. (IMG:style_emoticons/kolobok_light/wink3.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
DBColl
сообщение May 13 2004, 13:09
Сообщение #5


4-х Кубовый
Иконки Групп

Класс: Некромант
Характер: Lawful Evil
Раса: Человек
NWN: Скриптинг [Sn]
Проклятие Левора



Тарре, выкладывай сюда, а не в скрипты. (IMG:style_emoticons/kolobok_light/smile.gif) Айв, тебе чем не нравится, чтобы здесь лежало? Все по теме. К тому же с удовольствием гляну этот инклюд...
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Tarre Talliorne
сообщение May 13 2004, 15:12
Сообщение #6


Level 8
***

Класс: Псионик
Характер: Chaotic Good
Раса: Человек
NWN: Скриптинг [Sn]



Сам инклюд
Neverwinter Script Source
void GestaltDebugOutput(object oPC)
{
    // Get the current position of oPC's camera
    float fDirection = GetLocalFloat(oPC,"fCameraDirection");
    float fRange = GetLocalFloat(oPC,"fCameraRange");
    float fPitch = GetLocalFloat(oPC,"fCameraPitch");

    // Fire a message to say where the camera is
    AssignCommand(oPC,SpeakString(FloatToString(fDirection) + ", " + FloatToString(fRange) + ", " + FloatToString(fPitch)));
}



void GestaltStopCameraMoves(object oPC, int iParty = 0, int bAuto = TRUE, int iCamID = 0)
{
    object oParty;
    string sCam;
    int iCount;

    if (iParty == 1)      { oParty = GetFirstFactionMember(oPC); }
    else if (iParty == 2) { oParty = GetFirstPC(); }
    else                  { oParty = oPC; }

    while (GetIsObjectValid(oParty))
        {
        if (bAuto)
            { iCamID = GetLocalInt(oParty,"iCamCount"); }

        iCount = iCamID;

        while (iCount > 0)
            {
            // Find the camera movement
            sCam = "iCamStop" + IntToString(iCount);
            SetLocalInt(oParty,sCam,1);
            iCount--;

            // Uncomment the line below to get a message in the game confirming each id which is cancelled
            // AssignCommand(oParty,SpeakString("Camera movement id " + IntToString(iCount) + "has been stopped"));
            }

        if (iParty == 1)                       { oParty = GetNextFactionMember(oParty,TRUE); }
        else if (iParty == 2)                  { oParty = GetNextPC(); }
        else                                   { return; }
        }
}



vector GetVectorAB(object oA, object oB)
{
    vector vA = GetPosition(oA);
    vector vB = GetPosition(oB);
    vector vDelta = (vA - vB);
    return vDelta;
}



float GetHorizontalDistanceBetween(object oA, object oB)
{
    vector vHorizontal = GetVectorAB(oA,oB);
    float fDistance = sqrt(pow(vHorizontal.x,2.0) + pow(vHorizontal.y,2.0));
    return fDistance;
}



float GestaltGetDirection(object oTarget, object oPC)
{
    vector vdTarget = GetVectorAB(oTarget,oPC);
    float fDirection = VectorToAngle(vdTarget);
    return fDirection;
}



void GestaltCameraPoint(float fDirection, float fRange, float fPitch, float fdDirection, float fdRange, float fdPitch, float fd2Direction, float fd2Range, float fd2Pitch, float fCount, object oPC, int iCamID, int iFace = 0)
{
    // Check whether this camera movement has been stopped
    string sCam = "iCamStop" + IntToString(iCamID);
    if (GetLocalInt(oPC,sCam) == 1)
        { return; }

    // Work out where to point the camera
    fDirection = fDirection + ((fd2Direction * pow(fCount,2.0)) / 2) + (fdDirection * fCount);
    fRange = fRange + ((fd2Range * pow(fCount,2.0)) / 2) + (fdRange * fCount);
    fPitch = fPitch + ((fd2Pitch * pow(fCount,2.0)) / 2) + (fdPitch * fCount);

    // Reset fDirectionNew if it's gone past 0 or 360 degrees
    while (fDirection < 0.0)    { fDirection = (fDirection + 360.0); }
    while (fDirection > 360.0)  { fDirection = (fDirection - 360.0); }

    // Set the camera and/or player facing, according to iFace
    if (iFace < 2)        { AssignCommand(oPC,SetCameraFacing(fDirection,fRange,fPitch)); }
    if (iFace > 0)        { AssignCommand(oPC,SetFacing(fDirection)); }

    // Store the current position of the camera
    SetLocalFloat(oPC,"fCameraDirection",fDirection);
    SetLocalFloat(oPC,"fCameraRange",fRange);
    SetLocalFloat(oPC,"fCameraPitch",fPitch);
}



void GestaltFaceTarget(object oTarget, float fRange, float fPitch, object oPC, int iFace, int iParty = 0, int iCamID = 0)
{
    // Check whether this camera movement has been stopped
    string sCam = "iCamStop" + IntToString(iCamID);
    if (iCamID > 0 && GetLocalInt(oPC,sCam) == 1)
        { return; }

    float fDirection;
    object oParty;

    if (iParty == 1)      { oParty = GetFirstFactionMember(oPC); }
    else if (iParty == 2) { oParty = GetFirstPC(); }
    else                  { oParty = oPC; }

    while (GetIsObjectValid(oParty))
        {
        fDirection = GestaltGetDirection(oTarget,oParty);

        if (iFace < 2)        { AssignCommand(oParty,SetCameraFacing(fDirection,fRange,fPitch)); }
        if (iFace > 0)        { AssignCommand(oParty,SetFacing(fDirection)); }

        if (iParty == 1)                       { oParty = GetNextFactionMember(oParty,TRUE); }
        else if (iParty == 2)                  { oParty = GetNextPC(); }
        else                                   { return; }
        }
}



float GestaltGetPanRate(float fDirection, float fDirection2, float fTicks, int iClockwise)
{
    // Calculates how far the camera needs to move each to tick to go from fDirection to fDirection2
    // in fTicks steps, correcting as necessary to account for clockwise or anti-clockwise movement

    float fdDirection;

    if (iClockwise == 0)
        {
        if (fDirection > fDirection2)               { fdDirection = ((fDirection2 + 360.0 - fDirection) / fTicks); }
        else                                        { fdDirection = ((fDirection2 - fDirection) / fTicks); }
        }

    if (iClockwise == 1)
        {
        if (fDirection2 > fDirection)               { fdDirection = ((fDirection2 - fDirection - 360.0) / fTicks); }
        else                                        { fdDirection = ((fDirection2 - fDirection) / fTicks); }
        }

    if (iClockwise == 2)
        {
        float fCheck = fDirection2 - fDirection;
        if (fCheck > 180.0)                         { fdDirection = ((fDirection2 - fDirection - 360.0) / fTicks); }
        else if (fCheck < -180.0)                   { fdDirection = ((fDirection2 + 360.0 - fDirection) / fTicks); }
        else                                        { fdDirection = ((fDirection2 - fDirection) / fTicks); }
        }

    return fdDirection;
}



void GestaltCameraMove(float fDelay, float fDirection, float fRange, float fPitch, float fDirection2, float fRange2, float fPitch2, float fTime, float fFrameRate, object oPC, int iClockwise = 0, int iFace = 0, int iParty = 0)
{
    // Get timing information
    float fTicks = (fTime * fFrameRate);
    float fdTime = (fTime / fTicks);
    float fStart = fDelay;
    float fCount;

    float fdDirection = GestaltGetPanRate(fDirection,fDirection2,fTicks,iClockwise);
    float fdRange = ((fRange2 - fRange) / fTicks);
    float fdPitch = ((fPitch2 - fPitch) / fTicks);

    int iCamID;
    object oParty;

    if (iParty == 1)      { oParty = GetFirstFactionMember(oPC); }
    else if (iParty == 2) { oParty = GetFirstPC(); }
    else                  { oParty = oPC; }

    while (GetIsObjectValid(oParty))
        {
        // Set the camera to top down mode
        SetCameraMode(oParty,CAMERA_MODE_TOP_DOWN);

        // Give the camera movement a unique id code so that it can be stopped
        iCamID = GetLocalInt(oParty,"iCamCount") + 1;
        SetLocalInt(oParty,"iCamCount",iCamID);

        // reset variables
        fCount = 0.0;
        fDelay = fStart;

        // Uncomment the line below to get a message in the game telling you the id of this camera movement
        // AssignCommand(oParty,SpeakString("Camera id - " + IntToString(iCamID)));

        // After delay, stop any older camera movements and start this one
        DelayCommand(fStart,GestaltStopCameraMoves(oParty,0,FALSE,iCamID - 1));

        while (fCount <= fTicks)
            {
            DelayCommand(fDelay,GestaltCameraPoint(fDirection,fRange,fPitch,fdDirection,fdRange,fdPitch,0.0,0.0,0.0,fCount,oParty,iCamID,iFace));
            fCount = (fCount + 1.0);
            fDelay = fStart + (fCount * fdTime);
            }

        if (iParty == 1)                       { oParty = GetNextFactionMember(oParty,TRUE); }
        else if (iParty == 2)                  { oParty = GetNextPC(); }
        else                                   { return; }
        }
}



void GestaltCameraSmoothStart(float fdDirection1, float fdRange1, float fdPitch1, float fdDirection2, float fdRange2, float fdPitch2, float fTime, float fFrameRate, object oParty, object oSync, int iCamID)
{
    // Get starting position for camera
    float fDirection = GetLocalFloat(oSync,"fCameraDirection");
    float fRange = GetLocalFloat(oSync,"fCameraRange");
    float fPitch = GetLocalFloat(oSync,"fCameraPitch");

    // Get timing information
    float fTicks = (fTime * fFrameRate);
    float fdTime = (fTime / fTicks);
    float fDelay = 0.0;
    float fCount = 0.0;

    // Get camera speed and acceleration
    float fdDirection = fdDirection1 / fFrameRate;
    float fdRange = fdRange1 / fFrameRate;
    float fdPitch = fdPitch1 / fFrameRate;

    float fd2Direction = (fdDirection2 - fdDirection1) / ((fTicks - 1) * fFrameRate);
    float fd2Range = (fdRange2 - fdRange1) / ((fTicks - 1) * fFrameRate);
    float fd2Pitch = (fdPitch2 - fdPitch1) / ((fTicks - 1) * fFrameRate);

    // Start camera movement
    while (fCount < fTicks)
        {
        DelayCommand(fDelay,GestaltCameraPoint(fDirection,fRange,fPitch,fdDirection,fdRange,fdPitch,fd2Direction,fd2Range,fd2Pitch,fCount,oParty,iCamID));
        fCount = (fCount + 1.0);
        fDelay = (fCount * fdTime);
        }

    // Uncomment the line below to display the starting position of the camera movement
    // GestaltDebugOutput(oSync);

    // Uncomment the line below to display the finishing position of the camera movement
    // DelayCommand(fDelay,GestaltDebugOutput(oSync));
}



void GestaltCameraSmooth(float fDelay, float fdDirection1, float fdRange1, float fdPitch1, float fdDirection2, float fdRange2, float fdPitch2, float fTime, float fFrameRate, object oPC, int iParty = 0, int iSync = 1)
{
    object oParty;
    object oSync;
    int iCamID;

    if (iParty == 1)      { oParty = GetFirstFactionMember(oPC); }
    else if (iParty == 2) { oParty = GetFirstPC(); }
    else                  { oParty = oPC; }

    while (GetIsObjectValid(oParty))
        {
        // Work out whose camera position to use as the starting position
        if (iSync == 1)   { oSync = oPC; }
        else              { oSync = oParty; }

        // Set the camera to top down mode
        SetCameraMode(oParty,CAMERA_MODE_TOP_DOWN);

        // Give the camera movement a unique id code so that it can be stopped
        iCamID = GetLocalInt(oParty,"iCamCount") + 1;
        SetLocalInt(oParty,"iCamCount",iCamID);

        // Uncomment the line below to get a message in the game telling you the id of this camera movement
        // AssignCommand(oParty,SpeakString("Camera id - " + IntToString(iCamID)));

        // After delay, stop any older camera movements and start this one
        DelayCommand(fDelay,GestaltStopCameraMoves(oParty,0,FALSE,iCamID - 1));
        DelayCommand(fDelay,GestaltCameraSmoothStart(fdDirection1,fdRange1,fdPitch1,fdDirection2,fdRange2,fdPitch2,fTime,fFrameRate,oParty,oSync,iCamID));

        if (iParty == 1)                       { oParty = GetNextFactionMember(oParty,TRUE); }
        else if (iParty == 2)                  { oParty = GetNextPC(); }
        else                                   { return; }
        }
}



void GestaltCameraFace(float fDelay, object oStart, float fRange, float fPitch, object oEnd, float fRange2, float fPitch2, float fTime, float fFrameRate, object oPC, int iClockwise = 0, int iFace = 0, int iParty = 0)
{
    // Get timing information
    float fCount = 0.0;
    float fStart = fDelay;
    float fTicks = (fTime * fFrameRate);
    float fdTime = (fTime / fTicks);

    float fDirection;
    float fDirection2;

    float fdDirection;
    float fdRange = ((fRange2 - fRange) / fTicks);
    float fdPitch = ((fPitch2 - fPitch) / fTicks);

    object oParty;
    int iCamID;

    // Get first player
    if (iParty == 1)      { oParty = GetFirstFactionMember(oPC); }
    else if (iParty == 2) { oParty = GetFirstPC(); }
    else                  { oParty = oPC; }

    while (GetIsObjectValid(oParty))
        {
        // Set the camera to top down mode
        SetCameraMode(oParty,CAMERA_MODE_TOP_DOWN);

        // Give the camera movement a unique id code so that it can be stopped
        iCamID = GetLocalInt(oParty,"iCamCount") + 1;
        SetLocalInt(oParty,"iCamCount",iCamID);

        // reset variables
        fCount = 0.0;
        fDelay = fStart;

        // Work out rotation rate for this player
        fDirection = GestaltGetDirection(oStart,oParty);
        fDirection2 = GestaltGetDirection(oEnd,oParty);
        fdDirection = GestaltGetPanRate(fDirection,fDirection2,fTicks,iClockwise);

        // After delay, stop any older camera movements and start this one
        DelayCommand(fStart,GestaltStopCameraMoves(oParty,0,FALSE,iCamID - 1));

        while (fCount <= fTicks)
            {
            DelayCommand(fDelay,GestaltCameraPoint(fDirection,fRange,fPitch,fdDirection,fdRange,fdPitch,0.0,0.0,0.0,fCount,oParty,iCamID,iFace));
            fCount = (fCount + 1.0);
            fDelay = fStart + (fCount * fdTime);
            }

        if (iParty == 1)                       { oParty = GetNextFactionMember(oParty,TRUE); }
        else if (iParty == 2)                  { oParty = GetNextPC(); }
        else                                   { return; }
        }
}



void GestaltCameraTrack(float fDelay, object oTrack, float fRange, float fPitch, float fRange2, float fPitch2, float fTime, float fFrameRate, object oPC, int iFace = 0, int iParty = 0)
{
    // Get timing information
    float fCount;
    float fStart = fDelay;
    float fTicks = (fTime * fFrameRate);
    float fdTime = (fTime / fTicks);

    float fSRange = fRange;
    float fSPitch = fPitch;

    float fdRange = ((fRange2 - fRange) / fTicks);
    float fdPitch = ((fPitch2 - fPitch) / fTicks);

    object oParty;
    int iCamID;

    if (iParty == 1)      { oParty = GetFirstFactionMember(oPC); }
    else if (iParty == 2) { oParty = GetFirstPC(); }
    else                  { oParty = oPC; }

    while (GetIsObjectValid(oParty))
        {
        // Set the camera to top down mode
        SetCameraMode(oParty,CAMERA_MODE_TOP_DOWN);

        // Give the camera movement a unique id code so that it can be stopped
        iCamID = GetLocalInt(oParty,"iCamCount") + 1;
        SetLocalInt(oParty,"iCamCount",iCamID);

        // reset variables
        fCount = 0.0;
        fDelay = fStart;
        fRange = fSRange;
        fPitch = fSPitch;

        // After delay, stop any older camera movements and start this one
        DelayCommand(fStart,GestaltStopCameraMoves(oParty,0,FALSE,iCamID - 1));

        while (fCount <= fTicks)
            {
            DelayCommand(fDelay,GestaltFaceTarget(oTrack,fRange,fPitch,oParty,iFace,0,iCamID));
            fPitch = (fPitch + fdPitch);
            fRange = (fRange + fdRange);
            fCount = (fCount + 1.0);
            fDelay = fStart + (fCount * fdTime);
            }

        if (iParty == 1)                       { oParty = GetNextFactionMember(oParty,TRUE); }
        else if (iParty == 2)                  { oParty = GetNextPC(); }
        else                                   { return; }
        }
}



void GestaltFixedCamera(object oPC, float fFrameRate = 50.0)
{
    // Thanks to Tenchi Masaki for the idea for this function
    string sCamera = GetLocalString(oPC,"sGestaltFixedCamera");    // Gets the camera position to use
    if (sCamera == "STOP")                                          // Camera tracking is turned off, stop script and don't recheck
        { return; }
    if (sCamera == "")                                              // Camera tracking is inactive, stop script but recheck in a second
        {
        DelayCommand(1.0,GestaltFixedCamera(oPC,fFrameRate));
        return;
        }

    float fHeight = GetLocalFloat(oPC,"fGestaltFixedCamera");       // Gets the camera height to use
    if (fHeight == 0.0)         { fHeight = 10.0; }                 // Defaults camera height to 10.0 if none has been set yet

    object oCamera = GetObjectByTag(sCamera);
    float fDelay = 1.0 / fFrameRate;
    float fRange = GetHorizontalDistanceBetween(oPC,oCamera);

    float fAngle = GestaltGetDirection(oPC,oCamera);                // Works out angle between camera and player
    float fPitch = atan(fRange/fHeight);                            // Works out vertical tilt
    float fDistance = sqrt(pow(fHeight,2.0) + pow(fRange,2.0));    // Works out camera distance from player
    if (fDistance > 30.0)       { fDistance = 30.0; }               // Sets distance to 30.0 if player is too far away
    if (fDistance < 5.0)        { fDistance = 5.0; }                // Sets distance to 5.0 if player is too close

    AssignCommand(oPC,SetCameraFacing(fAngle,fDistance,fPitch));
    DelayCommand(fDelay,GestaltFixedCamera(oPC,fFrameRate));
}[/CODE]

и прототипы к функциям

[CODE]// Stops all camera movements immediately
    // oPC              the player whose camera movements you want to stop
    // iParty           sets whether to stop the camera of only oPC (0), all the players in oPC's party (1) or all the players on the server (2)
// DO NOT CHANGE THE FOLLOWING SETTINGS!
    // bAuto            sets whether the function should stop all camera movement (TRUE) or only ones with an id lower than iCamID (FALSE)
    // iCamID           the ID of the last camera move you want to stop (this is only needed if bAuto is set to FALSE)
void GestaltStopCameraMoves(object oPC, int iParty = 0, int bAuto = TRUE, int iCamID = 0);

// Gets the vector linking object A to object B
vector GetVectorAB(object oA, object oB);

// Finds the horizontal distance between two objects, ignoring any vertical component
float GetHorizontalDistanceBetween(object oA, object oB);

// Finds the compass direction from the PC to a target object
float GestaltGetDirection(object oTarget, object oPC);

// Turns a character and/or their camera to face the specified target object
    // oTarget          the object to face
    // fRange           the distance between the player and the camera
    // fPitch           the vertical tilt of the camera
                        // NOTE that fRange and/or fPitch can be set to -1.0 to keep the camera's range and/or pitch unchanged
    // oPC              the character you want to move
                        // NOTE that this can be an NPC, as long as iFace == 2
    // iFace            sets whether the camera (0), the character (2) or both (1) turn to face the specified direction
                        // NOTE that fRange and fPitch won't do anything if iFace == 2, as only the character is being moved
    // iParty           sets whether to move the camera of only oPC (0), all the players in oPC's party (1) or all the players on the server (2)
    // iCamID           the ID of the camera movement - DO NOT CHANGE THIS!
void GestaltFaceTarget(object oTarget, float fRange, float fPitch, object oPC, int iFace, int iParty = 0, int iCamID = 0);

// Moves the camera smoothly from one position to another over the specified time
    // STARTING TIME -
        // fDelay           how many seconds to wait before starting the movement
    // STARTING CONDITIONS -
        // fDirection       initial direction (0.0 = due east)
        // fRange           initial distance between player and camera
        // fPitch           initial pitch (vertical tilt)
    // FINAL CONDITIONS -
        // fDirection2      finishing direction
        // fRange2          finishing distance
        // fPitch2          finishing tilt
    // TIME SETTINGS -
        // fTime            number of seconds it takes camera to complete movement
        // fFrameRate       number of movements per second (governs how smooth the motion is)
    // MISC SETTINGS -
        // oPC              the PC you want to apply the camera movement to
        // iClockwise       set to 1 if you want the camera to rotate clockwise, 0 for anti-clockwise, or 2 for auto-select
        // iFace            sets whether the camera (0), the character (2) or both (1) turn to face the specified direction
        // iParty           sets whether to move the camera of only oPC (0), all the players in oPC's party (1) or all the players on the server (2)
void GestaltCameraMove(float fDelay, float fDirection, float fRange, float fPitch, float fDirection2, float fRange2, float fPitch2, float fTime, float fFrameRate, object oPC, int iClockwise = 0, int iFace = 0, int iParty = 0);

// Produces smooth transitions between different camera movements by setting initial and final speeds
// The function then interpolates between the two so that the movement rate changes smoothly over the
//  duration of the movement.
    // STARTING TIME -
        // fDelay           how many seconds to wait before starting the movement
    // MOVEMENT RATES AT START OF MOTION -
        // fdDirection1    how fast the camera's compass direction should change by in degrees per second
                            // positive numbers produce an anti-clockwise movement, negative anti-clockwise
        // fdRange1         how fast the camera's range should change in meters per second
                            // positive numbers move the camera away from the player, negative towards them
        // fdPitch1         how fast the camera's pitch should change in degrees per second
                            // positive numbers tilt the camera down towards the ground, negative up towards vertical
    // MOVEMENT RATES AT END OF MOTION -
        // fdDirection2    how fast the camera's compass direction should change by in degrees per second
                            // positive numbers produce an anti-clockwise movement, negative anti-clockwise
        // fdRange2         how fast the camera's range should change in meters per second
                            // positive numbers move the camera away from the player, negative towards them
        // fdPitch2         how fast the camera's pitch should change in degrees per second
                            // positive numbers tilt the camera down towards the ground, negative up towards vertical
    // TIME SETTINGS -
        // fTime            number of seconds it should take the camera to complete movement
        // fFrameRate       number of movements per second (governs how smooth the motion is)
    // MISC SETTINGS -
        // oPC              the player whose camera you want to move
        // iParty           sets whether to move the camera of only oPC (0), all the players in oPC's party (1) or all the players on the server (2)
        // iSync            sets whether to use separate camera starting positions for every player (0) or sync them all to oPC's camera position (1)
void GestaltCameraSmooth(float fDelay, float fdDirection1, float fdRange1, float fdPitch1, float fdDirection2, float fdRange2, float fdPitch2, float fTime, float fFrameRate, object oPC, int iParty = 0, int iSync = 1);

// Turns the camera and/or player between two objects
// NOTE that this will only work properly if the player and target objects are stationary while the function is active
    // STARTING TIME -
        // fDelay           how many seconds to wait before starting the movement
    // STARTING CONDITIONS -
        // oStart           object to face at start of movement
        // fRange           initial distance between player and camera
        // fPitch           initial pitch (vertical tilt)
    // FINAL CONDITIONS -
        // oEnd             object to finish movement facing
        // fRange2          finishing distance
        // fPitch2          finishing tilt
    // TIME SETTINGS -
        // fTime            number of seconds it takes camera to complete movement
        // fFrameRate       number of movements per second (governs how smooth the motion is)
    // MISC SETTINGS -
        // oPC              the player whose camera you want to move
        // iClockwise       set to 1 if you want the camera to rotate clockwise, 0 for anti-clockwise, or 2 for auto-select
        // iFace            controls whether the camera (0), the character (2) or both (1) turn
        // iParty           sets whether to move the camera of only oPC (0), all the players in oPC's party (1) or all the players on the server (2)
void GestaltCameraFace(float fDelay, object oStart, float fRange, float fPitch, object oEnd, float fRange2, float fPitch2, float fTime, float fFrameRate, object oPC, int iClockwise = 0, int iFace = 0, int iParty = 0);

// Tracks a moving object, turning the player's camera so that it always faces towards it
    // STARTING TIME -
        // fDelay           how many seconds to wait before starting the movement
    // TARGET -
        // oTrack           object to track the movement of
    // STARTING CONDITIONS -
        // fRange           initial distance between player and camera
        // fPitch           initial pitch (vertical tilt)
    // FINAL CONDITIONS -
        // fRange2          finishing distance
        // fPitch2          finishing tilt
    // TIME SETTINGS -
        // fTime            how long the camera will track the object for
        // fFrameRate       number of movements per second (governs how smooth the motion is)
    // MISC SETTINGS -
        // oPC              the PC you want to apply the camera movement to
        // iFace            controls whether the camera (0), the character (2) or both (1) turn
        // iParty           sets whether to move the camera of only oPC (0), all the players in oPC's party (1) or all the players on the server (2)
void GestaltCameraTrack(float fDelay, object oTrack, float fRange, float fPitch, float fRange2, float fPitch2, float fTime, float fFrameRate, object oPC, int iFace = 0, int iParty = 0);

// Gives the illusion of the camera being fixed in one place and rotating to face the player as they move
    // oPC              the PC you want to apply the camera movement to
    // fFrameRate       number of movements per second (governs how smooth the motion is)
//
// To setup a fixed camera position, place a waypoint with a unique tag in your area
    // Set the camera's tag as a LocalString "sGestaltFixedCamera" on the PC to let them know to use that camera
    // Set a LocalFloat "fGestaltFixedCamera" on the PC to set the camera's vertical position
    // Set "sGestaltFixedCamera" to "" to pause the tracking, or to "STOP" to end the tracking
void GestaltFixedCamera(object oPC, float fFrameRate = 50.0);


Если надо, могу выложить более подробное объяснение. Но, думаю, и так все ясно.
ЗЫ: зацените GestaltCameraMove() - шедевр (IMG:style_emoticons/kolobok_light/biggrin.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
2GoDoom
сообщение May 13 2004, 16:40
Сообщение #7


Level 11
***

Класс: Обыватель
Характер: True Neutral
Раса: Человек
NWN: Маппинг



Большое спасибо! (IMG:style_emoticons/kolobok_light/smile.gif)
Теперь не прийдется качать Лексикон (IMG:style_emoticons/kolobok_light/wink3.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
DBColl
сообщение May 13 2004, 21:38
Сообщение #8


4-х Кубовый
Иконки Групп

Класс: Некромант
Характер: Lawful Evil
Раса: Человек
NWN: Скриптинг [Sn]
Проклятие Левора



Хех, Гештальт Камера - старинный инклюд времен первого НВН. Не расчитан на Катсцены. Можете его адаптировать под них, но... имхо не имеет смысла. Я с него соскочил с появлением СоУ, где можно было сценки делать. Хех. (IMG:style_emoticons/kolobok_light/smile.gif) Я думал будет более интересное что-то... (IMG:style_emoticons/kolobok_light/sad.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Tarre Talliorne
сообщение May 15 2004, 17:26
Сообщение #9


Level 8
***

Класс: Псионик
Характер: Chaotic Good
Раса: Человек
NWN: Скриптинг [Sn]



Ну почему же не рассчитан... очень даж рассчитан. Лично МНЕ намного удобней юзать эту инлюду, чем стандартные функции. Кстати с помощью этой вещи можно реализовать фиксированную камеру(в принипе так тож можно, но нечто похожее я видел только при плавании камеры в ареи КАРТА ВАСТА Проклятия).
Цитата
Я думал будет более интересное что-то

Извините если что не так (IMG:style_emoticons/kolobok_light/smile.gif) )
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
DBColl
сообщение May 16 2004, 02:30
Сообщение #10


4-х Кубовый
Иконки Групп

Класс: Некромант
Характер: Lawful Evil
Раса: Человек
NWN: Скриптинг [Sn]
Проклятие Левора



Да нет, Тарре, не обижайся! (IMG:style_emoticons/kolobok_light/good.gif) Извини меня, если че не так (IMG:style_emoticons/kolobok_light/wink3.gif) .

Фиксированая камера, это не что иное, как удаление с экрана героя. (IMG:style_emoticons/kolobok_light/wink3.gif) Джамп в невидимом состоянии...
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Tarre Talliorne
сообщение May 16 2004, 19:14
Сообщение #11


Level 8
***

Класс: Псионик
Характер: Chaotic Good
Раса: Человек
NWN: Скриптинг [Sn]



Про фикс: я не совсем то имел ввиду.Про катсцен_инвизибл я и так знаю. Я иел ввиду, что можно релизовать такую полезнейшую вещь, как неуправляемая героем камера, причем все это не в режиме катсцены.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Аваддон
сообщение Jun 23 2004, 22:04
Сообщение #12


Level 10
***

Класс: Воин
Характер: Lawful Neutral
Раса: Человек
NWN: Скриптинг [PW]



Вопрос назрел к Айвану.
Что то у меня неполучается чтобы при нападении камера к монстру развернулась.
Код

object oEnemy = GetLastAttacker();
float fEnemy=GetFacing(oEnemy);
AssignCommand(oPC, SetCameraFacing(fEnemy, 5.0, 45.0, CAMERA_TRANSITION_TYPE_MEDIUM));
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Aiwan
сообщение Jun 23 2004, 23:47
Сообщение #13


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

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



Ну ты даешь! (IMG:style_emoticons/kolobok_light/shok.gif) У РС куча забот а ты его еще камерой мутузишь! (IMG:style_emoticons/kolobok_light/lol.gif)

Код

vector vD = GetPosition(oEnemy) - GetPosition(oPC);
float fEnemy = VectorToAngle(vD);
AssignCommand(oPC, SetCameraFacing(fEnemy, 5.0, 45.0, CAMERA_TRANSITION_TYPE_MEDIUM));

Не подумай что я такой умный (IMG:style_emoticons/kolobok_light/unsure.gif) это код ДБа. Просто я знаю где он и как работает (IMG:style_emoticons/kolobok_light/biggrin.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
DBColl
сообщение Jun 24 2004, 02:57
Сообщение #14


4-х Кубовый
Иконки Групп

Класс: Некромант
Характер: Lawful Evil
Раса: Человек
NWN: Скриптинг [Sn]
Проклятие Левора



Кстати спецы по векторам у нас Лекс и Баал. Так что разрулят, если возникнут вопросы (IMG:style_emoticons/kolobok_light/wink3.gif) .

LEX: не переводи на меня стрелки, ДБ. Я не шарю в векторах. Ты и Баал, вот, кто шарят.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Аваддон
сообщение Jul 9 2004, 00:07
Сообщение #15


Level 10
***

Класс: Воин
Характер: Lawful Neutral
Раса: Человек
NWN: Скриптинг [PW]



Интересный вопросик.
У нас есть один момент - заходишь в локацию. На игрока накладывается СетКутСценеМод=Трю,
потом эффект - КутСценИнвизибл. Тоесть как бы началась сценка и игрока не видно, видно только НеПиСей.
Так вот стоит нажать Esc как игрок появляется и появляется панель управления игрока(HUD).
И во время кутсцены игрок уже может ходить вокруг "отыгрывающих" НПС.
Пробовал наложить на него СетКоммандэйбл(Фолс, оПС). Но это ничего не поненяло - жм у Esc игрок появляется, только двигатся не может.
В чем дело не пойму.
З.Ы. У меня НВН в окне, может из за этого?!
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
DBColl
сообщение Jul 9 2004, 11:52
Сообщение #16


4-х Кубовый
Иконки Групп

Класс: Некромант
Характер: Lawful Evil
Раса: Человек
NWN: Скриптинг [Sn]
Проклятие Левора



Может и из-за этого... Но скорее всего это из-за известного бага - ставить на онЭнтр локации катсцену нельзя... (IMG:style_emoticons/kolobok_light/sad.gif) Возможны кучи багов. Лучше поставить триггер при входе в локу и на него вешать катсцену.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Tarre Talliorne
сообщение Jul 9 2004, 14:20
Сообщение #17


Level 8
***

Класс: Псионик
Характер: Chaotic Good
Раса: Человек
NWN: Скриптинг [Sn]



Нет. Ав, тебе надо было сначала у меня спросить. Просто я в своем моде для теста (вдруг с катсценой что не так) на он_катсцен_абортед поставил снятие всех эффектов + рестор положения камеры :-)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
2GoDoom
сообщение Jul 12 2004, 14:15
Сообщение #18


Level 11
***

Класс: Обыватель
Характер: True Neutral
Раса: Человек
NWN: Маппинг



Подскажите что тут не правильно...

Neverwinter Script Source
void main()
{
object oPC = GetEnteringObject();
object oNPC1 = GetNearestObjectByTag("NPC_1", OBJECT_SELF);
object oNPC2 = GetNearestObjectByTag("NPC_2", OBJECT_SELF);
object oNPC3 = GetObjectByTag("NPC_3");
object oDoor = GetNearestObjectByTag("DOOR", OBJECT_SELF);
object oWP = GetObjectByTag("GO_AWAY"); //Стоит в комнате за дверью oDoor
effect eDis = EffectDisappear(0);

if(!GetIsPC(oPC))
  return;
{
  SetCutsceneMode(oPC); //Включается катсцена
  ActionDoCommand(SetCameraFacing(180.0, 15.0, 50.0, CAMERA_TRANSITION_TYPE_SLOW));
  ActionWait(1.0);
  ActionDoCommand(AssignCommand(oNPC1, SetFacing(270.0))); //НПС смотрит на юг (потмоу как там второй НПС)
ActionDoCommand(AssignCommand(oNPC1, SpeakString("Ты тупой казел!", TALKVOLUME_TALK)));
  ActionDoCommand(AssignCommand(oNPC2, SetFacing(90.0))); //Поворачивает голову на север - если она смотрит не на север, и отвечает...
  ActionDoCommand(AssignCommand(oNPC2, SpeakString("Завались, баран!", TALKVOLUME_TALK)));
  ActionDoCommand(AssignCommand(oNPC1, SpeakString("Ты нарвалсЯ, ублюдок!", TALKVOLUME_TALK))); //Здесь мне влом прикручивать YA было (IMG:style_emoticons/kolobok_light/smile.gif)
  ActionDoCommand(AssignCommand(oNPC1, ActionMoveToObject(oNPC2, TRUE, 1.0))); //Первый Непись подходит ко второму
  ActionDoCommand(AssignCommand(oNPC1, ActionAttack(oNPC2, TRUE))); //Атаковать второго НПС (не пашет)
  ActionWait(5.0); //Ждем покуда оин подерутся какое-то время
  ActionDoCommand(AssignCommand(oPC, SetFacingPoint(GetPosition(oDoor)))); //Поворачиваемся к двери, а далее совсем смешно...
  ActionDoCommand(AssignCommand(oDoor, ActionOpenDoor(OBJECT_SELF))); //Дверь открывается
  ActionDoCommand(AssignCommand(oNPC3, ActionMoveToObject(oNPC1, TRUE, 1.0))); //Непись не идет
  ActionDoCommand(AssignCommand(oDoor, ActionCloseDoor(OBJECT_SELF))); //Дверь закрывается
  ActionDoCommand(AssignCommand(oNPC3, PlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 2.0))); //Анимация хз - проигрывается или нет
  ActionDoCommand(AssignCommand(oNPC3, ActionMoveToObject(oNPC2, TRUE, 1.0))); //Тоже что и выше (ну это типа в наручники заковывает
  ActionDoCommand(AssignCommand(oNPC3, PlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 2.0)));
  ActionDoCommand(AssignCommand(oNPC1, ActionForceFollowObject(oNPC3, 0.0))); //Идут к Неписю, который остался стоять в предыдущей комнатке
  ActionDoCommand(AssignCommand(oNPC2, ActionForceFollowObject(oNPC3, 0.0)));
  ActionDoCommand(AssignCommand(oNPC3, ActionMoveToObject(oDoor, FALSE, 1.0)));
  ActionDoCommand(AssignCommand(oDoor, ActionOpenDoor(OBJECT_SELF)));
  ActionDoCommand(AssignCommand(oNPC3, ActionMoveToObject(oWP, FALSE, 0.0)));
  ActionWait(1.0);
  ActionDoCommand(DestroyObject(oNPC1, 0.0));
  ActionDoCommand(DestroyObject(oNPC2, 0.0));
  ActionDoCommand(DestroyObject(oNPC3, 0.0));
  ActionDoCommand(DestroyObject(OBJECT_SELF, 0.0)); //Кстати сам триггер тоже удаляется, где-то слышал что говорили - что их нельзя удалить и т.п.
  ActionDoCommand(SetCutsceneMode(oPC, FALSE));
}

}


Что самое обидное - они не подравшись, и кстати за ними не пришел мент из комнаты, начинают бежать к двери и пропадают не добежав. А дверь открылась. (IMG:style_emoticons/kolobok_light/smile.gif)
Подскажите плиз
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
DBColl
сообщение Jul 12 2004, 15:02
Сообщение #19


4-х Кубовый
Иконки Групп

Класс: Некромант
Характер: Lawful Evil
Раса: Человек
NWN: Скриптинг [Sn]
Проклятие Левора



А скрипт на чем стоит? Триггер? Лока? Еще что?..
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
2GoDoom
сообщение Jul 12 2004, 15:32
Сообщение #20


Level 11
***

Класс: Обыватель
Характер: True Neutral
Раса: Человек
NWN: Маппинг



Триггер OnEnter
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
DBColl
сообщение Jul 12 2004, 15:45
Сообщение #21


4-х Кубовый
Иконки Групп

Класс: Некромант
Характер: Lawful Evil
Раса: Человек
NWN: Скриптинг [Sn]
Проклятие Левора



2GoDoom
Катсцены пишутся по такой схеме:
Neverwinter Script Source
DelayCommand(x.x, AssignCommand(...))

Иначе ты будешь еще долго разбираться в стеке акций... И сбои никогда неисключены. А через DelayCommand все всегда получается и быстрее, и безошибочнее.
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
2GoDoom
сообщение Jul 12 2004, 16:14
Сообщение #22


Level 11
***

Класс: Обыватель
Характер: True Neutral
Раса: Человек
NWN: Маппинг



Окей, спасибо - буду пробовать
Добавлено в [mergetime]1089639537[/mergetime]
Еще большие глюки (IMG:style_emoticons/kolobok_light/sad.gif)
Правильно написано?:

Neverwinter Script Source
void main()
{
object oPC = GetEnteringObject();
object oNPC1 = GetNearestObjectByTag("NPC_1", OBJECT_SELF);
object oNPC2 = GetNearestObjectByTag("NPC_2", OBJECT_SELF);
object oNPC3 = GetObjectByTag("NPC_3");
object oDoor = GetNearestObjectByTag("DOOR", OBJECT_SELF);
object oWP = GetObjectByTag("GO_AWAY");
effect eDis = EffectDisappear(0);

if(!GetIsPC(oPC) || GetLocalInt(OBJECT_SELF, "TRIGGER") == 1)
  return;
{
  SetLocalInt(OBJECT_SELF, "TRIGGER", 1);
  SetCutsceneMode(oPC);
  ActionDoCommand(SetCameraFacing(180.0, 15.0, 50.0, CAMERA_TRANSITION_TYPE_SLOW));
  DelayCommand(1.0 ,AssignCommand(oNPC1, SetFacing(270.0)));
  DelayCommand(2.0 ,AssignCommand(oNPC1, SpeakString("?? ????? ?????!", TALKVOLUME_TALK)));
  DelayCommand(4.0 ,AssignCommand(oNPC2, SetFacing(90.0)));
  DelayCommand(4.5 ,AssignCommand(oNPC2, SpeakString("????????, ?????!", TALKVOLUME_TALK)));
  DelayCommand(5.0 ,AssignCommand(oNPC1, SpeakString("?? ????????, ???????!", TALKVOLUME_TALK)));
  DelayCommand(5.0 ,AssignCommand(oNPC1, ActionMoveToObject(oNPC2, TRUE, 1.0)));
  DelayCommand(5.5 ,AssignCommand(oNPC1, ActionAttack(oNPC2, FALSE)));
  DelayCommand(10.0 ,AssignCommand(oPC, SetFacingPoint(GetPosition(oDoor))));
  DelayCommand(10.5 ,AssignCommand(oDoor, ActionOpenDoor(OBJECT_SELF)));
  DelayCommand(11.5 ,AssignCommand(oDoor, ActionCloseDoor(OBJECT_SELF)));
  DelayCommand(11.0 ,AssignCommand(oNPC3, ActionMoveToObject(oNPC1, TRUE, 1.0)));
  DelayCommand(11.0 ,AssignCommand(oNPC3, PlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 2.0)));
  DelayCommand(12.0 ,AssignCommand(oNPC3, ActionMoveToObject(oNPC2, TRUE, 1.0)));
  DelayCommand(12.0 ,AssignCommand(oNPC3, PlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 2.0)));
  DelayCommand(12.5 ,AssignCommand(oNPC1, ActionForceFollowObject(oNPC3, 0.0)));
  DelayCommand(12.5 ,AssignCommand(oNPC2, ActionForceFollowObject(oNPC3, 0.0)));
  DelayCommand(13.0 ,AssignCommand(oNPC3, ActionMoveToObject(oDoor, FALSE, 1.0)));
  DelayCommand(14.0 ,AssignCommand(oDoor, ActionOpenDoor(OBJECT_SELF)));
  DelayCommand(14.5 ,AssignCommand(oNPC3, ActionMoveToObject(oWP, FALSE, 0.0)));
  DelayCommand(15.0 ,DestroyObject(oNPC1, 0.0));
  DelayCommand(15.0 ,DestroyObject(oNPC2, 0.0));
  DelayCommand(15.0 ,DestroyObject(oNPC3, 0.0));
  DelayCommand(15.0 ,DestroyObject(OBJECT_SELF, 0.0));
  DelayCommand(16.0 ,SetCutsceneMode(oPC, FALSE));
}
}

Добавлено в [mergetime]1089639872[/mergetime]
Еще что не понятно - камера то не крутится (IMG:style_emoticons/kolobok_light/sad.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
Tarre Talliorne
сообщение Jul 12 2004, 17:46
Сообщение #23


Level 8
***

Класс: Псионик
Характер: Chaotic Good
Раса: Человек
NWN: Скриптинг [Sn]



Код
ActionDoCommand(SetCameraFacing(180.0, 15.0, 50.0, CAMERA_TRANSITION_TYPE_SLOW));

Неверно. Верно так:
Код
AssignCommand(oPC, SetCameraFacing(180.0, 15.0, 50.0, CAMERA_TRANSITION_TYPE_SLOW));
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
DBColl
сообщение Jul 12 2004, 18:19
Сообщение #24


4-х Кубовый
Иконки Групп

Класс: Некромант
Характер: Lawful Evil
Раса: Человек
NWN: Скриптинг [Sn]
Проклятие Левора



Ну вроде как все правильно. А что глючит-то? Как?
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения
2GoDoom
сообщение Jul 12 2004, 19:22
Сообщение #25


Level 11
***

Класс: Обыватель
Характер: True Neutral
Раса: Человек
NWN: Маппинг



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

Вот так то (IMG:style_emoticons/kolobok_light/sad.gif)
Вернуться в начало страницы
Скопировать ник в поле быстрого ответа
+Ответить с цитированием данного сообщения

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

 



Текстовая версия Сейчас: 28th March 2024 - 12:48