PDA

Просмотр полной версии : помогите с доработкой


VismuT
13.11.2008, 04:31
доброго время суток, собственно есть хороший скрипт "Бот - локомотив от Alexus" решил его немного доработать включив в него спойл. Получилось вот что

{################################################# ############################
Бот - локомотив от Alexus
версия : 0.3 (бета)
дата: 08.04.08

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

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

Недостатки: (со временем будет исправлено)
- бот не умеет обходить препядствия
- бот может увязаться за атаковавшим его другим игроком

Инструкция:
1. Запускаем ПакетХак, запускаем игрового клиента
2. Внимательно НАСТРАИВАЕМ параметры в секции настройки, жмем кнопку "Сохранить" и запускаем скрипт.
3. Добираемся до места кача
4. Выбираем в таргет моба на которого хотим охотится и отправляем в общий чат-> 1
5. Валим моба. Если все правильно сделали будет выдано сообщение в чате что моб добавлен.
6. Выбираем следующего моба отправляем в общий чат цифру 2, валим его и т.д. можно выбрать до 10 разных тварей.
7. Становимся в центр кача и отправляем в общий чат-> pos , если все правильно то в чате будет выдано сообщение, что координаты заданы.
8. Бежим к краю радиуса кача и отправляем в общий чат-> dist, в чате вылезет сообщение от системы, что радиус задан.
9. Валим как можно больше мобов в округе, становимся примерно в центр и отправляем в общий чат-> start ,
если все сделано верно, то будет выдано соответствующее сообщение.
10. Если бот поймал моба в таргет и побежал его атаковать, то можно свернуть окно игры
и смотреть на информационное окно скрипта.
################################################## ###########################}

const
//################### Сеция настройки бота ############################################
NickName = 'HiliH'; // Твой ник в игре
Interlude = true; // C4 - false, C6 - true;
HPMedium = 40; // Уровень жизни, при котором начинаем глотать банки
HPBottleID = 1061; // ItemID 1060=Lesser Healing Potion; 1061=Healing Potion; 1539=Greater Healing Potion;
Vertical = 300; // Вертикальный радиус кача
InvRazmer = 99; // Размер инвентаря -1 (т.е. если инвентарь 80, то пишем сюда 79)
//############# Секция расширенной настройки для опытных ботоводеров :) ###################################
TimerCombat_Interval = 1000; // частота срабатывания таймера атаки в милисекундах, чем меньше это число, тем быстрее бот будет думать.
TimerPickUp_Interval = 750; // частота срабатывания таймера сбора дропа, чем меньше это число, тем быстрее бот будет думать.
TimerForm_Interval = 10000; // частота срабатывания таймера обновления формы, чем меньше это число, тем быстрее будут обновляться данные в форме.
DrinkDelay = 14; // минимальное время задержки повторного питься бутылки (10 - 20 сек)
Attack_Time = 60; // Время на убивание моба в секундах.
PickUp_Time = 30; // Врямя на поднятие дропа в секундах.
OblastVidimosti = 1000; // Приращение к радиусу кача, для мобов которые стоят прямо на границе радиуса (изменять от 100 до 1000)
maximumItems = 100; // Размер базы мобов и дропа
//################################################## ######################################
NpcTypeID_List_Razmer = 10; // Размер списка мобов (не трогать!)
OX = 1; OY = 2; OZ= 3; // Служебные константы

var
InitMode, PickUpMode : 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; // Моб атакует меня или стоит в сторонке...
MobsLastIndex: integer; // индекс последнего элемента базы

NpcTypeID_List : array [1..NpcTypeID_List_Razmer] of integer; // Список мобов (коды мобов)
NpcTypeID_List_Count : integer; // Текущий размер списка
NpcTypeID_CurrentMob : integer;

Items_ObjectID : array [1..maximumItems] of integer; // БД дропа с мобов
Items_ItemID : array [1..maximumItems] of integer;
Items_XYZ : array [1..maximumItems, 1..3] of integer;
ItemsLastIndex: integer;

Inventory: array[0..InvRazmer, 0..9] of integer; // инвентарь (itemType1, ObjectID, ItemID, count, itemType2, CustType1, isEquipped, BodyPart, EnchantLevel, CustType2)
HPBottleObjID, HPBottleCount : integer; // ObjID и количество HP-бутылей

TargetID, LastKilledMobObjID : integer; // Текущая цель, последний убитый моб

MobsKilled : integer; // счетчик убитых мобов

Povtor: integer;
CenterX, CenterY, CenterZ : integer; // Центр кача
Radius: integer; // Радиус кача
//--------------------------------------------------------
MyX, MyY, MyZ : integer; // Мои статы
MyID, MyHP, MyMaxHP: integer;
MyMP, MyMaxMP, MyCP, MyMaxCP: integer;
HPlevelProcent : integer; // уровень жизни в прочентах
//--------------------------------------------------------
frm: TForm; // переменные описания формы
log, MobsDBscreen, ItemsDBScreen: 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, textMobsKilled: TEdit;
//----------------------------------------------------------
TimerForm, TimerCombat, TimerPickUp : TTimer; // таймеры
time1: integer;
Calculated_AttackTime, Calculated_PickUpTime : integer;
AttackCycle: integer; // Цикл атаки
//################################################## ############################################

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;
time1:=1;
Calculated_AttackTime:= round (1000 / TimerCombat_Interval * Attack_Time);
Calculated_PickUpTime:= round (1000 / TimerPickUp_Interval * PickUp_Time);
HPlevelProcent:= 0;
HPBottleObjID:= 0;
HPBottleCount:= 0;
InitMode:= true;
TimerCombat:=TTimer.Create(nil); // создаем таймеры
TimerCombat.OnTimer:=@OnTimerCombat;
TimerCombat.enabled:=false;
TimerCombat.interval:= TimerCombat_Interval;
TimerForm:=TTimer.Create(nil);
TimerForm.OnTimer:=@OnTimerForm;
TimerForm.enabled:=true;
TimerForm.interval:= TimerForm_Interval;
TimerPickUp:=TTimer.Create(nil);
TimerPickUp.OnTimer:=@OnTimerPickUp;
TimerPickUp.enabled:=false;
TimerPickUp.interval:= TimerPickUp_Interval;
frmParamIndex:=0; // создаем контролы в форме
frm:= TForm.Create(nil);
frm.Caption:= 'BOT by Alexus ver: 0.3 beta';
frm.BorderStyle := bsSizeable;
frm.Position := poScreenCenter;
frm.Width:=650;
frm.Height:=700;
MobsDBscreen:=TMemo.Create(frm);
MobsDBscreen.parent:=frm;
MobsDBscreen.ReadOnly:=true;
MobsDBscreen.ScrollBars:=2;
MobsDBscreen.Top:=1;
MobsDBscreen.Width:=460;
MobsDBscreen.Height:=285;
MobsDBscreen.Lines.Add('Мобы');
ItemsDBscreen:=TMemo.Create(frm);
ItemsDBscreen.parent:=frm;
ItemsDBscreen.ReadOnly:=true;
ItemsDBscreen.ScrollBars:=2;
ItemsDBscreen.Top:=286;
ItemsDBscreen.Width:=460;
ItemsDBscreen.Height:=285;
ItemsDBscreen.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:=2;
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('Цикл атаки:');
textMobsKilled:= CreateTextBox('MobsKilled');
CreateLabel('Убито моб:');
frm.Show; // выводим форму на экран
buf:= #$0F; // принудительно вызываем пакеты инвентаря и userinfo
SendToServerEx(NickName);
end;

procedure ClearDB; // Очистка БД
var // Надо все занулять, иначе там хрень всякая вылезает или старые данные
i, n: word;
begin
MobsLastIndex:= 0; // Очищаем переменные
ItemsLastIndex:= 0;
TargetID:= 0;
LastKilledMobObjID:= 0;
MobsKilled:= 0;
Povtor:= 0;
CenterX:= 0;
CenterY:= 0;
CenterZ:= 0;
Radius:= 0;
AttackCycle:= 0;
for i:=1 to NpcTypeID_List_Razmer do NpcTypeID_List[i]:= 0;
NpcTypeID_List_Count:= 0;
NpcTypeID_CurrentMob:= 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;
Items_ObjectID[i]:= 0;
Items_ItemID[i]:= 0;
Items_XYZ[i, OX]:= 0;
Items_XYZ[i, OY]:= 0;
Items_XYZ[i, OZ]:= 0;
end;
for i:=0 to InvRazmer do for n:=0 to 9 do Inventory[i, n]:= 0;
end;

function Wait(var tick: integer;Timewait: Integer): Boolean; // сквозная проверка без остановки скрипта (c)dmitry501, modifed by Sh00rGo
var
t: integer;
begin
result:=false;
t:=Round(Time*86400);
if t>(tick+Timewait) then begin
if tick>0 then result:=true;
tick:=t;
end;
end;

//############################## Модуль работы с Инвентарем ###########################
procedure InventoryCreate;
var
i,k, offset : integer;
begin
if interlude then offset:= 8 else offset:=0;
for i:=0 to InvRazmer do
if (i<ReadH(4)) then begin
Inventory[i,0]:=ReadH(i*(28+offset)+6); // itemType1
Inventory[i,1]:=ReadD(i*(28+offset)+8); // ObjectId
Inventory[i,2]:=ReadD(i*(28+offset)+12); // ItemID
Inventory[i,3]:=ReadD(i*(28+offset)+16); // count
Inventory[i,4]:=ReadH(i*(28+offset)+20); // itemType2
Inventory[i,5]:=ReadH(i*(28+offset)+22); // CustType1
Inventory[i,6]:=ReadH(i*(28+offset)+24); // isEquipped
Inventory[i,7]:=ReadD(i*(28+offset)+26); // BodyPart
Inventory[i,8]:=ReadH(i*(28+offset)+30); // EnchantLevel
Inventory[i,9]:=ReadH(i*(28+offset)+32); // CustType2
end else
for k:=0 to 9 do Inventory[i,k]:=0; // забиваем нулями
end;

procedure InventoryUpdate;
var
i,j,k, offset: integer;
begin
if interlude then offset:= 8 else offset:=0;
for j:=0 to (ReadH(2)-1) do
begin
case pck[j*(30+offset)+4] of
#$01: k:=0; // add item, запишет на пустую ячейку
#$02: k:=ReadD(j*(30+offset)+8); // mod item
#$03: begin // remove item, обнулит ячейки удаленного предмета
k:=ReadD(j*(30+offset)+8);
for i:=0 to InvRazmer do if (Inventory[i,0]=k) then
begin
for k:=0 to 9 do Inventory[i,k]:=0;
exit;
end;
end;
end;
for i:=0 to InvRazmer do if (Inventory[i,1]=k) then
begin
Inventory[i,0]:=ReadH(j*(30+offset)+6); // itemType1
Inventory[i,1]:=ReadD(j*(30+offset)+8); // ObjectId
Inventory[i,2]:=ReadD(j*(30+offset)+12); // ItemID
Inventory[i,3]:=ReadD(j*(30+offset)+16); // count
Inventory[i,4]:=ReadH(j*(30+offset)+20); // itemType2
Inventory[i,5]:=ReadH(j*(30+offset)+22); // CustType1
Inventory[i,6]:=ReadH(j*(30+offset)+24); // isEquipped
Inventory[i,7]:=ReadD(j*(30+offset)+26); // BodyPart
Inventory[i,8]:=ReadH(j*(30+offset)+30); // EnchantLevel
Inventory[i,9]:=ReadH(j*(30+offset)+32); // CustType2
break;
end;
end;
end;

function GetInv(obj,up,down:integer): integer; // up и down не проверяются
var // 0-itemType1, 1-ObjectId, 2-ItemID, 3-count, 4-itemType2, 5-CustType1, 6-isEquipped, 7-BodyPart, 8-EnchantLevel, 9-CustType2
i: integer;
begin
for i:=0 to InvRazmer do if (Inventory[i,up]=obj) then
begin
Result:=Inventory[i,down];
exit;
end;
Result:=-1;
end;

{procedure UseItemID(ItemID:integer); //Использовать предмет с заданным ItemID
var
ObjItemID : integer;
begin
ObjItemID:= GetInv(ItemID,2,1);
if ObjItemID = -1 then exit;
buf:=#$14;
WriteD(ObjItemID);
WriteD(0);
SendToServerEx(NickName);;
end;}

procedure UseItemObjID(ItemObjID:integer); //Использовать предмет с заданным ItemID
begin
buf:=#$14;
WriteD(ItemObjID);
WriteD(0);
SendToServerEx(NickName);;
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 AddDroppedItem (ObjID, ItemID, X, Y, Z: integer); // Процедура добавляет дропнутую вещь в БД
begin
inc (ItemsLastIndex);
if ItemsLastIndex > maximumItems then exit;
Items_ObjectID[ItemsLastIndex]:= ObjID;
Items_ItemID[ItemsLastIndex]:= ItemID;
Items_XYZ[ItemsLastIndex, OX]:= X;
Items_XYZ[ItemsLastIndex, OY]:= Y;
Items_XYZ[ItemsLastIndex, OZ]:= Z;
log.Lines.Add('Вещь добавлена, индекс в БД: '+ inttostr(ItemsLastIndex));
end;

procedure AddtoDB (id, x,y,z : integer; agression : boolean); // Процедура добавляет в БД нового моба
var
i:integer;
dist: integer;
begin
dist:= rastoyanie (x,y,z); // вычиляем расстояние от центра кача до моба
if dist > (Radius + OblastVidimosti) then exit; // если моб слишко далеко то ничего не делаем
inc (MobsLastIndex); // увеличиваем размер БД
log.Lines.Add('Моб добавлен, индекс в БД: '+ inttostr(i));
if agression then log.Lines.Add('На нас напала какая-то вражина.');
MobsID[MobsLastIndex]:= id; // Записываем моба
MobsDist[MobsLastIndex]:= dist;
MobsXYZ[MobsLastIndex, OX]:= x;
MobsXYZ[MobsLastIndex, OY]:= y;
MobsXYZ[MobsLastIndex, OZ]:= z;
MobsAgression[MobsLastIndex]:= 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 + OblastVidimosti) 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); // процедура удалаяет моба из БД
var
n: 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 < MobsLastIndex then for n:= i+1 to MobsLastIndex do // если надо, производим циклический сдвиг данных в массивах
begin
MobsID[n-1]:= MobsID[n];
MobsDist[n-1]:= MobsDist[n];
MobsXYZ[n-1, OX]:= MobsXYZ[n, OX];
MobsXYZ[n-1, OY]:= MobsXYZ[n, OY];
MobsXYZ[n-1, OZ]:= MobsXYZ[n, OZ];
MobsAgression[n-1]:= MobsAgression[n];
end;
dec (MobsLastIndex); // уменьшаем размер БД
end;

procedure DelDroppedItem (i: integer); // процедура удалаяет вещь из БД
var
n: integer;
begin
Items_ObjectID[i]:= 0;
Items_ItemID[i]:= 0;
Items_XYZ[i, OX]:= 0;
Items_XYZ[i, OY]:= 0;
Items_XYZ[i, OZ]:= 0;
log.Lines.Add('Вещь удалена, индекс в БД: '+ inttostr(i));
if i < ItemsLastIndex then for n:= i+1 to ItemsLastIndex do
begin
Items_ObjectID[n-1]:= Items_ObjectID[n];
Items_ItemID[n-1] := Items_ItemID[n];
Items_XYZ[n-1, OX]:= Items_XYZ[n, OX];
Items_XYZ[n-1, OY]:= Items_XYZ[n, OY];
Items_XYZ[n-1, OZ]:= Items_XYZ[n, OZ];
end;
dec (ItemsLastIndex);
end;

function CheckItems (id: integer) : integer; // функция проверяет наличие заданной вещи в БД
var
i: integer;
begin
result:= 0;
for i:=1 to ItemsLastIndex do if Items_ObjectID[i] = id then
begin
result:=i; // И возвращаем его индекс по БД
break;
end;
end;

function TestPovtor (id: integer) : integer; // функция проверяет наличие заданного моба в БД
var
i: integer;
begin
result:=0;
for i:=1 to MobsLastIndex 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 NpcTypeID_List_Count do if NpcTypeID_List[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; // функция проверки правильности задания всех параметров для начала кача
begin
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 (NpcTypeID_List_Count > 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
if (NpcTypeID_List_Count+1) <> strtoint(ReadS(2)) then
begin
SendMsg('Добавлять мобов можно тока по очереди 1, 2, 3...');
pck:='';
exit;
end;
NpcTypeID_CurrentMob:= 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:='';
SendMsg('Искуственный интелект остановлен.');
log.Lines.Add('Искуственный интелект остановлен.');
StopGame;
end;

end;
end;

procedure StopGame; // остановка кача
begin
TimerCombat.enabled:= false;
// InitMode:= true;
TimerPickUp.enabled:=false;
TargetID:= 0;
ClearDB;
end;

function GetMinDistID : integer; // функция поиска ближайшего моба в БД
var
i, dist : integer;
begin
dist:=10000; // задаем заранее нереальную дистанцию
for i:=1 to MobsLastIndex do if (MobsID[i] <> 0) and (MobsDist[i] < dist) then
begin // фишка в том, что в базе хранятся расстояния не до меня, а до центра кача
dist:= MobsDist[i]; // но в катах то расстояния небольшие
result:= i; // если нашли хоть одного моба или несколько возращаем его индекс ближайшего к центру кача
end;
if dist = 10000 then result:= 0; // иначе возвращаем 0 (ничего не найдено)
end;

function AgroTest : integer; // функция проверяет, атакует ли меня кто-нибудь или нет
var
i: integer;
begin
result:=0;
for i:=1 to MobsLastIndex do if MobsAgression[i] then // ищем первого попавшегося моба, который нас атакует
begin
result:= i; // возвращаем его индекс по БД
break;
end;
end;

procedure PhisicalAttack; // команда атаки
begin
buf:=#$04; //action
buf:=hstr('2F FE 00 00 00 00 00 00 00 00');
WriteD(TargetID);
WriteD(MyX);
WriteD(MyY);
WriteD(MyZ);
WriteC(0);
SendToServerEx(NickName);
SendToServerEX('HiliH');
end;

procedure InitPickUpMode(mode: boolean);
begin
if mode then
begin
PickUpMode:= true;
TimerCombat.enabled:= false;
TimerPickUp.enabled:= true;
end
else
begin
PickUpMode:= false;
TimerCombat.enabled:= true;
TimerPickUp.enabled:= false;
end;
end;

procedure OnTimerPickUp (Sender: TObject); // таймер поднятия дропа
var
povtor: integer;
begin
if (AgroTest > 0) and (TargetID = 0) then
begin
InitPickUpMode(false);
exit;
end;
if (ItemsLastIndex > 0) and (TargetID = 0) then
begin
TargetID:= Items_ObjectID[ItemsLastIndex];
AttackCycle:= 0;
PhisicalAttack;
exit;
end;
if (ItemsLastIndex > 0) and (TargetID > 0) then
begin
inc (AttackCycle);
if ((AttackCycle mod 5) = 0) then PhisicalAttack;
if AttackCycle > Calculated_PickUpTime then
begin
Povtor:= CheckItems(TargetID);
if Povtor <> 0 then DelDroppedItem(Povtor);
TargetID:= 0;
end;
exit;
end;
if (ItemsLastIndex = 0) then InitPickUpMode(false);
end;

procedure OnTimerCombat (Sender: TObject); // боевой таймер, вся логика поведения бота находится именно здесь!!!
var
Agro, MinDistID: integer;
begin
if MobsLastIndex = 0 then // если нет мобов в базе, то
begin
if ItemsLastIndex > 0 then InitPickUpMode(true); // надо дроп подбирать
exit; // выходим от сюда
end;
if TargetID > 0 then // если в прицеле есть моб, то
begin // валим вражину
if ((AttackCycle mod 5) = 0) then PhisicalAttack;
inc(AttackCycle);
if AttackCycle > Calculated_AttackTime then // если валим моба больше минуты, значит это баг...
begin
Povtor:= TestPovtor(TargetID);
if Povtor <> 0 then DelDBItem(Povtor);
TargetID:= 0;
end;
exit;
end;
Agro:= AgroTest; // если есть мобы в базе и нет текущей цели, то
MinDistID:= GetMinDistID; // запускаем алгоритм выбора цели
if Agro > 0 then // если нас кто-то атакует, то его и выбираем
begin
TargetID:= MobsID[Agro];
PhisicalAttack; // берем вражину в таргет
AttackCycle:= 0;
exit;
end;
if ItemsLastIndex > 0 then // если чего-то валяется на земле, то
begin
InitPickUpMode(true); // надо дроп подбирать
exit;
end;
if MobsDist[MinDistID] <= Radius then // иначе ищем ближайшего #################################################
begin
TargetID:= MobsID[MinDistID];
PhisicalAttack; // берем вражину в таргет
AttackCycle:= 0;
exit;
end
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);
textMobsKilled.text:= inttostr(MobsKilled);
MobsDBscreen.lines.Clear;
for i:=1 to MobsLastIndex do // выводим БД мобов
begin
if TargetID = MobsID[i] then MobsDBscreen.lines.add ('-> '+inttostr(i)+' МобID: '+inttostr(MobsID[i])+' дистанция '+inttostr(MobsDist[i]))
else if MobsAgression[i] then MobsDBscreen.lines.add ('<- '+inttostr(i)+' МобID: '+inttostr(MobsID[i])+' дистанция '+inttostr(MobsDist[i]))
else MobsDBscreen.lines.add ('-- '+inttostr(i)+' МобID: '+inttostr(MobsID[i])+' дистанция '+inttostr(MobsDist[i]));
end;
ItemsDBscreen.lines.Clear; // выводим БД дропа
for i:=1 to ItemsLastIndex do ItemsDBscreen.lines.add ('индекс в БД: '+inttostr(i)+' объект ID: '+inttostr(Items_ObjectID[i])+' ID вещи: '+inttostr(Items_ItemID[i]));
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 Free; //Вызывается при выключении скрипта
begin
MobsDBscreen.free;
ItemsDBscreen.free;
log.free;
frm.free;
ClearDB;
TimerForm.free;
TimerCombat.free;
TimerPickUp.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);
if interlude then i:=i+48 else 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;
if MyMaxHP > 0 then HPlevelProcent:= Round((MyMaxHP/100)*HPMedium);
end;

procedure DrinkBottle; // пьем бутылки и следим за их количеством
begin
if HPBottleCount > 0 then
begin
UseItemObjID(HPBottleObjID);
dec (HPBottleCount);
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(D estX)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(Wal kSpeed)d(SwimRunSpeed)d(SwimWalkSpeed)d(FlRunSpeed )d(FlWalkSpeed)d(FlyRunSpeed)d(FlyWalkSpeed)f(Move mentSpeedMultiplier)f(AttackSpeedMultiplier)f(Coll isionRadius)f(CollisionHeight)d(HairStyle)d(HairCo lor)d(Face)d(AccessLevel)s(Title)d(ClanId)d(ClanCr estId)d(AllyId)d(AllyCrestId)d(SiegeFlags)b(Sittin g)b(Running)b(InCombat)b(AlikeDead)b(Invisible)b(M ountType)b(PrivateStoreType)
#$04: if ReadS(22) = NickName then // 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(F eet)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(Ha ir)d(PAtk)d(PAtkSpd)d(PDef)d(EvasionRate)d(Accurac y)d(CritikalHit)d(MAtk)d(MAtkSpd)d(PAtkSpd)d(MDef) d(PvpFlag)d(Karma)d(RunSpeed)d(WalkSpeed)d(SwimRun Speed)d(SwimWalkSpeed)d(FlRunSpeed)d(FlWalkSpeed)d (FlyRunSpeed)d(FlyWalkSpeed)f(MovementSpeedMultipl ier)f(AttackSpeedMultiplier)f(CollisionRadius)f(Co llisionHeight)d(HairStyle)d(HairColor)d(Face)d(Acc essLevel)s(Title)d(ClanId)d(ClanCrestId)d(AllyId)d (AllyCrestId)d(IsClanLeader)b(MountType)b(PrivateS toreType)b(DwarvenCraft)d(PkKills)d(PvpKills)b(Cub ics)b(Cubics)b(FindPartyMembers)d(AbnormalEffect)b ()d(ClanPrivileges)d()d()d()d()d()d()d()b(RecomLef t)b()b(RecomHave)b()
begin
UserInfo;
if MyHP = 0 then // Проверка не убили ли нас...
begin
SendMsg('Нас убили...');
log.Lines.Add('Нас убили...');
StopGame;
end;
end;
#$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
LastKilledMobObjID:=TargetID;
inc (MobsKilled); // подводим статистику
TargetID:= 0;
buf:=hstr('2F 2A 00 00 00 00 00 00 00 00');
SendToServerEX('HiliH');
// споил надо делать тута
end;
DelDBItem(povtor);
end;
end;
#$0C: if LastKilledMobObjID = ReadD(2) then // DropItem:h(PlayerID)h(ObjectID)i(ItemID)d(X)d(Y)d( Z)d(Stackable)d(Count)
begin
AddDroppedItem(ReadD(6), ReadD(10), ReadD(14), ReadD(18), ReadD(22));
end;
#$0D: if TargetID = ReadD(6) then // GetItem:d(PlayerID)h(ObjectID)d(X)d(Y)d(Z)
begin
TargetID:= 0;
end;
#$0E: if MyID=ReadD(2) then // StatusUpdate:h(ObjectID)d(Attributes)
begin
StatusUpdate;
if (MyHP > 0) and (MyHP < HPlevelProcent) then if Wait(time1,DrinkDelay) then DrinkBottle; // пьем бутылки
if MyHP > HPlevelProcent then time1:=1;
if MyHP = 0 then // Проверка не убили ли нас...
begin
SendMsg('Нас убили...');
log.Lines.Add('Нас убили...');
StopGame;
end;
end;
#$12: begin // DeleteObject:h(ObjectID)
if LastKilledMobObjID = ReadD(2) then LastKilledMobObjID:= 0
else begin
Povtor:= CheckItems(ReadD(2));
if Povtor <> 0 then DelDroppedItem(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(FlRu nSpd)d(FlWalkSpd)d(FlyRunSpd)d(FlyWalkSpd)f(Proper Multiplier)f(PAtkSpd)f(CollisionRadius)f(Collision Height)d(RHand)d(Unknown)d(LHand)b(Unknown)b(IsRun ning)b(IsInCombat)b(IsALikeDead)b(IsSummoned)s(Nam e)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(F eet)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(Ha ir)d(PAtk)d(PAtkSpd)d(PDef)d(EvasionRate)d(Accurac y)d(CritikalHit)d(MAtk)d(MAtkSpd)d(PAtkSpd)d(MDef) d(PvpFlag)d(Karma)d(RunSpeed)d(WalkSpeed)d(SwimRun Speed)d(SwimWalkSpeed)d(FlRunSpeed)d(FlWalkSpeed)d (FlyRunSpeed)d(FlyWalkSpeed)f(MovementSpeedMultipl ier)f(AttackSpeedMultiplier)f(CollisionRadius)f(Co llisionHeight)d(HairStyle)d(HairColor)d(Face)d(Acc essLevel)s(Title)d(ClanId)d(ClanCrestId)d(AllyId)d (AllyCrestId)d(IsClanLeader)b(MountType)b(PrivateS toreType)b(DwarvenCraft)d(PkKills)d(PvpKills)b(Cub ics)b(Cubics)b(FindPartyMembers)d(AbnormalEffect)b ()d(ClanPrivileges)d()d()d()d()d()d()d()b(RecomLef t)b()b(RecomHave)b()
#$06: if (ReadD(2) = TargetID) and (NpcTypeID_CurrentMob <> 0) then // Die:d(ChaID)
if (NpcTypeID_List[NpcTypeID_CurrentMob] <> 0) then
begin
SendMsg('Моб №' + inttostr(NpcTypeID_CurrentMob) + ' добавлен в базу');
log.Lines.Add('Моб №' + inttostr(NpcTypeID_CurrentMob) + ' добавлен в базу');
inc(NpcTypeID_List_Count);
NpcTypeID_CurrentMob:= 0;
TargetID:= 0;
end;
#$16: if (ReadD(2) = TargetID) and (NpcTypeID_CurrentMob <> 0) then NpcTypeID_List[NpcTypeID_CurrentMob]:= 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(FlRu nSpd)d(FlWalkSpd)d(FlyRunSpd)d(FlyWalkSpd)f(Proper Multiplier)f(PAtkSpd)f(CollisionRadius)f(Collision Height)d(RHand)d(Unknown)d(LHand)b(Unknown)b(IsRun ning)b(IsInCombat)b(IsALikeDead)b(IsSummoned)s(Nam e)s(Title)
#$1B: begin
InventoryCreate; // Инвентарь
HPBottleObjID:= getinv(HPBottleID, 2,1);
HPBottleCount:= getinv(HPBottleID, 2,3);
end;
#$27: begin
InventoryUpdate;
HPBottleCount:= getinv(HPBottleID, 2,3);
end;
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.


собственно доработка состояла в добавлении нескольких строк, на спойл:

procedure PhisicalAttack; // команда атаки
begin
buf:=#$04; //action
WriteD(TargetID);
WriteD(MyX);
WriteD(MyY);
WriteD(MyZ);
WriteC(0);
buf:=hstr('2F FE 00 00 00 00 00 00 00 00');
SendToServerEx(NickName);
SendToServerEX('HiliH');
end;

На свип соответственно тут

#$06: begin // Die:d(ChaID)
povtor:= TestPovtor(ReadD(2));
if Povtor > 0 then
begin
if MobsID[povtor] = TargetID then
begin
LastKilledMobObjID:=TargetID;
inc (MobsKilled); // подводим статистику
TargetID:= 0;
buf:=hstr('2F 2A 00 00 00 00 00 00 00 00');
SendToServerEX('HiliH');
// споил надо делать тута
end;
DelDBItem(povtor);
end;
end;
Собственно он стал спойлить и свипать убитых мобов, но, сам он не начинает атаковать мобов и перестал поднимать дроп, помогите разобратся в чем трабла. Прошу строго не судить токо начинаю пытаться разобратся с языком

QaK
13.11.2008, 09:58
procedure PhisicalAttack; // команда атаки
begin
buf:=#$04; //action
WriteD(TargetID);
WriteD(MyX);
WriteD(MyY);
WriteD(MyZ);
WriteC(0);
SendToServerEx(NickName);
buf:=hstr('2F FE 00 00 00 00 00 00 00 00');
SendToServerEX('HiliH');
end;

попробуй так

VismuT
13.11.2008, 12:13
СЧпасибо, заработало, сегодня попробую еще сделать версию с манором.

QaK
13.11.2008, 13:09
тема клоуз.