Урок 3. И еще об объектах.Для начала изучим еще одну команду инжекта.
UO.Count( type [, color ] ) - Возвращает суммарное количество во всех стопках обьекта указаного типа
type (и цвета
color если указано) в вашем бекпаке и подсумках. Учитываются только те подсумки которые хоть раз открывались, иначе их содержимое не известно. Эта команда очень удобна для подсчета имеющегося у вас какого-то конкретного типа объектов. В подсчет входят и те объекты, которые надеты на чара (одежда) или находятся в руках чара (инструменты, оружие, щиты). Цвет
color можно не указывать.
Не путайте эту команду с командой
UO.FindCount(), которую мы рассматривали в предыдущем уроке.
Примеры использования этой команды мы рассмотрим чуть позже, а пока отвлечемся на время от объектов и вернемся к синтаксису скриптов.
Циклы
while и
repeat являются циклами, количество повторов которых неограниченно, они прерываются только при выполнении (или невыполнении) указанного условия. А что делать если нам необходимо повторить какой-то набор действий точно заданное кол-во раз? Для этих целей нам подойдет оператор
for:
For переменная = начальное значение To конечное значение
.........
NextЗдесь:
переменная - какая-то заранее созданная переменная (в принципе ее можно создать и прямо в операторе, но я не буду в этом учебнике рассматривать подобные усложнения), эта переменная будет при каждом повторе цикла автоматически наращиваться (к ней будет прибавляться единица), в диапазоне от
начального до
конечного значений.
Давайте посмотрим на простейший пример, чтобы было яснее:
Code:
sub TestFor()
VAR i
For i = 1 To 5
UO.Print( 'Test of cycle. Number = ' + str( i ) )
wait(100)
Next
endsub
Запустите этот пример и посмотрите сколько раз будет выведено тестовое сообщение. В данном случае мы используем в примере переменную i, которой в начале присваиваем значение 1, а ограничиваем цикл значением 5. В конце каждого повтора цикла оператор For автоматически наращивает указанную переменную, то есть в данном случае к переменной i добавляется 1. То есть в начале i равно 1, это меньше 5 (верхняя граница), поэтому тело цикла выполняется. Потом i наращивается, то есть становится равно 2. Оно все равно меньше 5 - поэтому тело цикла снова выполняется. Снова наращивается i, теперь оно равно 3 - снова выполняем. Следующий шаг - 4 - снова выполняем. Следующий шаг - i равно 5 - оно достигло верхней границы цикла - все равно цикл выполняется. Следующий шаг - i равно 6 - вот теперь переменная стала больше верхней границы цикла, поэтому повторы тела цикла прекращаются и скрипт переходит к выполнению следующей команды после цикла For. Ясно? Если нет - я уже более подробно разжевать не могу, сорри
В качестве границ (начального и конечного условия) могут выступать и переменные, то есть можно написать и так:
Code:
sub TestFor()
VAR i, x = 5
For i = 1 To x
...
Next
endsub
Ну и сразу расскажу как правильно прервать исполнение цикла For. К сожалению, в языке скриптов инжекта отсутствуют операторы Break и Continue, которые есть в большинстве других языков программирования. Поэтому фактически единственным корректным способом прервать выполнение цикла For является присваивание переменной цикла конечного значения. То есть:
Code:
sub TestFor()
VAR i
For i = 1 To 5
UO.Print( 'Test of cycle. Number = ' + str( i ) )
wait(100)
If i == 3 Then
i = 5
Endif
Next
endsub
В данном примере внутри цикла мы проверяем переменную цикла (то есть счетчик) и если он равен трем, то присваиваем ему новое значение 5. В результате цикл прервется, ведь в конце его тела переменная цикла будет увеличена на единицу и она превысит верхнюю границу цикла.
Лирическое отступление: В принципе, вы легко можете обойтись и без цикла For. Можно ввести счетчик в какой-то переменной и написать цикл While или Repeat, в условии которых будет проверяться, не превысил ли счетчик определенной величины. Так что этот цикл сделан только для удобства программиста (скриптера). Впрочем, как и все остальные циклы. Любой из них можно заменить на комбинацию оператора If и оператора Goto (этот оператор в данном учебнике не рассматривается, я его использую крайне редко). На самом деле раньше (в первых языках программирования) и не было никаких операторов цикла. И ничего, обходились люди. Но с циклами гораздо удобнее.Теперь о массивах. Очень часто вам в скриптах придется использовать не один объект или тип, а много. В том случае, если в скрипте предполагается однотипное использование этих объектов или типов - их гораздо удобнее хранить не в отдельных переменных, а вместе. Давайте посмотрим на это на примере. В качестве такого примера рассмотрим процедуру добора регов для реколла из сундука.
Code:
sub GetRecallRegs()
VAR Regs1 = '0x0F7A' ; Black Pearl
VAR Regs2 = '0x0F7B' ; Blood Moss
VAR Regs3 = '0x0F86' ; Mandrake Root
VAR sunduk = '0x12345678' ; сундук с регами
If UO.Count( Regs1 ) == 0 Then
......
; взять блек перл из сундука
Endif
If UO.Count( Regs2 ) == 0 Then
......
; взять блуд мосс из сундука
Endif
If UO.Count( Regs3 ) == 0 Then
......
; взять мандрейк рут из сундука
Endif
endsub
В этом примере мы задаем типы трех регов, а потом по очереди проверяем, есть у нас этот рег или нету. Если нету - добираем (пока тут я ничего не прописывал, в дальнейшем мы разберемся как это делать). Итак у нас три однотипных блока проверки и добора для каждого рега. А если у нас будет 8 регов и нам надо добирать их все? Придется делать 8 практически одинаковых блоков. Есть способ записать это гораздо проще:
DIM имя_массива[размер_массива]Вот такая команда объявляет создание массива под указанным именем и имеющим указанный размер. Массив - это и есть способ хранения однотипных (совсем не обязательно) данных. Массив состоит из элементов массива, их количество равно размеру массива. Каждый элемент массива - это, фактически, обычная переменная. То есть если размер массива 3 - то в массиве три элемента, 200 - двести элементов. Все элементы в массиве пронумерованы и к ним можно обращаться -
имя_массива[номер] - это очень удобная форма обращения. Надо помнить только одно - элементы массива нумеруются с 0. То есть в массиве с размером 3 будет три элемента: с номерами 0, 1 и 2. Давайте запишем в нашем примере реги в виде массива:
Code:
sub GetRecallRegs()
DIM Regs[3]
Regs[0] = '0x0F7A' ; Black Pearl
Regs[1] = '0x0F7B' ; Blood Moss
Regs[2] = '0x0F86' ; Mandrake Root
...
endsub
Вот это является правильной формой задания массива. Сначала определили имя массива и его размер, потом задали какие-то значения для элементов массива. В принципе, совсем не обязательно сразу задавать значения элементов массивов, более того, в некоторых скриптах вы будете задавать эти элементы программно, но в этом уроке мы будем рассматривать массивы только для задания наборов заранее известных типов.
Я не зря рассказываю о цикле for и массивах вместе. Все дело в том, что обычно использование массивов происходит именно в циклах for. Это наиболее удобный инструмент. Посмотрим, как преобразился наш скрипт на добор регов после ввода в него массива.
Code:
sub GetRecallRegs()
DIM Regs[3]
Regs[0] = '0x0F7A' ; Black Pearl
Regs[1] = '0x0F7B' ; Blood Moss
Regs[2] = '0x0F86' ; Mandrake Root
VAR i
For i = 0 To 2
If UO.Count( Regs[ i ] ) == 0 Then
......
; взять этот рег из сундука
Endif
Next
endsub
Итак, мы имеем массив из трех элементов и цикл for, в котором переменная i изменяет свои значения от 0 до 2. То есть по очереди равна 0, потом 1, потом 2. Тело цикла повторяется, соответственно, три раза, для каждого значения i. При каждом повторе проверяется количество рега, находящегося в элементе массива с номером i. Если этого рега нет - он берется. Если мы захотим ввести вместо трех регов восемь, то изменения скрипта будут минимальны:
Code:
sub GetRegs()
DIM Regs[8]
Regs[0] = '0x0F7A' ; Black Pearl
Regs[1] = '0x0F7B' ; Bood Moss
Regs[2] = '0x0F86' ; Mandrake Root
Regs[3] = '0x0F84' ; garlic
Regs[4] = '0x0F85' ; Ginseng
Regs[5] = '0x0F88' ; Night Shade
Regs[6] = '0x0F8C' ; Sulphorous Ash
Regs[7] = '0x0F8D' ; Spiders Silk
VAR i
For i = 0 To 7
If UO.Count( Regs[ i ] ) == 0 Then
......
; взять этот рег из сундука
Endif
Next
endsub
Если что-то не поняли, рекомендую перечитать еще раз. Я возвращаться к объяснению цикла for и массивов не буду. Дальше в уроке мы будем использовать их активно.
Пора вернуться к объектам. До сих пор мы рассматривали способы нахождения объектов. Но объекты ищутся обычно не просто для того, чтобы знать есть они или нет, а для того, чтобы сделать с ними что-нибудь. Для этого нам потребуется узнать несколько новых команд:
UO.MoveItem( object [, quantity, container / ground [, x, y, z ] ] )Команда для перемещения объекта
object. Можно указать количество
quantity, если оно не указано или указано '0' (все численные значения в этой команде и других, указанных ниже, остальных я настоятельно рекомендую указывать строками, то есть в кавычках, это повысит надежность работы ваших скриптов) - будет перемещена вся стопка. Третьим параметром команды может быть указан контейнер, в который надо поместить объект, либо слово
'ground' - выложить объект на землю. Четвертый параметр - координаты. Если вы кладете объект в контейнер - это координаты точного места в нем. Если вы выкладываете предмет на землю, то координаты - это либо абсолютные координаты в мире, либо относительные по отношению к чару. Не указанные координаты считаются нулевыми. То есть если предмет кладется на землю - он будет брошен под ноги, а если предмет помещается в контейнер - УО само выберет куда его там поместить. Если не указать контейнер - тот будет считаться контейнером по умолчанию, то бишь бекпаком чара.
Параметры можно указывать только в том порядке, как они перечислены. Нельзя пропускать какой-либо. То есть нельзя указать контейнер, не указав количество.
Итак:
UO.MoveItem( '0x12345678' ) - переместит указанный объект в бекпак чара
UO.MoveItem( '0x12345678', '1' ) - переместит 1 штучку из стопки указанного объекта в бекпак чара. Если в стопке всего один предмет - он и переместится. Если больше - переместится только 1.
UO.MoveItem( '0x12345678', '0' ) - переместит указанный объект в бекпак чара. Полностью аналогично первому примеру.
UO.MoveItem( '0x12345678', '1', '0x87654321' ) - переместит 1 штучку из стопки указанного предмета в указанный контейнер.
UO.MoveItem( '0x12345678', '1', 'ground', '1', '0', '0' ) - переместит 1 штучку из стопки указанного предмета на землю и положит ее рядом с чаром в одной клетке на восток (координаты заданы как относительные и к координате X чара прибавляется одна клетка).
Давайте закончим наш скрипт на добор регов.
Code:
sub GetRegs()
DIM Regs[8]
Regs[0] = '0x0F7A' ; Black Pearl
Regs[1] = '0x0F7B' ; Bood Moss
Regs[2] = '0x0F86' ; Mandrake Root
Regs[3] = '0x0F84' ; garlic
Regs[4] = '0x0F85' ; Ginseng
Regs[5] = '0x0F88' ; Night Shade
Regs[6] = '0x0F8C' ; Sulphorous Ash
Regs[7] = '0x0F8D' ; Spiders Silk
VAR i
VAR sunduk = '0x87654321' ; сундук с регами
For i = 0 To 7
If UO.Count( Regs[ i ] ) == 0 Then
; ищем данный рег в сундуке
UO.FindType( Regs[ i ], '-1', sunduk )
; проверяем нашли ли что-то
If UO.FindCount() > 0 Then
; берем 1 штучку этого рега в пак
UO.MoveItem( 'finditem', '1' )
; паузу надо обязательно, иначе нас заблокирует сервер!
wait( 1000 )
Else
; ну нету этого рега в сундуке! Ругнемся на это и пойдем дальше
UO.Print( 'Netu rega!' )
Endif
Endif
Next
endsub
Команда MoveItem является универсальной командой для перемещения объектов. Кроме нее в инжекте есть еще отдельные команды для взятия предметов в пак
(UO.Grab), выкладывания предметов на землю
(UO.Drop, UO.Drophere). В данном учебнике я не буду рассматривать эти команды - в них нет необходимости. Вы можете прекрасно изучить их сами.
Кроме перемещения объектов необходима еще возможность использовать их. То есть то, что в игре достигается двойным кликом по предмету.
UO.UseObject( object ) - Использовать указанный объект.
UO.UseType( type [, color ] ) - Искать в бекпаке или подсумках (а также в руках или на чаре) объект по указанному типу и цвету (если задано) и использовать найденный.
UO.UseFromGround( type [, color ] ) - Искать на земле объект по указанному типу и цвету (если задано) и использовать найденный.
Не думаю что эти команды нуждаются в каком-то особом пояснении, но одно хочу отметить. Последние две команды работают с типами предметов, они сами осуществляют поиск конкретного объекта, подходящего под заданные тип и цвет. В принципе, команду
UO.UseType можно заменить следующим блоком:
Code:
UO.FindType( какой-то_тип, какой-то_цвет )
If UO.FindCount() > 0 Then
UO.UseObject( 'finditem' )
Endif
Можно, но зачем? Во многих случаях гораздо удобнее использовать одну команду вместо нескольких. В конце урока мы рассмотрим пример скрипта на лут трупа, где будем использовать все знания, полученные в этом уроке, а пока я хочу остановиться на более подробном рассмотрении заложенных в инжект возможностей сокращения кода.
Основным инструментом в этом служат модификаторы. Модификатор - это специальный символ, добавляемый перед типом предмета для указания инжекту необходимости самому определить конкретный объект по этому типу. Естественно, все модификаторы подразумевают что инжект будет искать этот тип в указанном месте и потом будет использовать этот предмет. То есть мы добавляем перед типом предмета модификатор и используем полученное выражение как сериал объекта!
Вот имеющиеся модификаторы:
Code:
_ (подчеркивание) - Форма записи: _type (например '_0x0F88' ) - Ищет по типу на чаре, в бекпаке, подсумках
^ (крышка) - Форма записи: ^type (например '^0x0F88') - Ищет в бекпаке без подсумок
~ (тильда) - Форма записи: ~type (например '~0x0F88') - Ищет на земле в заданном (команда set findistance) радиусе
< (меньше) - Форма записи: <type (например '<0x0F88') - Ищет по типу в последнем открытом контейнере
. (точка) - Форма записи: object.type (например '0x87654321.0x0F88') - Ищет по типу в указанном контейнере.
Использовать эти модификаторы совершенно не обязательно, но они практически незаменимы при написании команд для биндов на клавиши, если вы не используете при этом запуск какого-то специально написанного скрипта. Например команда:
,grab 0 ~0x0F7A найдет на земле и поднимет в пак рег блек пеарл.
Для завершения краткого курса по работе с объектами мне осталось только рассказать о указателях на объекты. Мы уже широко использовали указатель 'finditem', теперь перечислю основные из остальных (обо всех указателях вы можете прочитать в хелпе инжекта):
Code:
lastobject - Последний использованый (двойным щелчком мыши) обьект
backpack - Текущий бекпак вашего персонажа
lastcontainer - Последний контейнер открытый сервером для вас
laststatus - Последнее существо, на которое была запрошена информация о здоровье. Это происходит например если вы используете встроеный в клиент макрос Target Next
lastattack - Последнее существо, которое вы атаковали
lastcorpse -Последний появившийся в области радиусом два экрана труп.
finditem - Обьект найденый командой findtype.
self - Ваш чар (персонаж).
Теперь давайте рассмотрим подробно простейший скрипт на лут трупа, чтобы на практике усвоить полученные знания.
Code:
sub LootLastCorpse()
DIM Nado[20]
Nado[0] = '0x0F7A' ; pearls, black pearls
Nado[1] = '0x0F7B' ; bood moss
Nado[2] = '0x0F84' ; garlic
Nado[3] = '0x0F85' ; ginseng
Nado[4] = '0x0F86' ; mandrake root
Nado[5] = '0x0F88' ; night shade
Nado[6] = '0x0F8C' ; sulphorous ash
Nado[7] = '0x0F8D' ; spiders silk
Nado[8] = '0x0E34' ; blank scrolls
Nado[9] = '0x0F78' ; batwings
Nado[10] = '0x0F7E' ; bones
Nado[11] = '0x0F7D' ; vials of blood
Nado[12] = '0x0F80' ; daemons bones
Nado[13] = '0x0F81' ; fertile dirt
Nado[14] = '0x0F82' ; dragons blood
Nado[15] = '0x0F87' ; eyes of newt
Nado[16] = '0x0F8E' ; serpents scales
Nado[17] = '0x0F90' ; dead woods
Nado[18] = '0x0F91' ; wyrms hearts
Nado[19] = '0x0F8F' ; volcanic ash
; я специально ограничился только регами и паган регами, вы сами можете расширять массив
; на те предметы, которые хотите лутить
VAR i
; Для начала откроем последний труп на экране
UO.UseObject( 'lastcorpse' )
wait(1000)
For i = 0 To 19
; Ищем по очереди весь лут в последнем трупе
UO.FindType( Nado[i], '-1', 'lastcorpse' )
; Пока количество найденного больше 0
While UO.FindCount() > 0
; Забираем найденное в пак
UO.MoveItem( 'finditem' )
wait( 1000 )
; Ищем снова - вдруг в трупе объектов с таким типом больше одного
UO.FindType( Nado[i], '-1', 'lastcorpse' )
Wend
Next
UO.Print( 'The loot was finished' )
endsub
На этом третий урок завершен. Я рассказал вам все что хотел о объектах и работе с ними, в следующих уроках мы будем рассматривать другие темы.