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