; Sets whether the player knows this form ; Should only be used for Magic Effects, ; Words of Power, and Enchantments Function SetPlayerKnows(bool knows) native
SoulDiablo, задержку сделать легко, циферблат - проблема.
Добавлено (19 Октября 2016, 19:18) --------------------------------------------- AlexeyVN, вот перечень всех меню, выбирай, что лучше подойдет (мое мнение - ничего):
+ Заклинание должно иметь архетип Scripts. + Должно иметь продолжительность не меньше 61 с (лучше 1 день или больше, чтобы иметь гарантированные 60 сек. работы, даже если другие моды перками снижают общую Duration всех заклинаний - я так перестраховываюсь). + Если повторно скастовать его, а таймер не дошел до нуля, отсчет пойдет заново.
Код
Scriptname _TESTTEST20 Extends ActiveMagicEffect
Spell Property ThisSpell Auto ; Заклинание с этим эффектом. Заполняется обязательно. Spell Property MyDevastatingSpell Auto ; Заклинание, уничтожающее все живое. Activator Property MyClock Auto ; Активатор с моделью-часами. Если оставить none, ничего плохого не случится (таймера не будет). Float Property MyStartTime = 60.0 Auto ; Начальный отсчет часов.
EVENT OnUpdate() IF fTimer > 0.0 ClockRef.SetAnimationVariableFloat("UcknownAnim", fTimer) ; Нужно знать название анимации для модели таймера. fTimer -= 1.0 RegisterForSingleUpdate(1.00) ELSE GetTargetActor().DispelSpell(ThisSpell) ENDIF ENDEVENT
EVENT OnEffectFinish(Actor xT, Actor xC) IF fTimer <= 0.0 MyDevastatingSpell.Cast(xT) ENDIF ClockRef.Delete() ENDEVENT
2)
+ Заклинание может иметь любой архетип. + Его продолжительность не имеет значения. + Если повторно скастовать его, появится новый таймер, каждый сработает в соотв. время.
Код
Scriptname _TESTTEST21 Extends ActiveMagicEffect
Spell Property MyDevastatingSpell Auto ; Заклинание, уничтожающее все живое. Activator Property MyClock Auto ; Активатор с моделью-часами. Если оставить none, ничего плохого не случится (таймера не будет). Float Property MyStartTime = 60.0 Auto ; Начальный отсчет часов.
EVENT OnEffectStart(Actor xT, Actor xC) ObjectReference ClockRef = xT.PlaceAtMe(MyClock) WHILE MyStartTime > 0.0 ClockRef.SetAnimationVariableFloat("UcknownAnim", MyStartTime) ; Нужно знать название анимации для модели таймера. Utility.Wait(1.0) MyStartTime -= 1.0 ENDWHILE MyDevastatingSpell.Cast(xT) ClockRef.Delete() ENDEVENT
Ничего не проверял, кроме компилируемости. Если модели таймера нет, отсчет не будет показан, а заклинание сработает в положенное время.
***
PS: Если вообще не учитывать модель таймера, варианты могут быть упрощены до:
1)
+ Теперь эффект должен иметь архетип ValueMod (с параметром "Morality", к примеру). + Поставить заклинанию нужную продолжительность, по окончании действия оно сработает.
Код
Scriptname _TESTTEST20 Extends ActiveMagicEffect
Spell Property MyDevastatingSpell Auto ; Заклинание, уничтожающее все живое.
EVENT OnEffectFinish(Actor xT, Actor xC) MyDevastatingSpell.Cast(xT) ENDEVENT
2)
Код
Scriptname _TESTTEST21 Extends ActiveMagicEffect
Spell Property MyDevastatingSpell Auto ; Заклинание, уничтожающее все живое.
EVENT OnEffectStart(Actor xT, Actor xC) Utility.Wait(60.0) MyDevastatingSpell.Cast(xT) ENDEVENT
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №785
| Тема: Вопросы по скриптам Papyrus
написано: 20 октября 2016, 11:39
| Отредактировано: Multigone - 20 октября 2016, 11:44
AlexeyVN, в общем, сделал, хотя не совсем так, как планировалось. Итак:
- игрок активирует алтарь. - опционально показывается сообщение, что нужно выбросить из инвентаря зачарованный предмет. - открывается инвентарь. - если игрок выбрасывает незачарованный предмет, он возвращается обратно в инвентарь. - если зачарованный, то меню закрывается, он теряет зачарование, плюс: - самопальные оружие и доспех - нормальный процесс. - уровневое оружие теряет заточку. - уровневый доспех никак не обрабатывается (нужно дополнять скрипт форм-листами, проблема в SKSE). - уникальные предметы не обрабатываются (нужно дополнять списком всех уникальных вещей). - если игрок выбрасывает стек из нескольких зачарованных предметов (от 5 по дефолту), то они теряют зачарование, один из них помещается на алтарь, остальные будут брошены рядом. - когда игрок закрывает меню вручную, ничего не происходит.
Код
Scriptname _TESTTEST22 Extends ObjectReference ; На алтарь.
Message Property MyMessage Auto ; Опционально сообщение (можно не заполнять). Должно иметь строки: 0 - да, 1 - нет. _TESTTEST23 Property L Auto ; Вместо _TESTTEST23 указать реальное название скрипта, присоединенного к алиасу игрока! И обязательно заполняется в СК!
EVENT OnActivate(ObjectReference xR) GoToState("S") IF xR AS Actor && (!MyMessage || !MyMessage.Show()) L.GoToState("S") L.Altar = Self Input.TapKey(Input.GetMappedKey("Quick Inventory")) ENDIF GoToState("") ENDEVENT
STATE S EVENT OnActivate(ObjectReference xR) ENDEVENT ENDSTATE
Код
Scriptname _TESTTEST23 Extends ReferenceAlias ; На алиас игрока.
STATE S Event OnItemRemoved(Form akBaseItem, Int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer) IF !akItemReference || akDestContainer ELSEIF akBaseItem as Weapon && (akBaseItem as Weapon).GetEnchantment() Form xF = ((akItemReference.GetBaseObject()) AS Weapon).GetTemplate() IF xF Input.TapKey(0x1) akItemReference.Delete() akItemReference = Altar.PlaceAtMe(xF, aiItemCount) akItemReference.MoveTo(Altar, 0.0, 0.0, 200.0) ; Доработать так, как необходимо. ELSE Debug.Notification("Предмет уникален.") ; Предмет имеет зачарование, но не имеет основополагающего оружия. Нужно рассматривать каждый случай отдельно (создавать лист). ENDIF ELSEIF akBaseItem as Armor && (akBaseItem as Armor).GetEnchantment() Form xF ;= ((akItemReference.GetBaseObject()) AS Armor).GetTemplate() ; На текущий момент такой функции в SKSE нет, нужно создавать несколько листов. IF xF Input.TapKey(0x1) akItemReference.Delete() akItemReference = Altar.PlaceAtMe(xF, aiItemCount) ; Доработать так, как необходимо. akItemReference.MoveTo(Altar, 0.0, 0.0, 200.0) ELSE Debug.Notification("Предмет уникален.") ENDIF ELSEIF akItemReference.GetEnchantment() Input.TapKey(0x1) akItemReference.MoveTo(Altar, 0.0, 0.0, 200.0) ; Доработать так, как необходимо. akItemReference.SetEnchantment(none, 0.0) ELSE GetRef().AddItem(akItemReference, aiItemCount, true) ENDIF ENDEVENT
... много лишних аргументов. В SKSE 1.7.3 такого нет (Upd: есть в WornObject.psc).
Идея понятна. Перебираются все надетые на актера вещи, и если какая-либо из них зачарована, зачарование снимается (что такое WornObject?). Это в теории.
Еще: все операции c зачарованием (Get / Set) для ObjectReference могут проводиться только в случае, если это зачарование было наложено игроком. Если зачарование указано в базовом объекте, то попытка применить на таком референсе akItemReference.SetEnchantment(none, 0.0) приведет к вылету из игры.
Lexo, добавление стандартных компаньонов происходит в квесте DialogueFollower. Еще можно изучить это. Расстояние между объектами определяется функцией...
; Calculates the distance between this reference and another - both must either be in the same interior, or same worldspace float Function GetDistance(ObjectReference akOther) native
Код
Float f = Ref1.GetDistance(Ref2)
PS: Расстояние следования за игроком задается в FollowerPackageTemplate, однако ничто не мешает сделать свой пакет.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №789
| Тема: Вопросы по скриптам Papyrus
написано: 8 ноября 2016, 15:06
| Отредактировано: Multigone - 8 ноября 2016, 15:16
grumpos, если заклинание модное и известно, можно поменять его Delivery на Target Actor, тогда Cast() будет накладывать заклинание на указанную цель, а не туда, куда смотрит игрок.
А по сути, есть вот что:
; Sets this actor's head tracking target, optionally forcing it as their pathing look-at target Function SetLookAt(ObjectReference akTarget, bool abPathingLookAt = false) native
Код
Actor1.SetLookAt(Ref1) Actor1.SetLookAt(none)
Не работает с оружием в руках (?) или в режиме от первого лица.
Еще в Dialogue Scene Action есть отделение с 3 настройками Headtracking, но не знаю, будет ли в этом случае вращаться камера. Для примера можно посмотреть квест DB09.
Еще можно попробовать (не проверял, не уверен) установить угол камеры игрока функцией SetAngle(), если игрок находится в режиме первого лица, но думаю, выглядеть это будет не очень (если вообще будет работать).
Еще можно (?) заставить игрока творить заклинание пакетом UseMagic.
Lexo, можно лишь с помощью SKSE узнать, содержал ли камень душу изначально, т.е. что было указано в строке "Soul" этой формы. Если камень изначально пуст, нельзя вообще никак узнать, заполнен ли он, когда: 1) он содержит душу меньшей величины, чем камень, или... 2) он содержит душу соотв. величины, но форма не имеет ссылки на изначально полную версию (Linked to).
Артефакт Азуры всегда подходит под один из этих случаев, значит, определить величину души, или факт содержания души, невозможно.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №791
| Тема: Вопросы по скриптам Papyrus
написано: 23 ноября 2016, 18:37
| Отредактировано: Multigone - 23 ноября 2016, 18:38
Crunatus, похоже, это условие не работает (по аналогии с GetQuestVariable). Вместо него нужно использовать GetVMScriptVariable / GetVMQuestVariable. Ссылка 1, ссылка 2 (про флаг Conditional).
Задача GetVMScriptVariable - проверить значение переменной скрипта (параметр 2) на референсе объекта (1).
DirtyLol, используя SKSE, можно сделать немного по-другому (если нужно затяжное поглощение cо множественными наложениями):
- меняем архетип на Value Mod - Health (Stamina/Magicka), флаг No Death Dispel снимаем. - добавляем скрипт:
Код
Scriptname _TESTTEST24 Extends ActiveMagicEffect
Actor xA Float fMag
EVENT OnEffectStart(Actor xT, Actor xC) xA = xC fMag = GetMagnitude() RegisterForSingleUpdate(1.0) ENDEVENT
EVENT OnUpdate() xA.RestoreActorValue("Health", fMag) ; Вместо Health нужно написать Stamina или Magicka, если исходный эффект "поглощает" силу или магию. RegisterForSingleUpdate(1.0) ENDEVENT
- проверяем результат в игре.
Проблема: восстановление атрибута происходит рывками, а не плавненько, как раньше. Этого можно избежать, если использовать не команду RestoreAV, а накладывать на источник заклинание продолжительностью 1с, восстанавливающее атрибут (создаются соотв. заклинания, меняется скрипт).
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №795
| Тема: Вопросы по скриптам Papyrus
написано: 3 января 2017, 12:14
| Отредактировано: Multigone - 23 апреля 2020, 09:44
Keyword property _LEXO_Agni Auto Spell Property _LEXO_FireWave auto
Actor xP Bool bL
EVENT OnInit() xP = GetActorReference() ENDEVENT
EVENT OnRaceSwitchComplete() xP = GetActorReference() ENDEVENT
EVENT OnObjectEquipped(Form xF, ObjectReference xR) IF xF AS Weapon && xF.HasKeyword(_LEXO_Agni) && !bL bL = true Utility.Wait(0.001) ; IF xP.GetEquippedWeapon(0).GetEnchantment().HasKeyword(_LEXO_Agni) || WornObject.GetEnchantment(xP, 1, 0).HasKeyword(_LEXO_Agni) ; Если чары оружия имеют кейворд (SKSE). IF xP.GetEquippedWeapon(0).HasKeyword(_LEXO_Agni) ; Если оружие имеет кейворд. RegisterForAnimationEvent(xP, "weaponSwing") ELSE UnRegisterForAnimationEvent(xP, "weaponSwing") ENDIF
; IF xP.GetEquippedWeapon(1).GetEnchantment().HasKeyword(_LEXO_Agni) || WornObject.GetEnchantment(xP, 0, 0).HasKeyword(_LEXO_Agni) IF xP.GetEquippedWeapon(1).HasKeyword(_LEXO_Agni) RegisterForAnimationEvent(xP, "weaponLeftSwing") ELSE UnRegisterForAnimationEvent(xP, "weaponLeftSwing") ENDIF bL = false ENDIF ENDEVENT
Если найдешь события, которые будут срабатывать на неписях: в любом случае, можно отслеживать либо экипирование конкретного оружия любым актером (скрипт на базовое оружие и заклинание), или экипирование любого оружия конкретным актером (скрипт на алиас / заклинание - как здесь). Сделать, чтобы отслеживание анимации было связано только с зачарованием (например, снимаемые чары, позволяющие любому оружию кидать фаербол при махании), таким методом нельзя.
Lexo, еще проверь:
- вешается на алиас игрока. - квест алиаса должен быть запущен. - заполняются Property (для проверки можно взять Firerball). - у экипированного оружия должно быть это ключ. слово (для проверки WeapMaterialIron).
Чтобы управлять референсом предмета, нужно его знать. Значит, предмет должен быть в алиасе. На активатор:
Код
Scriptname _TESTTEST27 extends objectReference ; если предмет создается алиасом (или находится там).
ReferenceAlias Property ItemAlias auto
Event OnLoad() objectReference ItemRef = ItemAlias.GetReference() IF Game.GetPlayer().GetItemCount(ItemRef) ItemRef.MoveTo(Self, 0.0, 0.0, 25.0) ; располагает предмет на 25 юнитов выше активатора. while !ItemRef.is3dloaded() utility.wait(0.05) endwhile ItemRef.setMotionType(Motion_Keyframed) ; если нужно, чтобы предмет не улетел куда-нибудь. ENDIF endEvent
Активатор должен иметь модель, можно Effects\FXEmptyObject.nif.
Dsion, если накрутить много действий на oninit (или просто вставить ожидание), он сработает несколько раз. Проверь свой скрипт через debug.notification(utility.randomfloat()), и там спавнится 3-4 меча. У меня это так работает для всех oninit.
Lokimo, находишь модель виз. эффекта, открываешь ее в Nifscope, ищешь все строчки типа BSEffectShaderProperty, указываешь свои цвета и пути к текстурам. Ванильные ресурсы запакованы в Meshes.bsa, Textures.bsa; открываются BSA Browser. Nifscope открывает только модели внутри Data/Meshes.
Сохраняешь модель, можно под старым именем, но в свою директорию (Data/Meshes/MyModDir). Используешь ее в СК.
Тем не менее, если в окно объектов кинуть кинжал, а в каком-нибудь скрипте заполнить им ObjectReference Property _TESTREFR Auto, то таким кинжалом можно управлять, когда он находится в инвентаре и сложен в стек - например, выбросить его оттуда с помощью _TESTREFR.MoveTo(Game.GetPlayer()).
Если к референсу этого кинжала добавить скрипт, то его self будет хранить информацию о себе, даже когда он попадает в инвентарь:
Dsion, если предметы были добавлены в инвентарь не подбором из мира, то у них, конечно, не будет своего id. Когда они будут выброшены, игра сформирует временный refid для этого стека (как если бы использовалась placeatme()). Наверное, поэтому, когда выбрасывается сразу весь стек из камней душ, вместо одной модели появляется несколько - стек из купленных / созданных (не имевших своего id) и отдельным предметом каждый из найденных в мире.
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
Quest Property mQuest Auto Int property QStage auto function OnActivate(ObjectReference akActionRef) mQuest.SetStage(QStage) (akActionRef as actor).evaluatepackage() endFunction
Если твой скрипт наследует ActiveMagicEffect - это означает, что ты в любом месте можешь прописать Dispel() и это должно снять именно этот эффект с того, на кого он наложен.
Возможно, Self для ActiveMagicEffect определяет скрипт, а не активный эффект. Я видел такую конструкцию:
Код
MyMagEffectScript X = Self
Хотя по общим правилам там должно быть написано:
Код
MyMagEffectScript X = Self AS MyMagEffectScript
А это далеко не одно и то же.
Кстати, Dispel() и GetBaseObject() вообще не работают. По крайней мере, у меня. Они должны применяться к ActiveMagicEffect объекту - но функции, которая возвращала бы его, в ванильном папирусе нет.
Dsion, забавно, сколько времени был уверен, что Dispel() не работает (сто раз проверял), сейчас завел СК - заработало, ***. Кое-что придется переписывать, избавляться от DispelSpell и Property.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №806
| Тема: Вопросы по скриптам Papyrus
написано: 7 февраля 2017, 20:03
| Отредактировано: Multigone - 7 февраля 2017, 21:00
Dsion, всегда думал, что self - это объект, а скрипт расширяет форму, а не является ей. Ну да ладно, я-то C++ не изучал. Про cast знаю - float as string всегда, а string as float иногда. В любом случае, спасибо за стену текста.)
PitrPokir, если эффект нужно снять извне (не из его скрипта), то DispelSpell. Или наложить другой эффект с флагом Dispel и ключ. словами. Первый снимает все копии всех эффектов этого заклинания, второй способ может снять копии только одного из эффектов заклинания, но требует ключ. слов.
Чтобы точно знать ID каждой копии эффекта (для применения Dispel()), можно использовать массив где-нибудь в квесте, который будет заполняться при старте каждого отдельного эффекта, при условии, что они накладываются только на одного актера и не строго одновременно.
А, в этом случае хватит и одной переменной. Скрипт на эффекте призрака будет примерно таким:
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
kelamor, можно через OnMagicEffectApply, как подсказывает PitrPokir, или onhit. Но лучше через OnObjectEquipped(Form akBaseObject, ObjectReference akReference), он срабатывает один раз при использовании зелья, а не все свободное время, пока на игроке есть хоть один долговременный маг. эффект.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №808
| Тема: Вопросы по скриптам Papyrus
написано: 10 февраля 2017, 12:01
| Отредактировано: Multigone - 10 февраля 2017, 15:35
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
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №809
| Тема: Вопросы по скриптам Papyrus
написано: 13 февраля 2017, 10:56
| Отредактировано: Multigone - 13 февраля 2017, 10:58
Int Num = AliasArray.Length While Num > 0 Num -= 1 if AliasArray[Num].ForceRefIfEmpty(Ghost) CurrentFilled = AliasArray[Num]; Slave = true Num = 0 endif EndWhile