ну смотря какой перс и как играть :) тёмным сумонером ПП нужен 74 лвл, если котоводом то ПП и ШЕ в пати и комнаты где 8 мобов ну понятно без резистов к физике умирают если БД воткнуть до 60лвла даже то кошка и тень простаивают долго, тенью и кошкой это по раздельности.
Всем привет. Вот наконец доделал и протестил АвтоСвип.
Зацените мой первый скриптец. Если какие ошибки найдете, пишите.
Код:
//Автоматизация sweep'а by APXAHGEJI
//Свип производится тока при условии что моб был ,хоть один раз, ударен ВАМИ и
//находится в списке нужных мобов.
//Возможность работы нескольких одновременных скриптов
//Социальное действие YES - запусстить/приостановить запись/АвтоСвип мобов
//Социальное действие NO остановиться - завершить запись мобов и перейтии к АвтоСвип
//После того как скрипт запущен нажимаете Yes и атакуете по одному мобу каждого
//вида которых собираетесь спойлить. Атакуете до тех пор пока не появилась запись
//что моб записан. Для удобства процесс записи можно приостановить нажатие той же
//клавиши Yes. После того как все нужные мобы записаны жмакаете NO, запись мобов
//завершается, АвтоСвип запускается, можете приступать к спойлу. АвтоСвип можно
//приостановить нажав всю туже клавишу соцдействия Yes, но запись мобов под АвтоСвип
//не остановится, и снова активировав, все нужные мобы просвипятся.
Const
Name='Yes';
Sweep='2F 2A 00 00 00 00 00 00 00 00';
Var
Timer: TTimer;
N,M,i,NpcNum: Byte;
X,Y,Z,CharID: Integer;
NpcTypeID,TargetID: array of Integer;
NeedSweep,Dead: array of Boolean;
Switch,SaveID,HaveNpc,OffSweeper: Boolean;
//******************************************************************************
// Вызывается при включении скрипта
//******************************************************************************
Procedure Init;
begin
N:= 1;
M:= 0;
Switch:= False;
SaveID:= True;
SetLength( NpcTypeID, N );
SetLength( TargetID, N );
Timer:=TTimer.Create(nil);
Timer.OnTimer:=@Sweeper;
Timer.Enabled:= False;
Timer.Interval:= 500;//время задержки свипа
Say('Введите 1 в чат, чтобы начать/приостановить');
Say('запись мобов или АвтоСвип.');
Say('Введите 2 в чат, чтобы завершить запись мобов');
Say('и приступить к сполйу.');
end;
//******************************************************************************
//******************************************************************************
// Вызывается при выключении скрипта
//******************************************************************************
Procedure Free;
begin
Timer.Free;
end;
//******************************************************************************
//******************************************************************************
// Посылаем сообщение, которое видно только в окне бота
//******************************************************************************
Procedure Say(msg:string);
begin
buf:=hstr('4A 00 00 00 00');
WriteD(2);
WriteS(Name);
WriteS(msg);
SendToClientEx(Name);
end;
//******************************************************************************
//******************************************************************************
// Проверка наличия ИД моба в массиве
//******************************************************************************
Procedure FindMob(ObjectID: Integer);
begin
HaveNpc:= False;
NpcNum:= M;
For i:=0 to (M-1) do
If (ObjectID=TargetID[i]) then begin
NpcNum:= i;
HaveNpc:= True;
break;
end Else
If (TargetID[i]= 0) and (NpcNum = M) then NpcNum:= i;
end;
//******************************************************************************
//******************************************************************************
// Запуск свипа каждые n секунд (n= Timer.Interval)
//******************************************************************************
Procedure Sweeper(Sender: TObject);
begin
OffSweeper:= True;
For i:=0 to (M-1) do begin
If NeedSweep[i] and Dead[i] then begin
If Switch then begin
buf:= #$04;
WriteD(TargetID[i]);
WriteD(X);
WriteD(Y);
WriteD(Z);
WriteC(00);
SendToServerEx(Name);
buf:=HStr(Sweep);
SendToServerEx(Name);
end;
exit;
end;
If (TargetID[i]<>0) then OffSweeper:= False;
end;
If OffSweeper then begin
M:= 0;
SetLength(TargetID, M);
SetLength(NeedSweep, M);
SetLength(Dead, M);
Timer.Enabled:= False;
exit;
end;
end;
//******************************************************************************
//******************************************************************************
// Вызывается при приходе каждого пакета, если скрипт включен
//******************************************************************************
Begin
//****************************************************************************
//Не обрабатываем пустые пакеты
If pck='' then exit;
//****************************************************************************
//****************************************************************************
//Если от сервака принят пакет UserInfo. Запоминаем собственный ИД.
If FromServer and (ConnectName=Name) and (pck[1]=#$04) then CharID:= ReadD(18);
//****************************************************************************
//****************************************************************************
//Переключение между записью ИД и АвтоСвипом
If SaveID then begin
//**************************************************************************
//Делаем выборку нужных для свипа видов мобов
//**************************************************************************
if Switch then
if FromServer and (ConnectName=Name) then
if (pck[1]=#$05) and (ReadD(2)=CharID) then
if (ReadD(6)<>TargetID[N-1]) then TargetID[N-1]:= ReadD(6);
if (pck[1]=#$16) and (ReadD(2)=TargetID[N-1]) then
if (ReadD(6)<> NpcTypeID[N-1]) then begin
NpcTypeID[N-1]:= ReadD(6);
Inc(N);
SetLength( NpcTypeID, N );
SetLength( TargetID, N );
TargetID[N-1]:= TargetID[N-2];
NpcTypeID[N-1]:= NpcTypeID[N-2];
Say('Моб записан');
end;
//**************************************************************************
//Управление записью мобов
//**************************************************************************
If FromClient and (ConnectName=Name) and (pck[1]=#$1B) then begin
If (ReadD(2)=6) then
if Switch then begin
pck:='';
Switch:= False;
Say('Запись мобов приостановлена');
end
else begin
pck:='';
Switch:= True;
Say('Начата запись мобов, атакуйте нужных мобов');
end;
If (ReadD(2)=5) then begin
pck:='';
Dec(N);
SetLength(NpcTypeID, N);
SetLength(TargetID, M);
SetLength(NeedSweep, M);
SetLength(Dead, M);
SaveID:= False;
Switch:= True;
Say('Запись мобов завершена, АвтоСвип активирован');
Say('Удачного спойла');
end;
end;
//**************************************************************************
end
//****************************************************************************
//****************************************************************************
//Переходим от записи нужных мобов к АвтоСвипу
Else begin
//****************************************************************************
//**************************************************************************
//Записываем текущие координаты
if FromClient and (ConnectName=Name) and (pck[1]=#$48) then begin
X:= ReadD(2);
Y:= ReadD(6);
Z:= ReadD(10);
end;
//**************************************************************************
//**************************************************************************
//Анализ мобов :=))
If FromServer and (ConnectName=Name) then begin
//************************************************************************
//Записываем всех атакованых нами мобов (пакет Attack, причем Attacker=CharID)
If ((pck[1]= #$05) and (ReadD(2)= CharID)) then begin
FindMob(ReadD(6));
If not HaveNpc then
If (NpcNum <> M) then begin
TargetID[NpcNum]:= ReadD(6);
NeedSweep[NpcNum]:= False;
Dead[NpcNum]:= False
end Else begin
Inc(M);
SetLength(TargetID, M);
SetLength(NeedSweep, M);
SetLength(Dead, M);
TargetID[M-1]:= ReadD(6);
NeedSweep[M-1]:= False;
Dead[M-1]:= False;
Timer.enabled:= True;
end;
end;
//************************************************************************
//Проверяем есть ли в списке мобы
if (M <> 0) then begin
//**********************************************************************
//Проверяем тот ли вид моба атакован (пакет NpcInfo)
If (pck[1]= #$16) then begin
FindMob(ReadD(2));
If HaveNpc and (not NeedSweep[NpcNum]) then begin
For i:=0 to (N-1) do
If (ReadD(6)= NpcTypeID[i]) then begin
HaveNpc:= False;
Break;
end;
If not HaveNpc then NeedSweep[NpcNum]:= True;
end;
end;
//**********************************************************************
//Записываем что атакованый моб умер (пакет Die, причем Sweepable=1)
If (pck[1]= #$06) and (pck[22]= #$01) then begin
FindMob(ReadD(2));
If HaveNpc then Dead[NpcNum]:= True;
end;
//**********************************************************************
//Удаляем записи об атакованом мобе (пакет DeleteObject)
If (pck[1]= #$12) then begin
FindMob(ReadD(2));
If HaveNpc then begin
TargetID[NpcNum]:= 0;
NeedSweep[NpcNum]:= False;
Dead[NpcNum]:= False;
end;
end;
//**********************************************************************
end;
//************************************************************************
end;
//**************************************************************************
//**************************************************************************
//Запускаем/приостанавливаем АвтоСвип
//**************************************************************************
If FromClient and (ConnectName=Name) and (pck[1]=#$1B) and (ReadD(2)=6) then
if Switch then begin
pck:='';
Switch:= False;
Say('АвтоСвип приостановлен');
end
else begin
pck:='';
Switch:= True;
Say('АвтоСвип запущен');
end;
//**************************************************************************
end;
//****************************************************************************
End.
//******************************************************************************
Новая версия бота. Проверяет координату Z. Подрихтовал миникарту.
Код:
//Bot by Skymanrus
//modified by NLObP специально для Владера, моего сына!
{Бот для кача ТК 64+ лвл
Скрипт распространяется как есть, и я не несу ответственности
за то, что ВЫ натворили у себя, его используя.
Возможности скрипта:
- работает на С4 и Интерлюде;
- миникарта, усл. обозн.:
- зеленые в зоне Radius кача;
- белые вне DeltaZ;
- синие вне зоны Radius кача;
- розовые нас атакуют;
- красный мы атакуем;
- панель с инфой;
- сам бафается;
- сам юзает кубики;
- сам юзает алакрити;
- сам лечит себя хил пошинами и элементал хилом;
- проверка координаты Z для кача в катакомбах;}
//***************************************************************
const
name='NLObP'; //имя чара для которого включен скрипт
//установить константу в зависимости от типа игры (С4 или Интерлюд)
IL=false; //true - IL, false - C4
max=100; //максимальное значение массива
Radius=1500; //радиус участка для поиска мобов
DZ=200; //глубина/высота до мобов
PercentHP=70; //при каком количестве хп в % юзать бутылку лечения
MEsit=55; //при каком количестве хп в % надо сесть и подкопить хп
MEup=90; //при каком количестве хп в % надо встать после отдыха
buff1=91; //бафф defense aura
buff2=77; //бафф attack aura
buff3=112; //бафф deflect arrow
buff4=230; //бафф sprint
buff5=123; //бафф spirit barrier
cubicstorm=10;
cubiclife=67;
elementalheal=58;
//***************************************************************
var
frm : TForm; //панель информации
info, msg, stats : TMemo;
splitter1, splitter2 : Tsplitter;
map : Tform; //виртуальная карта
xm, ym : integer; //координаты на карте
offs1 : integer; //смещение для типа игры Ил или С4
StartTime: TDateTime; //ведем подсчет времени
EndTime: TDateTime;
death1, mob1 : integer; //подсчитываем смерти
underAttack : boolean; //нас атакуют
heal, kill : string;
MaxHP, MyZpos, CurHP, ObjID, ID, xpos, ypos, skill, MyID : integer;
but, sud, bst, attackIDMinID, attackID, zpos: integer;
cvaX, cvaY, cvaZ: integer; //координата центра кача
Hpotion, Apotion, MyXpos, MyYpos, rezu, MaxX, MaxID, MinID, MinX: integer;
sit, povtor, tame, gdo, npc, stop: Boolean;
attackk, bfi, atck, hpi, i, ii: integer; //индексы различных циклов
last : integer; //последняя запись в массиве, для ускорения скрипта
//массив мобов
MobsObjID: array[1..max] of integer;
MobsID: array[1..max] of integer;
MobsName: array[1..max] of string;
MobsRAS: array[1..max] of integer;
MobsX: array[1..max] of integer;
MobsY: array[1..max] of integer;
MobsZ: array[1..max] of integer;
NPCid: array[1..max] of integer;
Aggro: array[1..max] of Boolean;
TTShpC : Tshape; //центр кача на карте
TTShape: array [0..max] of Tshape; //объекты на карте
TTLabel: array [0..max] of Tlabel; //подписи к объектам
timer1: TTimer;
timer2: TTimer;
timer3: TTimer;
timer4: TTimer;
//***************************************************************
procedure Init; //УПРАВЛЯЮЩИЕ ПЕРЕМЕННЫЕ
var
i: integer;
begin
if il then begin
//CharInfo
offs1:=48; //44 для С4, 48 для IL
end else begin
offs1:=44;
end;
StartTime:=time;
underattack:=false; //атакован?
stop:=true; //откл. атака
atck:=0; //кол-во неуспешных атак после которых пробуем сменить таргет, здесь инициализация =0
hpi:=0;
bfi:=60; //60 сек
ii:=1;
last:=1; //начальное значение
//ПАНЕЛЬКА
frm := TForm.Create(nil);
frm.Caption := 'BOT '+name;
frm.BorderStyle := bsSizeable;
frm.Position := poScreenCenter;
frm.Width:=600;
frm.Height:=800;
//информация
info:=TMemo.Create(frm);
info.parent:=frm;
info.align:=alLeft;
info.ReadOnly:=true;
info.ScrollBars:=0;
info.Width:=450;
info.Height:=370;
//статистика
stats:=TMemo.Create(frm);
stats.parent:=frm;
stats.align:=alClient;
stats.ReadOnly:=true;
stats.ScrollBars:=0;
stats.Width:=150;
stats.Height:=100;
//сообщения
msg:=TMemo.Create(frm);
msg.parent:=frm;
msg.align:=alBottom;
msg.ReadOnly:=true;
msg.ScrollBars:=2;
msg.Width:=600;
msg.Height:=100;
msg.Lines.Add('...');
//разделители
splitter1:=Tsplitter.Create(frm);
splitter1.parent:=frm;
splitter1.Top:=0;
splitter1.Width:=3;
splitter1.Left:=470;
splitter1.align:=alLeft;
//разделители
splitter2:=Tsplitter.Create(frm);
splitter2.parent:=frm;
splitter2.Left:=0;
splitter2.Height:=3;
splitter2.align:=alBottom;
frm.Show;
//карта
map := TForm.Create(nil);
map.Caption:='MiniMap: '+name;
map.BorderStyle:=bsSizeable;
map.Position:=poScreencenter;
map.Width:=300;
map.Height:=300;
map.FormStyle:=FsStayOnTop;
map.Show;
heal:=HStr('45 00 00 00 00 00 00 00 00 00 '); // СИДЕТЬ!!!
//атака и прочее
timer1:=TTimer.Create(nil);
timer1.OnTimer:=@OnAttack;
timer1.enabled:=false; //таймер по умолчанию выключен
timer1.interval:=1000; //через каждые 1сек будем обновлять
//вывод в форму
timer2:=TTimer.Create(nil);
timer2.OnTimer:=@OnView;
timer2.enabled:=true; //таймер по умолчанию включен
timer2.interval:=1000; //через каждые 1сек будем обновлять
//баффы
timer3:=TTimer.Create(nil);
timer3.OnTimer:=@OnBuff; //
timer3.enabled:=false; // таймер по умолчанию выключен
timer3.interval:=60000; // первый баф через 60 сек
//рисуем карту
timer4:=TTimer.Create(nil);
timer4.OnTimer:=@OnMap;
timer4.enabled:=true; //таймер по умолчанию включен
timer4.interval:=1000; //через каждые 1сек будем обновлять
for i:= 1 to max do begin
Aggro[i]:=false;
//готовим точки МОБов
TTShape[i]:=Tshape.create(nil); //для мобов
TTShape[i].parent:=map;
TTShape[i].Brush.Color:=clBlue; //(clBlack, clRed, clGreen, clYellow, clBlue, clPurple)
TTShape[i].shape:=stCircle;
TTShape[i].left:=-70; //координаты
TTShape[i].top:=-70;
TTShape[i].width:=7; //размеры
TTShape[i].height:=7;
//Готовим названия
TTlabel[i]:=Tlabel.create(nil);
TTlabel[i].parent:=map;
TTlabel[i].left:=TTShape[i].left+4; //координаты
TTlabel[i].top:=TTShape[i].top+4;
TTlabel[i].caption:=inttostr(i);
TTlabel[i].font.size:=7;
TTlabel[i].font.color:=clBlue;
end;
//Готовим точку для центра кача
TTShpC:=Tshape.create(nil); //для моего чара
TTShpC.parent:=map;
TTShpC.shape:=stCircle;
TTShpC.Brush.Color:=clYellow;
TTShpC.left:=-70; //координаты
TTShpC.top:=-70;
TTShpC.width:=3; //размеры
TTShpC.height:=3;
//Готовим точку для ГГ
TTshape[0]:=Tshape.create(nil); //для моего чара
TTshape[0].parent:=map;
TTshape[0].shape:=stCircle;
TTshape[0].Brush.Color:=clBlack;
TTshape[0].left:=-70; //координаты
TTshape[0].top:=-70;
TTshape[0].width:=5; //размеры
TTshape[0].height:=5;
//готовим имя ГГ
TTlabel[0]:=Tlabel.create(nil); //для моего чара
TTlabel[0].parent:=map;
TTlabel[0].left:=TTShape[0].left+4; //координаты
TTlabel[0].top:=TTShape[0].top+4;
TTlabel[0].caption:=name;
TTlabel[0].font.size:=7;
TTlabel[0].font.color:=clBlack;
end;
//***************************************************************
procedure GameToMap(x, y : integer);
//Пока ничего умнее не придумал =(
//преобразуем игровые координаты в координаты карты
var
masshtabx, masshtaby:integer;
begin
masshtabx:=radius*map.Width div 200;
masshtaby:=radius*map.Height div 200;
xm:=Round(((X-myXpos)*map.Width/masshtabx)+(map.Width/2));
//коэфф. 0.9 для попадания точки X,Y=0 в центр карты
ym:=Round(((Y-myYpos)*map.Height/masshtaby)+(map.Width/2)*0.9);
end;
//***************************************************************
//RequestRestartPoint
procedure RequestRestartPoint;
begin
buf:=#$6D;
WriteD(00);
SendToServerEx(Name);
end;
//***************************************************************
procedure ViewInfo;
var
i: integer;
begin
info.Lines.Clear;
stats.Lines.Clear;
stats.Lines.Add('Имя чара :'+Name);
stats.Lines.Add('Время старта :'+TimeToStr(starttime));
stats.Lines.Add('Время работы :'+TimeToStr(time-starttime));
stats.Lines.Add('Убили МОБов: '+IntToStr(mob1)+' шт.');
stats.Lines.Add('Погибли: '+IntToStr(death1)+' раз');
stats.Lines.Add('MaxHP :'+IntToStr(MaxHP));
stats.Lines.Add('CurHP :'+IntToStr(CurHP));
stats.Lines.Add('MyID :'+IntToStr(MyID));
stats.Lines.Add('MyXpos :'+IntToStr(MyXpos));
stats.Lines.Add('MyYpos :'+IntToStr(MyYpos));
stats.Lines.Add('MyZpos :'+IntToStr(MyZpos));
stats.Lines.Add('PercentHP :'+IntToStr(PercentHP)+' %хп');
stats.Lines.Add('MEsit :'+IntToStr(MEsit)+' %хп');
stats.Lines.Add('MEup :'+IntToStr(MEup)+' %хп');
stats.Lines.Add('Radius :'+IntToStr(RADIUS));
stats.Lines.Add('DeltaZ :'+IntToStr(DZ));
stats.Lines.Add('cvaX :'+IntToStr(cvaX));
stats.Lines.Add('cvaY :'+IntToStr(cvaY));
stats.Lines.Add('cvaZ :'+IntToStr(cvaZ));
stats.Lines.Add('but :'+IntToStr(but)+' бутылки');
stats.Lines.Add('sud :'+IntToStr(sud)+' сидеть');
stats.Lines.Add('bst :'+IntToStr(bst)+' встать');
stats.Lines.Add('ObjID :'+IntToStr(ObjID)+' кто ходит');
stats.Lines.Add('xpos :'+IntToStr(xpos)+' кто ходит');
stats.Lines.Add('ypos :'+IntToStr(ypos)+' кто ходит');
stats.Lines.Add('zpos :'+IntToStr(zpos)+' кто ходит');
stats.Lines.Add('sit :'+VarToStr(sit));
stats.Lines.Add('attackIDMinID :'+IntToStr(attackIDMinID)+' ближний');
stats.Lines.Add('attackID :'+IntToStr(attackID)+' ближний');
stats.Lines.Add('attackk :'+IntToStr(attackk)+' цикл атак');
stats.Lines.Add('atck :'+IntToStr(atck)+' цикл выбора другой цели');
stats.Lines.Add('Last :'+IntToStr(Last)+' последняя в бд');
stats.Lines.Add('SummaAR :'+IntToStr(Summ(MobsObjID))+' всего в бд');
stats.Lines.Add('rezu :'+IntToStr(DeltaXY(MyXpos, MyYpos, xpos, ypos))+' рез ближ');
stats.Lines.Add('MaxX :'+IntToStr(MaxX));
stats.Lines.Add('MaxID :'+IntToStr(MaxID));
stats.Lines.Add('MinX :'+IntToStr(MinX));
stats.Lines.Add('MinID :'+IntToStr(MinID));
stats.Lines.Add('povtor :'+VarToStr(povtor));
stats.Lines.Add('tame :'+VarToStr(tame)+' выч %хп');
stats.Lines.Add('gdo :'+VarToStr(gdo)+' центр окр');
stats.Lines.Add('Hpotion: '+inttostr(Hpotion));
stats.Lines.Add('Apotion: '+inttostr(Apotion));
stats.Lines.Add('xm :'+IntToStr(xm));
stats.Lines.Add('ym :'+IntToStr(ym));
if (MyID<>0) then begin
info.Lines.Add('Ближайший МОБ: id='+IntToStr(MinID)+' дистанция='+IntToStr(MinX));
info.Lines.Add('HP:'+IntToStr(CurHP)+' из '+IntToStr(MaxHP)+' Цикл1='+IntToStr(attackk)+' Цикл2='+IntToStr(atck)+' Цикл бафа='+IntToStr(bfi));
if (Hpotion=0) then info.Lines.Add('Юзать HP бутылки?: НЕТ!');
if (Hpotion<>0) then info.Lines.Add('Юзать HP бутылки?: ДА!');
if (Apotion=0) then info.Lines.Add('Юзать AP бутылки?: НЕТ!');
if (Apotion<>0) then info.Lines.Add('Юзать AP бутылки?: ДА!');
if (sit=false) then info.Lines.Add('Бот стоит!');
if (sit=true) then info.Lines.Add('Бот сидит!');
for i:= 1 to last do begin
if (MobsObjID[i]<>0) then begin
if (attackIDMinID<>i) then info.Lines.Add('--'+IntToStr(i)+' ID МОБа:'+IntToStr(MobsObjID[i])+' расстояние:'+IntToStr(MobsRAS[i])+' атакует:'+VarToStr(Aggro[i])+' x:'+IntToStr(MobsX[i])+' y:'+IntToStr(MobsY[i])+' z:'+IntToStr(MobsZ[i]));
if (attackIDMinID=i) then begin
info.Lines.Add('->'+IntToStr(i)+' ID МОБа:'+IntToStr(MobsObjID[i])+' расстояние:'+IntToStr(MobsRAS[i])+' атакует:'+VarToStr(Aggro[i])+' x:'+IntToStr(MobsX[i])+' y:'+IntToStr(MobsY[i])+' z:'+IntToStr(MobsZ[i]));
TTShape[i].Brush.Color:=clRed;
end;
end;
end;
end else info.Lines.Add('Для инициализации Бота используй или брось и подбери аптечку!');
end;
//***************************************************************
procedure Free;
begin
DelALL;
end;
//***************************************************************
procedure StatsUpdate;
var
i: integer;
begin
for i:=0 to ReadD(6)-1 do begin
case pck[i*8+10] of
#$09: CurHP:=ReadD(i*8+14);
#$0A: MaxHP:=ReadD(i*8+14);
end;
end;
if (MaxHP<>0) then // вычисляем процентное соотношение хп
begin
but:=Round((MaxHP/100)*PercentHP); // при каком количестве хп юзать бутылку лечения
sud:=Round((MaxHP/100)*MEsit); // при каком количестве хп надо сесть и подкопить хп
bst:=Round((MaxHP/100)*MEup); // при каком количестве хп надо встать после отдыха
end;
end;
//***************************************************************
//ПЕРЕМЕЩЕНИЕ:
//Идти в точку с координатами x,y,z
//MOVETO(x,y,z)
procedure MoveTo(TargetX,TargetY,TargetZ:integer);
begin
//01=MoveBackwardToLocation:d(targetX)d(targetY)d(targetZ)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)+','+inttostr(targety)+','+inttostr(targetz)+')');
end;
//***************************************************************
//Ориентация на местности:
//Проверка находится ли заданная точка в пределах досягаемости. Если да, то выполняется кусок скрипта в фигурных скобках {}.
function PosInRange(targetx,targety,targetz,distanciya:extended):boolean;
begin
if DeltaXY(targetx, targety, MyXpos, MyYpos)<=distanciya
then result:=true else result:=false;
end;
//***************************************************************
//возвращает растоянием между двумя точками
function DeltaXY(xpos1, ypos1, xpos2, ypos2:extended):integer;
begin
result:=Round(Sqrt(((xpos1-xpos2)*(xpos1-xpos2))+((ypos1-ypos2)*(ypos1-ypos2))));
end;
//***************************************************************
//возвращает растоянием между двумя координатами Z
function DeltaZ(Zpos1, Zpos2 : extended) : integer;
begin
result:=Round(abs(Zpos1-Zpos2));
end;
//***************************************************************
procedure DelElArr(ele:integer); //удаляет моба!
begin
MobsObjID[ele]:=0;
MobsID[ele]:=0;
MobsName[ele]:='';
MobsRAS[ele]:=0;
MobsX[ele]:=0;
MobsY[ele]:=0;
MobsZ[ele]:=0;
Aggro[ele]:=false;
TTShape[ele].left:=-70; //координаты
TTShape[ele].top:=-70;
TTShape[ele].Brush.Color:=clBlue;
TTlabel[ele].left:=TTShape[ele].left+4; //координаты
TTlabel[ele].top:=TTShape[ele].top+4;
TTlabel[ele].caption:='';
TTlabel[ele].font.color:=clBlue;
end;
//***************************************************************
procedure DelALL; //обнуляем всю базу!
var
i: integer;
begin
for i:= 1 to max do begin
NPCid[i]:=0;
MobsObjID[i]:=0;
MobsID[i]:=0;
MobsName[i]:='';
MobsRAS[i]:=0;
MobsX[i]:=0;
MobsY[i]:=0;
MobsZ[i]:=0;
Aggro[i]:=false;
TTshape[i].free;
TTlabel[i].free;
end;
TTShpC.free;
TTShape[0].free;
TTLabel[0].free;
timer1.Free;
timer2.Free;
timer3.Free;
timer4.Free;
splitter1.free;
splitter2.free;
info.Free;
msg.Free;
frm.Free;
map.Free;
end;
//***************************************************************
procedure GetMinMaxX(arra:array of integer);
//возвращает в переменную MinX - мин и MaxX - макс значение массива, а в MinID, MaxID номер этого элемента
var
minras, i: integer;
begin
MinX:=5000;
MinID:=0;
MaxX:=0;
MaxID:=0;
for i:= 1 to last do begin
//проверяем что расстояние до моба в радиусе кача и по высоте не глубоко
if (DeltaXY(Mobsx[i],Mobsy[i],cvaX,cvaY)<=Radius) and (DeltaZ(Mobsz[i],cvaz)<=DZ) then begin
if (arra[i]<=MinX) and (arra[i]<>0) then begin
MinX:=arra[i];
MinID:=i;
end;
if (arra[i]>=MaxX) then begin
MaxX:=arra[i];
MaxID:=i;
end;
end;
end;
end;
//***************************************************************
function ETOpovtor(chislo: integer; arra:array of integer):boolean;
//возвращает переменную povtor и если она равна 1 значит chislo уже есть в массиве!
var
i: integer;
begin
Result:=false;
for i:= 1 to last do begin
if (arra[i]=chislo) then Result:=true;
end;
end;
//***************************************************************
procedure attackt(mobus:integer);
begin
buf:=#$04; //action
WriteD(MobsObjID[mobus]);
WriteD(MyXpos);
WriteD(MyYpos);
WriteD(MyZpos);
WriteC(0);
SendToServerEx(Name);
end;
//***************************************************************
function Summ(sum:array of integer):integer;
//возвращает переменную SummaAR с количеством полных(не пустых) ячеек
var
Summa: integer;
i: integer;
begin
Result:=0;
for i:= 1 to max do begin
if (sum[i]<>0) then inc(Result);
end;
end;
//***************************************************************
procedure OnMap(Sender: TObject); //рисуем карту
begin
if (myxpos=0) and (myypos=0) then exit;
for i:= 1 to last do begin
if (MobsObjID[i]<>0) then begin
//красим мобов на карте
if stop=true then
if (DeltaXY(Mobsx[i],Mobsy[i],MyXpos,MyYpos)<=Radius)
then
if (DeltaZ(Mobsz[i],MyZPos)<=DZ)
then
TTShape[i].Brush.Color:=clGreen
else
TTShape[i].Brush.Color:=clWhite
else
if (DeltaZ(Mobsz[i],cvaz)<=DZ)
then
TTShape[i].Brush.Color:=clBlue
else
TTShape[i].Brush.Color:=clWhite;
if stop=false then
if (DeltaXY(Mobsx[i],Mobsy[i],cvaX,cvaY)<=Radius)
then
if (DeltaZ(Mobsz[i],cvaz)<=DZ)
then
TTShape[i].Brush.Color:=clGreen
else
TTShape[i].Brush.Color:=clWhite
else
if (DeltaZ(Mobsz[i],cvaz)<=DZ)
then
TTShape[i].Brush.Color:=clBlue
else
TTShape[i].Brush.Color:=clWhite;
if Aggro[i]=true then begin
TTShape[i].Brush.Color:=clPurple;
TTlabel[i].font.color:=clPurple;
end;
//ставим точку МОБа
GameToMap(MobsX[i],MobsY[i]);
TTShape[i].left:=xm; //координаты моба
TTShape[i].top:=ym;
TTlabel[i].left:=TTShape[i].left+4; //координаты
TTlabel[i].top:=TTShape[i].top+4;
TTlabel[i].caption:=inttostr(i);
end;
end;
//ставим точку ГГ
GameToMap(MyXpos,MyYpos);
TTShape[0].left:=xm; //координаты чара
TTShape[0].top:=ym;
TTlabel[0].left:=TTShape[0].left+4; //координаты надписи
TTlabel[0].top:=TTShape[0].top+4;
TTlabel[0].caption:=name;
//ставим точку центра кача
GameToMap(cvaX,cvaY);
TTShpC.left:=xm; //координаты ГГ
TTShpC.top:=ym;
end;
//***************************************************************
procedure OnAttack(Sender: TObject); //ВЫДЕЛЕНИЕ И АТАКА МОБА!
begin
if (MinID>0) then begin
if (sit=false) then begin
case attackk of
0: begin
attackID:=MobsObjID[MinID];
msg.Lines.Add('Атакую! '+IntToStr(attackID));
attackIDMinID:=MinID;
attackt(attackIDMinID); //target
end;
//делаем паузу
1: begin
attackt(attackIDMinID); //attack
end;
6: begin
attackt(attackIDMinID); //target
end;
//делаем паузу
7: begin
attackt(attackIDMinID); //attack
attackk:=1;
inc(atck);
end;
end;
//пробуем сместиться
case atck of
9: begin
MobsRAS[attackIDMinID]:=5000;
attackk:=-1;
atck:=0;
end;
end;
inc(attackk);
end;
end;
end;
//***************************************************************
procedure OnView(Sender: TObject); //вывод данных в форму
begin
//контролируем бафы
dec(bfi);
if bfi<0 then begin
timer3.interval:=1000; //пытаемся начать бафы каждые 1 сек
bfi:=1200; //20 мин
end;
//выводим в форму
ViewInfo;
GetMinMaxX(MobsRAS);
if (Summ(MobsRAS)>=round(max*0.9)) or (MaxX>5000) then begin
//если у нас занято более 90% ячеек с мобами надо удалить самых дальних от нас
msg.Lines.Add('Мусор удалён:'+IntToStr(MaxID)+' :'+IntToStr(MaxX)+' сумма'+IntToStr(Summ(MobsRAS))+'-');
DelElArr(MaxID);
end;
//идем в центр если нет мобов
// if (Summ(MobsRAS)=0) and (timer1.enabled=true) and (cvax<>0) then begin
//if not PosInRange(cvaX,cvaY,cvaZ,50) then MoveTo(cvaX,cvaY,cvaZ);
// end;
if (MyID<>0) and (CurHP<but) and (Summ(Aggro)=0) and (sit=false) then begin
msg.Lines.Add('Использую Elemental Heal!');
MagicSkillUse(elementalheal);
end;
if (CurHP<but) and (Hpotion<>0) then begin
if hpi=5 then begin
UseItem(Hpotion);
hpi:=0;
end else inc(hpi);
end;
if (CurHP<sud) and (Summ(Aggro)=0) and (sit=false) then begin
msg.Lines.Add('Всё, я отдыхаю!'+TimeToStr(time));
buf:=heal;
SendToServerEx(Name);
sit:=true;
end;
if (CurHP>bst) and (sit=true) then begin
msg.Lines.Add('Пора за работу!'+TimeToStr(time));
buf:=heal;
SendToServerEx(Name);
attackk:=0;
atck:=0;
sit:=false;
end;
end;
//***************************************************************
procedure OnBuff(Sender: TObject); //баффы
begin
if (MyID<>0) and (Summ(Aggro)=0) and (sit=false) then begin
case ii of
1: begin
timer1.enabled:=false; //откл. атаку
msg.Lines.Add('Бафаюсь Defense aura!');
//бафф
MagicSkillUse(buff1);
inc(ii);
timer3.interval:=6000; //каждые 6 сек
end;
2: begin
msg.Lines.Add('Бафаюсь Attack aura!');
MagicSkillUse(buff2);
inc(ii);
end;
3: begin
msg.Lines.Add('Бафаюсь Deflect arrow!');
MagicSkillUse(buff3);
inc(ii);
end;
4: begin
msg.Lines.Add('Бафаюсь Sprint!');
MagicSkillUse(buff4);
inc(ii);
end;
5: begin
msg.Lines.Add('Бафаюсь Spirit barrier!');
MagicSkillUse(buff5);
inc(ii);
timer3.interval:=10000; //каждые 10 сек
end;
6: begin
msg.Lines.Add('Бафаюсь Storm cubic!');
MagicSkillUse(cubicstorm);
inc(ii);
end;
7: begin
msg.Lines.Add('Бафаюсь Life cubic!');
MagicSkillUse(cubiclife);
inc(ii);
end;
8: begin
if Apotion<>0 then begin
msg.Lines.Add('Пью Potion of Alacrite!');
UseItem(Apotion);
end;
inc(ii);
end;
9: begin
ii:=1;
timer3.interval:=1150000; //каждые 20 мин
bfi:=1150;
timer1.enabled:=true; //вкл. атаку
end;
end;
end;
end;
//***************************************************************
procedure AddBD(objid, posx, posy, posz:integer;); //добавляем моба в базу данных
var
i: integer;
begin
for i:=1 to last do begin //перебираем базу и ищем свободную ячейку в ней
if (MobsObjID[i]=0) then begin //запоминаем моба в свободную ячейку
if (ETOpovtor(objid, MobsObjID)=false) then begin
MobsObjID[i]:=objid; //ид моба
if id<>0 then MobsID[i]:=id; //ид моба
MobsRAS[i]:=DeltaXY(MyXpos, MyYpos, posx, posy); //растояние до этого моба
MobsX[i]:=posx;
MobsY[i]:=posy;
MobsZ[i]:=posz;
msg.Lines.Add('!-'+IntToStr(i)+'-id-'+IntToStr(MobsObjID[i])+'-ras-'+IntToStr(MobsRAS[i]));
break;
end;
end;
end;
//если нет свободного места ищем дальше
for i:=last+1 to max do begin //перебираем базу и ищем свободную ячейку в ней
if (MobsObjID[i]=0) then begin //запоминаем моба в свободную ячейку
if (ETOpovtor(objid, MobsObjID)=false) then begin
MobsObjID[i]:=objid; //ид моба
if id<>0 then MobsID[i]:=id; //ид моба
MobsRAS[i]:=DeltaXY(MyXpos, MyYpos, posx, posy); //растояние до этого моба
MobsX[i]:=posx;
MobsY[i]:=posy;
MobsZ[i]:=posz;
msg.Lines.Add('!-'+IntToStr(i)+'-id-'+IntToStr(MobsObjID[i])+'-ras-'+IntToStr(MobsRAS[i]));
last:=i;
break;
end;
end;
end;
end;
//***************************************************************
function ISnpc(id: integer;): boolean;
var
i: integer;
begin
result:=false;
for i:= 1 to max do if (NPCid[i]=id) then result:=true;
end;
//***************************************************************
procedure UseItem(ItemObjID:integer);
begin
buf:=#$14;
WriteD(ItemObjID);
WriteD(00);
SendToServerEx(Name);
end;
//***************************************************************
//2F=RequestMagicSkillUse:dMagicID)d(CtrlPressed)b(ShiftPressed)
procedure MagicSkillUse(MagicID:integer);
begin
buf:=#$2F;
WriteD(MagicID);
WriteD(00);
WriteC(00);
SendToServerEx(Name);
end;
//******************************************************************************
// вызывается при приходе каждого пакета, если скрипт включен
//******************************************************************************
begin
//****************************************************************************
//не обрабатываем пустые пакеты
if pck='' then exit;
//****************************************************************************
if (ConnectName=Name) and FromServer then begin
case pck[1] of
#$01: begin
msg.Lines.Add('S>C $01 Move');
if (MyID<>0) and (ReadD(2)<>MyID) then begin //если кто-то перемещается
i:=2;
ObjID:=ReadD(i); //кто-то рыпнулся с места надо это записать...
ID:=0; //кто-то рыпнулся с места надо это записать...
xpos:=ReadD(i);
ypos:=ReadD(i);
zpos:=ReadD(i);
if not ISnpc(ObjID) {and (DeltaXY(cvaX,cvaY,xpos,ypos)<=Radius)} then AddBD(ObjID,xpos,ypos,zpos);
end;
end;
#$03: begin
msg.Lines.Add('S>C $03 Char');
if (MyID<>0) and (ReadD(2)<>MyID) then begin //если это не я
for i:=last to max do begin
if (NPCid[i]=0) then begin
if (ETOpovtor(ReadD(18),NPCid)=false) then begin
NPCid[i]:=ReadD(18);
msg.Lines.Add('ДОБАВЛЕН ИГРОК:'+ReadS(22)+'-'+IntToStr(i)+'--'+IntToStr(NPCid[i]));
break;
end;
end;
end;
end;
end;
#$04: begin
msg.Lines.Add('S>C $04 CharInfo');
//пакет с инфой о моём чаре
i:=2;
MyXpos:=ReadD(i); //получаю координату х моего чара
MyYpos:=ReadD(i); //получаю координату у моего чара
MyZpos:=ReadD(i); //получаю координату z моего чара
//Запоминаем ИД
i:=18;
MyID:=ReadD(i); //получаю ид моего чара
//смещение переменное, зависит от имени (LenName*2+2)
i:=i+(Length(Name)*2+2)+offs1; //44 для С4, 48 для IL
MaxHP:=ReadD(i);
CurHP:=ReadD(i);
//лупить всех без разбора, в пределах радиуса
{if (gdo=false) then begin //задаем центр окружности кача
cvaX:=MyXpos;
cvaY:=MyYpos;
gdo:=true;
end;}
for i:=1 to last do begin //перебираем базу и ищем себя
if (ETOpovtor(MyID, MobsObjID)=true) then begin
DelElArr(i);
msg.Lines.Add('Удаляем себя из базы МОБов!!!');
if isnpc(myID)=false then begin
for i:= last to max do begin
if (NPCid[i]=0) then begin
NPCid[i]:=MyID;
break;
end;
end;
end;
end;
end;
end;
//MagicSkillUse 48, Attack 05
#$05: begin
msg.Lines.Add('S>C $05 Attack');
if (ReadD(6)=MyID) then begin
//меня ударили
sit:=false;
{if myxpos<>0 then begin
cvaX:=MyXpos;
cvaY:=MyYpos;
cvaZ:=MyZpos;
end;}
if (ETOpovtor(ReadD(2),MobsObjID)=false) then AddBD(ReadD(2),ReadD(15),ReadD(19),ReadD(23));
for i:=1 to last do begin
if (MobsObjID[i]=ReadD(2)) then begin //если моб записан в базе данных
msg.Lines.Add('На нас напали враги!!!'+IntToStr(i)+'-'+IntToStr(MobsObjID[i]));
Aggro[i]:=true; // стал агрессор
if (timer1.enabled=false) then begin //если я только зашел в игру и на меня напали
attackIDMinID:=i;
//вкл. атаку
timer1.enabled:=true;
stop:=false; //вкл. атака
end;
if (attackIDMinID<>0) and (Aggro[attackIDMinID]=false) then attackIDMinID:=i;
break;
end;
end;
end;
end;
//принят пакет Die
#$06: begin
msg.Lines.Add('S>C $06 Die');
//нас убили
if (myID=ReadD(2)) then begin
//остановить атаку
timer1.enabled:=false;
msg.Lines.Add('Нас убили в '+TimeToStr(time));
inc(death1);
RequestRestartPoint; //оживаем после смерти
//мы в городе, снимаем атрибут атаки на нас
for i:= 1 to max do begin
Aggro[i]:=false;
TTShape[i].Brush.Color:=clBlue;
TTlabel[i].font.color:=clBlue;
end;
end else begin
//моб сдох! выкидываем его из базы and (attackID=ReadD(2))
for i:=1 to last do begin
if (MobsObjID[i]=ReadD(2)) then begin
msg.Lines.Add('Убили очередного МОБа в '+TimeToStr(time));
inc(mob1);
DelElArr(i);
attackk:=0;
atck:=0;
if (i=last) and (last<>1) then dec(last);
//timer1.enabled:=true;
break;
end;
end;
end;
end;
#$0C: begin
msg.Lines.Add('S>C $0C DropItem');
if (MyXpos<>0) then begin
if (DeltaXY(MyXpos, MyYpos, ReadD(14), ReadD(18))<=200) then begin
msg.Lines.Add('Выпала вещь!!!');
timer1.enabled:=false;
buf:=#$04;
WriteD(ReadD(6));
WriteD(ReadD(14));
WriteD(ReadD(18));
WriteD(ReadD(22));
WriteC(0);
SendToServerEx(Name);
msg.Lines.Add(' Пробую поднять!!!');
delay(1000);
timer1.enabled:=true;
end;
end;
end;
#$0E: begin
msg.Lines.Add('S>C $0E StatsUpdate');
if (MyID=ReadD(2)) then StatsUpdate; //обновление информации о хп
end;
//принят пакет DeleteObject
#$12: begin
msg.Lines.Add('S>C $12 DeleteObject');
//выкидываем из базы
for i:=1 to last do begin
if (MobsObjID[i]=ReadD(2)) then begin
DelElArr(i);
msg.Lines.Add('Удаляю из базы:'+IntToStr(i));
if (i=last) and (last<>1) then dec(last);
break;
end;
end;
end;
#$16: begin
msg.Lines.Add('S>C $16 NPC');
if (MyID<>0) and (ReadD(2)<>MyID) then begin //если это не я
msg.Lines.Add('Вижу NPC!');
if (ReadD(10)=0) then begin //если нельзя атаковать
for i:=last to max do begin
if (NPCid[i]=0) then begin
if (ETOpovtor(ReadD(2), NPCid)=false) then begin
NPCid[i]:=ReadD(2);
msg.Lines.Add('Запомнили, NPCid='+IntToStr(ReadD(2))+' нельзя атаковать!');
break;
end;
end;
end;
end;
if (ReadD(10)=1) and (pck[120]=#$00) then begin //если можно атаковать
id:=ReadD(6);
AddBD(ReadD(2), ReadD(14), ReadD(18), ReadD(22));
msg.Lines.Add('NPCid='+IntToStr(ReadD(2))+' запомнили в базе!');
end;
end;
end;
//InventoryUpdate
#$27: begin
msg.Lines.Add('S>C $27 InventoryUpdate');
if ((ReadD(12)=1060) or (ReadD(12)=1061)) then begin //Healing Potion, Lesser Healing Potion
Hpotion:=ReadD(8);
msg.Lines.Add('ID бутылок H.Potion:'+inttostr(Hpotion));
end;
if ReadD(12)=735 then begin //Potion of Alacrity
Apotion:=ReadD(8);
msg.Lines.Add('ID бутылок A.Potion:'+inttostr(Apotion));
end;
end;
end;
end;
//****************************************************************************
if (ConnectName=Name) and FromClient then begin
case pck[1] of
#$1B: begin
msg.Lines.Add('C>S $1B Yes');
case ReadD(2) of
//социальное действие Yes для начала
$06: begin
//не передаем серверу
pck:='';
msg.Lines.Add('C>S $1B Yes');
//устанавливаем центр кача
cvaX:=MyXpos;
cvaY:=MyYpos;
cvaZ:=MyZpos;
//переменные циклов сбрасываем
attackk:=0;
atck:=0;
msg.Lines.Add('БОТ ВКЛЮЧЕН, координаты центра ОБНОВЛЕНЫ!!');
//вкл. атаку
timer1.enabled:=true;
//вкл. бафы
timer3.enabled:=true;
stop:=false; //вкл. атака
end;
//социальное действие No для окончания
$05: begin
//не передаем серверу
pck:='';
msg.Lines.Add('C>S $1B No');
//откл. атаку
timer1.enabled:=false;
//откл. бафы
timer3.enabled:=false;
stop:=true; //откл. атака
msg.Lines.Add('БОТ ВЫКЛЮЧЕН!!!');
end;
//социальное действие Sorrow - удаляем текущую запись в базе
$0D: begin
//не передаем серверу
pck:='';
msg.Lines.Add('C>S $1B Sorrow');
ObjID:=MobsObjID[attackIDMinID];
DelElArr(attackIDMinID);
attackk:=0;
atck:=0;
msg.Lines.Add('Удаляем текущую запись в базе!!!');
for i:= last to max do begin
if (NPCid[i]=0) then begin
NPCid[i]:=ObjID;
msg.Lines.Add('ИГРОК ДОБАВЛЕН!-'+IntToStr(i)+'--'+IntToStr(NPCid[i]));
break;
end;
end;
end;
end;
end;
//ValidatePosition пакет от клиента с моими кординатами
#$48: begin
msg.Lines.Add('C>S $48 ValidatePosition');
//обновляем ВСЕ растояния в BD если мы сошли с места
MyXpos:=ReadD(2); //получаю координату х моего чара
MyYpos:=ReadD(6); //получаю координату у моего чара
MyZpos:=ReadD(10); //получаю координату z моего чара
//пересчитываем расстояние до мобов
for i:=1 to last do begin
if MobsObjID[i]<>0 then begin
//до атакующих нас мобов всегда расстояние 1
MobsRAS[i]:=DeltaXY(MyXpos,MyYpos,MobsX[i],MobsY[i]);
end;
end;
end;
end;
end;
end.
Ну все, Господа... Выкладываю свой собственный ботоскрипт- локомотив :D
Прошу высказывать свои замечания и предложения.
Код:
{#############################################################################
Бот от Alexus
версия : 0.1 (бета)
дата: 12.03.08
Скрипт основан на всем том что я вычитал на этом форуме и моем опыте программирования.
Некоторые интересные идеи взяты из волкера.
Скрипт распространяется как есть. Используем его на свой страх и риск.
Любые изменения и дополнения только приветствуются!!!
Бот для кача в принципе любого война, но тестился на гноме.
Бот оптимизирован для кача в катах, лучше в квадратных комнатах (равносторонний четырехугольник).
Охотиться только на заданных мобов, а то излишняя самостоятельность бота немного пугает.
Пока что бот умеет следующее:
- запоминать центр и радиус кача
- запоминать список мобов на которых надо охотиться!
- управляется из окна чата в самом клиенте
- имеет окно для вывода всех параметров и статистики
- работает пока только под С4
Инструкция:
1. Запускаем игру, запускаем скрипт, добираемся до места кача
2. Пьем HP пробирку (надежный способ добывания своего ID-номера).
3. Выбираем в таргет моба на которого хотим охотится и пишем в общий чат-> 1
4. Валим моба. Если все правильно сделали будет выдано сообщение в чате что моб добавлен.
5. Выбираем следующего моба пишем цифру 2, валим его и т.д. можно выбрать до 10 разных тварей.
6. Становимся в центр комнаты и пишем в чат-> pos , если все правильно то в чате будет выдано сообщение.
7. Бежим к выходу из комнаты, и пишем-> dist, в чате вылезет сообщение от системы
8. Валим всех мобов в комнате, становимся примерно в центр и пишем-> start , если все сделано верно,
то будет выдано соответствующее сообщение.
9. если бот поймал моба в таргет и побежал его атаковать, то можно свернуть окно игры
и смотреть на информационное окно скрипта.
#############################################################################}
const
NickName = 'abc'; // Твой ник в игре
maximumItems = 100; // Размер базы мобов
MobsListRazmer = 10; // Размер списка мобов (не трогать!)
Vertical = 1000; // Вертикальный радиус кача
// HPMedium = 70; // Пока не используется
OX = 1; OY = 2; OZ= 3; // Служебные константы
var
InitMode : boolean;
//-------------------------------------- БД мобов ------
MobsID : array [1..maximumItems] of integer;
MobsDist : array [1..maximumItems] of integer; // Расстояние от центра кача
MobsXYZ : array [1..maximumItems, 1..3] of integer; // Координаты
MobsAgression : array [1..maximumItems] of boolean; // Моб атакует меня или стоит в сторонке...
LastItem: integer; // индекс последнего элемента базы
MobsList : array [1..MobsListRazmer] of integer; // Список мобов (коды мобов)
MobsListCount : integer; // Текущий размер списка
TargetID: integer; // Текущая цель
Povtor: integer;
CenterX, CenterY, CenterZ : integer; // Центр кача
Radius: integer; // Радиус кача
//--------------------------------------------------------
MyX, MyY, MyZ : integer; // Мои статы
MyID, MyHP, MyMaxHP: integer;
MyMP, MyMaxMP, MyCP, MyMaxCP: integer;
//--------------------------------------------------------
frm: TForm; // переменные описания формы
log, mainscreen: TMemo;
panel: TPanel;
frmParamIndex: byte;
textX, textY, textZ, textMyID, textMyHP, textMyMaxHP: TEdit;
textMyMP, textMyMaxMP, textMyCP, textMyMaxCP: TEdit;
textCenterX, textCenterY, textCenterZ, textRadius : TEdit;
textTargetID, textMobX, textMobY, textMobZ : TEdit;
textAttackCycle, textLastItem: TEdit;
//----------------------------------------------------------
TimerForm, TimerCombat: TTimer;
AttackCycle: integer; // Цикл атаки
procedure ClearDB; // Очистка БД
var // Надо все занулять, иначе там хрень всякая вылезает или старые данные
i: word;
begin
LastItem:= 0; // Очищаем переменные
TargetID:= 0;
Povtor:= 0;
CenterX:= 0;
CenterY:= 0;
CenterZ:= 0;
Radius:= 0;
AttackCycle:= 0;
for i:=1 to MobsListRazmer do MobsList[i]:= 0;
MobsListCount:= 0;
for i:=1 to maximumItems do // Очищаем базу
begin
MobsID[i]:= 0;
MobsDist[i]:= 0;
MobsXYZ[i, OX]:= 0;
MobsXYZ[i, OY]:= 0;
MobsXYZ[i, OZ]:= 0;
MobsAgression[i]:= false;
end;
end;
function SearchFreeItemDB : integer; // Функция ищет первый свободный елемент в БД
var
i:integer;
begin
result:=0;
for i:=1 to maximumItems do if MobsID[i] = 0 then
begin
result:=i;
break;
end;
if result = 0 then result:=maximumItems; // Если БД переполнена, то возвращаем индекс последнего элемента
if result > LastItem then LastItem := result; // если надо, увеличиваем текущий размер БД
end;
function rastoyanie(NpcX, NpcY, NpcZ : integer) : integer; // вычисление растояния между 2 точками
var
dx,dy,dz, summa : integer;
begin
dx:= NpcX-CenterX;
dy:= NpcY-CenterY;
dz:= NpcZ-CenterZ;
summa:= dx*dx+dy*dy; // мне кажется, что так будет быстрее считаться
if summa = 0 then result:= 0 else result:= Round(sqrt(summa)); // обход возможной ошибки, если моб стоит прямо в центре кача
if abs(dz) > vertical then result := result + 5000; // добавляем коррекцию по вертикали
end;
procedure AddtoDB (id, x,y,z : integer; agression : boolean); // Процедура добавляет в БД нового моба
var
i:integer;
dist: integer;
begin
dist:= rastoyanie (x,y,z); // вычиляем расстояние от центра кача до моба
if dist > (Radius + 1000) then exit; // если моб слишко далеко то ничего не делаем
i:= SearchFreeItemDB; // ищем свободный эл. БД
log.Lines.Add('Моб добавлен, индекс в БД: '+ inttostr(i));
if agression then log.Lines.Add('На нас напала какая-то вражина.');
MobsID[i]:= id; // Записываем моба
MobsDist[i]:= dist;
MobsXYZ[i, OX]:= x;
MobsXYZ[i, OY]:= y;
MobsXYZ[i, OZ]:= z;
MobsAgression[i]:= agression;
end;
procedure UpdateDB (i:integer; id, x,y,z : integer; agression : boolean); // Процедура обновляет данные в БД по мобу
var
dist: integer;
begin
if (MOBSXYZ[i, OX] = x) and (MOBSXYZ[i, OY] = y) and (MobsAgression[i] = agression) then exit; // проверяем, а надо ли чего нить менят
dist:= rastoyanie (x,y,z);
if dist > (Radius + 1000) then DelDBItem(i) else // перепроверяем расстояние до моба, если он вышел за границу кача, то удаляем его
begin
log.Lines.Add('Моб обновлен, индекс в БД: '+ inttostr(i));
if agression then log.Lines.Add('На нас напала какая-то вражина.');
MobsDist[i]:= dist; // записываем данные
MobsXYZ[i, OX]:= x;
MobsXYZ[i, OY]:= y;
MobsXYZ[i, OZ]:= z;
MobsAgression[i]:= agression;
end;
end;
procedure DelDBItem (i: integer); // процедура удалаяет моба из БД
begin
log.Lines.Add('Моб удален, индекс в БД: '+ inttostr(i));
MobsID[i]:= 0;
MobsDist[i]:= 0;
MobsXYZ[i, OX]:= 0;
MobsXYZ[i, OY]:= 0;
MobsXYZ[i, OZ]:= 0;
MobsAgression[i]:= false;
if i = LastItem then LastItem := LastItem -1; // если надо, уменьшаем размер БД
end;
function TestPovtor (id: integer) : integer; // функция проверяет наличие заданного моба в БД
var
i: integer;
begin
result:=0;
for i:=1 to LastItem do if MobsID[i] = id then // Ищем нужный ID в нашей БД
begin
result:=i; // И возвращаем его индекс по БД
break;
end;
end;
function InMobsList (NpcTypeID: integer) : boolean; // функция проверяет наличие заданного моба в списке на атаку
var
i: integer;
begin
result:= false;
for i:=1 to MobsListCount do if MobsList[i] = NpcTypeID then result:= true; // проверяем по списку
end;
procedure SendMsg(msg:string); // отправка системных сообщений клиенту
begin
buf:=#$4A;
WriteD(0);
WriteD(10);
WriteS('');
WriteS(msg);
SendToClientEx(NickName);
end;
function ValidateData : boolean; // функция проверки правильности задания всех параметров для начала кача
procedure ValidateMobsList; // подпроцедурка, перепроверяющая список мобов, и подсчитывающая количество записей в нем
var // этот алгоритм мне не нравится, буду переделывать
i: integer;
begin
for i:=1 to MobsListRazmer do if MobsList[i] = 0 then break;
i:= i - 1;
MobsListCount := i;
log.Lines.Add('MobsListCount = '+ inttostr(MobsListCount));
end;
begin
ValidateMobsList;
if (MyX <> 0) and (MyY <> 0) and (MyZ <> 0) and (MyID <> 0) and (MyHP <> 0) and (MyMaxHP <> 0) and // верификация всех данных, чтобы потом в боевом режиме
(MyMP <> 0) and (MyMaxMP <> 0) and (MyCP <> 0) and (MyMaxCP <> 0) and // не перепроверять все данные по 100 раз
(CenterX <> 0) and (CenterY <> 0) and (CenterZ <> 0) and (Radius > 0) and (MobsListCount > 0) then
begin
SendMsg('Все начальные параметры заданы и проверены!');
log.Lines.Add('Все начальные параметры заданы и проверены!');
result:= true;
end
else
begin
SendMsg('Ошибка задания начальных параметров!');
log.Lines.Add('Ошибка задания начальных параметров!');
result:= false;
end;
end;
procedure UserCommandsInitMode; // комманды пользователя для режима настройки бота
begin // если комманда обработана удачно, то в чат сообщение не попадет, а будет выдано системное сообщение прямо в клиент
case (ReadS(2)) of
'pos' : if MyX <> 0 then // центр кача
begin
CenterX:= MyX;
CenterY:= MyY;
CenterZ:= MyZ;
SendMsg('Центр кача задан успешно!');
log.Lines.Add('Центр кача задан успешно!');
pck:='';
end;
'dist' : if (CenterX <> 0) and (MyX <> 0) then // радиус кача
begin
Radius:= rastoyanie (MyX,MyY,MyZ);
SendMsg('Радиус кача задан успешно');
SendMsg('R= '+ inttostr(Radius));
log.Lines.Add('Радиус кача задан успешно, R = '+ inttostr(Radius));
pck:='';
end;
'reset': begin // сброс параметров
ClearDB;
SendMsg('БД очищена, введите заново все параметры');
log.Lines.Add('БД очищена!');
pck:='';
end;
'1', '2', '3', '4', '5', '6', '7', '8', '9', '10' : // задаем мобов
begin
MobsListCount:= strtoint(ReadS(2));
SendMsg('Добавляем моба № '+ ReadS(2));
pck:='';
end;
'start': begin // собственно запуск бота
if ValidateData and InitMode then
begin
SendMsg('ЗАПУСКАЕМ ИСУСТВЕННЫЙ ИНТЕЛЛЕКТ!');
log.Lines.Add('ЗАПУСКАЕМ ИСУСТВЕННЫЙ ИНТЕЛЛЕКТ!');
TargetID:=0;
InitMode:= false;
TimerCombat.enabled:=true; // запускаем таймер
end
else
begin
SendMsg('Еще не все параметры заданы. Проверьте параметры...');
log.Lines.Add('Еще не все параметры заданы. Проверьте параметры...');
end;
pck:='';
end;
end;
end;
procedure UserCommandsCombatMode; // комманды пользователя для боевого режима
begin // команды говорят сами за себя)
case (ReadS(2)) of
'pause' : begin
TimerCombat.enabled:= not(TimerCombat.enabled);
pck:='';
if TimerCombat.enabled then
begin
SendMsg('Искуственный интелект запущен!');
log.Lines.Add('Искуственный интелект запущен!');
end
else
begin
SendMsg('Искуственный интелект приостановлен.');
log.Lines.Add('Искуственный интелект приостановлен.');
end
end;
'stop' : begin
pck:='';
TimerCombat.enabled:= false;
InitMode:= true;
SendMsg('Искуственный интелект остановлен.');
log.Lines.Add('Искуственный интелект остановлен.');
end;
end;
end;
function GetMinDistID : integer; // функция поиска ближайшего моба в БД
var
i, dist : integer;
begin
dist:=10000; // задаем заранее нереальную дистанцию
for i:=1 to LastItem do if (MobsID[i] <> 0) and (MobsDist[i] < dist) then
begin // фишка в том, что в базе хранятся расстояния не до меня, а до центра кача
dist:= MobsDist[i]; // но в катах то расстояния небольшие
result:= i; // если нашли хоть одного моба или несколько возращаем его индекс ближайшего к центру кача
end;
if dist = 10000 then result:= dist; // иначе возвращаем 10000
end;
function AgroTest : integer; // функция проверяет, атакует ли меня кто-нибудь или нет
var
i: integer;
begin
result:=0;
for i:=1 to LastItem do if MobsAgression[i] then // ищем первого попавшегося моба, который нас атакует
begin
result:= i; // возвращаем его индекс по БД
break;
end;
end;
procedure PhisicalAttack; // команда атаки
begin
buf:=#$04; //action
WriteD(TargetID);
WriteD(MyX);
WriteD(MyY);
WriteD(MyZ);
WriteC(0);
SendToServerEx(NickName);
end;
procedure OnTimerCombat (Sender: TObject); // боевой таймер, вся логика поведения бота находится именно здесь!!!
var
Agro, MinDistID: integer;
begin
if LastItem > 0 then // если есть мобы в базе то:
begin
if TargetID = 0 then // если нет текущей цели, то
begin
Agro:= AgroTest; // запускаем алгоритм выбора цели
MinDistID:= GetMinDistID;
if Agro > 0 then // если нас кто-то атакует, то его и выбираем
begin
TargetID:= MobsID[Agro];
PhisicalAttack; // берем вражину в таргет
AttackCycle:= 0;
end
else if MinDistID <= Radius then // иначе ищем ближайшего
begin
TargetID:= MobsID[MinDistID];
PhisicalAttack; // берем вражину в таргет
AttackCycle:= 0;
end;
end;
if TargetID > 0 then
begin
case AttackCycle of // валим вражину
1, 5, 6 : PhisicalAttack;
10 : ;
end;
inc(AttackCycle)
end;
end;
if LastItem = 0 then ; // если нет мобов в базе, то по идее надо вернуться в центр кача, пока не разобрался с алгоритмом
end; // хочется точно сэмулировать клиент, как он работает
procedure OnTimerForm (Sender: TObject); // таймер обновления данных в форме
var
i: integer;
begin
textMyID.text:= inttostr(MyID); // обновляем данные в окне
textX.text:= inttostr(MyX);
textY.text:= inttostr(MyY);
textZ.text:= inttostr(MyZ);
textMyHP.text:= inttostr(MyHP);
textMyMaxHP.text:= inttostr(MyMaxHP);
textMyMP.text:= inttostr(MyMP);
textMyMaxMP.text:= inttostr(MyMaxMP);
textMyCP.text:= inttostr(MyCP);
textMyMaxCP.text:= inttostr(MyMaxCP);
textCenterX.text:= inttostr(CenterX);
textCenterY.text:= inttostr(CenterY);
textCenterZ.text:= inttostr(CenterZ);
textRadius.text:= inttostr(Radius);
textTargetID.text:= inttostr(TargetID);
textAttackCycle.text:= inttostr(AttackCycle);
textLastItem.text:= inttostr(LastItem);
mainscreen.lines.Clear;
for i:=1 to LastItem do if MobsID[i] > 0 then // выводим БД мобов
begin // алгоритм пока не доделан
mainscreen.lines.add ('-- '+inttostr(i)+' МобID: '+inttostr(MobsID[i])+' дистанция '+inttostr(MobsDist[i]));
end;
end;
procedure CreateLabel (text: string); // процедура автоматизирует создание текстовых меток в форме
var
l: TLabel;
begin
l:= TLabel.Create(panel);
l.caption:=text;
l.parent:=panel;
l.left:=5;
l.top:=15+20*frmParamIndex;
inc(frmParamIndex);
end;
function CreateTextBox (text:string) :TEdit; // функция автоматизирует создание текстовых полей для вывода данных в форме
var
e: TEdit;
begin
e:= TEdit.Create(panel);
e.text:=text;
e.parent:=panel;
e.left:=60;
e.top:=10+20*frmParamIndex;
result:= e;
end;
procedure Init; //Вызывается при включении скрипта
begin
ClearDB;
MyID:= 0; // обнуляем ВСЕ данные
MyX:= 0;
MyY:= 0;
MyZ:= 0;
MyID:= 0;
MyHP:= 0;
MyMaxHP:= 0;
MyMP:= 0;
MyMaxMP:= 0;
MyCP:= 0;
MyMaxCP:= 0;
InitMode:= true;
TimerCombat:=TTimer.Create(nil); // создаем таймеры
TimerCombat.OnTimer:=@OnTimerCombat;
TimerCombat.enabled:=false;
TimerCombat.interval:=1000;
TimerForm:=TTimer.Create(nil);
TimerForm.OnTimer:=@OnTimerForm;
TimerForm.enabled:=true;
TimerForm.interval:=1000;
frmParamIndex:=0; // создаем контролы в форме
frm:= TForm.Create(nil);
frm.Caption:= 'BOT info';
frm.BorderStyle := bsSizeable;
frm.Position := poScreenCenter;
frm.Width:=650;
frm.Height:=700;
mainscreen:=TMemo.Create(frm);
mainscreen.parent:=frm;
mainscreen.align:=alLeft;
mainscreen.ReadOnly:=true;
mainscreen.ScrollBars:=2;
mainscreen.Width:=470;
mainscreen.Height:=370;
mainscreen.Lines.Add('Инициализация');
panel:=TPanel.Create(frm);
panel.parent:=frm;
panel.align:=alRight;
log:=TMemo.Create(panel);
log.parent:=frm;
log.align:=alBottom;
log.ReadOnly:=true;
log.ScrollBars:=0;
log.Width:=570;
log.Height:=100;
log.Lines.Add('...');
textMyID:= CreateTextBox('textMyID');
CreateLabel('Мой ID :');
textX:= CreateTextBox('textX');
CreateLabel('Мой X :');
textY:= CreateTextBox('textY');
CreateLabel('Мой Y :');
textZ:= CreateTextBox('textZ');
CreateLabel('Мой Z :');
textMyHP:= CreateTextBox('textMyHP');
CreateLabel('Мой HP :');
textMyMaxHP:= CreateTextBox('textMyMaxHP');
CreateLabel('Мой MaxHP :');
textMyMP:= CreateTextBox('textMyMP');
CreateLabel('Мой MP :');
textMyMaxMP:= CreateTextBox('textMyMaxMP');
CreateLabel('Мой MaxMP :');
textMyCP:= CreateTextBox('textMyCP');
CreateLabel('Мой CP :');
textMyMaxCP:= CreateTextBox('textMyMaxCP');
CreateLabel('Мой MaxCP :');
inc(frmParamIndex);
textCenterX:= CreateTextBox('textCenterX');
CreateLabel('Ц. кач Х:');
textCenterY:= CreateTextBox('textCenterY');
CreateLabel('Ц. кач Y:');
textCenterZ:= CreateTextBox('textCenterZ');
CreateLabel('Ц. кач Z:');
textRadius:= CreateTextBox('Radius');
CreateLabel('Radius :');
inc(frmParamIndex);
textTargetID:= CreateTextBox('TargetID');
CreateLabel('Цель ID :');
textAttackCycle:= CreateTextBox('AttackCycle');
CreateLabel('Цикл атаки:');
textLastItem:= CreateTextBox('LastItem');
CreateLabel('Элем. БД:');
frm.Show; // выводим форму на экран
end;
procedure Free; //Вызывается при выключении скрипта
begin
mainscreen.free;
log.free;
frm.free;
ClearDB;
TimerForm.free;
TimerCombat.free;
end;
procedure UserInfo; // обновление донных о себе
var // где-то тут что-то надо править чтобы в интерлюде работало
i:word;
begin
if InitMode then MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
i:=22;
ReadS(i);
i:=i+44;
MyMaxHP:=ReadD(i);
MyHP:=ReadD(i);
MyMaxMP:=ReadD(i);
MyMP:=ReadD(i);
i:=i+363;
MyMaxCP:=ReadD(i);
MyCP:=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);
#$21: MyCP:=ReadD(i*8+14);
#$22: MyMaxCP:=ReadD(i*8+14);
end;
end;
begin
if pck = '' then exit;
if (ConnectName = NickName) and FromServer and (not InitMode) then // разбор пакетов от сервера в Боевом режиме
case pck[1] of
#$01: begin // MoveToLocation:h(ObjectID)d(CurX)d(CurY)d(CurZ)d(DestX)d(DestY)d(DestZ)
povtor:= TestPovtor(ReadD(2));
if Povtor > 0 then
begin
updateDB(Povtor, ReadD(2), ReadD(18), ReadD(22), ReadD(26), false);
end;
end;
#$03: ; // CharInfo:d(X)d(Y)d(Z)-(4)h(ObjectID)s(Name)d(Race)d(Sex)d(ClassID)-(4)i(Head)i(RHand)i(LHand)i(Gloves)i(Chest)i(Legs)i(Feet)i(Back)i(LRHand)i(Hair)d(PvPFlag)d(Carma)d(MSpeed)d(PSpeed)d(PvpFlag)d(Karma)d(RunSpeed)d(WalkSpeed)d(SwimRunSpeed)d(SwimWalkSpeed)d(FlRunSpeed)d(FlWalkSpeed)d(FlyRunSpeed)d(FlyWalkSpeed)f(MovementSpeedMultiplier)f(AttackSpeedMultiplier)f(CollisionRadius)f(CollisionHeight)d(HairStyle)d(HairColor)d(Face)d(AccessLevel)s(Title)d(ClanId)d(ClanCrestId)d(AllyId)d(AllyCrestId)d(SiegeFlags)b(Sitting)b(Running)b(InCombat)b(AlikeDead)b(Invisible)b(MountType)b(PrivateStoreType)
#$04: if ReadS(22) = NickName then UserInfo; // UserInfo:d(X)d(Y)d(Z)d(Heading)h(ObjectID)s(Name)d(Race)d(Sex)d(ClassID)d(Level)d(Exp)d(STR)d(DEX)d(CON)d(INT)d(WIT)d(MEN)d(MaxHP)d(CurrentHP)d(MaxMP)d(CurrentMP)d(SP)d(CurrentLoad)d(MaxLoad)d(Unknown)d(Under)d(REar)d(LEar)d(Neck)d(RFinger)d(LFinger)d(Head)d(RHand)d(LHand)d(Gloves)d(Chest)d(Legs)d(Feet)d(Back)d(LRHand)d(Hair)i(Under)i(REar)i(LEar)i(Neck)i(RFinger)i(LFinger)i(Head)i(RHand)i(LHand)i(Gloves)i(Chest)i(Legs)i(Feet)i(Back)i(LRHand)i(Hair)d(PAtk)d(PAtkSpd)d(PDef)d(EvasionRate)d(Accuracy)d(CritikalHit)d(MAtk)d(MAtkSpd)d(PAtkSpd)d(MDef)d(PvpFlag)d(Karma)d(RunSpeed)d(WalkSpeed)d(SwimRunSpeed)d(SwimWalkSpeed)d(FlRunSpeed)d(FlWalkSpeed)d(FlyRunSpeed)d(FlyWalkSpeed)f(MovementSpeedMultiplier)f(AttackSpeedMultiplier)f(CollisionRadius)f(CollisionHeight)d(HairStyle)d(HairColor)d(Face)d(AccessLevel)s(Title)d(ClanId)d(ClanCrestId)d(AllyId)d(AllyCrestId)d(IsClanLeader)b(MountType)b(PrivateStoreType)b(DwarvenCraft)d(PkKills)d(PvpKills)b(Cubics)b(Cubics)b(FindPartyMembers)d(AbnormalEffect)b()d(ClanPrivileges)d()d()d()d()d()d()d()b(RecomLeft)b()b(RecomHave)b()
#$05{, #$48}: begin // 05= Attack:d(AttackerID)d(TargetID)d(Damage)b(Flags)d(X)d(Y)d(Z)h(Hits)
if ReadD(6) = MyID then
begin
Povtor:= TestPovtor(ReadD(2));// 48= MagicSkillUse
if Povtor = 0 then AddtoDB (ReadD(2), ReadD(15), ReadD(19), ReadD(23), true)
else UpdateDB(Povtor, ReadD(2), ReadD(15), ReadD(19), ReadD(23), true);
end;
end;
#$06: begin // Die:d(ChaID)
povtor:= TestPovtor(ReadD(2));
if Povtor > 0 then
begin
if MobsID[povtor] = TargetID then
begin
TargetID:= 0;
// статистика тут должна считаться
// и споил надо делать
end;
DelDBItem(povtor);
end;
end;
#$0C: ; // DropItem:h(PlayerID)h(ObjectID)i(ItemID)d(X)d(Y)d(Z)d(Stackable)d(Count)
#$0E: if MyID=ReadD(2) then StatusUpdate; // StatusUpdate:h(ObjectID)d(Attributes)
{ #$12: begin // DeleteObject:h(ObjectID)
povtor:= TestPovtor(ReadD(2));
if Povtor > 0 then
begin
DelDBItem(povtor);
end;
end;}
#$16: begin // NpcInfo:h(ObjectID)d(NpcTypeID)d(IsAttackable)d(X)d(Y)d(Z)d(Heading)d(Unknown)d(MAtkSpd)d(PAtkSpd)d(RunSpd)d(WalkSpd)d(SwimRunSpd)d(SwimWalkSpd)d(FlRunSpd)d(FlWalkSpd)d(FlyRunSpd)d(FlyWalkSpd)f(ProperMultiplier)f(PAtkSpd)f(CollisionRadius)f(CollisionHeight)d(RHand)d(Unknown)d(LHand)b(Unknown)b(IsRunning)b(IsInCombat)b(IsALikeDead)b(IsSummoned)s(Name)s(Title)
if InMobsList(ReadD(6)) and (ReadD(10)=1) and (pck[121]=#$00) then
begin
Povtor:= TestPovtor(ReadD(2));
if Povtor = 0 then AddtoDB (ReadD(2), ReadD(14), ReadD(18), ReadD(22), false)
else UpdateDB(Povtor, ReadD(2), ReadD(14), ReadD(18), ReadD(22), false);
end;
end;
end;
if (ConnectName = NickName) and FromClient and (not InitMode) then // разбор пакетов от клиента в боевом режиме
case pck[1] of
#$04: {TargetID:= ReadD(2)}; // Action:h(ObjectID)d(OriginX)d(OriginY)d(OriginZ)b(ActionID)
#$38: UserCommandsCombatMode; // Say2:s(Text)d(Type)s(Target)
#$48: begin // ValidatePosition:d(X)d(Y)d(Z)d(Heading)d(Data)
MyX:= ReadD(2);
MyY:= ReadD(6);
MyZ:= ReadD(10);
end;
end;
if (ConnectName = NickName) and FromServer and InitMode then // разбор клиентов от сервера в режиме настройки бота
case pck[1] of
#$04: if ReadS(22) = NickName then UserInfo; // UserInfo:d(X)d(Y)d(Z)d(Heading)h(ObjectID)s(Name)d(Race)d(Sex)d(ClassID)d(Level)d(Exp)d(STR)d(DEX)d(CON)d(INT)d(WIT)d(MEN)d(MaxHP)d(CurrentHP)d(MaxMP)d(CurrentMP)d(SP)d(CurrentLoad)d(MaxLoad)d(Unknown)d(Under)d(REar)d(LEar)d(Neck)d(RFinger)d(LFinger)d(Head)d(RHand)d(LHand)d(Gloves)d(Chest)d(Legs)d(Feet)d(Back)d(LRHand)d(Hair)i(Under)i(REar)i(LEar)i(Neck)i(RFinger)i(LFinger)i(Head)i(RHand)i(LHand)i(Gloves)i(Chest)i(Legs)i(Feet)i(Back)i(LRHand)i(Hair)d(PAtk)d(PAtkSpd)d(PDef)d(EvasionRate)d(Accuracy)d(CritikalHit)d(MAtk)d(MAtkSpd)d(PAtkSpd)d(MDef)d(PvpFlag)d(Karma)d(RunSpeed)d(WalkSpeed)d(SwimRunSpeed)d(SwimWalkSpeed)d(FlRunSpeed)d(FlWalkSpeed)d(FlyRunSpeed)d(FlyWalkSpeed)f(MovementSpeedMultiplier)f(AttackSpeedMultiplier)f(CollisionRadius)f(CollisionHeight)d(HairStyle)d(HairColor)d(Face)d(AccessLevel)s(Title)d(ClanId)d(ClanCrestId)d(AllyId)d(AllyCrestId)d(IsClanLeader)b(MountType)b(PrivateStoreType)b(DwarvenCraft)d(PkKills)d(PvpKills)b(Cubics)b(Cubics)b(FindPartyMembers)d(AbnormalEffect)b()d(ClanPrivileges)d()d()d()d()d()d()d()b(RecomLeft)b()b(RecomHave)b()
#$06: if (ReadD(2) = TargetID) and (MobsListCount <> 0) then // Die:d(ChaID)
if (MobsList[MobsListCount] <> 0) then
begin
SendMsg('Моб №' + inttostr(MobsListCount) + ' добавлен в базу');
log.Lines.Add('Моб №' + inttostr(MobsListCount) + ' добавлен в базу');
MobsListCount:= 0;
TargetID:= 0;
end;
#$16: if (ReadD(2) = TargetID) and (MobsListCount <> 0) then MobsList[MobsListCount]:= ReadD(6);//NpcInfo:h(ObjectID)d(NpcTypeID)d(IsAttackable)d(X)d(Y)d(Z)d(Heading)d(Unknown)d(MAtkSpd)d(PAtkSpd)d(RunSpd)d(WalkSpd)d(SwimRunSpd)d(SwimWalkSpd)d(FlRunSpd)d(FlWalkSpd)d(FlyRunSpd)d(FlyWalkSpd)f(ProperMultiplier)f(PAtkSpd)f(CollisionRadius)f(CollisionHeight)d(RHand)d(Unknown)d(LHand)b(Unknown)b(IsRunning)b(IsInCombat)b(IsALikeDead)b(IsSummoned)s(Name)s(Title)
end;
if (ConnectName = NickName) and FromClient and InitMode then // разбор пакетов от клиента в режиме настройки бота
case pck[1] of
#$04: TargetID:= ReadD(2); // Action:h(ObjectID)d(OriginX)d(OriginY)d(OriginZ)b(ActionID)
#$38: UserCommandsInitMode; // Say2:s(Text)d(Type)s(Target)
#$48: begin // ValidatePosition:d(X)d(Y)d(Z)d(Heading)d(Data)
MyX:= ReadD(2);
MyY:= ReadD(6);
MyZ:= ReadD(10);
end;
end;
end.
Ну все, Господа... Выкладываю свой собственный ботоскрипт- локомотив :D
Прошу высказывать свои замечания и предложения.
Надо посмотреть, попробовать. :)
Константы для ИЛ и С4
установить константы в зависимости от типа игры (С4 или Интерлюд)
//CreateItemBase
offs1=24; //16 для С4, 24 для IL
//InventoryUpdate
offs2=22; //14 для С4, 22 для IL
//UserInfo, основной цикл
offs3=48; //44 для С4, 48 для IL
//InventoryUpdate, основной цикл
offs4=41; //32 для С4, 41 для IL
//StatsUpdate
offs5=14; //одинаково для C4 и IL
Например в твоем случае
Код:
procedure UserInfo; // обновление донных о себе
var // где-то тут что-то надо править чтобы в интерлюде работало
i:word;
begin
if InitMode then MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
i:=22;
ReadS(i);
i:=i+48; //<----------- 44 для С4, 48 для IL
MyMaxHP:=ReadD(i);
MyHP:=ReadD(i);
MyMaxMP:=ReadD(i);
MyMP:=ReadD(i);
i:=515 //<-------i+363;
MyMaxCP:=ReadD(i);
MyCP:=ReadD(i);
end;
Так и не смог моба в базу добавить (на интерлюде).