Создаешь квест. Создаешь стадию квеста, отвечающую за состояние "задания нет" (напр., стадия 0), и несколько стадий, отвечающие за "конкретное случайное задание в процессе" (стадии 10, 20, 30 и т.д.). Для каждой стадии "конкретное случайное задание в процессе" (стадии 10, 20, 30 и т.д.) делаешь соотв. описание "Мне требуется принести предмет Х в кол-ве У подателю квеста Z". Создаешь глобальную Int - Short, значение 0. Значение глобальной будет определять новое случайное задание. К квесту должен быть прикреплен скрипт с таким фрагментом:
; При первом запуске квеста задает случайное значение глобальной (10, 20, 30 и т.д.).
EVENT OnInit() IF !IsRunning() && !IsCompleted() MyGLOB.SetValue(10 * Utility.RandomInt(1, 3)) ; Второе число (3) = количеству заданий. ; MyGLOB - глобальная, она должна являться Property. ENDIF ENDEVENT
Создаешь диалоги - инициаторы задания; каждый диалог отвечает за фразу "принеси мне предметы Х, кол-во У". Количество диалогов-инициаторов = количеству случайных заданий. В каждом диалоге указываешь условия: 1) Одно общее: если стадия квеста == задания нет (стадия 0). 2) Одно уникальное: если значение глобальной == соотв. числу (10 или 20 или 30 и т.д.). К каждому диалогу должен быть прикреплен скрипт, выполняющий: 1) Перевод стадии квеста с "задания нет" (0) на "конкретное случайное задание в процессе" (10, 20, 30 и т.д.).
; Пример кода, устанавливающего случайную стадию "конкретное случайное задание в процессе" на основе значения глобальной:
MyQuest.SetStage(MyGLOB.GetValueInt()) ; MyGLOB - глобальная, она должна являться Property.
Создаешь диалоги - завершители задания, каждый диалог отвечает за фразу "я принес тебе предметы Х, кол-во У". Количество диалогов-завершителей = количеству случайных заданий. В каждом диалоге указываешь условия: 1) Одно основное: если стадия квеста == соотв. числу (стадия 10 или 20 или 30 и т.д.). 2) Одно второстепенное: если игрок имеет количество предметов для задания >= количество У. К каждому диалогу должен быть прикреплен скрипт, выполняющий: 1) Перевод стадии квеста с "конкретное случайное задание в процессе" (стадии 10, 20, 30 и т.д.) на "задания нет" (стадия 0). 2) Установку нового случайного значения глобальной, это значение не должно совпадать с предыдущим. 3) Удаление предметов Х в кол-ве У. 4) Выдачу награды.
; Пример кода, переводящего стадию квеста на 0:
MyQuest.SetStage(0) ; MyQuest - квест, он должен являться Property.
; Пример кода, устанавливающего новое значение глобальной, не равное старому:
Int iGlobal = MyGLOB.GetValueInt() ; MyGLOB - глобальная, она должна являться Property. Int iCount = iGlobal WHILE iCount == iGlobal iCount = 10 * Utility.RandomInt(1, 3) ; Второе число (3) = количеству заданий ENDWHILE MyGLOB.SetValue(iCount)
; Пример кода, удаляющего предмет Х в кол-ве У:
Game.GetPlayer().RemoveItem(MyItem, iY) ; MyItem - предмет Х, он должен являться Property. ; iY - количество предметов (У), указывается цифрой (1, 2, 3 и т.д.)
; Пример кода, выдающего награду:
Game.GetPlayer().AddItem(Gold001, iRevard) ; Gold001 - золото, оно должно являться Property. ; iRevard - количество золота, указывается цифрой (1, 1000, 1000000 и т.д.).
Создаешь диалоги, отвечающие за фразу "у тебя нет предметов Х в кол-ве У, иди ищи дальше". Количество таких диалогов = количеству случайных заданий. В каждом диалоге указываешь:
Для первого:
Стадия квеста == "случайное задание 10 в процессе, т.е. стадия 10" (AND) Количество предметов Х1 < требуемое У1 (AND)
Для второго:
Стадия квеста == "случайное задание 20 в процессе, т.е. стадия 20" (AND) Количество предметов Х2 < требуемое У2 (AND)
Для третьего:
Стадия квеста == "случайное задание 30 в процессе, т.е. стадия 30" (AND) Количество предметов Х3 < требуемое У3 (AND)
...
Стадия квеста == "случайное задание N в процессе, т.е. стадия N" (AND) Количество предметов Хn < требуемое Уn (AND)
Никаких скриптов на эти диалоги вешать не надо.
Итого: 1 квест. 1 глобальная. 1 стадия "нет задания". + Для каждого случайного задания потребуется 3 фразы диалога (инициатор, ищи дальше, завершитель) и одна стадия квеста "конкретное случайное задание в процессе".
Не сомневаюсь, такой подход к реализации случайных заданий является одним из самых топорных. Думаю, это можно сделать меньшими телодвижениями. Нужно смотреть оригинальные квесты "подай-принеси-повтори".
ЗЫ: Спойлеры все поломались (сперва при добавлении, потом при редактировании), о глупый движок MG!
Scriptname MyScript extends ObjectReference ; Урезанный оригинальный скрипт. ; Играет анимацию на связанном с этим активатором бюсте для маски. ; Удаляет / добавляет указанную маску активирующему. ; Если указанной маски нет, сообщает об этом. ; В курсе, что для моделей масок из Dragonborn нужно делать новые модели, используемые в бюстах?
armor property myMask auto message property MyMESG auto
SoraSt, за добавление маски отвечает строка: actronaut.addItem(myMask, 1). Не вижу в ней ч.-л. необычного. А ты заполнял вот это:armor property myMask auto? При активации бюста без маски она удаляется из инвентаря?
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №277
| Тема: Вопросы по скриптам Papyrus
написано: 29 сентября 2014, 11:01
| Отредактировано: Multigone - 29 сентября 2014, 11:02
Кто-нибудь знает, как скриптом узнать Object Reference снаряда (Projectile), который выпускается при касте заклинания? Дело в том, что на сам снаряд скрипт повесить нельзя.
Нужно для того, чтобы при попадания снаряда в препятствие вызвать на нем PlaceAtMe.
Dsion, нет, не пойдет. Дело в том, что у меня размещаемый объект меняется скриптом. Кручу, верчу! В общем, этот вариант я продумывал. Вся надежда была сделать таким образом:
- к снаряду добавляется свет (единственное, что может связать снаряд и скрипт). - к свету добавляется скрипт с событиями Загрузка() и Выгрузка(). - дальше можно делать, что угодно (но это в теории). - на практике этот скрипт вообще не работает. - у света есть поле скриптов, но в оригинальных формах нет ни одного скрипта.
ПС: Кстати, а ведь можно спавнить невидимый объект, к нему цеплять скрипт с событиями Загрузка() и Выгрузка(), и через мгновение его Удалять(). Как думаешь, вариант жизнеспособен?
- скомпилировал скрипт. - добавил его к точильному камню, который скинул в окно рендера. - запустил игру и побежал в Ривервуд. - мой модный НПС начал пользоваться этой фурнитурой (у него пакет Сэндбокс). - пока НПС пользовался им, периодически выводилось уведомление (я его добавил). - когда НПС слез, вывелось Off. - проверил с игроком, все то же самое.
Если эффект имеет тип Constant, тогда условие нужно указывать в эффекте в самом заклинании. Если эффект имеет тип Concentration - можно указывать как в заклинании, так и в эффекте, но только в одном из них (здесь нужно уточнять). Если эффект имеет тип FireForget и не имеет продолжительности - условие указывается в самом эффекте. Если имеет продолжительность - условие, указываемое в эффекте, будет определять, наложится эффект на цель или нет; условие, указываемое в заклинании, будет определять, действует ли эффект на цель в текущий момент времени.
Почему так: условия, указанные в заклинании (в соотв. эффекте), будут проверяться каждую секунду. Условия, указанные в самом эффекте, будут проверяться один раз - в момент наложения эффекта на цель.
В общем, по-другому не могу объяснить. См. CK Вики.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №286
| Тема: Игра в правду
написано: 30 сентября 2014, 13:16
У меня не работает следующее событие в скрипте на квесте:
EVENT OnStoryRemoveFromPlayer(ObjectReference akOwner, ObjectReference akItem, Location akLocation, Form akItemBase, int aiRemoveType) Debug.Notification("Удалено!") ENDEVENT
Я так понимаю, событие должно срабатывать при удалении любого предмета из инвентаря игрока. Однако, это не работает. У кого-нибудь есть какие-нибудь идеи-нибудь?
Dsion, что-то я первый раз с этим сталкиваюсь. Спасибо, буду разбираться ИЛИ попробую пока обойтись событием
EVENT OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
на алиасе игрока.
------------------
Вот-вот, о чем я и говорю. Но у квеста есть возможность отследить, как именно был удален предмет, для меня это достаточно важно. Понятное дело, что в алиасе это будет выглядеть примерно так (я сейчас это и использую):
IF !akDestContainer && !akItemReference ; предмет удаляется бесследно.
IF akDestContainer ; В контейнер.
IF !akDestContainer && akItemReference ; В мир.
А мне нужно еще отследить, когда он удаляется движком (это камни душ), скриптом (у меня несколько скриптов удаляют их), а также для того, чтобы при удалении скриптами др. модов (если таковые будут) это тоже можно было определить.
Event OnUnequipped(Actor akActor) IF akActor.GetEquippedSpell(0) akActor.UnequipSpell(MySpell, 0) ENDIF IF akActor.GetEquippedSpell(1) akActor.UnequipSpell(MySpell, 1) ENDIF akActor.RemoveSpell(MySpell) endEvent
anton,
По поводу крафта:
1) Можно попробовать действовать через скрипт др. квеста:
ScriptName MyScript extends Quest
Quest Property MyQuest Auto MiscObject Property MyItem Auto ; Указать соотв. тип своего предмета.
Event OnStoryAddToPlayer(ObjectReference akOwner, ObjectReference akContainer, Location akLocation, Form akItemBase, int aiAcquireType) IF akItemBase == MyItem IF aiAcquireType == 0 IF !(MyQuest.IsRunning()) && !(MyQuest.IsCompleted()) MyQuest.Start() ENDIF ENDIF ENDIF ENDEVENT
2) Через скрипт алиаса игрока:
ScriptName MyScript extends ReferenceAlias
Quest Property MyQuest Auto MiscObject Property MyItem Auto ; Указать соотв. тип своего предмета.
EVENT OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer) IF akBaseItem == MyItem IF UI.IsMenuOpen("Crafting Menu") ; Функция требует SKSE, к сожалению. ; Crafting Menu - любое меню крафта. ; Если предмет создастся в любом месте для крафта (алхимия, кузница, топка, чары и т.д.), то... ; ... UI.IsMenuOpen("Crafting Menu") - проверка будет выполнена. IF !(MyQuest.IsRunning()) && !(MyQuest.IsCompleted()) MyQuest.Start() ENDIF ENDIF ENDIF ENDEVENT
- пост. обновление на игроке. - в малом радиусе ищется ближайший реф. с типом нужной фурнитуры. - при нахождении - этот реф. добавляется в алиас (Optional), на котором есть скрипт и событие ПриАктивации(). - когда игрок активирует его, переводит булевую переменную (или глобальную на значения 0 и 1) на true, когда уходит с фурнитуры - на false. - событие добавления предмета на алиасе игрока. - если при добавлении предмета переменная = true, запустить квест.