Это третий из серии гайдов по нововведениям NVSE4, освежившими моддинг сцену Нью Вегаса: UDFы, строковые переменные и массивы. Моддеры Обливиона, незнакомые с ОБСЕ 16+ тоже получат пользу от этих статей.
В данной части речь пойдет о Строках (Strings) и Строковых Переменных (String Variables).
1. Введение. Теория строк
Строки – определенные комбинации символов, то есть буквы, цифры и знаки пунткуации. Ничего нового. Всё в игровом интефрейсе, что является словом или предложением, а не числом, является строкой: названия кнопок в меню, слово «Открыть» и «Войти» при наведении на дверь или контейнер, заметка «Вы больше не хотите есть», «имя» клавиши, которую нужно нажать, и так далее. Всё это хранится как строки под вывеской «Игровые Настройки» (Game Settings). Различные языковые версии игры хранят различные значения этих строк.
Из туториала по синтаксису вы помните, что в строчке playerref.SetAV Health, та самая Health это просто напросто строка, которая может быть заменена целым числом (numeric int), ссылающимся на то же значение актора — использование строки «Health» просто избавляет вас от необходимости искать это целое число.
Мы же говорим о форматированных строках, однако, не относящихся к игровым настройкам или значениям актора. Если вы пользовались командами DebugPrint, Printc или MessageEX (а если вы это читаете, то значит вы их знаете, поскольку их использование – стандартная практика даже для новичков), то вы использовали форматированне строки для того, чтобы игра отобразила вам информацию, которую вы хотите:
DebugPrint "I'm a string"
Printc "I'm a string"
MessageEX "I'm a string"
То, что взято в кавычки, это форматированная строка, поскольку использованы двойные кавычки чтобы сказать компилятору скрипта, что это форматированная строка. Без этого вылезет ошибка: I’m – это не аргумент для функции. (тк эти кавычки создают строки, я буду использовать одинарные кавычки для закавычивания текста в туториале, чтобы избежать путаницы. С этого момента «строка» и «форматированная строка» - одно и то же).
С точки зрения скриптинга проблема со строками в том, что оригинал не дает нам достаточно команд для работы с ними. Это особенно актуально для игровых настроек и их строк и строк значений актора. Форматированные строки, по крайней мере, имеют то преимущество, что оригинал позволяет нам использовать для них несколько спецификаторов формата (format specifiers), чтобы передавать значение переменной float в саму строку:
Если fSomeFloat равен 3.4, то:
DebugPrint "The number is %.0f" fSomeFloat --> will display 'The number is 3'
DebugPrint "the number is %g" fSomeFloat --> will display 'The number is 3'
DebugPrint "The number is %.2f" fSomeFloat --> отобразит 'The number is 3.40'
DebugPrint "The number is %2.2f" fSomeFloat --> отобразит 'The number is 3.40'
И NVSE кое-что добавляет к этому.
Если rRef равен DocMitchellRef:
DebugPrint "Имя обьекта: %n" rRef --> отобразит Имя обьекта: Doc Mitchell'
DebugPrint "FormID этого референса - %i" rRef --> отобразит FormID этого референса - 00104C0C'
DebugPrint "%ps чешет %pp бороду" rRef rRef --> отобразит ‘Он (He’s) чешет свою (his) бороду.'
MessageEX "Нажмите %k чтобы почесать свою" iInt
--> отобразит “Нажмите M чтобы почесать свою”, если iInt равен 50, поскольку так написано в directxinput scan code для кнопки M
MessageEX "Нажмите sUActnActivate для активации"
--> отобразит " Нажмите E для активации " если вы установили эту кнопку для активации, поскольку sUActnActivate отображает клавишу, указанную для активации, см control codes
Ну хорошо, но мы все еще не умеем хранить эти строки и не может их менять по скрипту, лишь только заново переписывать. Вот здесь-то нам пригодятся переменные типа string.
2. Основы Строковых Переменных: Обьявление и Инициализация
Прямо как переменные ref отсылают к форме или референсу, а переменные float отсылают к числу с плавающей точкей, строковые переменные отсылают к строке. «Очевидно!», скажете вы, но нужно помнить, что сами по себе эти переменные строками не являются, поэтому я на это и указываю и под «строкой» имею в виду «строковую переменную» (string var). Строки у нас уже были, а вот строковые переменные и манипуляции с ними – вещь новая. Собственно строки, на которые ссылаются строковые переменные, и содержатся в файле .nvse, соответствующем вашему сохранению.
Обьявляются строковые переменные следующим образом:
string_var somestringvariablename
(заметка о конвенциональном наименовании: большинство скриптеров добавляют префикс к переменным, например, float, значит fSomeFloat, ref, значит rSomeForm, чтобы не забыть к какому типу эти переменные отсылают. Некоторые скриптеры делают это и со строковыми переменными и используют s в начале (sSomeStringVar), но я лично против, поскольку в игре сотни таких же строковых игровых настроек с тем же префиксом s, что ведет к конфликтам. Лично я использую префикс sv_ или вообще не пишу ничего. Конечно, и в такой ситуации может быть конфликт с другими строковыми переменными с таким же префиксом, но их немного. В любом случае выбор за вами, просто будьте внимательны).
Обьявление строковой переменной не означает, что она содержит уже строку, что логично и для других переменных в скрипте. Если вы сами не присвоили ей значение, то она ни на что и не ссылается, и если команда вызвана без обьекта, то игра баганет или вылетет.
Присвоение строки строковой переменной именуется «инициализацией» и сделать её можно:
- используя let, присвоить форматированную строку
- используя let, присвоить другую строковую переменную
- используя let, присвоить функцию, которая может возвращать строку (включая UDF, которые возвращают строку или строковую переменную с помощью SetFunctionValue).
let sv_mystringvar1 := "Я – это строка" ; сравни с: let rRefVar := DocMitchellRef
let sv_mystringvar2 := sv_mystringvar1 ; сравни с: let rRefVar2 := rRefVar1
let sv_mystringvar3 := player.GetName ; сравни с: let rRefVar := GetActionRef
Можно использовать и форматирующие спецификаторы при инициализации, хотя это заставляет вернуться к устаревшему пути инициализации строк, используя sv_construct:
let sv_mystringvar := sv_construct "I'm string number %.0f" someInt
let rForm := Pencil01
let sv_mystringvar := sv_construct "Got a %n?" rForm
(Заметьте, что присваивание цифр и имен предметов строкам легче делать с помощью комнады ToString, смотри соответствующую главу туториала)
Если строковая переменная не инициализированна, она возвращает числовое значение 0. Это единственный раз, когда строковые и числовые переменные смешиваются: никогда не присваивайте строковым числовое значение, никогда не присваивайте float переменным строку или строковую переменную. Чтобы проверить прошла ли инициализиация строковой переменной, перед использованием этой переменной сделайте так:
if sv_mystringvar
; do stuff with your initialized string var
else
; you haven't initialized
endif
if eval !(sv_mystringvar) ; ! means LogicalNot
; you haven't initialized
endif
Конечно, если вы в курсе, что она проинициализированна, смысла в этом коде нет.
3. Синтаксис: Let Vs Set
Строковые переменные введены в OBSE прямо перед Let и if eval, так что имейте в виду, что старая документация обсе ссылается на до-letовую эпоху. Прежде чем просто написать ‘let sv_mystringvar := "I'm a string”’ приходилось писать ‘set sv_mystringvar to sv_construct "I'm a string"'. С командой let функция sv_construct полностью лишился смысла, поэтому я больше не буду упоминать эквиваленты команд с set, если в этом нет необходимости. Реально, используйте let.
Я ссылался на set, потому что присваивание строковой переменной к другой через set приводит к тому, что они ссылаются на ту же самую строку, и изменение одной переменной ведет к изменению другой:
Скрипт
выкладка из скрипта:
string_var sv_string1
string_var sv_string2
set sv_string1 to sv_construct "I'm string 1"
printc "string1 says '%z'" sv_string1 --> string1 says 'I'm string 1'
set sv_string2 to sv_string1
printc "string2 says '%z'" sv_string2 --> string2 says 'I'm string 1'
set sv_string1 to sv_construct "I'm a different string now"
printc "string1 says '%z'" sv_string1 --> string1 says 'I'm a different string now'
printc "string2 says '%z'" sv_string2 --> string2 says 'I'm a different string now'
set sv_string2 to sv_construct "In that case, I'm changing too"
printc "string1 says '%z'" sv_string1 --> string1 says 'In that case, I'm changing too'
printc "string2 says '%z'" sv_string2 --> string2 says 'In that case, I'm changing too'
чтобы такого не было, нужно создать sv_string2, которая будет ссылаться на копию строки sv_string1, а не на ту же самую строку:
set sv_string2 to sv_construct "%z" sv_string1
и это был единственную путь «чисто» скопировать содержание строковой переменной в другую.
Когда мы присваиваем одну строковую другой через let, оно сразу сошлется на копию первой, и если поменять что-то в одной, другая останется той же.
string_var sv_string1
string_var sv_string2
let sv_string1 := "I'm string 1"
printc "string1 says '%z'" sv_string1 --> string1 says 'I'm string 1'
let sv_string2 := sv_string1
printc "string2 says '%z'" sv_string2 --> string2 says 'I'm string 1'
let sv_string1 := "I'm a different string now"
printc "string1 says '%z'" sv_string1 --> string1 says 'I'm a different string now'
printc "string2 says '%z'" sv_string2 --> string2 says 'I'm string 1'
let sv_string2 := "In that case, I'm changing too"
printc "string1 says '%z'" sv_string1 --> string1 says 'I'm a different string now'
printc "string2 says '%z'" sv_string2 --> string2 says 'In that case, I'm changing too'
Я вижу так, что путь set заставляет не только больше писать, но и создает больше опасностей, к примеру тот с потереей данных строки. Ну и давайте прямо скажу: зачем две переменных на одну и ту же вещь? Вы хотите скопировать значение первой, чтобы затем поменять её, а не для того чтобы дублировать в двух переменных то же самое значение. То же характерно и для присваивания через set\let строковым переменным значений, возвращаемых через GetName, увеличивая тем самым шансы для косяков с этим set.
4. Уничтожение Строковых Переменных
С оригинальными переменными скриптов (), не надо волноваться с тем, что будет после того, как вы их использовали. Если они храились в квестовом скрипте, вы храните их вечно, пока не удалите мод. Если же они были частью заклинания или обьекта, который больше не действует, то они просто исчезают из поля зрения: их не нужно уничтожать.
Но для строковых переменных всё иначе. Они хранятся во .nvse файле даже после того, как скрипт перестал работать. Они насильственно удаляются при удалении мода, но до этого они приводят к разбуханию сохранения (cause a bit of bloat), так что нужно четко следить за их удалением\де-инициализацией\уничтоежением как можно скорее, когда они перестают быть нужными.
sv_destruct MyStringVar
Можно разрушить до 10 различных строковых переменных подобным образом:
sv_destruct stringvar1 stringvar2 stringvar3 stringvar4 stringvar5 stringvar6 stringvar7 stringvar8 stringvar9 stringvar10
Как вы помните из туториала по UDF, строковые переменные – единственные локальные переменные UDF, которые нужно удалять самому.
5. Проверка Строковых Переменных
Синтаксис с if eval, позволяющий проверять равна ли строковая переменная другой, и то же со строкой, выглядит вот так:
if eval sv_stringvar == "some string"
if eval sv_stringvar1 == sv_stringvar2
и можно использовать != для проверки не-равенства.
Но до этого следует проверить возвращаются ли целочисленные значения командой sv_compare чтобы сравнить строковую переменную и строку:
if 0 == sv_compare "some string" FormatSpecVars sv_stringvar bCaseSensitiveComparebool
; they are the same
elseif 1 == sv_compare "some string" FormatSpecVars sv_stringvar bCaseSensitiveComparebool
; the string var's string occurs before the string, alphabetically speaking
elseif -1 == sv_compare "some string" FormatSpecVars sv_stringvar bCaseSensitiveComparebool
; the string var's string occurs after the string, alphabetically speaking
elseif -2 == sv_compare "some string" FormatSpecVars sv_stringvar bCaseSensitiveComparebool
; none of the above, the compare 'fails'
endif
Нет смысла использовать sv_compare, когда есть альтернатива в лице if eval, только если только вас действительно интересует сравнение по алфавиту.
Эти сравнения не учитываю регистр (case-insensitive), если только не использовать sv_compare.
6. Проброс Строковых Переменных как Параметров: TOSTRING ($)
Если оригинальные или NVSE функции хранят одну и более строк как параметры
DebugPrint "I'm a string"
MessageEX "I'm a string"
SetModelPathEX "Clutter\Junk\WhetStone.NIF"
NX_SetEVFl "some nx key string" someFloat
NX_SetEVSt "some nx key string" "some string value"
Можно заставить их хранить строковые переменные как параметр, используя ToString, или $
DebugPrint $sv_stringvar
MessageEX $sv_stringvar
SetModelPathEX $sv_stringvar
NX_SetEVFl $sv_keystringvar someFloat
NX_SetEVSt $sv_keystringvar $sv_valuestringvar
Есть парочка функций, особенно только для Fallout или тех, что вводят плагины NVSE, подобные MCM, которые не работают с ToString + строковая переменная, поскольку не были созданы для этого. Если это актуально для вашего скрипта, используйте script compiler override, который заставит ваш скрипт работать.
ToString может возвращать в виде строк числа и формы, то есть превращать их в строки:
Вернет имя формы, если оно есть:
let rRef := DocMitchellRef
let sv_name := $rRef
printc "%z" sv_name --> displays 'Doc Mitchell'
Вернет гексовую formID,если имени нет:
let rRef := BlackBoardMarker
let sv_name := $rRef
printc "%z" sv_name --> displays '00002FCC'
Числа:
let iInt := 32
let sv_name := $iInt
printc "%z" sv_name --> displays '32'
7. Контаминация Строковых Переменных, Или: Их Добавление
Легко:
let sv_stringvar := "String1" + "String2"
printc "%z" sv_stringvar --> reads: 'String1String2'
let sv_stringvar := Player.GetName + "'s chair"
rChairRef.SetName $sv_stringvar --> reads 'Prudencia's chair' because that's my test char's name
Отмечу: имена определяются базовой формой, использование set меняет их для базовой формы тоже
Работая со строками, можно наткнуться на некоторые ограничения в превращении переменных в строки с спецификаторами форматирования в контексте добавления к уже существующим строкам:
let sv_stringvar := "First Part:" + playerref.GetName + ":" + "%.0f" iSomeInt
let sv_stringvar := "First Part:" + "%n" rSomeForm
это не сработает и не скомпилируется.
Но у нас есть ToString, в очередной раз помогая:
let sv_stringvar := "First Part:" + playerref.GetName + ":" + $iSomeInt
let sv_stringvar := "First Part:" + $rSomeForm
сработает.
И если на одной строке этого сделать нельзя и нельзя применить ToString, то можно разбить на два или использовать sv_construct:
let sv_stringvar := sv_construct " is scratching %pp balls" rSomeRef ; had to add the sv_construct there to make the %pp ↑specifier work
let sv_stringvar := $rSomeRef + $sv_stringvar
И также можно получить некоторую выгоду от функции sv_Insert:
sv_insert "Some String" FormatSpecifierVars String_VarToInsertTheStringIn PositionToInsertAtInt
let sv_stringvar := " борода чешется яростно"
sv_insert "%pp" rSomeForm sv_stringvar 0
or
sv_insert "%pp" rSomeform sv_stringvar
; мы хотим включить её в самом начале строки строковой переменной, что равно позиции 0 (как и в случае с формлистами и массивами)
; если позиция равна 0, то можно опустить этот параметр
8. Измерение и Поиск Ваших Строковых Переменных
sv_Length возвращает длину строки строковой переменной:
let iSomeInt := sv_length sv_stringvar
Поскольку начальная позиция всегда индексируется как 0, конечная позиция всегда будет (sv_length sv_stringvar) - 1.
sv_Find находит первое вхождение подстроки в строке и возвращает позицию в виде целого числа:
let iSomeInt := sv_Find "substring" FormatSpecifierVars SourceStringVar StartPositionInt SearchLengthFromStartPosInt CaseSensitiveSearchBool
; leave out the parameters if you don't need them
let sv_stringvar := "This is example 3"
let iSomeInt1 := sv_Find "example %.0f" someInt2 sv_stringvar ; --> will return 8 if someInt2 is 3
sv_Count возвращает количество вхождений подстроки, содержащихся в строке:
let sv_stringvar := "Ain't no sunshine when she's gone. And she's always gone too long."
let iSomeInt := sv_Count "gone" sv_stringvar --> returns 2
9. Разбиение Строковых Переменных, Замена Их Частей и Их Пересборка
Самый простой способ извлечения фрагментов из строки строковой переменной — использование sv_Erase:
sv_erase stringvar StartPositionInt NumberofCharacterstoEraseInt
; StartPositionInt: if you leave that out we'll start at position 0
; NumberofCharacterstoEraseInt: if you leave that out we erase everything from the start position to the end
scn CensorshipScpt
let sv_stringvar := "I fucked up."
sv_erase sv_stringvar 2 6 --> 'I up.'
sv_insert "messed" sv_stringvar 2
Или вы можете заменить часть строки другой с помощью sv_Replace:
sv_replace "texttoreplace|texttoreplacewith" FormatSpecVars SourceStringVar StartPositionInt SearchLengthFromStartPosInt CaseSensitiveBool NumberofOccurrencestoReplaceInt
; don't use what you don't need
sv_replace "продолбался|ошибся" sv_stringvar
усложненная версия:
scn Variety
let sv_stringvar := "Этот долбанный долбанавт обдолбанно обдолбался. Долбать!"
sv_replace "долба|dick" sv_stringvar 19 38 1 1
Единственный «долба», который заменится, будет в слове «долбанавт». То же самое будет:
sv_replace "долба|dick" sv_stringvar 19 4
Если элементы строки отделены распространенным символом, как пробел или слеш, sv_Split может разделить их и возвратить их как строковые переменные в массиве:
let sv_stringvar := "This is a sentence."
let somearray := sv_Split sv_stringvar " " ; the 'delimiter', what separates the string, is the 'space' that I stuck in that format string, you can have several characters be delimiters at once
и затем команда ar_dump возвратит:
[ 0.000000 ] : This
[ 1.000000 ] : is
[ 2.000000 ] : a
[ 3.000000 ] : sentence.
Каждое из значений – строка.
Пример 1. Допустим, у нас есть кусок одежды в виде меша для конкретной части тела, ну как в оригинале, и мы хотим менять их по скрипту.
Оригинальные пути файлов будут такими: armor\LegateArmor\LegateArmor.NIF
А наши такими: armor\MyModFolderName\LegateArmor\LegateArmor.NIF
Тогда действовать будем так:
let sv_filepath := GetBiPedModelPath 0 ArmorLegate --> 'armor\LegateArmor\LegateArmor.NIF'
let ar_paths := sv_Split sv_filepath "\" --> ar_paths[0] is "armor", ar_paths[1] is "LegateArmor", ar_paths[2] is "LegateArmor.Nif"
let sv_newfilepath := ar_paths[0] + "\MyModFolderName\" + ar_paths[1] + "\" + ar_paths[2] ; you'll probably need the compiler override on to add that up
SetBiPedModelPathEX $sv_newfilepath 0 ArmorLegate
Заметьте, что я использовать параметр 0 чтобы получить мужской меш, и вызвал базовый обьект, а не референс
(ArmorRef.GetBiPedModelPath 0), поэтому этот код переключает пути к файлам для базовой формы. Что-то близкое к get в TempCloneForm.
Вы можете заметить, что мне на самом деле не нужно знать конкретные пути к файлам, мне нужно просто вставить имя папки после первого раздела («armor»), поэтому ArmorLegate может с таким же успехом быть переменной ref, содержащей любую броню, полученную с помощью GetEquippedObject или чего-то подобного, при условии, что новый путь к файлу в остальном тот же самый.
Пример 2. Потратьте немного времени на изучение разделов Fallout на LL, и вы обязательно столкнетесь с упоминанием переменных NX, которые принимают строку для клавиш:
let fSomeFloat := rSomeRef.NX_GetEVfl "Строка какой-то клавиши"
rSomeRef.NX_SetEVfl " Строка какой-то клавиши" fSomeFloatValue
Эти клавиши будут строками, можно применить ToString чтобы функции NX хранили строковую переменную как клавишу:
let fSomeFloat := rSomeRef.NX_GetEVFl $somestringvar
Вероятно, вы создадите клавиши в виде «MyModNameString:SomeKeyString:SomeOptionalSubKeyString» (и эти двоеточия будут хорошим разделителем для sv_split), но, конечно, такие наборы текста утомляют, и иногда следует создавать NX клавиши динамически, на лету, не зная, сколько конкретно нужно.
Допустим, мы хотим отслеживать конкретную комбинацию предметов одежды, которые мы экипировали, чтобы сохранить эту комбинацию:
let iNum := -1
while (iNum += 1) < 20 ; check equipment slots 0-19
let rForm := playerref.GetEquippedObject iNum
if rForm
let sv_keystring := "OutfitMod:OutfitSet:" + "1:" + "Slot:" + $iNum
playerref.NX_SetEVFo $sv_keystring rForm
endif
loop
и чтобы затем экипировать эту комбинацию:
let iNum := -1
while (iNum += 1) < 20
let sv_keystring := "OutfitMod:OutfitSet:" + "1:" + "Slot:" + $iNum
let rForm := playerref.NX_GetEVfo $sv_keystring
if rForm
if playerref.getitemcount rForm
playerref.EquipItem rForm
endif
endif
loop
И если это поменять, то можно иметь несколько таких комбинаций
let sv_keystring := "OutfitMod:OutfitSet:" + "1:"
на это:
let sv_keystring := "OutfitMod:OutfitSet:" + $someInt + ":"
В зависимости от того, что вы носите, и сколько слотов отмечено каждым предметом, вы можете установить любое количество этих переменных EVFo для своего персонажа. Строковые переменные полезны тем, что они редактируемы и вам не нужно вводить все это в условия elseif, учитывая, что вы не знаете, сколько их нужно. Надеюсь, кто-нибудь перепишет MCM, чтобы всё это применить, да?
10. Переключение Между Строкой и Другими Представлениями, Функциями Символов
Не буду долго тут останавливаться, и так много написал. Просто соберем эту инфу в одном месте, а то она размазана по всей документации обсе. Немного основ: вы уже знаете ToString, и, окзаывается, она очень полезна. Альтернатива – ToNumber (или вкратце: #), которая прокинет числовое значение строки в тип float\int:
let sv_somestringvar := "34.5"
let fFloat := ToNumber sv_somestringvar
let fFloat := #sv_somestringvar --> fFloat will be 34.5
Это также можно сделать с шестнадцатеричными числами (hex numbers), хранящимися в строке, если добавить параметр hex bool или если строка начинается с «0x», что может перехватить динамически созданный ref.
let sv_somestringvar := "00000ADE"
let fFloat := ToNumber sv_somestringvar 1
NumToHex, в свою очередь, преобразует целое число в шестнадцатеричную строку с шириной по умолчанию 8 символов, хотя вы можете указать этот параметр:
let iInt := 2782
let sv_somestringvar := NumToHex iInt --> "00000ADE"
let sv_somestringvar := NumToHex iInt 4 --> "0ADE"
Чтобы выполнить некоторые операции на уровне отдельных символов, вам необходимо передать символ из строки в его ascii-код, что можно сделать с помощью sv_GetChar:
let iSomeInt := "somestring" somePosInt
let iSomeInt := sv_GetChar "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ.,:" 4
--> вернет 53, что является кодом ASCII для цифры 5, находящейся в позиции 4 в нашей строке
Если наша строка состоит из одного символа, мы можем просто использовать CharToAscii
let sv_somestringvar := "5"
let iSomeInt := CharToAsci sv_somestringvar --> again, 53
После передачи его ASCII-коду вы можете проверить тип символа с помощью булевых функций IsDigit, IsLetter, IsPunctuation и IsPrintable. Вы также можете переключаться между верхним и нижним регистром с помощью ToUpper и ToLower. А затем вернуть этот ASCII-код int обратно в строку с помощью ASCIIToChar:
let sv_SomeStringVar := AsciiTochar 53 --> "5"
let iSomeInt := ToLower 65 ; 65 is A --> iSomeINt = 141
let sv_SomeStringVar := AsciiToChar iSomeInt --> "a"
Если вы хотите выполнять такие функции и проверки для каждого символа в строке, а не для того, который вы извлекаете из его позиции с помощью sv_GetChar, вы можете использовать цикл foreach, который передает каждый символ в строковую переменную, называемую итератор, который хранит его на протяжении всего тела цикла:
foreach sv_iterator <- "SomeString" ; or: foreach sv_iterator <- somestringvar
; do stuff to sv_iterator, which will contain one character for each loop run going from position 0 to end
Loop
Команды "Break" и "continue", которые вы, возможно, помните по циклам while, здесь тоже применимы. Подробнее о циклах foreach смотрите в руководстве по массивам.
И теперь, когда мы говорим о кодах типа int, GetKeyName (он же GetKey) вернет строку для клавиши клавиатуры, если вы передадите DirectX scan code как параметр int:
let sv_somestringvar := GetKeyName 1 --> "Escape"
что, как я полагаю, может быть удобно для различных локализаций или в ситуациях, когда спецификатора формата %k недостаточно.
Вот и всё. Поверьте, вам редко придется использовать все эти функции, просто убедитесь, что вы четко понимаете основы и знаете, какие у вас есть варианты.
Комментарии