Как написать скрипт на ламбер
Posted: 16.11.2006 23:36
Когда у меня найдется время на уроки - хз, но вот эту тему попробую расписать в подобной форме. Назовем ее, скажем:
УРОК 11
Внимание: в этом уроке не будет дано готового скрипта на ламбер! Но будут приведены необходимые функции и алгоритмы, так, чтобы желающий в этом разобраться мог написать себе такой скрипт сам, с учетом особенностей своего шарда.
Итак, ламбер. Что нам надо для хорошего ламбера? Во-первых, нам потребуется массив координат деревьев, их типов, а также, с учетом отсутствия удобной ходилки с обходом препятствий, массив координат в которых чар должен стоять перед деревьями. Естественно, писать такой массив в файл) сложно и не нужно, проще такое сделать на скрипте.
Потому заходим в игру на инжекте. Нам потребуется домик в лесу/около леса, рядом прилоченный/засечуренный сундук. Встаем около сундука и в инжекте запускаем этот скрипт:
Проведите чара от сундука по лесу, по разу рубя каждое рубимое дерево. Завершите маршрут снова около сундука.
На выходе у нас будет файл (не забудьте перекинуть координаты из текстового окна в файл) такого вида:
Теперь нам надо написать скрипт, который будет работать по такому файлу.
Для этого, для начала, нам надо определиться, в каком виде мы данные из этого файла будем использовать в скрипте. Считывать данные из файла мы можем через StringList (фактически - массив строк переменной длины), но использовать эти строки в скрипте не очень удобно. Гораздо лучше для этого годится Record.
Record (запись) - это, упрощенно, тоже массив, но уже многомерный. Каждой ячейке в нем соответствует несколько элементов (столько, сколько вы объявите). Это очень удобно для ламбера: каждый ячейка записи - это точка на маршруте чара, а в элементах ячейки сидят все необходимые данные для этой точки маршрута.
Здесь есть еще одна вещь: объявление type. В Паскале есть различные виды данных, типа integer (целые числа), string (строки), array (массивы). Для удобства программистов есть еще возможность объявить свой собственный тип данных, для этого и используется команда type. В приведенном выше коде мы объявляем тип данных под названием LumbRecord, который представляет из себя запись, каждая ячейка которого содержит пять целочисленных элемента, названия для этих элементов мы также задали.
Теперь мы можем объявлять любое количество нужных нам записей, просто используя LumbRecord как тип данных.
Мы создали массив записей с максимальной длиной 5000 ячеек. Вполне возможно, что у нас будет меньше точек на маршруте, это нестрашно, главное - чтобы не было больше.
Теперь надо занести в этот массив данные из файла.
Для этого будем использовать такую процедуру:
Разберем процедуру. Мы объявляем StringList под именем List, создаем его, загружаем в него файл и в цикле от 0 (то есть от начала) до List.Count-1 (List.Count - длина файла, так как мы считаем от 0 - то цикл идет до List.Count-1 элемента. Если вы этого не понимаете - это не ко мне. Читайте базовые учебники по программированию) перебираем строки файла, загруженные в StringList.
Так как мы будем разбирать строку на отдельные элементы через пробелы, то для удобства добавим в конец строки пробел (я для удобства делаю это уже в отдельной переменной s). Теперь функцией Copy(скопировать из строки s часть, начиная с 1 символа до позиции перед первым пробелом) выделяем символы первого числа, преобразуем его из строки в число и заносим в первый элемент данной ячейки нашего массива записей. Формат обращения к элементам ячеек таков:
После этого мы для удобства дальнейшей работы просто удаляем из строки символы начиная с 1 до первого пробела включительно. Дальше все точно также повторяется еще 5 раз (у нас 6 элементов в каждой ячейке массива).
В конце, после выхода из цикла, мы записываем в переменную MaxPosL получившуюся длину массива. Не забудьте объявить эту переменную в начале скрипта как целочисленную!
Теперь уже можно писать главную процедуру нашего скрипта. Что будет представлять из себя такой скрипт? Это будет цикл, в котором будет какой-то блок, отвечающий за перемещение чара по маршруту от сундука к сундуку обратно по лесу и рубку деревьев, какой-то блок отвечающий за разгрузку чара, еще какие-то блоки по вашему желанию (например, рес чара если он был убит, или взятие нового топора). Так и напишем:
Я сделал бесконечный цикл, но вы можете ограничить его чем-нибудь. Разгрузку и прочие действия вы будете писать сами, я дальше рассматриваю только первый блок, блок хождения и рубки.
Этот блок тоже будет представлять из себя цикл, но уже с конкретным количеством шагов, так что нам лучше всего подойдет цикл for...do:
Я сознательно упростил наши действия на каждом шаге цикла, оставив за бортом проверки на смерть чара, на макс вес и прочее. Все это вы можете уже добавить сами. Процедура LumbCurTree отвечает за рубку конкретного дерева, причем она получает в качестве параметров тип тайла и его координаты. В этой процедуре вы должны будете сделать какие-то необходимые проверки, использование топора и направление ловушки на данный тип тайла с заданными координатами. После этого необходимо проверить сообщения о успехе/физле рубки, если необходимо, повторить рубку в цикле, проверить вес и прочее. Но это уже обычно и тут на форуме есть примеры как это делать.
Функцию GotoXY() вы можете найти в разделе Scripts данного форума.
УРОК 11
Внимание: в этом уроке не будет дано готового скрипта на ламбер! Но будут приведены необходимые функции и алгоритмы, так, чтобы желающий в этом разобраться мог написать себе такой скрипт сам, с учетом особенностей своего шарда.
Итак, ламбер. Что нам надо для хорошего ламбера? Во-первых, нам потребуется массив координат деревьев, их типов, а также, с учетом отсутствия удобной ходилки с обходом препятствий, массив координат в которых чар должен стоять перед деревьями. Естественно, писать такой массив в файл) сложно и не нужно, проще такое сделать на скрипте.
Потому заходим в игру на инжекте. Нам потребуется домик в лесу/около леса, рядом прилоченный/засечуренный сундук. Встаем около сундука и в инжекте запускаем этот скрипт:
Code: Select all
sub MarkRail()
; ====================================================
; ВНИМАНИЕ! Это скрипт для инжекта, а не для стелса!!!
; ====================================================
; Скрипт разметки маршрута передвижения чара и копки/рубки
; Создает файл со строками вида:
; X Y TileType TileX TileY TileZ
; где: X, Y - координаты чара в узловой точке
; TileType - тип цели. То есть тип тайла или статики,
; которую либо рубим/либо копаем
; TileX, TileY, TileZ - координаты цели
; Узловые точки могут быть двух видов - либо тут копаем/рубим,
; либо тут чар должен повернуть при передвижении. Если второе, то
; последние четыре параметра равны 0. Учитывайте это в своих скриптах.
;
; Как работает? Записываются начальные координаты с нулями в четырех последних
; параметрах, запоминается направление взгляда чара, чистится журнал.
; Потом каждые 50 мс проверяются: не изменилось ли направление взгляда чара, не
; появилось ли сообщение в журнале о копке/рубке. Если одно из условий выполнено,
; то в файл записывается строка с текущими данными чара. То есть, если чар повернул,
; но копка/рубка не началась - пишется строка с четырьмя нулями в конце, если есть
; сообщение - пишутся координаты ласттайла и тип из-под него.
; Скрипт прекращает работу при появлении в журнале слова Finish, произнесенного
; данным чаром (проверяется по сериалу строки журнала).
;
; v.1.01b (с) Edred
;
; В данной версии данные пишутся в текстовое окно, а не файл.
; Также не проверяется сериал чара, сказавшего Finish.
;
VAR msg1 = 'You put the'
VAR msg2 = 'There is nothing'
VAR msgf = 'Finish'
VAR cx1, cy1, cdir1, tx1, ty1, tz1, ttyp1, oldx, oldy
UO.TextOpen()
UO.TextClear()
cx1 = UO.GetX()
cy1 = UO.GetY()
cdir1 = UO.GetDir()
UO.TextPrint(str(cx1) + ' ' + str(cy1) + ' ' + '0 0 0 0')
oldx = cx1
oldy = cy1
repeat
UO.DeleteJournal()
repeat
wait(50)
until UO.InJournal(msg1) OR UO.InJournal(msg2) OR UO.InJournal(msgf) OR UO.GetDir() <> cdir1
if UO.InJournal(msgf) then
return
endif
If UO.InJournal(msg1) OR UO.InJournal(msg2) Then
cx1 = UO.GetX()
cy1 = UO.GetY()
ttyp1 = UO.LastTile( 0 )
tx1 = UO.LastTile( 1 )
ty1 = UO.LastTile( 2 )
tz1 = UO.LastTile( 3 )
UO.TextPrint(str(cx1) + ' ' + str(cy1) + ' ' + str(ttyp1) + ' ' + str(tx1) + ' ' + str(ty1) + ' ' + str(tz1))
oldx = cx1
oldy = cy1
cdir1 = UO.GetDir()
Else
cx1 = UO.GetX()
cy1 = UO.GetY()
if (cx1 <> oldx) OR (cy1 <> oldy) then
UO.TextPrint(str(cx1) + ' ' + str(cy1) + ' ' + '0 0 0 0')
oldx = cx1
oldy = cy1
endif
cdir1 = UO.GetDir()
Endif
until false
endsub
На выходе у нас будет файл (не забудьте перекинуть координаты из текстового окна в файл) такого вида:
Code: Select all
3266 2767 0 0 0 0
3266 2766 3280 3265 2766 10
3266 2765 0 0 0 0
3265 2765 0 0 0 0
3262 2765 0 0 0 0
3259 2762 3291 3258 2762 10
3259 2760 3296 3258 2761 10
3259 2754 3286 3258 2754 10
3260 2754 0 0 0 0
.......
Для этого, для начала, нам надо определиться, в каком виде мы данные из этого файла будем использовать в скрипте. Считывать данные из файла мы можем через StringList (фактически - массив строк переменной длины), но использовать эти строки в скрипте не очень удобно. Гораздо лучше для этого годится Record.
Record (запись) - это, упрощенно, тоже массив, но уже многомерный. Каждой ячейке в нем соответствует несколько элементов (столько, сколько вы объявите). Это очень удобно для ламбера: каждый ячейка записи - это точка на маршруте чара, а в элементах ячейки сидят все необходимые данные для этой точки маршрута.
Code: Select all
type LumbRecord = Record
x,y,tt,tx,ty,tz : integer;
end;
Теперь мы можем объявлять любое количество нужных нам записей, просто используя LumbRecord как тип данных.
Code: Select all
var
LumberDim : array [0..5000] of LumbRecord;
Теперь надо занести в этот массив данные из файла.
Для этого будем использовать такую процедуру:
Code: Select all
procedure GetRail(FileNam : String);
var
List : TStringList;
i : integer;
s : string;
begin
List := TStringList.Create;
List.LoadFromFile(FileNam);
for i := 0 to List.Count-1 do
begin
s := List.strings[i] + ' ';
LumberDim[i].x := StrToInt(Copy(s,1,Pos(' ',s)-1));
Delete(s,1,Pos(' ',s));
LumberDim[i].y := StrToInt(Copy(s,1,Pos(' ',s)-1));
Delete(s,1,Pos(' ',s));
LumberDim[i].tt := StrToInt(Copy(s,1,Pos(' ',s)-1));
Delete(s,1,Pos(' ',s));
LumberDim[i].tx := StrToInt(Copy(s,1,Pos(' ',s)-1));
Delete(s,1,Pos(' ',s));
LumberDim[i].ty := StrToInt(Copy(s,1,Pos(' ',s)-1));
Delete(s,1,Pos(' ',s));
LumberDim[i].tz := StrToInt(Copy(s,1,Pos(' ',s)-1));
Delete(s,1,Pos(' ',s));
end;
MaxPosL := i;
end;
Так как мы будем разбирать строку на отдельные элементы через пробелы, то для удобства добавим в конец строки пробел (я для удобства делаю это уже в отдельной переменной s). Теперь функцией Copy(скопировать из строки s часть, начиная с 1 символа до позиции перед первым пробелом) выделяем символы первого числа, преобразуем его из строки в число и заносим в первый элемент данной ячейки нашего массива записей. Формат обращения к элементам ячеек таков:
Code: Select all
LumberDim[ячейка].элемент
В конце, после выхода из цикла, мы записываем в переменную MaxPosL получившуюся длину массива. Не забудьте объявить эту переменную в начале скрипта как целочисленную!
Теперь уже можно писать главную процедуру нашего скрипта. Что будет представлять из себя такой скрипт? Это будет цикл, в котором будет какой-то блок, отвечающий за перемещение чара по маршруту от сундука к сундуку обратно по лесу и рубку деревьев, какой-то блок отвечающий за разгрузку чара, еще какие-то блоки по вашему желанию (например, рес чара если он был убит, или взятие нового топора). Так и напишем:
Code: Select all
repeat
...ходим и рубим...
...разгружаемся...
...что-то еще...
until false;
Этот блок тоже будет представлять из себя цикл, но уже с конкретным количеством шагов, так что нам лучше всего подойдет цикл for...do:
Code: Select all
For k := 0 to MaxPosL-1 do
begin
GotoXY(LumberDim[k].x,LumberDim[k].y,0,true);
if LumberDim[k].tt <> 0 then LumbCurTree(LumberDim[k].tt,LumberDim[k].tx,LumberDim[k].ty,LumberDim[k].tz);
end;
Функцию GotoXY() вы можете найти в разделе Scripts данного форума.