Модератор форума: Kris†a™  
Форум » TES V: Skyrim » Мастерская » Вопросы по скриптам Papyrus (О скриптах Papyrus (Skyrim). Скриптеры не проходите мимо!)

Вопросы по скриптам Papyrus
sansuli  Offline  Сообщение №1 написано: 31 августа 2012, 13:29 | Отредактировано: Multigone - 23 апреля 2020, 14:24


The Red Sun


193
Уроки по скриптованию на языке Papyrus
Прежде чем задать вопрос просмотрите вышеуказанные уроки.
ok


Тема регламентирована.


• Прежде, чем задать вопрос, пожалуйста, убедитесь, что такой вопрос не задавался раньше. Старайтесь описать суть вопроса как можно подробней.
• Прежде, чем опубликовать ответ на вопрос, пожалуйста, убедитесь, что обладаете необходимыми для этого знаниями. Старайтесь cформулировать суть ответа как можно лаконичней.
• При желании ответить в приватном порядке, пожалуйста, воспользуйтесь ЛС.
• При желании поблагодарить ответившего, пожалуйста, воспользуйтесь кнопкой "
+" полезного сообщения.

Сообщения, не относящиеся к вопросам по скриптам Papyrus, ответам на них или уточнениям, являются оффтопом и могут быть удалены.

Красное солнце
Есть вопросы по скриптам Papyrus? Пиши не в ЛС, а в эту тему.
PitrPokir  Offline  Сообщение №2341 написано: 29 января 2017, 18:54



26
Не могу разобраться, что я сделал не так? Цель за мной не следует, никого не атакует, даже если бьют ее. Ходят просто по своему маршруту с обнаженным оружием. 
Код
Event OnEffectStart(Actor Target, Actor Caster)
       Target.RemoveFromAllFactions() 
       Target.AddToFaction(NecroUndead) 
       NecroUndead.SetAlly(Player) 
       Target.SetPlayerTeammate() 
       Target.SetActorValue("Confidence", 4) 
       Target.SetActorValue("Assistance", 1) 
       Target.SetActorValue("Aggression", 2)
EndEvent

Dsion  Offline  Сообщение №2342 написано: 29 января 2017, 19:05



PitrPokir, так ни одна из строчек скрипта и не заставляет цель за кем-то ходить... И еще обрати внимание, что почти каждая строчка вносит непоправимые изменения в характеристики актора. Не обязательно, конечно, но лично я попытался бы этого избежать. В идеале, после завершения действия заклинания, NPC должен оставаться в том же состоянии, в котором был до начала его действия...

Добавлено (29 Января 2017, 22:03)
---------------------------------------------
Если ты делаешь что-то типа временного подчинения живой цели (не призванной и не "поднятой"), то способ заставить её следовать за тобой, по сути, есть только один - засунуть её в алиас высокоприоритетного квеста. А на алиасе - пакет следования. См. квест DialogueFollower и скрипт на нем.

Добавлено (29 Января 2017, 22:05)
---------------------------------------------
Если нужно изменить Actor Value актора, лучше делать это через магический эффект. А если магическим эффектом не получается, то лучше вообще не делать. Сохранять оригинальное значение и восстанавливать его потом можно, но это хрень по многим причинам. Использовать ModActorValue - чуть лучше, но тоже хрень (если пользователь не вовремя отключит мод).


PitrPokir  Offline  Сообщение №2343 написано: 29 января 2017, 20:07



26
Dsion, мне надо призвать духа указанной цели и заставить его следовать за игроком, сражаться за игрока. Пока что я сделал тестовое заклинание на копию актера с накладыванием на него визуальных эффектов призрака и второе заклинание на подчинение, а вот оно работает непонятно как. Ни помощи в бою, ни следования. Во фракцию он попадает, т.к. он тоже становится врагом моих врагов (ну или это не из-за фракции, не знаю точно), а вот сам он какой-то пофигист.
В описании функции SetPlayerTeammate() сказано, что актер будет следовать и повторять некоторые действия за игроком, но в игре я этого не наблюдаю  :( 

П.С. с квестом как-то странно получается. У меня в планах, что бы у игрока была возможность делать несколько таких призраков и выходит, что к каждому будет квест начинаться? Или я не совсем понял. Но скриптики гляну, спасибо за наводку

Dsion  Offline  Сообщение №2344 написано: 29 января 2017, 20:20 | Отредактировано: Dsion - 29 января 2017, 20:40



Не, SetPlayerTeammate(), следовать не заставляет... И я бы вообще это не включал на твоем духе... Оно только заставляет актора доставать оружие одновременно с игроком, приседать одновременно с игроком и вступать в бой, когда вступает игрок. Но это всё только мешает... Особенно мешает вступление в бой для стелс-ориентированных игроков.
В общем, тебе точно надо разбираться с алиасами... Когда создается дух, сразу суешь его в алиас. На алиасе пакет следования.
Если нужно добавить духу заклинания (в том числе пассивные), добавляешь не скриптом, а на алиас. Если нужно добавить предметы, тоже на алиас. Фракции - на алиас. Ну итп. В первую очередь, можно добавить GhostAbility (или abGhostAbility - не помню точно) - тогда любой нип в алиасе станет похож на адского духа.

PitrPokir  Offline  Сообщение №2345 написано: 30 января 2017, 20:13



26
Dsion, да, верно. Я в описании воспринял "following" как "следование", а там имеется ввиду "следующее", лол.
А с алиасами и квестами вообще дел не имел. Можете вкратце написать как это реализуется?

Multigone  Offline  Сообщение №2346 написано: 30 января 2017, 21:05



832
Lexo, если проблему с выбрасыванием нужного референса щита (среди одинаковых) не решил, то у меня для тебя хорошие новости.

 
Код
ObjectReference Property xC1 Auto ; реф. пустого контейнера.
ObjectReference Property xC2 Auto ; реф. пустого контейнера.
ObjectReference Property PlayerRef Auto ; игрок.

FUNCTION F()
    Armor xARMO = (PlayerRef AS Actor).GetEquippedShield()
    IF xARMO
        Int iC = PlayerRef.GetItemCount(xARMO)
        IF iC > 99 ; слишком большое кол-во не обрабатываем.
        ELSEIF iC > 1
            WHILE iC
                PlayerRef.RemoveItem(xARMO, 1, true, xC1)
                IF (PlayerRef AS Actor).GetEquippedShield()
                    xC1.RemoveItem(xARMO, 1, true, xC2)
                    iC -= 1
                ELSE
                    PlayerRef.RemoveItem(xARMO, PlayerRef.GetItemCount(xARMO), true, xC2)
                    xC1.RemoveItem(xARMO, 1, true, PlayerRef)
                    PlayerRef.DropObject(xARMO, 1)
                    iC = 0
                ENDIF
            ENDWHILE
            xC2.RemoveAllItems(PlayerRef)
        ELSE
            PlayerRef.DropObject(xARMO, 1)
        ENDIF
    ENDIF
ENDFUNCTION

Нарада  Offline  Сообщение №2347 написано: 2 февраля 2017, 06:45



129
Уважаемые, знатоки. У меня появился к вам вопрос.
Для открывания дверей клетоr взял маркер фурнитуры рычаг.  На рычаг простенький скрипт
 
Код
Quest Property mQuest  Auto  
Int property QStage auto
function OnActivate(ObjectReference akActionRef)
          mQuest.SetStage(QStage)       
endFunction

На НПС навесил пакет Sit с условием по стадии квеста. При достижении этой стадии НПС бодро бежит к рычагу. 
И тут начинается чехорда. НПС переводит рычаг один раз - двери клеток открываются, пленники выбегают (это показывает, что скрипт акивации на рычаге сработал, значит пакет Sit тоже должен перестать работать) , но НПС продолжает переводить рычаг снова и снова. 
Вопрос: Каким образом сделать чтобы НПС переводил рычаг только один раз?

Multigone  Offline  Сообщение №2348 написано: 2 февраля 2017, 19:45



832
Нарада


Код
Quest Property mQuest  Auto  
Int property QStage auto
function OnActivate(ObjectReference akActionRef)
    mQuest.SetStage(QStage)
    (akActionRef as actor).evaluatepackage()
endFunction

AlexeyVN  Offline  Сообщение №2349 написано: 3 февраля 2017, 10:35



52
ЗДРАВСТВУЙТЕ, подскажите пожалуйста можно ли определить предмет находящийся в триггере?

Dsion  Offline  Сообщение №2350 написано: 3 февраля 2017, 10:40



AlexeyVN, а если их там ШЕСТЬ?!

AlexeyVN  Offline  Сообщение №2351 написано: 3 февраля 2017, 10:59



52
Dsion, В моём случае в триггер попадает один предмет

Dsion  Offline  Сообщение №2352 написано: 3 февраля 2017, 11:46



AlexeyVN, и нету никакого шанса, что там окажется несколько предметов? Ну как скажешь! Тогда легко. На триггер вешается скрипт с ивентами
OnTriggerEnter(ObjectReference akActionRef)
OnTriggerLeave(ObjectReference akActionRef)

В первом - сохранение объекта в проперти, чтоб можно было в любой момент его узнать. А во втором - очиска проперти.

AlexeyVN  Offline  Сообщение №2353 написано: 3 февраля 2017, 11:53



52
Dsion, идея такая;   один активатор помещает предмет в триггер, другой активатор удаляет предмет из триггера
Я так понимаю мне нужна связь между триггером и вторым активатором и я не знаю как это сделать(((

Dsion  Offline  Сообщение №2354 написано: 3 февраля 2017, 12:18



Я даже не понимаю, зачем вообще триггер... Может, кто-то другой поможет :(

AlexeyVN  Offline  Сообщение №2355 написано: 3 февраля 2017, 12:36



52
Dsion, Задуматься заставили на счёт триггера)))) можно и без триггера)))  Но всё ровно мне не понятно как в скрипте указать проперти из другова скрипта

Dsion  Offline  Сообщение №2356 написано: 3 февраля 2017, 12:46



Если, допустим, есть квест SiskiQuest, а на нем скрипт SiskiQuestScript, а на скрипте проперти SiskiVar и функция SiskiFunc, то в любом другом скрипте можно вот так:

Код
Quest Property SiskiQuest Auto
...
(SiskiQuest As SiskiQuestScript).SiskiVar = 40;
(SiskiQuest As SiskiQuestScript).SiskiFunc(4040);
...


или еще вот так:

Код
SiskiQuestScript Property SiskiQuest Auto
...
SiskiQuest.SiskiVar = 40;
SiskiQuest.SiskiFunc(4040);
...


С объектами в мире так же, но нужно заполнять проперти конкретным референсом из конкретной локации...

PitrPokir  Offline  Сообщение №2357 написано: 4 февраля 2017, 01:00 | Отредактировано: PitrPokir - 4 февраля 2017, 01:20



26
Dsion, скопировал и немного переделал квест на спутников, но я слабовато понимаю что делаю. Квест должен начинаться благодаря строчке с функцией Start в скрипте заклинания, а цель запихнуть в алиас при помощи ForceRefTo? Или хватит чего-то одного? И достаточно ли будет одного алиаса, если потребуется "подчинить" много целей поочередно? Так же есть вкладка Scripts и я не знаю, туда ли кидать скрипт "подчинения" или в сам алиас/-ы.
Хотелось бы знать как вообще выглядит это все. Начинается какой-то невидимый квест пока у меня в алиасах будет нпс/существо, а когда алиас/-ы опустеют, то квест завершиться?
Прошу прощение за навязчивость и глупые вопросы, но для меня эта тема довольно темна и я смутно понимаю как это работает в рамках квеста, а вопрос как-то решить надо :с

Dsion  Offline  Сообщение №2358 написано: 4 февраля 2017, 01:26



PitrPokir, ну вот небольшое задание. Выполнять, конечно, не обязательно, если не хочешь, но, на мой взгляд, было бы полезно.
1. Создаешь новенький мод.
2. Создаешь в моде один единственный квест. На квесте оставляешь галочку Start Game Enabled - он будет запущен всегда.
3. Создаешь в квесте один пустой алиас. (Specific Reference, но никого не выбирать).
4. На алиасе обязательно ставишь галочку Optional. Это означает, что он может быть пустым.
5. На алиас вешаешь собственно созданный (или ванильный) пакет следования за игроком. Можно взять PlayerFollowerPackage.
6. На этом же квесте создаешь один диалог. Игрок говорит что-то типа "за мной идти хочешь ты...", а NPC отвечает "..за тобой идти хочу я...". В поле для скрипта на диалоге сначала вбиваешь ; и компилируешь. Потом к скрипту добавляешь проперти с типом ReferenceAlias и именем типа FollowerAlias, а в потом в само поле для скрипта вписываешь FollowerAlias.ForceRefTo(akSpeaker)
7. Проверяешь в игре (может понадобиться сохраниться/загрузиться, чтоб появился диалог).

Скрипт на диалоге засовывает НИП в алиас и пакет на алиасе становится приоритетнее всех пакетов на самом НИП.
Когда предлагаешь пойти с тобой другому НИП, то в алиас засовывается уже другой НИП, а первый "освобождается" и идет по своим делам. Если нужно, чтоб бегало с тобой сразу много, надо много алиасов. И чуточку усложнить скрипт. Скрипт должен заполнять не конкретный алиас, а первый свободный из списка.

Ну да, оно не совсем просто, но и не сложно. Может, стоило бы еще другие варианты рассмотреть. Типа, при вытягивании духа, можно было бы этого духа сразу убивать, а потом поднимать каким-то воскрешением. Тогда бы он и без алиаса бегал за игроком. Но с алиасами - гибче

Aksyonov  Offline  Сообщение №2359 написано: 4 февраля 2017, 16:54



937
Всем привет есть вопрос по скриптам, есть ли способ определить какой либо функцией то что находится у игрока в инвентаре и сохранить этот список, что бы использовать в скрипте?

AlexeyVN  Offline  Сообщение №2360 написано: 4 февраля 2017, 18:58 | Отредактировано: Multigone - 23 апреля 2020, 08:50



52
Aksyonov, Это часть скрипта на активаторе, который добавляет в FormList только оружие и броню из инвенторя игрока .

Код
Event OnActivate(ObjectReference akActivator)
   If  akActivator == Game.GetPlayer()
      List.Revert()
      Int Index = Game.GetPlayer().GetNumItems() - 1
      While Index >= 0
         Form InvetoryItems = Game.GetPlayer().GetNthForm(Index)
         If (InvetoryItems as Weapon) ||  (InvetoryItems as Armor)
            List.AddForm(InvetoryItems)
         EndIf
         Index -= 1
      EndWhile
   EndIf
EndEvent

PitrPokir  Offline  Сообщение №2361 написано: 5 февраля 2017, 01:54 | Отредактировано: PitrPokir - 5 февраля 2017, 02:05



26
Dsion, спасибо большое, с этим разобрался. Почти...  :(
Вешаю скрипт "подчинения" на алиас, все месседжи кроме первого появляются, т.е. все функции отработали как надо, актер за мной бегает, но как только я нарушаю закон в городе, он сразу становится моим врагом.


Запускается это дело простым скриптом на заклинании:

Код
Scriptname NecroFollowAlias extends activemagiceffect  

ReferenceAlias Property NecroFollowerAlias  Auto  

Event OnEffectStart(Actor Target, Actor Caster)
       Target.RemoveFromAllFactions()
       NecroFollowerAlias.ForceRefTo(Target)
EndEvent


На алиасе висит пакет следования, абилка на внешность призрака и созданная фракция для нежити.
У созданной фракции в союзниках сама фракция и фракция игрока, там тоже от безысходности разрешил любые нарушения закона, но ничего не помогает.
Проверял на жителях Вайтрана, стражниках и драуграх в ветреном пике. Что интересно, потенциальные компаньоны и всякие существа остаются на моей стороне, даже во время боя будучи моими врагами можно их "околдовать", а жители и стражники лишь на мгновение прекращают бой, потом снова бить начинают.
Можно, конечно, просто забить на них и не иметь с ними дел, но тут могут быть неудобности, ведь в некоторых ситуациях заранее не знаешь кто к какому городу или деревушке относится и быть внезапно атакованным из-за убитой курицы как-то не круто :/
Буду очень признателен, если вы поделитесь какими-то мыслями на этот счет.

Dsion  Offline  Сообщение №2362 написано: 5 февраля 2017, 08:09



Не, нету мыслей. Ну можно еще попробовать удалять им CrimeFaction:
ххх.SetCrimeFaction(None)
но вряд ли в этом дело...

PitrPokir  Offline  Сообщение №2363 написано: 5 февраля 2017, 15:00



26
Dsion, сработало  ^_^ 
Но сначала эффект почему-то заключался лишь в том, что они просто не вступали в бой. Потом пришлось сменить ивент, а то OnHit в данном случае не очень подходил, поменял на OnLoad и добавил в заклинание помещения цели в алиас 2 строчки с функциями Disable и Enable. И актеры вдруг начали мне еще и помогать в бою, удивительно. Наконец-то!
Вот только стражники, видимо, не люди. На них не действует Disable, как это вообще?

P.S. а какой вообще ивент лучше использовать? OnLoad срабатывает не сразу, надо как-то заставлять объект загружаться.

Dsion  Offline  Сообщение №2364 написано: 5 февраля 2017, 15:34 | Отредактировано: Dsion - 5 февраля 2017, 15:41



Лично я ивенты не использовал бы. Ну вот зачем выполнять кусок кода и делать какие-то проверки каждый раз, когда призрак получает урон?
У тебя в перспективе будет квест и на нем много алиасов, да? Будет разумно добавить скрипт на сам квест и сделать в нем функцию типа

Код
Function CreateGhost(Actor akSource)
    Actor Clone = Game.GetPlayer().PlaceActorAtMe(akSource.GetActorBase());
    Clone.RemoveFromAllFactions();
    ...
    Alias[Index].ForceRefTo(Clone);
EndFunction

Заданием этой функции будет получить аргументом какого-то живого НИП и создать призрака-спутника. Причем это функция должна делать вообще всё, что надо сделать...
Вот в этой функции можно создать клона, удалить ему фракции, изменить характеристики итп, а потом сунуть в первый свободный алиас. А на алиас можно никаких скриптов и не вешать.
А потом откуда там тебе надо (из заклинания или из диалога) просто вызываешь эту функцию на своем квесте одним из двух способов на выбор:

Код
Quest Propery MyQuest Auto

Event OnEffectStart(Actor akTarget, Actor akCaster)
    (MyQuest As MyQuestScript).CreateGhost(akTarget);
EndEvent
или
Код
MyQuestScript Propery MyQuest Auto

Event OnEffectStart(Actor akTarget, Actor akCaster)
    MyQuest.CreateGhost(akTarget);
EndEvent
Блин, так же сделано в DialogueFollower. И чего я распинался? :)

Добавлено (05 Февраля 2017, 18:34)
---------------------------------------------
Там всё легко, но только два подвоха, про которые важно не забыть:
1. Проверку наличия свободного алиаса лучше делать до создания клона. А если свободного алиаса нету, то клона не создавать.
2. Не забыть сделать правильное отключение и удаление клонов. И позаботиться, чтоб они удалялись всегда-всегда-всегда. Если умрут, если закончится время действия заклинания итп. Во всех случаях надо Disable() + DeleteWhenAble() референс. Ну и не забыть очистить алиас.

PitrPokir  Offline  Сообщение №2365 написано: 6 февраля 2017, 18:24 | Отредактировано: PitrPokir - 6 февраля 2017, 18:30



26
Dsion, ну, задумка не совсем такая, это я пока тестирую. Так-то много еще чего надо сделать.

просто вызываешь эту функцию на своем квесте одним из двух способов на выбор:
Функцию вызвать не получилось, ошибки. В первом варианте пишет, что квест нельзя скастовать или что-то в этом роде. Во-втором сразу 3 и я их почти не запомнил. Не хотелось вас мучить дополнительными вопросами. Просто поместил этот код сразу в заклинание, пока все работает как надо. Мне, в принципе, пока такой вариант подходит.
Большое спасибо за помощь, не знаю даже сколько бы я еще потратил времени, что бы дойти до работоспособного варианта.

Единственное, что я до сих пор не могу понять, так это ошибку в таком банальном кусочке кода:
Код
Scriptname NecroGhostManaReservScript extends activemagiceffect  

SPELL Property ManaReserv  Auto
SPELL Property ManaR  Auto  
MagicEffect Property ManaRes  Auto  

Event OnEffectStart(Actor Target, Actor Caster)
       ManaReserv.Dispel()
EndEvent

NecroGhostManaReservScript.psc(8,18): Dispel is not a function or does not exist
Пробовал засовывать в ManaReserv маг.эффект, способность, заклинание. Все-равно такая ошибка. Ну емае(

Dsion  Offline  Сообщение №2366 написано: 6 февраля 2017, 18:40 | Отредактировано: Dsion - 6 февраля 2017, 18:46



Ну нельзя же вот так просто брать от фонаря название функции и пытаться её вызвать :( Вот тут полный список всех методов на всех типах:
https://www.creationkit.com/index.php?title=Category:Script_Objects
И видно, что никакого Dispel на объектах типа "Spell" нету. Dispel есть на ActiveMagicEffect, но только на нем. А еще на объектах "Actor" есть DispelSpell(Spell akSpell).

PitrPokir  Offline  Сообщение №2367 написано: 6 февраля 2017, 20:41



26
Dsion, ну, с использованием таких функций позже разберусь, если потребуется. Пока работает и ладно, буду двигаться дальше. А за ссылку спасибо  :) 
Про Dispel не совсем понял. Мой скрипт же наследует ActiveMagicEffect, про который вы написали, Dispel так же применялся непосредственно и на магический эффект, не только на заклинание, указанное в предоставленном коде. Что ему еще надо?

Dsion  Offline  Сообщение №2368 написано: 7 февраля 2017, 07:06 | Отредактировано: Dsion - 7 февраля 2017, 08:04



Ну в Скайриме есть базовые объекты и их референсы. В CreationKit в списках слева - это почти всё базовые объекты. А в мире базовых объектов не бывает, а только референсы.
Вот есть, например, базовый объект IronSword (тип проперти для скрипта: Weapon). Он всего один, на нем указаны все характеристики и вид меча. А в мире может валяться дофига референсов этого меча (тип проперти: ObjectReference). Изменение характеристик базового объекта изменяет характеристики всех референсов.
И вот представь, что ты пытаешься "снять" этот IronSword (базовый). С кого игра должна его снять? Какой именно нужно снять, если НИП держит их два сразу? Вот потому на проперти типа Weapon нету метода "снять".
Ну и по аналогии:
Spell  - это базовый объект заклинания. С кого оно должно сниматься функцией диспел?
MagicEffect - это базовые объект магического эффекта.
А вот ActiveMagicEffect - это уже что-то типа референса - это настоящий уже действующий эффект на каком-то настоящем НИП в мире. И его можно Dispel.

Если твой скрипт наследует ActiveMagicEffect - это означает, что ты в любом месте можешь прописать Dispel() и это должно снять именно этот эффект с того, на кого он наложен.

Multigone  Offline  Сообщение №2369 написано: 7 февраля 2017, 14:31



832
Цитата Dsion

Если твой скрипт наследует ActiveMagicEffect - это означает, что ты в любом месте можешь прописать Dispel() и это должно снять именно этот эффект с того, на кого он наложен.


Возможно, Self для ActiveMagicEffect определяет скрипт, а не активный эффект. Я видел такую конструкцию:


Код
MyMagEffectScript X = Self

Хотя по общим правилам там должно быть написано:


Код
MyMagEffectScript X = Self AS MyMagEffectScript

А это далеко не одно и то же.

Кстати, Dispel() и GetBaseObject() вообще не работают. По крайней мере, у меня. Они должны применяться к ActiveMagicEffect объекту - но функции, которая возвращала бы его, в ванильном папирусе нет.

Dsion  Offline  Сообщение №2370 написано: 7 февраля 2017, 14:44



Ну Self - это всегда именно тот скрипт, в котором мы написали "Self". Так что первый вариант вполне правильный.
И в скрипте на магическом эффекте, теоретически, Self.Dispel() или просто Dispel() должно работать. А если не работает, то это, скорее, баг или недоработка Скайрима, а не что-то другое...

Форум » TES V: Skyrim » Мастерская » Вопросы по скриптам Papyrus (О скриптах Papyrus (Skyrim). Скриптеры не проходите мимо!)
Поиск:





Ответ на жалобу смотрите в разделе жалоб