Показать сообщение отдельно
Старый 13.03.2008, 18:43   #288
Местный
 
Аватар для nezabudkin
 
Регистрация: 06.03.2008
Сообщений: 154
Сказал Спасибо: 46
Имеет 130 спасибок в 38 сообщенях
nezabudkin
По умолчанию

Ну все, Господа... Выкладываю свой собственный ботоскрипт- локомотив :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.
nezabudkin вне форума   Ответить с цитированием