Скрипты: Все вопросы, Алгоритмы, оптимизация, особености и хитрости в скриптинге |
Здравствуйте, гость ( Вход | Регистрация )
Скрипты: Все вопросы, Алгоритмы, оптимизация, особености и хитрости в скриптинге |
Apr 2 2006, 19:41
Сообщение
#1
|
|
Level 5 Класс: Обыватель Характер: Lawful Neutral Раса: Человек NWN: Модмейкер Проклятие Левора Порядок Времени |
Обсуждение каки-то непонятных моментов в алгоритме, вариантов использования функций, оптимизация скриптов. Тут можно обсудить алгоритмы и особености скриптинга.
>> просьбы написать скрипт не в эту тему, а сюда: Напишите пожалуйста скрипт >> выкладывать готовые и отлаженные скрипты не в эту тему, а сюда: Готовые скрипты Тут только вопросы и обсуждение проблем и методов их решения, а так же все непонятки с "должно работать, но не работает". ___ База скриптов (NWN) Скрипты для новичков (NWN) Вопросы по скриптам (NWN) Построение скриптовых сцен (NWN) Так как скриптинг не сильно изменился, то большая часть вещей, написаная под НВН1 нормально работает и в НВН2. Посмотрите в этих темах, вполне возможно вы найдете интересующую вас информацию. |
Dec 15 2009, 06:00
Сообщение
#251
|
|
Level 2 Класс: Клерик Характер: Lawful Neutral Раса: Человек |
Реализую не стакающиеся бонусы к атаке разноименных типов (ДнД 3.5, ем буквы).
Вариант 1: Код effect MoraleBonus (effect eEffect) { eEffect = SetEffectSpellId (eEffect, 1600); return eEffect; } Вариант 2 - хранение переменных/массивов на объекте-цели или в БД. Вопрос - как сделать все так, чтобы и диспелл был меньше, чем на 20 страниц кода и длительность нескольких разных спеллов с одноименными эффектами выверялась нормально? P.S. только что задумался о создании динамического списка на модуле... Если что, у нас есть еще вот такой список своих функций: void AppendArrayInt(object obj,string bufName,int value); int GetArrayInt(object obj,string bufName,int index); void SetArrayInt(object obj,string bufName,int index,int value); void AppendArrayLoc(object obj,string bufName,location value); location GetArrayLoc(object obj,string bufName,int index); void SetArrayLoc(object obj,string bufName,int index,location value); void AppendArrayString(object obj,string bufName,string value); string GetArrayString(object obj,string bufName,int index); void SetArrayString(object obj,string bufName,int index,string value); void AppendArrayFloat(object obj,string bufName,float value); float GetArrayFloat(object obj,string bufName,int index); void SetArrayFloat(object obj,string bufName,int index,float value); void AppendArrayObject(object obj,string bufName,object value); object GetArrayObject(object obj,string bufName,int index); void SetArrayObject(object obj,string bufName,int index,object value); void DestroyArray(object obj,string bufName,int type=tINT); int IsArraySet(object obj,string bufName); int GetArrayIdxCount(object obj,string bufName); void DestroyArrayIdx(object obj,string bufName,int index,int type=tINT); int Split(object obj,string str,string bufName,int type=tSTR,string separator=","); int SplitCount(string str,string separator=","); void OutputArray(object obj,string bufName,int type,object oPC=OBJECT_INVALID); void CreateMatrix(object obj,string bufName,int width,int height); void DeleteMatrix(object obj,string bufName,int type=tINT); void ExpandMatrix(object obj,string bufName,int xcount,int ycount); int GetMatrixInt(object obj,string bufName,int x,int y); string GetMatrixString(object obj,string bufName,int x,int y); float GetMatrixFloat(object obj,string bufName,int x,int y); object GetMatrixObject(object obj,string bufName,int x,int y); void SetMatrixInt(object obj,string bufName,int x,int y,int value); void SetMatrixString(object obj,string bufName,int x,int y, string value); void SetMatrixFloat(object obj,string bufName,int x,int y,float value); void SetMatrixObject(object obj,string bufName,int x,int y,object value); Сообщение отредактировал Melshin - Dec 15 2009, 06:09 |
Dec 16 2009, 15:14
Сообщение
#252
|
|
Level 2 Класс: Клерик Характер: Lawful Neutral Раса: Человек |
Цитата P.S. только что задумался о создании динамического списка на модуле... Начал. Вопрос к опытным мастерам: стоит ли? Будет ли у этого нормальная производительность? Смысл вышенаписанного: при загрузке в модуль первого персонажа инициализируется рекурсивная (6 секунд) ProcessEffects (). На модуле хранится массив, в котором каждый элемент - объект, на котором находится эффект какого-то заклинания или еще чего. На каждом объекте хранится массив, в котором каждый элемент - какой-то SpellId. Для каждого существующего SpellId берутся локальные интеджеры: кастер лвл, длительность в раундах, ДЦ (если нужно, еще можно весь дамаг для ДОТ-ов сразу рассчитать, т.к. всякие эмповерд нехорошие). Если длительность не закончилась - держим на объекте эффект заклинания 6 секунд до следующего выполнения ProcessEffects. Если длительность закончилась - стираем нафиг спелл из массива и всю информацию о нем. Если объект подвергся диспеллу - работаем с соответствующим массивом. На выходе мы получаем систему, которая очень сильно повышает функциональность стандартного НВН скрипта. Можно, например, временно подавлять эффекты заклинаний (анти-магическое поле, защита от зла/добра и т.д.) Можно модифицировать кастер лвл и другие параметры любого спелла как угодно и чем угодно... Так вот собственно объектов в модуле много, на каждом может быть несколько спеллов, а в каждом спелле разные эффекты... Сообщение отредактировал Melshin - Dec 16 2009, 15:17 |
Feb 22 2010, 00:33
Сообщение
#253
|
|
Level 3 Класс: Воин Характер: Chaotic Good Раса: Человек |
Извините если не по теме, но есть ли русскоязычные статьи по основам скриптинга для nwn2? Я недавно взялся за тулсет. Освоил практически всё кроме скриптов и не знаю как к ним подступиться. С использованием готовых скриптов в диалогах вроде разобрался, но дальше никак.
Вот например, нужны такие скрипты: 1) Если переменная Local Int "XXXXX" принимает значение 1, начинается отсчёт времени, после которого переменная возвращается в значение 0. 2) Если игрок покидает локацию, все открытые двери в этой локации закрываются. 3) Если в сундуке А есть вещи, они переносятся в сундук Б. |
Feb 22 2010, 15:31
Сообщение
#254
|
|
Level 9 Класс: Волшебник Характер: Neutral Good Раса: Эльф |
Merkuta,
1) Для этого переменная твоя должна быть локальной, и где-то храниться. Например на игроке. Для этого задавай ее так: Neverwinter Script object oPC = GetFirstPC(); //будет брать первого игрока в модуле. Если игрок один это сработает. Иначе придумай как нам найти нужного (зависит от того, откуда запускается скрипт) SetLocalInt(oPC, "A", 1); //А = 1 В другом месте, где надо ее проверять и запускать таймер, пиши: Neverwinter Script object oPC = GetFirstPC(); int A = GetLocalInt(oPC, "A"); //берем с первого попавшегося игрока переменную А if (A == 1) { float fTime = 10.0; //через сколько секунд занулять будем? DelayCommand(fTime, SetLocalInt(oPC, "A", 0)); } 2) Это намного сложнее. 3) Здесь нужно организовать цикл перебора всех вещей в сундуке А и копирования их в сундук Б. Напиши мне в аську/пм, подскажу по ходу дела, если нужно. Melshin, думаю если воспользуешься NWNX и подрубишь внешнюю БД, то производительность будет норм. Если юзать стандартные скрипты для работы с массивами - загрузишь его серьезно. Но наверняка не могу говорить. Сообщение отредактировал Lorendroll - Feb 22 2010, 15:42 |
May 26 2010, 15:15
Сообщение
#255
|
|
Level 9 Класс: Фея Характер: Chaotic Evil Раса: Фея |
Здрасте.
Нужно на хартбит повесить функцию, которая будет отсчитывать внутриигровое время начиная с первой загрузки модуля. Neverwinter Script #include "inc_array_system" void main() { object oPC = GetFirstPC(1); //if (!GetIsPC(oPC)) return; int nInt; int nDay; int nMin; int nHr; nInt = array_get_int(oPC, "timer", 3); nInt = nInt + 3; //изменяется в зависимости от текущего таймскейла array_set_int(oPC, "timer", 3, nInt); /*if (array_get_int(oPC, "timer", 4) == 60) //seconds into minutes { nMin = array_get_int(oPC, "timer", 3); nMin = nMin + 1; array_set_int(oPC, "timer", 3, nMin); array_set_int(oPC, "timer", 4, 0); }*/ if (array_get_int(oPC, "timer", 3) == 60) //minutes into hours { nHr = array_get_int(oPC, "timer", 2); nHr = nHr + 1; array_set_int(oPC, "timer", 2, nHr); array_set_int(oPC, "timer", 3, 0); } if (array_get_int(oPC, "timer", 2) == 24) //hours into days { nDay = array_get_int(oPC, "timer", 1); nDay = nDay + 1; array_set_int(oPC, "timer", 1, nDay); array_set_int(oPC, "timer", 2, 0); } } в качестве inc_array_system используется этот скрипт. Проблема в том, что нифига это ненадежно и недостоверно. Из-за фаст тревелов/возможных кастомных системах отдыхов и прочего. Может быть есть какой-нибудь более простой способ/функции о которых я даже не подозреваю? Использоваться это будет в сингл модуле. |
May 26 2010, 16:17
Сообщение
#256
|
|
Level 5 Класс: Обыватель Характер: Lawful Neutral Раса: Человек NWN: Модмейкер Проклятие Левора Порядок Времени |
самый простой способ работы с игровым временем, имхо, это его пересчет в игровые секунды. Те текущий месяц, день и час пересчитывается в секунды и сравнивается с контрольным для определения, прошло ли нужное количество времени или нет. Этим решается проблема временных скипов в скриптах. Проверять можно не каждые 6 секунд, а лишь когда нужно (в диалоге, в скрипте и тд), что экономит ресурсы. И тд.
|
May 26 2010, 17:01
Сообщение
#257
|
|
Level 9 Класс: Фея Характер: Chaotic Evil Раса: Фея |
самый простой способ работы с игровым временем, имхо, это его пересчет в игровые секунды. Те текущий месяц, день и час пересчитывается в секунды и сравнивается с контрольным для определения, прошло ли нужное количество времени или нет. Этим решается проблема временных скипов в скриптах. Проверять можно не каждые 6 секунд, а лишь когда нужно (в диалоге, в скрипте и тд), что экономит ресурсы. И тд. Не, для меня это не подходит, нужно чтобы все юзер-френдли было (IMG:style_emoticons/kolobok_light/crazy.gif) Можно допустим сделать такой костыль: при первой загрузки модуля (самой-самой первой) создается массив, в который записывается день, час, минута, секунда (последнее можно и не использовать), затем на хардбит вешается скрипт который создает другой массив, записывает в него текущую день, час, минуту, секунду затем эти массивы между собой вычитает и получается вполне себе достоверный таймер Только топорно все это, и, ввиду малого опыта работы с большими модами, спрашиваю скажется ли это негативно на перфомансе? |
May 26 2010, 23:43
Сообщение
#258
|
|
Level 19 Класс: Воин Характер: Lawful Good Раса: Человек NWN: Скриптинг [PW] Gem of the North Край Лесов |
Почему бы не юзать аптайм в секундах в скриптах, а для юзерфрендли вывода не написать конвертер из секунд в остальное посредством деления с остатком?
|
May 27 2010, 09:29
Сообщение
#259
|
|
Level 5 Класс: Обыватель Характер: Lawful Neutral Раса: Человек NWN: Модмейкер Проклятие Левора Порядок Времени |
Не, для меня это не подходит, нужно чтобы все юзер-френдли было crazy.gif для юзерфрендлиности нужно все расчеты спрятать внутрь инклуда, оставив снаружи несколько управляющих функций. Например: * SetTimer(string sTimerName); - запоминаем текущее время и привязываем число к sTimerName для последующей работы с ним пользователя * CheckTimer(string sTimerName, int nTimeHour, int nTimeMinute = 0); - проверемя разницу между текущим временем и запомненым по идентификатору. Тру - если прошло больше времени, чем указано в nTimeHour/nTimeMinute * DeleteTimer(string sTimerName); - удалить таймер Довольно плотно в свое время работал с внутриигровым временем, по своему опыту скажу: в 90% случаев не нужно в каждый момент знать сколько прошло (те каждые 6 секунд ничего пересчитывать не нужно), проверки прохождения энного количества времени стоят в весьма конкретных местах: вход в локу, фраза диалога и тд. У меня было лишь 2-3 случая, когда пришлось повесить на ХБ, потому что отложенное событие было само по себе. В этой связи завязывать систему на постоянный пересчет считаю не совсем верным, пересчет должен быть вызываемым. И пусть в паре случаев вызов будет в ХБ, ничего страшного. |
Jun 5 2010, 06:33
Сообщение
#260
|
|
Level 9 Класс: Фея Характер: Chaotic Evil Раса: Фея |
Lex, спасибо, момент с вызовом функции по требованию что-то совсем выпал из головы (IMG:style_emoticons/kolobok_light/prankster2.gif)
|
Jun 5 2010, 11:48
Сообщение
#261
|
|
Level 9 Класс: Обыватель Характер: Lawful Good Раса: Человек NWN: Модмейкер Рыцарская Сага |
Тут для теста Аз написал скрипт подсчета игрового времени. Цикл вывода инфы 5 минут, подсчета 1 минута. Может пригодится...
Neverwinter Script //::///////////////////////////////////////////////
//:: Скрип работает при загрузке модуля //:: FileName: module_load //:: auth: azathoth //////////////////////////////////////////////////////////////////////////////// // ***** ПОДСЧЕТ ВРЕМЕНИ ДЛЯ ТЕСТА ***** //////////////////////////////////////////////////////////////////////////////// void Count(int nTimer) { object oPC = GetFirstPC(); object oMod = GetModule(); int iHB = GetLocalInt(oMod, "HB_TIME"); SetLocalInt(oMod, "HB_TIME", iHB+1); if(iHB >= 4) { int iTimeGameM = GetLocalInt(oMod, "Time_Game_M"); //минуты int iTimeGameH = GetLocalInt(oMod, "Time_Game_H"); //часы SetLocalInt(oMod, "HB_TIME", 0); if(iTimeGameM > 55) { iTimeGameH++; SetLocalInt(oMod, "Time_Game_H", iTimeGameH); //часы SetLocalInt(oMod, "Time_Game_M", 0); //минуты } else { iTimeGameM+=5; SetLocalInt(oMod, "Time_Game_M", iTimeGameM); } SendMessageToPC(oPC, "Длительность игры: "+IntToString(iTimeGameH)+" ч. "+IntToString(iTimeGameM)+" мин."); } DelayCommand(60.0, Count(nTimer + 1)); } //////////////////////////////////////////////////////////////////////////////// void main() { // ================= ДЛЯ ТЕСТА ==================== if (GetLocalInt(GetModule(), "START_TIME_TEST") == 0) // Проверить { SetLocalInt(GetModule(),"START_TIME_TEST",1); Count(0); } } Сообщение отредактировал gennady - Jun 5 2010, 11:50 |
Jun 20 2010, 19:16
Сообщение
#262
|
|
Level 3 Класс: Воин Характер: Chaotic Good Раса: Человек |
Мне нужно было написать скрипт, который перемещает вещи из одного сундука в другой. Решил вопрос так:
Neverwinter Script void main() { object oPC = GetFirstPC(), oChest_01 = GetObjectByTag("RC_chest_01"), oChest_02 = GetObjectByTag("RC_chest_02"), oItem = GetFirstItemInInventory(oChest_01), oItem_in; //string sString = "скрипт сработал"; while(GetIsObjectValid(oItem)) { //FloatingTextStringOnCreature(sString, oPC); CopyItem(oItem, oChest_02); DestroyObject(oItem); //sString = "скрипт сработал более одного раза"; oItem = GetNextItemInInventory(oChest_01); } //FloatingTextStringOnCreature("вещей нет", oPC); return; } Однако выяснилось, что предметы типа контейнера не копируются, если в них что-то есть. Копируется только их содержимое. Сам контейнер пропадает. Попробовал решить вопрос следующим образом(хотя ясно, что это не совсем то, что нужно): Neverwinter Script void main() { object oPC = GetFirstPC(), oChest_01 = GetObjectByTag("RC_chest_01"), oChest_02 = GetObjectByTag("RC_chest_02"), oItem = GetFirstItemInInventory(oChest_01), oItem_in; //string sString = "скрипт сработал"; while(GetIsObjectValid(oItem)) { //FloatingTextStringOnCreature(sString, oPC); while(GetHasInventory(oItem)) { oItem_in = GetFirstItemInInventory(oItem); while(GetIsObjectValid(oItem_in)) { CopyItem(oItem_in, oChest_02); DestroyObject(oItem_in); oItem_in = GetNextItemInInventory(oItem); } CopyItem(oItem, oChest_02); DestroyObject(oItem); oItem = GetNextItemInInventory(oChest_01); } CopyItem(oItem, oChest_02); DestroyObject(oItem); //sString = "скрипт сработал более одного раза"; oItem = GetNextItemInInventory(oChest_01); } //FloatingTextStringOnCreature("вещей нет", oPC); return; } Но в этом случае предметы из контейнера копируются дважды, а сам контейнер опять же пропадает. Есть идеи, как скопировать контейнер с вложенными в него вещами? |
Jun 20 2010, 23:17
Сообщение
#263
|
|
Level 19 Класс: Воин Характер: Lawful Good Раса: Человек NWN: Скриптинг [PW] Gem of the North Край Лесов |
Никак. Sad, but true.
|
Jun 21 2010, 07:05
Сообщение
#264
|
|
Level 5 Класс: Пьяный Мастер Характер: Chaotic Good Раса: Человек |
ну по идеи нужно скопировать/создать сначала сам контейнер
а потом скопировать вещи из одного в другой у тебя во всех скриптах копируются только вещи |
Jun 21 2010, 08:13
Сообщение
#265
|
|
Level 3 Класс: Воин Характер: Chaotic Good Раса: Человек |
|
Jun 21 2010, 08:41
Сообщение
#266
|
|
Level 19 Класс: Воин Характер: Lawful Good Раса: Человек NWN: Скриптинг [PW] Gem of the North Край Лесов |
Контейнеры вообще зло (IMG:style_emoticons/kolobok_light/smile.gif)
Цитата я исходил из того, что после перебора, копирования и удаления всех вещей в контейнере, он станет пустым и скопируется нормально. Но не получилось. Потому что дестрой только помечает на удаление, удаляются вещи после окончания работы скрипта. Пока скрипт работает, контейнер не пустой.Цитата у тебя во всех скриптах копируются только вещи Нет, там и контейнер мелькает, он тоже ловится при переборе параллельно со своим содержимым.
|
Jun 21 2010, 16:54
Сообщение
#267
|
|
Level 7 Класс: Некромант Характер: True Neutral Раса: Нежить |
|
Jun 21 2010, 18:02
Сообщение
#268
|
|
Level 3 Класс: Воин Характер: Chaotic Good Раса: Человек |
В первом это можно было сделать при помощи ActionGiveItem, но на втором не проверялось. Хотя можно и с копированием извратиться при особом желании. Спасибо, контейнер действительно переносится со всеми вложенными вещами. Neverwinter Script void main() { object oPC = GetFirstPC(), oChest_01 = GetObjectByTag("RC_chest_01"), oChest_02 = GetObjectByTag("RC_chest_02"), oItem = GetFirstItemInInventory(oChest_01), oItem_in; //string sString = "скрипт сработал"; while(GetIsObjectValid(oItem)) { //FloatingTextStringOnCreature(sString, oPC); AssignCommand(oChest_01, ActionGiveItem(oItem, oChest_02)); //sString = "скрипт сработал более одного раза"; oItem = GetNextItemInInventory(oChest_01); } //FloatingTextStringOnCreature("вещей нет", oPC); return; } |
Jun 21 2010, 23:42
Сообщение
#269
|
|
Level 19 Класс: Воин Характер: Lawful Good Раса: Человек NWN: Скриптинг [PW] Gem of the North Край Лесов |
Эпично (IMG:style_emoticons/kolobok_light/smile.gif) Помню даже на волте видел когда-то скрипт, где всё копировалось, а вот контейнер уничтожался, и в комментах было типа "так надо, иначе дюп" (IMG:style_emoticons/kolobok_light/smile.gif)
|
Jun 22 2010, 04:33
Сообщение
#270
|
|
Миловидный Бегрюссунг Класс: Воин Характер: Chaotic Good Раса: Человек NWN: Модмейкер Проклятие Левора Порядок Времени |
Да, здорово... Сразу вспоминается куча проблем при работе с рюкзаками. (IMG:style_emoticons/kolobok_light/smile.gif)
|
Jun 22 2010, 08:08
Сообщение
#271
|
|
Level 19 Класс: Воин Характер: Lawful Good Раса: Человек NWN: Скриптинг [PW] Gem of the North Край Лесов |
Ну если ActionGiveItem() работает через стек действий, то с игроком может не прокатить (скажем, дроп при смерти, или забитый стек, или дикие лаги). Но вот между сундуками работает (IMG:style_emoticons/kolobok_light/smile.gif)
|
Jun 22 2010, 11:03
Сообщение
#272
|
|
Level 11 Класс: Волшебник Характер: Lawful Evil Раса: Эльф NWN: Скриптинг [PW] Gem of the North |
Если уж так приспичило, сундук всегда можно пересоздать с палитры (IMG:style_emoticons/kolobok_light/rolleyes.gif)
|
Jun 22 2010, 11:55
Сообщение
#273
|
|
Level 7 Класс: Некромант Характер: True Neutral Раса: Нежить |
|
Jun 24 2010, 18:15
Сообщение
#274
|
|
Level 2 Класс: Волшебник Характер: Neutral Good Раса: Человек |
Извините, если вопрос не по теме. Я видел, как в обе NWN прикручивали новые навыки (feats). Я понял, что это делали через скрипт, но как?
Кто-нибудь так делал? Сообщение отредактировал GoodLuc - Jun 24 2010, 18:21 |
Jun 24 2010, 19:01
Сообщение
#275
|
|
Level 5 Класс: Обыватель Характер: Lawful Neutral Раса: Человек NWN: Модмейкер Проклятие Левора Порядок Времени |
нужно 2da таблицы ковырять: feats + spells + еще пара по мелочи, и конечно же скрипты. Все это довольно подробно описано в разделе Кастом Контент в категории тулсета первого НВН (во втором суть та же, мб чуток больше параметров).
Новые фиты могут быть только активными. Пассивные вещи типа (+1 атака всегда) сделать нельзя, к сожалению. Те можно, но коряво и через попу. Или через nwnx - но это только для мультиплеера. |
Текстовая версия | Сейчас: 18th May 2024 - 13:46 |