Помощь - Поиск - Пользователи - Календарь
Полная версия: Скрипты
Город Мастеров > РЕДАКТОРЫ > Neverwinter Nights Aurora Toolset
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74
Ilerien
Означает. Я ж говорю, в вышеприведенном коде проверка на отсутствие, а не на присутствие хотя бы одного предмета.
wirTUS
Благодарю. Кстати, визард все условия (из тех, что я использовал) ставит "если не это условие, тогда вернуть FALSE", что равноценно "если это условие, тогда вернуть TRUE". Какая из этих конструкций эффективнее?
Ilerien
Вторая.
Но гораздо изящнее без всяких проверок:
Neverwinter Script
int StartingContidional()
{
    return <условие>;
}
wirTUS
Еще раз спасибо.
Очередной вопрос: можно ли скриптом запретить игроку получать уровни в определенном классе до выполнения некоего условия?
Задумка: реализовать условия получения престиж-классов по 3.5 (вроде убить кого-либо, кого убивать у игрока причин не было для ассасина/ достижения мирных отношений (или чего-то вроде, я обычно использовал контракт) с вызванным злым аутсайдером для блэкгарда)
Ilerien
Можно. В таблицах требований к классам (cls_pres_*) есть тип пререквизита VAR, который требует локальной переменной с указанным названием и значением на персонаже. По дефолту для каждого престижа указана в таблицах своя переменная с требуемым значением 0, что с точки зрения требований к классу включает в себя и отсутствие данной переменной на персонаже. Для запрета левелапиться ассассином, скажем, достаточно вызвать такой код:
Neverwinter Script
SetLocalInt(oPC, "X1_AllowAsasin", 1); //oPC - игрок
Я для своего проекта, который находится в стадии разработки, довольно широко использую этот принцип, поскольку он имеет огромную гибкость. Скажем, если ввести аналогичную переменную для паладина, можно реализовать его ограничение на мультикласс из 3.5. С другой стороны, за этой переменной нужно очень аккуратно следить.
wirTUS
Большое спасибо

Опять проблема с условием
Neverwinter Script
int StartingConditional()
{
    return ((GetAbilityScore(GetPCSpeaker(), ABILITY_INTELLIGENCE, TRUE) > 13) && (HasItem(GetPCSpeaker(), "Mmod_water")) && ((HasItem(GetPCSpeaker(), "Mmodacid")) || (HasItem(GetPCSpeaker(), "Mmodacid_long")) || (HasItem(GetPCSpeaker(), "Mmodacid_strong"))));
}

(все между фиг. скобками записано в одну строчку, напихал по методу "вдруг поможет" скобок, кол-во открывающих вроде как совпадает)
Ругается "ERROR: UNKNOWN STATE IN COMPILER"
планировалась конструкция "условие и условие1 и (условие2 или условие3 или условие4)".
Так же: можно ли как-либо разрешить учить перформ кому угодно, а не только барду? Попробовал через хак с измененным CLS_SKILL_ROG.2da, в который добавлялся, собственно, перформ и ставился как класс скилл, но это не помогло.
Ilerien
Код правильный вроде, только скобок многовато.
Я бы навскидку сказал, что HasItem компилятор не признает из-за того, что не включена соответствующая библиотека через #include.

Добавить перформ вору можно именно так, как ты описал. Не знаю, где косяк - может, в подключении хаков. Попробуй выставить еще в skills.2da AllClassesCanUse в 1.
wirTUS
в 2da сейчас копаюсь, я там еще выставил неправильный skill index, а в скрипте действительно инклюд забыл, спасибо
wirTUS
Очередной вопрос: можно ли поменять сообщение, выдаваемое игроку при исполнении скрипта
Neverwinter Script
AdjustAlignment(oPC, ALIGNMENT_EVIL, -5);

с "Your actions have shifted your alignment -5 point(s) toward Evil" на какое-либо другое и, если да, как это сделать?
Ilerien
Простым способом нельзя. Вероятно, можно через NWNX Chat как-то изловить, но я этот плагин не ковырял.
wirTUS
Спасибо, попробую.

И еще вопрос: можно ли ставить скрипт, заполняющий инвентарь плэйсебла, на его onused, описывая плэйс как OBJECT_SELF, PC как GetLastUsedBy()?
Проблема: скрипт компилится нормально, стоит на onUsed сундука с активированными флагами Plot, Useable и Has Inventory, при попытке открыть персонажем 1го уровня(как свежесгенеренным, так и экспортированным) сундук открывается, но его инвентарь пустой. Т.к. существует возможность пустого сундука при верном исполнении скрипта, пробовал перезаходить (3 раза подряд) и, т.к. ограничения в одно использование в скрипте нету, пробовал открывать несколько раз подряд.
Собственно, скрипт.
Neverwinter Script
///////////////////////////////////////////////////////////////////
//Скрипт, спавнящий в плэйсеблы барахло///By HailAnDkilL aka///////
//почти по таблице 3-5(рандомные сокро-///wirTUS aka Бессонов//////
//вища) DMG 3.5. Различия в вещах(пред-///Георгий Борисович////////
//ставлено не все, ибо некоторых вещей/////////////////////////////
//в NWN нету, некоторые вещи бесполез-/////////////////////////////
//ны, а до некоторых не дошли руки) и//////////////////////////////
//в проверке не d100 и диапазоны вари-/////////////////////////////
//антов, а рандом(кол-во вариантов)+1//////////////////////////////
///////////////////////////////////////////////////////////////////
#include "NW_I0_GENERIC"

string sARMTAG()
{
string sSTR="MUNDANEARMOR";
int iMARMV = Random(13)+1;
int iMARMT = Random(9)+1;

switch(iMARMV)
{
case 10: sSTR=sSTR+"10_";
case 11: sSTR=sSTR+"11_";
case 12: sSTR=sSTR+"12_";
case 13: sSTR=sSTR+"13_";
default: sSTR=sSTR+"0"+IntToString(iMARMV)+"_";
}
sSTR=sSTR+IntToString(iMARMT);
return(sSTR);
}
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
string sWEAPTAG()
{
string sSTR="MUNDANEWEAPON";
int iMWEMV = Random(12)+1;
int iMWEMT = Random(4)+1;

switch(iMWEMV)
{
case 10: sSTR=sSTR+"10_";
case 11: sSTR=sSTR+"11_";
case 12: sSTR=sSTR+"12_";
default: sSTR=sSTR+"0"+IntToString(iMWEMV)+"_";
}
sSTR=sSTR+IntToString(iMWEMT);
return(sSTR);
}
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
void PGTC(int var1, int var2)
{
object oGOLD = GetObjectByTag("NW_IT_GOLD001");
object oCHEST = OBJECT_SELF;
SetItemStackSize(oGOLD, var1*var2);
ActionGiveItem(oGOLD, oCHEST);
}

void main()
{
object oPC = GetLastUsedBy();
object oCHEST = OBJECT_SELF;
int iPC_LVL = GetCharacterLevel(oPC);
int iVAR1 = Random(5)+1;
int iVAR2 = Random(3)+1;
int iVAR3 = Random(3)+1;
int iGEMV = d6(1);
string sTAG;
switch(iPC_LVL)
{
case 1:
        switch(iVAR1)
        {
        case 1: break;
        case 2: PGTC(d6(1),1);
        case 3: PGTC(d8(1),10);
        case 4: PGTC(d8(2),10);
        case 5: PGTC(d4(1),100);
        }/*
        switch(iVAR2)
        {
        case 1: break;
        case 2: sTAG="GEM"+IntToString(iGEMV);
        }*/

        switch(iVAR3)
        {
        case 1: break;
        case 2: ActionGiveItem(GetObjectByTag(sARMTAG()), oCHEST);
        case 3: ActionGiveItem(GetObjectByTag(sWEAPTAG()), oCHEST);
                }
        }
}

инклюд требуется для работы GetCharacterLevel, без него все равно не работало (использовалась сумма трёх GetLevelByPosition)
Ilerien
Здесь нужно использовать не ActionGiveItem(), которая применяется для передачи уже существующих предметов, а CreateItemOnObject().
Neverwinter Script
GetObjectByTag(sARMTAG()) //скорее всего, вернет OBJECT_INVALID
Цитата
инклюд требуется для работы GetCharacterLevel, без него все равно не работало (использовалась сумма трёх GetLevelByPosition)
Можно использовать GetHitDice() - это сразу общий уровень.
wirTUS
Исправил на
Neverwinter Script
#include "NW_I0_GENERIC"

string sARMTAG()
{
string sSTR="MUNDANEARMOR";
int iMARMV = Random(13)+1;
int iMARMT = Random(9)+1;

switch(iMARMV)
{
case 10: sSTR=sSTR+"10";
case 11: sSTR=sSTR+"11";
case 12: sSTR=sSTR+"12";
case 13: sSTR=sSTR+"13";
default: sSTR=sSTR+"0"+IntToString(iMARMV);
}
if(iMARMV<7) {sSTR=sSTR+"_"+IntToString(iMARMT);}
return(sSTR);
}
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
string sWEAPTAG()
{
string sSTR="MUNDANEWEAPON";
int iMWEMV = Random(12)+1;
int iMWEMT = Random(4)+1;

switch(iMWEMV)
{
case 10: sSTR=sSTR+"10_";
case 11: sSTR=sSTR+"11_";
case 12: sSTR=sSTR+"12_";
default: sSTR=sSTR+"0"+IntToString(iMWEMV)+"_";
}
sSTR=sSTR+IntToString(iMWEMT);
return(sSTR);
}
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
void PGTC(int var1, int var2)
{
string oGOLD = "NW_IT_GOLD001";
object oCHEST = OBJECT_SELF;
CreateItemOnObject(oGOLD, oCHEST, var1*var2, "");
}
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
void main()
{
object oPC = GetLastUsedBy();
object oCHEST = OBJECT_SELF;
int iPC_LVL = GetHitDice(oPC);
int iVAR1 = Random(5)+1;
int iVAR2 = Random(3)+1;
int iVAR3 = Random(3)+1;
int iGEMV = d6(1);
string sTAG;
switch(iPC_LVL)
{
case 1:
        switch(iVAR1)
        {
        case 1: break;
        case 2: PGTC(d6(1),1);
        case 3: PGTC(d8(1),10);
        case 4: PGTC(d8(2),10);
        case 5: PGTC(d4(1),100);
        }
        switch(iVAR3)
        {
        case 1: break;
        case 2: CreateItemOnObject(sARMTAG(), oCHEST, 1, "");
        case 3: CreateItemOnObject(sWEAPTAG(), oCHEST, 1, "");
                }
        }
}

Золото прилежно спавнит, вещи - нет. Тэги вещей заданы MUNDANEWEAPON[1-12]_[1-4], MUNDANEARMOR[1-6]_[1-9], MUNDANEARMOR[7-13]
Примеры тэгов: "MUNDANEWEAPON10_4", "MUNDANEARMOR01_5", "MUNDANEARMOR09"
Наиболее вероятно, что ошибка в процедурах, генерящих тэги
Ilerien
Теги тут вообще ни при чём. При создании объекта из палитры нужно указывать название ресурса (ResRef) - уникальный идентификатор ресурса в определённом пространстве имен (в данном случае, в пространстве наименований ресурсов предметов). Длина ресрефа (вообще для любого ресурса в NWN, хоть для скриптов или иконок) не превышает 16 символов - скажем, попытка создать предмет с ресрефом "MUNDANEWEAPON10_4" обречена на провал сразу же. smile.gif
wirTUS
Спасибо, сейчас буду исправлять, потом выложу что получится; перечитал описание CreateItemOnObject в Лексиконе, по тэгам можно вызывать только предметы стандартной палитры, почему собс-но золото и дается
Ilerien
Цитата
перечитал описание CreateItemOnObject в Лексиконе, по тэгам можно вызывать только предметы стандартной палитры, почему собс-но золото и дается
Это де-факто неправда. smile.gif Просто в стандартной палитре соблюдена конвенция - дефолтный тег предмета совпадает с его ресрефом, но написан в верхнем регистре. Строка, передаваемая в CreateObject/CreateItemOnObject(), автоматически конвертируется в нижний регистр, поэтому и так и получается. Никто не мешает соблюдать ту же конвенцию в кастомной палитре.
wirTUS
Исправил, работает, спасибо
wirTUS
Скрипт
Neverwinter Script
object GiveToChest(string str, int integer)
{
return CreateItemOnObject(str, OBJECT_SELF, integer, "");
}
object GetMundaneArmorByD100()
{
int i1 = d100(1);
int i2 = Random(9)+1;
int i3 = d100(1);

//   if(i1==1)
//   {
    return GiveToChest("ba13_"+IntToString(i2),1);
//   }
}
void MakeEnchMagicArmor(int Ench)
{
object oARMOR = GetMundaneArmorByD100();
string sNAME = GetName(oARMOR);
int i = GetStringLength(sNAME);
int n = FindSubString(sNAME, " мастерской работы");

while(i>=n)
{
  sNAME[i]=&#39;&#39;;
  i = i-1;
}
}

void main()
{
//int i1 = d100(1);
}

Выдает ошибку "NO SEMICOLON AFTER EXPRESSION"(нет точки с запятой после выражения) на строку "sNAME[i]='';". Пробовал вместо '' ставить "" или null, так же заменял
Neverwinter Script
while(i>=n)
{
  sNAME[i]=&#39;&#39;;
  i = i-1;
}

на
Neverwinter Script
while(n<=i)
{
  sNAME[n]=&#39;&#39;;
  n++;
}

все равно ругался
там, где
Neverwinter Script
&#39
было " ' " без пробелов
Ilerien
В нвскрипте нет массивов.
wirTUS
Т.е. отдельный символ строки получить нельзя, и, следовательно, строку нельзя уменьшить без полного изменения (приравнивания к меньшей строке)?

Решил порезать процедуру получения айтема, вставив ее в получение енча, соотв., куб кидается там же, соотв., по этому кубу сразу получается айтем, меняется имя и дается енч(пока еще не дается, но это не на долго). По идее, должно работать
Neverwinter Script
object GiveToChest(string str, int integer)
{
return CreateItemOnObject(str, OBJECT_SELF, integer, "");
}
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
}
void MakeEnchMagicArmor(int Ench)
{
object oARMOR;
int i1 = d100(1);
int i2 = Random(9)+1;

   if(i1==1)
   {
    oARMOR = GiveToChest("ba13_"+IntToString(i2),1);
    SetName(oARMOR, "+"+IntToSrting(Ench)+" Обитый доспех");
   }


}

void main()
{
//int i1 = d100(1);
}

Кстати, padded armor, переведенный как обитый доспех это нормально? Вроде у него в русском есть свое имя, на "б" что-то, кажется

Уже налипил лишнюю скобку и "srting" prankster2.gif

Цитата
Вроде у него в русском есть свое имя, на "б" что-то, кажется
Стеганка на "б" biggrin.gif
Ilerien
Цитата
Т.е. отдельный символ строки получить нельзя, и, следовательно, строку нельзя уменьшить без полного изменения (приравнивания к меньшей строке)?
Да. GetSubString() в помощь.

Багов на первый вгляд нет.

Переводом названий итемов не заморачивался, на английском всяко лучше. rolleyes.gif
wirTUS
А вот такой вопрос: что есть database и кастомный dialog.tlk, с чем их едят, в чем (и есть ли) преимущества кастомного "диалога" над стандартным?
Еще вопрос: можно ли для какого-нибудь feat'а, сделанного спеллом (как ярость варвара, например) сделать радиальное меню с выбором из n вариантов (как клик ПКМ на игрока)?
Если да, то
1)Как?
2)Можно ли сделать многоуровневое радиальное меню (как ПКМ на игрока - spells - wizard - VI)?
3)Можно ли, "достраивать" это меню по ходу игры (например, прошел игрок по триггеру и бац! в меню фита новый пункт)?
Keks
1) database - папка игры, где содержаться данные о встроенной БД (да и сама БД тож);
2) кастомный dialog.tlk - основной тлк игры, содержит текст, который используется как в самой игре, палитрах, так и во всех менюшках запуска nwn.exe. Если вносить изменения в него, то необходимо "закинуть" измененный файл в корень игры и в папку тлк. Система кастомного диалога была разработана биоварями для шардов (разный шарды = разные тлк), в то время как дефолтный вносит изменение во все с момента запуска игры
3) Да можно.
3.1 ) Создать фит и выдать его чару/ сделать выборным через cls_feat_***.2da, в последнем столбце поставив "1" это отразит фит в радикальном меню класса.
3.2 ) Можно - смотри по аналогии с многоуровневыми заклинаниями (например шейпы перевертыша).
3.3 ) Да можно - выдавать фиты (правда я делал это с применением нвнх, отключенным дефолтным ЕЛЦ и соответственно включенным своим ЕЛЦ wink3.gif )
Ilerien
База данных в НВН бывает внутренней (стандартные средства вроде SetCampaignInt() и т. д.) и внешней (я пользуюсь MySQL, прикрученным через NWNX ODBC). Выгоды от использования очевидны - возможность сохранять информацию вне зависимости от рестартов сервера.

Измененный dialog.tlk используется, когда хочется изменить какие-то строки, не поддающиеся переписыванию через 2да (скажем, название урона), или если критично видеть при создании персонажа измененные описания классов/фитов/заклинаний/.. Использовать не рекомендуется - потому что эта замена для клиента распространяется на все. smile.gif
Кастомный tlk - это отдельный tlk-файл, который подключается непосредственно к модулю. Хорош всем, кроме того, что строки из него при создании персонажа и заходе на сервер не видны.
Цитата
Еще вопрос: можно ли для какого-нибудь feat'а, сделанного спеллом (как ярость варвара, например) сделать радиальное меню с выбором из n вариантов (как клик ПКМ на игрока)?
Если да, то
1)Как?
2)Можно ли сделать многоуровневое радиальное меню (как ПКМ на игрока - spells - wizard - VI)?
3)Можно ли, "достраивать" это меню по ходу игры (например, прошел игрок по триггеру и бац! в меню фита новый пункт)?
Можно.
1) Сделав целевое заклинание состоящим из подзаклинаний, как всяческие теневые вызывания. Там есть грабли, которые я не так давно описывал в окрестности этой темы - поиск в помощь.
2) Нет.
3) Нет.
wirTUS
Огромное спасибо
wirTUS
А вот вопрос по NWNx: куда и как он девает бд, созданую скриптом (был поюзан скрипт из примера по odbc)? Поиском обшарил на pwdata весь компьютер, ничего не нашел
Ilerien
Странный вопрос. Честно говоря, я не помню, как MySQL хранит данные на харде, но зачем это вообще понадобилось? Есть удобный интерфейс для доступа к данным, зачем их физически на харде отлавливать?
Сам мускуль-то поставил? Без него (ну или SQLite/Postgres - но с мускулем проще всего) этот плагин в принципе работать не будет.
Laajin
Там при распаковки NWNx в директорию игры по умолчанию стоит другой тип БД не MySQL, нужно в ручную за коментить в настройках NWNx ее и раскоментить MySQL. Может, в этом проблема?
wirTUS
Я сначала попробовал в ацесс, в mysql попробовал создать скриптом из nwnx'овского демо модуля, на \u nonamedb (поменял в скрипте с pwdata на nonamedb) ругается ERROR 1049 <42000>: Unknown database 'nonamedb'. Предварительно создал nwnx'ом хост и зашел до вылета, скрипт должен был сработать
Цитата
Там при распаковки NWNx в директорию игры по умолчанию стоит другой тип БД не MySQL, нужно в ручную за коментить в настройках NWNx ее и раскоментить MySQL. Может, в этом проблема?
Понял, меняю
Цитата
Я сначала попробовал в ацесс, в mysql попробовал создать скриптом из nwnx'овского демо модуля, на \u nonamedb (поменял в скрипте с pwdata на nonamedb) ругается ERROR 1049 <42000>: Unknown database 'nonamedb'. Предварительно создал nwnx'ом хост и зашел до вылета, скрипт должен был сработать

Поставил настройки под mysql, скорее всего через скрипт получить доступ к БД получится, через mysql идет та же ошибка. С бд в принципе и mysql в частности до вчерашнего дня дела не имел, наверняка где-то тут кроется причина
Keks
я как человек не искушенный в БД через SQLite подключал
denis0k
Цитата
С бд в принципе и mysql в частности до вчерашнего дня дела не имел, наверняка где-то тут кроется причина
Самое простое - взять сборку типа денвера, там есть субд и веб-сервер со специальной мордой для взаимодействия с мусклом. Для разработки - самое то.
Цитата
я как человек не искушенный в БД через SQLite подключал
Если с бд будет взаимодействовать только сервер (т.е. никаких армори, онлайн-списков игроков, пополнения всякой фигни дмами в реальном времени и прочее), то это идеальный вариант. БД будет в файле, так что никакого гемора с настройкой субд и потерей коннекта. Благодаря реконнекту последнее не очень очевидно, но вылезает в виде забавных багов smile.gif
Keks
Берем любой плагин для БД (я юзаю SQLite Expert Personal version 2.3.49), устанавливаем его на комп, затем берем папочку НВН и дублируем ее (скажем обозвав NWN_Server) в тот же каталог, где стоит клиентская версия, таким образом получается 2 папки, полностью подобные, но с разными названиями. Я работаю только в папке NWN_Server (правлю модуль, создаю ерки и пр.), из нее же запускаю NWNX, а из клиентской папки запускаю только игровой процесс.
Таким образом ставить виртуальные сервера на комп НЕ НАДО. Таким образом уже года 3 все пашет оки.

Цитата
Благодаря реконнекту последнее не очень очевидно, но вылезает в виде забавных багов smile.gif
Если честно, как-то не замечал багов, хотя человек спрашивает для "рабочей машины", т.е. дома делать неискушенному человеку, повторюсь, тут это оптимальный вариант, а для сервера да, лучше MYSQL

З.ы. А отредактировать чара в момент создания артмани и ему подобными можно, т.к. чар создается локально и только после нажатия кнопочки "Играть" в первый раз дублируется на сервере в папке аккаунта. Т.е. изначально чар локален, а следовательно с ним мона делать все, что душе угодно. Выдача плюшек и "всякой фигни" ДМами обрабатывается движком сервера по запросу из ДМклиента, т.ч. таким образом можно редактировать чаров игроку.
Talarasha
Вопрос по работе с освещением. В модуле понадобился аналог "призрачного зрения", как в XP2 с кольцом. По определенным причинам смена освещения через смену дня и ночи мне не подошла (не хотелось отказываться от стандартного ночного освещения), поэтому делал руками, через SetTileSourceLightColor(). Проблемы как таковых две - не дает результата применение черного цвета к источнику света (погасить не удается), но здесь, я думаю, ничего не сделать - так во всяком случае лексикон говорит. Во-вторых, не могу после возврата в нормальный режим корректно вернуть цвета, даже с помощью RecomputeStaticLighting(). Сначала думал, что ошибка в алгоритме, которым я запоминаю исходные цвета, но перезаход в область восстанавливает корректно. В чем ошибка, можно ли как-то обойти?

Код для ознакомления:
Neverwinter Script
void EtherealVision(int Color1, int Color2, int Recovery = 0)
{
    object oPC = GetFirstPC();
    object oArea = GetArea(OBJECT_SELF);
    int Height = GetAreaSize(AREA_HEIGHT);
    int Width = GetAreaSize(AREA_WIDTH);
    vector v = Vector(0.0f, 0.0f, 0.0f);
    location Pointer;

    // Main cycle; 10.0f is because Tile functions has it's own coordinate
    // system (we got coordinate of points and tile functions uses coordinate
    // of grid (integer number of squares, first square [0][0] is a bottom left)
    while(v.y < Height * 10.0f)
    {
        v.x = 0.0f;
        while(v.x < Width * 10.0f)
        {
            v = Vector(v.x/10.0, v.y/10.0, 0.0f);
            Pointer = Location(oArea,v,0.0f);
            if(Recovery == 0) // Remember colors
            {
                SetLocalInt(oArea,"TILECOLOR1"+IntToString(FloatToInt(v.x)) + IntToString(FloatToInt(v.y)),
                    GetTileSourceLight1Color(Pointer));
                SetLocalInt(oArea,"TILECOLOR2"+IntToString(FloatToInt(v.x)) + IntToString(FloatToInt(v.y)),
                    GetTileSourceLight2Color(Pointer));
            }
            else // Recover colors if it's a recovery call
            {
                Color1 = GetLocalInt(oArea,"TILECOLOR1"+IntToString(FloatToInt(v.x)) + IntToString(FloatToInt(v.y)));
                Color2 = GetLocalInt(oArea,"TILECOLOR2"+IntToString(FloatToInt(v.x)) + IntToString(FloatToInt(v.y)));
            }
            SetTileSourceLightColor(Pointer,Color1,Color2);
            v = Vector(v.x*10.0, v.y*10.0, 0.0f);
            v.x = v.x + 10.0f;
        }
        v.y = v.y + 10.0f;
    }
    RecomputeStaticLighting(oArea);
}

По "функция(цвет1,цвет2)" включает режим, по "функция(0,0,1)" выключает.
virusman
Динамическое освещение в НВН вообще глючное, и RecomputeStaticLighting работает криво. Видимо, это один из его багов, наряду со свечением у плейсов после его выполнения.
ReZkiy
А как сделать,что бы НПС ходил туда-сюда от сундука к сундуку и совершал анимацию "открыть ключом"?
wirTUS
Ставится на триггер (например, у двери, за которой находится NPC. Наиболее оптимальный метод, ибо NPC начнет ходить только тогда, когда его видят (в зависимости от того, для мультиплеера модуль или нет надо дописывать прерывание похождений, когда перестают видеть)) на событие OnEntered

Neverwinter Script
void main()
{
object
        oNPC = GetNearestObjectByTag("NPCTag", GetEnteringObject()),
//Ходить будет ближайший к игроку NPC c тэгом NPCTag
        oCont1 = GetNearestObjectByTag("Container1Tag", oNPC),
//Обозначаем первый сундук. Это окажется ближайший к NPC сундук с тэгом Container1Tag.
        oCont2 = GetNearestObjectByTag("Container2Tag", oNPC);
//Обозначаем второй сундук. Это окажется ближайший к NPC сундук с тэгом Container2Tag.

vector vPos;
//Для дальнейшего использования

int i = 0;
//Для дальнейшего использования

AssignCommand(oNPC, ClearAllActions(TRUE))
while(i<1)
//1 - количество проходов NPC по маршруту
//[позиция NPC] - первый сундук - второй сундук,
{
  ++i;
  //закомментировать строчку выше - плохая идея, ибо при попытке использования бесконечного цикла
  //nwn благополучно зависает
  AssignCommand(oNPC, ActionMoveToObject(oCont1, FALSE));
  //NPC идет к первому сундуку

  vPos = GetPosition(oNPC);
  AssignCommand(oNPC, ActionJumpToLocation(Location(GetArea(oNPC), vPos, 360-GetFacing(oCont1))));
  //Поворачиваем NPC к сундуку

  AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 3.0));
  //После того, как NPC подошел к сундуку, идет проигрышь анимации ANIMATION_LOOPING_GET_LOW
  //(можно заменить на цифру 12, см. лексикон на "ANIMATION_* Constant Group") со стандартной
  //скоростью (1.0 - коэффициент скорость относительно начальной скорости анимации, т.е.
  //заменив 1.0 на большее число можно увеличить скорость проигрыша анимации, аналогично можно
  //ее уменьшить) в течение трех секунд (3.0) (коэффициент скорости влияет только на время
  //проигрыша FnF-анимаций, которыми не используется параметр времени проигрыша)
  AssignCommand(oNPC, ActionMoveToObject(oCont2, FALSE));
  //NPC идет ко второму сундуку

  vPos = GetPosition(oNPC);
  AssignCommand(oNPC, ActionJumpToLocation(Location(GetArea(oNPC), vPos, 360-GetFacing(oCont2))));
  //Поворачиваем NPC к сундуку

  AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 3.0));
  //аналогично предыдущему
}
}

ВНИМАНИЕ:
Neverwinter Script
vPos = GetPosition(oNPC);
возвращает стартовую позицию NPC, а не нынешнюю. Следовательно, "поворачивание" NPC будет работать криво. Чтобы работало прямо, надо найти метод получения вектора местонахождения на момент запроса и заменить GetPosition(oNPC) на него. Есть подозрение, что такая проблема возникла из-за использования стека. Альтернативный метод выпила данной кривоты - удаление "поворотов" из скрипта и расставление сундуков друг напротив друга, желательно строго напротив.
ReZkiy
Цитата(wirTUS @ Sep 9 2011, 19:14) *
Ставится на триггер (например, у двери, за которой находится NPC. Наиболее оптимальный метод, ибо NPC начнет ходить только тогда, когда его видят (в зависимости от того, для мультиплеера модуль или нет надо дописывать прерывание похождений, когда перестают видеть)) на событие OnEntered

Neverwinter Script
void main()
{
object
        oNPC = GetNearestObjectByTag("NPCTag", GetEnteringObject()),
//Ходить будет ближайший к игроку NPC c тэгом NPCTag
        oCont1 = GetNearestObjectByTag("Container1Tag", oNPC),
//Обозначаем первый сундук. Это окажется ближайший к NPC сундук с тэгом Container1Tag.
        oCont2 = GetNearestObjectByTag("Container2Tag", oNPC);
//Обозначаем второй сундук. Это окажется ближайший к NPC сундук с тэгом Container2Tag.

vector vPos;
//Для дальнейшего использования

int i = 0;
//Для дальнейшего использования

AssignCommand(oNPC, ClearAllActions(TRUE))
while(i<1)
//1 - количество проходов NPC по маршруту
//[позиция NPC] - первый сундук - второй сундук,
{
  ++i;
  //закомментировать строчку выше - плохая идея, ибо при попытке использования бесконечного цикла
  //nwn благополучно зависает
  AssignCommand(oNPC, ActionMoveToObject(oCont1, FALSE));
  //NPC идет к первому сундуку

  vPos = GetPosition(oNPC);
  AssignCommand(oNPC, ActionJumpToLocation(Location(GetArea(oNPC), vPos, 360-GetFacing(oCont1))));
  //Поворачиваем NPC к сундуку

  AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 3.0));
  //После того, как NPC подошел к сундуку, идет проигрышь анимации ANIMATION_LOOPING_GET_LOW
  //(можно заменить на цифру 12, см. лексикон на "ANIMATION_* Constant Group") со стандартной
  //скоростью (1.0 - коэффициент скорость относительно начальной скорости анимации, т.е.
  //заменив 1.0 на большее число можно увеличить скорость проигрыша анимации, аналогично можно
  //ее уменьшить) в течение трех секунд (3.0) (коэффициент скорости влияет только на время
  //проигрыша FnF-анимаций, которыми не используется параметр времени проигрыша)
  AssignCommand(oNPC, ActionMoveToObject(oCont2, FALSE));
  //NPC идет ко второму сундуку

  vPos = GetPosition(oNPC);
  AssignCommand(oNPC, ActionJumpToLocation(Location(GetArea(oNPC), vPos, 360-GetFacing(oCont2))));
  //Поворачиваем NPC к сундуку

  AssignCommand(oNPC, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 3.0));
  //аналогично предыдущему
}
}

ВНИМАНИЕ:
Neverwinter Script
vPos = GetPosition(oNPC);
возвращает стартовую позицию NPC, а не нынешнюю. Следовательно, "поворачивание" NPC будет работать криво. Чтобы работало прямо, надо найти метод получения вектора местонахождения на момент запроса и заменить GetPosition(oNPC) на него. Есть подозрение, что такая проблема возникла из-за использования стека. Альтернативный метод выпила данной кривоты - удаление "поворотов" из скрипта и расставление сундуков друг напротив друга, желательно строго напротив.

О-о-огромное спасибо!Я буду теперь равняться на тебя и учиться писать такие же сложные скрипты!Я научусь,будь уверен!
nepejke
всем привет, поспорил с человеком, насчёт возможности сокращения кода в нвн1.
существует ли возможность, создать отдельный скрипт который будет просчитывать метамагию, кастерлвл, спеллпенетру
дабы не захлямлять этим строчки в скрипте каждого спелла. Так вот, реально ли это всё соединить в 1 инклюд скажем, чтобы не писать в каждом спелле???

цит: "У НОРМАЛЬНЫХ ЛЮДЕЙ, а разрабы нвн по ходу не очень нормальные функция
http://www.nwnlexicon.com/compiled/functio...tlastspell.html - несла бы с собой все нужное от спелла, после того как спелл все посчитает:
Для боевых спеллов это только
getlastspell(dam) - посчитанный урон
getlastspell(dam_type) - тип урона

http://www.nwnlexicon.com/compiled/functio...pellcaster.html - она бы несла с собой такие вещи:
getlastspellcaster(sLevel) - с левел в зависимости от уровня колдующего.
getlastspellcaster(s_meta) - с какой метой пришел спелл
ну и так далее для любых спеллов где что нужно.

Далее, как будет выглядеть только в таком минимуме:
OnSpellCastAt скрипт

Код: [Выделить]
//Make SR Check
if (!MyResistSpell(OBJECT_SELF, getlastspellcaster(sLevel)))
{
//Make metamagic checks
if (getlastspellcaster(s_meta) == METAMAGIC_MAXIMIZE)
{
nDam = getlastspell(dam) + getlastspellcaster(sLevel); //Damage is at max
}
if (getlastspellcaster(s_meta) == METAMAGIC_EMPOWER)
{
nDam = getlastspell(dam) + (getlastspell(dam)/2); //+50% to Damage
}
//здесь же экстенд спелл для длительности, впадлу дописывать. А вот сайлент хуяйлент должны так же отдельно обрабатываться в каком нибудь _onspellcast
//все, посчитали да, теперь эта же функция наносит урон, с утра впадлу искать чем он там наносит будем так
f.damage(nDam, getlastspell(dam_type))
//СЮДА ЖЕ ДОПИСЫВАЮТСЯ ПЕРЕД f.damage все абсорбящие заклинания. Надеюсь понятно да как это происходит?

И в итоге КАЖДЫЙ СПЕЛЛ В НВН получает минус 15 строк не теряя абсолютно своего функционала и возможность вносить в него изменения меняя только циферку, можно дописать в него любые эффекты, и прочее.
Это за вычетом того, что функция потом будет нести в себе абсорбы с защитных спеллов, что разгрузит ту функцию, которая считает абсорбы и прочее, я думаю, что она тоже дублирована раз 50.
Да и сама механика абсорбов сведется к одному таймеру с набором переменных для окончания длительности, а количество абсорбов будет висеть просто на чаре. Это открывает нормальное суммирование эффектов абсорбов и прочее.
Так же ЭТОТ ЕВЕНТ МОЖЕТ ОТВЕЧАТЬ И ЗА ЛЕЧАЩИЕ СПЕЛЛЫ ТЕМ САМЫМ РАЗГРУЗИВ И ИХ.
Вот и посчитай, насколько меньшим и удобным будет код. "


я думаю что это не возможно, что думаете вы?
Ilerien
Нет такой возможности в НВН. Не говоря уж о том, что OnSpellcastAt слот используется совсем для других целей.
Твоя гипотетическая реализация - крайне негибка, стоит придумать нетривиальный спелл, и его реализация немедленно добавит десяток строчек в пухнущий свич общего скрипта по spellid. Биоварская реализация, если и не оптимальна, то близка к этому.
ReZkiy
Цитата(ReZkiy @ Sep 9 2011, 23:34) *
О-о-огромное спасибо!Я буду теперь равняться на тебя и учиться писать такие же сложные скрипты!Я научусь,будь уверен!

А больше нет никаких предложений,люди???ПОМОГИТЕ ЕЩЕ!!!
wirTUS
Цитата
ПОМОГИТЕ ЕЩЕ!!!

Можно попробовать заменить
Neverwinter Script
...ActionPlayAnimation(...));
на
Neverwinter Script
...ActionUnlockObject(oContN));
AssignCommand(oNPC, ActionLockObject(oContN));
и выпилить повороты. Возможно между локом и анлоком красоты ради поставить паузу, опять же при желании можно сделать, чтобы перед тем, как открыть сундук непись посмотрел по сторонам (чтобы он при этом реагировал на игрока - уже сложнее и включает как минимум чек хайда игрока, если он хайдится, аналогично со спрятанностью (Concleated или что-то вроде), проверки на наличие невидимостей и грейтер санкураси и, собственно, реакцию, если игрок будет замечен). А так же вполне возможно, что вообще работать не будет, нету что-то желания проверять.
Цитата
Я буду теперь равняться на тебя и учиться писать такие же сложные скрипты!

Равняться на меня не стоит, не настолько-то из меня и хороший скриптер. Лучше прочитай эту тему и, если еще не прочитал, то "Скрипты новичкам", может найдешь что-нибудь, что пригодится.
ReZkiy
Цитата(wirTUS @ Sep 10 2011, 20:12) *
Можно попробовать заменить
Neverwinter Script
...ActionPlayAnimation(...));
на
Neverwinter Script
...ActionUnlockObject(oContN));
AssignCommand(oNPC, ActionLockObject(oContN));
и выпилить повороты. Возможно между локом и анлоком красоты ради поставить паузу, опять же при желании можно сделать, чтобы перед тем, как открыть сундук непись посмотрел по сторонам (чтобы он при этом реагировал на игрока - уже сложнее и включает как минимум чек хайда игрока, если он хайдится, аналогично со спрятанностью (Concleated или что-то вроде), проверки на наличие невидимостей и грейтер санкураси и, собственно, реакцию, если игрок будет замечен). А так же вполне возможно, что вообще работать не будет, нету что-то желания проверять.

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

Слушай,это все очень муторно.Можно сделать такой скрипт,что бы он стоял в OnHeartBeat НПС и тот делал нужные мне действия?
wirTUS
Цитата
Слушай,это все очень муторно.

Заменить две строчки и удалить еще четыре - муторно? shok.gif
Цитата
Можно сделать такой скрипт

Можно.
Цитата
OnHeartBeat НПС

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

Писал скрипты? biggrin.gif
offtopic.gif
ReZkiy
Цитата(wirTUS @ Sep 10 2011, 21:22) *
Заменить две строчки и удалить еще четыре - муторно? shok.gif

Можно.

Хертбит лучше не использовать если есть альтернативы, ввиду того, что он сильно загружает модуль
offtopic.gif

Писал скрипты? biggrin.gif
offtopic.gif

Молодец,чувство юмора имеется.Я сам в скриптах не очень,поэтому тебя спросил.Можешь такой подкинуть или нет?Только ответь нормально,без этих шуточек.
wirTUS
Цитата
Я сам в скриптах не очень

Основываясь на весьма посредственных знаниях (!)паскаля, лексиконе, в/о с данного сайта вообще и в/о со страниц 136, 137 и 138 (а так же стр. 133, но тогда я еще по нулям был даже в паскале) данной темы я получил весьма неплохие знания (по моему мнению, ес-сно. На данной странице писали как минимум пять человек, по сравнению с которыми я, имхо, нуб и позорюсь smile.gif ) нвскрипта.
Цитата
Можешь такой подкинуть или нет?

Все еще не вижу смысла в использовании ХБ. Если нужно заставить NPC вечно ходить открывать-закрывать сундуки, то первое, что пришло в голову: OnSpawn непися дописывается/ставится скрипт, заставляющий идти к первому сундуку и открыть его. На OnOpen сундука идет проверка, кто открыл, и если это нужный нам непись, то заставляем открывшего закрыть и пойти к другому сундуку, на котором повторяется то же, но учитывая, что сундук другой. Писать за тебя не буду, но попробую понятно привести лексику, что тут понадобится.
Основа
Neverwinter Script
void main() //обозначение, гхм, начала скрипта (на самом деле - процедура, но это сейчас совсем не нужно)
{ //совсем начало скрипта, только после которого можно записывать то, что скрипт делает
} //обозначает конец скрипта (в данном случае)

Переменные, их объявление и математика (возможно, страшно звучит, но пугаться не стоит: все донельзя легко)
Neverwinter Script
//Переменная - буквоциферный идентификатор чего-то (например: цифре, букве, фразе), при помощи которого можно использовать это что-то
//Объявление переменной - "говорим" скрипту, что существует такой-то идентификатор, принадлежащий к такому-то типу (см. ниже)
//Тип переменной - что может идентифицировать переменная (например, целое число). Переменная, принадлежащая к целочисленному типу не может
//обозначать, например, букву.
//Общий вид объявления переменных
/*
[тип переменной] [идентификатор1];
//или
[тип переменной] [идентификатор1] = [значение1];
//или
[тип переменной] [идентификатор1], [идентификатор2];
[другой тип переменной] [идентификатор3], [идентификатор4];
//можно комбинировать, например:
[тип переменной] [идентификатор1] = [значение1], [идентификатор2];
[другой тип переменной] [идентификатор3], [идентификатор4] = [значение2];
*/

//Список типов переменных (возможно, неполный, максимальные и минимальные значения для каждого типа описывал где-то по соседству)
/*
int - целые числа (-1; 0; 1; 2 и т.д.)
float - рациональные числа (-1.0; -0.5; 0.0; 0.5; 1.0 и т.д.)
string - буквы и строки ("a"; "abc"; "abcdefg"; "aaanbhdjfjkdfsljfh" и т.п.)
vector - координаты в трехмерном пространстве. Можно получить при помощи Vector([координата x], [координата y], [координата z]). x, y и z принадлежат float, но не обязательно являются переменными (по сути - использование переменных не обязательно и можно использовать запись Vector(1.0, 3.0, 7.5) (обращаю внимание на большую букву (регистр играет роль): с маленькой буквы получится объявление переменной типа вектор, с большой - получение значения типа вектор из трех координат), но с переменными удобнее.) Далее принадлежность переменной к какому-либо типу буду обозначать [тип] [идентификатор]
location - подробное описание местоположения чего-либо. Аналогично вектору, можно получить при помощи Location(object oArea (об объектах речь далее), vector vPosition, float fOrientation (поворот по градусам, где север - 90 градусов (см. Лексикон SetFacing)));
object - вероятно, наиболее часто используемый в нвскрипте тип. Включает в себя созданий (creature, в т.ч. и игроков), вещи, плэйсы и т.д. За подробностями - в Лексикон, OBJECT_TYPE (кроме того, что включает в себя тип object там еще можно узнать, как обозначить тот или иной подтип объекта для специфических функций, этого требующих (пока не надо))
*/

//Пример объявления переменных и примитивных мат. действий
void main()
{
int nNum = 7, nN = 5, nNumber = 4; //создаем переменные и присваиваем им значения. Т.е. создели целочисленную переменную nNum и задали
int nResult;                                     //(присвоили) ей значение 7
nResult = nNum - nN;               //присвоили переменной nResult значение разности переменных nNum и nN, т.е. nResult = nNum - nN = 7 - 5 = 2
nResult = nResult * nNumber;   //присвоили переменной nResult собственное значение, умноженное на nNumber, т.е. nResult = nResult * 4 = 2 * 4 = 8
nResult = nResult * nNumber;   //повторяем предыдущее действие. НО после предыдущего действия значение переменной nResult изменилось, стало
                                               //равным восьми. Следовательно, теперь nResult = nResult * nNumber = 8 * 4 = 32
//предположим, что это скрипт, стоящий на OnOpen плэйса-контейнера
object oPC = GetLastOpenedBy(); //в таком случае GetLastOpenedBy() будет работать, ее значением будет являться (далее: он(а) возвращает
//значение) объект (наиболее вероятно, что это будет существо, но да не суть важно), открывший контейнер.
object oArea = GetArea(oPC); //GetArea(object oObj) возвращает объект-арию (локацию в плане продукта работы маппера), в которой находится
//объект oObj, в данном случае арию, где находится существо, открывшее контейнер
float fX = 6.0, fY = 7.0 - 1.0, fZ = 16.0/16.0 - 2.0; //да, значением может являться результат математического действия.
vector vPos = Vector(fX, fY, fZ); //три вышеописанных числа были использованы для создания вектора
vPos = GetPosition(oPC); //а теперь мы записали в переменную vPos координаты существа, открывшего контейнер, тем самым удалив предыдущее
vector vPos2 = Vector(fX, fY, fZ); //значение. Но в данном случае его нетрудно восстановить, что только что мы и сделали
location lLoc = Location(oArea, vPos, 90.0); //А теперь, воспользовавшись вышеполученными арией и вектором мы получили  из них локацию,
location lLoc2 = GetLocation(oPC); //совпадающую с локацией открывшего, только с ориентацией на север. А сейчас мы присвоили некой переменной
lLoc = lLoc2; //lLoc2 локацию открывшего контейнер, без изменений. И приравняли к ней переменную lLoc.
}

Условия и логика
Neverwinter Script
/*
Если (на что я очень надеюсь) известны неравенства, то с примитивными условиями и такой же логикой проблем возникнуть не должно.
Как выглядит условие в нвскрипте? Очень просто:
if([условие])
{
[часть скрипта, которая будет выполнена, если условие верно и проигнорирована в противном случае]
}
else
{
[часть скрипта, которая будет выполнена, если условие неверно]
}
Так выглядит условие в полном виде (т.н. полный условный оператор)
Так же можно использовать краткую его версию:
if([условие])
{
[часть скрипта, которая будет выполнена, если условие верно и проигнорирована в противном случае]
}
Теперь: как получить логическое выражение, которое должно быть использовано как условие? Есть несколько вариантов:
1) использовать 0 и 1 как логические выражения (0 - неверное условие (в любом случае), 1 - верное)
2) использовать "неравенства", например, nNum<nN (данное условие будет верно, если переменная nNum меньше, чем nN, следовательно nNum и nN
    должны быть обе одного типа: или int, или float. Ес-сно сравнить локацию и целое число не получится)
   Список для неравенств:
    > строго больше
    < строго меньше
    <= нестрого меньше
    >= нестрого больше
    == равно
    != не равно
*/

//Сложные условия
/*
А что, если нам надо выполнение одновременно нескольких условий? А делать нужно вот что:
if([условие][логическая операция][условие1] ...[логическая операция][условиеN])
{}
Логические операции
||    или
&&  и
==  равно     //логические выражения тоже можно сравнивать, но только при помощи "равно" или "не равно"
!= не равно
Что же это означает? Пример:
условие || условие1
будет считаться верным, если верно только одно из условий. Пример1:
условие && условие 1
будет считаться верным, если верны оба условия одновременно. Пример2:
(условие && условие1) || условие2
будет считаться верным, только если ЛИБО первые два условия будут одновременно верны, ЛИБО если верно ТОЛЬКО третье условие
! считается знаком отрицания, т.е. логическое выражение !(условие) будет верным, только если условие будет неверным. Пример3:
(условие || условие1) && !(условие2)
будет считаться верным, если верно ТОЛЬКО ОДНО из первых двух условий И ОДНОВРЕМЕННО С ЭТИМ НЕ будет верно третье условие
*/

//Пример сложных и не очень условий
void main()
{
int bFlag = FALSE, nN; //0 и 1 можно записывать как FALSE и TRUE соответственно
if(!bFlag)
{
  nN = 100;
  if(nN<100)
  {nN = 100;}
  else
  {nN = 0;}
}
if((nN == 0) && (nN != 1) && !(nN == 1)) //тут написан бред. Достаточно ограничиться лишь nN == 0, т.к. если nN равно нолю, то в любом случае она не
//равна единице. А так же условия nN != 1 и !(nN == 1) - одно и то же.
{nN = 0;} //Бессмысленное действие, т.к. нету смысла приравнивать nN к нолю, если она уже равна нолю (см. пред. условие)
}

Агась, а теперь домашнее задание: посмотреть в Лексиконе функции, названия которых написаны ниже и понять как их использовать
GetLastOpenedBy
GetTag
GetObjectByTag
GetNearestObjectByTag
AssignCommand
ActionMoveToObject
ActionLockObject
ActionUnlockObject
Эти функции понадобятся тебе для твоих хождений по сундукам. Если поймешь, как их использовать (если при этом понял, что я писал выше, хех), то сможешь эти хождения по сундукам написать сам. Если хочешь, чтобы ходящий по сундукам, например, оглядывался по сторонам, перед тем, как открыть сундук, то посмотри ActionPlayAnimation. Если хочешь еще и всяких ништяков вроде свечений и прочего, посмотри effect (это тип, тут, скорее всего, понадобится английский), EffectVisualEffect и ApplyEffectToObject.
Как-то так
greye
Цитата(wirTUS @ Sep 11 2011, 02:42) *
Все еще не вижу смысла в использовании ХБ. Если нужно заставить NPC вечно ходить открывать-закрывать сундуки, то первое, что пришло в голову: OnSpawn непися дописывается/ставится скрипт, заставляющий идти к первому сундуку и открыть его. На OnOpen сундука идет проверка, кто открыл, и если это нужный нам непись, то заставляем открывшего закрыть и пойти к другому сундуку, на котором повторяется то же, но учитывая, что сундук другой.

Если оставить только вызов на onSpawn, то после любого чиха (диалог, бой) непись перестанет ходить по сундукам.
Ко всему вышесказанному можно просмотреть x0_i0_walkway как пример.
denis0k
x0_i0_walkway - это просто ад и яркий пример того, как делать нельзя smile.gif Там функция запускается из спавна, хертбита и хз чего ещё, а потом ещё рекурсивно вызывает сама себя каждую секунду.

http://www.city-of-masters.ru/forums/index...?showtopic=5123


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

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

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

Если это сингл, но проще запихнуть в хб и не трахать мозги smile.gif Один голый скрипт игру не повесит.
wirTUS
offtopic.gif
Цитата
На данной странице писали как минимум пять человек, по сравнению с которыми я, имхо, нуб и позорюсь

Шесть biggrin.gif
offtopic.gif
gennady
Цитата(denis0k @ Sep 11 2011, 10:25) *
x0_i0_walkway - это просто ад и яркий пример того, как делать нельзя Там функция запускается из спавна, хертбита и хз чего ещё, а потом ещё рекурсивно вызывает сама себя каждую секунду.

+1
Я тоже выкинул неверский WalkWayPoints что сильно улучшило быстродействие.
Про скрипты НВ для сингла даже написал статейку http://remmgen.narod.ru/tscript3.html#SC_HB
Ilerien
Цитата
Во-вторых, если заморочиться, вместо выключения можно написать деспавн. Я так делал для стражи на шарде. Все остальные неписи были без скриптов, стража - полностью боевая и с точками ходьбы. При выходе игроков из локации стража удалялась, заменяясь простыми вейпоинтами, а при входе - ставилась заново.
Интересный вариант. Надо попробовать их в лимбо кидать (NWNX Funcs умеет), возможно, вместе с проверкой на лимбо будет дешевле, чем пересоздание.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.
Invision Power Board © 2001-2024 Invision Power Services, Inc.