в общем не хочет он строчки вставлять! ругается... говорить ему якобы не с кем, и команду вторую он не понимэ!
Так и я не понимаю. Откуда в скрипте КВЕСТА взялась запись Actor akSpeaker = akSpeakerRef as Actor ??? это топиковая переменная. Почему ВСЕ фрагменты == Fragment_0 ???
Ты что, открываешь сам стадийный скрипт QF_000ThePassageInPrison_010DF766 в последней вкладке квеста Scripts и пишешь там что-то вручную??? Просто копируешь блок нулевого фрагмента и вставляешь со своими командами... Мда... сильно! Это служебный скрипт, там ничего самостоятельно писать не надо, тем более, не понимая своих действий. Для этого есть окна Papyrus Fragment во вкладке стадий и в топиках. На нужном топике в этом окне вставляешь свои команды и компилируешь (там есть кнопочка). Если есть в командах свойства, то сперва добавляешь свойство через кнопку Properties и только потом пишешь сами команды, иначе компиляции без свойств не будет. Так же и со стадиями, там такое же окно, и точно также надо писать.
Скрипты топиков и стадий - разные скрипты. На каждый топик свой скрипт. На все стадии один общий квестовый стадийный скрипт.
Alias Property Pass Auto не Alias, а ReferenceAlias
Вот в этом посте расписано именно так, как писал ты сам https://modgames.net/forum/110-6941-997457-16-1380887341 Здесь в первом спойлере написаны стадии и скрипты на стадиях. В третьем спойлере написаны топики и скрипты на топиках. Вот поэтому там и применяется топиковая переменная akSpeaker, она отдаёт референс говорящего.
Если ты решил все команды прописать в стадиях, а не топиках, то и надо соответственно правильно прописать свойство. Game.GetPlayer().RemoveItem(Pass1.GetRef(), 1, false, akSpeaker) - это значит: "из инвентаря ГГ удаляется предмет Pass1.GetRef() в контейнер akSpeaker", т.е. в инвентарь НПС1. Поэтому надо указать движку, кто именно этот НПС, какой у него ID, иначе движок не будет знать, куда засунуть эту вещь. У тебя есть алиасы неписей, вот и надо вместо akSpeaker прописать ID актёра, которому будет дан предмет, а раз нет ID актёра и есть алиас с нужным ID актёра, то пишется алиас.GetActorRef() (естественно, вместо "алиас" пишется или GuardPrison, или PassInPrison, или как там у тебя алиас нпс1) алиас.GetActorRef() возвращает референс того, кто назначен на этот алиас.
значит так пункт по перемещению вещи от нпс2 к гг выполняется.. и тут же выполняется пункт по перемещению вещи к нпс1 на веще у меня сидит скрипт:
Всё правильно, ты сам так и сделал, твой скрипт на вещи переключает стадию на 40 сразу по добавлении в инвентарь ГГ. А ведь ГГ сперва должен вернуться к нпс1, поговорить с ним и только тогда отдать вещь. Этот скрипт на вещи вообще не нужен, его надо удалить.
Вот если бы по заданию надо было найти и забрать/подобрать эту вещь, вот тогда скрипт был бы нужен, а в твоём варианте он лишний.
*************** SetObjectiveDisplayed(40) - эти команды не надо везде вписывать, достаточно одной в стадии.
возможно нужно впереди команду добавить, чтобы он отдавал только после разговора с нпс1?
Нужно сделать, как написано выше, где пост со спойлерами. Там написано, что команды на добавление и удаление предмета находятся в топиках, а ты куда их вписал? Вот в топике нпс1 и должна быть команда на удаление вещи у ГГ, и естественно, в таком случае она удалится только после разговора с нпс1.
На нужном топике в этом окне вставляешь свои команды и компилируешь (там есть кнопочка). Если есть в командах свойства, то сперва добавляешь свойство через кнопку Properties и только потом пишешь сами команды, иначе компиляции без свойств не будет.
Скрипты топиков правильные. Все необходимые команды в них есть, и поэтому, если в стадиях квеста есть команды, то их ВСЕ надо удалить, т.е. не должно быть стадийных команд, да и самого стадийного скрипта тоже. Так же не должно быть скрипта на самом "пропуске" (ни на объекте, ни на алиасе).
Должно быть в квесте 3 оранжевых блока топиков, связей (линий со стрелками) между этими блоками быть не должно, вообще никакой.
akActivator - что это такое и откуда оно взялось? Это переменная, а раз переменная, то откуда она взялась и где назначено ей значение? А взялась она из события - это тот, кто активировал. Значит, она должна быть вписана в событии: Event OnActivate(ObjectReference akActivator)
Далее: If - это по русски "если", значит, проверка. У тебя написано If(ThePassageInPrison.SetStage(40) && akActivator == GuardPrison) Но SetStage(40) - это "назначить стадию 40", а тебе надо проверить и сравнить текущую стадию. Значит, надо GetStage() == 40
нпс как сидел на месте так и сидит... не хочет вставать и дёргать за рычаг.. а в аипакетах я не нашёл подобного пакета... (TryToEvaluatePackage())
TryToEvaluatePackage() - это команда на пересмотр пакетов актёра-алиаса, а не сам пакет. Чтобы актёр не ждал планового пересмотра пакетов (10-20 сек.), а сменил пакет сейчас. Алиасу надо дать пакет с типом Activate и там цель - твой рычаг, условие на пакете "стадия == 40". На рычаге скрипт, который я писал чуть раньше, чтобы при его активации переключалась стадия и квест выключался, и ГГ телепортировался.
*************** Нужного тебе пакета нет в списке, ведь нет ни одного пакета с целью - "твой новый рычаг". В Скайриме пакеты добавить скриптом нельзя, нет такой команды.
Изменение репутации для пользователя AleksTirex
AleksTirexOffline
Сообщение №160
| Тема: Вопросы по скриптам Papyrus
написано: 7 октября 2013, 20:27
| Отредактировано: AleksTirex - 7 октября 2013, 21:33
можно ли в Папирусе можно создать двухмерный массив
Не уверен, но вроде бы нельзя.
Array = {1,2,3} не многим отличается от Array[1]=1, Array[2]=2, Array[3]=3 , есть ли смысл заморачиваться? Если массив объектный, то можно форм-лист составить, если цифровой, то можно циклом прописать используя коэффициент (*2.3 или /1.28 или + 1 и т.д). А если цифры хаотичные, то проще вручную прописать Array[1]=1, Array[2]=2, Array[3]=3
Если это для времени анимации, то лучше вручную, т.к. всё равно придётся корректировать не один раз.
Можно и "провиртуалить" массивы, но можно и просто сделать два массива (строковый и числовой) с равной длиной, где порядок заполнения будет соответствовать друг другу: anim[0] - анимашка №1 fTime[0] - время работы анимашки №1 anim[1] - анимашка №2 fTime[1] - время работы анимашки №2 (пример такого использования чуть ниже)
"допустимых вариантов" - а что, есть несовместимые анимации? И много ли таких вариантов?
Возможно, проще разбить анимации по своим массивам по принципу совместимости. Или индексировать анимации по совместимости, например, несовместимые раскидывать в начало и конец массива. Тогда:
int index While ... if index < 5 ;активная анимашка в зоне плохой совместимости index = RandomInt(0, 20) ;после 20 идут анимашки с плохой совместимостью с анимашками 0-5 elseif index > 20 index = RandomInt(5, 25) else index = RandomInt(0, 25) endif SendAnimationEvent(player, anim[index]) Wait(fTime[index]) ... endWhile
А условие на пакете "стадия == 40" сделана? (вкладка Conditions)
Если нет, то добавь и тести на чистом сейве. (скрипт и свойства правильные. Возможно, надо будет ввести задержку командой Utility.Wait(1.5) перед командой телепортации, для лучшего визуального эффекта)
********* TranslateToRef() - это не латентная функция, в отличии от Wait(), скрипт не будет ждать её исполнения, а сразу же начнёт исполнять следующую команду. Для "ожидания" есть своё событие OnTranslationComplete(). Поэтому можно было сразу написать Game.GetPlayer().TranslateToRef(Point7, 200), т.к. только эта функция будет работать (она заменит все предыдущие). Писать Utility.Wait(0.0) не стоит - время нулевое, поэтому никаких действий не будет.
Изменение репутации для пользователя AleksTirex
AleksTirexOffline
Сообщение №171
| Тема: Вопросы по скриптам Papyrus
написано: 17 октября 2013, 13:30
| Отредактировано: AleksTirex - 17 октября 2013, 13:46
Без SKSE не узнать, какой именно оутфит носил НПС.
Возврат ВСЕЙ одежды обратно ГГ необходим потому, что при смене оутфитов одежда бесследно удаляется у НПС (не только надетая, а практически вся броня и шмотки, кольца и амулеты не исчезают, это дефолтный баг/эффект). Для упрощения сделан возврат игроку всего содержимого инвентаря непися (можно и только одежду возвращать, но тогда скрипт заметно усложнится). В блоке OnEquipped команду на удаление вещей можно и не писать, если игрок предварительно заберёт сам всю одежду у НПС, но это неудобно. Но здесь есть "баг" - броня-оутфит тоже перемещается к ГГ. Чтобы было всё красиво и без недостатков, надо заметно усложнить скрипт.
Myprism, так же попробуй вариант не с перемещением вещей НПС к игроку, а с сундуком. Т.е. сперва все вещи НПС перемещаешь в свой сундук, потом меняешь оутфит, а после этого из того сундука все вещи возвращаешь НПС. Какой вариант больше понравится.
Результаты очень интересные. Строка akActor.RemoveAllItems(Game.GetPlayer()) оказалась не нужна вообще.
Должен огорчить - нужна эта команда. Если её нет, то при смене оутфита из инвентаря НПС-компаньона пропадёт одежда, практически вся, которую ты туда положил, что весьма жалко.
Вот посмотри: 1. На НПС одежда из родного оутфит, ты поменял оутфит и НПС теперь имеет новую одежду (или ничего, если оутфит пустой). 2. Теперь ты удалил всё из инвентаря НПС, он типа опять оделся в одежду из родного оутфит. После этого меняешь оутфит на новый и... и получаешь 100% эффект из пункта №1.
К тому же, при смене оутфита старые шмотки автоматически удаляются из инвентаря. Т.е. разницы быть не должно ни при каком варианте, если скрипт написан правильно и пустой оутфит сделан и назначен тоже правильно. Оутфит сменится в любом случае, у НПС не может остаться старый родной.
Если все потенциальные актёры - уникальные, то можешь поиграться с актёр-базовый актёр. akActor.SetOutfit(kOutfitEmpty) akActor.GetActorBase().SetOutfit(kOutfitEmpty) Результаты таких команд разные.
*******************
VALKNUT, пакеты добавляются через алиасы или сцены. Если пакет долговременный (не на пару минут), то делаешь алиас, в него добавляешь нужный пакет, потом в топике akMyAlias.ForceRefTo(akSpeaker). И теперь говорящий прописан в алиас, а на алиасе пакет, и пакет получится на этом актёре. Для удаления пакта - akMyAlias.Clear(). Если НПС принадлежит нескольким алиасам, то приоритетный пакет тот, чей квест имеет выше приоритет.
Если бы это был один НПС, то можно было бы прописать пакет только ему и запускать его по нужной стадии квеста... а если мне нужно, чтоб это был ЛЮБОЙ нужный НПС, то тут уже грабли...
Делаешь всой квест, там алиас с пустой позицией Specific Reference и галочкой Optional. Алиасу в соответстующем месте добавляешь пакет. Приоритет пакета определяется приоритетом его квеста, поэтому приоритет квеста надо ставить 75-90, тогда этот пакет перекроет все остальные пакеты. Добавление пакета НПСу - назначение этого НПС алиасу:
ReferenceAlias Property akMyAlias Auto
akMyAlias.ForceRefTo(akActor)
Удаление пакета у НПС - очистка алиаса от ссылки на этого НПС:
akMyAlias.Clear()
Важно: при работе с алиасами свойства должны быть ReferenceAlias, а не Alias.
Код
И, раз я научился менять оутфиты, хочу сделать переодевание ко сну хоть у своих персонажей. В связи с этим вопрос: как засекать события засыпания и просыпания?
Package Property akPackageSleep Auto
Event OnPackageStart(Package akNewPackage) if akNewPackage == akPackageSleep ; пакет начался, НПС идёт к кровати endif endEvent
Event OnPackageEnd(Package akOldPackage) if akOldPackage == akPackageSleep ; пакет продолжается, НПС лёг на кровать endif endEvent
Event OnPackageChange(Package akOldPackage) if akOldPackage == akPackageSleep ; пакет закончился, НПС встал с кровати endif endEvent
Код
А ведь GhostAbility стоит именно у базового актёра и у него я пока не знаю как её убирать
**** Но можно и не удалять сам спелл, а просто сделать условия на этом спелле, и управляя этим условием - управлять спеллом. Можно и глобалкой, но лучше привязать условие спелла к своему скрипту. Для этого надо сделать скрипт и свойство "общедоступными", т.е. conditional, тогда это свойство можно использовать в любых условиях на любых объектах.
Есть одно НО. Если я отправляю в указанное место НПС, то он возвращается ко мне, как только я отправляю в указанную локацию второго(третьего.. не важно) НПС... как побороть это?
Один алиас - один актёр. Двух актёров на один алиас не назначить, что очевидно. Поэтому второй актёр прописывается вместо первого, поэтому у первого уже нет пакета алиаса и он идёт обратно. Надо сделать необходимое количество алиасов и назначать нового актёра на свободный алиас. Те же актёры, которые больше не должны сидеть в "той локации", надо те алиасы очищать.
Т.е. надо делать цикл проверки алиасов на их заполнение. Проще всего сделать массив, прописать там алиасы и цклом проверять всё это. Сколько ты планируешь задействовать одновременно актёров для отправки в "ту локацию"? Учти, столько же надо будет сделать алиасов (они все идентичны). Если с массивами не справишься - помогу.
**** Увы, но с пакетами работают только алиасы и сцены (а в сценах - алиасы), т.е. пакет можно только через алиас передать актёру. Это фишка разрабов. (если кто знает другой вариант добавить пакет - пишите)
Код
Как узнать актёра в скрипте на отслеживание смены AI-пакетов?
Странный вопрос - на ком висит скрипт с отслеживанием работы пакета, тот и есть нужный актёр. Если имеешь в виду, какой референс у твоего актёра, то Self возвращает хозяина скрипта: Actor akActor = Self Если это алиас, то Actor akActor = Self.GetActorRef() Если скрипт висит на актёре, но имеет тип ObjectReference, тогда Actor akActor = Self as Actor
Код
Вот только актёра я передаю скрипту через параметр
Совсем ничего не понял. Что значит через параметр? Пример в студию.
Делаешь своего актёра манекена. На него вешаешь свой скрипт вместо дефолтного, он сделан на основе скрипта манекена, но с маленькой доработкой:
Добавляешь свойства: Activator Property MannequinActivateTrig Auto Static Property XMarkerHeading Auto ObjectReference akMarkerHeading ; референс маркера XMarkerHeading
Добавляешь функцию: Function CreateMarkers() self.PlaceAtMe(MannequinActivateTrig) akMarkerHeading = self.PlaceAtMe(XMarkerHeading) endFunction
Во ВСЕХ местах скрипта меняешь MoveTo(GetLinkedRef()) на MoveTo(akMarkerHeading)
**************** В своём скрипте на создание манекена делаешь так:
Actor akNewMannequin = akMarker.PlaceActorAtMe(MannequinBase) Utility.Wait(0.5) (akNewMannequin as myMannequinActivatorScript).CreateMarkers()
myMannequinActivatorScript - название своего скрипта манекена, менять можно как угодно, но название скрипта и эта строка должны совпадать. Свойство MannequinBase - назначается свой базовый манекен, название любое.
Добавлено (27 Октября 2013, 15:59) ---------------------------------------------
Код
Ругается во всех трёх вариантах одинаково
И правильно ругается - команды не могут работать вне тела/блоков функций или событий. К тому же, событие OnPackageStart на ObjectReference работать не может, оно работает на актёре или алиасе.
Скрипт висит же на актёре? Тогда меняй тип скрипта Scriptname aaSleeping extends ObjectReferenceActor
Сами события будут такими:
Event OnPackageStart(Package akNewPackage) if akNewPackage == akPackageSleep ; пакет начался, НПС идёт к кровати kOutfit = self.GetActorBase().GetOutfit(false) self.SetOutfit(self.GetActorBase().GetOutfit(true)) endif endEvent
Или так:
Event OnPackageStart(Package akNewPackage) Actor akActor = Self as Actor if akNewPackage == akPackageSleep ; пакет начался, НПС идёт к кровати kOutfit = akActor.GetActorBase().GetOutfit(false) akActor.SetOutfit(akActor.GetActorBase().GetOutfit(true)) endif endEvent
Или так:
Event OnPackageStart(Package akNewPackage) if akNewPackage == akPackageSleep ; пакет начался, НПС идёт к кровати kOutfit = GetActorBase().GetOutfit(false) SetOutfit(GetActorBase().GetOutfit(true)) endif endEven
******* По умолчанию скрипт всегда использует "хозяина", т.е. Self, если для команды не назначен другой объект. Поэтому self.GetActorBase() == GetActorBase()
Да думаю, что не больше 10. Да, не справлюсь, помощь очень нужна.
На всякий случай сделал на 18 алиасов. Лучше всего использовать в квесте, причём постоянно работающий без выключения. Если будешь скрипт добавлять в свой уже существующий квест, то тест только на чистой сохранке. Всем свойствам алиасов не забывай назначать свои алиасы из квеста. На алиасах должна быть галочка Optional.
Scriptname aMyQuestScript extends Quest
ReferenceAlias Property Alias1 Auto ReferenceAlias Property Alias2 Auto ReferenceAlias Property Alias3 Auto ReferenceAlias Property Alias4 Auto ReferenceAlias Property Alias5 Auto ReferenceAlias Property Alias6 Auto ReferenceAlias Property Alias7 Auto ReferenceAlias Property Alias8 Auto ReferenceAlias Property Alias9 Auto ReferenceAlias Property Alias10 Auto ReferenceAlias Property Alias11 Auto ReferenceAlias Property Alias12 Auto ReferenceAlias Property Alias13 Auto ReferenceAlias Property Alias14 Auto ReferenceAlias Property Alias15 Auto ReferenceAlias Property Alias16 Auto ReferenceAlias Property Alias17 Auto ReferenceAlias Property Alias18 Auto ReferenceAlias[] aAliasAA
Function ClearAlias(Actor akActor) int index While index < 18 if aAliasAA[index].GetActorRef() == akActor aAliasAA[index].Clear() endif index += 1 endWhile endFunction
Function ForceAlias(Actor akActor) int index bool bForceAlias While index < 18 && bForceAlias == false bForceAlias = aAliasAA[index].ForceRefIfEmpty(akActor) if bForceAlias akActor.EvaluatePackage() endif index += 1 endWhile if index >= 18 ; debug.notification("Aliass Full !!!!!!") endif endFunction
************************************************************* aMyQuest - постоянно работающий квест
Назначить алиасу нужного актёра: (aMyQuest as aMyQuestScript).ForceAlias(akCurrentActor) ; если это из другого скрипта ForceAlias(akCurrentActor) ; если из этого же скрипта akCurrentActor - референс данного актёра для передачи алиасу
Удалить у алиаса актёра: (aMyQuest as aMyQuestScript).ClearAlias(akOldActor) ; если это из другого скрипта ClearAlias(akOldActor) ; если из этого же скрипта akOldActor - референс удаляемого актёра из алиаса
Добавлено (27 Октября 2013, 17:41) --------------------------------------------- Можешь добавить функцию на полную очистку всех алиасов:
Function ClearAllAliass() int index While index < 18 aAliasAA[index].Clear() index += 1 endWhile endFunction
На сам алиас желательно повесть скрипт на случай смерти НПС, чтобы его алиас очистился:
Event OnDeath(Actor akKiller) Clear() endEvent
На все алиасы один и тот же скрипт. Алисасы проще делать так: создал один и полностью его настроил, т.е. поставил нужные галочки и добавил скрипт. Потом просто дублируешь алиас и прописываешь дубликату своё имя.
Я делаю какую-то простую ошибку [img]http://modgames.net/forumstyle/Smail/sad.gif Там же в алиасе неписи и места для инвентаря и для молитв, а у меня туда ничего не передаётся, вещей не оказывается, а молитвы не действуют.
Совсем простую - ты тестишь на грязном сейве (!). Ты загрузи тот сейв, где ещё ни разу не было твоего квеста, тогда и ключ появится и предметы со спеллами. У тебя нет ключа и спеллов потому, что алиас не заполнился.
Уникальный или левельный актёр - разницы нет, он по любому будет вписан в алиас и ему будут добавлены предметы, спеллы и фракции с пакетами.
Алиасы заполняются в момент старта квеста. Если квест уже работает, то новый алиас как правило уже не заполняется. Алиас ключа всегда должен быть ниже в списке, чем алиас актёра, которому будет дан этот ключ.
Если изначально актёр может быть выключенным или дохленьким, то надо ставить галочки Allow Disabled и Allow Dead. Если квест запускается не автоматически, то желательна галочка Allow Reserved.
Добавлено (27 Октября 2013, 20:12) ---------------------------------------------
Код
Никак не могу заставить призванного некроскелета использовать заклинание "истерия". Заклинание призыва и вытягивание жизни использует, а вот итерию ни в какую... В чем тут дело?
И не будет использовать, пока его навык "Иллюзия" не достигнет 100. Если хочешь неписю прикрутить такой спелл, то ты должен сделать свою копию спелла и маг.эффекта. В маг.эффекте в графе Minimum Skill Level поставить "0". Потом этот спелл и добавляй неписю.
Скажи, пожалуйста, для правильного заполнения алиасов достаточно ли сделать один сев в игре с отключенным модом, или надо чисто проходить её до этого места? Правильно ли ставить квестам галочку, чтобы они начинались с самого начала игры?
Да, достаточно просто сейв, где ещё нет следов от этого мода. Ведь неизвестно, когда игрок поставит этот мод, и как долго он будет добираться до этого места. Алиасы заполнятся в любом случае, если правильно сделаны. Делать сейв "у этого места" просто удобнее для теста, а так, разницы нет.
А вот посещал ли ты локацию, которая будет задействована в квесте, так это уже "технический" вопрос. Т.е. по самому принципу работы/исполнения твоего квеста будет зависеть правильность его работы. Поэтому желательно иметь два сохранения - с пройденной локацией и с не пройденной (ведь в реальной игре бывают оба варианта). Тогда можно будет проверить, как скажется на работе квеста сам факт посещения или нет этой локации. (иногда бывает, что квесты и скрипты по разному реагируют на эти события)
Если в квесте имеются диалоги, то нельзя (крайне нежелательно) делать автозапуск квеста. Ведь до первой перезагрузки игры диалоги у таких квестов не появляются. Тогда надо делать запуск по событию или свой скриптовый автозапуск.
Добавлено (28 Октября 2013, 16:15) ---------------------------------------------
Код
Причем если я меняю рассу на обычного скелета, то он все использует, и не только скопированные заклинания но и стандартные, без проблем. Это как то связано с рассой, но как именно не пойму...
Конечно связано. Заклинание может быть применено неписем только тогда, когда у непися имеется соответствующая анимация для данного заклинания. (скриптово можно и без анимации akSpell.Cast(NPC)) У всех рас разный набор анимаций (у НПС он на все расы один). Например, оборотни вообще не могут кастовать, у них нет анимации для магии, Драконьи жрецы не могут использовать оружие, и т.д.