УРОК 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 данного форума.