Однако эффекта не вижу. Похоже, спеллы просто не назначаются.
1) Ошибки возникают из за того, что функция FindRandomActorFromRef возвращает None (никого не найдено), а скрипт пытается добавить Spell. 2) На ком это должно срабатывать? В таком виде скрипт даже кроликам будет пытаться добавлять Spell. Можно сделать проверку GetRace() и FormListHeadPartsAllRacesMinusBeast. 3) Код скрипта не эффективен. Если хотите могу подправить, но напишите подробно условия срабатывания.
Изменение репутации для пользователя LordVadim
LordVadimOffline
Сообщение №92
| Тема: Вопросы по скриптам Papyrus
написано: 25 марта 2014, 17:35
| Отредактировано: LordVadim - 25 марта 2014, 18:21
Spell Property aaARCRWeapArmMatSpecBase auto Spell Property aaARCRabilityWeapArmMatSpecDrag auto Spell Property aaARCRabilityUndead auto Spell Property aaARCRabilityUndeadMod auto Faction Property _00SICUndeadFaction auto
FormList Property prClosestActors Auto;- Используем форм-лист вместо массива (создать пустой форм-лист prClosestActors в СК и не забыть присвоить свойство в скрипте)
Actor randomActor Int iIndex
Event OnInit() While IsRunning();- Работает, пока квест активный iIndex = 40;- Количество попыток поиска НПС While iIndex > 0;- Поиск НПС около ГГ iIndex -= 1 randomActor = Game.FindRandomActorFromRef(Game.GetPlayer(), 30000.0);- Алекс прав - радиус великоват, я бы поставил не более 10000 if randomActor != None;- Если НПС найден if !prClosestActors.HasForm(randomActor);- Если НПС нет в форм-листе значит и спелов у него нет (если они даются только из скрипта) prClosestActors.AddForm(randomActor);- Добавляем НПС в форм-лист randomActor.AddSpell(aaARCRWeapArmMatSpecBase);- Добавляем спелл randomActor.AddSpell(aaARCRabilityWeapArmMatSpecDrag);- Добавляем спелл randomActor.AddSpell(aaARCRabilityUndead);- Добавляем спелл if randomActor.IsInFaction(_00SICUndeadFaction);- Если НПС принадлежит фракции _00SICUndeadFaction randomActor.AddSpell(aaARCRabilityUndeadMod);- Добавляем спелл EndIf EndIf else;- Если поблизости нет НПС, то нет смысла 40 раз вызывать функцию FindRandomActorFromRef iIndex = 0;- Выходим из цикла While iIndex > 0, чтобы сработала задержка EndIf EndWhile iIndex = prClosestActors.GetSize();- Количество НПС в форм-листе While iIndex > 0;- Поиск далёких или мёртвых НПС iIndex -= 1 randomActor = prClosestActors.GetAt(iIndex) as Actor;- Текущий НПС из форм-листа if (randomActor.GetDistance(Game.GetPlayer()) > 30000) || (randomActor.IsDead());- Если НПС далеко или мёртв(я бы поставил 12000) if randomActor.HasSpell(aaARCRWeapArmMatSpecBase);- Если у НПС есть спелл randomActor.RemoveSpell(aaARCRWeapArmMatSpecBase);- Убираем спелл EndIf if randomActor.HasSpell(aaARCRabilityWeapArmMatSpecDrag);- Если у НПС есть спелл randomActor.RemoveSpell(aaARCRabilityWeapArmMatSpecDrag);- Убираем спелл EndIf if randomActor.HasSpell(aaARCRabilityUndead);- Если у НПС есть спелл randomActor.RemoveSpell(aaARCRabilityUndead);- Убираем спелл EndIf if randomActor.HasSpell(aaARCRabilityUndeadMod);- Если у НПС есть спелл randomActor.RemoveSpell(aaARCRabilityUndeadMod);- Убираем спелл EndIf prClosestActors.RemoveAddedForm(randomActor);- Убираем НПС из форм-листа iIndex = prClosestActors.GetSize();- Пересчитываем количество НПС в форм-листе EndIf EndWhile Utility.Wait(5.0);- Задержка. я поставил 5 сек. это снизит нагрузку на движок игры, да и при таком радиусе всё равно будет успевать срабатывать EndWhile;- Если Квест не завершается, то и цикл не кончится никогда - поэтому нет смысла писать какой либо код после EndWhile EndEvent
В скрипт не включил проверки на ком срабатывать, я так понял, что они прописаны в условиях спеллов. Кстати, если спеллы не срабатывают - проверь правильность написания этих условий.
Изменение репутации для пользователя LordVadim
LordVadimOffline
Сообщение №93
| Тема: Вопросы по скриптам Papyrus
написано: 25 марта 2014, 19:27
| Отредактировано: LordVadim - 25 марта 2014, 20:06
Уважаемые скриптеры, срочно нужна ваша помощь! Проблема вот в чём: у меня деревья не ЛОДятся. Я хочу вручную расставить ЛОД-модели деревьев внутри обычных, отметить галочкой IsFullLod. Нужен скрипт, который делает так, чтобы на близких расстояниях этих ЛОД-деревьев не было видно, а на расстоянии появления лодов они включались. Если возможно, учитываться должен параметр UGridsToLoad (подгружаемые ячейки), так как некоторые игроки могут изменить этот параметр, и лоды деревьев могут перемежаться с обычными деревьями. Варианты типа пересоздай ЛОДы не прокатят. Я уже сделал всё что мог с лодами, остался только этот параметр. Большое спасибо всем, кто откликнеться.
Как привязать к UGridsToLoad - не знаю. Все, что могу предложить - скрипт для скрытия/отображения дерева:
ScriptName LodTreeOnOffSCRIPT extends ObjectReference;- Скрипт на статическом объекте
Event OnInit() RegisterForUpdate(5);- Включаем процедуру обновления 1 раз в 5 секунд EndEvent
Event OnUpdate();- Процедура обновления if GetLinkedRef().GetDistance(Game.GetPlayer()) > 30000;- Если расстояние до ГГ > 30000 (значение подобрать опытным путём) GetLinkedRef().Enable();- Показываем дерево else GetLinkedRef().Disable();- Скрываем дерево EndIf EndEvent
Скрипт на любой статический объект рядом с деревом. Дерево привязать к объекту через LinkedRef в СК. Если надо скрывать/отображать несколько стоящих рядом деревьев, то остальные привязываются к главному дереву, через Enable Parent в СК.
Пришлось кое что переделать, но у меня заработало. Подробности под спойлером:
В квесте сделать алиас игрока и на него скрипт:
Scriptname aaTestSCRIPT extends ReferenceAlias;- Скрипт на алиасе игрока
Spell Property aaTest_Spell auto;- Спелл должен быть способностью
FormList Property aaTest_FormList Auto;- Используем форм-лист вместо массива (создать пустой форм-лист prClosestActors в СК и не забыть присвоить свойство в скрипте)
Actor Property prActor Auto Hidden Int ivIndex
Event OnInit();- При инициализации RegisterForSingleUpdate(5) EndEvent
Event OnUpdate() ivIndex = 40;- Количество попыток поиска НПС While ivIndex > 0;- Поиск НПС около ГГ ivIndex -= 1 prActor = Game.FindRandomActorFromRef(Game.GetPlayer(), 10000.00);- Радиус поиска if (prActor != None) && (prActor != Game.GetPlayer());- Если НПС найден if !aaTest_FormList.HasForm(prActor);- Если НПС нет в форм-листе значит и спелов у него нет (если они даются только из скрипта) aaTest_FormList.AddForm(prActor);- Добавляем НПС в форм-лист prActor.AddSpell(aaTest_Spell, False);- Добавляем спелл EndIf else;- Если поблизости нет НПС, то нет смысла 40 раз вызывать функцию FindRandomActorFromRef ivIndex = 0;- Выходим из цикла While ivIndex > 0, чтобы сработала задержка EndIf EndWhile ivIndex = aaTest_FormList.GetSize();- Количество НПС в форм-листе While ivIndex > 0;- Поиск далёких или мёртвых НПС ivIndex -= 1 prActor = aaTest_FormList.GetAt(ivIndex) as Actor;- Текущий НПС из форм-листа if (prActor.GetDistance(Game.GetPlayer()) > 12000) || (prActor.IsDead());- Если НПС далеко или мёртв (радиус поиска) if prActor.HasSpell(aaTest_Spell);- Если у НПС есть спелл prActor.RemoveSpell(aaTest_Spell);- Убираем спелл EndIf aaTest_FormList.RemoveAddedForm(prActor);- Убираем НПС из форм-листа ivIndex = aaTest_FormList.GetSize();- Пересчитываем количество НПС в форм-листе EndIf EndWhile RegisterForSingleUpdate(5) EndEvent
LordVadim, EVENT onDying - основное событие. При смерти актера, к которому будет применен магический эффект (Constant Self) с этим скриптом, происходит взрыв в точке местонахождения актера. Скрипт УЖЕ работает, но остался огрызок EVENT OnEffectStart от первоначального скрипта (этот скрипт используется в Ability огненного атронаха для создания огненного шлейфа и взрыва при гибели). Вот этот огрызок и надо удалить, чтобы скрипт оставался работоспособным. Также надо изменить условия активации события EVENT onDying, поскольку в текущий момент, если актер убит добивающим ударом ближнего боя (киллмуви), то событие гарантированно не срабатывает (взрыва не происходит). Может, надо убрать проверку по величине здоровья? Если просто удалить EVENT OnEffectStart, то скрипт не компилируется (или не работает, не помню сейчас), похоже, ему нужно вот это: selfRef = caster. Как-то так.
Событие OnEffectStart удалить не получится, так как именно в нем определяется к кому будет применен эффект, то есть задается значение переменной selfRef. Что бы скрипт срабатывал всегда можно событие onDying() заменить на OnDeath() Тогда скрипт будет выглядеть так:
LordVadim, да, теперь работает! Тестовую абилку сделала идентичную твоей (огненный плащ), радиус увеличила до 15000. Если при первой загрузке игры скрипт быстро раздает всем актерам в локации абилку, то после перехода в новую локацию довольно часто бывает ситуация, когда некоторым ближайшим к игроку актерам абилка дается в последнюю очередь. Примерно, 1-2 из 5 актеров в радиусе примерно 500 юнитов получают абилку с большой задержкой, уже когда и самые дальние актеры загорелись. Соответственно, вопрос. Можно ли в в одном цикле сделать несколько этапов проверки FindRandomActorFromRef? Например, 4 этапа: до 500, потом до 2500, потом до 7500, потом до 15000, или для этого лучше сделать 4 цикла и соответственно 4 форм. листа, или вообще каждый цикл в отдельном скрипте?
Новый вариант под спойлером, но все равно могут оставаться пропущенные персонажи, FindRandomActorFromRef - рандомная функция, может одного и того же найти 10 раз, а другой не попадется ни разу. Самое поганое, что FindRandomActorFromRef и ГГ находит постоянно, причем чаще чем всех остальных вместе взятых. В связи с этим я убрал else из проверки.
Scriptname aaTestSCRIPT extends ReferenceAlias;- Скрипт на алиасе игрока
Spell Property aaTest_Spell auto;- Спелл должен быть способностью
FormList Property aaTest_FormList Auto;- Используем форм-лист вместо массива (создать пустой форм-лист prClosestActors в СК и не забыть присвоить свойство в скрипте)
Actor Property prActor Auto Hidden Int ivIndex
Event OnInit();- При инициализации RegisterForSingleUpdate(5) EndEvent
Event OnUpdate() ivIndex = 20;- Количество попыток поиска НПС для первого прохода While ivIndex > 0;- Поиск НПС около ГГ ivIndex -= 1 prActor = Game.FindRandomActorFromRef(Game.GetPlayer(), 500.00);- Радиус поиска if (prActor != None) && (prActor != Game.GetPlayer());- Если НПС найден if !aaTest_FormList.HasForm(prActor);- Если НПС нет в форм-листе значит и спелов у него нет (если они даются только из скрипта) aaTest_FormList.AddForm(prActor);- Добавляем НПС в форм-лист prActor.AddSpell(aaTest_Spell, False);- Добавляем спелл EndIf EndIf EndWhile ivIndex = 30;- Количество попыток поиска НПС для второго прохода While ivIndex > 0;- Поиск НПС около ГГ ivIndex -= 1 prActor = Game.FindRandomActorFromRef(Game.GetPlayer(), 2000.00);- Радиус поиска if (prActor != None) && (prActor != Game.GetPlayer());- Если НПС найден if !aaTest_FormList.HasForm(prActor);- Если НПС нет в форм-листе значит и спелов у него нет (если они даются только из скрипта) aaTest_FormList.AddForm(prActor);- Добавляем НПС в форм-лист prActor.AddSpell(aaTest_Spell, False);- Добавляем спелл EndIf EndIf EndWhile ivIndex = 50;- Количество попыток поиска НПС для третьего прохода While ivIndex > 0;- Поиск НПС около ГГ ivIndex -= 1 prActor = Game.FindRandomActorFromRef(Game.GetPlayer(), 10000.00);- Радиус поиска if (prActor != None) && (prActor != Game.GetPlayer());- Если НПС найден if !aaTest_FormList.HasForm(prActor);- Если НПС нет в форм-листе значит и спелов у него нет (если они даются только из скрипта) aaTest_FormList.AddForm(prActor);- Добавляем НПС в форм-лист prActor.AddSpell(aaTest_Spell, False);- Добавляем спелл EndIf EndIf EndWhile ivIndex = aaTest_FormList.GetSize();- Количество НПС в форм-листе While ivIndex > 0;- Поиск далёких или мёртвых НПС ivIndex -= 1 prActor = aaTest_FormList.GetAt(ivIndex) as Actor;- Текущий НПС из форм-листа if (prActor.GetDistance(Game.GetPlayer()) > 12000) || (prActor.IsDead());- Если НПС далеко или мёртв (радиус поиска) if prActor.HasSpell(aaTest_Spell);- Если у НПС есть спелл prActor.RemoveSpell(aaTest_Spell);- Убираем спелл EndIf aaTest_FormList.RemoveAddedForm(prActor);- Убираем НПС из форм-листа ivIndex = aaTest_FormList.GetSize();- Пересчитываем количество НПС в форм-листе EndIf EndWhile RegisterForSingleUpdate(5) EndEvent
Event OnCellAttach() RegisterForSingleUpdate(0.1);- При смене локации/ячейки скрипт должен срабатывать без задержки EndEvent
Всем привет, у меня 2 вопроса по скрипту, отвечающему за расовую способность Орков - берсерк.
Не силен в заклинаниях и талантах, но в приведенном скрипте нет ничего кроме визуализации. Так что назначение эффектов и способностей происходит где то в другом месте.
Вылетова стало меньше, но все равно часто вылетает. Причем, общи принцип такой: где-то полчаса - час работает стабильно. Потом появляются одиночные вылеты. А потом начинает вылетать примерно раз в 5-10 минут.
Alliria, Это похоже на засорение памяти скайрима. При больших количествах визуальных эффектов может происходить. В этом случае скрипт не причем, вернее как ты его не переделывай все равно будет вылетать. У меня была такая же история когда я делал "Звёзды небесного края". Помогла установка SSME + SMC. Скайрим стал грузиться чуть дольше, но вылеты практически исчезли.
Подскажите как правильно использовать функцию GetRandomPercent? хочу сделать, чтобы при срабатывании рандома, допустим в 20% цели наносился дополнительный урон надо как то использовать if и GetRandomPercent, но как правильно?
if Utility.RandomInt(0, 99) <= 19 ;- Ваши действия endif
Господа и дамы есть такой вопрос, может это делается и не при помощи скриптов но как сделать так что бы напарник компаньон лечил вас когда запас вашего здоровья падает до определенной отметки? буду счастлив любому пояснению а если это сделать можно только при помощи скрипта - добрые скриптеры напишите пожалуйста этот сценарий для меня.
Именно через скрипт. Свойству HealOther в СК не забыть присвоить значение.
Scriptname CompanionHealthSCRIPT extends Actor;- Скрипт на компаньоне
Spell Property HealOther Auto;- Лечение
Event OnInit() RegisterForUpdate(3);- Включаем процедуру обновления 1 раз в 3 секунды EndEvent
Event OnUpdate();- Процедура обновления if Game.GetPlayer().GetAV("Health") < 50;- Если здоровье ГГ < 50 HealOther.Cast(Self, Game.GetPlayer());- Лечим EndIf EndEvent
Изменение репутации для пользователя LordVadim
LordVadimOffline
Сообщение №110
| Тема: Вопросы по скриптам Papyrus
написано: 2 апреля 2014, 07:11
| Отредактировано: LordVadim - 2 апреля 2014, 07:14
есть еще какой нибудь вариант, как нибудь дать моему скрипту поработать, затем уже усыпить его?
Попробуй такой вариант:
Scriptname newscript extends activemagiceffect
Spell property Fireball auto Int ivCounter = 0
Event OnEffectStart(Actor akTarget, Actor akCaster) Fireball.cast(selfRef) ivCounter += 1 if ivCounter > 2;- Скрипт сработает 3 раза потом выключится и перезагрузится ivCounter = 0 GoToState("DoNotWork");- Переводим скрипт в состояние ничего не делать Utility.Wait(2);- Задержка 2 сек. GoToState("");- Возвращаем скрипт в нормальное состояние EndIf EndEvent
State DoNotWork;- Скрипт в состоянии: "Ничего не делать" Event OnEffectStart(Actor akTarget, Actor akCaster) EndEvent EndState
Fireball.cast в скобочках надо указывать от кого идет каст, в нашем случае akCaster мб у меня с игрой что не так? в CK вики пишут что скрипты со спеллами экстендить через Form, я же через activemagiceffect делаю extend. Как сильно это может повлиять?
У Cast() в скобках два параметра: первый - источник заклинания (кто это заклинание произносит), второй - цель (на кого это заклинание направлено). Какой скрипт дополнять activemagiceffect или Form зависит от того, куда ты вешаешь скрипт (на актера, на предмет или на заклинание). Список функций Papyrus
Кажется просек в чем проблема с работой скриптов с 1 раза. Лоад ордер в лаунчере. Щас опять у меня спелл не работал раз 5-6, изменил новый мод, поставив его на 1 строчку - заработало. Все моды же всегда на последнем слоте появляются после создания
Последняя строка в лаунчере - это так сказать наивысший приоритет. Потому, что моды в последней строке перекрывают (при совпадении) данные предыдущих модов. В твоем случае перемещение на 1 сточку, по идее, никак не должно было влиять на работу скрипта.
Так же не надо забывать о свойствах - они не изменятся, если скрипт уже начал свою работу и вы сохранились. Как не меняй значение этого своёства в СК, оно так и останется тем старым, что было при запуске скрипта, эти данные остаются в сохранке.
AleksTirex, а что происходит в игре если скрипт попал в сохранение, а после он был полностью заменен, то есть название тоже, а содержание (процедуры, события, свойства) другое. Можно новый скрипт как то заставить работать или это не реально?
Что-то у меня это не сработало... Буду признателен, если объяснишь, что еще необходимо выполнить. Заранее благодарю!
Проверил скрипт, у меня работает. Но лучше отслеживать не числовое, а процентное состояние здоровья:
Scriptname aaTestCastSCRIPT extends Actor;- Скрипт на компаньоне
Spell Property HealOther Auto;- Лечение
Event OnInit() While !IsDead() if Game.GetPlayer().GetAVPercentage("Health") < 0.5;- Если здоровье ГГ < 50% While Game.GetPlayer().GetAVPercentage("Health") < 1 HealOther.Cast(Self, Game.GetPlayer());- Лечим Utility.Wait(0.5) EndWhile EndIf Utility.Wait(3);- Задержка перед очередной проверкой EndWhile EndEvent
Циклы и постоянное обновление вместе делать нельзя. В данном случае это не критично, но всё же не стоит (народ привыкнет так делать и... результат предсказуем )
А так всегда на собственные грабли... Сейчас подправлю.
Подскажите, повесил на дракона камеру и послал далеко. ГГ остался на месте, в итоге локация не подгружается и с дракона видно только лоды. Есть ли команда которая подгружала бы локацию там где находится камера а не гг?
Попробуй так:
На месте ГГ создаешь Xmarker, чтобы потом его вернуть обратно. ГГ делаешь невидимым: Game.GetPlayer().SetAlpha(0) Отключаешь коллизию: Debug.ToggleCollisions() Цепляешь камеру, отправляешь дракона Регистрируешь OnUpdate() И периодически отправляешь ГГ к Дракону: Game.GetPlayer().TranslateToRef(akDragon, 100000) ... Потом возвращаешь все обратно: Отключаешь OnUpdate(), возвращаешь ГГ к Xmarker, включаешь коллизию и видимость игрока.