Дивный новый метод, Parser для НВН |
Здравствуйте, гость ( Вход | Регистрация )
Дивный новый метод, Parser для НВН |
Aug 28 2009, 13:13
Сообщение
#1
|
|
Пушкин Класс: Обыватель Характер: Chaotic Neutral Раса: Гигант NWN: Тексты |
Во всяком случае, используется этот метод нечасто. Для кого-то он может быть совсем в новинку.
Функции SetListening, SetListenPattern и иже с ними предназначены для проверки реакций, главным образом, NPC на те или иные реплики. PC могут узнавать через них пароли и т.п. - очень ограниченная функциональность, которую обычно оставляют, как она есть. Но подумаем, что такое система "слушания" вообще, если она позволяет игре отмечать "сказанные", то есть напечатанные, слова и реагировать на них? Это клавишный интерфейс, - по сути, parser, как назывались в текстовых квестах системы, позволявшие набрать в DOS-строчке, к примеру, TAKE SWORD - и персонаж брал меч. Клавишный интерфейс сложнее использовать, чем графический, но и возможности у него шире. В NWN мы можем использовать эту функцию для разного рода настроек. Меня интересует прежде всего магия. Вот один случай: как нам указать, кого именно мы хотим получить, употребив чары Monster Summoning? Случайный выбор или, наоборот, никакого выбора - это не по мне, но и радиальные кнопки для стольких вариантов завести нереально. Делаем для Monster Summoning скрипт по образцу следующего, который управляет вызыванием элементалов. Neverwinter Script /// Пример чар, вызывающих элементала нужной стихии. void Summon(string sElemental); { effect eSummon = EffectSummonCreature(sElemental, ЭФФЕКТ ПОЯВЛЕНИЯ, 0.5f); /// или другая функция вызова location lTarget = GetLocation(OBJECT_SELF); float fDuration = GetCasterLevel() * 18; /// длится 3 раунда за уровень мага if (GetMetaMagicFeat() = METAMAGIC_EXTEND) /// метамагия { fDuration * 2; } ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, lTarget, fDuration); } void main() { effect eStun = SupernaturalEffect(EffectStun()); /// контролируя элементала, маг выключен из происходящего SignalEvent(OBJECT_SELF, EventSpellCastAt(OBJECT_SELF, SPELL_CONJURE_ELEMENTAL, FALSE)); ApplyEffectTObject(DURATION_TYPE_TEMPORARY, eStun, OBJECT_SELF, fDuration); string sPattern = "(**зем**|**почв**|**камен**|**песк**|**песч** |**песо**|**глин**)|(**огонь**|**огн**|**плам**|**у голь**|**зол**|**жар**|**дым**)|(**вод**|**мор**|** рек**|**реч**|**рек**|**океан**|**дожд**)|(**возду* *|**ветр**|**вихр**|**бриз**|**ураган**|**бур**)"; /// желательно сделать struct с индексами всех схем для ListenPattern /// любая группа этих слов даст игре знать, какой элемент мага интересует. Фраза может варьироваться от простого "камень" до "Явись, порождение песка!" SetListenPatternNumber(OBJECT_SELF, 2); /// ставим схему SetListening(oPC, TRUE); /// начинаем слушать DelayCommand(5.0, SetListening(oPC, FALSE)); /// у мага пять секунд на то, чтобы напечатать команду string sCall = GetMatchedSubstring(0)); /// следим за ЛЮБЫМИ словами мага int nTheElement = GetMatchedSubstringsCount(sCall); /// считаем совпадения со схемой while (nTheElement > 0) /// если они нашлись, то где именно? { if (TestStringAgainstPattern("**зем**|**почв**|**камен**|**песк**|**песч**| **песо**|**глин**", sCall) = TRUE) /// если призыв к земле, то... { Summon("Земной элементал"); break; } } else if (TestStringAgainstPattern("**огонь**|**огн**|**плам**|**уголь**|**зол**| **жар**|**дым**", sCall) = TRUE) /// если призыв к огню, то... { Summon("Огненный элементал"); break; } } else if (TestStringAgainstPattern("**вод**|**мор**|**рек**|**реч**|**рек**|**оке ан**|**дожд**", sCall) = TRUE) /// если призыв к воде, то... { summon("Водный элементал"); break; } } else if (TestStringAgainstPattern("**возду**|**ветр**|**вихр**|**бриз**|**ураган **|**бур**", sCall) = TRUE) /// если призыв к воздуху, то... { Summon("Воздушный элементал"); break; } } } Не исключено, что я допустил ошибки в коде. Тогда прошу меня поправить, тем более, что он писался для Авроры. Но идея верна. Известно во всяком случае, что можно получить PC через GetLastSpeaker и можно записать его слова в string - а остальное, как говорится, дело техники. Вы в состоянии сами домыслить, для чего еще хорош этот слуховой аппарат. В голову приходят варианты: 1) С его помощью можно отвечать на простые вопросы NPC напрямую, без диалогового окна. Стражник спрашивает "Сдаешься?" и если через пять секунд игрок не напечатает "Да" или "Сдаюсь", то - 2) Можно отдавать персонажу несложные команды, как то: "Следи за (имя NPC или игрока)". Эту команду необходимо предварить "командным словом", в ответ на которое игра будет фиксировать следующие реплики по заданным схемам. Слово, разумеется, игрок должен знать наперед. Тогда, при правильных настройках, персонаж автоматически включит Stealth и будет ходить за объектом по пятам. Другое командное слово выключит режим записи. Так как все функции слушания проверяются через общий для всего шарда GetLastSpeaker, на крупных шардах полезно давать знать игроку, что его команда услышана. Кстати, Функции SetListening все равно, кричит персонаж на весь сервер или шепчет, поэтому лишние сообщения не будут качаться над головами. Точно так же можно приказать самому себе "Делай зелья невидимости" - и персонаж займется алхимией. Эти автоматические действия было бы не так сложно прописать. По сути функция открывает дорогу макросам. 3) Система аукционов. NPC или PC говорит командное слово, объявляет лот, говорит другое командное слово и внимает выкрикам. Максимальное услышанное значение автоматически забирает у покупателя деньги и вручает ему товар. 4) Всякого рода численные параметры теперь могут быть указаны точно. Предположим, какое-то заклинание создает nLevel * 5 HD нежити любого рода, а игроку нужна конкретная смесь. Теперь он может напечатать "3 гуля, 1 гаст и 5 зомби" - и вуаля! 4) Чары наподобие Sequencer. 5) Завещания! 6) Новые возможности контроля для Dungeon Master, который теперь может просто напечатать, к примеру, "дождь"... И так далее, и так далее, и так далее. |
Aug 28 2009, 13:25
Сообщение
#2
|
|
Level 8 Класс: Бледный Мастер Характер: Chaotic Neutral Раса: Человек |
Вообще с патчем 1.23 у нас появилась возможность обрабатывать реплики более удобным способом. Подробности здесь.
|
Aug 31 2009, 13:48
Сообщение
#3
|
|
Пушкин Класс: Обыватель Характер: Chaotic Neutral Раса: Гигант NWN: Тексты |
На это я погляжу.
|
Sep 2 2009, 14:20
Сообщение
#4
|
|
Пушкин Класс: Обыватель Характер: Chaotic Neutral Раса: Гигант NWN: Тексты |
Благодаря Sharklike я смог переписать свои скрипты под более удобное событие OnChat. Вот скрипты для заклинания "Чтение мыслей" (ESP). Не исключено, что я допустил здесь ошибки или не учел какие-то факторы. Что ж, говорите! Для того и пишу.
1. Neverwinter Script /// Заклинание "Чтение мыслей" (Divination, Enchantment). 2 уровень. Время сотворения 5. Позволяет одному игроку слышать все, что думает (говорит по любому из каналов) другой, до тех пор, пока не истечет срок и не сотрутся переменные. Требует добавлений к OnDisturbed и OnChat модуля или шарда. /// дополнительные функции void Domination() /// что происходит с телепатами, попавшими не в тот разум { effect eEffect = GetFirstEffect(oTarget); while(GetIsEffectValid(eEffect)) { nType = GetEffectType(eEffect); if (nType = EFFECT_TYPE_CONFUSED | nType = EFFECT_TYPE_STUNNED) { FloatingTextStringOnCreature(OBJECT_SELF, "Вой помех в этом мозге ломает ваш тонкий щуп. Передернувшись, вы еще долго массируете виски.", FALSE); } else if (nType = EFFECT_TYPE_DOMINATED) { FloatingTextStringOnCreature(OBJECT_SELF, "Страшный гул и крики едва не валят вас наземь. Чья-то стальная воля вертит этим существом, как марионеткой!", FALSE); int nOwnPower = GetHitDice(OBJECT_SELF); int nTheirPower = GetHitDice(GetEffectCreator(eEffect)); if (nTheirPower => (nOwnPower*2)) /// Если захвативший разум очень силен, например, Domination создал лич 30-го уровня, маг рискует жестоко пострадать { int nSave = (nTheirPower + 10) / (GetWisdom(OBJECT_SELF) / 15); if (WillSave(OBJECT_SELF, nSave, SAVING_THROW_TYPE_MIND_SPELLS, GetEffectCreator(eEffect)) = 0) { effect eStone = EffectMagicalEffect(EffectPetrify()); effect eVis = EffectVisualEffect(VFX_DUR_PETRIFY); effect eDarkness = EffectVisualEffect(VFX_DUR_BLIND); effect eLink = EffectLinkEffects(eStone, eVis); effect eLink2 = EffectLinkEffects(eLink, eDarkness); DelayCommand(3.5, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink2, OBJECT_SELF)); DelayCommand(1.5, FloatingTextStringOnCreature(OBJECT_SELF, "Вы мечетесь, пытаясь выбраться из черепной крысоловки, но...", FALSE)); DelayCommand(3.0, FloatingTextStringOnCreature(OBJECT_SELF, "Холод и темнота смыкаются вокруг.", FALSE)); } } else { DelayCommand(1.5, FloatingTextStringOnCreature(OBJECT_SELF, "Мощным рывком вы выбираетесь из мрачной воронки, куда уже начали погружаться, и разрываете связь.", FALSE)); } } else { eEffect = GetNextEffect(oTarget); } } void RetainControl() /// победа в борьбе за контроль объекта прежнего телепата { sWho = "Есть! Усилием воли вы изгоняете нахала. Это был кто-то по имени " + GetName(OBJECT_SELF) + "."; DelayCommand(11.0, FloatingTextStringOnCreature(oFormer, sWho, FALSE)); DelayCommand(10.0, FloatingTextStringOnCreature(OBJECT_SELF, "...Но тот, другой, слишком силен.", FALSE)); sWho = "Вы отступаете, узнав имя соперника -" + sFormer + "."; DelayCommand(11.0, FloatingTextStringOnCreature(OBJECT_SELF, sWho, FALSE)); DelayCommand(10.0, FloatingTextStringOnCreature(oTarget, "Разброд в мыслях.", FALSE); } void GainControl() /// победа пришельца { DelayCommand(10.0, FloatingTextStringOnCreature(oFormer, "Трах! Телепатическую связь уводят у вас из-под носа!", TRUE)); /// переключаем канал на себя и даем знать ему и всей его шатии - ради интриги DelayCommand(10.0, FloatingTextStringOnCreature(OBJECT_SELF, "Прикрыв глаза, вы вплываете в чужой разум.", FALSE)); DelayCommand(10.0, GiveXP(OBJECT_SELF, (10 - nSuperiority) * 20)); /// небольшая награда активно нападающему, но не защищавшемуся DelayCommand(11.0, SetLocalInt(oTarget, "ESP_target", 1)); fDuration + 11.0; DelayCommand(fDuration, DeleteLocalInt(oTarget, "ESP_target")); DelayCommand(11.0, Scrutiny()); } void Scrutiny() /// в самом начале заклинание сообщает дополнительные данные { string sMoney = IntToString((GetGold(oTarget) / (d10() + 5)) * (d10() + 5)); /// шпион примерно узнает, сколько у существа золота... if (GetGender(oTarget) = MALE) { string sEstimate = "У него в кошельке порядка " + sMoney + " монет и вот какая экипировка." } else { string sEstimate = "У нее в кошельке порядка " + sMoney + " монет и вот какая экипировка." } FloatingTextStringOnCreature(OBJECT_SELF, sEstimate, FALSE); /// и может посмотреть на снаряжение. Добавление к OnDisturbed гарантирует, что он ничего не сможет оттуда похитить или добавить. DelayCommand(2.5, OpenInventory(oTarget, OBJECT_SELF)); } /// главная функция чтения мыслей void main() { float fDuration = GetCasterLevel(oSender) * 60; /// длится 10 раундов за уровень if (GetMetaMagicFeat() = METAMAGIC_EXTEND) /// метамагия удваивает срок { fDuration * 2; } object oTarget = GetAttemptedSpellTarget(); effect eEffect = SupernaturalEffect(EffectParalyze()); if (GetLocalInt(OBJECT_SELF, "ESP_listener") = 1) /// если маг уже слушает кого-то... { FloatingTextStringOnCreature(OBJECT_SELF, "Вы уже поддерживаете одну ментальную смычку.", FALSE); } else if (GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS) = TRUE) /// если цель защищена { FloatingTextStringOnCreature(OBJECT_SELF, "Вход закрыт...", FALSE); } else if (GetLocalInt(oTarget, "ESP_target") = 0) но если разум цели свободен, то можно войти в него { SignalEvent(EventSpellCastAt(OBJECT_SELF, SPELL_ESP, TRUE)); /// объявляем о заклинании Domination(); /// проверка нынешнего состояния цели SetLocalInt(oTarget, "ESP_target", 1); /// задаем переменные шпиона и цели SetLocalInt(OBJECT_SELF, "ESP_listener", 1); DelayCommand(fDuration, DeleteLocalInt(oTarget, "ESP_target")); /// на некоторое время DelayCommand(fDuration, DeleteLocalInt(OBJECT_SELF, "ESP_listener")); Scrutiny(); } else /// а может оказаться, что кто-то уже шпионит за мыслями объекта. Тогда мы вступаем с ним в противоборство { SignalEvent(EventSpellCastAt(OBJECT_SELF, SPELL_ESP, TRUE)); /// объявляем о заклинании Domination(); /// проверка эффектов object oFormer = GetFirstObjectInArea(); while (oFormer != OBJECT_INVALID && GetLocalInt(oFormer, "ESP_listener") = 0) { oFormer = GetNextPC(); } ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, OBJECT_SELF, 11.0f); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, oFormer, 11.0f); FloatingTextStringOnCreature(OBJECT_SELF, "Вы встречаете в разуме этого объекта другого наблюдателя!", FALSE); DelayCommand(1.0, FloatingTextStringOnCreature(OBJECT_SELF, "Напрягшись, вы пытаетесь вытеснить чужака...", FALSE)); DelayCommand(2.3, FloatingTextStringOnCreature(OBJECT_SELF, "...Мышцы скрутились в узлы, едкий пот сочится по лбу...", FALSE)); DelayCommand(6.0, FloatingTextStringOnCreature(OBJECT_SELF, "...Не в состоянии шевельнуть и пальцем, вы будто превратились в статую Упорства...", FALSE)); string sWho = GetName(oTarget) + "?" + " ...Нет. Творится что-то неладное."; FloatingTextStringOnCreature(oFormer, sWho, FALSE); DelayCommand(1.0, FloatingTextStringOnCreature(oFormer, "Кто-то другой внедрился в это сознание и пытается выбросить вас!", FALSE)); DelayCommand(2.3, FloatingTextStringOnCreature(oFormer, "Сцепив зубы, вы вступаете на мысленную арену...", FALSE)); DelayCommand(6.0, FloatingTextStringOnCreature(oFormer, "Борьба умов не видна другим, но высекает огромные, как звезды, искры у вас за переносицей...", FALSE)); float fOwnPower = GetHitDice(OBJECT_SELF); float fTheirPower = GetHitDice(oFormer); float fSuperiority = fabs(fOwnPower - fTheirPower); int nSuperiority = FloatToInt(fSuperiority); if (fOwnPower => fTheirPower) /// В побединке держит верх чаще всего сильнейший... { if (d100() > nSuperiority * 10) /// ...но и разница в уровне не гарантирует триумфа { GainControl(); } else { RetainControl(); } else if (d100() > nSuperiority * 10) { RetainControl(); } else { GainControl(); } } else { DelayCommand(10.0, FloatingTextStringOnCreature(OBJECT_SELF, "Прикрыв глаза, вы вплываете в чужой разум.", FALSE)); SetLocalInt(oTarget, "ESP_target", 1); SetLocalInt(OBJECT_SELF, "ESP_listener", 1); fDuration + 10.0; DelayCommand(fDuration, DeleteLocalInt(oTarget, "ESP_target")); DelayCommand(fDuration, DeleteLocalInt(OBJECT_SELF, "ESP_listener")); DelayCommand(10.0, Scrutiny()); } } } 2. Neverwinter Script /// Заклинание "Чтение мыслей" (Divination, Enchantment). 2 уровень. Время сотворения 5. Добавление к OnChat модуля или шарда. Блок ставится внутри общей функции StartingConditional события. if (GetLocalInt(oSender, "ESP_target") = 1) /// если отправитель чатового сообщения имеет на себе переменную "Чтения мыслей", тогда... { if (GetCurrentHitPoints(oSender) >0) { object oListener = GetFirstObjectInArea(); string sAha = "~" + sMessage + "~"; while (GetIsPC(oListener) != TRUE || GetLocalInt(oListener, "ESP_listener") = 0) { oListener = GetNextObjectInArea(); } FloatingTextStringOnCreature(oListener, GetStringLowerCase(sAha), FALSE); /// его слова идут кому надо } return TRUE; /// и доходят до адресата также else if (GetCurrentHitPoints(oSender) < 0 & GetCurrentHitPoints(oSender) > 10) { sAha = "Мысли объекта взрываются пульсом боли, скоро он разгоняется до чистой агонии. Кажется, объект умирает!" FloatingTextStringOnCreature(oListener, GetStringLowerCase(sAha), FALSE); } } return TRUE; 3. Neverwinter Script /// Заклинание "Чтение мыслей" (Divination, Enchantment). 2 уровень. Время сотворения 5. Добавление к скрипту OnDisturbed модуля или шарда. Добавление к OnChat "Чтения мыслей" позволяет в качестве одного из эффектов заклинания заглянуть в рюкзак объекта, то есть OBJECT_SELF. Эта приписка не даст брать или класть туда вещи. if GetLocalInt(GetIsDead(OBJECT_SELF) != TRUE && OBJECT_SELF, "ESP_target" = 1) { object oItem=GetInventoryDisturbItem(); object oSpying = GetFirstObjectInArea(); int nType=GetInventoryDisturbType(); while (GetIsDead(OBJECT_SELF) != TRUE && GetIsPC(oSpying) != TRUE && oSpying != OBJECT_INVALID && GetLocalInt(oSpying, "ESP_listener") = 0 && GetLocalInt(OBJECT_SELF, "ESP_target") = 0) /// нас интересуют живые персонажи с переменной подслушивания { oSpying = GetNextObjectInArea(); } switch (nType) { case INVENTORY_DISTURB_TYPE_REMOVED: AssignCommand(OBJECT_SELF, ActionTakeItem(oItem), oSpying); break; case INVENTORY_DISTURB_TYPE_STOLEN: AssignCommand(OBJECT_SELF, ActionTakeItem(oItem), oSpying); break; case INVENTORY_DISTURB_TYPE_ADDED: AssignCommand(oSpying, ActionTakeItem(oItem), OBJECT_SELF); break; } } Что вы думаете? |
Sep 8 2009, 13:26
Сообщение
#5
|
|
Пушкин Класс: Обыватель Характер: Chaotic Neutral Раса: Гигант NWN: Тексты |
Новость: удалось установить на моем ноутбуке тулсет. Он даже запускается, и я могу писать диалоги и компилировать скрипты. (IMG:style_emoticons/kolobok_light/prankster2.gif) Но стоит попытаться создать зону или предмет, все, где фигурирует графика, и ХХХ. (IMG:style_emoticons/kolobok_light/vava.gif) Поэтому если кто-то может протестировать мои скрипты у себя, буду весьма благодарен.
|
Текстовая версия | Сейчас: 10th November 2024 - 22:17 |