Автор расскажет о специальных функциях NX из форка NVSE, добавляющих уникальные возможности для моддинга Fallout New Vegas.
Необходимые навыки: референсы и базовые формы, переменные скриптов (плавающие, целы, референсы), get\set
Навыки для продвинутых пользователей: строки, строковые переменные, переменные массивов, ссылающиеся на квестовые переменные в диалоге, другие условия
Что ж… Если немного побродить вокруг скриптинга, вылезет слово ‘nx’. Это экстра-функции из NVSE Extender от prideslayer. Самые популярные из них – переменные NX.
Переменная NX функций…
- позволяет хранить игровую информацию в референсе
- как переменная EVFI хранит плавающие и целые числа, как EVFo хранит формы, референсы и базовые формы, динамические референсы с помощью NX_Get или NX_Set
- без необходимости обьявлять её в скрипте: как только на ней применили set, она существует в референсе:
someRef.NX_SetEVFl “thenameyougiveit” someNumericValue/someFloat/someInteger
someRef.NX_SetEVFo “thenameyougiveit” someForm/someRef
“the name you give it” = ключ
И будучи функцией референсов (reference functions), NX_Set/GetEVF* функции становястя применимыми в синтаксисе референсов
Короче, если нужно отслеживать сколько напитков выпил непись, нужно и создать переменную ‘DrinksDrunk’ и изменять её значение, привязав его к референсу:
BuddyRef.NX_SetEVFl "DM:DrinksDrunk" 1
И то же для его любимого яда\алкоголя:
BuddyRef.NX_SetEVFo "DM:FavoriteDrink" Scotch
BuddyRef.NX_SetEVFo "DM:BestestFriendInTheWholeWorld" Buddy2Ref
- отслеживая всё это, переменная референса останется в сохранении, но только на том же референсе. Больше ей ничего не нужно, так что можно спокойно удалять мод, и она останется.
- и если любой мог захочет получить доступ к информации из переменной, он сможет получить её из референса, как только будет знать ключи доступа:
set somefloat/integer to someRef.NX_GetEVFl “whateverkeyithas”
set somescriptRef to someRef.NX_GetEVFo “whateverkeyithas”
Например:
int iDrinkCount
ref favDrink
set iDrinkCount to BuddyRef.NX_GetEVFl "DM:DrinksDrunk"
set favDrink to BuddyRef.NX_GetEVFo "DM:FavoriteDrink"
if BuddyRef.GetItemCount favDrink > 0 ; у нас есть напиток
BuddyRef.CIOS favDrink ; пьет его
BuddyRef.removeitem favDrink 1 ; теперьнаединичкуменьше
set iDrinkCount to iDrinkCount + 1
BuddyRef.NX_SetEVFl "DM:DrinksDrunk" iDrinkCount ; продолжаем отслеживать
endif
if 10 < BuddyRef.NX_GetEVFl "DM:DrinksDrunk" ; возможно, перестарались
BuddyRef.CIOS ReallyStinkingDrunkSpell
endif
Другой мод, который хочет прочитать эту информацию, не нуждается в вашем мастере, чтобы сделать это.
И вы можете выполнять все эти отслеживания на стольких NPC, на скольких захотите.
ref BuddyRef
set BuddyRef to whoever
- можно иметь столько переменных NX на любом референсе, сколько захотите
- а если они не нужны, то избавляемся от них так:
someRef.NX_ClrEFVl “key”
someRef.NX_ClrEVFo “key”
а если нужно избавиться от кучи таких переменных, то вот так:
someRef.NX_ClrEVFl “partthatallkeysshare” 2
someRef.NX_ClrEVFo “partthatallkeysshare” 2
все наши ключи в моде на напитки начинаются с DM, так что уничтожение всей информации на референсе BuddyRef будет выглядеть вот так:
BuddyRef.NX_ClrEVFl "DM:" 2
BuddyRef.NX_ClrEVFo "DM:" 2
Очистим состояние и дух!
Это означает, что вы можете иметь целую кучу пользовательских переменных, привязанных к любому актору или предмету, какой захотите. Не требуется никаких эффектов, никаких токенов, никаких квестовых скриптов чтобы все это хранить, что уменьшает конфликты модов и позволяет модам общаться друг с другом вне зависимости от мастера и порядка загрузки. Если вы хотите сохранить какую-либо информацию об акторе, например, его любимую пиццерию, вы просто прикрепляете ее к этому актору, у которого потом вы и найдете ее, когда она вам понадобится.
Хорошей практикой будет:
Никогда не знаешь, будет ли повторено название твоего ключа для переменной nx, но для других целей. Поэтому в большинстве случаев, просто добавим немного акронимов своего мода в начале строки: «MyCleverModAcronym:restofthekey» и т. д.
Еще один полезный совет:
Поскольку это реально крутой инструмент взаимодействия между модами, лучше всего четко указать какие переменные NX вы используете, особенно если вы используете их в огромных количествах. Сохраните их в dummy esp или перечислите их в фиктивном скрипте, добавьте текстовый файл к архиву с модом, что угодно.
Обновление:
С выходом NX12 появляется возможность хранить и извлекать строки как переменную EVST: NX_SetEVST, NX_GetEVST и NX_ClrEVST. Вы можете делать это как с реальными строками, так и с переменными строк.
Продолжая пример с напитками:
string_var sv_quote
...
BuddyRef.NX_SetEVST "DM:BoozeQuote" "Champagne for my real friends - real pain for my sham friends, ha ha!"
BuddyRef.NX_SetEVST "DM:DrunkType" "Aggressive"
...
if BuddyRef.GetItemCount favDrink > 0 ; we have booze
BuddyRef.CIOS favDrink ; drinking it
let sv_quote := BuddyRef.NX_GetEVST "DM:BoozeQuote"
MessageEX "%z" sv_quote ; will pop up a message with the quote in it
...
endif
if 10 < BuddyRef.NX_GetEVFl "DM:DrinksDrunk"
..
if eval BuddyRef.NX_GetEVST "DM:DrunkType" == "Aggressive"
BuddyRef.startcombat playerref
endif
endif
В NVSE4+ есть целый ряд функций строковых переменных, которые позволяют вам сохранять, изменять и извлекать строки на лету. В сочетании с функцией ToString (сокращенно: $), которая позволяет вам передавать строковые переменные в функции, которые в противном случае ожидали бы фактическую строку, это означает, что вы можете динамически создавать ключи nx, а в случае EVST — и значения. Это означает, что вы можете сделать что-то вроде:
string_var sv_fightoutcome
string_var sv_nxkey
int iFightNum
int iIsFighting
float fTimer
if BuddyRef.GetCombatTarget == playerref
set iFightNum to iFightNum + 1 ;(or: let iFightNum += 1)
set iIsFighting to 1
endif
if eval iIsFighting && (ftimer += GetSecondsPassed) > 30
BuddyRef.StopCombat
endif
if iIsFighting && 0 == BuddyRef.IsInCombat
set iIsFighting to 0
if playerref.GetAV Health > BuddyRef.GetAV Health
let sv_fightoutcome := "Lost"
else
let sv_fightoutcome := "Won"
endif
let sv_nxkey := "DM:Fight:" + $iFightNum + ":Score" ; creates a string that'll be like "DM:Fight:1:Score", "DM:Fight:2:Score" etc)
BuddyRef.NX_SetEVST $sv_nxkey $sv_fightoutcome
endif
Также в NX12 появились новые функции, которые возвращают информацию nx об актере в строковой карте, с ключами nx в ключах строковых карт и значениями в значениях строковых карт: NX_GetEVFlAr, NX_GetEVFoAr и NX_GetEVStAr.
Допустим, у нас есть потасовки в барах, в которых buddyref то выиграл, то проиграл, а чтобы вренуть эту инфу мы напишем следующее:
array_var ar_results
let ar_results := BuddyRef.NX_GetEVStAr "DM:Fight"
ar_dump ar_results
и ar_dump инфа будет выглядет так:
[DM:Fight:1:Score] : Won
[DM:Fight:2:Score] : Lost
Нужно немного рабираться в массивах и циклах foreach чтобы работать с этой информацией. Позже я напишу гайд об этом.
Обновление 2:
Об этом много говорили, и вот оно здесь: EVFL переменные nx теперь можно просматривать в условиях диалога/квеста/анимации. (Только EVFL, потому что такие условия имеют только числа для значений.)
Сначала вставляете строковую переменную в квестовый скрипт и устанавливаете ее на ключ nx, который вы хотите, чтобы она представляла. В соответствии с предыдущими примерами я выбрал "DM:DrinksDrunk":

Прикрепите скрипт к квесту, очевидно. Обратите внимание, что квест не обязательно должен быть включен, чтобы просто хранить переменную, но в этом случае я устанавливаю переменную в том же скрипте, поэтому я включаю ее, чтобы всё работало. (Я мог бы добавить let DSTestQst.sv_drinksdrunk := "DM:DrinksDrunk" в какой-нибудь другой скрипт и сделать то же самое.)

Поскольку у нас уже есть квест, давайте продолжим его тестирование с условиями диалога. Как вы видите, я создал тему и строку, которую я хочу сделать зависящей от EVFL, имеющего значение 1.
Я добавляю условие и выбираю NX_GetQVEVFL для функции условия. Появляется окно, очень похожее на то, которое вы увидите, если проверите обычную переменную квеста.

Выберите квест, в котором есть скрипт квеста со строковой переменной в нем в выпадающем меню. Чтобы выбрать переменную, вам нужно ввести ее индекс. Если это первая переменная в скрипте, она будет 1. Если вы не уверены, какой индекс имеет ваша строковая переменная, вы можете посмотреть его в FNVEdit:

И как вы можете видеть на следующих скринах, вы можете легко изменить переменную nx для актера в результирующем скрипте, и следующая строка обнаружит изменение.
Обратите внимание — и это справедливо для всех переменных квеста — что вам не следует переставлять переменные квеста после того, как вы уже сделали сохранения с активным квестом; вы можете добавлять новые в конец списка переменных скрипта, но не перемешивать их. (Ну, вы можете, если вас не волнует получение отчетов об ошибках.)
Спасибо jaam за создание этой штуки, за EVST и переменные массивов и обьяснение всего этого.
Комментарии