PDA

Просмотр полной версии : Автоматизация движения по маршруту


NLObP
27.04.2008, 17:41
Организация движения чара по маршруту. Выдернул из скрипта рыбалки.
//Автоматизация движения по маршруту by NLObP для L2PacketHack v.3.1.8+//
program Move;

{
Скрипт распространяется как есть, и я не несу ответственности
за то, что ВЫ натворили у себя, его используя.
}

const
Name='NLObP'; //имя чара для которого включаем скрипт

//************************************************** *************
var
moveto1: TTimer;

distanciya:boolean;
MestoLovli, mov, i, j, MyID, MyXpos, MyYpos, MyZpos: integer;

//************************************************** *************
//Вызывается при включении скрипта
//************************************************** *************
procedure Init;
begin
MestoLovli:=1; //номер маршрута
//таймеры, можно поправить время по обстоятельствам
moveto1:=TTimer.Create(nil);
moveto1.OnTimer:=@Onmoveto1;
moveto1.enabled:=false;
moveto1.interval:=1000; //время задержки
end;

//************************************************** *************
//Вызывается при выключении скрипта
//************************************************** *************
procedure Free;
begin
moveto1.OnTimer := nil;
moveto1.Enabled := false;
moveto1.Interval := 0;
moveto1.Free;
end;

//************************************************** *************
// Все перемещения чара здесь!!!
//************************************************** *************
procedure OnMoveTo1(Sender: TObject);
begin
case mov of
//-------------------------------------------------
//1 бежим к фишерману в Гиран-харбор
//-------------------------------------------------
1100: MoveTo(51049,186286,-3672);
1101: MoveTo(50920,186425,-3631);
1102: MoveTo(50553,186269,-3631);
1103: MoveTo(49912,185723,-3561);
1104: MoveTo(49126,185867,-3491);
1105: MoveTo(48806,186219,-3491);
1106: Mov:=1315;
//-------------------------------------------------
//2 бежим к фишерману в Гиран-харбор
//-------------------------------------------------
1200: MoveTo(50931,185930,-3672);
1201: MoveTo(51030,186033,-3676);
1202: MoveTo(51065,186124,-3676);
1203: MoveTo(50987,186359,-3656);
1204: MoveTo(50837,186416,-3630);
1205: MoveTo(50620,186268,-3630);
1206: MoveTo(50397,186114,-3630);
1207: MoveTo(50152,185954,-3589);
1208: MoveTo(49912,185830,-3560);
1209: MoveTo(49625,185825,-3560);
1210: MoveTo(49347,185813,-3490);
1211: MoveTo(49118,185886,-3490);
1212: MoveTo(48942,186034,-3490);
1213: MoveTo(48786,186220,-3490);
1214: Mov:=1315;
//-------------------------------------------------
//3 бежим к фишерману в Гиран-харбор
//-------------------------------------------------
1300: MoveTo(52452,186940,-3665);
1301: MoveTo(52280,187089,-3631);
1302: MoveTo(52025,187265,-3631);
1303: MoveTo(51755,187315,-3631);
1304: MoveTo(51476,187101,-3631);
1305: MoveTo(51228,186902,-3631);
1306: MoveTo(50977,186692,-3631);
1307: MoveTo(50676,186423,-3631);
1308: MoveTo(50425,186213,-3631);
1309: MoveTo(50182,186015,-3599);
1310: MoveTo(49932,185836,-3560);
1311: MoveTo(49591,185850,-3560);
1312: MoveTo(49290,185853,-3490);
1313: MoveTo(49032,185921,-3490);
1314: MoveTo(48790,186223,-3490);
1315: begin
//мы у фишермана, покупаем крючки и обмениваем мусор на пруфы
MoveTo1.enabled:=false;
trade:=200;
trade1.enabled:=true;
TradeCount:=0;
Mov:=0;
msg.Lines.Add('Продадим/купим/обменяем...');
end;
//-------------------------------------------------
//1 бежим от фишермана на берег в Гиран-харбор
//-------------------------------------------------
2100: MoveTo(48786,186215,-3480);
2101: MoveTo(48922,186037,-3490);
2102: MoveTo(49058,185930,-3490);
2103: MoveTo(49170,185860,-3490);
2104: MoveTo(49585,185865,-3560);
2105: MoveTo(49908,185843,-3560);
2106: MoveTo(50121,185970,-3587);
2107: MoveTo(50502,186174,-3630);
2108: MoveTo(50701,186330,-3630);
2109: MoveTo(50904,186471,-3630);
2110: MoveTo(51062,186567,-3630);
2111: MoveTo(51164,186504,-3676);
2112: MoveTo(51381,186442,-3676);
2113: Mov:=2320;
//-------------------------------------------------
//2 бежим от фишермана на берег в Гиран-харбор
//-------------------------------------------------
2200: MoveTo(48781,186197,-3490);
2201: MoveTo(48899,186049,-3490);
2202: MoveTo(49066,185916,-3490);
2203: MoveTo(49222,185843,-3490);
2204: MoveTo(49580,185846,-3560);
2205: MoveTo(49783,185862,-3560);
2206: MoveTo(50012,185914,-3568);
2207: MoveTo(50191,186002,-3599);
2208: MoveTo(50375,186097,-3630);
2209: MoveTo(50515,186211,-3630);
2310: MoveTo(50619,186301,-3630);
2311: MoveTo(50715,186381,-3630);
2312: MoveTo(50831,186422,-3630);
2313: MoveTo(50949,186359,-3647);
2314: MoveTo(51033,186267,-3676);
2315: MoveTo(51100,186129,-3676);
2316: MoveTo(51001,186029,-3676);
2317: MoveTo(50933,185934,-3676);
2318: Mov:=2320;
//-------------------------------------------------
//3 бежим от фишермана на берег в Гиран-харбор
//-------------------------------------------------
2300: MoveTo(48784,186224,-3480);
2301: MoveTo(48906,186063,-3490);
2302: MoveTo(49037,185949,-3490);
2303: MoveTo(49200,185858,-3490);
2304: MoveTo(49601,185833,-3560);
2305: MoveTo(49844,185827,-3560);
2306: MoveTo(50200,186064,-3607);
2307: MoveTo(50448,186242,-3630);
2308: MoveTo(50648,186407,-3630);
2309: MoveTo(50848,186584,-3630);
2310: MoveTo(51077,186782,-3630);
2311: MoveTo(51258,186927,-3630);
2312: MoveTo(51424,187069,-3630);
2313: MoveTo(51630,187205,-3630);
2314: MoveTo(51787,187300,-3630);
2315: MoveTo(52019,187216,-3630);
2316: MoveTo(52192,187106,-3630);
2317: MoveTo(52329,187024,-3630);
2318: MoveTo(52482,186920,-3677);
2319: MoveTo(52568,186838,-3677);
2320: begin
MoveTo1.enabled:=false;
Mov:=0;
fishin.enabled:=true; //продолжим ловить рыбу
msg.Lines.Add('Продолжим ловить рыбу!!!');
end;
//-------------------------------------------------
//1 бежим после смерти на берег в Гиран-харбор...
//-------------------------------------------------
3100: MoveTo(48786,186215,-3480);
3101: MoveTo(48922,186037,-3490);
3102: MoveTo(49058,185930,-3490);
3103: MoveTo(49170,185860,-3490);
3104: MoveTo(49585,185865,-3560);
3105: MoveTo(49908,185843,-3560);
3106: MoveTo(50121,185970,-3587);
3107: MoveTo(50502,186174,-3630);
3108: MoveTo(50701,186330,-3630);
3109: MoveTo(50904,186471,-3630);
3110: MoveTo(51062,186567,-3630);
3111: MoveTo(51164,186504,-3676);
3112: MoveTo(51381,186442,-3676);
3113: Mov:=3317;
//-------------------------------------------------
//2 бежим после смерти на берег в Гиран-харбор...
//-------------------------------------------------
3200: MoveTo(48785,186203,-3490);
3201: MoveTo(48907,186068,-3490);
3202: MoveTo(49041,185940,-3490);
3203: MoveTo(49201,185825,-3490);
3204: MoveTo(49628,185829,-3560);
3205: MoveTo(49983,185850,-3560);
3206: MoveTo(50507,186220,-3630);
3207: MoveTo(50760,186382,-3630);
3208: MoveTo(50889,186435,-3630);
3209: MoveTo(51030,186278,-3676);
3210: MoveTo(51096,186134,-3676);
3211: MoveTo(50915,185939,-3676);
3212: Mov:=3317;
//-------------------------------------------------
//3 бежим после смерти на берег в Гиран-харбор...
//-------------------------------------------------
3300: MoveTo(48768,186185,-3490);
3301: MoveTo(48918,186002,-3490);
3302: MoveTo(49080,185890,-3490);
3303: MoveTo(49238,185821,-3490);
3304: MoveTo(49598,185839,-3560);
3305: MoveTo(49835,185826,-3560);
3306: MoveTo(50052,185868,-3568);
3307: MoveTo(50434,186189,-3630);
3308: MoveTo(50744,186457,-3630);
3309: MoveTo(51096,186752,-3630);
3310: MoveTo(51487,187037,-3630);
3311: MoveTo(51717,187227,-3630);
3312: MoveTo(51881,187325,-3630);
3313: MoveTo(52007,187299,-3630);
3314: MoveTo(52181,187192,-3630);
3315: MoveTo(52349,187025,-3630);
3316: MoveTo(52579,186835,-3676);
3317: begin
MoveTo1.enabled:=false;
Mov:=0;
if not isEquipRod then giverod;
delay(1000);
if not isEquipLure then givelure;
delay(1000);
fishin.enabled:=true; //продолжим ловить рыбу
msg.Lines.Add('Продолжим ловить рыбу!!!');
end;

//-------------------------------------------------
//1 меняем место
//-------------------------------------------------
4100: MoveTo(51384,186429,-3672);
4101: MoveTo(51219,186267,-3672);
4102: MoveTo(51036,186050,-3672);
4103: MoveTo(50932,185926,-3672);
4104: Mov:=4306;
//-------------------------------------------------
//2 меняем место
//-------------------------------------------------
4200: MoveTo(51090,186099,-3671);
4201: MoveTo(51076,186201,-3671);
4202: MoveTo(50977,186336,-3653);
4203: MoveTo(50876,186510,-3625);
4204: MoveTo(51181,186804,-3625);
4205: MoveTo(51365,186967,-3625);
4206: MoveTo(51572,187157,-3625);
4207: MoveTo(51752,187311,-3625);
4208: MoveTo(51955,187368,-3625);
4209: MoveTo(52123,187211,-3625);
4210: MoveTo(52334,187043,-3625);
4211: MoveTo(52586,186835,-3672);
4212: Mov:=4306;
//-------------------------------------------------
//3 меняем место
//-------------------------------------------------
4300: MoveTo(52359,187030,-3626);
4301: MoveTo(51784,187362,-3626);
4302: MoveTo(51365,186951,-3626);
4303: MoveTo(51087,186638,-3626);
4304: MoveTo(51275,186445,-3672);
4305: MoveTo(51378,186435,-3671);
4306: begin
MoveTo1.enabled:=false;
Mov:=0;
MMesto:=0;
fishin.enabled:=true; //продолжим ловить рыбу
msg.Lines.Add('Продолжим ловить рыбу на новом месте!!!');
end;
//-------------------------------------------------
//1 Репозиция на месте рыбалки после боя с мобом
//-------------------------------------------------
9100: begin
moveto1.interval:=500; //время задержки 0,5 сек
MoveTo(51333,186383,-3671);
end;
9101: MoveTo(51381,186427,-3671);
9102: Mov:=9302;
//-------------------------------------------------
//2 Репозиция на месте рыбалки после боя с мобом
//-------------------------------------------------
9200: begin
moveto1.interval:=500; //время задержки 0,5 сек
MoveTo(50966,185965,-3672);
end;
9201: MoveTo(50931,185931,-3672);
9202: Mov:=9302;
//-------------------------------------------------
//3 Репозиция на месте рыбалки после боя с мобом
//-------------------------------------------------
9300: begin
moveto1.interval:=500; //время задержки 0,5 сек
MoveTo(52589,186837,-3672);
end;
9301: MoveTo(52586,186837,-3672);
9302: begin
MoveTo1.enabled:=false;
Mov:=0;
fishin.enabled:=true; //продолжим ловить рыбу
msg.Lines.Add('Продолжим ловить рыбу!!!');
moveto1.interval:=1000; //время задержки 1 сек
end;
end;
end;

//************************************************** *************
//ПЕРЕМЕЩЕНИЕ:
//Идти в точку с координатами x,y,z
procedure MoveTo(TargetX,TargetY,TargetZ:integer);
begin
if PosInRange(TargetX,TargetY,TargetZ,100) then inc(mov)
else MoveTo2(TargetX,TargetY,TargetZ);
end;

//************************************************** *************
procedure MoveTo2(TargetX,TargetY,TargetZ:integer);
begin
//01=MoveBackwardToLocation:d(targetX)d(targetY)d(ta rgetZ)d(originX)d(originY)d(originZ)d(moveByMouse)
buf:=#$01;
WriteD(targetx); //куда
WriteD(targety);
WriteD(targetz);
WriteD(MyXpos); //откуда
WriteD(MyYpos);
WriteD(MyZpos);
WriteD(1); //используем 1-мышь 0-клавиатура
SendToServerEx(Name);
msg.Lines.Add('MoveTo('+inttostr(targetx)+','+intt ostr(targety)+','+inttostr(targetz)+')');
end;

//************************************************** *************
//Ориентация на местности:
//Проверка находится ли заданная точка в пределах досягаемости.
function PosInRange(targetx,targety,targetz,distanciya:exte nded):boolean;
begin
if delta(targetx, targety, MyXpos, MyYpos)<=distanciya
then result:=true else result:=false;
end;

//************************************************** *************
// вызывается при приходе каждого пакета, если скрипт включен
//************************************************** *************
begin
//************************************************** **************************
//не обрабатываем пустые пакеты
if pck='' then exit;

//************************************************** **************************
if (ConnectName=Name) and FromServer then begin
case pck[1] of
#$04: begin
//msg.Lines.Add('S>Пакет UserInfo #$04');
//пакет с инфой о моём чаре
i:=2;
MyXpos:=ReadD(i); //получаю координату х моего чара
MyYpos:=ReadD(i); //получаю координату у моего чара
MyZpos:=ReadD(i); //получаю координату z моего чара
//Запоминаем ИД
i:=18;
MyID:=ReadD(i); //получаю ид моего чара
end;
end;
end;
//************************************************** **************************
if (ConnectName=Name) and FromClient then begin
case pck[1] of
#$1B: begin
//msg.Lines.Add('C>Пакет RequestSicialAction #$1B');
//социальное действие
case ReadD(2) of
8: begin //unaware
case MestoLovli of
1: mov:=210;
2: mov:=220;
3: mov:=230;
end;
moveto1.enabled:=true;
//msg.Lines.Add('Бежим из магазина на берег...');
//не передаем серверу
pck:='';
end;
//для облечения написания маршрута (требуется панель информации!)
{ 11: begin //applaud - чекаем точку движения для внесения в скрипт.
info.Lines.Add(': begin');
info.Lines.Add(' if PosInRange('+inttostr(MyXpos)+','+inttostr(MyYpos) +','+inttostr(MyZpos)+',50) then inc(mov)');
info.Lines.Add(' else MoveTo('+inttostr(MyXpos)+','+inttostr(MyYpos)+',' +inttostr(MyZpos)+');');
info.Lines.Add('end;');
//не передаем серверу
pck:='';
end;}
12: begin //dance
case MestoLovli of
1: mov:=110;
2: mov:=120;
3: mov:=130;
end;
moveto1.enabled:=true;
//msg.Lines.Add('Бежим в магазин...');
//не передаем серверу
pck:='';
end;
end;
end;
//ValidatePosition пакет от клиента с моими кординатами
#$48: begin
//msg.Lines.Add('C>Пакет ValidatePosition #$48');
MyXpos:=ReadD(2); //получаю координату х моего чара
MyYpos:=ReadD(6); //получаю координату у моего чара
MyZpos:=ReadD(10); //получаю координату z моего чара
end;
end;
end;
end.

alexsl
13.05.2008, 18:08
маленькая лепта в скриптоводстве, возможно кому-нибудь понадобится.

что делает:
- автоматически записывает в файл маршрут следования.
- можно загрузить данные пути из файла
- передвигается по маршруту.

Для начала, нужно создать маршрут(ы), запись происходит так:
1. соц. действ. Да - начать запись
2 соц. действ. Нет - остановить.
(записывает в файл все события от клиента на движение юзера, событе мув))
=== вот примерная структкра файла (x,y,z)=========
|19007|145255|-3151|
|19016|144485|-3130|
|19124|144579|-3128|
|19112|144059|-3103|
======================================
Следование по маршруту:
1. соц.дейст. Виктори
(определяется ближ. чекпоинт из массива данных MovePath и следует к данной точке, если достигнит ее то переходит к следующей в зависимости от направления.)

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

зыы: интересно выслушать различные мнения по данному вопросу



var
// movement data
MovePath, // данные по которому мы будем двигатся в данный момент
MyFile: TStringList; // данные для записи пути
PointsCount: integer;
SavePathEnabled: boolean;
MoveToPathEnabled: boolean;
MoveToForward: boolean;
MoveStepIndex: integer;
MoveTimer: TTimer;
MoveStepTime: integer;
// self states
myX,myY,myZ: integer;
myID: integer;
myHP,myMP,myMaxHP,myMaxMP: integer;

const
MyFileName = 'c:\myfile.txt';
MyNick = 'МойНик';
interlude = false;
debug = false;

procedure Init; //Вызывается при включении скрипта
begin
MoveTimer := TTimer.Create(nil);
MoveTimer.Enabled := False;
MoveTimer.Interval := 1000;
MoveTimer.OnTimer := @OnMove;

buf:=hstr('0F');
SendToServerEX(MyNick);

MyFile:=TStringList.Create;
MovePath:=TStringList.Create;
try
MyFile.LoadFromFile(MyFileName);
except
end;
//ShowMessage(inttostr(ExtractValue('|100|12345|300| ',2))); // debug
end;

procedure Free; //Вызывается при выключении скрипта
begin
if MyFile<>nil then
begin
MyFile.Free;
end;
if MovePath<>nil then
MovePath.Free;
end;

function GetValue(ValName: string): string;
begin
result:=MyFile.Values[ValName];
end;

procedure SetValue(ValName: string; Value: string);
begin
MyFile.Values[ValName]:=Value;
end;

procedure StartRecord;
begin
if SavePathEnabled then
exit;
if MoveToPathEnabled then
begin
SendMsg('Во время следования по маршруту запись не возможна');
exit;
end;
MyFile.Clear;
PointsCount:=0;
SendMsg('Начата запись маршрута');
SavePathEnabled := True
end;

procedure StopRecord;
begin
if not SavePathEnabled then
exit;
MyFile.SaveToFile(MyFileName);
SendMsg('Запись маршрута завершена');
SavePathEnabled := False;
end;

procedure SendMsg(msg:string); // отправка системных сообщений клиенту
begin
buf:=#$4A;
WriteD(0);
WriteD(10);
WriteS('');
WriteS(msg);
SendToClientEx(MyNick);
end;

procedure ParseMoveClient;
var
i,x,y,z: integer; s: string;
begin
if not SavePathEnabled then
exit;
i:=2;
x:=readd(i);
y:=readd(i);
z:=readd(i);
inc(PointsCount);
s:='|'+inttostr(x)+'|'+inttostr(y)+'|'+inttostr(z) +'|';
MyFile.Add(s);
SendMsg('добавлен чекпоинт № '+inttostr(PointsCount));
end;

function delta(xpos1, ypos1, xpos2, ypos2:extended):integer; //возвращает переменную rezu которая является растоянием между 2 точками
var
dx,dy,summa: extended;
begin
dx:= xpos1-xpos2;
dy:= ypos1-ypos2;
summa:= dx*dx+dy*dy;
if summa = 0 then result:= 0 else result:= Round(sqrt(summa));
if debug then
SendMsg('delta='+inttostr(result));
{
try
result:= Round(Sqrt(((xpos1-xpos2)*(xpos1-xpos2))+((ypos1-ypos2)*(ypos1-ypos2))));
if debug then
SendMsg('delta='+inttostr(result));
except
result:=-1;
if debug then
SendMsg('error in delta');
end;
}
end;


function GetMinCheckPoint(PointsList: TStringList): integer;
var
i,m,min_dist: integer;
s: string;
x,y,z: integer;
begin
result:=-1;
min_dist:=-1;
if PointsList.Count<=1 then
exit;
for i:=0 to PointsList.count-1 do
begin
s:=PointsList[i];
y:=ExtractValue(s,2);
x:=ExtractValue(s,1);

if debug then
SendMsg(s+' x:='+inttostr(x)+' y:='+inttostr(y));
m:=delta(x,y,myx,myy);
if m>0 then
begin
if (result=-1) then
begin
min_dist:=m;
result:=i;
end
else
if m<min_dist then
begin
min_dist:=m;
result:=i;
end;
end;
end;
end;

//*********************************************
// основная процедура запуска на движение по маршруту
//*********************************************
procedure GoToPath(ToForward: boolean);
var
x,y,z,i: integer;
s: string;
begin
MoveToPathEnabled:= not MoveToPathEnabled;
MoveToForward:=ToForward;
if not MoveToPathEnabled then
begin
MoveTimer.Enabled:=False;
SendMsg('Следование по маршруту остановлено');
exit;
end;
//***********************
// берем путь из MyFile
MovePath.assign(MyFile);
//**********************
SendMsg('Пробуем выйти на путь...');
// сперва идем к ближайшему чекпоинту
i:= GetMinCheckPoint(MovePath);
if i<0 then
begin
SendMsg('чекпоинт не найден');
MoveToPathEnabled:=False;
end else
begin
SendMsg('найден ближайший чекпоинт бежим туды');
MoveToPathEnabled:=True;
MoveStepIndex:=i;
if debug then
SendMsg('checkpoint #'+inttostr(i));

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
MoveTo(x,y,z);
end;
MoveTimer.Enabled:=True;
end;

procedure OnMove(Sender: TObject);
var
x,y,z: integer; s: string;
begin
if not MoveToPathEnabled then
begin
TTimer(Sender).Enabled:=False;
if debug then
SendMsg('OnMove disabled');
exit;
end;

try
// проверяем на существ. объекта
// при отладке всякое может быть
MovePath.Count;
except
TTimer(Sender).Enabled:=False;
exit;
end;

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if PosInRange(x,y,z,100) then
begin
if MoveToForward then
begin
if MoveStepIndex=MovePath.Count-1 then
begin
MoveToPathEnabled:=False;
SendMsg('Мы по идее в конечной точке');
exit;
end
else
begin
inc(MoveStepIndex);
end;
end
else
begin
if MoveStepIndex>0 then dec(MoveStepIndex)
else
begin
MoveToPathEnabled:=False;
SendMsg('Мы по идее в начальной точке');
exit;
end;
end;
// мы достигли чекпоинта идем далее
SendMsg('бежим к #'+inttostr(MoveStepIndex));
s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
MoveTo(x,y,z);
end;
end;

function ExtractValue(sData: string;nIndex: integer): integer;
var
s: string;
i,j: integer;
begin
i:=0;j:=0;s:='';
s:=sData;
while j<nIndex do
begin
i:=pos('|',S);
if i>=0 then
begin
s:=copy(s,i+1,length(s)-i);
inc(j);
end
else
break;
end;
i:=pos('|',s);
if i>=0 then
s:=copy(s,1,i-1);
try
result:=strtoint(s);
except
end;
end;
//************************************************** ****************
//Bot by Skymanrus
//modified by NLObP специально для Владера, моего сына!
//ПЕРЕМЕЩЕНИЕ:
//Идти в точку с координатами x,y,z
//MOVETO(x,y,z)
procedure MoveTo(TargetX,TargetY,TargetZ:integer);
begin
//01=MoveBackwardToLocation:d(targetX)d(targetY)d(ta rgetZ)d(originX)d(originY)d(originZ)d(moveByMouse)
buf:=#$01;
WriteD(targetx); //куда
WriteD(targety);
WriteD(targetz);
WriteD(MyX); //откуда
WriteD(MyY);
WriteD(MyZ);
WriteD(1); //используем 1-мышь 0-клавиатура
SendToServerEx(MyNick);
end;

//Ориентация на местности:
//Проверка находится ли заданная точка в пределах досягаемости. Если да, то выполняется кусок скрипта в фигурных скобках {}.
function PosInRange(targetx,targety,targetz,distanciya:inte ger):boolean;
begin
if delta(targetx, targety, MyX, MyY)<=distanciya
then result:=true else result:=false;
end;

procedure UserInfo; // обновление донных о себе
var
i:word;
begin
MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
if interlude then i:=i+48 else i:=i+44;
MyMaxHP:=ReadD(i);
MyHP:=ReadD(i);
MyMaxMP:=ReadD(i); // чисто информативно
MyMP:=ReadD(i);
end;

procedure StatusUpdate; // обновление данных о себе
var
i:integer;
begin
for i:=0 to ReadD(6)-1 do
case pck[i*8+10] of
#$09: MyHP:=ReadD(i*8+14);
#$0A: MyMaxHP:=ReadD(i*8+14);
#$0B: MyMP:=ReadD(i*8+14);
#$0C: MyMaxMP:=ReadD(i*8+14);
end;
end;

//************************************************** *************

procedure OnConnect(WithClient: Boolean); //Вызывается при установке соединения
begin

end;

procedure OnDisonnect(WithClient: Boolean); //Вызывается при потере соединения
begin

end;

function iif(Bool: Boolean;aTrue: variant; aFalse: variant): variant;
begin
if Bool then
result:=aTrue
else
result:=aFalse;
end;

//основная часть скрипта
//вызывается при приходе каждого пакета если скрипт включен
var
i: integer;
begin
if FromClient and (ConnectName=MyNick)then
case pck[1] of
#$1B: // social
case pck[2] of
#$06: StartRecord; //Yes
#$05: StopRecord;//No
#$04: begin GoToPath(true); pck:=''; end;//attack!
end; //case
#$01: // move
ParseMoveClient;
#$48:
begin
myx:=ReadD(2);
myY:=ReadD(6);
myZ:=ReadD(10);
end;
end; // case
if FromServer and (ConnectName=MyNick) then
case pck[1] of
#$04: UserInfo;
#$0E: StatusUpdate;
end; // case
end.

DashKAaa
13.05.2008, 18:52
ппц откуда этот скрипт? сам писал?

alexsl
13.05.2008, 19:43
ппц откуда этот скрипт? сам писал?

так сказать на вольную тему (для изучения). естестено с встаками из готовых скриптов. Чтото конкретно интересует?

DashKAaa
13.05.2008, 20:15
да просто маштаб скрипта и функциональность его удивила, можно немножко его подправить и будет готовый фармер для S рецептиков)

Grinch
13.05.2008, 22:26
NLObP, а последнюю версию скрипта не выложишь она вроде у тя оптимизирована и писанины меньше, честно до фарма дальше записать пакеты разговора с нпц не ушёл :) а тут ты вроде уменьшил объём скрипта, плиз выложи если не затруднит :)

NLObP
14.05.2008, 02:10
маленькая лепта в скриптоводстве, возможно кому-нибудь понадобится.

что делает:
- автоматически записывает в файл маршрут следования.
- можно загрузить данные пути из файла
- передвигается по маршруту.

Надо попробовать развить скрипт в разрезе ASTAR (A*) алгоритма (http://coderx.ru/showpost.php?p=5305&postcount=5)

Добавлено через 1 час 16 минут
Следование по маршруту:
1. соц.дейст. Виктори

Здесь опечатка: надо Адвансе!

Потестил скрипт. Очень удобен в использовании. Из Гирана в Гиран-харбор 73 чекпоинта. Гном теперь бегает туда и обратно по маршруту как экспресс! В рыбалку можно засунуть и менять места станет намного легче.

alexsl
14.05.2008, 08:32
важно: скрипт токо для отладки

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

///////////////////////////////////////////////////////////////
// для: L2PacketHack by xkor
// посл. редактирование: 14.05.2008, 15:03msk, alexsl
// назначение: перемещение чара по заранее записаным маршруту(м)
//
// краткая инструкция:
//
// 1. прописать ник в MyNick
//
// - для записи пути в файл:
// 1. встаем на исходную позицию
// 2. в чат пишим "===rec test1" (test1 - или другое имя без пробелов)
// 3. бежим куда нужно. (желательно много не кликать на одно и тоже место. все клики записываются в файл)
// 4. в чат пишим "===save"
// 5. все. теперь данные записаны на диск, согласно настройкам и под именем test1 указ. в п.п.2
//
// - записываем требуемые пути с разными маршрутами и названиями
//
// - использование
// 1. бег до последнего чекпоинта(при достижении скрипт завершает работу):
// пишим в чат "===go test1" (test1 - название записанного маршрута)
// 2. бег до первого чекпоинта (при достижении скрипт завершает работу):
// пишим в чат "===back test1" (test1 - название записанного маршрута)
// 3. для остановки скрипта при передвижении: пишим в чат "===stop"
//
// как работает?: при запуске бежит к ближайшему чекпоинту и следует согласно направлению
// Использовались идеии, коды участников форума за, что спасибо
/////////////////////////////////////////////////////////////////////
var
// movement data
MovePath, // данные по которому мы будем двигатся в данный момент
RecordPath: TStringList; // данные для записи пути
RecordPathFileName: string; // название файла для записи
PointsCount: integer; // кол-во поинтов в процессе записи пути

SavePathEnabled: boolean; // флаг записи пути

MoveToPathEnabled: boolean; // флаг движения по пути
MoveToForward: boolean; // направление движения да-вперед, нет - назад
MoveStepIndex: integer; // текущ. чекпоинт (куды бежим сейчас)
MoveTimer: TTimer; //

old_X,old_Y,old_Z,old_time: integer;

myX,myY,myZ: integer; // наши статы
myID: integer;
myHP,myMP,myMaxHP,myMaxMP: integer;

const
MyNick = 'Мой ник';// <------------------------------
interlude = false;
debug = false;
// эта переменная указывает уничтожить пакет или нет если он обработан
// может данные нужны для других скриптов
EraseCommandFromChat = true;
//************************************************** *****
RecordFilesPath = 'c:\'; // путь где хранятся наши файлы
RecordPathName = 'recordmove'; // файл по умолчанию
RecordFileExt = '.txt';// расширение по умолчанию

RangeToCheckPoint = 150; // дистанция до чекпоинта при которой считается , что мы достигли оного
MoveTrigerDelay = 800; // срабатывание таймера на движение 0,8 сек

cmdPrefix = '===';// с этих символов начинается команда
cmdDlm = ' ';// разделитель параметров команды, параметры не должены содержать разделитель
// команды в общий чат
// пример
cmdRecordPath = 'rec'; // в общий чат "===rec giran1"
cmdSavePath = 'save'; // в общий чат "===save"
cmdMove = 'go'; // в общий чат "===go giran1"
cmdBack = 'back'; // в общий чат "===back giran1"
cmdStop = 'stop'; // останавливает следование по маршруту
//************************************************** *****


procedure Init; //Вызывается при включении скрипта
begin
MoveTimer := TTimer.Create(nil);
MoveTimer.Enabled := False;
MoveTimer.Interval := MoveTrigerDelay;
MoveTimer.OnTimer := @OnMove;

RecordPathFileName:='';

buf:=hstr('0F');
SendToServerEX(MyNick);

RecordPath:=TStringList.Create;
MovePath:=TStringList.Create;
end;

procedure Free; //Вызывается при выключении скрипта
begin
if RecordPath<>nil then
try
RecordPath.Free;
except
debugmsg('error free RecordPath');
end;

if MovePath<>nil then
try
MovePath.Free;
except
debugmsg('error free MovePath');
end;
end;

procedure debugmsg(s: string);
begin
if debug then
SendMsg(s);
end;

function GetValue(ValName: string): string;
begin
result:=RecordPath.Values[ValName];
end;

procedure SetValue(ValName: string; Value: string);
begin
RecordPath.Values[ValName]:=Value;
end;

procedure StartRecord;
begin
if SavePathEnabled then
exit;
if MoveToPathEnabled then
begin
SendMsg('Во время следования по маршруту запись не возможна');
exit;
end;
RecordPath.Clear;
PointsCount:=0;
SendMsg('Начата запись маршрута');
SavePathEnabled := True
end;

procedure StopRecord;
begin
if not SavePathEnabled then
exit;
// записываем
RecordPath.SaveToFile(GetRecordFileName);
SendMsg('Запись маршрута завершена');
SavePathEnabled := False;
end;

function GetRecordFileName: string;
begin
result:=RecordFilesPath+RecordPathFileName+RecordF ileExt;
end;

procedure SendMsg(msg:string); // отправка системных сообщений клиенту
begin
buf:=#$4A;
WriteD(0);
WriteD(10);
WriteS('');
WriteS(msg);
SendToClientEx(MyNick);
end;

procedure ParseMoveClient;
var
i,x,y,z: integer; s: string;
begin
if not SavePathEnabled then
exit;
i:=2;
x:=readd(i);
y:=readd(i);
z:=readd(i);
inc(PointsCount);
s:='|'+inttostr(x)+'|'+inttostr(y)+'|'+inttostr(z) +'|';
RecordPath.Add(s);
SendMsg('добавлен чекпоинт № '+inttostr(PointsCount));
end;

function delta(xpos1, ypos1, xpos2, ypos2:extended):integer; //возвращает переменную rezu которая является растоянием между 2 точками
var
dx,dy,summa: extended;
begin
try
dx:= xpos1-xpos2;
dy:= ypos1-ypos2;
summa:= dx*dx+dy*dy;
if summa = 0 then result:= 0 else result:= Round(sqrt(summa));
debugmsg('delta='+inttostr(result));
except
debugmsg('error in delta');
end;
end;


function GetMinCheckPoint(PointsList: TStringList): integer;
var
i,m,min_dist: integer;
s: string;
x,y,z: integer;
begin
result:=-1;
min_dist:=-1;
// проверка на наличие маршрута
if PointsList.Count=0 then
begin
exit;
MoveTimer.Enabled:=False;
MoveToPathEnabled:=False;
SendMsg('Нет данных по маршруту');
exit;
end;

try
for i:=0 to PointsList.count-1 do
begin
s:=PointsList[i];
y:=ExtractValue(s,2);
x:=ExtractValue(s,1);

debugMsg(s+' x:='+inttostr(x)+' y:='+inttostr(y));
m:=delta(x,y,myx,myy);
if m>0 then
begin
if (result=-1) then
begin
min_dist:=m;
result:=i;
end
else
if m<min_dist then
begin
min_dist:=m;
result:=i;
end;
end;
end;
except
debugMsg('error in GetMinCheckPoint');
end;//try
end;

procedure GoToPath(ToForward: boolean);
var
x,y,z,i: integer;
s: string;
begin
MoveToPathEnabled:= not MoveToPathEnabled;
MoveToForward:=ToForward;
if not MoveToPathEnabled then
begin
MoveTimer.Enabled:=False;
SendMsg('Следование по маршруту остановлено');
exit;
end;
//
// предположительно путь уже прописан в MovePath
//
SendMsg('Пробуем выйти на путь...');
// сперва идем к ближайшему чекпоинту
i:= GetMinCheckPoint(MovePath);
if i<0 then
begin
SendMsg('чекпоинт не найден');
MoveToPathEnabled:=False;
end else
begin
SendMsg('найден ближайший чекпоинт бежим туды');
MoveToPathEnabled:=True;
MoveStepIndex:=i;
if debug then
SendMsg('checkpoint #'+inttostr(i));

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if (old_x<>x) and (old_y<>y) and (old_z<>z) then
begin
MoveTo(x,y,z);
old_x:=x;
old_y:=y;
old_z:=z;
old_time:=0;
end;
end;
MoveTimer.Enabled:=True;
end;
//************************************************** *************
procedure OnMove(Sender: TObject);
var
x,y,z: integer; s: string;
begin
inc(old_time);// счетчик, сколько тиков прошло с последнего клика. исп. при следованию по маршруту
if not MoveToPathEnabled then
begin
try
TTimer(Sender).Enabled:=False;
except
end;
SendMsg('Движение остановлено');
exit;
end;
// возможно мы пали смертью храбрых, то не дергаемся пока
if myHP<=0 then
begin
sendmsg('Die');
MoveToPathEnabled:=False;
exit;
end;
debugmsg('hp:'+inttostr(myhp));
try
// проверяем на существ. объекта
// при отладке всякое может быть
MovePath.Count;
except
TTimer(Sender).Enabled:=False;
exit;
end;

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if PosInRange(x,y,z,RangeToCheckPoint) then
begin
if MoveToForward then
begin
if MoveStepIndex=MovePath.Count-1 then
begin
MoveToPathEnabled:=False;
SendMsg('Мы по идее в конечной точке');
exit;
end
else
begin
inc(MoveStepIndex);
end;
end
else
begin
if MoveStepIndex>0 then dec(MoveStepIndex)
else
begin
MoveToPathEnabled:=False;
SendMsg('Мы по идее в начальной точке');
exit;
end;
end;
// мы достигли чекпоинта идем далее
SendMsg('бежим к #'+inttostr(MoveStepIndex));
s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
MoveTo(x,y,z);
end;
end;

function ExtractValue(sData: string;nIndex: integer): integer;
var
s: string;
i,j: integer;
begin
i:=0;j:=0;s:='';
s:=sData;
while j<nIndex do
begin
i:=pos('|',S);
if i>=0 then
begin
s:=copy(s,i+1,length(s)-i);
inc(j);
end
else
break;
end;
i:=pos('|',s);
if i>=0 then
s:=copy(s,1,i-1);
try
result:=strtoint(s);
except
end;
end;
//************************************************** ****************
//Bot by Skymanrus
//modified by NLObP специально для Владера, моего сына!
//ПЕРЕМЕЩЕНИЕ:
//Идти в точку с координатами x,y,z
//MOVETO(x,y,z)
procedure MoveTo(TargetX,TargetY,TargetZ:integer);
begin
//01=MoveBackwardToLocation:d(targetX)d(targetY)d(ta rgetZ)d(originX)d(originY)d(originZ)d(moveByMouse)
buf:=#$01;
WriteD(targetx); //куда
WriteD(targety);
WriteD(targetz);
WriteD(MyX); //откуда
WriteD(MyY);
WriteD(MyZ);
WriteD(1); //используем 1-мышь 0-клавиатура
SendToServerEx(MyNick);
end;

//Ориентация на местности:
//Проверка находится ли заданная точка в пределах досягаемости. Если да, то выполняется кусок скрипта в фигурных скобках {}.
function PosInRange(targetx,targety,targetz,distanciya:inte ger):boolean;
begin
if delta(targetx, targety, MyX, MyY)<=distanciya
then result:=true else result:=false;
end;

procedure UserInfo; // обновление донных о себе
var
i:word;
begin
MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
i:=22;
ReadS(i);
if interlude then i:=i+48 else i:=i+44;
MyMaxHP:=ReadD(i);
MyHP:=ReadD(i);
MyMaxMP:=ReadD(i); // чисто информативно
MyMP:=ReadD(i);
end;

procedure StatusUpdate; // обновление данных о себе
var
i: integer;
begin
for i:=0 to ReadD(6)-1 do
case pck[i*8+10] of
#$09: MyHP:=ReadD(i*8+14);
#$0A: MyMaxHP:=ReadD(i*8+14);
#$0B: MyMP:=ReadD(i*8+14);
#$0C: MyMaxMP:=ReadD(i*8+14);
end;
end;

//************************************************** *************

procedure OnConnect(WithClient: Boolean); //Вызывается при установке соединения
begin

end;

procedure OnDisonnect(WithClient: Boolean); //Вызывается при потере соединения
begin

end;

function iif(Bool: Boolean;aTrue: variant; aFalse: variant): variant;
begin
if Bool then
result:=aTrue
else
result:=aFalse;
end;

function ParseCmd(cmd: string):boolean;
var
s: string;
i,j,k: integer;
params: array[0..9] of string; // до 10 параметров, должно хватить
begin
result:=False;
try
j:=-1;
i:=pos(cmdPrefix,trim(cmd));
if i=0 then
exit;
debugmsg('start ParseCmd: idx:'+inttostr(i)+' cmd: '+cmd);
result:=true;

k:=length(cmdPrefix);
s:=trim(lowercase(cmd));
s:=trim(copy(s,i+k,length(cmd)-i));
debugmsg('trim:'+s);
repeat
inc(j);
k:=pos(cmdDlm,s);
if k>0 then
begin
params[j]:=copy(s,1,k-1);
// s:=copy(s,k+length(cmdDlm),length(s)-k-length(cmdDlm));
s:=trim(copy(s,k+length(cmdDlm),length(s)-k));
debugmsg('extract idx:'+inttostr(j) +' param:'+params[j]);
end
else
begin
params[j]:=s;
debugmsg('parm is one');
end;
until pos(cmdDlm,S)=0;
if j>-1 then
begin
inc(j);
params[j]:=s;
debugmsg('extract idx:'+inttostr(j) +' param:'+params[j]);
end;
if j=-1 then
exit;
//************************************************** *****
// пропарсили команду
// теперь выполняем
//************************************************** *****
if params[0]=cmdRecordPath then
begin
if params[1]<>'' then
RecordPathFileName:=params[1]
else
RecordPathFileName:=RecordPathName;
StartRecord;
end
else
if params[0]=cmdSavePath then
begin
StopRecord;
end
else
if params[0]=cmdMove then
begin
if params[1]='' then
begin
SendMsg('хз куда бежать, укажите имя');
exit;
end;
try
MovePath.LoadFromFile(RecordFilesPath+params[1]+RecordFileExt);
except
SendMsg('файл пути не найден');
exit;
end;
GoToPath(true);
end
else
if params[0]=cmdBack then
begin
if params[1]='' then
begin
SendMsg('хз куда бежать, укажите имя');
exit;
end;
try
MovePath.LoadFromFile(RecordFilesPath+params[1]+RecordFileExt);
except
SendMsg('файл пути не найден');
exit;
end;
GoToPath(false);
end
else
if (params[0]=cmdStop) and MoveToPathEnabled then
MoveToPathEnabled:=False;

except
debugmsg('error in ParseCmd,params='+cmd);
end;
end;

//основная часть скрипта
//вызывается при приходе каждого пакета если скрипт включен
var
i: integer;
begin
if FromClient and (ConnectName=MyNick)then
case pck[1] of
{
#$1B: // social
case pck[2] of
#$06: StartRecord; //Yes
#$05: StopRecord;//No
#$04: begin GoToPath(true); pck:=''; end;
end; //case
}
#$01: // move
ParseMoveClient;
#$38: // say2
// если это команда и она обработана и надо очистить чат
if ParseCmd(ReadS(2)) and EraseCommandFromChat then
pck:='';// kill packet
#$48:
begin
myx:=ReadD(2);
myY:=ReadD(6);
myZ:=ReadD(10);
end;
end; // case
if FromServer and (ConnectName=MyNick) then
case pck[1] of
#$04: UserInfo;
#$0E: StatusUpdate;
end; // case
end.

Добавлено через 48 минут
Надо попробовать развить скрипт в разрезе ASTAR (A*) (http://coderx.ru/showpost.php?p=5305&postcount=5)
интересная идея, гдето видел геодату от явы сервера, вечерком посмотрю может можно будет прикрутить. ну а на счет оценки стоимости передвижения ... ммм .. какие идеи? вариант: бот камикадзе, бегает туды сюды тыкается или самому отмечать чекпоинты или если есть в геодате инфа о проходимости того или иного участка юзать ее.

mks
14.05.2008, 11:17
интересная идея, гдето видел геодату от явы сервера, вечерком посмотрю может можно будет прикрутить. ну а на счет оценки стоимости передвижения ... ммм .. какие идеи? вариант: бот камикадзе, бегает туды сюды тыкается или самому отмечать чекпоинты или если есть в геодате инфа о проходимости того или иного участка юзать ее.
да, на счет геодаты было бы круто, тогда перемещение бота можно было бы вообще сделать рандомным, что б он просто проверял возможность перемещения в определюнную точку сверяясь с маской геодаты.
ЗЫ а вообще в каком виде и где именно хранится геодата?

alexsl
14.05.2008, 13:31
да, на счет геодаты было бы круто, тогда перемещение бота можно было бы вообще сделать рандомным, что б он просто проверял возможность перемещения в определюнную точку сверяясь с маской геодаты.
ЗЫ а вообще в каком виде и где именно хранится геодата?

_http://l2j-geodata.sourceforge.net в общем геодата, есть общее описание но нет формата файла или не туды глядел. Может общими усилиями попробуем вычислить формат или гдето уже есть описание? или ну его нх :confused: игра не стои свеч
зы: ИМХО довольно удачно продуманный формат описания геодаты
че понял основное:
- мир резделен на 32*32 района/региона
- район разделен на 256*256 блоков
- блок разделен на 8*8 ячеек
- ячейка равняется 16*16 игровым units

ну и всякие вкусности, проверка возможности передвижения
в сторону из ячейки и т.д.

Grinch
14.05.2008, 15:55
ну геодата я пробывал раскопать файлы клиента единственно до чего добрался это программа для делания геодаты из файлов клиента картинку даже где то выкладывал.
мир состоит из 2-х типов геодаты рельеф и объектная т.е. рельеф он везде есть а объектная это каты, города, также есть третий тип но понему ходить нельзя он тупо является препятствием

alexsl
16.05.2008, 14:53
ну геодата я пробывал раскопать файлы клиента единственно до чего добрался это программа для делания геодаты из файлов клиента картинку даже где то выкладывал.
мир состоит из 2-х типов геодаты рельеф и объектная т.е. рельеф он везде есть а объектная это каты, города, также есть третий тип но понему ходить нельзя он тупо является препятствием

ага вот глянул сейчас в папке мапс, там файлы стандартно запакованы.
Можеш ли выложить описание структуры?

Grinch
16.05.2008, 23:26
ага вот глянул сейчас в папке мапс, там файлы стандартно запакованы.
Можеш ли выложить описание структуры?

панятия не имею какая там структура загугли может тебе повезёт

Добавлено через 7 часов 50 минут
возможно тебе повезло и в бекапе системы найду эти файлы, но вопрос в другом как раскрутить геодату сервера лутьше искать её :) и xkor вроде как то говорил что были у него какие то наработки в этом направление может поделиться опытом.

NLObP
17.05.2008, 04:30
Суперский скрипт от Alexsl с панелью управления. Из чата тоже можно.
Работает Rec Save Go Back Stop согласно описания ниже.
Остальное заготовка для рыбалки.
///////////////////////////////////////////////////////////////
// для: L2PacketHack by xkor
// посл. редактирование: 14.05.2008, 15:03msk, alexsl
// модифицировано by NLObP 17.05.2008
// назначение: перемещение чара по указанному маршруту
//
// краткая инструкция:
//
// 1. прописать ник в MyNick
//
// - для записи пути в файл:
// 1. встаем на исходную позицию
// 2. в чат пишим "===rec test1" (test1 - или другое имя без пробелов)
// 3. бежим куда нужно. (желательно много не кликать на одно и тоже место. все клики записываются в файл)
// 4. в чат пишим "===save"
// 5. все. теперь данные записаны на диск, согласно настройкам и под именем test1 указ. в п.п.2
//
// - записываем требуемые пути с разными маршрутами и названиями
//
// - использование
// 1. бег до последнего чекпоинта:
// пишим в чат "===go test1" (test1 - название записанного маршрута)
// 2. бег до первого чекпоинта:
// пишим в чат "===back test1" (test1 - название записанного маршрута)
// 3. остановить передвижение: пишим в чат "===stop"
//
// Использовались идеи, коды участников форума за, что спасибо
/////////////////////////////////////////////////////////////////////
const
MyNick = 'NLObP';// <------------------------------
interlude = false;
debug = true;
// эта переменная указывает уничтожить пакет или нет если он обработан
// может данные нужны для других скриптов
EraseCommandFromChat = true;
//************************************************** *****
RecordFilesPath = 'c:\'; // путь где хранятся наши файлы
RecordPathName = 'recordmove'; // файл по умолчанию
RecordFileExt = '.txt';// расширение по умолчанию

RangeToCheckPoint = 150; // дистанция до чекпоинта при которой считается , что мы достигли оного
MoveTrigerDelay = 800; // срабатывание таймера на движение 0,8 сек

cmdPrefix = '===';// с этих символов начинается команда
cmdDlm = ' ';// разделитель параметров команды, параметры не должены содержать разделитель
// команды в общий чат
// пример
cmdRecordPath = 'rec'; // в общий чат "===rec giran1"
cmdSavePath = 'save'; // в общий чат "===save"
cmdMove = 'go'; // в общий чат "===go giran1"
cmdBack = 'back'; // в общий чат "===back giran1"
cmdStop = 'stop'; // останавливает следование по маршруту
//************************************************** *****

var
// movement data
MovePath, // данные по которому мы будем двигатся в данный момент
RecordPath: TStringList; // данные для записи пути
RecordPathFileName: string; // название файла для записи
PointsCount: integer; // кол-во поинтов в процессе записи пути

SavePathEnabled: boolean; // флаг записи пути

MoveToPathEnabled: boolean; // флаг движения по пути
MoveToForward: boolean; // направление движения да-вперед, нет - назад
MoveStepIndex: integer; // текущ. чекпоинт (куды бежим сейчас)
MoveTimer: TTimer; //

old_X,old_Y,old_Z,old_time: integer;

myX,myY,myZ: integer; // наши статы
myID: integer;
myHP,myMP,myMaxHP,myMaxMP: integer;

splitter1, splitter2 : Tsplitter;
msg, stats: TMemo;
form1: TForm;
Panel1 : Tpanel;
Button1,Button2,Button3,Button4,Button5,Button6,Bu tton7,Button8 : TButton;
GroupBox1,GroupBox2,GroupBox3,GroupBox4 : TGroupBox;
ComboBox1,ComboBox2,ComboBox3,ComboBox4,ComboBox5, ComboBox6,ComboBox7,ComboBox8 : TComboBox;
CheckBox1,CheckBox2,CheckBox3,CheckBox4,CheckBox5, CheckBox6,CheckBox7,CheckBox8,CheckBox9,CheckBox10 ,CheckBox11,checkBox12,CheckBox13,CheckBox14,Check Box15,CheckBox16,CheckBox17,CheckBox18: TCheckBox;
Label1,Label2,Label3,Label4:TLabel;
Edit1:TEdit;

//************************************************** *************
procedure Init;
begin
MoveTimer := TTimer.Create(nil);
MoveTimer.Enabled := False;
MoveTimer.Interval := MoveTrigerDelay;
MoveTimer.OnTimer := @OnMove;

RecordPathFileName:='';

buf:=hstr('0F');
SendToServerEX(MyNick);

RecordPath:=TStringList.Create;
MovePath:=TStringList.Create;

//форма
form1:=TForm.Create(nil);
with form1 do
begin
Left:=0;
Top:=0;
Caption:='FishBot by NLObP v.0.10';
ClientHeight:=494;
ClientWidth:=613;
OnClose:=@FormClose;
end;

Panel1:=TPanel.Create(form1);
with Panel1 do
begin
parent:=form1;
Left:=0;
Top:=0;
Width:=425;
Height:=379;
Align:=alLeft;
TabOrder:=0;
end;

//статистика
Stats:=TMemo.Create(form1);
with Stats do
begin
parent:=form1;
Left:=428;
Top:=0;
Width:=185;
Height:=379;
Align:=alClient;
TabOrder:=1;
ScrollBars:=2;
end;
//сообщения
Msg:=TMemo.Create(form1);
with Msg do
begin
parent:=form1;
Left:=0;
Top:=382;
Width:=613;
Height:=112;
Align:=alBottom;
TabOrder:=2;
ReadOnly:=true;
ScrollBars:=2;
msg.Lines.Add('...');
end;

//разделители
splitter2:=Tsplitter.Create(form1);
with splitter2 do
begin
parent:=form1;
Top:=0;
Left:=425;
// Height:=379;
Width:=3;
Align:=alLeft;
end;
splitter1:=Tsplitter.Create(form1);
with splitter1 do
begin
parent:=form1;
Left:=0;
Height:=3;
Align:=alBottom;
end;

GroupBox1:=TGroupBox.Create(Panel1);
with GroupBox1 do
begin
parent:=Panel1;
Left:=1;
Top:=1;
Width:=423;
Height:=76;
Align:=alTop;
Caption:=' Movement ';
TabOrder:=0;
end;

Label1:=TLabel.Create(GroupBox1);
with Label1 do
begin
parent:=GroupBox1;
Left:=9;
Top:=18;
Width:=47;
Height:=13;
Caption:='FileName:';
end;

Button4:=TButton.Create(GroupBox1);
with Button4 do
begin
parent:=GroupBox1;
Left:=251;
Top:=42;
Width:=75;
Height:=25;
Caption:='Back';
TabOrder:=0;
OnClick:=@Button4Click;
end;

Button7:=TButton.Create(GroupBox1);
with Button7 do
begin
parent:=GroupBox1;
Left:=329;
Top:=42;
Width:=75;
Height:=25;
Caption:='Stop';
TabOrder:=1;
OnClick:=@Button7Click;
end;

Button3:=TButton.Create(GroupBox1);
with Button3 do
begin
parent:=GroupBox1;
Left:=173;
Top:=42;
Width:=75;
Height:=25;
Caption:='Go';
TabOrder:=2;
OnClick:=@Button3Click;
end;

Button2:=TButton.Create(GroupBox1);
with Button2 do
begin
parent:=GroupBox1;
Left:=90;
Top:=42;
Width:=75;
Height:=25;
Caption:='Save';
TabOrder:=3;
OnClick:=@Button2Click;
end;

Button1:=TButton.Create(GroupBox1);
with Button1 do
begin
parent:=GroupBox1;
Left:=9;
Top:=42;
Width:=75;
Height:=25;
Caption:='Rec';
TabOrder:=4;
OnClick:=@Button1Click;
end;

Edit1:=TEdit.Create(GroupBox1);
with Edit1 do
begin
parent:=GroupBox1;
Left:=56;
Top:=15;
Width:=109;
Height:=21;
TabOrder:=5;
Text:='recordmove';
end;

ComboBox8:=TComboBox.Create(GroupBox1);
with ComboBox8 do
begin
parent:=GroupBox1;
Left:=173;
Top:=15;
Width:=231;
Height:=21;
// Anchors:=[akLeft, akTop, akRight];
ItemHeight:=13;
TabOrder:=6;
Text:='ComboBox8';
OnChange:=@ComboBox8Change;
end;

GroupBox2:=TGroupBox.Create(Panel1);
with GroupBox2 do
begin
parent:=Panel1;
Left:=1;
Top:=77;
Width:=423;
Height:=239;
Align:=alNone;
//Anchors:=[akLeft, akTop, akRight];
Caption:=' Fishing ';
TabOrder:=1;
end;

Label2:=TLabel.Create(GroupBox2);
with Label2 do
begin
parent:=GroupBox2;
Left:=32;
Top:=164;
Width:=43;
Height:=13;
Caption:='FisherMan';
end;

ComboBox7:=TComboBox.Create(GroupBox2);
with ComboBox7 do
begin
parent:=GroupBox2;
Left:=90;
Top:=161;
Width:=314;
Height:=21;
//Anchors:=[akLeft, akTop, akRight];
ItemHeight:=13;
TabOrder:=0;
Text:='ComboBox7';
OnChange:=@ComboBox7Change;
end;

ComboBox6:=TComboBox.Create(GroupBox2);
with ComboBox6 do
begin
parent:=GroupBox2;
Left:=90;
Top:=137;
Width:=314;
Height:=21;
//Anchors:=[akLeft, akTop, akRight];
ItemHeight:=13;
TabOrder:=1;
Text:='ComboBox1';
OnChange:=@ComboBox6Change;
end;

CheckBox1:=TCheckBox.Create(GroupBox2);
with CheckBox1 do
begin
parent:=GroupBox2;
Left:=32;
Top:=18;
Width:=55;
Height:=17;
Caption:='Rod';
TabOrder:=2;
OnClick:=@CheckBox1Click;
end;

ComboBox1:=TComboBox.Create(GroupBox2);
with ComboBox1 do
begin
parent:=GroupBox2;
Left:=90;
Top:=16;
Width:=314;
Height:=21;
//Anchors:=[akLeft, akTop, akRight];
ItemHeight:=13;
TabOrder:=3;
Text:='ComboBox1';
OnChange:=@ComboBox1Change;
end;

ComboBox5:=TComboBox.Create(GroupBox2);
with ComboBox5 do
begin
parent:=GroupBox2;
Left:=90;
Top:=113;
Width:=314;
Height:=21;
//Anchors:=[akLeft, akTop, akRight];
ItemHeight:=13;
TabOrder:=4;
Text:='ComboBox1';
OnChange:=@ComboBox5Change;
end;

Button5:=TButton.Create(GroupBox2);
with Button5 do
begin
parent:=GroupBox2;
Left:=173;
Top:=206;
Width:=75;
Height:=25;
Caption:='Start';
TabOrder:=5;
OnClick:=@Button5Click;
end;

Button6:=TButton.Create(GroupBox2);
with Button6 do
begin
parent:=GroupBox2;
Left:=263;
Top:=206;
Width:=75;
Height:=25;
Caption:='Stop';
TabOrder:=6;
OnClick:=@Button6Click;
end;

CheckBox2:=TCheckBox.Create(GroupBox2);
with CheckBox2 do
begin
parent:=GroupBox2;
Left:=32;
Top:=39;
Width:=55;
Height:=23;
Caption:='Lure';
TabOrder:=7;
OnClick:=@CheckBox2Click;
end;

CheckBox3:=TCheckBox.Create(GroupBox2);
with CheckBox3 do
begin
parent:=GroupBox2;
Left:=32;
Top:=64;
Width:=55;
Height:=22;
Caption:='Weapon';
TabOrder:=8;
OnClick:=@CheckBox3Click;
end;

CheckBox4:=TCheckBox.Create(GroupBox2);
with CheckBox4 do
begin
parent:=GroupBox2;
Left:=32;
Top:=90;
Width:=52;
Height:=17;
Caption:='Shield';
TabOrder:=9;
OnClick:=@CheckBox4Click;
end;

CheckBox5:=TCheckBox.Create(GroupBox2);
with CheckBox5 do
begin
parent:=GroupBox2;
Left:=32;
Top:=115;
Width:=52;
Height:=17;
Caption:='FShot';
TabOrder:=10;
OnClick:=@CheckBox5Click;
end;

CheckBox6:=TCheckBox.Create(GroupBox2);
with CheckBox6 do
begin
parent:=GroupBox2;
Left:=32;
Top:=139;
Width:=52;
Height:=17;
Caption:='HPotion';
TabOrder:=11;
OnClick:=@CheckBox6Click;
end;

ComboBox2:=TComboBox.Create(GroupBox2);
with ComboBox2 do
begin
parent:=GroupBox2;
Left:=90;
Top:=40;
Width:=314;
Height:=21;
//Anchors:=[akLeft, akTop, akRight];
ItemHeight:=13;
TabOrder:=12;
Text:='ComboBox1';
OnChange:=@ComboBox2Change;
end;

ComboBox3:=TComboBox.Create(GroupBox2);
with ComboBox3 do
begin
parent:=GroupBox2;
Left:=90;
Top:=64;
Width:=314;
Height:=21;
//Anchors:=[akLeft, akTop, akRight];
ItemHeight:=13;
TabOrder:=13;
Text:='ComboBox1';
OnChange:=@ComboBox3Change;
end;

ComboBox4:=TComboBox.Create(GroupBox2);
with ComboBox4 do
begin
parent:=GroupBox2;
Left:=90;
Top:=88;
Width:=314;
Height:=21;
//Anchors:=[akLeft, akTop, akRight];
ItemHeight:=13;
TabOrder:=14;
Text:='ComboBox1';
OnChange:=@ComboBox4Change;
end;

CheckBox10:=TCheckBox.Create(GroupBox2);
with CheckBox10 do
begin
parent:=GroupBox2;
Left:=32;
Top:=189;
Width:=38;
Height:=17;
Caption:='PFO';
TabOrder:=15;
OnClick:=@CheckBox10Click;
end;

CheckBox11:=TCheckBox.Create(GroupBox2);
with CheckBox11 do
begin
parent:=GroupBox2;
Left:=32;
Top:=210;
Width:=45;
Height:=17;
Caption:='GFO';
TabOrder:=16;
OnClick:=@CheckBox11Click;
end;

GroupBox3:=TGroupBox.Create(Panel1);
with GroupBox3 do
begin
parent:=Panel1;
Left:=1;
Top:=318;
Width:=104;
Height:=51;
Align:=alNone;
Caption:=' Trade ';
TabOrder:=2;
end;

Button8:=TButton.Create(GroupBox3);
with Button8 do
begin
parent:=GroupBox3;
Left:=12;
Top:=20;
Width:=75;
Height:=25;
Caption:='Start';
TabOrder:=0;
OnClick:=@Button8Click;
end;

GroupBox4:=TGroupBox.Create(Panel1);
with GroupBox4 do
begin
parent:=Panel1;
Left:=111;
Top:=318;
Width:=313;
Height:=51;
//Anchors:=[akLeft, akTop, akRight];
Caption:=' Ready ';
TabOrder:=3;
end;

CheckBox7:=TCheckBox.Create(GroupBox4);
with CheckBox7 do
begin
parent:=GroupBox4;
Left:=16;
Top:=24;
Width:=73;
Height:=17;
Caption:='Fisherman';
TabOrder:=0;
end;

CheckBox8:=TCheckBox.Create(GroupBox4);
with CheckBox8 do
begin
parent:=GroupBox4;
Left:=95;
Top:=24;
Width:=58;
Height:=17;
Caption:='Fishing';
TabOrder:=1;
end;

CheckBox9:=TCheckBox.Create(GroupBox4);
with CheckBox9 do
begin
parent:=GroupBox4;
Left:=159;
Top:=24;
Width:=57;
Height:=17;
Caption:='Moving';
TabOrder:=2;
end;
form1.Show;
end;

//************************************************** *************
//Вызывается при выключении скрипта
//************************************************** *************
procedure Free;
begin
if RecordPath<>nil then
try
RecordPath.Free;
except
debugmsg('error free RecordPath');
end;

if MovePath<>nil then
try
MovePath.Free;
except
debugmsg('error free MovePath');
end;
Button1.Free;
Button2.Free;
Button3.Free;
Button4.Free;
Button5.Free;
Button6.Free;
Button7.Free;
Button8.Free;
ComboBox1.Free;
ComboBox2.Free;
ComboBox3.Free;
ComboBox4.Free;
ComboBox5.Free;
ComboBox6.Free;
ComboBox7.Free;
ComboBox8.Free;
CheckBox1.Free;
CheckBox2.Free;
CheckBox3.Free;
CheckBox4.Free;
CheckBox5.Free;
CheckBox6.Free;
CheckBox7.Free;
CheckBox8.Free;
CheckBox9.Free;
CheckBox10.Free;
CheckBox11.Free;
checkBox12.Free;
CheckBox13.Free;
CheckBox14.Free;
CheckBox15.Free;
CheckBox16.Free;
CheckBox17.Free;
CheckBox18.Free;
Label1.Free;
Label2.Free;
Label3.Free;
Label4.Free;
Edit1.Free;
GroupBox1.Free;
GroupBox2.Free;
GroupBox3.Free;
GroupBox4.Free;
Panel1.Free;
splitter1.free;
splitter2.free;
msg.Free;
stats.Free;
form1.Free;
end;

procedure Edit1Change(Sender: TObject);
begin
//
RecordPathFileName:=Edit1.text;
end;
procedure Button1Click(Sender: TObject);
begin
//
RecordPathFileName:=Edit1.text;
StartRecord;
end;

procedure Button2Click(Sender: TObject);
begin
//
StopRecord;
end;

procedure Button3Click(Sender: TObject);
begin
//идти в конец пути
RecordPathFileName:=Edit1.text;
try
MovePath.LoadFromFile(RecordFilesPath+RecordPathFi leName+RecordFileExt);
except
SendMsg('файл пути не найден');
exit;
end;
GoToPath(true);
end;

procedure Button4Click(Sender: TObject);
begin
//идти в начало пути
RecordPathFileName:=Edit1.text;
try
MovePath.LoadFromFile(RecordFilesPath+RecordPathFi leName+RecordFileExt);
except
SendMsg('файл пути не найден');
exit;
end;
GoToPath(false);
end;

procedure Button5Click(Sender: TObject);
begin
//
end;

procedure Button6Click(Sender: TObject);
begin
//
end;

procedure Button7Click(Sender: TObject);
begin
//
MoveToPathEnabled:=False;
//SendMsg('Движение остановлено');
end;

procedure Button8Click(Sender: TObject);
begin
//
end;

procedure CheckBox10Click(Sender: TObject);
begin
//
end;

procedure CheckBox11Click(Sender: TObject);
begin
//
end;

procedure CheckBox1Click(Sender: TObject);
begin
//
end;

procedure CheckBox2Click(Sender: TObject);
begin
//
end;

procedure CheckBox3Click(Sender: TObject);
begin
//
end;

procedure CheckBox4Click(Sender: TObject);
begin
//
end;

procedure CheckBox5Click(Sender: TObject);
begin
//
end;

procedure CheckBox6Click(Sender: TObject);
begin
//
end;

procedure ComboBox1Change(Sender: TObject);
begin
//
end;

procedure ComboBox2Change(Sender: TObject);
begin
//
end;

procedure ComboBox3Change(Sender: TObject);
begin
//
end;

procedure ComboBox4Change(Sender: TObject);
begin
//
end;

procedure ComboBox5Change(Sender: TObject);
begin
//
end;

procedure ComboBox6Change(Sender: TObject);
begin
//
end;

procedure ComboBox7Change(Sender: TObject);
begin
//
end;

procedure ComboBox8Change(Sender: TObject);
begin
//
end;
//************************************************** ****************************
procedure FormClose(Sender: TObject; var Action: TCloseAction);
begin
//Action:=caNone;
end;

procedure debugmsg(s: string);
begin
if debug then
SendMsg(s);
end;

function GetValue(ValName: string): string;
begin
result:=RecordPath.Values[ValName];
end;

procedure SetValue(ValName: string; Value: string);
begin
RecordPath.Values[ValName]:=Value;
end;

procedure StartRecord;
begin
if SavePathEnabled then
exit;
if MoveToPathEnabled then
begin
SendMsg('Во время следования по маршруту запись не возможна');
exit;
end;
RecordPath.Clear;
PointsCount:=0;
SendMsg('Начата запись маршрута');
SavePathEnabled := True
end;

procedure StopRecord;
begin
if not SavePathEnabled then
exit;
// записываем
RecordPath.SaveToFile(GetRecordFileName);
SendMsg('Запись маршрута завершена');
SavePathEnabled := False;
end;

function GetRecordFileName: string;
begin
result:=RecordFilesPath+RecordPathFileName+RecordF ileExt;
end;

procedure SendMsg(msg:string); // отправка системных сообщений клиенту
begin
buf:=#$4A;
WriteD(0);
WriteD(10);
WriteS('');
WriteS(msg);
SendToClientEx(MyNick);
end;

procedure ParseMoveClient;
var
i,x,y,z: integer; s: string;
begin
if not SavePathEnabled then
exit;
i:=2;
x:=readd(i);
y:=readd(i);
z:=readd(i);
inc(PointsCount);
s:='|'+inttostr(x)+'|'+inttostr(y)+'|'+inttostr(z) +'|';
RecordPath.Add(s);
SendMsg('добавлен чекпоинт № '+inttostr(PointsCount));
end;

function delta(xpos1, ypos1, xpos2, ypos2:extended):integer; //возвращает переменную rezu которая является растоянием между 2 точками
var
dx,dy,summa: extended;
begin
try
dx:= xpos1-xpos2;
dy:= ypos1-ypos2;
summa:= dx*dx+dy*dy;
if summa = 0 then result:= 0 else result:= Round(sqrt(summa));
debugmsg('delta='+inttostr(result));
except
debugmsg('error in delta');
end;
end;

function GetMinCheckPoint(PointsList: TStringList): integer;
var
i,m,min_dist: integer;
s: string;
x,y,z: integer;
begin
result:=-1;
min_dist:=-1;
// проверка на наличие маршрута
if PointsList.Count=0 then
begin
exit;
MoveTimer.Enabled:=False;
MoveToPathEnabled:=False;
SendMsg('Нет данных по маршруту');
exit;
end;

try
for i:=0 to PointsList.count-1 do
begin
s:=PointsList[i];
y:=ExtractValue(s,2);
x:=ExtractValue(s,1);

debugMsg(s+' x:='+inttostr(x)+' y:='+inttostr(y));
m:=delta(x,y,myx,myy);
if m>0 then
begin
if (result=-1) then
begin
min_dist:=m;
result:=i;
end
else
if m<min_dist then
begin
min_dist:=m;
result:=i;
end;
end;
end;
except
debugMsg('error in GetMinCheckPoint');
end;//try
end;

procedure GoToPath(ToForward: boolean);
var
x,y,z,i: integer;
s: string;
begin
MoveToPathEnabled:= not MoveToPathEnabled;
MoveToForward:=ToForward;
if not MoveToPathEnabled then
begin
MoveTimer.Enabled:=False;
SendMsg('Следование по маршруту остановлено');
exit;
end;
//
// предположительно путь уже прописан в MovePath
//
SendMsg('Пробуем выйти на путь...');
// сперва идем к ближайшему чекпоинту
i:= GetMinCheckPoint(MovePath);
if i<0 then
begin
SendMsg('чекпоинт не найден');
MoveToPathEnabled:=False;
end else
begin
SendMsg('найден ближайший чекпоинт бежим туды');
MoveToPathEnabled:=True;
MoveStepIndex:=i;
if debug then
SendMsg('checkpoint #'+inttostr(i));

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if (old_x<>x) and (old_y<>y) and (old_z<>z) then
begin
MoveTo(x,y,z);
old_x:=x;
old_y:=y;
old_z:=z;
old_time:=0;
end;
end;
MoveTimer.Enabled:=True;
end;

//************************************************** *************
procedure OnMove(Sender: TObject);
var
x,y,z: integer; s: string;
begin
inc(old_time);// счетчик, сколько тиков прошло с последнего клика. исп. при следованию по маршруту
if not MoveToPathEnabled then
begin
try
TTimer(Sender).Enabled:=False;
except
end;
SendMsg('Движение остановлено');
exit;
end;
// возможно мы пали смертью храбрых, то не дергаемся пока
if myHP<=0 then
begin
sendmsg('Die');
MoveToPathEnabled:=False;
exit;
end;
debugmsg('hp:'+inttostr(myhp));
try
// проверяем на существ. объекта
// при отладке всякое может быть
MovePath.Count;
except
TTimer(Sender).Enabled:=False;
exit;
end;

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if PosInRange(x,y,z,RangeToCheckPoint) then
begin
if MoveToForward then
begin
if MoveStepIndex=MovePath.Count-1 then
begin
MoveToPathEnabled:=False;
SendMsg('Мы по идее в конечной точке');
exit;
end
else
begin
inc(MoveStepIndex);
end;
end
else
begin
if MoveStepIndex>0 then dec(MoveStepIndex)
else
begin
MoveToPathEnabled:=False;
SendMsg('Мы по идее в начальной точке');
exit;
end;
end;
// мы достигли чекпоинта идем далее
SendMsg('бежим к #'+inttostr(MoveStepIndex));
s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
MoveTo(x,y,z);
end;
end;

function ExtractValue(sData: string;nIndex: integer): integer;
var
s: string;
i,j: integer;
begin
i:=0;j:=0;s:='';
s:=sData;
while j<nIndex do
begin
i:=pos('|',S);
if i>=0 then
begin
s:=copy(s,i+1,length(s)-i);
inc(j);
end
else
break;
end;
i:=pos('|',s);
if i>=0 then
s:=copy(s,1,i-1);
try
result:=strtoint(s);
except
end;
end;

//************************************************** ****************
//Идти в точку с координатами x,y,z
procedure MoveTo(TargetX,TargetY,TargetZ:integer);
begin
//01=MoveBackwardToLocation:d(targetX)d(targetY)d(ta rgetZ)d(originX)d(originY)d(originZ)d(moveByMouse)
buf:=#$01;
WriteD(targetx); //куда
WriteD(targety);
WriteD(targetz);
WriteD(MyX); //откуда
WriteD(MyY);
WriteD(MyZ);
WriteD(1); //используем 1-мышь 0-клавиатура
SendToServerEx(MyNick);
end;

//Проверка находится ли заданная точка в пределах досягаемости.
function PosInRange(targetx,targety,targetz,distanciya:inte ger):boolean;
begin
if delta(targetx, targety, MyX, MyY)<=distanciya
then result:=true else result:=false;
end;

procedure UserInfo; // обновление донных о себе
var
i:word;
begin
MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
i:=22;
ReadS(i);
if interlude then i:=i+48 else i:=i+44;
MyMaxHP:=ReadD(i);
MyHP:=ReadD(i);
MyMaxMP:=ReadD(i); // чисто информативно
MyMP:=ReadD(i);
end;

procedure StatusUpdate; // обновление данных о себе
var
i: integer;
begin
for i:=0 to ReadD(6)-1 do
case pck[i*8+10] of
#$09: MyHP:=ReadD(i*8+14);
#$0A: MyMaxHP:=ReadD(i*8+14);
#$0B: MyMP:=ReadD(i*8+14);
#$0C: MyMaxMP:=ReadD(i*8+14);
end;
end;

//************************************************** *************

procedure OnConnect(WithClient: Boolean); //Вызывается при установке соединения
begin

end;

procedure OnDisonnect(WithClient: Boolean); //Вызывается при потере соединения
begin

end;

function iif(Bool: Boolean;aTrue: variant; aFalse: variant): variant;
begin
if Bool then
result:=aTrue
else
result:=aFalse;
end;

function ParseCmd(cmd: string):boolean;
var
s: string;
i,j,k: integer;
params: array[0..9] of string; // до 10 параметров, должно хватить
begin
result:=False;
try
j:=-1;
i:=pos(cmdPrefix,trim(cmd));
if i=0 then
exit;
debugmsg('start ParseCmd: idx:'+inttostr(i)+' cmd: '+cmd);
result:=true;

k:=length(cmdPrefix);
s:=trim(lowercase(cmd));
s:=trim(copy(s,i+k,length(cmd)-i));
debugmsg('trim:'+s);
repeat
inc(j);
k:=pos(cmdDlm,s);
if k>0 then
begin
params[j]:=copy(s,1,k-1);
// s:=copy(s,k+length(cmdDlm),length(s)-k-length(cmdDlm));
s:=trim(copy(s,k+length(cmdDlm),length(s)-k));
debugmsg('extract idx:'+inttostr(j) +' param:'+params[j]);
end
else
begin
params[j]:=s;
debugmsg('parm is one');
end;
until pos(cmdDlm,S)=0;
if j>-1 then
begin
inc(j);
params[j]:=s;
debugmsg('extract idx:'+inttostr(j) +' param:'+params[j]);
end;
if j=-1 then
exit;
//************************************************** *****
// пропарсили команду
// теперь выполняем
//************************************************** *****
if params[0]=cmdRecordPath then
begin
if params[1]<>'' then
RecordPathFileName:=params[1]
else
RecordPathFileName:=RecordPathName;
StartRecord;
end
else
if params[0]=cmdSavePath then
begin
StopRecord;
end
else
if params[0]=cmdMove then
begin
if params[1]='' then
begin
SendMsg('хз куда бежать, укажите имя');
exit;
end;
try
MovePath.LoadFromFile(RecordFilesPath+params[1]+RecordFileExt);
except
SendMsg('файл пути не найден');
exit;
end;
GoToPath(true);
end
else
if params[0]=cmdBack then
begin
if params[1]='' then
begin
SendMsg('хз куда бежать, укажите имя');
exit;
end;
try
MovePath.LoadFromFile(RecordFilesPath+params[1]+RecordFileExt);
except
SendMsg('файл пути не найден');
exit;
end;
GoToPath(false);
end
else
if (params[0]=cmdStop) and MoveToPathEnabled then
MoveToPathEnabled:=False;

except
debugmsg('error in ParseCmd,params='+cmd);
end;
end;

//основная часть скрипта
//вызывается при приходе каждого пакета если скрипт включен
var
i: integer;
begin
if FromClient and (ConnectName=MyNick)then
case pck[1] of
{
#$1B: // social
case pck[2] of
#$06: StartRecord; //Yes
#$05: StopRecord;//No
#$04: begin GoToPath(true); pck:=''; end;
end; //case
}
#$01: // move
ParseMoveClient;
#$38: // say2
// если это команда и она обработана и надо очистить чат
if ParseCmd(ReadS(2)) and EraseCommandFromChat then
pck:='';// kill packet
#$48:
begin
myx:=ReadD(2);
myY:=ReadD(6);
myZ:=ReadD(10);
end;
end; // case
if FromServer and (ConnectName=MyNick) then
case pck[1] of
#$04: UserInfo;
#$0E: StatusUpdate;
end; // case
end.

wanick
08.12.2008, 22:00
вот

///////////////////////////////////////////////////////////////
// для: L2PacketHack by xkor
// посл. редактирование: 14.05.2008, 15:03msk, alexsl
// переделка под протокол русского оффа by Wanick 08.12.2008
// назначение: перемещение чара по заранее записаным маршруту(м)
//
// краткая инструкция:
//
// 1. прописать ник в MyNick
//
// - для записи пути в файл:
// 1. встаем на исходную позицию
// 2. в чат пишим "===rec test1" (test1 - или другое имя без пробелов)
// 3. бежим куда нужно. (желательно много не кликать на одно и тоже место. все клики записываются в файл)
// 4. в чат пишим "===save"
// 5. все. теперь данные записаны на диск, согласно настройкам и под именем test1 указ. в п.п.2
//
// - записываем требуемые пути с разными маршрутами и названиями
//
// - использование
// 1. бег до последнего чекпоинта(при достижении скрипт завершает работу):
// пишим в чат "===go test1" (test1 - название записанного маршрута)
// 2. бег до первого чекпоинта (при достижении скрипт завершает работу):
// пишим в чат "===back test1" (test1 - название записанного маршрута)
// 3. для остановки скрипта при передвижении: пишим в чат "===stop"
//
// как работает?: при запуске бежит к ближайшему чекпоинту и следует согласно направлению
// Использовались идеии, коды участников форума за, что спасибо
/////////////////////////////////////////////////////////////////////
var
// movement data
MovePath, // данные по которому мы будем двигатся в данный момент
RecordPath: TStringList; // данные для записи пути
RecordPathFileName: string; // название файла для записи
PointsCount: integer; // кол-во поинтов в процессе записи пути

SavePathEnabled: boolean; // флаг записи пути

MoveToPathEnabled: boolean; // флаг движения по пути
MoveToForward: boolean; // направление движения да-вперед, нет - назад
MoveStepIndex: integer; // текущ. чекпоинт (куды бежим сейчас)
MoveTimer: TTimer; //

old_X,old_Y,old_Z,old_time: integer;

myX,myY,myZ: integer; // наши статы
myID: integer;
myHP,myMP,myMaxHP,myMaxMP: integer;

const
MyNick = 'мой ник';// <------------------------------
interlude = false;
debug = false;
// эта переменная указывает уничтожить пакет или нет если он обработан
// может данные нужны для других скриптов
EraseCommandFromChat = true;
//************************************************** *****
RecordFilesPath = 'c:\'; // путь где хранятся наши файлы
RecordPathName = 'recordmove'; // файл по умолчанию
RecordFileExt = '.txt';// расширение по умолчанию

RangeToCheckPoint = 150; // дистанция до чекпоинта при которой считается , что мы достигли оного
MoveTrigerDelay = 800; // срабатывание таймера на движение 0,8 сек

cmdPrefix = '===';// с этих символов начинается команда
cmdDlm = ' ';// разделитель параметров команды, параметры не должены содержать разделитель
// команды в общий чат
// пример
cmdRecordPath = 'rec'; // в общий чат "===rec giran1"
cmdSavePath = 'save'; // в общий чат "===save"
cmdMove = 'go'; // в общий чат "===go giran1"
cmdBack = 'back'; // в общий чат "===back giran1"
cmdStop = 'stop'; // останавливает следование по маршруту
//************************************************** *****


procedure Init; //Вызывается при включении скрипта
begin
MoveTimer := TTimer.Create(nil);
MoveTimer.Enabled := False;
MoveTimer.Interval := MoveTrigerDelay;
MoveTimer.OnTimer := @OnMove;

RecordPathFileName:='';

//запрос на itemList вместе с ним приходит пакет UserInfo
//нужен для первоначального определения позиции
buf:=hstr('14');
SendToServerEX(MyNick);

RecordPath:=TStringList.Create;
MovePath:=TStringList.Create;
end;

procedure Free; //Вызывается при выключении скрипта
begin
if RecordPath<>nil then
try
RecordPath.Free;
except
debugmsg('error free RecordPath');
end;

if MovePath<>nil then
try
MovePath.Free;
except
debugmsg('error free MovePath');
end;
end;

procedure debugmsg(s: string);
begin
if debug then
SendMsg(s);
end;

function GetValue(ValName: string): string;
begin
result:=RecordPath.Values[ValName];
end;

procedure SetValue(ValName: string; Value: string);
begin
RecordPath.Values[ValName]:=Value;
end;

procedure StartRecord;
begin
if SavePathEnabled then
exit;
if MoveToPathEnabled then
begin
SendMsg('Во время следования по маршруту запись не возможна');
exit;
end;
RecordPath.Clear;
PointsCount:=0;
SendMsg('Начата запись маршрута');
SavePathEnabled := True
end;

procedure StopRecord;
begin
if not SavePathEnabled then
exit;
// записываем
RecordPath.SaveToFile(GetRecordFileName);
SendMsg('Запись маршрута завершена');
SavePathEnabled := False;
end;

function GetRecordFileName: string;
begin
result:=RecordFilesPath+RecordPathFileName+RecordF ileExt;
end;

{procedure SendMsg(msg:string); // отправка системных сообщений клиенту
begin
buf:=#$4A;
WriteD(0);
WriteD(10);
WriteS('');
WriteS(msg);
SendToClientEx(MyNick);
end; }

procedure ParseMoveClient;
var
i,x,y,z: integer; s: string;
begin
if not SavePathEnabled then
exit;
i:=2;
x:=readd(i);
y:=readd(i);
z:=readd(i);
inc(PointsCount);
s:='|'+inttostr(x)+'|'+inttostr(y)+'|'+inttostr(z) +'|';
RecordPath.Add(s);
SendMsg('добавлен чекпоинт № '+inttostr(PointsCount));
end;

function delta(xpos1, ypos1, xpos2, ypos2:extended):integer; //возвращает переменную rezu которая является растоянием между 2 точками
var
dx,dy,summa: extended;
begin
try
dx:= xpos1-xpos2;
dy:= ypos1-ypos2;
summa:= dx*dx+dy*dy;
if summa = 0 then result:= 0 else result:= Round(sqrt(summa));
debugmsg('delta='+inttostr(result));
except
debugmsg('error in delta');
end;
end;


function GetMinCheckPoint(PointsList: TStringList): integer;
var
i,m,min_dist: integer;
s: string;
x,y,z: integer;
begin
result:=-1;
min_dist:=-1;
// проверка на наличие маршрута
if PointsList.Count=0 then
begin
exit;
MoveTimer.Enabled:=False;
MoveToPathEnabled:=False;
SendMsg('Нет данных по маршруту');
exit;
end;

try
for i:=0 to PointsList.count-1 do
begin
s:=PointsList[i];
y:=ExtractValue(s,2);
x:=ExtractValue(s,1);

debugMsg(s+' x:='+inttostr(x)+' y:='+inttostr(y));
m:=delta(x,y,myx,myy);
if m>0 then
begin
if (result=-1) then
begin
min_dist:=m;
result:=i;
end
else
if m<min_dist then
begin
min_dist:=m;
result:=i;
end;
end;
end;
except
debugMsg('error in GetMinCheckPoint');
end;//try
end;

procedure GoToPath(ToForward: boolean);
var
x,y,z,i: integer;
s: string;
begin
MoveToPathEnabled:= not MoveToPathEnabled;
MoveToForward:=ToForward;
if not MoveToPathEnabled then
begin
MoveTimer.Enabled:=False;
SendMsg('Следование по маршруту остановлено');
exit;
end;
//
// предположительно путь уже прописан в MovePath
//
SendMsg('Пробуем выйти на путь...');
// сперва идем к ближайшему чекпоинту
i:= GetMinCheckPoint(MovePath);
if i<0 then
begin
SendMsg('чекпоинт не найден');
MoveToPathEnabled:=False;
end else
begin
SendMsg('найден ближайший чекпоинт бежим туды');
MoveToPathEnabled:=True;
MoveStepIndex:=i;

if debug then
SendMsg('checkpoint #'+inttostr(i));

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if (old_x<>x) and (old_y<>y) and (old_z<>z) then
begin
MoveTo(x,y,z);
old_x:=x;
old_y:=y;
old_z:=z;
old_time:=0;
end;
end;
MoveTimer.Enabled:=True;
end;
//************************************************** *************
procedure OnMove(Sender: TObject);
var
x,y,z: integer; s: string;
begin
inc(old_time);// счетчик, сколько тиков прошло с последнего клика. исп. при следованию по маршруту
if not MoveToPathEnabled then
begin
try
TTimer(Sender).Enabled:=False;
except
end;
SendMsg('Движение остановлено');
exit;
end;
// возможно мы пали смертью храбрых, то не дергаемся пока
if myHP<=0 then
begin
sendmsg('Die');
MoveToPathEnabled:=False;
exit;
end;
debugmsg('hp:'+inttostr(myhp));
try
// проверяем на существ. объекта
// при отладке всякое может быть
MovePath.Count;
except
TTimer(Sender).Enabled:=False;
exit;
end;

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if PosInRange(x,y,z,RangeToCheckPoint) then
begin
if MoveToForward then
begin
if MoveStepIndex=MovePath.Count-1 then
begin
MoveToPathEnabled:=False;
SendMsg('Мы по идее в конечной точке');
exit;
end
else
begin
inc(MoveStepIndex);
end;
end
else
begin
if MoveStepIndex>0 then dec(MoveStepIndex)
else
begin
MoveToPathEnabled:=False;
SendMsg('Мы по идее в начальной точке');
exit;
end;
end;
// мы достигли чекпоинта идем далее
SendMsg('бежим к #'+inttostr(MoveStepIndex));
s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
MoveTo(x,y,z);
end;
end;

function ExtractValue(sData: string;nIndex: integer): integer;
var
s: string;
i,j: integer;
begin
i:=0;j:=0;s:='';
s:=sData;
while j<nIndex do
begin
i:=pos('|',S);
if i>=0 then
begin
s:=copy(s,i+1,length(s)-i);
inc(j);
end
else
break;
end;
i:=pos('|',s);
if i>=0 then
s:=copy(s,1,i-1);
try
result:=strtoint(s);
except
end;
end;
//************************************************** ****************
//Bot by Skymanrus
//modified by NLObP специально для Владера, моего сына!
//ПЕРЕМЕЩЕНИЕ:
//Идти в точку с координатами x,y,z
//MOVETO(x,y,z)
procedure MoveTo(TargetX,TargetY,TargetZ:integer);
begin
//01=MoveBackwardToLocation:d(targetX)d(targetY)d(ta rgetZ)d(originX)d(originY)d(originZ)d(moveByMouse)
buf:=#$0F;
WriteD(targetx); //куда
WriteD(targety);
WriteD(targetz);
WriteD(MyX); //откуда
WriteD(MyY);
WriteD(MyZ);
WriteD(1); //используем 1-мышь 0-клавиатура
SendToServerEx(MyNick);
end;

//Ориентация на местности:
//Проверка находится ли заданная точка в пределах досягаемости. Если да, то выполняется кусок скрипта в фигурных скобках {}.
function PosInRange(targetx,targety,targetz,distanciya:inte ger):boolean;
begin
if delta(targetx, targety, MyX, MyY)<=distanciya
then result:=true else result:=false;
end;

procedure UserInfo; // обновление донных о себе
var
i:word;
begin
MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
i:=22;
ReadS(i);
if interlude then i:=i+48 else i:=i+44;
MyMaxHP:=ReadD(i);
MyHP:=ReadD(i);
MyMaxMP:=ReadD(i); // чисто информативно
MyMP:=ReadD(i);
end;

procedure StatusUpdate; // обновление данных о себе
var
i: integer;
begin
for i:=0 to ReadD(6)-1 do
case pck[i*8+10] of
#$09: MyHP:=ReadD(i*8+14);
#$0A: MyMaxHP:=ReadD(i*8+14);
#$0B: MyMP:=ReadD(i*8+14);
#$0C: MyMaxMP:=ReadD(i*8+14);
end;
end;

//************************************************** *************

procedure OnConnect(WithClient: Boolean); //Вызывается при установке соединения
begin

end;

procedure OnDisonnect(WithClient: Boolean); //Вызывается при потере соединения
begin

end;

function iif(Bool: Boolean;aTrue: variant; aFalse: variant): variant;
begin
if Bool then
result:=aTrue
else
result:=aFalse;
end;

function ParseCmd(cmd: string):boolean;
var
s: string;
i,j,k: integer;
params: array[0..9] of string; // до 10 параметров, должно хватить
begin
result:=False;
try
j:=-1;
i:=pos(cmdPrefix,trim(cmd));
if i=0 then
exit;
debugmsg('start ParseCmd: idx:'+inttostr(i)+' cmd: '+cmd);
result:=true;

k:=length(cmdPrefix);
s:=trim(lowercase(cmd));
s:=trim(copy(s,i+k,length(cmd)-i));
debugmsg('trim:'+s);
repeat
inc(j);
k:=pos(cmdDlm,s);
if k>0 then
begin
params[j]:=copy(s,1,k-1);
// s:=copy(s,k+length(cmdDlm),length(s)-k-length(cmdDlm));
s:=trim(copy(s,k+length(cmdDlm),length(s)-k));
debugmsg('extract idx:'+inttostr(j) +' param:'+params[j]);
end
else
begin
params[j]:=s;
debugmsg('parm is one');
end;
until pos(cmdDlm,S)=0;
if j>-1 then
begin
inc(j);
params[j]:=s;
debugmsg('extract idx:'+inttostr(j) +' param:'+params[j]);
end;
if j=-1 then
exit;
//************************************************** *****
// пропарсили команду
// теперь выполняем
//************************************************** *****
if params[0]=cmdRecordPath then
begin
if params[1]<>'' then
RecordPathFileName:=params[1]
else
RecordPathFileName:=RecordPathName;
StartRecord;
end
else
if params[0]=cmdSavePath then
begin
StopRecord;
end
else
if params[0]=cmdMove then
begin
if params[1]='' then
begin
SendMsg('хз куда бежать, укажите имя');
exit;
end;
try
MovePath.LoadFromFile(RecordFilesPath+params[1]+RecordFileExt);
except
SendMsg('файл пути не найден');
exit;
end;
GoToPath(true);
end
else
if params[0]=cmdBack then
begin
if params[1]='' then
begin
SendMsg('хз куда бежать, укажите имя');
exit;
end;
try
MovePath.LoadFromFile(RecordFilesPath+params[1]+RecordFileExt);
except
SendMsg('файл пути не найден');
exit;
end;
GoToPath(false);
end
else
if (params[0]=cmdStop) and MoveToPathEnabled then
MoveToPathEnabled:=False;

except
debugmsg('error in ParseCmd,params='+cmd);
end;
end;

//основная часть скрипта
//вызывается при приходе каждого пакета если скрипт включен
var
i: integer;
begin
if FromClient and (ConnectName=MyNick)then
case pck[1] of
{
#$1B: // social
case pck[2] of
#$06: StartRecord; //Yes
#$05: StopRecord;//No
#$04: begin GoToPath(true); pck:=''; end;
end; //case
}
#$0F: // move
ParseMoveClient;
#$49: // say2
// если это команда и она обработана и надо очистить чат
if ParseCmd(ReadS(2)) and EraseCommandFromChat then
pck:='';// kill packet
#$59:
begin
myx:=ReadD(2);
myY:=ReadD(6);
myZ:=ReadD(10);
end;
end; // case
if FromServer and (ConnectName=MyNick) then
case pck[1] of
#$32: UserInfo;
#$18: StatusUpdate;
end; // case
end.
для ру ОФФА проверял работает :) скорее всего и на Kamael пойдет

функцию sendMsg - закоментарил т.к. она встроена в последних версиях пакетхака

wanick
10.12.2008, 21:50
А вот это скрипт переделан и доработан мной, управление скриптом прямо в игре

http://www.realtiz.ru/files/from_coderx_ru/scr.jpg

в шорткаты 2 закладку 1 ячейку вставляется предмет по клику на который открывается управление скриптом



///////////////////////////////////////////////////////////////
// для: L2PacketHack by xkor
// посл. редактирование: 14.05.2008, 15:03msk, alexsl
// доработан и внедре интерфейс управления из Игры by Wanick 10.12.2008 4:45msk
// назначение: перемещение чара по заранее записаным маршруту(м)
//
// краткая инструкция:
//
// 1. прописать ник в MyNick
//
// - для записи пути в файл:
// 1. встаем на исходную позицию
// 2. в чат пишим "===rec test1" (test1 - или другое имя без пробелов)
// 3. бежим куда нужно. (желательно много не кликать на одно и тоже место. все клики записываются в файл)
// 4. в чат пишим "===save"
// 5. все. теперь данные записаны на диск, согласно настройкам и под именем test1 указ. в п.п.2
//
// - записываем требуемые пути с разными маршрутами и названиями
//
// - использование
// 1. бег до последнего чекпоинта(при достижении скрипт завершает работу):
// пишим в чат "===go test1" (test1 - название записанного маршрута)
// 2. бег до первого чекпоинта (при достижении скрипт завершает работу):
// пишим в чат "===back test1" (test1 - название записанного маршрута)
// 3. для остановки скрипта при передвижении: пишим в чат "===stop"
//
// как работает?: при запуске бежит к ближайшему чекпоинту и следует согласно направлению
// Использовались идеии, коды участников форума за, что спасибо
/////////////////////////////////////////////////////////////////////
const
MyNick = 'ваш Ник';// <------------------------------
interlude = false;
debug = false;
// эта переменная указывает уничтожить пакет или нет если он обработан
// может данные нужны для других скриптов
EraseCommandFromChat = true;
//************************************************** *****
RecordFilesPath = 'c:\tmp\'; // путь где хранятся наши файлы
RecordPathName = 'recordmove'; // файл по умолчанию
RecordFileExt = '.txt';// расширение по умолчанию

RangeToCheckPoint = 150; // дистанция до чекпоинта при которой считается , что мы достигли оного
MoveTrigerDelay = 500; // срабатывание таймера на движение 0,5 сек

cmdPrefix = '===';// с этих символов начинается команда
cmdDlm = ' ';// разделитель параметров команды, параметры не должены содержать разделитель
// команды в общий чат
// пример
cmdRecordPath = 'rec'; // в общий чат "===rec giran1"
cmdSavePath = 'save'; // в общий чат "===save"
cmdMove = 'go'; // в общий чат "===go giran1"
cmdBack = 'back'; // в общий чат "===back giran1"
cmdStop = 'stop'; // останавливает следование по маршруту
cmdDelete = 'delete'; // в общий чат "===delete giran1"
cmdPatrol = 'patrol'; // в общий чат "===patrol giran1" - егает туда обратно по маршруту
//************************************************** *****

QItemID = 765; // Свиток Заговорщика
RandomID = 1953719668; // случаны objectID;
//************************************************** *****

var
// movement data
MovePath, // данные по которому мы будем двигатся в данный момент
RecordPath: TStringList; // данные для записи пути
RecordPathFileName: string; // название файла для записи
selectPathFileName: string; // название файла движения
PointsCount: integer; // кол-во поинтов в процессе записи пути

SavePathEnabled: boolean; // флаг записи пути

MoveToPathEnabled: boolean; // флаг движения по пути
MoveToForward: boolean; // направление движения да-вперед, нет - назад
MoveStepIndex: integer; // текущ. чекпоинт (куды бежим сейчас)
MoveTimer: TTimer; //

old_X,old_Y,old_Z,old_time: integer;

myX,myY,myZ: integer; // наши статы
myID: integer;
myHP,myMP,myMaxHP,myMaxMP: integer;

// by wanick
// id нашего диалогового окна для сартировки на перехвате
menuID :String = 'scr_'+ IntToStr (RandomID) +'?';
isInit,isPatrol:boolean;

procedure Init; //Вызывается при включении скрипта
begin
isInit:=true;

MoveTimer := TTimer.Create(nil);
MoveTimer.Enabled := False;
MoveTimer.Interval := MoveTrigerDelay;
MoveTimer.OnTimer := @OnMove;

RecordPathFileName:='';

//запрос на itemList вместе с ним приходит пакет UserInfo
//нужен для первоначального определения позиции
buf:=hstr('14');
SendToServerEX(MyNick);

RecordPath:=TStringList.Create;
MovePath:=TStringList.Create;
end;

procedure Free; //Вызывается при выключении скрипта
begin
if RecordPath<>nil then
try
RecordPath.Free;
except
debugmsg('error free RecordPath');
end;

if MovePath<>nil then
try
MovePath.Free;
except
debugmsg('error free MovePath');
end;
end;

procedure debugmsg(s: string);
begin
if debug then
SendMsgPM(s);
end;

function GetValue(ValName: string): string;
begin
result:=RecordPath.Values[ValName];
end;

procedure SetValue(ValName: string; Value: string);
begin
RecordPath.Values[ValName]:=Value;
end;

procedure StartRecord;
begin
if SavePathEnabled then
exit;
if MoveToPathEnabled then
begin
SendMsgPM('Во время следования по маршруту запись не возможна');
exit;
end;
RecordPath.Clear;
PointsCount:=0;
SendMsgPM('Начата запись маршрута');
SavePathEnabled := True
end;

procedure StopRecord;
begin
if not SavePathEnabled then
exit;
// записываем
RecordPath.SaveToFile(GetRecordFileName);
SendMsgPM('Запись маршрута завершена');
SavePathEnabled := False;
end;

function GetRecordFileName: string;
begin
result:=RecordFilesPath+RecordPathFileName+RecordF ileExt;
end;

procedure SendMsgPM(msg:string); // отправка сообщений клиенту
begin
//62 CB 04 00 00 02 00 00 00 00 00 00 00 42 04 35 04 41 04 42 04
buf:=#$62;
WriteD(1227);
WriteD(2);
WriteD(0);
WriteS(msg);
SendToClientEx(MyNick);
end;

procedure ParseMoveClient;
var
i,x,y,z: integer; s: string;
begin
if MoveToPathEnabled then begin ParseCmd ('===stop'); OpenControl; end;
if not SavePathEnabled then
exit;
i:=2;
x:=readd(i);
y:=readd(i);
z:=readd(i);
inc(PointsCount);
s:='|'+inttostr(x)+'|'+inttostr(y)+'|'+inttostr(z) +'|';
RecordPath.Add(s);
SendMsgPM('добавлен чекпоинт № '+inttostr(PointsCount));
end;

function delta(xpos1, ypos1, xpos2, ypos2:extended):integer; //возвращает переменную rezu которая является растоянием между 2 точками
var
dx,dy,summa: extended;
begin
try
dx:= xpos1-xpos2;
dy:= ypos1-ypos2;
summa:= dx*dx+dy*dy;
if summa = 0 then result:= 0 else result:= Round(sqrt(summa));
debugmsg('delta='+inttostr(result));
except
debugmsg('error in delta');
end;
end;


function GetMinCheckPoint(PointsList: TStringList): integer;
var
i,m,min_dist: integer;
s: string;
x,y,z: integer;
begin
result:=-1;
min_dist:=-1;
// проверка на наличие маршрута
if PointsList.Count=0 then
begin
exit;
MoveTimer.Enabled:=False;
MoveToPathEnabled:=False;
SendMsgPM('Нет данных по маршруту');
exit;
end;

try
for i:=0 to PointsList.count-1 do
begin
s:=PointsList[i];
y:=ExtractValue(s,2);
x:=ExtractValue(s,1);

debugMsg(s+' x:='+inttostr(x)+' y:='+inttostr(y));
m:=delta(x,y,myx,myy);
if m>0 then
begin
if (result=-1) then
begin
min_dist:=m;
result:=i;
end
else
if m<min_dist then
begin
min_dist:=m;
result:=i;
end;
end;
end;
except
debugMsg('error in GetMinCheckPoint');
end;//try
end;

procedure GoToPath(ToForward: boolean);
var
x,y,z,i: integer;
s: string;
begin
MoveToPathEnabled:= not MoveToPathEnabled;
MoveToForward:=ToForward;
if not MoveToPathEnabled then
begin
MoveTimer.Enabled:=False;
SendMsgPM('Следование по маршруту остановлено');
exit;
end;
//
// предположительно путь уже прописан в MovePath
//
SendMsgPM('Пробуем выйти на путь...');
// сперва идем к ближайшему чекпоинту
i:= GetMinCheckPoint(MovePath);
if i<0 then
begin
SendMsgPM('чекпоинт не найден');
MoveToPathEnabled:=False;
end else
begin
//SendMsgPM('найден ближайший чекпоинт бежим туды');
MoveToPathEnabled:=True;
MoveStepIndex:=i;
if debug then
SendMsgPM('checkpoint #'+inttostr(i));

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if (old_x<>x) and (old_y<>y) and (old_z<>z) then
begin
MoveTo(x,y,z);
old_x:=x;
old_y:=y;
old_z:=z;
old_time:=0;
end;
end;
MoveTimer.Enabled:=True;
end;
//************************************************** *************
procedure OnMove(Sender: TObject);
var
x,y,z: integer; s: string;
begin
inc(old_time);// счетчик, сколько тиков прошло с последнего клика. исп. при следованию по маршруту
if not MoveToPathEnabled then
begin
try
TTimer(Sender).Enabled:=False;
except
end;
SendMsgPM('Движение остановлено');
exit;
end;
// возможно мы пали смертью храбрых, то не дергаемся пока
if myHP<=0 then
begin
SendMsgPM('Die');
MoveToPathEnabled:=False;
exit;
end;
debugmsg('hp:'+inttostr(myhp));
try
// проверяем на существ. объекта
// при отладке всякое может быть
MovePath.Count;
except
TTimer(Sender).Enabled:=False;
exit;
end;

s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
if PosInRange(x,y,z,RangeToCheckPoint) then
begin
if MoveToForward then
begin
if MoveStepIndex=MovePath.Count-1 then
begin
SendMsgPM('Вы в конечной точке');
MoveToPathEnabled:=False;
if isPatrol then
ParseCmd ('===back '+selectPathFileName);
OpenControl;
exit;
end
else
begin
inc(MoveStepIndex);
end;
end
else
begin
if MoveStepIndex>0 then dec(MoveStepIndex)
else
begin
MoveToPathEnabled:=False;
SendMsgPM('Вы в начальной точке');
if isPatrol then
ParseCmd ('===go '+selectPathFileName);
OpenControl;
exit;
end;
end;
// мы достигли чекпоинта идем далее
SendMsgPM('бежим к #'+inttostr(MoveStepIndex));
s:=MovePath[MoveStepIndex];
x:=ExtractValue(s,1);
y:=ExtractValue(s,2);
z:=ExtractValue(s,3);
MoveTo(x,y,z);
end;
end;

function ExtractValue(sData: string;nIndex: integer): integer;
var
s: string;
i,j: integer;
begin
i:=0;j:=0;s:='';
s:=sData;
while j<nIndex do
begin
i:=pos('|',S);
if i>=0 then
begin
s:=copy(s,i+1,length(s)-i);
inc(j);
end
else
break;
end;
i:=pos('|',s);
if i>=0 then
s:=copy(s,1,i-1);
try
result:=strtoint(s);
except
end;
end;
//************************************************** ****************
//Bot by Skymanrus
//modified by NLObP специально для Владера, моего сына!
//ПЕРЕМЕЩЕНИЕ:
//Идти в точку с координатами x,y,z
//MOVETO(x,y,z)
procedure MoveTo(TargetX,TargetY,TargetZ:integer);
begin
//01=MoveBackwardToLocation:d(targetX)d(targetY)d(ta rgetZ)d(originX)d(originY)d(originZ)d(moveByMouse)
buf:=#$0F;
WriteD(targetx); //куда
WriteD(targety);
WriteD(targetz);
WriteD(MyX); //откуда
WriteD(MyY);
WriteD(MyZ);
WriteD(1); //используем 1-мышь 0-клавиатура
SendToServerEx(MyNick);
end;

//Ориентация на местности:
//Проверка находится ли заданная точка в пределах досягаемости. Если да, то выполняется кусок скрипта в фигурных скобках {}.
function PosInRange(targetx,targety,targetz,distanciya:inte ger):boolean;
begin
if delta(targetx, targety, MyX, MyY)<=distanciya
then result:=true else result:=false;
end;

procedure UserInfo; // обновление донных о себе
var
i:word;
begin
MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
i:=22;
ReadS(i);
if interlude then i:=i+48 else i:=i+44;
MyMaxHP:=ReadD(i);
MyHP:=ReadD(i);
MyMaxMP:=ReadD(i); // чисто информативно
MyMP:=ReadD(i);
end;

procedure StatusUpdate; // обновление данных о себе
var
i: integer;
begin
for i:=0 to ReadD(6)-1 do
case pck[i*8+10] of
#$09: MyHP:=ReadD(i*8+14);
#$0A: MyMaxHP:=ReadD(i*8+14);
#$0B: MyMP:=ReadD(i*8+14);
#$0C: MyMaxMP:=ReadD(i*8+14);
end;
end;

//************************************************** *************

procedure OnConnect(WithClient: Boolean); //Вызывается при установке соединения
begin

end;

procedure OnDisonnect(WithClient: Boolean); //Вызывается при потере соединения
begin

end;

function iif(Bool: Boolean;aTrue: variant; aFalse: variant): variant;
begin
if Bool then
result:=aTrue
else
result:=aFalse;
end;

function ParseCmd(cmd: string):boolean;
var
s: string;
i,j,k: integer;
params: array[0..9] of string; // до 10 параметров, должно хватить
isOne:boolean =false;
begin
result:=False;
try
j:=-1;
i:=pos(cmdPrefix,trim(cmd));
if i=0 then
exit;
debugmsg('start ParseCmd: idx:'+inttostr(i)+' cmd: '+cmd);
result:=true;

k:=length(cmdPrefix);
s:=trim(lowercase(cmd));
s:=trim(copy(s,i+k,length(cmd)-i));
debugmsg('trim:'+s);

repeat
inc(j);
k:=pos(cmdDlm,s);
params[0] := '';
params[1] := '';
if k>0 then
begin
params[j]:=copy(s,1,k-1);
// s:=copy(s,k+length(cmdDlm),length(s)-k-length(cmdDlm));
s:=trim(copy(s,k+length(cmdDlm),length(s)-k));
debugmsg('extract idx:'+inttostr(j) +' param:'+params[j]);
end
else
begin
params[j]:=s;
isOne := true;
debugmsg('parm is one');
end;
until pos(cmdDlm,S)=0;
if (j>-1) AND (NOT isOne) then
begin
inc(j);
params[j]:=s;
debugmsg('extract idx:'+inttostr(j) +' param:'+params[j]);
end;

if j=-1 then
exit;
//************************************************** *****
// пропарсили команду
// теперь выполняем
//************************************************** *****
if params[0]=cmdRecordPath then
begin
sendMsg(params[1]);
if (params[1] <> '') then
RecordPathFileName:=params[1]
else
RecordPathFileName:=RecordPathName;
StartRecord;
end
else
if params[0]=cmdSavePath then
begin
StopRecord;
end
else
if params[0]=cmdMove then
begin
if (params[1] <> '') then
selectPathFileName:=params[1]
else
selectPathFileName:=RecordPathName;

try
MovePath.LoadFromFile(RecordFilesPath+selectPathFi leName+RecordFileExt);
except
SendMsgPM('файл пути не найден');
exit;
end;
GoToPath(true);
end
else
if params[0]=cmdBack then
begin
if (params[1] <> '') then
selectPathFileName:=params[1]
else
selectPathFileName:=RecordPathName;

try
MovePath.LoadFromFile(RecordFilesPath+selectPathFi leName+RecordFileExt);
except
SendMsgPM('файл пути не найден');
exit;
end;
GoToPath(false);
end
else
if (params[0]=cmdStop) and MoveToPathEnabled then begin
MoveToPathEnabled:=False;
isPatrol:= false;
end
else
if (params[0] = cmdDelete) then begin SendMsgPM ('Удаление не работает'); exit; end
else
if (params[0] = cmdPatrol) then
begin
isPatrol := true;
if (params[1] <> '') then
selectPathFileName:=params[1]
else
selectPathFileName:=RecordPathName;
ParseCmd ('===go '+selectPathFileName);
end;
except
debugmsg('error in ParseCmd,params='+cmd);
end;
end;

procedure OpenControl;
var
// первая часть
tmpRS, textSR, textPath:string;
//вторая часть
textCombo:string;
begin
tmpRS := 'rec';
if SavePathEnabled then tmpRS := 'save';
textSR := 'Начать запись';
if SavePathEnabled then textSR := 'Завершить запись';
textPath := 'Введите название пути:</td><td><edit length="15" var="RecordPathName" height=9 width=120>';
if SavePathEnabled then textPath := 'Идет запись пути: <font color="FF0000">'+RecordPathFileName+'</font>';
//--------------
textCombo := 'Выберите путь:</td><td><edit length="15" var="selectPathName" height=9 width=170>';
// textCombo := 'Выберите пути:</td><td><combobox var="selectPathName" width=170 list="'+ getPathList +'">';
buf:=#$19;
WriteD(RandomID);
WriteS('<HTML><BODY> '
+'<font color="LEVEL">Создать новый маршрут:</font><br>'
+'<table width=270 height=17>'
+'<tr>'
+'<td>'+ textPath +'</td>'
+'</tr>'
+'</table>'
+'<br>'+ cButton(textSR, '==='+tmpRS+' $RecordPathName', 110, 22, (not MoveToPathEnabled))
+'<img src="L2UI.SquareWhite" width=270 height=1><img src="L2UI.SquareBlank" width=270 height=4>'
+'<font color="LEVEL">Использовать уже имеющийся маршрут:</font><br>'
+'<table width=270 height=17>'
+'<tr>'
+'<td>'+ textCombo +'</td>'
+'</tr>'
+'</table><br>'
+'<table width=270 height=17>'
+'<tr>'
+'<td fixwidth=95>'+ cButton('Вперед', '===go $selectPathName', 95, 22, ((not MoveToPathEnabled) AND (not SavePathEnabled))) +'</td>'
+'<td fixwidth=95>'+ cButton('Стоп', '===stop', 95, 22, MoveToPathEnabled) +'</td>'
+'<td fixwidth=95>'+ cButton('Назад', '===back $selectPathName', 95, 22, ((not MoveToPathEnabled) AND (not SavePathEnabled))) +'</td>'
+'</tr>'
+'</table><br>'
+'<font color="LEVEL">а также можно:</font>'
+ cButton('Патрулировать путь', '===patrol $selectPathName', 145, 22, ((not MoveToPathEnabled) AND (not SavePathEnabled)))
//+ cButton('Удалить выбраный путь', '===delete $selectPathName', 145, 22)
+'<img src="L2UI.SquareWhite" width=270 height=1><img src="L2UI.SquareBlank" width=270 height=4>'
+'скрипт сохранения маршрутов передвижения by <font color="LEVEL">alexsl</font>.<br>'
+'Игровой интерфейс, доработка и расширение возможностей by <font color="LEVEL">Wanick</font>.<br>'
+'Вопросы и обсуждения на сайте <font color="LEVEL">http://coderx.ru</font>'
+'</BODY></HTML>');
WriteD(QItemID);
SendToClient;
end;
function cButton(var value, action:string; width, height:integer; show:boolean=true ):string;
begin
Result := '<table border=1 cellspacing=1 cellpadding=0 bgcolor="b09979" width="'+ IntToStr(width) +'" height="'+ IntToStr(height) +'"><tr><td><center>'+value+'</center></td></tr></table>';
if not show then exit;
Result := '<button value="'+ value +'"'
+'action="bypass -h '+ menuID + action +'"'
+'width="'+ IntToStr(width) +'" height="'+ IntToStr(height) +'"'
+'back="L2UI_CT1.Button_DF_Down" fore="L2UI_CT1.Button_DF">';
end;
function getPathList:string;
begin
Result := 'recordmove';
end;

procedure MyRule (var sel:string);
begin
//sendMsg(sel);
ParseCmd(sel);
OpenControl;
end;

//основная часть скрипта
//вызывается при приходе каждого пакета если скрипт включен
var
i: integer;
tmp1: string; // временная переменная
begin
if FromClient and (ConnectName=MyNick)then
case pck[1] of
#$0F: // move
ParseMoveClient;
#$49: // say2
// если это команда и она обработана и надо очистить чат
if ParseCmd(ReadS(2)) and EraseCommandFromChat then
pck:='';// kill packet
#$59:
begin
myx:=ReadD(2);
myY:=ReadD(6);
myZ:=ReadD(10);
end;
//by wanick
#$19: //перехват пакета на использование наше вещи
if ReadD(2) = RandomID then begin pck := ''; OpenControl; end;

#$23: // перехват наших действий в диалоговом окне
begin
tmp1:= ReadS(2);
if Pos (menuID, tmp1) = 1 then begin
pck:='';
tmp1 := Copy(tmp1, Length(menuID)+1, Length(tmp1)-Length(menuID));
MyRule(tmp1);
end;
end;

end; // case
if FromServer and (ConnectName=MyNick) then
case pck[1] of
#$32: UserInfo;
#$18: StatusUpdate;
//by Wanick
#$11:begin
if isInit=false then
begin
buf:=pck;
SendToClient;
end
else
begin
isInit:=false;
pck:='';

buf:=#$21;
buf := buf + HStr('01 00 02 00 04 00 ');
WriteD (RandomID);
WriteD(QItemID);
buf := buf + HStr('11 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF FE FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F1 D8 FF FF');
SendToClient;

buf:=#$44;
buf := buf + HStr('01 00 00 00 0C 00 00 00 ');
WriteD(RandomID);
buf := buf + HStr('01 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00');
SendToClient;
pck:='';
// OpenControl;
end;

end; //#11
end; // case
if pck='' then exit;
end.


Не получилось сделать выбор уже существующих маршрутов в combobox
из-за ограниченных возможностей FastScript в плагине, собираюсь сделать плагин там будет по проще.

если кто знает как из fastScript получить список фалов пишите

NLObP
11.12.2008, 18:54
если кто знает как из fastScript получить список фалов пишите

Надо вот так попробовать
var
searchResult : TSearchRec;

begin
// Попытка найти правильные файлы, соответствующие Unit1.d* в текущем каталоге
if FindFirst('Unit1.d*', faAnyFile, searchResult) = 0 then
begin
repeat
ShowMessage('Имя файла = '+searchResult.Name);
ShowMessage('Размер файла = '+IntToStr(searchResult.Size));
until FindNext(searchResult) <> 0;

// Должен освободить ресурсы, используемые этим успешным поиском
FindClose(searchResult);
end;
end;

wanick
11.12.2008, 20:33
я так пробовал проблема в том что TSearchRec, это запись(record) из sysutils.dll, а FastScript не позволяет использовать "uses sysutils;"
пробовал и через подгрузку dll делать, скорее всего не получилось, из-за того что SysUtils не лежит в папке с пакетхаком, и надо указывать полный путь от корня диска, а как определить путь в зависимости от системы я не знаю да и не искал, в скрипте нестал вводить переменную, путь до библиотеки SysUtils узеры могут испугатся :))) , проще сделать плагин. что я и собираюсь сделать. а в плагине и "uses sysutils;" не проблема.

xkor
12.12.2008, 01:02
uses sysutils;такое FastScript собсно и не поддерживает...

wanick
13.12.2008, 18:27
скрипт включил ?
myNick - прописал ?
на каком серваке грация или что у тебя или ру Офф?

Vebstor23
13.12.2008, 18:41
грация парт 2 ру офф

wanick
13.12.2008, 18:49
в моем скрипте тебе ничего писать ненадо в чат
при запуске скрипта ты у тебя в быстрых кнопках на 2 вкладке должен появится "свиток заговорщика" нажимай на него и откроется диалоговое окно как на прикрепленной картинке

Vebstor23
13.12.2008, 19:07
в моем скрипте тебе ничего писать ненадо в чат
при запуске скрипта ты у тебя в быстрых кнопках на 2 вкладке должен появится "свиток заговорщика" нажимай на него и откроется диалоговое окно как на прикрепленной картинке

чёт всё сделал ник вписал скрипт запустил в списке соединения появился ник но на панели ничего непояаляется( в чём может быть проблемма? и можно ли какнить переделать скрипт от NLObP чтоб он работал на грации? на ИЛ запускал всё работает норм а на грации нехочет пахать(

wanick как я понял ты переделывал скрипт от NLObP

wanick
13.12.2008, 19:13
нет я переделывал скрипт от alexsl, чтобы переделать скрипт от NLObP, тебе надо знать соответствие пакетов в Il и Gracia
там id только сменились если сможешь делай.

отправь в ЛС скрипт в том виде котором сейчас ник можешь спрятать

Vebstor23
17.12.2008, 21:23
народ так неукого и неполучилось зделать запись пути?

Гема
15.05.2009, 16:09
Возникла такая проблемка:
Необходимо периодически узнавать геодату земли в опред точке.
А точнее какая точка Z соответствует координатам X,Y.
Нужно это, что бы бот посылал координату Z не высосанную из пальца, а такую которую бы послал оригинальный клиент вот:(:cool:
Может кто-то догадался как геодату достать из клиента (((
ИМХО: бота легко пропалить если он на неровной поверхности шлет координату " не как у клиента".

xkor
17.05.2009, 01:14
Гема, сервак усрётся z координаты проверять.., учитывая что он их сам знает весьма примерно...

ПолуГость2
17.05.2009, 05:22
Надо попробовать развить скрипт в разрезе ASTAR (A*) алгоритма (http://coderx.ru/showpost.php?p=5305&postcount=5)
А*!
Господа, вы психи!..

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

Гема
17.05.2009, 13:59
А*!
Господа, вы психи!..
Добавлено через 13 минут
Так ли это? Если да, то перс в клиенте постоянно бы "скакал", занимая те координаты, которые диктует сервер. Если же координаты модели игрока определяются реальными коллизиями в клиенте, и они являются основными (коль скоро сервер не поправляет те координаты, которые клиент определяет по мешам и направляет серверу), то вот вам и геодата - меши в клиенте. Нужно только сообразить метод их автоматически изъять. Кстати, в этом случае также не понимаю, почему админы не могут получить реальную геодату - по тем же соображениям. Конечно, все непросто, нужен способ фильтрации по Z, иначе по любой веревке можно будет пробежать, но это алгоритмическая задача. Возможно, решаемая в полуручном режиме.
Я малограмный - что такое реальные колизии в клиенте?
Когда я клиентом щелкою мышкой по поверхности земли, клиент отдает 1 значение z, затем сервер возвращает значение немного отличаемое от того которое послал клиент. Проверю пошлю на много меньше, посмотрим чем серв ответит.

//alexteam: коллизия - столкновение.

ПолуГость2
17.05.2009, 14:43
Серв ответит тебе проекцией на модель земли отвесно вниз, по крайней мере скорее всего. У сервера есть модель поверхности, называемая здесь геодатой, по этой информации он строит пути. Кстати, можно прощелкать таким образом поверхность на официальном сервере и получить геодату, только это скорее всего привлечет внимание, и займет изрядно времени. Смысл в том, что клиент также строит пути - например, он обходит динамичные препятствия, тех же торгашей, хотя вероятнее всего он это делает тупейшим образом, типа сдвига от препятствия на какую-то величину. Так или иначе надо определиться - либо координаты дает только сервер (по своей геодате), либо клиент также имеет такую возможность, значит имеет сходные данные. Если бы сервер рулил и, как говорит xcor, знал координаты лишь приблизительно, игрок бы двигался скачками, т.к. на пути некоторые точки лежали бы выше моделей земли в клиенте, а там уж зависит от количество возвращаемых сервером точек на пути - говоря правильней, от степени детализации пути. Мне кажется, вернее вторая версия - например, игрок иногда при падении останавливается в некоторых координатах, а потом сервер "поправляет" его положение и клиент отображает игрока в другом месте. Особенно это заметно на втором клиенте, там отставание модели игрока от реального его положения может быть весьма значительным, и клиент тем не менее не пропускает его сквозь стены и горы, хотя реально игрок совсем в другом месте, это видно первым клиентом, и сервер говорит второму клиенту - твои координаты такие-то, и клиент стремится отрисовать анимацию бега в эту точку, но на пути гора, и клиент не пускает модель, и она ломится в гору. Исходя из этого получается, что клиент имеет свою версию геодаты, возможно такую же, как у и сервера, но скорее всего иную, "визуальную", основанную на мешах гор и прочих препятствий, соотносящуюся с какой-то степень точности с геодатой сервера (в идеале - 100% совпадение, но скорее всего серверная геодата грубее), и считает столкновения модели игрока и поверхностей.
Это теория. Теперь практика. Думаю, геодата клиента имеет столь грандиозные размеры, что забрать ее из клиента и использовать в боте нереально. К тому же она может иметь непривычный вид, т.е. не быть самостоятельной, и представлять собой, положим, просто набор полигонов в такой-то локации (именно эти текстурированные полигоны и есть то, что мы видим), а клиент ломит игрока вниз эмулирая гравитацию и находит точку коллизии с этими полигонами. И таким же образом находит целевую точку перемещений, передавая ее серверу. А уж сервер подправляет ее по z по своей "геодате". Что же касается A*, это очень ресурсоемкий алгоритм, к тому же ему нужны те же данные геодаты. Уверен, на сервере используется специальная версия A* с предварительным просчетом части путей, потому что иначе для сервера линейки с нормальным онлайном нужен был бы суперкомп. Поэтому я и оторопел, увидев идеи реализации в пакетхаке A*. Кстати, пакетхак паскакалевский код интерпретирует, или как? Если да, то это вообще труба...

Кстати, в разрезе темы геодаты - очень интересно, как в этом плане работает волкер. Ведь и по горам ходит, и из катов не вылетает, собака. И где в нем инфа о геодате, спрашивается?

Гема
17.05.2009, 23:13
У меня и из кат вылетает валкер, и в каты залетает...
Так что с валкером тоже проблемы(у мну точно).

dmitry501
18.05.2009, 06:00
Геодата для сервера занимает 140 Мб в сжатом виде http://www.megaupload.com/?d=SWFDJ7MP

Причем для фришек её получают из геодаты клиента утилитой GeoConv а затем дорабатывают руками.

При движении клиент проверяет свою клиентскую геодату.

Сервер корректирует пакеты MoveTo в соотвтетствии со своей геодатой.

ПолуГость2
18.05.2009, 21:51
Гема - до ХБ ничего не вылетало и не влетало, т.е. на правильном сервере волкер работает корректно. Про Шоки не говорим вообще по той же причине, по которой не обсуждаем особенности диеты Предаторов.

dmitry501 - все сходится. ;) Но - как работает волкер???

xkor
19.05.2009, 01:29
Причем для фришек её получают из геодаты клиента утилитой GeoConv а затем дорабатывают руками.

При движении клиент проверяет свою клиентскую геодату.
у клиента всё таки не геодата а 3d мир с проверкой коллизий, что кстати намного точнее чем геодата сервера которая сильно упрощена

Качественная GeoConv думаю есть только у Стазиса (её автора), и распространять её ему нет смысла так как он на делаемых ей геодатах неплохие шиши делает)

TAMBIK
02.08.2009, 20:06
alexsl Спасибо за скрипт ВСЕ ЗАМЕЧАТЕЛЬНО
поправил под ХБ