Пятница, 26.04.2024, 23:30 Приветствую Вас Гость


Гильдия -=InS=- (Ultima Onlie)

Гильдия Love BF (My Lands)

Главная | Регистрация | Вход | RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Обмен опытом » Макросы для Injection » УЧЕБНИК ИНЖЕКТ
УЧЕБНИК ИНЖЕКТ
SaNeKДата: Среда, 24.09.2008, 15:30 | Сообщение # 1
Генералиссимус
Группа: Администраторы
Сообщений: 168
Репутация: 10
Статус: Offline
Урок 1. Самая важная команда, синтаксис и "Hello, shard!"

Итак, вы стали счастливым обладателем инжекта, вам удалось его настроить (или для вас это сделал кто-то другой ), вы прочитали справочник по инжекту (составленный мной), более-менее разобрались в его менюшках и настройках… Но самое главное - скрипты - для вас все еще тайна за семью печатями? Ну что ж, этот небольшой учебник поможет вам освоить азы программирования на инжекте. Я не буду пытаться охватить все команды инжекта, но я покажу вам как пользоваться основными командами, а дальше… дальше вы уже сами.

А начнем мы с самой важной команды скриптов. Команды, без которой не обходится, фактически, ни один скрипт. Команды, которую вы можете использовать только в скриптах - большинство команд инжекта имеют как форму для скриптов, так и "консольную" форму, то есть вы их можете писать прямо в клиенте и запускать. Многие мелкие скрипты, кстати, именно так и устроены. При бинде их на клавишу просто перечисляются команды инжекта и вуаля - скрипт готов. Но я отвлекся. Так вот, эту команду в консоли вы написать не можете. Как некоторые из вас уже наверно догадались, это команда Wait() - пауза.

Wait() - ждать заданное количество миллисекунд.

Внутри скобок этой команды надо указать ей параметр - сколько миллисекунд ждать. 1 секунда - это 1000 миллисекунд. Поэтому Wait(1000) - это ждать 1 секунду. В конце этого урока я приведу пример как не надо писать скрипты. А именно - скрипт который совершенно надежно подвешивает компьютер, на котором он запущен. И ошибка того скрипта в том, что в нем нету команды wait в нужном месте. Причем с самым маленьким параметром времени. Хотя бы wait(50) - и скрипт уже не подвесит вашу систему.

Паузы очень важны в ваших скриптах. Во-первых, нужно дожидаться, пока игра совершит какое-либо действие. Во-вторых, надо дожидаться появления какого-либо сообщения. В-третьих, надо дожидаться появления какого-либо чара или животного - в основном все скрипты состоят из пауз. Причем в начале, пока вы неопытны, вы будете использовать в основном фиксированные паузы, типа wait(4000) - ждать 4 секунды (именно столько вам надо ждать на Цитадели, чтобы сработал скил Хайдинг), в дальнейшем вы быстрее всего перейдете на использование динамических пауз - то есть пауз, длина которых заранее не определена, это просто паузы пока не совершится какое-либо событие. Но в основе этих динамических пауз все равно вы найдете команду wait.

Вот теперь пора познакомиться с синтаксисом скриптов инжекта.

Для начала, несколько слов о терминологии. Скрипт - это программа. Написанная на специальном языке. Основой для этого языка стал язык программирования Basic, причем в самой простой своей форме. Еще вам будут постоянно встречаться такие понятия, как функции и процедуры. По определению, функция получает какие-то параметры, обрабатывает их и возвращает какое-то значение. Процедура от функции отличается тем, что ничего не возвращает. На самом деле, разницы между процедурами и функциями никакой нету. Это те же самые скрипты. Или программы, как хотите. Зачастую функция, которая, по идее, что-то возвращает, будет вами использоваться как процедура - ну не нужен нам этот результат. А из процедуры можно вернуть результат "непрямым" способом. Да и параметры не обязательны. Головной скрипт (главный) - это тоже, фактически, процедура. Поэтому, если путаетесь - плюньте. Даже опытные программисты постоянно в этих терминах путаются и называют одно другим. Неважно. Главное - знать что все это отдельные программы.

Любой скрипт (программа) на языке скриптов инжекта всегда начинается с команды sub и заканчивается командой endsub. Скрипты пишутся в текстовые файлы, в одном файле может быть очень много скриптов (я даже затрудняюсь сказать сколько, у меня есть скрипта на 3000 строк кода, там этих функций и процедур под сотню, и ничего, все нормально живет в одном файле). Итак, любой скрипт должен выглядеть так:
Code:
sub MyScript()
……….
endsub

Тут есть одна тонкость, запомните ее на будущее - если вы напишете команду sub вначале скрипта с заглавной буквы, то есть Sub - этот скрипт не будет отражаться в списке скриптов, доступных к запуску в инжекте, но при этом будет спокойно запускаться из других скриптов. Поэтому многие скриптеры "прячут" свои функции и процедуры именно таким образом, чтобы они "не мешали" в списке скриптов к запуску.

После команды sub через пробел пишется имя этого скрипта. После имени указываются круглые скобки, в которые могут быть помещены 1 или несколько имен переменных для параметров скрипта. Если это функция или процедура. (снова читаем тремя абзацами выше).

Но к параметрам мы еще вернемся. А пока давайте напишем самый первый скрипт, используя те знания, что уже получили:
Code:
sub MyWait()
wait(3000)
endsub

Этот скрипт делает всего одну вещь - он ждет 3 секунды. То есть ничего не делает. Но работает. Понятное дело, совершенно бесполезный скрипт. Пауза всегда нужна для чего-то, сама по себе она не нужна. Но ничего, счас изучим еще одну команду и сделаем первый рабочий скрипт. Эта команда – UO.Print(). Вывести сообщение.

UO.Print() – вывести информационное сообщение в игре

Внутри скобок этой команды надо указать сообщение в кавычках и вы получите в игре это сообщение. Его видите только вы и на сервер оно не направляется. Например UO.Print( 'Privet' ) – выведет сообщение 'Privet'. Кавычки вы можете использовать как одинарные (апостроф), так и двойные - главное чтобы они были одинаковые в начале и в конце выражения. Давайте вставим такую команду в наш скрипт.
Code:
sub MyMessage()
UO.Print( "Hello, shard!" )
wait(3000)
endsub

Если вы сохраните и запустите этот скрипт он вам выдаст сообщение Hello, Shard!, потом подождет 3 сек (зачем-то) и закончит работу. Пауза здесь, как понятно, опять же не у дел. Но не будем ее трогать, а просто добавим еще одну команду UO.Print.
Code:
sub MyMessage()
UO.Print( "Hello, shard!" )
wait(3000)
UO.Print( "I go!" )
endsub

Вот теперь все встало на свои места. Скрипт говорит: "привет, шард", ждет три секунды и добавляет: "я иду"...

Все было бы хорошо, но вот только ваше приветствие кроме вас никто и не увидит... Лучше бы было, если бы эти фразы произносил ваш чар, тогда все кто рядом будут их "слышать". Нет проблем:

UO.Say() - произнести фразу чаром в игре

Так что если мы заменим в нашей программе UO.Print на UO.Say - получится то, что надо.
Code:
sub MyMessage()
UO.Say( "Hello, shard!" )
wait(3000)
UO.Say( "I go!" )
endsub

На самом деле язык скриптов инжекта содержит множество разных команд, которые позволяют выводить, говорить чаром, говорить минуя чара в игре и т. д. Потом, может быть, мы к этой теме еще вернемся, а пока этих двух команд нам вполне хватит.

Продолжим рассматривать синтаксис скриптов. Теперь поговорим о переменных. Переменная - это какое-то имя, заданное вами, которому в скрипте вы можете присваивать различные значения. Перед использованием переменную нужно создать. В более сложных языках программирования переменные обычно надо задавать указывая их тип: числовые, строковые и т. д. В инжекте вам это не требуется. Главное - ее создать. Создать ее можно перед самим использованием, но хорошей привычкой будет создавать все нужные вам переменные (пока не станете опытным скриптописателем) в начале скрипта. Для этого используется оператор VAR:

VAR myvar1, myvar2, myvar3 ...

Имена myvar1 и т.д. - это просто пример имен. Имя может быть любым, главное чтобы оно состояло из английских букв и цифр и не имело пробелов. Дефисы тоже допустимы. Цифру в начало имени не ставим.

Значение переменной присваивается знаком равно (=). Это можно сделать отдельной строкой, а можно сделать в операторе VAR:

VAR i = 1, mymessage1 = 'Hello, Shard!', mymessage2 = "I go!"

Вот тут переменная i числовая, мы ей присвоили единицу, остальные две переменные строковые - им мы присвоили свои сообщения. Естественно, в скрипте мы можем присвоить переменной новое значение в любой момент. Для этого ее создавать снова не надо, достаточно в отдельной строке скрипта написать:

i = 2

И все. Давайте перепишем наш скрипт на приветствие через переменные:
Code:
sub MyMessage()
VAR mymessage1 = 'Hello, Shard!', mymessage2 = "I go!"
UO.Say( mymessage1 )
wait(3000)
UO.Say( mymessage2 )
endsub

Теперь мы передаем командам UO.Say не конкретный текст, а имена переменных, этот текст содержащих. По фигу. Одно и тоже.

Вот теперь стоит вернуться к функциям и процедурам. Давайте посмотрим как нам их писать (возращаемые значения пока рассматривать не будем, так что речь идет о процедурах).
Code:
sub MyMessage()
VAR mymessage1 = 'Hello, Shard!', mymessage2 = "I go!"
MySay( mymessage1 )
MySay( mymessage2 )
endsub

sub MySay( myparam )
UO.Say( myparam )
wait(1000)
endsub

У нас теперь два скрипта. Первый - основной, в нем мы создаем две переменных с приветствиями, и дважды вызываем процедуру MySay, передавая ей в качестве параметра имя переменной с сообщением. Потом у нас идет эта процедура, в имени которой в качестве параметра написано myparam - это мы определили новую переменную, в которую будет попадать параметр, переданный в эту процедуру. То есть текстовую строку. А дальше - процедура выводит ее на экран и ждет 1 сек.

Кстати, созданные вами переменные действуют только в пределах того скрипта (функции, процедуры), в которой вы их создали. В другом скрипте вы можете снова использовать эти же имена - это все равно будут другие переменные.

Вот с этим (все что выше) вам надо очень внимательно разорбраться. В дальнейшем я подобные вещи подробно расписывать не буду. Так что если хоть что-то осталось непонятно - перечитайте еще раз, попробуйте сами.

Теперь несколько слов о тех переменных, которые уже существуют в инжекте. Вы не можете использовать их имена, но вы можете использовать значения этих переменных просто указав в скрипте их имя. Перечислю основные:

UO.Life - текущее здоровье вашего чара
UO.Mana - текущее количество маны вашего чара
UO.Stamina - текущее количество стамины вашего чара
UO.STR - уровень силы вашего чара
UO.INT - уровень интеллекта вашего чара
UO.DEX - уровень ловкости вашего чара
UO.Weight - вес вашего чара
UO.Armor - текущий армор-класс вашего чара
UO.Gold - суммарное количество денег (бэкпак и банк) вашего чара
UO.BM - количество рега bloodmoss в паке у вашего чара
UO.BP - количество рега black pearl в паке у вашего чара
UO.GA - количество рега garlic в паке у вашего чара
UO.GS - количество рега ginseng в паке у вашего чара
UO.MR - количество рега mandrake root в паке у вашего чара
UO.NS - количество рега nightshade в паке у вашего чара
UO.SA - количество рега sulfurous ash в паке у вашего чара
UO.SS - количество рега spider's silk в паке у вашего чара
UO.VA - количество паган рега volcanic ash в паке у вашего чара
UO.EN - количество паган рега eyes of newt в паке у вашего чара
UO.WH - - количество паган рега wyrm's heart в паке у вашего чара
UO.FD - количество паган рега blackmoor в паке у вашего чара
UO.BR - количество паган рега fertile dirt в паке у вашего чара
UO.H - количество поушенов heal в паке у вашего чара
UO.C - количество поушенов cure в паке у вашего чара
UO.M - количество поушенов mana в паке у вашего чара
UO.L - количество поушенов refresh в паке у вашего чара
UO.B - количество бинтов в паке у вашего чара
UO.AR - количество стрел в паке у вашего чара
UO.BT - количество болтов в паке у вашего чара

Вы не можете изменять эти переменные, они автоматически изменяются в игре, но вы можете использовать их в своих скриптах. Не буду приводить примера, тут и так все ясно. Позже в примерах мы будем эти переменные активно использовать.

Теперь посмотрим как устроен скрипт. В скрипте каждая команда должна идти на отдельной строке, объединять несколько команд в одну строку нельзя. Если вам нужно просто выполнить несколько команд по очереди - это самый простейший вид скриптов, то вы пишете каждую команду в отдельную строку (именно так мы и делали в скрипте на приветствие) и все. Но такое требуется редко. Обычно в скриптах нужно проверять выполнение каких-нибудь условий, в зависимости от этого выполнять разные действия, повторять какой-то набор действий либо фиксированное количество раз, либо пока не выполнится определенное условие. Для этого нам потребуются условные операторы и циклы.

Простейший условный оператор - If. Выглядит он так:
Code:
If условие Then
.........
Endif

Если условие выполняется тогда делать то-то и то-то. Расширенный вариант этого условного оператора:
Code:
If условие Then
...........
Else
...........
Endif

Если условие выполняется тогда делать то-то и то-то, иначе (если условие не выполняется) - делать другое что-то. Условный оператор If является простейшим способом проверки выполнения условия. И одним из основных. Давайте переделаем наш пример на приветствие с использованием проверки условия. При этом введем еще переменную i которой в начале присвоим 1.
Code:
sub MyMessage()
VAR i = 1
VAR mymessage1 = 'Hello, Shard!', mymessage2 = "I go!"
If i == 1 Then
UO.Say( mymessage1 )
Else
UO.Say( mymessage2 )
Endif
endsub

Внимательно посмотрите на пример. Во-первых, у нас появилось две строки с VAR. Их вообще может быть сколько угодно. Во-вторых, условие в If. Тут мы используем знак == - сравнение двух значений. Не путайте его с присваиванием (=). Если написать If i = 1 Then - вы получите ошибку. Что теперь делает наш скрипт? На самом деле он выводит только первое приветствие, второе не будет выводиться никогда. Разберитесь сами почему. Попробуйте в строке VAR i = 1 единицу заменить на 2. Посмотрите на результат. А я иду дальше.

Следующим оператором, важным для скриптинга в инжекте является while.
Code:
While условие
...
Wend

Повторять действия до тех пор, пока выполняется условие. Проверка условия производится перед выполнением действий! То есть если условие не выполняется - никаких действий не будет. Скрипт сразу перейдет на следующую команду, расположенную сразу за словом wend. Вот теперь мы можем переделать наш скрипт на новый лад.
Code:
sub MyMessage()
VAR i = 1
VAR mymessage1 = 'Hello, Shard!', mymessage2 = "I go!"
While i < 3
If i == 1 Then
UO.Say( mymessage1 )
Else
UO.Say( mymessage2 )
Endif
i = i + 1
Wend
endsub

Вот тут рассмотрим работу скрипта подробнее. Вначале у нас переменная i равна 1. Приходим к while. Проверяется i, меньше ли оно 3. 1 меньше чем 3, значит все что между while и wend будет выполняться. Здесь проверяется - равно ли i единице - равно. Поэтому сработает команда UO.Say( mymessage1 ). В результате чар скажет первое приветственное сообщение. Выход из if - следующий оператор i = i + 1. В нем переменная i будет увеличена на 1. Это стандартный способ увеличения счетчиков (такие переменные в скритптах обычно называют счетчиками) на какую-то величину. То есть к переменной i прибавляется 1 и результат сложения записывается в переменную i. В результате в переменная i будет равна 2. Дальше следует wend - значит переходим снова к строке While i < 3. Это условие опять выполняется (2 меньше 3). Теперь проверяется условие If. 2 не равно 1, поэтому условие не выполняется и будет выполнено действие после Else. То есть UO.Say( mymessage2 ) - получим на экране второе приветственное сообщение. Теперь опять счетчик увеличивается на 1 - i будет равно 3. Опять переходим на проверку условия в While - вот теперь оно не выполняется (3 не меньше 3) - соответсвенно сразу переходим на оператор после wend - а там у нас конец скрипта.

Разбирайтесь с этим примером столько раз, сколько потребуется чтобы все понять. Очень мало будет вам встречаться скриптов в которых нету операторов if, while и оператора repeat - аналогичного оператору while с некоторыми изменениями.
Code:
repeat
....................
until условие

Выполнять действия пока условие НЕ выполняется. Проверка условия производится после действий! Этот оператор отличается от while - только этими двумя вещами, названными мной, но при этом это отличие принципиальное! Давайте рассмотрим маленький пример.
Code:
while i < 3
wait( 1000)
wend

Code:
repeat
wait(1000)
until i > 2

Вот два цикла. Условие в обоих одно и то же по действию - в первом случае цикл выполняется пока i меньше 3, во втором случае пока не выполняется i > 2. То есть пока i < 3. Проще всего это понять подставив вместо i разные числа. Если например i равняется 2: 2 меньше 3 - это верно, while выполняется. 2 не больше 2 - то есть условие в until не выполняется - значит действия в repeat выполняются. Понятно? Вот теперь насчет "после". Предположим, что i равно 3. Что у нас происходит? В цикле while проверка производится перед действиями - так как 3 не меньше 3, то никаких действий не производится, скрипт сразу переходит к командам после wend. В случае же repeat - проверка производится после действий, поэтому одна пауза в 1 секунду все равно будет выполнена! После этого проверка 3 > 2 выдаст истину и цикл repeat будет прерван. Итак, цикл repeat важен тем, что указанные в нем действия будут выполняться по крайней мере 1 раз!

Вот мы и подбираемся к концу первого урока. Это далеко не все операторы языка скриптов инжекта, но пока нам хватит и их. Другие операторы мы рассмотрим позже. А счас, как и обещал в начале, привожу пример (у вас достаточно знаний чтобы этот скрипт понять) скрипта, как не надо писать скрипты
Code:
sub MyScript()
While UO.Life > 0
If UO.Life < 70 Then
UO.Bandageself()
wait(2000)
Endif
Wend
endsub

Этот скрипт - это попытка написать автополхилл чара. Цикл while "крутится" пока здоровья больше 0, то есть пока чар не умрет. Если здоровья становится меньше 70 - чар лечится с бинтов (именно это и делает команда UO.Bandageself() ). В чем же ошибка этого скрипта? Эта ошибка называется "пустой цикл". Давайте проверим, что происходит во время работы этого скрипта. А именно, если здоровья у чара больше 70 (или равно). В этом случае действия внутри if...endif не выполняются, и цикл while...wend становится пустым, то есть в нем не производится никаких действий. Скриптовый модуль инжекта устроен так, что в этом случае вы получите 100%-загрузку процессора вашего компьютера (зависнет) и, быстрее всего, креш игры или системы. Как избежать такого конца? Очень просто. Предусмотреть чтобы в скрипте всегда какие-нибудь действия производились. В данном случае вполне достаточно добавить Else:
Code:
sub MyScript()
While UO.Life > 0
If UO.Life < 70 Then
UO.Bandageself()
wait(2000)
Else
wait(50)
Endif
Wend
endsub

Вот смотрите: мы добавили в скрипт паузу в 50 миллисекунд, то есть 0,005 секунды, а скрипт сразу заработал.

Ну и напоследок. Обратите внимание на то, как я привожу скрипты. А именно на отступы. Старайтесь сразу приучить себя использовать подобный стиль написания. Это облегчит понимание скриптов и вам, и тем другим, кто их будет смотреть. А чем легче читается скрипт, тем проще найти в нем ошибки.

 
SaNeKДата: Среда, 24.09.2008, 15:32 | Сообщение # 2
Генералиссимус
Группа: Администраторы
Сообщений: 168
Репутация: 10
Статус: Offline
Урок 2. Поиск и использование объектов.

В ближайших двух уроках (2 и 3) мы будем разбираться с принципами работы с различными объектами УО. Это очень важная тема, очень мало скриптов в которых в той или иной степени не задействована работа с объектами. Для удобства я разбил эту, в принципе, почти необъятную на два этапа изучения - вводный и более сложный - именно поэтому и сделано разделение на
2 урока. Внимательно читайте и изучайте этот урок, помня при этом, что это только "цветочки"

Прежде чем начинать разбираться с инструментами инжекта по работе с объектами, надо разобраться в устройстве мира Ультимы и терминологии. Весь мир УО состоит из двух типов - динамические объекты и статитические объекты. Статические объекты (обычно называют статикой) - это фоновое изображение, в основном неизменная на различных шардах. Это земля, вода, деревья, скалы, пещеры, города (здания). Статика тоже может быть подразделена на типы, но об этом позже. Динамические объекты (или просто объекты, как их обычно называют) - это (обычно) то, что привнесено в мир администрацией и игроками. Это оружие, ресурсы, контейнеры, двери, ворота, заборы, украшения, животные, сами игроки в конце концов (игровые чары). Инжект предоставляет удобный инструмент определения статик или динамик - наберите команду ,hide и ткните прицелом в объект. Если он исчезнет (вернуть вы его можете выполнив команду ,resend) - это динамический объект. Если не исчезнет или вообще прицел не нажимается - статика.

Каждый объект в мире имеет уникальный номер (обычно называется сериалом или ID), по которому вы можете работать с этим объектом. Номер обычно представлен в виде длинного (8 знаков) шестнадцатиричного числа, например 0x4010AF44. Практически всегда в инжекте эти числа используются в строковом виде, то есть "0x4010AF44". Обратиться к объекту можно тремя способами: использовав его сериал, использовав имя, присвоенное этому объекту на закладке Objects, либо использовав указатель на этот объект. Об указателях мы поговорим позже.

Пока же дальше о устройстве мира. Каждый объект мира УО имеет ряд свойств. Это номер его графического предствления (то есть номер картинки, которой этот объект в мире представлен), это его цвет, это количество в стопке (если объект предствляет из себя стопку или кучку чего-либо), это его координаты в мире в данное время и так далее. Наберите в игру команду ,info и укажите прицелом на объект. Вы получите полные сведения об этом объекте и о способе предствления этих данных.

Что еще важно? Объект получает от сервера сериал при создании и обычно сохраняет этот сериал до разрушения. Но есть и исключения. Во-первых, нельзя путаться - стопка (кучка) из, например, 4 штучек руды - это один объект, уберите 1 штучку руды и вы получите новый объект - стопку из 3 штучек руды. Соответственно, новый сериал. Во-вторых, обычно такие стопки (кучки) изменяют свой сериал даже при простом перекладывании. Понятно, что в этом случае нет никакого смысла запоминать сериал таких объектов. В подобных случаях, а также в массе других случаев важным инструментом работы с объектами становится его тип.

Тип объекта - это номер его графического представления в игре. Именно поэтому тип объекта иногда называют его графикой. Тип объекта представляется в виде четырёхзначного шестнадцатеричного числа, например 0x1234. Типы объектов вы тоже практически всегда будете использовать как строки, то есть "0x1234". В отличие от сериала типы нескольких одинаковых по графическому представлению предметов будут совпадать. Так у всех даггеров один тип, у всех хитер-щитов тоже один тип. Аналогично другие объекты. В некоторых случаях один предмет может иметь два типа, в зависимости от ориентации (например кирки и хатчеты, поэкспериментируйте, берите в руку и кладите обратно - кирка будет поворачиваться и у нее будет изменяться тип).

Опять же, повторю: тип объекта - это его графическое представление, то есть фактически иконка. Причем без привязки к цвету. Так у рега black pearl, у жемчуга (pearl) - один тип, они отличаются только цветом. Тоже самое касается ингов разных металлов - это все один тип. Если вы снова взглянете на тот результат, который вы получили командой ,info (см. выше) вы увидите, что тип объекта и цвет объекта - это разные параметры.

Ну и напоследок. О указателях, то есть о третьем способе указания на объект. Указатель - это некая переменная инжекта (уже существующая, вам не надо ее создавать), которая хранит в себе ссылку на какой-то объект УО. Здесь важно понимать, что указатель - это не сериал объекта, а только ссылка на этот предмет, которую можно использовать в скриптах вместо сериала объекта. Но если вы захотите получить сериал этого объекта - вам надо будет использовать специальную функцию "взятия" этого сериала с указателя. Подробнее о указателях мы будем говорить в следующей главе, но определение мне надо было дать сейчас, так как есть один указатель, который мы будем использовать практически сразу - это 'finditem'. Сразу хочу обратить ваше внимание, что все имена указателей в скриптах всегда должны писаться в кавычках!

Ну, думаю, с теорией разобрались. Теперь ближе к инжекту.

Если у вас есть сериал объекта, который вы хотите использовать - тут все просто. Вставляйте его в соответствующую команду и все. Самая распространенная ошибка - это пытаться искать объект по сериалу. Этого делать не нужно. Игра (сервер, клиент, инжект) сама знает где лежит объект с таким сериалом. Если же он для вас недоступен (находится далеко) или вообще не существует - вы просто получите соответствующее сообщение. Но в инжекте есть возможность проверить местоположение конкретного объекта по сериалу, это команда ContainerOf.

UO.ContainerOf( object ) - возвращает параметр объекта object (по умолчанию - персонажа игрока) - контейнер, в котором находится этот объект.

То есть команда ContainerOf вернет вам сериал контейнера в котором находится ваш объект. Тут важно учитывать один аспект. Инжект и клиент "не помнят" что находится в закрытом контейнере, например, сундуке, если он с момента последнего запуска игры ни разу не открывался. И команда ContainerOf в этом случае вернет нам '0xFFFFFFFF' - что означает: на земле или неизвестно где (если предмет находится на земле, мы всегда сможем понять где он командами определения дистанции до объекта, об этом мы поговорим позже).

Давайте рассмотрим пример:
Code:
sub TestContOf()
VAR ser1 = '0x12345678', ser2
ser2 = UO.ContainerOf ( ser1 )
If ser2 <> '0xFFFFFFFF' Then
UO.Print( 'Сериал контейнера: ' + ser2 )
Endif
endsub

В данном примере в переменную ser1 у нас занесен сериал какого-то определенного предмета. Этот скрипт запросит сериал контейнера в котором находится наш объект (это может быть сундук, мешок, бекпак персонажа, банковский бокс), потом проверит, что вернула нам команда UO.ContainerOf - если объект недоступен или находится на земле - скрипт закончится, иначе - выведет сериал этого контейнера.

Теперь мы приходим к наиболее распространенной ситуации - когда нам неизвестен сериал объекта, который мы хотим использовать. Мы знаем только его тип и (необязательно) цвет. Тогда нам надо найти этот объект. Для такого поиска служит команда Findtype.

UO.FindType( type, [ color, containerobject/ground/my ] ) - ищет обьект указаного типа type и цвета color в указаном контейнере и помещает найденый обьект в системный указатель finditem.

Сразу отметим синтаксис указания команд. В круглых скобках после названия указываются параметры команды (я об этом уже писал), в квадратных - необязательные параметры, то есть параметры, которые можно не указывать. В данном случае единственным обязательным параметром является параметр type - то есть тип объекта для поиска. Результат поиска - то есть ссылка на конкретный найденный объект будет помещен в указатель finditem.

Теперь о параметрах:
Code:
Если тип type указан '-1' или '0xffff' то ищутся обьекты любого типа.
Если цвет color не указан, указан '-1' или '0xffff' то ищутся обьекты любого цвета.
Если контейнер object указан, то ищется в контейнере. Если не указан, указан '-1' или '0xffff', или указан ошибочно то ищутся обьекты в бекпаке персонажа.
указан 'ground' или '1' то обьект ищется на земле, в радиусе устанавливаемом ,set finddistance.
Если указан 'my' или '2' то ищется в бекпаке и всех подсумках.
Нельзя указывать контейнер для поиска не указав цвет color.

Например, UO.Findtype( '0x1BEF') будет искать инги (указан тип ингов) в паке персонажа (остальные параметры опущены, соответственно по умолчанию ищутся объекты любого цвета в паке персонажа). UO.Findtype( '0x1BEF', '0x0000' ) будет искать инги указанного цвета в паке персонажа. UO.Findtype( '0x1BEF', '0x0000', '0x12345678' ) будет искать инги указанного цвета в контейнере с сериалом '0x12345678'.

Не забывайте контролировать, что указанный контейнер хоть раз открывался за текущий сеанс игры. Если контейнер не открывался - инжект "не помнит" его содержимого и не сможет искать в нем (как открыть контейнер из скрипта я расскажу ниже).

Поиск остановится при нахождении первого найденного объекта, соответствующего условиям. Что же делать если нам нужен не он, а какой-то другой? Для этого используется команда Ignore.

UO.Ignore( object, [ on/off ] ) - указывает что обьект должен игнорироваться (или не игнорироваться, с параметром off) при последующих командах поиска, например findtype. Разрешить поиск всех обьектов снова можно командой ignorereset.

Я лично ни разу не пользовался переключателями on/off в этой команде, вполне достаточно что по умолчанию идет параметр on.

Обычно в скрипте идет поиск объекта по типу, потом проверяется - нужный ли мы объект нашли, если нет - найденное игнорируется и поиск повторяется. Для примера предположим что в паке лежат две кучки ингов, в одной 10 штук, в другой 100. Надо найту ту, в которой 100 ингов.
Code:
UO.Findtype( '0x1BEF' )
If UO.GetQuantity( 'finditem' ) == 10 Then
UO.Ignore( 'finditem' )
UO.Findtype( '0x1BEF' )
Endif

В данном примере мы ищем инги, потом проверяем командой GetQuantity (она считает количество объектов в указанной стопке), количество ингов в найденной стопке. Если количество равно 10 - игнорируем результат поиска и ищем снова.

Обратите внимание - мы используем указатель 'finditem' как объект. Именно так и есть - в этом указателе содержится ссылка на конкретный найденный объект последним поиском. Если же нам нужен (для каких-нибудь целей) сериал этого объекта, то нам нужно воспользоваться командой GetSerial:

VAR MySerial = UO.GetSerial( 'finditem' )

После такого "считывания" сериала найденного объекта мы можем использовать как MySerial, так и 'finditem' совершенно одинаково, только 'finditem' изменит свое содержимое при следующем поиске.

После находения нужного нам объекта (если мы использовали Ignore) желательно очистить список игнорируемых объектов командой IgnoreReset (чтобы не было проблем при последующих поисках).

UO.IgnoreReset() - Включает в поиск все обьекты, которые были указаны как игнорируемые командой Ignore.

Теперь можно приведенный выше код оформить отдельным скриптом:
Code:
sub FindIngs()
UO.Findtype( '0x1BEF' )
If UO.GetQuantity( 'finditem' ) == 10 Then
UO.Ignore( 'finditem' )
UO.Findtype( '0x1BEF' )
Endif
UO.Print( 'Сериал найденного объекта: ' + UO.GetSerial( 'finditem' ) )
UO.IgnoreReset()
endsub

Но этот скрипт работает только в данном конкретном случае, когда мы знаем что у нас в паке две кучки ингов, в одной из них 10 штук (ищем другую). А если их у нас много?

На самом деле поиск находит сразу все подходящие под условия объекты, но устанавливает указатель "finditem' на первый из них (первый с точки зрения инжекта, вы не можете узнать в каком порядке он их считает). Но вы всегда в скрипте можете узнать сколько подходящих объектов поиск нашел. Для этого служит команда FindCount.

UO.FindCount() - Возвращает количество обьектов, найденых последней командой FindType.

Как видите из синтаксиса, команда возвращает число - количество найденных объектов. Обычное применение этой команды - проверка найдено ли что-то подходящее под заданные условия. Например, вам надо в скрипте использовать инги в паке (скажем, для БСа). Вот пример:
Code:
UO.Findtype( '0x1BEF' )
If UO.FindCount() > 0 Then
.... ; используем найденный объект через указатель 'finditem')
Else
UO.Print( 'Нету ингов!' )
Endif

Теперь рассмотрим подробно один практический скрипт, хорошо иллюстрирующий вышеописанные команды. Давайте напишем скрипт, который будет искать вокруг нас разных чаров и выдавать нам их сериалы. Именно так устроены скрипты на поиск ПК. Для удобства (это все-таки пример) ограничимся поиском только мужских чаров, то есть чаров с типом '0x0190'. Как будет устроен такой скрипт? Скрипт будет в цикле искать вокруг вашего чара других чаров по типу, если находит - брать его сериал, определять расстояние до этого чара, выводить на экран сообщение об этом. После этого игнорировать этого чара и искать следующего. Напишем сначала общий цикл:
Code:
sub FindMen()
VAR SerChar, ColChar, NamChar, DistChar
Repeat
UO.FindType( '0x0190', '-1', '1' )
.........
Until UO.FindCount() == 0
UO.IgnoreReset()
endsub

Основным циклом я выбрал Repeat...Until потому что во-первых, мне надо чтобы хоть раз поиск производился, во-вторых, так как команда UO.FindCount() количество найденных чаров будет возвращать только после первого поиска, а поиск у нас производится уже внутри цикла. В самом деле, нельзя написать:
Code:
While UO.FindCount() > 0
UO.FindType(.....)
...........
Wend

так как на момент первой проверки в операторе While условия ни одного поиска произведено не было, а значит и UO.FindCount() быстрее всего вернет ошибку или случайное число.

В конце скрипта я сразу поставил команду UO.IgnoreReset(), так как внутри цикла мы точно будем использовать UO.Ignore(). Конечно, мы будем ее использовать только в случае успешности поиска, а если никого вокруг чара нету - цикл прервется после первого поиска и никаких чаров в игнор-список занесено не будет. Но это не страшно. UO.IgnoreReset() в этом случае просто ничего не сделает.

Также я завел четыре переменные: SerChar, ColChar, NamChar, DistChar. Для чего они - узнаете позже.

Продолжаем. Дополним наш скрипт проверкой результатов поиска:
Code:
sub FindMen()
VAR SerChar, ColChar, NamChar, DistChar
Repeat
UO.FindType( '0x0190', '-1', '1' )
If UO.FindCount() > 0 Then
...........
Else
wait( 500 )
Endif
Until UO.FindCount() == 0
UO.IgnoreReset()
endsub

Итак, внутри цикла в скрипте у нас появился оператор If...Endif, в котором мы проверяем, нашел ли последний поиск какого-либо чара. Если нашел - тут мы дальше будем писать какие-то действия, если не нашел - тут мы ставим небольшую паузу, чтобы избежать ошибки пустого цикла (см. урок 1). На самом деле у нас не будет пустого цикла, даже если мы не поставим паузы - у нас есть действие в цикле (это поиск), ну лучше перестраховаться. Идем дальше:
Code:
sub FindMen()
VAR SerChar, ColChar, NamChar, DistChar
Repeat
UO.FindType( '0x0190', '-1', '1' )
If UO.FindCount() > 0 Then
SerChar = UO.GetSerial( 'finditem' )
UO.Print( 'Нашли чара! Его сериал: ' + SerChar )
UO.Ignore( 'finditem' )
Else
wait( 500 )
Endif
Until UO.FindCount() == 0
UO.IgnoreReset()
endsub

Ну вот. В случае успешного поиска мы записываем в переменную SerChar сериал этого чара, потом выводим на экран сообщение с этим сериалом и даем команду игнорировать этого чара при следующих поисках. Что теперь происходит в скрипте? При запуске скрипт производит первый поиск, если никого рядом нету - ждет полсекунды и выходит из скрипта. Если же кто-то найден - берется его сериал, выводится сообщение, этот чар игнорируется при следующих поисках. Так как кто-то был найден - цикл будет продолжен (условие в until не выполняется). И так далее.

Теперь один важный момент. Когда я описывал параметры команды FindType, там упоминалась установка дистанции поиска на земле. Все дело в том, что инжект позволяет изменять расстояние, на котором мы будем искать необходимое нам на земле (то есть вокруг чара). Минимум - это 1 тайл (клетка), максимум - зависит от шарда, обычно это 12-14 тайлов. Это очень удобно. В самом деле - не всегда нужен поиск на максимальной дистанции, часто нужно поискать что-то совсем рядом с чаром, а на те объекты, что находятся вне пределов возможностей чара для использования лучше не обращать внимания. Эта установка производится через команду Set (через эту команду производится достаточно много разных установок, мы еще будем возвращаться к этой команде). Пока нас интересует параметр finddistance.

UO.Set( 'finddistance', '6' ) - устанавливает параметр finddistance в 6 тайлов (клеток).

Обратите внимание на синтаксис команды - и параметр, и значение пишутся в кавычках. Добавим эту команду в наш скрипт:
Code:
sub FindMen()
VAR SerChar, ColChar, NamChar, DistChar
UO.Set( 'finddistance', '6' )
Repeat
UO.FindType( '0x0190', '-1', '1' )
If UO.FindCount() > 0 Then
SerChar = UO.GetSerial( 'finditem' )
UO.Print( 'Нашли чара! Его сериал: ' + SerChar )
UO.Ignore( 'finditem' )
Else
wait( 500 )
Endif
Until UO.FindCount() == 0
UO.IgnoreReset()
endsub

Надо понимать - мы установили дистанцию для поиска командой FindType для всех скриптов, которые вы будете запускать в течение текущего сеанса игры. После перезапуска инжекта дистанция сбросится на дистанцию по умолчанию (вы можете ее посмотреть если наберете в клиенте команду ,set finddistance без значения).

Получился вполне рабочий скрипт. Единственное - информации о найденном чаре мало. Хочется больше о нем узнать. Нет проблем. Давайте расширять возможности скрипта. Сначала добавим определение расстояния до этого чара. Для этого используется команда UO.GetDistance (эта команда возвращает расстояние до объекта):
Code:
sub FindMen()
VAR SerChar, ColChar, NamChar, DistChar
UO.Set( 'finddistance', '6' )
Repeat
UO.FindType( '0x0190', '-1', '1' )
If UO.FindCount() > 0 Then
SerChar = UO.GetSerial( 'finditem' )
DistChar = UO.GetDistance( 'finditem' )
UO.Print( 'Нашли чара! Его сериал: ' + SerChar )
UO.Print( 'Расстояние до этого чара: ' + str( DistChar ) )
UO.Ignore( 'finditem' )
Else
wait( 500 )
Endif
Until UO.FindCount() == 0
UO.IgnoreReset()
endsub

У нас в скрипте появилась новая команда: str. Она написана в нестандартном синтаксисе, то есть без префикса UO. Эта команда (на самом деле тут у нас очередная небольшая путаница в терминологии, большинство команд, называемых мною, на самом деле является встроенными функциями, но выбор терминологии - право автора учебника ) относится к командам, встроенным в скриптовый модуль инжекта, их не так много, но мы в ближайшем будущем будем использовать только три, причем одну из них мы уже хорошо знаем:

str( число) - преобразует число в строку
int( строка) - преобразует строку в число
wait( число) - ну это вы уже знаете...

Другие команды, встроенные в скриптовый модуль (они все пишутся без префикса UO) мы будем рассматривать по мере необходимости.

Итак, теперь наш скрипт определяет расстояние до найденного чара и выводит о нем информацию. Продолжим. Еще было бы неплохо, определить - ПК или АПК этот чар. Инжект нам это позволяет сделать. Для этого нам потребуется команда GetNotoriety.

UO.GetNotoriety( object ) - возвращает параметр обьекта object (по умолчанию - персонажа игрока) - злобность (цвет). Значения такие:
1 - Innocent (синий), 2 - Friend (зелёный), 3 - Gray (серый), 4 - Criminal (серый), 5 - Enemy (рыжий), 6 - Murderer (красный).

Не на всех шардах есть все эти значения, поэтому мы не будем встраивать в скрипт преобразование числа в название цвета, добавим просто определение злобности и вывод номера:
Code:
sub FindMen()
VAR SerChar, ColChar, NamChar, DistChar
UO.Set( 'finddistance', '6' )
Repeat
UO.FindType( '0x0190', '-1', '1' )
If UO.FindCount() > 0 Then
SerChar = UO.GetSerial( 'finditem' )
DistChar = UO.GetDistance( 'finditem' )
ColChar = UO.GetNotoriety( 'finditem' )
UO.Print( 'Нашли чара! Его сериал: ' + SerChar )
UO.Print( 'Расстояние до этого чара: ' + str( DistChar ) )
UO.Print( 'Уровень злобности этого чара: ' + str( ColChar ) )
UO.Ignore( 'finditem' )
Else
wait( 500 )
Endif
Until UO.FindCount() == 0
UO.IgnoreReset()
endsub

Ну вот. Осталась только одна характеристика найденного чара, которую мы еще не выводим, это его имя. Добавим в скрипт и это, только сначала обращу ваше внимание на одну тонкость. Дело в том, что до тех пор, пока вы не кликнули по нему - инжект не знает имени этого чара и не может его предоставить нам. Учтем это. Заодно запомните очередную команду: Click.

UO.Click( object ) - эмулирует клик левой клавишей мышки по указанному объекту.

Ну и заодно:

UO.GetName( object ) - Возвращает параметр обьекта object (по умолчанию - персонажа игрока) - имя обьекта.

Добавляем. Сразу только укажу - после клика надо поставить какую-то паузу, чтобы дождаться реакции сервера на одиночный клик по чару (должно высветиться в игре имя чара). Вполне вероятно, что указанной мною паузы в полсекунды вам не хватит - тогда увеличьте ее.
Code:
sub FindMen()
VAR SerChar, ColChar, NamChar, DistChar
UO.Set( 'finddistance', '6' )
Repeat
UO.FindType( '0x0190', '-1', '1' )
If UO.FindCount() > 0 Then
SerChar = UO.GetSerial( 'finditem' )
DistChar = UO.GetDistance( 'finditem' )
ColChar = UO.GetNotoriety( 'finditem' )
UO.Click( 'finditem' )
wait( 500 )
NamChar = UO.GetName( 'finditem' )
UO.Print( 'Нашли чара! Его сериал: ' + SerChar )
UO.Print( 'Расстояние до этого чара: ' + str( DistChar ) )
UO.Print( 'Уровень злобности этого чара: ' + str( ColChar ) )
UO.Print( 'Имя этого чара: ' + NamChar )
UO.Ignore( 'finditem' )
Else
wait( 500 )
Endif
Until UO.FindCount() == 0
UO.IgnoreReset()
endsub

На этом второй урок закончен. В третьем уроке мы продолжим изучать работу с объектами в скриптах, а также изучим оператор for...next и массивы.

 
SaNeKДата: Среда, 24.09.2008, 15:34 | Сообщение # 3
Генералиссимус
Группа: Администраторы
Сообщений: 168
Репутация: 10
Статус: Offline
Урок 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
......
; взять этот рег из сундуку
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', Cont )
Wend
Next
UO.Print( 'The loot was finished' )
endsub

На этом третий урок завершен. Я рассказал вам все что хотел о объектах и работе с ними, в следующих уроках мы будем рассматривать другие темы.

 
SaNeKДата: Среда, 24.09.2008, 15:37 | Сообщение # 4
Генералиссимус
Группа: Администраторы
Сообщений: 168
Репутация: 10
Статус: Offline
Урок 4. Прицелы.

Начну с того что прицелом называется указатель - который указывает на предмет или область, над которым или которой в дальнейшем могут совершаться действия.

В инжекте, прицела как такового нету-он заменяется ловушкой для прицела. Чтобы объяснить приведу пример из жизни:

ключ-замочная скважина
ядерная ракета-пункт назначения

причём в инжекте, эти ловушки имеют не столь малые значения как ракета, и без них редко обходятся хорошие скрипты.

Вернёмся к ключу и ракете. Изначально вы задаёте прицел(ловушку) куда в дальнейшем пойдет ключ или ракета. Точно так же происходит и в инжекте- сначала мы прописываем ловушку для прицела, а затем уже само действие для предмета.

Если не понятно, объясню еще проще:

а)ловушка
б)действие,задающее прицел

ловушка поясняет инжекту, что как только появится прицел-читай меня, куда мне его направлять. Ну а действие предмета сами понимаете, выдаёт прицел который обработает ловушка. ( помоему уже проще некуда)
Причем отмечу что ловушки бывают не только для предметов,как я уже сказал ранее, но и для объектов и областей( тайлов ).

Ну а теперь поподробнее в инжект:

Первая команда с которой начну- Code:
uo.waittargetself()

Ловушка ставится на себя( тоесть прицел следует на вашего персонажа ).
Code:
uo.waittargetself()
uo.Cast('Greater Heal')

или
Code:
uo.waittargetself()
uo.UseType(bandages) # Бинты

Но сам я очень редко сталкиваюсь с такой ловушкой, практически никогда т.к. заменить всё это можно и проще:
Code:
uo.Cast('Greater Heal','self')

uo.bandageself()

Думаю принцип вам понятен(если до сих пор не поняли что такое ловушка читайте пока не дойдет-дальше хуже).

Следующей командой будет Code:
uo.waittargettype(type,[color])

Ловушка ставится на объект найденый в бекпеке и подсумках по типу(и цвету). Другими словами- ищет объект и ставит ловушку на него.

примером может являтся скил Poisoning: Code:

uo.waittargettype(' Type ')
uo.UseSkill('Poisoning')

Выбираем тип предмета, и кликаем на него, когда появляется прицел от скила-" Что травим ".
Если же у вас несколько предметов одного типа,на которые ставится ловушка(2 меча например)-проставьте так же и цвет.
Думаю тут всё понятно.Продолжу

Code:
uo.waittargetobject(object,[object2])

Эта команда, в отличии от предыдущей, ставит ловушку на определённый предмет(объект) который задаётся по ID.

Ну к примеру:
Code:
uo.waittargetobject('ID Rune')
uo.Cast('Recall')

Задаём ID руны, и вот вам скрипт на то чтобы быстро улететь с поля боя, или вовсе для удобства ).

Чтоже касается 2ого объекта:

В некоторых случаях появляются несколько прицелов в последовательности,- для этого и предназначен второй объект.Как только появится прицел-он попадёт в ловушку на первый объект, и если указан второй объект-то при появившемся втором прицеле-его поймает ловушка второго объекта.Думаю вы поняли ) продолжаю:

Следующей командой будет: Code:
uo.waittargetground(type,[color])

Ищет на земле объект по типу и цвету(если задано), и устанавливает на указанный объект ловушку прицела. Аналогично предыдущей команде.

Продолжу командой: Code:
uo.waittargetobjecttype(object,type,[color])

Она же совмещает 2 предыдущих команды, и устанавливает прицел на объект который ищется и по ID и по Типу и по Цвету.

Ну чтож. С объектами почти закончили, приступаем к области(тайлу)
Думаю вам известно, что прицелы нужны не только для объектов но и для тайлов-в пример приведу скрипты на мининг,фишинг, копание кладов и т.д. Рассмотрим поподробнее:
Code:
uo.waittargettile(lasttile/tilenum,[x],[y],[z])

- устанавливаем ловушку на тайл, который указан в параметрах. Это может быть как uo.waittargettile(lasttile) - тайл, на который кликали до этого, так и тайл который задаётся координатами- uo.waittargettile(tilenum,[x],[y],[z])

Что касается предыдущего тайла: Code:

if uo.InJournal('You put') then
uo.waittargettile(lasttile)
uo.UseType( PickAxe )

...

Типичная похожая конструкция, в скрипте на мининг. Выкопали- пробуем копать еще.
Что же касается указанного тайла, то думаю тут и так понятно,-указываем, действуем .

Ну вот и всё, что я вам могу рассказать о Прицелах,Ловушках и тому подобному =). В добавок прокоментирую следующие команды, которые возможно вам помогут:

Code:
uo.waittargetlast()

Прицел следует на предшествующий объект, на котором стояла ловушка. Другими словами- повторяет предыдущую ловушку .
Code:
uo.CancelTarget()

Обнуляем прицел.
Code:
uo.infotile

(,infotile) Узнаем информацию о тайле(координаты)

 
SaNeKДата: Среда, 24.09.2008, 15:38 | Сообщение # 5
Генералиссимус
Группа: Администраторы
Сообщений: 168
Репутация: 10
Статус: Offline
Урок 5. Работа с журналом инжекта

Пока писал, понял… писатель из меня никакой. Может, кто допишет.
А пока пользуемся тем что есть

Напишем простую программку. Она открывает банк и мешочек в нем
Code:

UO.Say("Bank") ;
UO.UseObject(0x01258856) ;

Пробуем, банк откроется, а вот мешочек нет. Дело в том, что ответ от сервера придет не мгновенно.
Переделаем...
Code:

UO.Say("Bank") ;
wait(1000)
UO.UseObject(0x01258856) ;

Все открылось. И будет открывается почти всегда. Только не устойчиво к лагам и сейвам.
Заменим статическую паузу на динамическую
Code:

UO.Say("Bank") ;
CheckLag()
UO.UseObject(0x01258856) ;

Вот и сама функция.
Code:

sub CheckLag()
UO.DeleteJournal() ; вытрем все сообщения в журнале (Inj, но не клиента)
UO.Click('backpack') ; одиночный клик по вашему backpack
; ждем сообщения в журнале
repeat
wait(100)
until UO.InJournal("Backpack")
; этот цикл завершится, если это сообщение появится.... замечу "Backpack" и "backpack"
; регистр важен Пишите точно что ждете
end sub

Многие с невероятным рвением тут же заменят все wait(ххх) на CheckLag(). ЧТО в корне не правильно
И точно не круто. Эта замечательная функция создана вовсе ни как универсальная динамическая пауза.
И у wait(ххх) есть свое назначение
Code:

UO.DeleteJournal() ; вытрем все сообщения в журнале
UO.Say("Bank") ;
; ждем сообщения в журнале
repeat
wait(100)
until UO.InJournal("your Bank Box")
; открываем мешок
UO.UseObject(0x01258856) ;
CheckLag() ; тут уместно так как мешок нам не сообщит что открыт

Теперь все пашет как часы. Это только на первый взгляд. Все рухнет, если мы не у банка и нет мешочка.
А любая программа считается рабочей пока не найдены условия когда она работать не сможет...
А они найдены. Далее правьте сами....

Рассмотрим теперь команды

Вот эта наверное самая главная

showjournal отобразить журнал Injection
Синтакс: ,showjournal [lines_num]
none uo.showjournal([lines_num])
Отображает в текстовом окне последние lines_num строк настоящего журнала Injection (по умолчанию 10).

Забиндим ее на клаву.. И будем всегда готовы ее нажать.
Только во время выполнения скрипта ее нажатие без смыслено по причине вот этой команды

DeleteJournal Очистка журнала
Синтакс: none uo.DeleteJournal()
Очищает журнал Injection. Учтите что журнал един для всех скриптов запущенных в данном экземпляре инжекта/клиента.
Команда выполняется чтобы отсечь уже отработанные варианты для команды InJournal

По этой причине будем чистить журнал не напалмом, а скальпелем
Code:

sub CheckLag()
DeleteJournal("Backpack") ; вытрим ТОЛЬКО нужные нам сообщения в журнале
UO.Click('backpack') ; одиночный клик по вашему backpack
; ждем сообщения в журнале
repeat
wait(100)
until UO.InJournal("Backpack")
end sub

Вот скальпель
Code:

sub DeleteJournal(msg) ; msg это параметр, см. выше как его передают
var nom=UO.InJournal(msg) ; ищем сообщение и в переменную его
if nom>0 then
UO.SetJournalLine(Nom - 1," ----- 8< ----- ") ; подменим сообщение
DeleteJournal(msg) ; вызов функцией самой себя, рекурсия
endif
endsub

InJournal Поиск в журнале текста
Синтакс: number uo.InJournal(text)
Ищет в журнале Injection строку, в которой встречается text, и возвращает её номер плюс 1, или возвращает 0 если
такая строка с момента последнего удаления журнала DeleteJournal не обнаружена. Номер может быть использован в
дальнейшем для функций Journal, JournalSerial, SetJournalLine (не забыть отнять единицу).
Максимальная длина журнала на данный момент 100 строк. Просмотреть последние строки журнала можно командой showjournal.

SetJournalLine Строка журнала: перезапись
Синтакс: none uo.SetJournalLine(number,text)
Перезаписывает текст в строке журнала номер number новым текстом text. Получить текст можно командой Journal.

Вот еще важная команда, думаю что в ее описании достаточный пример

JournalSerial Обьект связаный со строкой журнала
Синтакс: object uo.JournalSerial(number)
Возвращает сериал обьекта object связаного со строкой журнала номер number. Обычно это обьект, который произнёс
данную строку. Системные сообщения имеют обычно сериал 0x01010101. Для чтения данной строки используется Journal.
Так как функция Injournal возвращает номер строки в журнале +1, то можно воспользоваться например подобной комбинацией:
Code:
var name=uo.GetName(uo.JournalSerial(uo.InJournal("хавчик")-1))
if name<>"" then
uo.print(name+", хочешь кушать? :)")

Устаревшие команды .. Так для общего развития

LastMessage Последняя строка журнала
Синтакс: text uo.LastMessage()
Возвращает последнюю строку журнала Injection. Journal(0) возвращает то же что и LastMessage. Предпочтительно
использовать функцию InJournal для проверок в журнале.

Journal Строка журнала
Синтакс: text uo.Journal(number)
Возвращает строку журнала Injection номер number. Journal(0) возвращает то же что и LastMessage. Предпочтительно
использовать функцию InJournal для проверок в журнале.

Теперь рассмотрим более подробно приемы работы с журналом..

Вот скрипт который делает ключи.
Ждет сообщения сделал - не сделал
Code:

sub Tinker()
UO.CancelMenu()
UO.AutoMenu('Tinkering','Keys')
UO.AutoMenu('Keys','Iron key')
repeat
DeleteJournal("You put")
DeleteJournal("fail")
UO.Usetype(0x1EBC)
repeat
wait(100)
until UO.InJournal("You put") or UO.InJournal("fail")
until UO.Dead()
end sub

Вроде все работает, с максимальной скоростью, только если инструмент разрушится .... Зависнем
Code:
sub Tinker()
var LastTimer
UO.CancelMenu()
UO.AutoMenu('Tinkering','Keys')
UO.AutoMenu('Keys','Iron key')
repeat
if UO.Count(0x1BEF) and UO.Count(0x1EBC) then
DeleteJournal("You put")
DeleteJournal("fail")
DeleteJournal("You broke your tools")
LastTimer=UO.Timer()
UO.Usetype(0x1EBC)
repeat
wait(100)
until UO.InJournal("You put|fail|You broke your tools") or UO.Timer()>LastTimer+50
else
UO.CancelMenu()
return
endif
until UO.Dead()
end sub

Изменения. Скрипт теперь в формате инжи 505.хх Добавлено сообщение инструменту кирдык.
Добавлен таймер для исключения зависания. Проверка возможности крафта и выход из цикла.

 
SaNeKДата: Среда, 24.09.2008, 15:40 | Сообщение # 6
Генералиссимус
Группа: Администраторы
Сообщений: 168
Репутация: 10
Статус: Offline
Урок 6. Меню.

В этом уроке речь пойдёт о работе с меню(крафта),переодически появляющимися в повседневном мире уо.Разберу на конкретных примерах команды для работы ,а так же различные способы обрабатывания. Но сначала объясню "чайникам" на пальцах.

Меню - графический объект,содержащий в себе информацию, о возможном действии(превращении) над предметом. Другими словами:
1.Nightshade-предмет
2.Двойным кликом по реагенту, обрабатываем его и получаем долгожданное меню.
3.На большенстве шардов появится "рамочка с выбором" в верхнем левом углу(Меню крафта алхимии),теперь попродробнее как воплотить это в скриптах.

uo.WaitMenu('Заголовок','Выбор'['Заголовок2','Выбор2'])

Команда uo.WaitMenu содержит в себе информацию, по которой Injection будет посылать ответы при появлении того или иного меню.Сервер выдал меню- а инжект уже сам распорядился куда ему надо зайти и что скрафтить.

Заголовок -название самого меню,обычно пишется в верхней части меню.

Выбор -то что крафтим,или в какое следующее меню переходим из предыдущего.

Приведу несколько примеров:

Алхимия. Code:
sub Alchemy()
var garlick=' type '
uo.WaitMenu('What sort of potion do you want to','Cure')
uo.UseType(garlick)
end sub

В скрипте на алхимию,в уо при х2 клике на гарлик, появится меню которое обработает команда uo.WaitMenu -заглавием меню будет What sort of potion do you want to а выбором Cure

Инскрипт. Code:
sub Inscription()
var blanc=' type '
uo.WaitMenu('Spell Circle','First Circle','Spell Circle 1','Magic')
uo.UseType(blanc)
end sub

Заглавие Spell Circle Выбор First Circle Заглавие второго меню Spell Circle 1 Выбор во втором меню Magic Arrow

Тинкер. Code:
sub Tinkering()
var tools=' type '
uo.WaitMenu('Tinkering','Tools','Tools','empty bottle')
uo.UseType(tools)
end sub

Заглавие Tinkering выбор Tools заглавие Tools выбор empty bottle

Думаю хватит об этом, уже должно было зарубиться на носу,-приступим к следующей команде, которая разобьёт uo.WaitMenu на uo.AutoMenu ...

uo.AutoMenu (' Заголовок ',' Выбор ')
uo.AutoMenu (' Заголовок2 ',' Выбор2 ')

Принцип этой команды остаётся тем же, как и uo.WaitMenu , только она разбита на несколько пунктов.Приведу несколько примеров с теми же скриптами:
Code:
sub Tinkering()
var tools=' type '
uo.CancelMenu()
uo.AutoMenu('Tinkering','Tools')
wait(500)
uo.AutoMenu('Tools','empty bottle')
wait(500)
uo.UseType(tools)
end sub

Code:

sub Alchemy()
var garlick=' type '
uo.CancelMenu()
uo.AutoMenu('What sort of potion do you want to','Cure')
uo.UseType(garlick)
end sub

Code:
sub Inscription()
var blanc=' type '
uo.CancelMenu()
uo.AutoMenu('Spell Circle','First Circle')
wait(500)
uo.AutoMenu('Spell Circle 1','Magic')
uo.UseType(blanc)
end sub

Между AutoMenu разумно будет использовать паузу, дабы уменьшить вероятность сбивания скрипта.
А чтобы свести вероятность сбивания скрипта к нулю, перед меню ставим uo.CancelMenu -команда,которая уберёт все лишние меню, которые могут появиться в результате игрового процесса(ворлд сейвов и лаг).

Ну вобщемто и всё,напоследок лишь скажу что оформлять Выбор можно как:

а) Code:
(1),(2),(3)

... Цифрой, в порядке которой стоит нужный вам выбор, допустим:

Алхимия. Вам нужен Potion, который получается при двойном клике на 2ую менюшку, в порядке слева-направо:
Code:
uo.WaitMenu('What sort',(2))

Если у вас в меню будут стоять: Lesser Poison , Poison , Deadly Poison , то поставив (3) -вы сварите Deadly Poison. Думаю понятно.

б) Code:
(first),(second)

...

Аналогично, только не цифрами а английскими числительными (первое,второе)

в) Code:
(last)

Повторяем выбор предыдущего Potion'a

г) Code:
(random)

Injection сам выберет за вас,что ему сварить.

-----------------------------------------------------------------
Если что то забыл-добавьте. Сори за ошипки.
_________________
Уроки языка Injection
Основные команды языка Injection

Форум создан не только для того чтобы на нём писать, но и чтобы его читать. (с)

 
SaNeKДата: Среда, 24.09.2008, 15:43 | Сообщение # 7
Генералиссимус
Группа: Администраторы
Сообщений: 168
Репутация: 10
Статус: Offline
Урок 7. Работа с текстом в инжекте.
Заранее хочу извиниться перед читателями, за то, что не умею красиво оформлять код.

Итак, что же есть в инжекте для работы с текстом?

Команды
1. Len([text]) - длина строки
Пример использования: Code:
sub main()
var text='hello wolrd'
uo.print('length: ' + str( len(text) ) ) ; не забываем, что len возвращает число поэтому используем преобразовывание число-текст (str)
end sub

Скрипт выдаст нам фразу "length: 11"

2. LTrim([text]) - убрать пробелы слева
Пример использования: Code:
sub main()
var text=' hello wolrd'
uo.print(LTrim(text))
end sub

Скрипт выдаст нам фразу "hello world"

3. RTrim([text]) - убрать пробелы справа
Пример использования: Code:
sub main()
var text='hello wolrd '
uo.print(LTrim(text))
end sub

Скрипт выдаст нам фразу "hello world"

4. Trim([text]) - убрать пробелы слева и справа.
Пример использования вы, я надеюсь, уже поняли, поэтому скажу лишь, что из фразыCode:
' hello wold ' получим "hello world"

5. Left([text],numb) - ([строка], число символов), оставляет заданное количество символов от строки (с лева на право)
Пример использования: Code:
sub main()
var text='hello wolrd - i say!'
uo.print(Left(text,11))
end sub

Скрипт выдаст нам фразу "hello world"

6 Right([text],numb) - ([строка], число символов), оставляет заданное количество символов от строки (с права на лево)
Пример использования: Code:
sub main()
var text='i say: hello wolrd'
uo.print(Right(text,11))
end sub

Скрипт выдаст нам фразу "hello world"

7. Mid([text],numb,numb) - ([строка],позиция,число символов), оставляет заданное количество символов от строки (с лева на право - начиная с заданной позиции)
Пример использования: Code:
sub main()
var text='i say: hello wolrd - it sounds great'
uo.print(Mid(text,7,11))
end sub

Скрипт выдаст нам фразу "hello world"

Вобщем-то можно было бы обойтись и без Mid, но тогда пришлось бы делать очень длинные строчки с использованием Righ и Left - сами представьте, чтобы из фразы 'i say: hello wolrd - it sounds great' получить любимую фразу "hello world", нужно взять левые 11 сиволов от правых 29, иными словами это выглядело бы вот так: Code:
Left(Right(text,29),11)

так что настоятельно рекоммендую запомнить вам команду Mid (от англ. middle - середина), чтобы избежать лишней головной боли
Вот пожалуй и все, больше команд для работы с текстом в инжекте нет.. Конечно есть еще команды типа Code:
Str(numb) (число в текст), Val([text]) (текст (0-9) в число), IsString([text] / numb) - (текст ли перед нами?), IsNumber([text] / numb) - (число ли перед нами?)

но о них вы читале ранее.

Скрипты
Итак, со списком доступных команд мы ознакомились, примеры использования тоже поняли, остается извечный вопрос - зачем это надо? На этот вопрос каждый должен сам для себя ответить.. к примеру я использую это для удобной настройки скриптов (об этом далее), так же можно использовать это для выделения нужной информации из сроки и т.д.

Сейчас мы рассмотрим простейшие примеры использования работы с текстом из журнала.

Задача: определить сколько в руне зарядов и вывести полученную информацию на дисплей.
-
В подавляющем большинстве текстовых задач используется принципе перебора строки (с лева на право или с права на лево - это уж от поставленной задачи зависит) по 1 символу.. так поступим и здесь.
Решение: Code:
sub main()
uo.findtype('0x1F14',-1,2) ;type of rune
if uo.findcount() then
uo.click('finditem')
wait(100) ; тут лучше бы использовать checklag() (см. поиск)
uo.print('charges: ' + onlynumbers( uo.getname('finditem') ) ) ; будем надеиться что вы это проходили smile
end if
end sub

sub onlynumbers(string)
var i, j
var text=''
for i=0 to len(string) ; вот начинается этот самый перебор строки по 1 символу
for j=0 to 9 ; используется для "если символ (str) от 0 до 9, то.."
if mid(string,i,1)==str(j) then ; если текущий символ в строке равен (преобразованному в текст) числу от 0 до 9, то...
text = text + mid(string,i,1) ; ...то записываем его в переменную которая потом будет передана в исходный скрипт
end if
next
next
return text
end sub

Может это был не самый примитивный пример, но если попытаться разобраться - ничего сложного.

А если у нас разные типы предметов (в данном случае рун) и нужно определять заряды только у определенного типа\цвета\названия? Чтобы не городить огромные скрипты проще сделать массив с заданными параметрами а уж скрипт сам будет воспроизводить с ним нужные вам действия..
Дабы не перегружать ваш и без того измученный нашими уроками моск , пока ограничимся только типа и цветами.

Задача: Определить количество зарядов у рунразных типов но определенных цветов.
Решение:
Code:
sub main()
var i
Dim a[3]

#a[0]='[тип] [цвет] [отображаемое название]'
a[0]='0x1F12 0x0002 руны типа1'
a[1]='0x1F13 0x0001 руны типа2'
a[2]='0x1F14 0x0000 руны типа3'

for i=0 to 2
uo.findtype( Left(a[i],6), Mid(a[i],7,6), 'backpack' ) ; ищем по типу и цвету из массива
if uo.findcount() then
uo.click('finditem')
wait(100)
uo.print(Trim ( Right(a[i], len(a[i])-13) )+' charges: ' + onlynumbers ( uo.getname('finditem') ) )
end if
next
end sub

sub onlynumbers(string) ; используем все ту же функцию из предыдущего скрипта
var i, j
var text=''
for i=0 to len(string)
for j=0 to 9
if mid(string,i,1)==str(j) then
text = text + mid(string,i,1)
end if
next
next
return text
end sub

Скрипт выдаст нам фразы типа: "руны типа1 charges: 99"

Может быть когда в массиве 3 предмета это не так существенно.. а когда 10...?

Вот вам самостоятельная работа - попробуйте написать к примеру лог выкопанной руды для мининга используя массив вида: Code:
#a[0]='[color] [name]'
a[0]='0x0000 Iron Ore'
a[1]='0x0010 Cooper Ore'

...

Не получается? Что ж - если не получается дам подсказку - в цвете у предмета всего 6 символов (+ 1 пробел перед началом названия руды - в данном примере) итого получаем что нам нужно: Code:
uo.findtype('тип руды',Left(a[i],6),'backack')
...
uo.print(Right(a[i], len(a[i])-7 )+': '+ uo.getquantity('finditem') ) ; название определяется так: берем все что справа за исключением длины [color] слева (6 символов + 1 символ в качестве пробела).

Скрипт выдаст: "Iron Ore: 1230"

-
Вот пожалуй основные приемы при работе с текстом в инжекте.. Урок наш подходит к концу и напоследок я хотел бы сказать еще пару полезных вещей:

1. строку можно читать и задом-наперед используя шаг -1
Пример: Code:
for i=Len(string) to 0 step -1

2. В инжекте нет функции "удалить все пробелы из строки" поэтому можете использовать эту:
Code:
sub delsps(string)
#Mihail
var i, text=''
for i=0 to len(string)
if not mid(string,i,1)==' ' then
text=text+mid(string,i,1)
end if
next
return text
end sub

Пример использования писать не буду - теперь уже сами разберетесь

 
AgvilarДата: Пятница, 26.09.2008, 13:52 | Сообщение # 8
Рядовой
Группа: Пользователи
Сообщений: 14
Репутация: 0
Статус: Offline
это наверно в другой раздел)
ps Спасибо вам за информацию


Сообщение отредактировал Fallen - Вторник, 30.09.2008, 12:40
 
Форум » Обмен опытом » Макросы для Injection » УЧЕБНИК ИНЖЕКТ
  • Страница 1 из 1
  • 1
Поиск: