• Прежде, чем задать вопрос, пожалуйста, убедитесь, что такой вопрос не задавался раньше. Старайтесь описать суть вопроса как можно подробней. • Прежде, чем опубликовать ответ на вопрос, пожалуйста, убедитесь, что обладаете необходимыми для этого знаниями. Старайтесь cформулировать суть ответа как можно лаконичней. • При желании ответить в приватном порядке, пожалуйста, воспользуйтесь ЛС. • При желании поблагодарить ответившего, пожалуйста, воспользуйтесь кнопкой "+" полезного сообщения.
Сообщения, не относящиеся к вопросам по скриптам Papyrus, ответам на них или уточнениям, являются оффтопом и могут быть удалены.
Красное солнце Есть вопросы по скриптам Papyrus? Пиши не в ЛС, а в эту тему.
Myprism, я только об одном плюсе слышал: возможность сразу обнаружить то, что ты забыл поставить второй "=" в операторе "==". Но все-равно так очень мало кто делает.
А за переодевание... Если охота будет, то можно сделать его совместимым с любыми модами. Надо только подумать, как. Ну, например, невидимую ауру вокруг игрока, которая будет накладывать на всех магический эффект со скриптом. Или не на всех, а только на teammate. Неоправданная трата ресурсов, да? Я когда-то делал мод, чтоб спутники не вступали в бой и игнорирвали врагов, пока игрок в режиме скрытности. Тоже был нужен способ засовывать спутника в алиас, не зависимо от установленных модов. Да еще чтоб на Серану работало. Я тогда забил и просто добавил в диалог опцию "Пожалуйста, не выдавай наше присутствие.".
Изменение репутации для пользователя emelya8307
emelya8307Offline
Сообщение №2882
написано: 18 апреля 2020, 19:08
| Отредактировано: Multigone - 21 апреля 2020, 18:54
Емеля, если Вы в Яндексе погуглите "Скайрим Курица", то в первой же статье прочтёте вот такое примечание.
Нет, просто у курицы, оказывается, стоит флаг "Simple Actor", а это значт в том числе, что "Also disables the Story Manager's Death and Assault events".
То есть убийство курицы, как я понял, отключено в ивентах Story Manager, а у меня как раз этот квест построен на событии OnStoryKillActor, Стори Менеджер просто его не фиксирует. А как фиксировать я не знаю, я всего лишь третью неделю изучаю скрипты и квесты.
Multigone, буквально нашёл в коде мода, с которым сейчас разбираюсь вот такие штуки (именно то, о чём ты говорил):
Код
String n = ((self as ReferenceAlias) As TweakSettings).originalName if (n == "Erik") invCode=10 elseif (n == "Iona") invCode=1 elseif (n == "Calder") invCode=1 ..............................
И если переводчик пытался эти строки переводить, то, естественно, получал неработающий код. Иногда этот код поражает меня своим объёмом и аккуратностью, но иногда натыкаюсь вот на такую фигню...
Добавлено (26 Апреля 2020, 07:59) --------------------------------------------- Как скриптом изменить Outfit? Нет, не заменить у персонажа один Outfit на другой, а именно изменить имеющийся или создать новый. Outfit является расширением Form. Из описания следует, что это специальная разновидность FormList, которая принимает только объекты Armor. Есть команда getoutfit(), в SKSE есть команды: getnumparts() и GetNthPart(Int n), т.е. получить этот список легко, можно получить и его компоненты. Но как решить обратную задачу, т.е. закинуть туда свой объект? Приведение FormList, Form[], Armor[] к(as) Outfit не работает, сообщается о несовместимости типов.
Добавлено (26 Апреля 2020, 13:11) --------------------------------------------- Нет ли способа принудительно по ID (как по указателю в других языках) подсунуть туда данные, не объявляя типа в явном виде?
Приведение FormList, Form[], Armor[] к(as) Outfit не работает, сообщается о несовместимости типов.
А что бы это дало?
Код
Outfit Property MyOTFT Auto FormList Property MyFLST Auto
FUNCTION MyFun() MyOTFT = MyFLST AS Outfit ; Даже если бы это работало, это было бы простое присвоение переменной MyOTFT, ранее заполненной / / твоим комплектом, нового значения в виде MyFLST AS Outfit. Над базовой формой твоего комплекта при этом не совешится / / никаких действий, для этого нужна к.-л. функция (типа MyOTFT.SetSomePart(n)).
Единственное, что приходит на ум, это управление вещами комплекта через LVLI с помощью глобальных, но для этого LVLI уже должен быть там и заменять собой все или некоторые вещи.
Я в свое время способа не нашел. Разве что действительно создавать специальные аутфиты из LeveledItem. Там есть функции AddForm() и Revert(). Либо, как это делали большинство модов, устанавливать НИПам пустой аутфит и надевать на них все вещи вручную. Только после отключения мода они могут и голыми остаться т.к. оригинальный аутфит не вернется.
Dsion, вот в том то и дело, что мне хочется, чтобы отпущенный на волю персонаж оставался с новым оутфитом, который создал для него игрок.
Цитата Dsion
Разве что действительно создавать специальные аутфиты из LeveledItem. Там есть функции AddForm() и Revert().
А вот это мне нравится! Ведь тогда я могу менять не аутфит, а левельный список который в нём лежит! Только надо продумать, как это сделать не для всех персонажей, а только для тех, кого игрок захочет переодевать в первую очередь. Или сделать пару десятков таких аутфитов и выдавать их последним нанятым и освобождённым спутникам и когда запас подготовленных аутфитов закончится, освобождать их с конца. Надо думать. Multigone, похоже, надо просто заменять аутфит у отпущенного персонажа на тот, что содержит только один левельный список.
Если установить НИП "голый" аутфит, а потом надеть вещи функцией equipitem() с флагом preventunequip, то они, вроде, эти вещи больше и не снимают. Даже если отключить мод. Я бы потестил оба варианта.
Dsion, Буду всё пробовать. Сейчас игра ставит стандартный аутфит при смене интеллектуального пакета. Но если в обработчик события смены пакета поставить добавление персонажу некоторой шмотки (лук спутника, например) и тут же отобрать её обратно, то на время действия пакета игра ставит персонажу наилучший комплект из имеющихся у персонажа шмоток, вместо стандартного аутфита. Это я уже проверил.
Уважаемые скриптеры. Хочу сделать, чтобы в сообщениях квеста отображалось количество убитых определенных персонажей. В игровых квестах это делается через тег <Global=MyGlobal>, тег заменяется значением из глобальной переменной MyGlobal . Но у меня всегда цифра 0. В Quest Data в окне Text Display Globals я эту переменную вписал. При убийстве определенные персонажи вносятся в эту глобальную переменную. Другие скрипты её значение нормально видят и работают с ней правильно. А в тексте сообщения, выводимого квестом всегда "убито 0". Пишу так: "Убито <Global=MyGlobal>" Смотрел в игровых квестах, например, про виноград джазби - точно так же сделано. Но там нормально выводится значение. Вносить значение в переменную пробовал разными командами, например: MyGlobal.SetValue(MyGlobal.GetValue() +1) или ModObjectiveGlobal(1, MyGlobal) или MyGlobal.Value +=1 и еще другими способами. У меня совсем нет опыта, многое делаю наугад или по аналогии с другими скриптами.
emelya8307, присоединяюсь к вопросу. Я попробовал сделать это позавчера и так же не получилось. Только у меня это не первоочередная задача, поэтому я отложил её. Что-то мы одно и то же пропускаем сделать.
emelya8307, Myprism, там в первом табе настроек квеста был какой-то список, в который нужно вносить все глобалы, используемые для замены текста в квесте... Видели, да?
Изменение репутации для пользователя emelya8307
emelya8307Offline
Сообщение №2893
написано: 28 апреля 2020, 13:30
| Отредактировано: emelya8307 - 28 апреля 2020, 13:31
Dsion, Myprism, Multigone, спасибо за отклик. Заставил-таки отображаться значение переменной в сообщениях. Оно отбражается при условии, что значение переменной было изменено в этом же квесте. А у меня при событии убийства заносилось значение в переменную, затем стартовал другой квест, из которого я пытался выцепить это значение переменной. Но оно почему-то из другого квеста не читается. Хотя квесты связаны, и в пропертях ее обьявил, и в первой вкладке квеста прописал.
emelya8307, если ты разбирал квест с джазби, то, наверное, видел, что там используется UpdateCurrentInstanceGlobal() для обновления кэшированного значения глобальной (квест не читает значение напрямую?).
Multigone, да, я использовал UpdateCurrentInstanceGlobal(), но это ничего не давало. Квест читает только переменные, которые сам изменяет. Не знаю, как сделать по другому. Ну хотя бы так.
Как определить, каких случаях передаются данные, а в каких указатель на них. Так у меня есть скрипт:
Код
FormList Property TweakInv3 Auto FormList Property TweakInv4 Auto
Function InventorySnapshot() ............................ TweakInv4 = TweakInv3 ........................... endFunction
В игре обнаруживается, что любые изменения в TweakInv3 приводят к таким же изменениям TweakInv4. Т.е. в данном случае передался указатель на формлист. Как копировать именно содержимое, а самое главное: как различать, когда копируются данные, а когда только указатель?
Myprism, да, вроде, копируются только простые типы: int, float, bool, string. А всё, что наследует Form, - указатели. Только в Oblivion и только в OBSE была функция что-то типа CloneForm, которая позволяла создать временный клон формы и изменять его. Но этот клон даже не сохранялся в сейве.
Добавлено (30 Апреля 2020, 11:20) --------------------------------------------- Вместо формлистов, есть еще массивы в скриптах. Их можно копировать и изменять. Там только ограничение на 128 элементов.
И у них есть преимущество: в них можно записывать одинаковые объекты, в то время, как в формлист только разные.
В скрипте, с которым я сейчас разбираюсь, объявлено довольно много переменных вот таким образом:
Код
Form Property lastLeftWeapon Auto Form property lastRightWeapon Auto int property lastLeftCharge Auto int property lastRightCharge Auto
Т.е. предусмотрено заполнение их как свойств извне. Но извне они никак не заполняются. Таким образом, автор скрипта использует их как обычные переменные скрипта. Одновременно, в скрипте нет других обычных переменных не объявленных свойствами. Правильно ли это? В чём сермяжная правда - объявлять все переменные свойствами, даже те, что в моде не заполняются?
Myprism, можно оперировать Property переменными из др. скриптов, не используя напрямую ту форму, к которой прицеплен этот скрипт (т.е. не определяется через Use Info). Что-нибудь такое:
Код
Event OnTriggerEnter(ObjectReference akActionRef) IF akActionRef AS Actor MyActorScriptName xRandomName = (akActionRef AS Actor) AS MyActorScriptName IF xRandomName Int iRandomName = xRandomName.lastLeftCharge ... EndEvent
Изменение репутации для пользователя Myprism
MyprismOffline
Сообщение №2901
написано: 4 мая 2020, 10:13
| Отредактировано: Myprism - 4 мая 2020, 10:14
Multigone, т.е. единственное оправдание - возможность менять переменную из другого скрипта? Dsion, сейчас есть временный клон формы TempClone(), например:
Код
Actor npc0 = npc.TempClone() as Actor
вроде работает.
Добавлено (06 Мая 2020, 11:15) --------------------------------------------- Попал в очередную засаду. Вот фрагмент кода:
Весь код очень большой, поэтому я вычленил только значимый фрагмент. Дело в том, что если я размещаю в коде отладочное сообщение Debug.MessageBox( "Stop" ) вот в том месте, где оно стоит сейчас, то всё работает так, как мне нужно (это ещё не значит, что правильно ) Если это сообщение закоментарить, нужной мне работы не будет. Это же сообщение поставленное там, где оно сейчас закоментарено (ниже по коду), нужной мне работы не даёт (не действует). 1. Почему код с отладочным сообщением работает иначе, чем без него? Понятно, что это сообщение вызывает остановку (задержку) выполнения кода. Но когда я вместо него ставлю просто заведомо большую задержку (она сейчас закоментарена), то это не помогает. 2. Почему отладочное сообщение поставленное до строки Armor TItem = SleepOutfit.getNthPart( CN ) as Armor действует иначе, чем после неё. Переменная TItem только обозначена, заполнена, но больше нигде не используется (для поиска разгадки я всё остальное отрубил).
Dsion, да вроде в Скайриме всё с 0 начинается... Вот пример:
Код
Actor property Ralof Auto int NumPart
Function Outfit() NumPart = Ralof.GetActorBase().getoutfit().getnumparts() while NumPart Numpart -= 1 Form Clothing = Ralof.GetActorBase().GetOutfit().getNthPart(NumPart) If (Clothing.IsCuirass()) ;Checks for the Cuirass Keyword. Debug.Trace("Index " + NumPart + " is a Cuirass.") EndIf EndWhile EndFunction
Цикл выполняется пока NumPart на его входе больше 0. Т.е. от общего числа уменьшается до 1, которая тут же уменьшается до 0. Т.е. младшим членом является нулевой.
А, сорян, это в LUA с 1 (я на нем аддоны для WOW писал). Везде с нуля, а вот LUA почему-то решили пооригинальничать. Не, без понятия, почему не работает скрипт.
Изменение репутации для пользователя xCYNICx
xCYNICxOffline
Сообщение №2905
написано: 31 мая 2020, 07:13
| Отредактировано: xCYNICx - 31 мая 2020, 09:22
Здрасти всем. Если тут еще кто-то есть, можете помочь? Я тут создал несколько paired animations, и при помощи FNISS зарегистрировал соответствующие Anim Events. Теперь CK видит мои анимации. Я создал заклинание с магическим эффектом со скриптом, что бы проигрывать эти анимации. Все работает, но есть проблема. Эти анимации не Killmovesб после их проигрывания не предусматривается убийство NPC. И тут оказывается что если вызвать анимации во время боя, после проигрывания непись перестает сражаться и вообще что-либо делать, он тупо бегает вокруг игрока и ничего не делает)) Есть ли возможность как то это исправить, что бы после проигрывания парной анимации непись возвращался в прежнее состояние? Вообще я новичок в скриптах, прошу тапками не закидывать.
Idle Property pa_01 Auto
Event OnEffectStart(Actor akTarget, Actor akCaster) akCaster.PlayIdleWithTarget(pa_01, akTarget)
Endevent
[b]Добавлено[/b] (31 Мая 2020, 12:09) --------------------------------------------- Дополню. Путем многочисленных проб я обнаружил, что если в мое заклинание, инициирующее проигрывание анимации, добавить ванильный магический эффект - calm, который понижает агрессию NPC и выставить его длительность больше, чем длительность парной анимации, то после проигрывания анимации во время боя, непись снова продолжает бой, а не бегает вокруг. Видимо это как то связано с behaviors NPC во время боя, ведь парные анимации это по сути айдлы, которые должны работать в спокойном состоянии, а я пытаюсь их впихнуть во время боя. Есть ли возможность добиться такого же эффекта в самом скрипте без дополнительного эффекта calm в моем заклинании.
Мне просто захотелось освежить немного боевку скайрима эффектами типа killmoves, но только без убийства, что бы после анимации бой продолжился. Кстати, я сейчас подумал, а можно ли с помощью скрипта на время проигрывания анимации замедлить время для остальных персонажей, такой эффект слоумо, но только что бы парная анимация воспроизводилась без замедления на персонаже и NPC? Еще забыл упомянуть, помимо всего прочего, после проигрывания моей анимации персонаж игрока переходит в состояние вне боя, приходится переэкипировать оружие каждый раз, есть ли какая нибудь команда как его принудительно вернуть в состояние в котором он был до воспроизведения анимации, проблема не критична, но надоедлива.
Попробуй ре-экипировать оружие скриптом (UnequipItem / EquipItem).
Спасибо за совет. Я пока только учусь папирусу, поэтому не знаю как снять конкретное оружие с NPC, но я использовал команду aktarget.unequipall(), а затем после проигрывания IdleStop_Loose анимации - akTarget.DrawWeapon().
В результате эффект получился почти такой же как я и ожидал. Неписи реагируют на обстановку и сражаются, только в трусах. Осталось понять как снимать с них только оружие, а не всю экипировку. Вт что я добавил в своем скрипте:
xCYNICx, все функции есть в исходниках (Data/Scripts/Source). Смотри, что расширяет скрипт, который ты пишешь (Например, заголовок "Script MyScript Extends Actor"), ищи в исходниках .psc с таким именем (Actor.psc), в нем будут все допустимые функции для этого типа форм с комментами. Больше инфо о любой функции можно получить здесь, набрав в поиске ее название. Также смотри, что расширяет Actor.psc (ObjectReference), ищи ObjectReference.psc и смотри все функции, многие из них могут применяться в том числе к Actor. И так далее. Большинство скрипт-объектов имеют иерархию.
В твоем случае нужно определить, что именно влияет на исправление - экипирование, проигрывание IdleStop_Loose или мб что-то другое. Ре-экипировать оружие можно так:
Если есть SKSE:
Код
Form ActorObject = akTarget.GetEquippedObject(0) IF ActorObject akTarget.UnequipItem(ActorObject) Utility.Wait(0.01) akTarget.EquipItem(ActorObject) ELSE ActorObject = akTarget.GetEquippedObject(1) IF ActorObject akTarget.UnequipItem(ActorObject) Utility.Wait(0.01) akTarget.EquipItem(ActorObject) ELSE Debug.Notification("У актера нет ничего.") ENDIF ENDIF
xCYNICx, все функции есть в исходниках (Data/Scripts/Source). Смотри, что расширяет скрипт, который ты пишешь (Например, заголовок "Script MyScript Extends Actor"), ищи в исходниках .psc с таким именем (Actor.psc), в нем будут все допустимые функции для этого типа форм с комментами. Больше инфо о любой функции можно получить здесь, набрав в поиске ее название. Также смотри, что расширяет Actor.psc (ObjectReference), ищи ObjectReference.psc и смотри все функции, многие из них могут применяться в том числе к Actor. И так далее. Большинство скрипт-объектов имеют иерархию.
Спасибо за подсказку. Теперь буду знать где искать полезные функции. Попробую все предложенные тобой варианты. Надеюсь все заработает)
У меня возник еще один вопрос. Как можно определить под каким углом стоит НПС по отношению к игроку. Например я хочу чтобы событие (анимация) произошло когда НПС стоит спиной или лицом к персонажу. Я вписал в скрипт такой код. Но работает он как то не правильно, как будто рандомно. Видимо я использую не ту функцию: