ScriptName _TestSCPTREFA Extends ReferenceAlias ; На алиас игрока.
FormList Property ArtifactFLST Auto ; Лист с арт. FormList Property CopyFLST Auto ; Лист с копиями. В том же порядке, такое же кол-во. Keyword Property CopyKYWD Auto ; Каждая копия должна содержать это ключ. слово. Оптимизирует скрипт. Keyword Property IsEnchanting Auto ; Заполнить.
Bool bL
EVENT OnSit(ObjectReference xR) IF xR.HasKeyword(IsEnchanting) bL = true GoToState("S") Actor xA = GetActorRef() IF xA.GetItemCount(ArtifactFLST) Int iC = ArtifactFLST.GetSize() WHILE iC iC -= 1 IF xA.GetItemCount(ArtifactFLST.GetAt(iC)) xA.AddItem(CopyFLST.GetAt(iC), 1, true) ENDIF ENDWHILE ENDIF bL = false ENDIF ENDEVENT
STATE S EVENT OnItemRemoved(Form xF, Int iN, ObjectReference xR, ObjectReference xD) IF xF.HasKeyword(CopyKYWD) Int iC = CopyFLST.GetSize() - 1 WHILE iC > 0 && xF != CopyFLST.GetAt(iC) iC -= 1 ENDWHILE GetRef().RemoveItem(ArtifactFLST.GetAt(iC), 1, true) ENDIF ENDEVENT
Можно как-то исправить редактирование спойлеров? А то теряются Tab'ы и порой, если в спойлере много разного bb-кода, после точечного исправления, когда точно ничего не должно повредиться, получается такая каша... Особенно, если есть цветной текст. Наблюдаю это уже давно. Firefox.
Lexo, похоже, дело обстоит так: после активации стола игра создает список всех доступных для снятия чар предметов. Поскольку это происходит одновременно с добавлением копий, то они уже не будут учитываться в первоначальном списке. После того, как чары с любого предмета будут сняты (возможно, также после зачарования любого предмета), список будет обновлен, и в нем появятся копии. Далее по накатанной - изучаем чары с копии, копия уничтожается, уничтожается первоначальный артефакт в инвентаре.
Что делать, чтобы копии попали в инвентарь ДО активации стола - пока хз. Возможно, попробовать перк Entry - Activate, как предлагал Dsion...
Цитата Lexo
повесил скрипт просто на игрока
Он не будет работать, т.к. предназначен исключительно для ReferenceAlias.
Lexo, новая версия. Итак:
ScriptName _TestSCPTREFA Extends ReferenceAlias ; На алиас игрока.
Perk Property ActivatePERK Auto ; Перк. FormList Property ArtifactFLST Auto ; Лист с арт. FormList Property CopyFLST Auto ; Лист с копиями. В том же порядке, такое же кол-во. Keyword Property CopyKYWD Auto ; Каждая копия должна содержать это ключ. слово. Оптимизирует скрипт. Keyword Property IsEnchanting Auto ; Заполнить.
FUNCTION F(ObjectReference xR) IF !bL bL = true GoToState("S") Actor xA = GetActorRef() IF xA.GetItemCount(ArtifactFLST) Int iC = ArtifactFLST.GetSize() WHILE iC iC -= 1 IF xA.GetItemCount(ArtifactFLST.GetAt(iC)) xA.AddItem(CopyFLST.GetAt(iC), 1, true) ENDIF ENDWHILE ENDIF xR.Activate(xA) ENDIF ENDFUNCTION
STATE S EVENT OnItemRemoved(Form xF, Int iN, ObjectReference xR, ObjectReference xD) IF xF.HasKeyword(CopyKYWD) Int iC = CopyFLST.GetSize() - 1 WHILE iC > 0 && xF != CopyFLST.GetAt(iC) iC -= 1 ENDWHILE GetRef().RemoveItem(ArtifactFLST.GetAt(iC), 1, true) ENDIF ENDEVENT
1) Тип: Entry -> Activate. Отметить флаги: Run Immediately, Replace Default. 2) Условия: Target -> (S) (HasKeyword) (IsEnchanting) (==) (1.0)
Чтобы правильно повесить скрипт на перк, нужно в точности повторить следующие действия:
- повесить на алиас основной скрипт. - открыть Entry перка и в поле Papyrus Fragment написать:
Код
akactor.kill()
- сохранить перк, нажав OK -> OK. - открыть папку Scripts / Source и найти там свежесозданный скрипт. Он будет наименован как "PRKF_(EditorID перка)_(FormID перка).psc" (в моем случае это был PRKF__MGTTestPERK_031662DB.psc). - открыть этот скрипт редактором текста и написать в конце:
Код
<Имя твоего основного скрипта> Property L Auto
... в моем случае это было так:
Код
;END FRAGMENT CODE - Do not edit anything between this and the begin comment _TestSCPTREFA Property L Auto
- сохранить скрипт. - СКОМПИЛИРОВАТЬ этот скрипт штатными средствами СК (через Gameplay -> Compile). - открыть перк и в поле Papyrus Scripts заполнить Property L, указав твой квест и содержащийся в нем алиас, на который навешен основной скрипт. Нажать ОК. - открыть Entry перка и в поле Papyrus Fragment написать:
Код
L.F(akTargetRef)
- сохранить перк, нажав OK -> OK. Сохранить мод.
PS: Оба скрипта являются неотъемлемой частью мода, что следует учитывать. PPS: У меня все работает. PPPS: На скрине под спойлером перепутаны предметы в листах, но в целях теста это не важно. PPPPS: Долбаные bb-коды.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №695
| Тема: Вопросы по скриптам Papyrus
написано: 9 мая 2016, 23:05
| Отредактировано: Multigone - 24 апреля 2020, 10:44
Lexo, скрин не показывает саму ошибку, там после (8, 2... есть еще текст. Скорей всего, переменная L не содержит функцию F. Возможно, имя Property L выбрано неправильно (не соотв. имени осн. скрипта).
Lexo, а, еще кое-что: если тот перк можно выбирать в меню повышения уровня, то следующие элементы надо убрать из скрипта (с последующей компиляцией):
1) OpenInventory(). Даже если игрок находится в скрытности, все равно открывается обычное контейнер-меню, как при осмотре трупа этого НПС (надеялся, что скрытность повлияет на режим меню).
2) Через такой фрагмент на перке Activation (условия - игрок в скрытности, цель в бою):
Actor xA = akTargetRef AS Actor Actor xT = xA.GetCombatTarget() xA.StopCombat() Utility.Wait(0.001) xA.Activate(akActor) Utility.Wait(0.5) IF xT xA.StartCombat(xT) ELSE xA.SetAlert(true) ENDIF
При активации выводится сообщение, мол, вас уже поймали, и меню не открывается.
Пока только такие идеи были.
Lexo, по поводу стрел - скорее всего, да, через OnHit(). Только скрипт должен быть на маг. эффекте заклинания, которое творится от имени игрока через опред. интервалы времени, действует в большом радиусе и игнорирует преграды.
PS: Вместо selfref надо использовать akAggressor, впрочем, все это нюансы.
Neell, хм-хм-хммм... Интересно. Если ты говоришь, что актер следует за игроком сразу после подключения .esp, значит, он изначально имеет пакет Follow. Если пакет не указан у актера во вкладке AI, значит, актер сразу попадает в алиас квеста, где этот пакет есть. Остается узнать, что является причиной попадания туда. Как заполняется алиас? Он имеет такие же настройки, как в квесте DialogueFollower?
Кстати, хотелось бы знать, заполнял ли ты Property своих скриптов, а если да, то какими формами. Везде, где в Property указывается квест DialogueFollower или его алиас, вместо них нужно указывать свой квест / алиас.
; это комментирование и можно смело убирать?
Да. Можно не убирать, в скомпилированный скрипт эти строки не попадут.
Еще, если делать стандартного компаньона, то свой квест можно не создавать. Тогда он будет подчиняться общим правилам рекрутирования / найма, которые могут изменяться в зависимости от установленных модов у пользователя.
Когда я делал своего, создал квест только ради 2 строчек диалога ("открыть меню тренировки навыка", "навык слишком высок").
и галочки в Fill Type (вместо Specific Reference у меня Unique Actor и ID компаньона)
Понятно. В DialogueFollower алиас изначально пуст. Предположим, НПС подходит по условиям для диалога его найма в компаньоны. Тогда, в конце фразы, алиас квеста DialogueFollower скриптом заполняется этим НПС, ему добавляются необходимые пакеты (следование) и фракции. А у тебя актер изначально обладает ими. В общем, я к тому, что все настройки алиаса нужно сделать такими же, как в оригинале.
Еще, вот это вот:
Код
_0RossenFollowerScript Property _0RossenDialogue Auto _0RossenDialogue.DismissFollower(5)
... эквивалентно этому:
Код
(GetOwningQuest() as _0RossenFollowerScript).DismissFollower(5)
Neell, если о файле, который появляется после архивации контента в .bsa, то это мусор. Скрипты добавляются в архив точно так же, как и все остальное. Исходники можно не ложить.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №703
| Тема: Вопросы по скриптам Papyrus
написано: 15 мая 2016, 12:27
| Отредактировано: Multigone - 15 мая 2016, 12:34
1) Думаю, да. Но реализация может быть разной. Вот какие идеи, когда игрок в скрытности действует телекинезом на актера: - он активирует его на расстоянии (процесс по умолчанию). - он заставляет его выбросить случайный (не экипированный) предмет из инвентаря, который затем можно подобрать. Игроку наносится урон магии, скажем, 50 ед., или перезарядка Х сек. Нужен SKSE. - открывается контейнер-меню для этого НПС. Первый предмет, который выберет игрок, выбрасывается из инвентаря актера (можно выбирать экипированное), меню закрывается и НПС переходит в состояние тревоги (если выбран экипированный предмет, то атакует). Нужен SKSE.
2) На пред. странице Dsion уже говорил про двери и заклинания. Есть еще вариант - искать ближайший референс указанного типа - FindClosestReferenceOfAnyTypeInListFromRef(). Но кол-во дверей и сундуков в сумме больше 400 (или около того), так что искать будет долго. Плюс, модные типы учитываться не будут. Не знаю, стоит ли оно того...
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №704
| Тема: Вопросы по скриптам Papyrus
написано: 15 мая 2016, 15:15
| Отредактировано: Multigone - 15 мая 2016, 15:16
Lexo, можно создать отдельное заклинание FF - Target Actor, длительностью 5с и условием "этого заклинания нет на актере". На телекинез повесить скрипт с постоянным апдейтом и кастом этого заклинания (цель не указывать). Тогда, как только игрок наведет прицел на актера, следующее заклинание в апдейте сработает и выполнит повешенный на него скрипт с Activate. Следующие 5с оно срабатывать не будет (типа кулдаун). Конечно, было бы проще, если б скриптом можно было узнавать референс, на который смотрит игрок. Но я такой функции не нашел (плохо искал?).
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №705
| Тема: Вопросы по скриптам Papyrus
написано: 15 мая 2016, 17:15
| Отредактировано: Multigone - 15 мая 2016, 17:24
Dsion, как ты знаешь, в Form есть SKSE-событие OnCrosshairRefChange(), но если в момент запуска скрипта с ним игрок уже смотрит на к.-л. референс, то его получить не выйдет. Событие полезное, но не в том конкретном случае.
Lexo, а? Я бы не стал на одно заклинание накручивать много разных вещей. Ванильные тем и хороши, что они простые и игроку легко запомнить, что какое делает. К тому же то, что ты предложил, уже есть в оригинале у крика... Эм, не помню название. К тому же, первое уже содержит второе (т.е. до боя можно снять экипированное оружие). К тому же, эта идея не слишком простая в реализации. Но если надо...
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №706
| Тема: Вопросы по скриптам Papyrus
написано: 16 мая 2016, 10:25
| Отредактировано: Multigone - 16 мая 2016, 10:26
Lexo, можно так, как это сделано для эффекта PerkImpactStaggerPushFFAimed.
Еще можно сделать абсолютно разное действие в зависимости от того, с левой руки творится заклинание, с правой или с обеих. Для этого понадобится алиас игрока, SKSE-событие OnActorAction() и проверка GetAnimationVariableBool("IsCastingDual") для левой руки. Будет работать только для игрока.
Lexo, там скрипт отслеживает OnHit() от допустимых источников. Чтобы заклинание проходило проверку, его нужно добавить в mineOreToolsList. Как сделать, чтобы заклинание с Self могло творить другое заклинание, я уже говорил.
STATE S EVENT OnBeginState() ; Debug.Notification("OnBeginState") IF fW Actor xP = Game.GetPlayer() xP.DamageAV("Magicka", 50.0) Int iC WHILE !bE && iC < 50 Utility.Wait(0.01) iC += 1 ENDWHILE xP.CreateDetectionEvent(xA, iMin((10.0 * fW + 50.0 * (bE AS Int)) AS Int, 100)) IF xP.GetRelationshipRank(xA) < 0 ELSEIF bE ; Друж. НПС теряет дружбу с игроком. ELSE ; Друж. НПС говорит WI и поднимает (?) предмет. ENDIF ENDIF ENDEVENT ENDSTATE
EVENT OnEffectStart(Actor xT, Actor xC) ; Debug.Notification("OnEffectStart") xA = xT RegisterForMenu("ContainerMenu") xA.OpenInventory(true) ENDEVENT
EVENT OnItemAdded(Form xF, Int iN, ObjectReference xR, ObjectReference xS) IF xS F(xF, iN, xA, xS) ENDIF ENDEVENT
EVENT OnItemRemoved(Form xF, Int iN, ObjectReference xR, ObjectReference xD) IF xD F(xF, -iN, xD, xA) ENDIF ENDEVENT
EVENT OnObjectUnequipped(Form xF, ObjectReference xR) bE = true ENDEVENT
EVENT OnMenuClose(String sN) ; Debug.Notification("OnMenuClose") WHILE iS Utility.Wait(0.01) ENDWHILE GoToState("S") ENDEVENT
FUNCTION F(Form xF, Int iN, ObjectReference xS, ObjectReference xD) iS += iN IF iS * iN <= 0 ELSEIF iN < 0 && !fW fW = xF.GetWeight() + 1.0 Input.TapKey(0x1) ; в Input нет Valid controls для ESC? xS.RemoveItem(xF, Math.Abs(iN) AS Int, true, xD) xD.DropObject(xF, 1) ELSE xS.RemoveItem(xF, Math.Abs(iN) AS Int, true, xD) ENDIF ENDFUNCTION
Int FUNCTION iMin(Int A, Int B = 0) IF A < B RETURN A ENDIF RETURN B ENDFUNCTION
Как работает: при касте телекинеза на актера открывается его инвентарь. Первый выбранный игроком предмет выбрасывается, игроку наносится урон магии 50 ед. за перенапряжение, создается шумовое событие амплитудой (от 10 + 10 за каждый 1 ед. веса выброшенного предмета + 50 за экипированный предмет, максимум 100; нужен тест события). Кулдаун 3с. Не проработана реакция дружественного НПС на такую кражу.
Что учтено: - игрок не может положить предмет в инвентарь актеру или напрямую взять его оттуда. - нельзя одновременно взять предмет телекинезом и копаться в инвентаре актера. - если игрок просто закроет меню, не выбрав предмет, ничего не произойдет.
PS: Возможно, я что-нибудь забыл указать, т.к. сказывается недостаток времени. Как я и говорил, этот идея не слишком простая в реализации.
Я б не сказал, что совсем уж потрясающе. Единственное, что в скрипте ценного (и над чем я долго думал), это система возврата предметов, но я ее пилил еще давно, а сейчас просто чуть улучшил.
А, в первом спойлере нужно закомментировать Debug.Notification("+").
Lexo, меня тоже один раз (из многих тестов), когда я пытался сунуть НПС 6 флаконов зелья, но я не понимаю, с чем это связано. В скрипте нет структур, которые могли бы сильно загрузить процессор или заставить движок выполнять множество одновременных команд. К слову, меня иногда (редко) выкидывает из МСМ-меню, когда я тестирую разные настройки. Совершенно рандомные вылеты. В общем, используй на свой страх и риск.
Aksyonov, если предметы квестовые (их нельзя выкинуть), то вот примерный скрипт на алиасы:
Код
Scriptname X extends ReferenceAlias
GlobalVariable Property MyGlobal Auto ; Новая глобальная, значение 0.
Event OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer) if akNewContainer == Game.GetPlayer() MyGlobal.Value += 1.0 ; Считаем предметы. EndIf IF MyGlobal.Value >= 5.0 ; Пусть у нас 5 разных квестовых предметов. GetOwningQuest().SetStage(7) ; Нам нужно установить 7 стадию. Endif EndEvent
Вместо глобальной можно использовать переменную скрипта квеста. В общем, см. FreeformRiften14, правда, там немного по-другому.