Князь_Далик, для каждого маркера потребуется пара "квест. задача + алиас". Скрипт для любого кол-ва маркеров (насколько хватит алиасов, нужен тест):Е
Код
Scriptname _TESTTEST43 Extends ObjectReference ; Скрипт на контейнер.
Message Property pxNotNoted Auto ; Сообщение 1 ;0 - доступ к инвентарю сундука ;1 - забрать все в инвентарь игрока ;2 - добавить маркер
Message Property pxNoted Auto ; Сообщение 2 ;0 - доступ к инвентарю сундука ;1 - забрать все в инвентарь игрока ;2 - удалить маркер
Quest Property MMarker Auto MiscObject Property chestparts Auto Int Property piNoted = -1 Auto Hidden
EVENT OnActivate(ObjectReference akActionRef) GoToState("Empty") Int button IF piNoted < 0 button = pxNotNoted.Show() ELSE button = pxNoted.Show() ENDIF if !button Activate(Game.GetPlayer(), true) elseif button == 1 removeAllItems(Game.GetPlayer(), true) Game.GetPlayer().AddItem(chestparts) Delete() ELSEIF piNoted < 0 button = 0 WHILE button < 128 && (MMarker.GetAlias(button) AS ReferenceAlias).GetReference() ; Вместо 128 указать реальное кол-во алиасов. Напр., если последний номер равен 15, общее кол-во = 16. ; Алиасы должны иметь ID-номера строго по порядку от 0 до Х (0, 1, 2, 3, ..., X). ; Чтобы нумерация была строгой, алиасы нельзя удалять после создания. ; Квестовые задачи должны нумероваться строго по порядку от 0 до Х. button += 1 ENDWHILE IF button < 128 ; Вместо 128 указать свое число. piNoted = button (MMarker.GetAlias(button) AS ReferenceAlias).ForceRefTo(Self) MMarker.SetObjectiveDisplayed(button, true) ELSE Debug.MessageBox("Слишком много активных маркеров") ENDIF ELSE MMarker.SetObjectiveDisplayed(piNoted, false) (MMarker.GetAlias(piNoted) AS ReferenceAlias).Clear() piNoted = -1 ENDIF GoToState("") ENDEVENT
STATE Empty EVENT OnActivate(ObjectReference akActionRef) ENDEVENT ENDSTATE
Event onEffectStart(Actor akTarget, Actor akCaster) IF !akTarget RETURN ENDIF ValueMod = GetMagnitude()/100.0 if IsNegative ; ...
В процессе проверки нужно учитывать, что изменения не повлияют на уже запущенные скрипты. А вообще, я бы не рассчитывал на столь неуважительно обращающегося с weaponSpeedMult.
Dsion, немного дополню. В случае, если Х - переменная Bool, писать (IF X == true) нет никакого смысла.
Код
IF X ; Если Х истинно, то... IF X == true ; Если (X == true) истинно, то...
Переменная (X) и результат выражения (X == true) всегда имеют одинаковые значения, но во втором случае затрачивается лишнее действие на вычисление результата.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №845
| Тема: Тех. проблемы
написано: 25 декабря 2017, 13:40
Поставил плюсик комментарию, но зелененькое число не поменялось. Ткнул еще раз, спустя пару секунд оценка комментария подскочила на 2 (появилось 2 окошка с сообщением). Хмм... так можно вообще? Firefox, Flash 23.0 r0 (устаревший).
modgms_user, обычно, если функции применять к none, они возвращают false, 0, "", none. Конкретно в том скрипте - не будет никакого влияния на глобальную и AV актера, если GetMagnitude() вернет 0.0. Там другая проблема. Если события старта и финиша срабатывают почти одновременно (например, когда продолжительность эффекта 0), то это может привести к возврату AV не в исходное состояние. Параноик-код должен выглядеть примерно так:
modgms_user, финиш должен ждать окончания старта. Старт должен ждать финиш - в одном скрипте могут много раз срабатывать эти события, если в EffectItem заклинания есть какое-то периодически срабатывающее условие.
Код будет выполняться, но нагрузка там смешная. К тому же она уже заложена в функционал мода.
Чем защищенней код, тем в нем будет больше проверок. Я бы даже сказал, иногда, чтобы использовать одну строчку, которая что-то там по задумке делает, нужно обеспечить ее десятью защитами, чтобы она срабатывала только тогда и ровно столько раз... С другой стороны, если знаешь, что код будет выполняться только так, и никак иначе, и создавать лишние проверки нет нужды.
modgms_user, как только эффект снимается с актера, он перестает существовать. А скрипт этого эффекта будет до тех пор, пока не выполнятся все уже запущенные события и функции. Поэтому if self будет (должен?) проходить проверку всегда. А чтобы работала GetMagnitude(), выходит, нужно наличие эффекта на актере. Ведь она возвращает не базовую магнитуду из EffectItem заклинания, а настоящую, с учетом всех его перков / сопротивлений.
Этим можно воспользоваться - если между стартом и финишем пройдет меньше 0.1 с, значит,.. 1) ...эффект имеет продолжительность 0... 2) ...или заклинание было снято принудительно, например, если актер в связанных скриптах имеет подобное:
modgms_user, проверил на игроке, как при нулевой, так и при ненулевой продолжительности эффекта скрипт всегда завершает и старт, и финиш. Не знаю, в чем там у тебя дело. Во втором скрипте допущен маленький косячок, который при нулевой продолжительности дает теоретический шанс, что финиш все-таки сработает раньше старта, но в этом случае GetMagnitude() вернет 0 и AV не будет затронуто. Ничего критичного. В обоих случаях цикл крутится только тогда, пока выполняется код другого события. Чтобы цикл крутился вечно, нужно изначально допустить ошибку в логике - но при первом же тесте это будет выявлено. Ладно, вот тебе версия, где цикл гарантированно завершается не более чем через 2 секунды после срабатывания события финиша.
Код
Bool Property IsNegative Auto Bool Property AffectsGV Auto GlobalVariable Property affectedGV Auto
Float ValueMod Bool Kicked Int iLock = 80
Event onEffectStart(Actor akTarget, Actor akCaster) Utility.Wait(0.2) IF iLock <= 40 iLock -= 1000 RETURN ENDIF ValueMod = GetMagnitude() / 100.0 IF !ValueMod iLock -= 1000 RETURN ENDIF if IsNegative ValueMod = -ValueMod Endif If AffectsGV If akTarget == Game.GetPlayer() || akTarget.IsPlayerTeammate() Kicked = true affectedGV.Mod(ValueMod) Endif else if StatToMod == "weaponSpeedMult" && akTarget.GetActorValue(StatToMod) == 0.0 ValueMod += 1.0 endif akTarget.ModActorValue(StatToMod, ValueMod) endif iLock -= 40 Endevent
V Финиш ждет старт - безопасный возврат AV в исходное состояние. V Выполнение GetMagnitude() предотвращается, если эффект имеет слишком малую продолжительность - не будет ошибки в лог. V Цикл всегда завершается - гарантия возврата AV и отсутствия накапливающейся нагрузки. V C осторожностью (и тестами) можно использовать в эффекте, имеющем условия в EffectItem. X Возможная проблема с weaponSpeedMult остается - после снятия первого из 2х таких эффектов актер может быть замедлен.
- эффект с архетипом ValueMod не накладывается на уже мертвых актеров. - когда актер погибает, большинство эффектов снимаются, если в них не указано NoDeathDispel. С игрока - не всегда. - если для заклинания, кастуемого игроком, по результатам проверок условий и сопротивлений на другую цель не будет наложено ни одного эффекта, в верхнем углу появится сообщение "такой-то избегает действия того-то". - проверки в EffectItem происходят раз в секунду, в окне TargetConditions эффекта - один раз при наложении. Множество постоянных проверок нежелательно. - если условие TargetConditions не дает эффекту наложиться, его скрипт не инициализируется, требование DispelEffectsWithTheseKeywords не выполняется. - условие в EffectItem не препятствует наложению эффекта, просто "переключает" его состояние, при этом срабатывают события старта и финиша (соответствующее, скрипт продолжает работать); требование DispelEffectsWithTheseKeywords выполняется один раз в момент наложения; в отключенном состоянии он все еще определяется через HasMagicEffect(). - если заклинание имеет несколько эффектов, условия TargetConditions следующего эффекта начнут проверяться после того, как будут проверены у вышестоящего. - для эффектов Concentration условия в TargetConditions и EffectItem играют обратную роль (с СК.сом / не проверял / возможно, это только кажется из-за продолжительности большинства их в 1 секунду).
Quest SideQuest = Game.GetFormFromFile(0x123456, "SideModName.esp") AS Quest; Вместо цифр FormID стороннего квеста. IF SideQuest SideQuest.Start() ENDIF
Предположим, в его алиасе есть целевой НПС:
Код
IF SideQuest Actor SideActor = (SideQuest.GetAlias(0) AS ReferenceAlias).GetActorReference() ; Вместо 0 реальный номер (ID) алиаса с актером. IF SideActor SideActor.Kill() ENDIF ENDIF
modgms_user, проверил, возможно, (Self AS String != "[ScriptName ]") и даст необходимую проверку, наложен ли этот эффект на актера.
Код
if target.HasMagicEffect()
Не рекомендую, т.к. активных копий одного эффекта может быть больше 1 (некоторые архетипы позволяют это, напр., ValueMod). Один конкретный эффект уже исчез, но на актере есть и другие - проверка в скрипте первого будет положительна.
modgms_user, действительно, это быстрее. В среднем на 0.0000003 с (на моем компе). Но переменная, в отличие от литерала, занимает какую-то память, пока живет в отрезке кода, где была объявлена. Тогда предположу, что создание переменной и литерала - это примерно одно и то же, на это затрачивается опред. время.
Как я и сказал, в твоем случае это не имеет значения.
Error: Unable to call RegisterForSingleUpdate - no native object bound to the script object, or object is of incorrect type
Невозможно вызвать RegisterForSingleUpdate - нет объекта. Значит, эффект был снят в промежутке, когда выполнялся очередной onUpdate(). Даже если сделать проверку на наличие эффекта перед каждым RegisterForSingleUpdate (а их там 2), это не даст 100% гарантии, поскольку эффект может быть снят точно между проверкой и регистрацией. Типа так:
Код
Event onUpdate() ; ... IF self as sring != "[scriptname <None>]" ; в этот момент эффект внезапно! снимается. RegisterForSingleUpdate(1.0) ENDIF endif Endevent
Шанс этого ничтожен, но если эффекты распространенные, несколько могут и сработать таким образом.
Ну, я так думаю.
Вообще, такую конструкцию, как в том скрипте, я много раз где видел, никто с этим особо не парился. Ну да, в лог может кинуть ошибку. И... все.
armor property ArmorhisSnowElfBoots auto armor property ArmorhisSnowElfCrown auto armor property ArmorhisSnowElfCuirass auto armor property ArmorhisSnowElfGauntlets auto
armor property ArmorhisSnowElfBoots auto armor property ArmorhisSnowElfCrown auto armor property ArmorhisSnowElfCuirass auto armor property ArmorhisSnowElfGauntlets auto
EVENT onItemAdded(form itemAdded, int itemCount, objectReference itemRef, objectReference sourceRef) if hisQuestArmorSnowElf.getStageDone(20) && !hisQuestArmorSnowElf.getStageDone(30) RemoveInventoryEventFilter(itemAdded) iCount += 1 IF iCount > 3 GoToState("Emp") hisQuestArmorSnowElf.SetStage(30) RemoveAllInventoryEventFilters() ; ENDIF endif endEVENT
STATE Emp EVENT onItemAdded(form itemAdded, int itemCount, objectReference itemRef, objectReference sourceRef) endEVENT ENDSTATE
Твой вариант имеет лишние переменные, но он железный. Здесь же при некоторых исключительных обстоятельствах запуск может произойти раньше. А именно: хотя ладно, все равно это никто не читает.
И да, тут есть тема по скриптам.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №860
| Тема: Вопросы по скриптам Papyrus
написано: 12 января 2018, 18:47
| Отредактировано: Multigone - 12 января 2018, 18:49
Как ты хочешь это сделать? Input позволяет получить клавишу контроля, или нажать / зажать / отпустить. Такого, чтобы разбиндить управление, там нет. Когда я делал мод на прыжки, в меню менял управление с пробела на неиспользуемую клавишу, регистрировал пробел, и когда игрок нажимал его, через TapKey() нажимал эту неиспользуемую клавишу. Ну а что поделать? Беседка построила кривую беседку, а мы продолжаем ее в чудесную башню (нет).
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №861
| Тема: Кракозябры в скриптах
написано: 25 января 2018, 11:59
| Отредактировано: Multigone - 25 января 2018, 12:16
Dagnir, возможно, проблема в скрипте из-за использования GetName(). С латиницей там все нормально работает, но с кириллицей нет, она имеет разную кодировку внутри СК и в папирусе.
Например, такая конструкция:
Код
String Property sDestinationPoint = "By the destination it is established: (" Auto ; В СК переводишь этот Property как "Пунктом возврата установлен: (".
Location Property xLocationPoint Auto Hidden; Локация, меняется откуда-то извне, в СК ее имя переведено на русский.
Function ShowMessage() Debug.Notification(sDestinationPoint + xLocationPoint.GetName() + ")") Endfunction
В этом случае текст sDestinationPoint принадлежит скриптам, GetName() - СК. Их объединение вызовет кракозябру.
Как один из кривых вариатов решения (возможно, единственный), люди советуют создать в СК любую форму с именем 'Пунктом возврата установлен: ', и такое:
Код
Location Property xLocationPoint Auto Hidden; Локация, меняется откуда-то извне, в СК ее имя переведено на русский. MiscObject Property xSomeTextName Auto ; Объект с именем 'Пунктом возврата установлен: '
Function ShowMessage() Debug.Notification(xSomeTextName.GetName() + xLocationPoint.GetName()) ; Неизвестно, как дополнительные текстовые слагаемые типа + ")" могут повлиять на результат. Endfunction
Я не проверял, но говорят, работает. Может, у тебя дело в чем-то другом, а я просто неправильно понял проблему.
AlexeyVN, насколько я знаю, в Actor Values это никак не отражается. Если захват производится ванильным SoulTrap(), то тут можно мало что посоветовать. Способ есть, но с побочными действиями. А именно: попытаться захватить душу мертвого актера, временно выдав игроку подходящий камень душ. Если душа есть, то захват будет успешен. Поскольку SoulTrap() работает только для игрока, для этого придется поменять в СК пустые камни душ, чтобы они могли складываться с заполненными изначально; из игры убрать сообщения (душа захвачена / нет камней душ). Если такое устраивает...
- смерть актера - наличие на нем эффекта захвата душ - наличие у игрока подходящих камней ПЕРЕД смертью актера.
Третий пункт невозможно выполнить. А проверка после смерти актера, есть ли у игрока подходящий заполненный камень (который мог бы образоваться в результате захвата), ни о чем не говорит, т.к. неизвестно, не таскал ли его игрок до этого. Плюс, камень станет полным только в случае, если размеры души и камня совпадают, иначе получается камень вроде "Великий камень душ (крохотный)", который все еще считается пустым с точки зрения GetItemCount().
Поэтому моя версия ответа - нет, по косвенным признакам нельзя определить.
modgms_user, можно перком Activate получить референс "активируемого" игроком объекта, сделать что нужно (проверить, положить предметы, еtс.) и потом активировать его по-настоящему.