Модератор форума: 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? Пиши не в ЛС, а в эту тему.
Multigone  Offline  Сообщение №2371 написано: 7 февраля 2017, 15:10



832
Dsion, забавно, сколько времени был уверен, что Dispel() не работает (сто раз проверял), сейчас завел СК - заработало, ***. Кое-что придется переписывать, избавляться от DispelSpell и Property.

PitrPokir  Offline  Сообщение №2372 написано: 7 февраля 2017, 16:40



26
Dsion, какое узкое применение у этого диспела, однако. Я уж обрадовался сколько пользы от него будет, а оно вот как...
Как же тогда убрать один эффект, по завершении другого, если время заранее неизвестно? DispelSpell же сразу все эффекты рубит

Dsion  Offline  Сообщение №2373 написано: 7 февраля 2017, 17:54 | Отредактировано: Dsion - 7 февраля 2017, 17:38



Многие не понимают один важный аспект скриптов, а я не знаю, как это описать без четырех страниц текста...

1. Все скрипты в Скайриме - это почти то же самое, что классы в С++. Создание папирусового скрипта с именем "SluttyActor" равноценно объявлению класса SluttyActor в С++.

2. Все классы(скрипты) могут быть типом переменной (или проперти), таким же как int и float. Но в С++ мы можем в любом месте создать экземпляр любого класса: SluttyActor a; , а в папирусе таким образом мы можем создать только простые переменные (int и float). Экземпляры всех остальных классов могут существовать только связанными с каким-то реальным объектом в мире игры.

3. Actor, ObjectReference, Spell итп - мы можем создавать проперти этих типов только потому, что в Data/Scripts/Source у нас лежат скрипты Actor.psc, ObjectReference.psc, Spell.psc итп.

4. Как в С++ классы могут наследовать друг друга, так и в папирусе скрипты могут наследовать друг друга. Например, класс Actor (живой объект в мире) наследует класс ObjectReference (любой объект в мире). Это означает, что любой Actor - это всегда и ObjectReference тоже. На Actor всегда можно вызвать любую функцию, которую можно вызвать на ObjectReference. Актора можно передать аргументом в функцию, которая просит ObjectReference итп. Но Actor еще и расширяет ObjectReference, добавляя новые функции. Актор - это всегда ObjectReference, но ObjectReference - не всегда Актор.

5. И самое главное. Это не совсем правильно, но так будет легче понять. Попробуйте не отделять в сознании скрипт от какой-то вазы, на которой он висит. Представьте, что скрипт - это есть ваза, а ваза - это есть скрипт. Не называйте скрипт "СкриптНаВазе", а назовите его "УлучшеннаяВаза". И с этого момента можете думать об "УлучшеннаяВаза" точно так же, как вы думаете об "Actor". А почему нет? Точно такой же класс. Точно так же, как и Actor, наследует и расширяет ObjectReference. Вы теперь можете создать проперти с типом УлучшеннаяВаза. Или написать функцию, которая будет принимать аргументом именно улучшенную вазу. Ну и еще всякое...

Multigone, если ты вдруг это всё читал... То (AAA as BBB) - это не обращение к скрипту BBB на объекте AAA... А это называется type cast или приведением типов... Мы как-бы говорим "Вот у меня есть объект типа AAA, но я точно знаю, что это объект типа BBB. Так что заглохни, компилятор, и дай мне работать с ним как с BBB.". В папирусе это безопасно, но в том же Си или С++ надо быть осторожным...

Добавлено (07 Февраля 2017, 20:54)
---------------------------------------------
PitrPokir, а как получилось, что время действия не известно? Мало ты информации подогнал :(


PitrPokir  Offline  Сообщение №2374 написано: 7 февраля 2017, 19:07



26
Dsion, речь все о тех же призраках. При подчинении призрака игроку добавляется пустой эффект, который висит в активных эффектах и позволяет понять, что призрак еще на его стороне и сколько их вообще. И естественно, эффект должен спадать вместе с эффектом подчинения, а поскольку он длится 999 дней, то ориентироваться надо по смерти призрака. А когда это будет - неизвестно)

Multigone  Offline  Сообщение №2375 написано: 7 февраля 2017, 20:03 | Отредактировано: Multigone - 7 февраля 2017, 21:00



832
Dsion, всегда думал, что self - это объект, а скрипт расширяет форму, а не является ей. Ну да ладно, я-то C++ не изучал. Про cast знаю - float as string всегда, а string as float иногда. В любом случае, спасибо за стену текста.)

PitrPokir, если эффект нужно снять извне (не из его скрипта), то DispelSpell. Или наложить другой эффект с флагом Dispel и ключ. словами. Первый снимает все копии всех эффектов этого заклинания, второй способ может снять копии только одного из эффектов заклинания, но требует ключ. слов.

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

А, в этом случае хватит и одной переменной. Скрипт на эффекте призрака будет примерно таким:

Код
scriptname myghostspellscript extends activemagiceffect

spell  property mymenuspell auto
myquestscript property s auto
activemagiceffect x

event oneffectstart(actor t, actor c)
    mymenuspell.cast(game.getplayer())
    int ic = 3000
    while !s.q && ic
        utility.wait(0.001)
        ic -= 1
    endwhile
    if s.q
        x = s.q
        s.q = none
    endif
endevent

event oneffectfinish(actor t, actor c) ;
    x.dispel()
endevent

event ondying(actor k)
    x.dispel()
endevent

Скрипт на эффекте игрока:


Код
scriptname mymenuspellscript extends activemagiceffect

myquestscript property s auto

event oneffectstart(actor t, actor c)
    s.q = self as activemagiceffect
endevent

Скрипт на квесте (одна переменная):


Код
scriptname myquestscript extends quest

activemagiceffect property q auto hidden

Можно доп. защитить скрипт - когда кол-во призраков = 0 (глобальная), снимаются не отдельные эффекты, а dispelspell(mymenuspell).

Dsion  Offline  Сообщение №2376 написано: 8 февраля 2017, 05:38 | Отредактировано: Dsion - 8 февраля 2017, 05:51



PitrPokir, ну сам смотри... Лично я пока не вижу смысла вешать на игрока эффект... Через квест, на котором алиасы и основной скрипт, всегда можно узнать, сколько у игрока в подчинении призраков и их референсы.
Вешать эффект на призрака (кроме abGhostAbility) тоже пока смысла не вижу...
Но, может, он (смысл) и есть. Ты же не всё рассказываешь. Ладно-ладно, не моё дело.

PitrPokir  Offline  Сообщение №2377 написано: 8 февраля 2017, 14:15



26
Multigone, вот это танцы с бубнами :) 
Я даже не до конца понимаю что к чему. Но за код спасибо, попробую

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

Dsion  Offline  Сообщение №2378 написано: 8 февраля 2017, 14:52



А поддержку нескольких призраков уже получилось сделать? Или только один пока?

kelamor  Offline  Сообщение №2379 написано: 8 февраля 2017, 15:45



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

PitrPokir  Offline  Сообщение №2380 написано: 8 февраля 2017, 21:42



26
kelamor, ивент OnMagicEffectApply вызывается каждый раз, когда на актера применяется любой эффект.

Dsion, пока один. Не придумал еще как лучше всего будет очищать определенный алиас после смерти определенного призрака

Multigone  Offline  Сообщение №2381 написано: 8 февраля 2017, 23:50



832
kelamor, можно через OnMagicEffectApply, как подсказывает PitrPokir,  или onhit. Но лучше через OnObjectEquipped(Form akBaseObject, ObjectReference akReference), он срабатывает один раз при использовании зелья, а не все свободное время, пока на игроке есть хоть один долговременный маг. эффект.

Dsion  Offline  Сообщение №2382 написано: 9 февраля 2017, 07:16



PitrPokir, так это же важно! Лучше об этом бы и подумал!
Варианта, как минимум, два:
1. Вешаем скриптик на алиас с ивентом OnDeath. Когда ивент срабатывает, скрипт сразу отключает и удаляет референс. А потом еще и очищает алиас. Таким же способом можно сделать ограничение времени действия. При создании призрака - заказ OnUpdate. А в OnUpdate - отключение, удаление, очистка.
2. Не очищаем алиас сразу после смерти. Но для функции поиска пустого алиаса алиас с мертвым НИП будет считаться пустым. Опять же, надо не забыть отключить и удалить труп.

Ну и еще дофига вариантов можно придумать. Придумать нормальную систему работы с алиасами - это же самое важное для тебя.

AlexeyVN  Offline  Сообщение №2383 написано: 10 февраля 2017, 00:24



52
Здравствуйте, подскажите пожалуйста как проверить экипированное оружие что оно улучшенное ?
Пытался сделать так: 

Weapon BaseWeapon = Game.GetPlayer().GetEquippedWeapon()
If BaseWeapon.GetItemHealthPercent() < 1.6000
    Debug.MessageBox("Оружие можно улучшить")
Else
    Debug.MessageBox("Оружие максимально улучшено")
EndIf

Компилятор ругается. Как можно это исправить?

Multigone  Offline  Сообщение №2384 написано: 10 февраля 2017, 12:01 | Отредактировано: Multigone - 10 февраля 2017, 15:35



832
AlexeyVN, ругается потому, GetEquippedWeapon() возвращает Weapon, а ты пытаешься к нему применить функцию, предназначенную для ObjectReference.

Используя SKSE:


Код
Scriptname _TESTTEST30 extends objectReference

bool function CheckTempering(bool rightHand = true, float hold = 1.6)
    actor a = Game.GetPlayer()
    if a.GetEquippedWeapon(!rightHand)
        return wornobject.GetItemHealthPercent(a, rightHand as int, 0) < hold
    endif
endfunction

; rightHand:
; false - левая / обе
; true - правая / обе

;    примеры:
;    If CheckTempering(true, 1.5) == true ; проверяем оружие в правой на заточку 1.5.
;        Debug.MessageBox("Оружие можно улучшить")
;    Else
;        Debug.MessageBox("Оружие максимально улучшено") ; или оружия нет в указанной руке.
;    EndIf

;    If CheckTempering()

Upd. 18:28

PitrPokir  Offline  Сообщение №2385 написано: 12 февраля 2017, 23:46 | Отредактировано: PitrPokir - 12 февраля 2017, 23:55



26
Dsion, а если вешать скрипт на алиас с ивентом OnDeath, то как сделать, что бы конкретно данный алиас очищал себя? "SELF.GetReference().Clear()"? Прост у меня не менее 20ти алиасов, для каждого делать индивидуальный скрипт как-то жирно получается.
И не будет ли OnUpdate оказывать сильное влияние на производительность? Ну относительно сильное. Допустим, если засунуть в ивент цикл на проверку смерти и очищать.
Хотя первый вариант получше, если его можно реализовать.

P.S. а почему важно отключать и удалять трупы? В игре же по дефолту они остаются после битв и прочего. Если речь о том, что бы именно призрак исчезал, то я добавил дефолтный скрипт по превращению в "остатки призрака", а если применять отключение и удаление, то остатки тоже исчезают.

Добавлено (13 Февраля 2017, 00:09)
---------------------------------------------
Проверил вариант с OnDeath, вроде исправно работает при помощи "SELF.Clear()".

Добавлено (13 Февраля 2017, 02:46)
---------------------------------------------
Что-то я немного застрял с заполнением алиаса. В чем может быть ошибка? (Оставил строчки имеющие отношение к циклу)

Код
Scriptname NecroFollowAlias extends activemagiceffect  

Alias[] Property AliasArray  Auto  
ReferenceAlias Property NecroFollowerAlias  Auto   

Bool Slave = false
Int Num
Alias aElement

Event OnEffectStart(Actor Target, Actor Caster)

       Num = AliasArray.Length
       While Num > 0
              Num -= 1
              aElement = AliasArray
              [Num]if (aElement.ForceRefIfEmpty(Ghost) == true)
                     Slave = true
                     Num = 0
              endif
       EndWhile

(25,15): ForceRefIfEmpty is not a function or does not exist
(25,38): cannot compare a none to a bool (cast missing or types unrelated)

P.S. Если переменную aElement объявить как ReferenceAlias или прописать её в свойствах, то ошибка:"type mismatch while assigning to a referencealias (cast missing or types unrelated)"

P.P.S. что странно, вне цикла на конкретном алиасе NecroFollowerAlias условие if работает как надо. Я так понял, дело в переменной aElement, но что именно с ней не так?

Multigone  Offline  Сообщение №2386 написано: 13 февраля 2017, 10:56 | Отредактировано: Multigone - 13 февраля 2017, 10:58



832
PitrPokir,


Код
ReferenceAlias[] Property AliasArray Auto

ReferenceAlias CurrentFilled
Bool Slave

;;;

    Int Num = AliasArray.Length
    While Num > 0
        Num -= 1
        if AliasArray[Num].ForceRefIfEmpty(Ghost)
            CurrentFilled = AliasArray[Num];
            Slave = true
            Num = 0
        endif
    EndWhile

Хисимэль  Offline  Сообщение №2387 написано: 14 февраля 2017, 08:48 | Отредактировано: gangrena1972 - 14 февраля 2017, 08:50


Эльфийка-оборотень


100
Пытаюсь сделать спутника с поведением Сераны.

Все получается, только он тормозит с переходом от пакета песочницы к пакету следования. Причина, думаю, в следующем:

У Сераны на пакете песочницы (DLC1NPCSandboxAroundPlayer600) стоит условие PlayerSettled_var.
Соответственно, в скрипте на квесте - Bool property PlayerSettled auto conditional
Dsion объяснил, что это что-то вроде постоянной перепроверки пакетов.

Подскажите, пожалуйста, откуда и как эта переменная запускается?

озвучиваю моды
Multigone  Offline  Сообщение №2388 написано: 14 февраля 2017, 14:18



832
Цитата gangrena1972

как


Код
; из этого квеста.

(getowningquest() as DLC1_NPCMentalModelScript).PlayerSettled = true

; из др. мест.

quest Property DLC1NPCMentalModel auto

(DLC1NPCMentalModel as DLC1_NPCMentalModelScript).PlayerSettled = true

; или

((game.getformfromfile(0x2b6e, "dawnguard.esm") as quest) as DLC1_NPCMentalModelScript).PlayerSettled = true

Dsion  Offline  Сообщение №2389 написано: 14 февраля 2017, 14:25 | Отредактировано: Dsion - 14 февраля 2017, 14:26



Я смотрел квест, из которого она меняется. Точно название не помню, но там в нем есть слова "monitoring" и "dlc1". Каждую секунду выполняется необоснованно сложная и длинная функция, определяющая, "осел" ли игрок... Если результат определения изменяется, то и переменная изменяется, и выполняется EvaluatePackage()... Я бы эту функцию не копировал, о чем и сообщил гангрене в приват... А вот EvaluatePackage() каждую секунду действительно могло бы помочь.

Multigone  Offline  Сообщение №2390 написано: 14 февраля 2017, 15:01



832
Dsion, тогда это DLC1NPCMonitoringPlayer. Ну, там каждую секунду проверяется, прошел ли игрок за 8 предыдущих секунд 150 юнитов. И да, есть лишние телодвижения, такие, как смещение всего массива на одну ячейку.

Dsion  Offline  Сообщение №2391 написано: 14 февраля 2017, 15:38



Ага, он! Я ни сильно вникал, что там делается. Видел только массивы для сохранения истории перемещений игрока. Ну его нафиг.

kelamor  Offline  Сообщение №2392 написано: 19 февраля 2017, 11:33



19
Товарищи, как отследить событие, когда ГГ атакует?
Уже измучился )))

Из скрипта, привязанного к РеференсАлиасу квеста его можно поймать?

Aksyonov  Offline  Сообщение №2393 написано: 19 февраля 2017, 11:50



937
Всем привет нужно реализовать следующие задачи при помощи скриптов или чего то ещё, вопрос:

1. Нужен скрипт для книги который бы запрещал выкидывать книгу выбранную из инвентаря.
книга квестовая не знаю как сделать при помощи алиосов что бы книга не выкидывалась, помогите.

2. Нужна смена стадий если в инвентаре появляется какой то определенной
предмет, и если его нет в инвентаре что бы менялась стадия на исходную.

Multigone  Offline  Сообщение №2394 написано: 19 февраля 2017, 12:22



832
kelamor,

1) По атаке актеров: дать игроку перк apply combat hit spell, при старте его эффекта делаем, что хотим.

2) По анимации: в алиасе игрока регистрируем анимации "weaponSwing", "weaponleftSwing" и используем событие OnPlayerBowShot() для лука.

AlexeyVN  Offline  Сообщение №2395 написано: 23 февраля 2017, 16:11 | Отредактировано: AlexeyVN - 23 февраля 2017, 16:13



52
Здравствуйте с праздником всех, помогите разобраться в проблеме со скриптом
String RefName = akItemReference.GetDisplayName()
akItemReference.SetDisplayName(RefName + " (Усил.)")

В самой игре в место Усил. отображается какие то символы

Multigone  Offline  Сообщение №2396 написано: 23 февраля 2017, 23:06



832
AlexeyVN, кириллица в СК и в папирусе имеет разную кодировку. Это никак не исправить.

Dsion  Offline  Сообщение №2397 написано: 24 февраля 2017, 03:02 | Отредактировано: Dsion - 24 февраля 2017, 03:02



Multigone, я бы просто для интереса попробовал какой-то бред типа... Ну создать новый предмет с именем "Усил.", а потом делать
String NewName = RefName1 + RefName2
Но у меня SKSE вообще нету.

AlexeyVN  Offline  Сообщение №2398 написано: 24 февраля 2017, 05:57 | Отредактировано: AlexeyVN - 24 февраля 2017, 06:13



52
Multigone, спасибо
Dsion, я тоже об этом думал но мне это идея  не пришла по душе я просто Усил на + поменял.  
А так  это идея работает.

Нарада  Offline  Сообщение №2399 написано: 18 марта 2017, 11:30



129
Здравствуйте, друзья!
Не подскажите, каким образом можно отследить переход состояния объекта Enable\Disable? События на такое изменения я, увы, не нашел.

Dsion  Offline  Сообщение №2400 написано: 18 марта 2017, 13:51



Нарада, если включение и отключение производится другим скриптом, то можно вот так:


Код
Scriptname SionHuldaScript extends ObjectReference

Function Enable(bool abFadeIn = false)
    Parent.Enable(abFadeIn);
    Debug.MessageBox("Enabled");
EndFunction

Function Disable(bool abFadeOut = false)
    Parent.Disable(abFadeOut);
    Debug.MessageBox("Disabled");
EndFunction

Но, скорее всего, ты что-то вообще не то делаешь...

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





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