Myprism, ну, гладкости функции игрок не оценит, а вот совместимость - да. И для ломаной нет нужды делать несколько неравенств, там должно быть примерно такое:
Код
aiLevels[] ; Массив 1 - уровни из Settings (первый эл. = 0) aiEnergy[] ; Массив 2 - энергия камней (первый эл. = 0) iActor ; Уровень актера iSoul ; Уровень души 0-4, как определять, уже известно
Int FUNCTION iMin(Int A, Int B = 0) IF A < B RETURN A ENDIF RETURN B ENDFUNCTION
Здесь принимается, что для актеров с уровнем выше iGrandSoulActorLevel, расчет энергии души проводится по прямой, проходящей через отрезок iGreaterSoulActorLevel -- iGrandSoulActorLevel.
Myprism, Поменять ванильную функцию TrapSoul можно только в случае, если отредактировать ее в Actor.psc - в общем, лучше искать другие пути. Смысл оставлять скрипт чистым? Если в целях совместимости, чтобы другой мод мог представить свою версию этого скрипта поверх твоей модно-ванильной функции, то такая система совместно работать явно не будет. Там в любом случае нужно будет редактировать маг. эффекты, добавляя ключ. слова, меняя условия, флаги и прочее. Исправляя баги (посох Холдира и проч.). Наверное.
Другой скрипт вызвать можно, ничего не указывая в Property:
Код
MyScriptName MyScriptObject = (Game.GetFormFromFile(0x001234, "MyESPModName.esp") AS SomeEditorType) AS MyScriptName MyScriptObject.DoSomething() MyScriptObject.MyInt += 1 ((Game.GetFormFromFile(0x001234, "MyESPModName.esp") AS SomeEditorType) AS MyScriptName).DoSomething()
; MyScriptName - имя вызываемого скрипта ; MyScriptObject - произвольное имя для этой временной переменной ; 0x001234 - первые 2 цифры всегда 0 ; MyESPModName.esp - имя и расширение мода, содержащего форму со скриптом ; SomeEditorType - приведение формы к конкретному типу (Actor, MiscObject и т.д.). Всегда должно совпадать с типом, который расширяет данный скрипт. Приведение может происходить в несколько этапов. ; DoSomething() - эта функция содержится в MyScriptName ; MyInt - эта Property-переменная содержится в MyScriptName (но не внутренняя перем.)
(((Game.GetFormFromFile(0x005678, "SoulTrap.esp") AS Quest).GetAlias(0)) AS ReferenceAlias).GetReference() AS Actor) AS _MGTrackSCPTNPCB ; Напр., получаем скрипт на базовом актере, находящемся в алиасе №0 такого-то квеста ; Если алиас не заполнен, или заполнен не актером, или базовый актер не имеет _MGTrackSCPTNPCB, то все выражение == none.
myav, можно попробовать закинуть актера в алиас высокоприоритетного квеста, имеющий пакет с CombatStyle, в котором все атаки сведены к 0, а защита к 1. Чтобы пакет подействовал немедленно, EvaluatePackage(). Правда, неясно, как это будет выгдядеть в динамике боя.
Насчет невозможности отхода назад - в пакете следования указывается мин. и макс. дистанция, так что если актеру определить пакет с высоким параметром минимума, он должен отойти для его соблюдения (в теории).
Неплохо бы понимать, что это делает. А делает оно следующее: выбирает из списка всех возможных для этого актера AI-пакетов (Packages) один подходящий по условиям (первый сверху по списку либо в листе актера, либо в одном из алиасов, заполненных этим актером; алиасы сортируются по приоритету квестов) и применяет его немедленно. В твоем коде он явно не нужен.
Код
ты не сможешь поменять стиль во время боя
Вообще-то можешь, согласно проверке, делая в точности то, что и написано выше. 1) Создать новый квест c флагами Start Game Enabled, Run Once (хз, может, и без них будет работать) 2) Создать пустой алиас Specifiс Ref c флагом Optional. 3) Создать новый стиль боя (General - первые 4 ползунка на 0, за исключением Defensive = 1) (Melee - все на 0) 4) Создать пустой пакет (Type = Package, Template = none, Public Package Data - все удалить) (Combat Style = п. 3) 5) Пакет внести в алиас п. 2. 6) Код активации:
Думаю, можно обойтись и SetCombatStyle(), просто проверял по старинке. Маги все равно атакуют, но вроде бы реже. Драугры с 2H не блокируют от слова совсем. Как вернуть прежний стиль, расписывать не буду.
Именно ТАК я тестирую, все варианты блока. Не на персонаже у которого атака ниже за блок по умолчанию, а на персонаже у которого атака в 3 раза выше. И вплотную.
Попробуй взять в правую руку оружие, бессердечный AI безоружных атакует по возможности.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №908
| Тема: Вопросы по скриптам Papyrus
написано: 23 февраля 2020, 18:27
| Отредактировано: Multigone - 23 февраля 2020, 18:32
myav, это не мой способ, это лишь одна из возможностей реализовать твою идею, в котором я вынужден разбираться, чтобы другие люди, читающие форум, получили более точные знания.
Цитата myav
не только кинжалы, но и мечи
1) Люди с кинжалом в правой и кулаком в левой, не блокируют, потому что, вероятно, это не предусмотрено писарями AI. 2) Люди с любым 1H в правой (кроме кинжалов) и кулаком в левой, блокируют, потому что могут. 3) Люди с любым 1H, включая кинжалы, блокируют, если в левой есть щит. 4) Люди с любым 2Н блокируют. 5) Драугры с 2Н не блокируют, потому что я не знаю. 6) Драугры со щитом блокируют, как обычно. 7) Не важно, какой Combat Style был у актеров до его смены.
Единственное, актер не всегда с первого раза понимает команду Evaluate(), поэтому ее лучше повторить несколько раз. Или, может быть, времени между помещением в алиас и командой должно пройти больше.
Честно говоря, немного удивляет, как ты проводишь тестирования. Вместо того, чтобы задаться вопросом, почему у кого-то это работает, вместо того, чтобы попытаться воспроизвести показанное при таких же условиях и подумать, что влияет на разницу результатов... В конечном счете, кому из нас это нужно больше?
Arclis, скрипт на референсе активатора LA_RK_ForSaleActivator (найти в активаторах -> ПКМ на нем -> Use Info -> выбрать Tamriel Wilderness 6 -10 -> в окне объектов набрать LA_RK_ForSaleActivator -> ПКМ, Edit -> вкладка Scripts -> ПКМ на (la_forsale) -> Edit Properties -> Cost).
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №911
| Тема: Вопросы по скриптам Papyrus
написано: 5 апреля 2020, 10:03
| Отредактировано: Multigone - 5 апреля 2020, 10:10
UnlimitedCloud, руны размещаются через Projectile, указанное в MGEF. Projectile ведет к Explosion, где есть поле Damage. Весь урон через него наносится напрямую. Для рун там указано значение 2. Может, это?
Myprism, значит, там есть Property-переменные String, которые не только выводятся в Debug.Notification(), MCM ShowMessage(), MCM SetInfoText(), MCM-название-опций или что-то подобное, но и участвуют в проверках или каких-то операциях. Например, такое в качестве иллюстрации и грубого примера:
Код
String Property MyArmorPart = "Cuirass" Auto
EVENT OnPageReset(String sP) AddHeaderOption(MyArmorPart) ; Добавить заголовок МСМ - нужен перевод "Cuirass" как "Нагрудник" ENDEVENT
FUNCTION MyFun(String sPart) IF sPart == "Cuirass" ; Это не будет работать, если где-то вызывается MyFun(MyArmorPart) и при этом "Cuirass" переведено как "Нагрудник"
Не знаю, в чем там дело в действительности, и для чего может понадобиться такая конструкция, но, надеюсь, сама идея понятна.
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №914
| Тема: Вопросы по скриптам Papyrus
написано: 17 апреля 2020, 13:04
| Отредактировано: Multigone - 17 апреля 2020, 13:59
Dsion, я не советовал делать так). Просто представил ситуацию, когда перевод сломает работоспособность скрипта (как и описывал Myprism.)
Цитата Dsion
Но прописывать значение проперти в коде скрипта - все-равно не вариант.
Ну, поскольку переменная всегда имеет дефолтное значение, и англоязычному создателю нужно, чтобы оно было конкретным, думаю, все же удобнее прописать его в самом скрипте, а не в СК Property.
Приведение FormList, Form[], Armor[] к(as) Outfit не работает, сообщается о несовместимости типов.
А что бы это дало?
Код
Outfit Property MyOTFT Auto FormList Property MyFLST Auto
FUNCTION MyFun() MyOTFT = MyFLST AS Outfit ; Даже если бы это работало, это было бы простое присвоение переменной MyOTFT, ранее заполненной / / твоим комплектом, нового значения в виде MyFLST AS Outfit. Над базовой формой твоего комплекта при этом не совешится / / никаких действий, для этого нужна к.-л. функция (типа MyOTFT.SetSomePart(n)).
Единственное, что приходит на ум, это управление вещами комплекта через LVLI с помощью глобальных, но для этого LVLI уже должен быть там и заменять собой все или некоторые вещи.
emelya8307, если ты разбирал квест с джазби, то, наверное, видел, что там используется UpdateCurrentInstanceGlobal() для обновления кэшированного значения глобальной (квест не читает значение напрямую?).
Myprism, можно оперировать Property переменными из др. скриптов, не используя напрямую ту форму, к которой прицеплен этот скрипт (т.е. не определяется через Use Info). Что-нибудь такое:
Код
Event OnTriggerEnter(ObjectReference akActionRef) IF akActionRef AS Actor MyActorScriptName xRandomName = (akActionRef AS Actor) AS MyActorScriptName IF xRandomName Int iRandomName = xRandomName.lastLeftCharge ... EndEvent
Vittru1986, разве файлы озвучки не поддаются редактированию в каком-нибудь Sony Sound Forge?
UPD: Только после конвертации в читабельный формат с помощью Skyrim Audio Converter (у меня прога глючит при попытке включить Lip-файл при распаковке .fuz).
Vittru1986, редактировать записи .esp можно в TESVEdit. Если не ясно, что именно создает проблему, нужно сделать бэкап .esp, ограничить круг подозреваемых потенциально опасных форм, удалить их, проверить. Если заработало, откатить .esp до бэкапа, удалить половину из них, проверить. И т.д.
xCYNICx, все функции есть в исходниках (Data/Scripts/Source). Смотри, что расширяет скрипт, который ты пишешь (Например, заголовок "Script MyScript Extends Actor"), ищи в исходниках .psc с таким именем (Actor.psc), в нем будут все допустимые функции для этого типа форм с комментами. Больше инфо о любой функции можно получить здесь, набрав в поиске ее название. Также смотри, что расширяет Actor.psc (ObjectReference), ищи ObjectReference.psc и смотри все функции, многие из них могут применяться в том числе к Actor. И так далее. Большинство скрипт-объектов имеют иерархию.
В твоем случае нужно определить, что именно влияет на исправление - экипирование, проигрывание IdleStop_Loose или мб что-то другое. Ре-экипировать оружие можно так:
Если есть SKSE:
Код
Form ActorObject = akTarget.GetEquippedObject(0) IF ActorObject akTarget.UnequipItem(ActorObject) Utility.Wait(0.01) akTarget.EquipItem(ActorObject) ELSE ActorObject = akTarget.GetEquippedObject(1) IF ActorObject akTarget.UnequipItem(ActorObject) Utility.Wait(0.01) akTarget.EquipItem(ActorObject) ELSE Debug.Notification("У актера нет ничего.") ENDIF ENDIF
Myprism, Wait() может использоваться для ожидания закрытия игроком любых меню - например, событие возникает в момент ковыряния игроком шмоток в инвентаре - часть кода события, нижеследующая за ожиданием, выполнится только после того, как игрок выйдет оттуда.
Конкретно в случае комбо (Ожидание + Регистрация), если оно находится в потенциально часто повторяющемся событии (например, OnHit()), это уменьшает минимальное время между повторными апдейтами. Как мы знаем, повторная регистрация апдейта, если была вызвана до того, как событие апдейта произошло, заменяет собой предыдущую. А вовсе не генерирует второе событие апдейта, независимое от первого. Поэтому, минимальный интервал времени между повторными апдейтами, вызываемыми из одного и того же события, равен времени в регистрации:
EVENT OnUpdate() ; OnUpdate будет срабатывать с макс. частотой = один раз в 0.6с. ENDEVENT
Я точно помню, что сам пользовался такой конструкцией. Но это может понадобиться только в очень специфических случаях. Вот тут наглядно (плиз, только не говори, что ничего не понял xD).
Изменение репутации для пользователя Multigone
MultigoneOffline
Сообщение №925
| Тема: Вопросы по скриптам Papyrus
написано: 3 июня 2020, 11:41
| Отредактировано: Multigone - 3 июня 2020, 12:07
Myprism, проще говоря, счетчики Wait() и RegisterForUpdate() останавливаются, пока игра находится на паузе. Например, если играть с модом, убирающим паузу, то и Wait() будет истекать, несмотря на открытые меню (уверен на 99%).
Как я понял, у тебя такая схема:
Код
EVENT Event1() или Event2() или Event3() RegisterForSingleUpdate(0.5) ENDEVENT
EVENT OnUpdate() FixGear() ENDEVENT
Тут нет ничего криминального, и гарантированно не будет одновременных срабатываний OnUpdate(). Может, дело в FixGear(). Сходу сложно сказать.
Хотя... Если, к примеру, задержку поставить очень маленькую (0.05), а код внутри FixGear() требует для своего полного выполнения время > 0.05с (в силу объемности или чего-то еще, например, тех же внутренних задержек Wait()), то, когда следующее OnUpdate() стартует раньше, чем завершится предыдущее, возможно пересечение строк, приводящее к (не)предсказуемым результатам. Чтобы избежать такого, нужно делать защиту (Bool-замок или перевод скрипта в другое State). На самом деле, это очень частое явление, и его всегда надо держать на прицеле.
1) Перки добавляются базовым актерам на этапе редактирования в СК. Непосредственно в игре скриптом их можно добавлять / убирать только игроку. Чтобы добавить в СК, нужно просто перетащить мышью в окно Perks вкладки SpellList базового актера. Как устроены перки, можно почитать здесь, и посмотреть на примере ванильных. По поводу сложности. Во-первых, влияющие на здоровье (силу? магию?) эффекты от заклинаний, зелий и прочего, модифицированные перком, и так меняются в зависимости от сложности игры. Во-вторых, поскольку она задается в SkyrimPrefs (iDifficility), ее нельзя напрямую проверить через Conditions, т.к. отсутствует необходимая для этого функция (или это просто я не нашел). Думаю, тут надо делать скрипт - переводить значение из .ini в глобальную переменную, в перке проверять ее значение функцией GetGlobalValue. Скрипт будет выглядеть примерно так (требуется SKSE):
Код
Scriptname MyScript Extends ReferenceAlias ; на алиас игрока.
2) Вся "работа" со SKSE (7z archive) для модмейкера заключается в грамотном использовании новых функций. Частично их описания можно найти в исходниках (Data/Scripts/Source) под комментариями "; SKSE additions built". Кое-что - на вики (creationkit.com). Чтобы компилировать скрипты с использованием SKSE-функций, исходники из архива SKSE должны быть в (Data/Scripts/Source). Т.е. закинуть всю папку Data архива, заменить файлы.
3) Если под SkyUI подразумевается MCM, то вот тут подробно, тут перевод (автор IgorLutiy).
Иsкатель, сперва попробуй запустить Quest2 консолью с помощью StartQuest. Если не запускается, проверь, что все пустые алиасы имеют флаг "Optional". Если запускается, проверь, чем заполнено Property Quest2 (должно быть твоим квестом). В целом, неважно, откуда исходит команда на запуск - из скрипта другого квеста, маг. эффекта, актера и т.д. Если квест может запуститься, он сделает это.
Иsкатель, так вроде Start Game Enabled автоматически запускает квест в момент начала новой игры. Может, он запускается, но не отображается в журнале? Проверить это можно скриптом:
Код
IF Quest2.IsRunning() Debug.MessageBox("Запущен") ELSEIF Quest2.IsCompleted() Debug.MessageBox("Завершен") ELSE Debug.MessageBox("Не запущен") ENDIF
yakor77, если хочешь сделать это, найди переменную Settings или GlobalVariable, отвечающую либо за фактический уровень игрока (пока игрок не повысит уровень через меню, он считается такого, какой был зафиксирован после последнего повышения); либо за накопленный не распределенный бонус уровней. В первом случае эта переменная всегда будет равна текущему уровню игрока, пока ему нечего повышать, или большей величины, если есть что. Во втором случае эта переменная всегда будет равна 0, пока ему нечего повышать, или >0, если есть что. Дерзай!
PS: Settings "iCalcLevelAdjustUp" и "iCalcLevelAdjustDown" не подходят, проверено. PPS: В Actor Value подходящей переменной не найдено. PPPS: Это может быть также, к примеру, счетчик нераспределенного опыта. Или оба сразу. PPPPS: Пойду задам вопрос на СК.сом.