Для начала изучим еще одну команду инжекта.
UO.Count( type [, color ] ) - Возвращает суммарное количество во всех стопках обьекта указаного типа type (и цвета color если указано) в вашем бекпаке и подсумках. Учитываются только те подсумки которые хоть раз открывались, иначе их содержимое не известно. Эта команда очень удобна для подсчета имеющегося у вас какого-то конкретного типа объектов. В подсчет входят и те объекты, которые надеты на чара (одежда) или находятся в руках чара (инструменты, оружие, щиты). Цвет color можно не указывать.
Не путайте эту команду с командой UO.FindCount(), которую мы рассматривали в предыдущем уроке.
Примеры использования этой команды мы рассмотрим чуть позже, а пока отвлечемся на время от объектов и вернемся к синтаксису скриптов.
Циклы while и repeat являются циклами, количество повторов которых неограниченно, они прерываются только при выполнении (или невыполнении) указанного условия. А что делать если нам необходимо повторить какой-то набор действий точно заданное кол-во раз? Для этих целей нам подойдет оператор for:
For переменная = начальное значение To конечное значение
.........
Next
Здесь:
переменная - какая-то заранее созданная переменная (в принципе ее можно создать и прямо в операторе, но я не буду в этом учебнике рассматривать подобные усложнения), эта переменная будет при каждом повторе цикла автоматически наращиваться (к ней будет прибавляться единица), в диапазоне от начального до конечного значений.
Давайте посмотрим на простейший пример, чтобы было яснее:
Code: Select all
sub TestFor()
VAR i
For i = 1 To 5
UO.Print( 'Test of cycle. Number = ' + str( i ) )
wait(100)
Next
endsubВ качестве границ (начального и конечного условия) могут выступать и переменные, то есть можно написать и так:
Code: Select all
sub TestFor()
VAR i, x = 5
For i = 1 To x
...
Next
endsubCode: Select all
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Лирическое отступление: В принципе, вы легко можете обойтись и без цикла For. Можно ввести счетчик в какой-то переменной и написать цикл While или Repeat, в условии которых будет проверяться, не превысил ли счетчик определенной величины. Так что этот цикл сделан только для удобства программиста (скриптера). Впрочем, как и все остальные циклы. Любой из них можно заменить на комбинацию оператора If и оператора Goto (этот оператор в данном учебнике не рассматривается, я его использую крайне редко). На самом деле раньше (в первых языках программирования) и не было никаких операторов цикла. И ничего, обходились люди. Но с циклами гораздо удобнее.
Теперь о массивах. Очень часто вам в скриптах придется использовать не один объект или тип, а много. В том случае, если в скрипте предполагается однотипное использование этих объектов или типов - их гораздо удобнее хранить не в отдельных переменных, а вместе. Давайте посмотрим на это на примере. В качестве такого примера рассмотрим процедуру добора регов для реколла из сундука.
Code: Select all
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
endsubDIM имя_массива[размер_массива]
Вот такая команда объявляет создание массива под указанным именем и имеющим указанный размер. Массив - это и есть способ хранения однотипных (совсем не обязательно) данных. Массив состоит из элементов массива, их количество равно размеру массива. Каждый элемент массива - это, фактически, обычная переменная. То есть если размер массива 3 - то в массиве три элемента, 200 - двести элементов. Все элементы в массиве пронумерованы и к ним можно обращаться - имя_массива[номер] - это очень удобная форма обращения. Надо помнить только одно - элементы массива нумеруются с 0. То есть в массиве с размером 3 будет три элемента: с номерами 0, 1 и 2. Давайте запишем в нашем примере реги в виде массива:
Code: Select all
sub GetRecallRegs()
DIM Regs[3]
Regs[0] = '0x0F7A' ; Black Pearl
Regs[1] = '0x0F7B' ; Blood Moss
Regs[2] = '0x0F86' ; Mandrake Root
...
endsubЯ не зря рассказываю о цикле for и массивах вместе. Все дело в том, что обычно использование массивов происходит именно в циклах for. Это наиболее удобный инструмент. Посмотрим, как преобразился наш скрипт на добор регов после ввода в него массива.
Code: Select all
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
endsubCode: Select all
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Пора вернуться к объектам. До сих пор мы рассматривали способы нахождения объектов. Но объекты ищутся обычно не просто для того, чтобы знать есть они или нет, а для того, чтобы сделать с ними что-нибудь. Для этого нам потребуется узнать несколько новых команд:
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: Select all
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Кроме перемещения объектов необходима еще возможность использовать их. То есть то, что в игре достигается двойным кликом по предмету.
UO.UseObject( object ) - Использовать указанный объект.
UO.UseType( type [, color ] ) - Искать в бекпаке или подсумках (а также в руках или на чаре) объект по указанному типу и цвету (если задано) и использовать найденный.
UO.UseFromGround( type [, color ] ) - Искать на земле объект по указанному типу и цвету (если задано) и использовать найденный.
Не думаю что эти команды нуждаются в каком-то особом пояснении, но одно хочу отметить. Последние две команды работают с типами предметов, они сами осуществляют поиск конкретного объекта, подходящего под заданные тип и цвет. В принципе, команду UO.UseType можно заменить следующим блоком:
Code: Select all
UO.FindType( какой-то_тип, какой-то_цвет )
If UO.FindCount() > 0 Then
UO.UseObject( 'finditem' )
EndifОсновным инструментом в этом служат модификаторы. Модификатор - это специальный символ, добавляемый перед типом предмета для указания инжекту необходимости самому определить конкретный объект по этому типу. Естественно, все модификаторы подразумевают что инжект будет искать этот тип в указанном месте и потом будет использовать этот предмет. То есть мы добавляем перед типом предмета модификатор и используем полученное выражение как сериал объекта!
Вот имеющиеся модификаторы:
Code: Select all
_ (подчеркивание) - Форма записи: _type (например '_0x0F88' ) - Ищет по типу на чаре, в бекпаке, подсумках
^ (крышка) - Форма записи: ^type (например '^0x0F88') - Ищет в бекпаке без подсумок
~ (тильда) - Форма записи: ~type (например '~0x0F88') - Ищет на земле в заданном (команда set findistance) радиусе
< (меньше) - Форма записи: <type (например '<0x0F88') - Ищет по типу в последнем открытом контейнере
. (точка) - Форма записи: object.type (например '0x87654321.0x0F88') - Ищет по типу в указанном контейнере.Для завершения краткого курса по работе с объектами мне осталось только рассказать о указателях на объекты. Мы уже широко использовали указатель 'finditem', теперь перечислю основные из остальных (обо всех указателях вы можете прочитать в хелпе инжекта):
Code: Select all
lastobject - Последний использованый (двойным щелчком мыши) обьект
backpack - Текущий бекпак вашего персонажа
lastcontainer - Последний контейнер открытый сервером для вас
laststatus - Последнее существо, на которое была запрошена информация о здоровье. Это происходит например если вы используете встроеный в клиент макрос Target Next
lastattack - Последнее существо, которое вы атаковали
lastcorpse -Последний появившийся в области радиусом два экрана труп.
finditem - Обьект найденый командой findtype.
self - Ваш чар (персонаж). Code: Select all
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