Скрипты: Все вопросы, Алгоритмы, оптимизация, особености и хитрости в скриптинге |
Здравствуйте, гость ( Вход | Регистрация )
Скрипты: Все вопросы, Алгоритмы, оптимизация, особености и хитрости в скриптинге |
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 - но это только для мультиплеера. |
Текстовая версия | Сейчас: 24th April 2024 - 01:39 |