Many many thanks. i have spent many hours looking for the error.
ill use extended var, in a way diffrent to your script, i think it will work.
Then ill post it here.
I just keep the "raw" mob location, an use the variable Distance[i] to convert the int to ext...
I can not test it because im at work -.-
Then ill tell you the results.
надрал кусков из скриптов выложеных на форуме, получилось вот так:
Код:
if (pck[1]=#$21) and Fromserver and (pck[2]=#$01) and (pck[4]=#$01) and (pck[12]=#$58) and (pck[13]=#$02) then
begin
j:=4;
T:=ReadH(j);
j:=j+2;
myoid:=ReadD(j);
// msg('start');
buf:=#$37;
WriteD(0);
WriteD(1);
WriteD(myoid);
WriteD(600);
WriteD(1);
SendToServerEx(ConnectName);
вроде работает.
[quote=NLObP;16514] Надо писать READ()QUOTE]
А как действует функция read?
Да и где-то тут видел код для отключения от клиента, но немогу найти. поиск результатов не дал, да и ключеве слова подобрать сложно, а очистить оперативы очень хочеться
Последний раз редактировалось creaDo, 13.10.2008 в 03:09.
Да и где-то тут видел код для отключения от клиента, но немогу найти. поиск результатов не дал, да и ключеве слова подобрать сложно, а очистить оперативы очень хочеться
Посмотреть можно в моём скрипте рыбалки и еще где-то на форуме точно есть. C отключением клиента, не всё так просто. И Neting надо отлавливать и с движением проблемы. Допустим в той же рыбалке, пока стоит - ловит, а вот ходить не может. Пакеты на движение клиент шлет, а его мы выгружаем, значит сами должны их формировать.
//Автоматизация заточки предметов до необходимого уровня by NLObP//Адаптированая под Gracia by CreaDo//Затачиваем поочереди все предметы с Weapon ID пока не переломаем или не заточим//Работа проверена на L2C4 Protocol 660 LocalServer "L2J FORTRESS"//Необходимо затариться оружием, заточками и валерьянкой//Открываем инвентарь для инициализации скрипта//Социальное действие YES начать//Социальное действие NO остановиться//Enjoy!{Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.}//******************************************************************************const
Name='Fatish';
Scroll=959; // 959 - ItemID Scroll Enchant Weapon (Grade S)
Weapon=9866; // 9866 - ItemID Dinasty dager focus (Grade S80)
MaxEnchLvl=10; //max уровень заточкиmax=100; //max количество предметов в базеvar// WpnObjID: array[1..maxwpn,1..maxwpn] of integer; //Weapon ObjID
WpnBase: array[1..2,1..max] ofinteger; //Weapon ObjID,lvl
ScrlBase: integer; //Scroll ObjID
add: boolean; //прошла заточка?
timer: TTimer;
CurEnchLvl, ColvoWpn, ColvoScrl, CurWpn, CurScrl: integer;
//******************************************************************************procedure Init; //Вызывается при включении скриптаvar
i:integer;
begin//Enchant:=false;
CurEnchLvl:=0;
timer:=TTimer.Create(nil);
timer.OnTimer:=@OnTimerHP;
timer.enabled:=false;
timer.interval:=2500; //время задержки
Say('Для инициализации скрипта, откройте инвентарь');
end;
//******************************************************************************procedure Free; //Вызывается при выключении скриптаbegin
WpnBase:=nil;
ScrlBase:=nil;
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 CreateItemBase; //пакет 1B, Создает базу ObjectID по ItemIDvar
i, ss, sc, ww, j, ObjID, ItemID, lvl, ListCount: integer;
begin
ss:=1; //индекс в массиве скроллов
ww:=1; //индекс в массиве предметов
j:=4; //смещение для ListCount
ListCount:=ReadH(j); //количество итемов не должно превышать max!if ListCount>max then ListCount:=max;
j:=8; //смещение для ObjectID//Пробегаем по Инвентарю и сохраняем ObjectID соответствующие необходимым ItemIDfor i:=1to ListCount dobegin
ObjID:=ReadD(j); //ObjectID
ItemID:=ReadD(j); //ItemID
j:=j+4;
sc:=readD(j);
j:=j+10;
Lvl:=ReadH(j); //Level
say(inttostr(lvl));
case ItemID of
scroll: begin
ss:=sc;
ScrlBase:=ObjID;
// Say('ColvoScrl='+IntToStr(ss));end;
weapon: begin
WpnBase[1,ww]:=ObjID;
WpnBase[2,ww]:=lvl;
ww:=ww+1;
// Say('ColvoWpn='+IntToStr(ww));end;
end;
j:=j+44//Gracia// j:=j+2; //для С4// j:=j+10; //для Интерлюдииend;
ColvoWpn:=ww-1;
ColvoScrl:=ss;
Say('>ColvoWpn='+IntToStr(ColvoWpn)+' ColvoScrl='+IntToStr(ColvoScrl)+' CurEnchLvl='+IntToStr(CurEnchLvl));
end;
//******************************************************************************procedure UpdateItemBase; //пакет 27, Создает базу ObjectID по ItemIDvar
i, ii, j, ss, sc, ww, ObjID, ItemID, Lvl, ListCount, UpdType: integer;
begin
ListCount:=ReadH(2); //количество итемов//Пробегаем по Инвентарю и сохраняем пары ObjectID - Lvl
j:=4; //смещение для действия с предметом 1-добавлен 2-изменен 3-удален// Say('Апдейт базы!');for i:=1to ListCount dobegin
UpdType:=ReadH(j);
j:=j+2;
ObjID:=ReadD(j); //ObjectID
ItemID:=ReadD(j); //ItemID
j:=j+4;
sc:=readD(j);
j:=j+10;
Lvl:=ReadH(j); //Level// Say('Предмет! ObjectID='+IntToStr(ObjID)+' ItemID='+IntToStr(ItemID));case UpdType of1:case ItemID of
weapon: begin
ColvoWpn:=ColvoWpn+1;
//Say('Добавили предмет! ObjectID='+IntToStr(ObjID)+' ItemID='+IntToStr(weapon));for ii:=1tomaxdoif WpnBase[1,ii]=0thenbegin WpnBase[1,ii]:=ObjID; WpnBase[2,ii]:=lvl; end;
end;
scroll: begin ss:=ss+1;
if ScrlBase=0then ScrlBase:=ObjID;
end;
end;
2:case ItemID of
weapon:
for ii:=1tomaxdoif WpnBase[1,ii]=ObjID thenbegin WpnBase[2,ii]:=lvl; say(inttostr(WpnBase[2,ii])); end;
scroll: sc:=ss;
//Say('Внимание! Изменения в скролле!?');end;
//удален3:case ItemID of
weapon: begin
ColvoWpn:=ColvoWpn-1;
for ii:=1tomaxdoif WpnBase[1,ii]=ObjID thenbegin WpnBase[1,ii]:=0; WpnBase[2,ii]:=0; end;
//Say('Удаляем предмет! ObjectID='+IntToStr(ObjID)+' ItemID='+IntToStr(weapon));end;
scroll: begin
ColvoScrl:=ColvoScrl-1;
for ii:=1tomaxdoif ScrlBase=ObjID then ScrlBase:=0;
//Say('Удаляем скролл! ObjectID='+IntToStr(ObjID)+' ItemID='+IntToStr(scroll));end;
end;
end;
j:=j+44;
// j:=j+2; //для С4// j:=j+10; //для Интерлюдииend;
// Say('>>ColvoWpn='+IntToStr(ColvoWpn)+' ColvoScrl='+IntToStr(ColvoScrl)+' CurEnchLvl='+IntToStr(CurEnchLvl));end;
//******************************************************************************function GetNextWeapon: integer; //Выдает ObjID предмета, если не найден в базе, выдает -1,//достигли макс уровня заточки -2, подбираем мин текущий уровень заточки -3var
i: integer;
begin
Result:=-1;
if CurEnchLvl>=MaxEnchLvl thenbegin
Result:=-2;
exit;
end;
for i:=1tomaxdobegin//находим первый подходящий предметif(WpnBase[1,i]<>0)and(WpnBase[2,i]<=CurEnchLvl)thenbegin
Result:=WpnBase[1,i];
exit;
end;
end;
CurEnchLvl:=CurEnchLvl+1;
Result:=-3;
end;
//******************************************************************************function GetNextScroll: integer; //Выдает ObjID скролла, если не найден в базе, выдает -1var
i: integer;
begin
Result:=-1;
for i:=1tomaxdobegin//находим первый подходящий предметif(ScrlBase<>0)thenbegin
Result:=ScrlBase;
exit;
end;
end;
end;
//******************************************************************************procedure UseItem(ObjectID: integer);
begin
buf:=#$19;
WriteD(ObjectID);
WriteD(0);
SendToServerEx(Name);
end;
//******************************************************************************procedure RequesEnchantItem(ObjectID: integer);
begin
buf:=#$5F;
WriteD(ObjectID);
SendToServerEx(Name);
end;
//******************************************************************************procedure OnTimerHP(Sender: TObject);
var
wpn, scrl:integer;
beginif ColvoScrl=0thenbegin
Say('Кончились скроллы! Прервано!');
timer.enabled:=false;
exit;
end;
if ColvoWpn=1thenbegin
Say('Остался последний предмет! Прервано!');
timer.enabled:=false;
exit;
end;
Scrl:=GetNextScroll;
if scrl=-1thenbegin
Say('Нет такой заточки! Прервано!');
timer.enabled:=false;
exit;
end;
Wpn:=GetNextWeapon;
case wpn of
-1: begin
Say('Нет такого предмета! Прервано!');
timer.enabled:=false;
exit;
end;
-2: begin
Say('Достигли максимальный уровень заточки! Прервано!');
timer.enabled:=false;
exit;
end;
-3: begin//Say('Подбираем текущий уровень заточки!');
timer.enabled:=true;
exit;
end;
end;
//************************************************
UseItem(Scrl);
RequesEnchantItem(Wpn);
//************************************************
Say('Заточили предмет! Weapon='+IntToStr(Wpn));
end;
//******************************************************************************// вызывается при приходе каждого пакета, если скрипт включен//******************************************************************************begin//****************************************************************************//не обрабатываем пустые пакетыif pck=''thenexit;
//****************************************************************************//социальное действие yes для начало точкиif FromClient and(ConnectName=Name)and(pck=HStr('34 06 00 00 00'))thenbegin
CurEnchLvl:=0;
Say('Команда Старт!!!');
timer.enabled:=true;
end;
//****************************************************************************//социальное действие no для начало точкиif FromClient and(ConnectName=Name)and(pck=HStr('34 05 00 00 00'))thenbegin
Say('Команда Стоп!!!');
timer.enabled:=false;
end;
//****************************************************************************//ItemListif FromServer and(ConnectName=Name)and(pck[1]=#$11)then CreateItemBase; //создание базы предметов// if (ColvoWpn=0) or (ColvoScrl=0) then exit; //если нет базы итемов, скрипт дальше не пустит//****************************************************************************//если удалились предметы, стираем в базе предметов пары ObjectID - ItemIDif FromServer and(ConnectName=Name)and(pck[1]=#$21)then UpdateItemBase; //Обновление базы, если принят пакет на удаление предметаend.
Скрипт начал писать для того, чтобы поднатаскать себя в понимании l2phx. Может кому и пригодится....
Бот не умеет мочить моба и подбирать с него дроп, НО он автоматом находит в инвентаре бутылки с хилкой и хиляется ими, а также юзает соски под грейд удочки, если находит.
Для показа меню нада написать 'f' в пати чат, без кавычек.
delphi Код:
//Автоматизация ловли рыбы by VerWolF//Скрипт ловит рыбу и хиляется когда вылавливает монстра.//Работа проверена на L2C6 Protocol 750 la2.theabyss.ru x3//Необходимо затариться удочкой и крючками, выучить соответствующие скиллы,//потеплей одется :D желательно в хэви, ловить советую какким-н толстозадым гномом.//Бот сам находит соски в инвентаре, которые подходят под грейд удочки и автоматически их использует.//Бот сам находит Банки для хила в инвентаре и автоматически их использует, когда его атакует моб.//Бот распознает 3 вида банок для хила: обычные, GHP и QHP и юзает их в соответствии с ситуацией.//Рыба будет ловиться как с сосками, так и без них, без,//соответственно, дольше...//Если вас забанили, то автор ответственности не несет!//Используйте скрипт на ваш страх и риск!//Для работы нужно задать константе NAME чара, которым будете рыбачить.const
fish='2F 20 05 00 00 00 00 00 00 00';
pump='2F 21 05 00 00 00 00 00 00 00';
reel='2F 22 05 00 00 00 00 00 00 00';
NAME='Popka';//Имя чара, который рыбачит.
HPBottleID=1061; //ID бутылок с хилкой
GHPBottleID=1539;
QHPBottleID=1540;
{необходимо уточнить ItemID для своего сервера!!!
1060=Lesser Healing Potion
1061=Healing Potion
1539=Greater Healing Potion
1540=Quick Healing Potion}
HealInterval=15000; //Интервал, через который будет питься бутылко. 15сек. На QHP не распространяется.
FishingIterval=100; //Задержка между закидованием удочки.
HTML='<html><body><center>'+
'<img src="L2UI_CH3.herotower_deco width=256 height=32>'+
'<img src="L2UI.SquareWhite" width=280 height=1>'+
'<img src="L2UI.SquareBlank" width=260 height=4><br>'+
'<font color="04fbfb">.::FiShInG v0.3 by VerWolF::.</font><br>'+
'<font color="04fbfb">.::[Написано на основе кода QaK и NLObP]::.</font><br>'+
'<button value="Start Fishing!" action="bypass -h StartFishing" width=100 height=15 back="sek.cbui94" fore="sek.cbui92">'+
'<button value="Stop Fishing" action="bypass -h StopFishing" width=100 height=15 back="sek.cbui94" fore="sek.cbui92">'+
'<img src="L2UI.SquareWhite" width=260 height=1>'+
'<img src="L2UI.SquareBlank" width=260 height=4><br>'+
'</center></body></html>';
//====================================================================================================================== var
FishCycleTimer : TTimer;
HealReuseTimer : TTimer;
Status : Boolean;
CharObjID : Integer;
SocialID : Integer;
bypass : String;
MaxHP : Integer;
CurrentHP : Integer;
FSoulshotID : Integer;
FSoulshotObjID : Integer;
ItemCount : Integer; //количество занятых слотов/количество вещей
Inventory: array[1..250,1..10]of integer; //массив инвентаря//инвентарь//1 - ItemType1//2 - ObjectID//3 - ItemID//4 - ItemCount//5 - ItemType2//6 - CustType1//7 - IsEquipped//8 - BodyPart//9 - EnchantLevel//10 - CustType2procedure Init; //Вызывается при включении скриптаbegin
MaxHP:=0;
CurrentHP:=0;
FSoulshotID:=0;
FSoulshotObjID:=0;
ItemCount:=0;
CharObjID:=0;
Status:=false;
FishCycleTimer:=TTimer.Create(nil);
FishCycleTimer.OnTimer:=@OnFishCycleTimer;
FishCycleTimer.enabled:=false;
FishCycleTimer.interval:=FishingIterval;
HealReuseTimer:=TTimer.Create(nil);
HealReuseTimer.OnTimer:=@OnHealReuseTimer;
HealReuseTimer.enabled:=false;
HealReuseTimer.interval:=HealInterval;
Say('Для вывода меню набрать в пати-чате букву f');
end;
procedure Free; //Вызывается при выключении скриптаbegin
FishCycleTimer.Free;
HealReuseTimer.Free;
end;
//процедура для отображения диалога управления ботом.procedure ShowHTML( _html : string);
begin
buf:=#$00f;
WriteD(5);
WriteS(_HTML);
SendToClientEX(NAME);
end;
//посылаем сообщение, которое видно только в окне бота//можно использовать для отладкиprocedure Say(msg:string);
begin
buf:=hstr('4A 00 00 00 00');
WriteD(2);
WriteS(NAME);
WriteS(msg);
SendToClientEx(NAME);
end;
//процедура считывания параметров одного предметаprocedure ItemAction(var Counter:integer; CurrentSlot:integer);
//Counter - Позиция считываемая из пакета, модифицируется функциями ReadC,ReadD//CurrentSlot - Индекс в массиве Inventory (от 1 до 250)var
c1:integer;
beginfor c1:=1to10dobegin//Если значение однобайтноеif(c1=1)or(c1=5)or(c1=6)or(c1=7)or(c1=9)thenbegin
Inventory[CurrentSlot,c1]:=ReadH(Counter);
end;
//Если значение четырехбайтноеif(c1=2)or(c1=3)or(c1=4)or(c1=8)thenbegin
Inventory[CurrentSlot,c1]:=ReadD(Counter);
end;
//Если значение последнееif c1=10thenbegin
Inventory[CurrentSlot,c1]:=ReadH(Counter);
Counter:=Counter+8;
end;
end;
end;
//Пакет от сервера 1В - создаем или модифицируем весь инвентарьprocedure CreateItemBase;
var
i,j: integer;
begin
ItemCount:=ReadH(4);//Считываем количество вещей в инвентаре
j:=6;
for i:=1to ItemCount do ItemAction(j,i);
end;
//Пакет от сервера 27 - действия (доавить/изменить/удалить) над одним/несколькими предметамиprocedure UpdateItemBase;
var
i,ij,ijk:integer; //простые счетчики для перебора значений
j:integer; //Текущая позиция, откуда считываем значения из пакета
count:integer; //Количество изменяемых предметов
Action: integer; //Действие над предметом
k:boolean; //Нашли ли мы удаляемый предмет?begin
k:=false;
count:=ReadH(2);//Считываем количество изменяемых предметов
j:=4;
for i:=1to count dobegin
Action:=ReadH(j);//Считываем действиеcase Action of1:begin//ADDInc(ItemCount);//Увеличиваем количество занятых слотов
ItemAction(j,ItemCount); //Добавляем предметend;
2:begin//UPDATEfor ij:=1to ItemCount do//Ищем изменяемый предмет по ObjectIDIf Inventory[ij,2]=ReadD((j-1)*30+8)thenbegin//Если нашли
ItemAction(j,ij); //Изменяем данные о немexit; //Больше проверять не надо - выходим из циклаend;
end;
3:begin//DELETEfor ij:=1to ItemCount-1dobegin//Ищем удаляемый предметIf Inventory[ijk,2]=ReadD((j-1)*30+8)then k:=true; //Если нашли,фиксируем этоIf k then//если найден удаляемы объектfor ijk:=1to10do//то сдвигаем элементы массива-инвентаря
Inventory[ij,ijk]:=Inventory[ij+1,ijk];
end;
Dec(ItemCount);//Уменьшаем количество занятых слотовend;
end;
end;
end;
//Получить ObjectID предмета, зная его ItemIDfunction GetInfo(ItemID:integer):integer;
var
c1:integer;
begin Result:=-1;
for c1:=1to ItemCount doif(ItemID=Inventory[c1,3])thenbegin
Result:=Inventory[c1,2];
exit;//Если нашли - выходим из циклаend;
end;
//Проверяем, одет ли предмет по ItemIDfunction IsEquipped(ItemID:integer):integer;
var
c1:integer;
begin Result:=-1;
for c1:=1to ItemCount doif(ItemID=Inventory[c1,3])and(Inventory[c1,7]=1)thenbegin
Result:=1;
exit;
end;
end;
//Использовать предмет с заданным ItemIDprocedure UseItem(ItemID:integer);
var
c1:integer;
beginfor c1:=1to ItemCount doif(ItemID=Inventory[c1,3])thenbegin
buf:=#$14;
WriteD(Inventory[c1,2]);
WriteD(0);
SendToServerEX(NAME);
exit; //Чтоб не использовать несколько предметов с одинаковым ItemID (например заточки)end;
end;
//Используем рыбное соско.....procedure UseSoulshot(ObjID:integer);
begin
buf:=#$14;
WriteD(ObjID);
WriteD(0);
SendToServerEX(NAME);
end;
//Процедура для отсылки пакета о начале или окончании рыбалки.//Также определяет по одетой на чара удочке ID и ObjectID сосок, //которые нада юзать и юзает их в дальнейшем автоматически.{ Проверьте эти значения для своего сервера!!!
6529=Baby Duck Rod (NG) 6535=Fishing Shot: non-grade
6530=Albatross Rod (D) 6536=Fishing Shot: D-grade
6531=Pelican Rod (C) 6537=Fishing Shot: C-grade
6532=KingFisher Rod (B) 6538=Fishing Shot: B-grade
6533=Cygnus Pole (A) 6539=Fishing Shot: A-grade
6534=Triton Pole (S) 6540=Fishing Shot: S-grade
}procedure Fishing;
var
i : Integer;
beginif(FSoulshotID=0)and(FSoulshotObjID=0)thenbeginfor i:=6529to6534dobeginif IsEquipped(i)=1thenbegin
FSoulshotID:=(i+6);
FSoulshotObjID:=GetInfo(FSoulshotID);
if(FSoulshotObjID<>-1)thenbegin
Say('Соски будут использоваться автоматически.');
endelsebegin
FSoulshotID:=0;
FSoulshotObjID:=0;
end;
end;
end;
end;
buf:=HStr(fish);
SendToServerEX(NAME);
end;
//юзаем Pumping вместе с соскойprocedure Pumping;
beginif(FSoulshotObjID<>-1)then UseSoulshot(FSoulshotObjID);
buf:=HStr(pump);
SendToServerEX(NAME);
end;
//юзаем Reeling вместе с соскойprocedure Reeling;
beginif(FSoulshotObjID<>-1)then UseSoulshot(FSoulshotObjID);
buf:=HStr(reel);
SendToServerEX(NAME);
end;
//пьем банко как только пройдет 15 секундprocedure OnHealReuseTimer(Sender: TObject);
beginif(CurrentHP < MaxHP)and(CurrentHP > (MaxHP/2))thenbegin
UseItem(HPBottleID);
HealReuseTimer.enabled:=false;
exit;
end;
if(CurrentHP < (MaxHP/2))and(CurrentHP > ((MaxHP/100)*10))thenbeginif(GetInfo(GHPBottleID)<>-1)thenbegin
UseItem(GHPBottleID);
HealReuseTimer.enabled:=false;
exit;
end;
if(GetInfo(HPBottleID)<>-1)thenbegin
UseItem(HPBottleID);
HealReuseTimer.enabled:=false;
exit;
end;
end;
if(CurrentHP < ((MaxHP/100)*10))thenbeginif(GetInfo(QHPBottleID)<>-1)then UseItem(QHPBottleID);
if(GetInfo(GHPBottleID)<>-1)thenbegin
UseItem(GHPBottleID);
HealReuseTimer.enabled:=false;
exit;
end;
if(GetInfo(HPBottleID)<>-1)thenbegin
UseItem(HPBottleID);
HealReuseTimer.enabled:=false;
exit;
end;
end;
end;
//начинаем рыбачить как только щелкнет таймерprocedure OnFishCycleTimer(Sender: TObject);
begin
Fishing;
FishCycleTimer.enabled:=false;
end;
//******************************************************************************// Тело скрипта.//******************************************************************************begin//не обрабатываем пустые пакетыif pck=''thenexit;
//Если скрипт ничего не знает о содержимом инвентаря, то вынуждаем его узнать о нем.if ItemCount=0thenbegin
buf:=#$0F;
SendToServerEX(NAME);
end;
//****************************************************************************//РАЗБОР ПАКЕТОВ ОТ СЕРВЕРА:if FromServer thenbegin//создаем или обновляем описание предметов в инветаре.case pck[1] of
#$1B:begin
CreateItemBase;
end;
#$27:begin
UpdateItemBase;
end;
end;
//Получаем пакет UserInfo, вынимаем оттуда свой ObjectIDif(pck[1]=#$04)and(ReadS(22)=ConnectName)and(CharObjID=0)thenbegin
CharObjID:=ReadD(18);
end;
//Хиляемся..... СНачала обычными банками, потом, когда хп меньше половины - GHP, а когда хп - 10% - QHPif(pck[1]=#$0E)and(pck[6]=#$04)thenbegin
CurrentHP:=ReadD(14);
MaxHP:=ReadD(22);
if(CurrentHP < MaxHP)and(CurrentHP > (MaxHP/2))and(HealReuseTimer.enabled=false)thenbegin
UseItem(HPBottleID);
HealReuseTimer.enabled:=true;
end;
if(CurrentHP < (MaxHP/2))and(CurrentHP > ((MaxHP/100)*10))and(HealReuseTimer.enabled=false)thenbeginif(GetInfo(GHPBottleID)<>-1)thenbegin
UseItem(GHPBottleID);
HealReuseTimer.enabled:=true;
exit;
end;
if(GetInfo(HPBottleID)<>-1)thenbegin
UseItem(HPBottleID);
HealReuseTimer.enabled:=true;
end;
end;
if(CurrentHP < ((MaxHP/100)*10))and(HealReuseTimer.enabled=false)thenbeginif(GetInfo(QHPBottleID)<>-1)then UseItem(QHPBottleID);
if(GetInfo(GHPBottleID)<>-1)thenbegin
UseItem(GHPBottleID);
HealReuseTimer.enabled:=true;
exit;
end;
if(GetInfo(HPBottleID)<>-1)thenbegin
UseItem(HPBottleID);
HealReuseTimer.enabled:=true;
end;
end;
end;
//Рыбачим.....if Status=truethenbeginif(ReadH(1)=5886)and(pck[16]=#$00)and(ReadD(4)=CharObjID)then Pumping;
if(ReadH(1)=5886)and(pck[16]=#$01)and(ReadD(4)=CharObjID)then Reeling;
if(ReadH(1)=5374)and(ReadD(4)=CharObjID)then FishCycleTimer.enabled:=true;
endelseexit;
end;
//РАЗБОР ПАКЕТОВ ОТ КЛИЕНТА:if FromClient thenbeginif(pck[1]=#$21)thenbegin
bypass:=ReadS(2);
case bypass of'StartFishing':beginif(Status=false)thenbegin
Status:=true;
Fishing;
end;
end;
'StopFishing':beginif Status=truethen Fishing;
Status:=false;
FishCycleTimer.enabled:=false;
end;
end;
end;
if(pck[1]=#$38)and(ReadS(2)='f')and(ReadD(6)=3)then ShowHTML(HTML);
end;
end.
Долго мучисля, но все таки научил его спойлить. Выкладываю правленый скрипт бота от Alexus.
Огромное спасибо QaK за оказаную помощь и проявленное терпение=)
delphi Код:
{#############################################################################
Бот - локомотив от Alexus edit by VismuT (Научился спойлить)
версия : 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, SpoilMode : boolean;
//-------------------------------------- БД --------------------------------------------------
MobsID : array [1..maximumItems] ofinteger;
MobsDist : array [1..maximumItems] ofinteger; // Расстояние от центра кача
MobsXYZ : array [1..maximumItems, 1..3] ofinteger; // Координаты
MobsAgression : array [1..maximumItems] ofboolean; // Моб атакует меня или стоит в сторонке...
MobsLastIndex: integer; // индекс последнего элемента базы
NpcTypeID_List : array [1..NpcTypeID_List_Razmer] ofinteger; // Список мобов (коды мобов)
NpcTypeID_List_Count : integer; // Текущий размер списка
NpcTypeID_CurrentMob : integer;
Items_ObjectID : array [1..maximumItems] ofinteger; // БД дропа с мобов
Items_ItemID : array [1..maximumItems] ofinteger;
Items_XYZ : array [1..maximumItems, 1..3] ofinteger;
ItemsLastIndex: integer;
Inventory: array[0..InvRazmer, 0..9] ofinteger; // инвентарь (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;
SpoilMode:= true;
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:=1to NpcTypeID_List_Razmer do NpcTypeID_List[i]:= 0;
NpcTypeID_List_Count:= 0;
NpcTypeID_CurrentMob:= 0;
for i:=1to 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:=0to InvRazmer dofor n:=0to9do Inventory[i, n]:= 0;
end;
function Wait(var tick: integer;Timewait: Integer): Boolean; // сквозная проверка без остановки скрипта (c)dmitry501, modifed by Sh00rGovar
t: integer;
begin
result:=false;
t:=Round(Time*86400);
if t>(tick+Timewait)thenbeginif tick>0then result:=true;
tick:=t;
end;
end;
//############################## Модуль работы с Инвентарем ###########################procedure InventoryCreate;
var
i,k, offset : integer;
beginif interlude then offset:= 8else offset:=0;
for i:=0to InvRazmer doif(i<ReadH(4))thenbegin
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); // CustType2endelsefor k:=0to9do Inventory[i,k]:=0; // забиваем нулямиend;
procedure InventoryUpdate;
var
i,j,k, offset: integer;
beginif interlude then offset:= 8else offset:=0;
for j:=0to(ReadH(2)-1)dobegincase 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:=0to InvRazmer doif(Inventory[i,0]=k)thenbeginfor k:=0to9do Inventory[i,k]:=0;
exit;
end;
end;
end;
for i:=0to InvRazmer doif(Inventory[i,1]=k)thenbegin
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); // CustType2break;
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;
beginfor i:=0to InvRazmer doif(Inventory[i,up]=obj)thenbegin
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); //Использовать предмет с заданным ItemIDbegin
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 = 0then result:= 0else result:= Round(sqrt(summa)); // обход возможной ошибки, если моб стоит прямо в центре качаifabs(dz) > vertical then result := result + 5000; // добавляем коррекцию по вертикалиend;
procedure AddDroppedItem (ObjID, ItemID, X, Y, Z: integer); // Процедура добавляет дропнутую вещь в БДbegininc(ItemsLastIndex);
if ItemsLastIndex > maximumItems thenexit;
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)thenexit; // если моб слишко далеко то ничего не делаем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;
beginif(MOBSXYZ[i, OX] = x)and(MOBSXYZ[i, OY] = y)and(MobsAgression[i] = agression)thenexit; // проверяем, а надо ли чего нить менят
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 thenfor n:= i+1to 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 thenfor n:= i+1to ItemsLastIndex dobegin
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:=1to ItemsLastIndex doif Items_ObjectID[i] = id thenbegin
result:=i; // И возвращаем его индекс по БДbreak;
end;
end;
function TestPovtor (id: integer) : integer; // функция проверяет наличие заданного моба в БДvar
i: integer;
begin
result:=0;
for i:=1to MobsLastIndex doif MobsID[i] = id then// Ищем нужный ID в нашей БДbegin
result:=i; // И возвращаем его индекс по БДbreak;
end;
end;
function InMobsList (NpcTypeID: integer) : boolean; // функция проверяет наличие заданного моба в списке на атакуvar
i: integer;
begin
result:= false;
for i:=1to NpcTypeID_List_Count doif 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; // функция проверки правильности задания всех параметров для начала качаbeginif(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)thenbegin
SendMsg('Все начальные параметры заданы и проверены!');
log.Lines.Add('Все начальные параметры заданы и проверены!');
result:= true;
endelsebegin
SendMsg('Ошибка задания начальных параметров!');
log.Lines.Add('Ошибка задания начальных параметров!');
result:= false;
end;
end;
procedure UserCommandsInitMode; // комманды пользователя для режима настройки ботаbegin// если комманда обработана удачно, то в чат сообщение не попадет, а будет выдано системное сообщение прямо в клиентcase(ReadS(2))of'pos' : if MyX <> 0then// центр кача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' : // задаем мобовbeginif(NpcTypeID_List_Count+1) <> strtoint(ReadS(2))thenbegin
SendMsg('Добавлять мобов можно тока по очереди 1, 2, 3...');
pck:='';
exit;
end;
NpcTypeID_CurrentMob:= strtoint(ReadS(2));
SendMsg('Добавляем моба № '+ ReadS(2));
pck:='';
end;
'start': begin// собственно запуск ботаif ValidateData and InitMode thenbegin
SendMsg('ЗАПУСКАЕМ ИСУСТВЕННЫЙ ИНТЕЛЛЕКТ!');
log.Lines.Add('ЗАПУСКАЕМ ИСУСТВЕННЫЙ ИНТЕЛЛЕКТ!');
TargetID:=0;
InitMode:= false;
TimerCombat.enabled:=true; // запускаем таймерendelsebegin
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.enabledthenbegin
SendMsg('Искуственный интелект запущен!');
log.Lines.Add('Искуственный интелект запущен!');
endelsebegin
SendMsg('Искуственный интелект приостановлен.');
log.Lines.Add('Искуственный интелект приостановлен.');
endend;
'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:=1to MobsLastIndex doif(MobsID[i] <> 0)and(MobsDist[i] < dist)thenbegin// фишка в том, что в базе хранятся расстояния не до меня, а до центра кача
dist:= MobsDist[i]; // но в катах то расстояния небольшие
result:= i; // если нашли хоть одного моба или несколько возращаем его индекс ближайшего к центру качаend;
if dist = 10000then result:= 0; // иначе возвращаем 0 (ничего не найдено)end;
function AgroTest : integer; // функция проверяет, атакует ли меня кто-нибудь или нетvar
i: integer;
begin
result:=0;
for i:=1to MobsLastIndex doif 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);
if SpoilMode=truethenbegin
buf:=hstr('2F FE 00 00 00 00 00 00 00 00');
SendToServerEX(NickName);
end;
end;
procedure InitPickUpMode(mode: boolean);
beginif mode thenbegin
PickUpMode:= true;
TimerCombat.enabled:= false;
TimerPickUp.enabled:= true;
endelsebegin
PickUpMode:= false;
TimerCombat.enabled:= true;
TimerPickUp.enabled:= false;
end;
end;
procedure OnTimerPickUp (Sender: TObject); // таймер поднятия дропаvar
povtor: integer;
beginif(AgroTest > 0)and(TargetID = 0)thenbegin
InitPickUpMode(false);
exit;
end;
if(ItemsLastIndex > 0)and(TargetID = 0)thenbegin
TargetID:= Items_ObjectID[ItemsLastIndex];
AttackCycle:= 0;
PhisicalAttack;
exit;
end;
if(ItemsLastIndex > 0)and(TargetID > 0)thenbegininc(AttackCycle);
if((AttackCycle mod5) = 0)then PhisicalAttack;
if AttackCycle > Calculated_PickUpTime thenbegin
Povtor:= CheckItems(TargetID);
if Povtor <> 0then DelDroppedItem(Povtor);
TargetID:= 0;
end;
exit;
end;
if(ItemsLastIndex = 0)then InitPickUpMode(false);
end;
procedure OnTimerCombat (Sender: TObject); // боевой таймер, вся логика поведения бота находится именно здесь!!!var
Agro, MinDistID: integer;
beginif MobsLastIndex = 0then// если нет мобов в базе, тоbeginif ItemsLastIndex > 0then InitPickUpMode(true); // надо дроп подбиратьexit; // выходим от сюдаend;
if TargetID > 0then// если в прицеле есть моб, тоbegin// валим вражинуif((AttackCycle mod5) = 0)then PhisicalAttack;
inc(AttackCycle);
if AttackCycle > Calculated_AttackTime then// если валим моба больше минуты, значит это баг...begin
Povtor:= TestPovtor(TargetID);
if Povtor <> 0then DelDBItem(Povtor);
TargetID:= 0;
end;
exit;
end;
Agro:= AgroTest; // если есть мобы в базе и нет текущей цели, то
MinDistID:= GetMinDistID; // запускаем алгоритм выбора целиif Agro > 0then// если нас кто-то атакует, то его и выбираемbegin
TargetID:= MobsID[Agro];
PhisicalAttack; // берем вражину в таргет
AttackCycle:= 0;
exit;
end;
if ItemsLastIndex > 0then// если чего-то валяется на земле, тоbegin
InitPickUpMode(true); // надо дроп подбиратьexit;
end;
if MobsDist[MinDistID] <= Radius then// иначе ищем ближайшего #################################################begin
TargetID:= MobsID[MinDistID];
PhisicalAttack; // берем вражину в таргет
AttackCycle:= 0;
exit;
endend;
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:=1to MobsLastIndex do// выводим БД мобовbeginif TargetID = MobsID[i] then MobsDBscreen.lines.add('-> '+inttostr(i)+' МобID: '+inttostr(MobsID[i])+' дистанция '+inttostr(MobsDist[i]))elseif 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:=1to 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;
beginif InitMode then MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
i:=22;
ReadS(i);
if interlude then i:=i+48else 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;
beginfor i:=0to ReadD(6)-1docase 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 > 0then HPlevelProcent:= Round((MyMaxHP/100)*HPMedium);
end;
procedure DrinkBottle; // пьем бутылки и следим за их количествомbeginif HPBottleCount > 0thenbegin
UseItemObjID(HPBottleObjID);
dec(HPBottleCount);
end;
end;
beginif pck = ''thenexit;
if(Connectname=nickname)and FromServer and(pck=HStr('64 64 02 00 00 00 00 00 00'))thenbegin
SpoilMode:=false;
end;
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 > 0thenbegin
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: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()begin
UserInfo;
if MyHP = 0then// Проверка не убили ли нас...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 thenbegin
Povtor:= TestPovtor(ReadD(2));// 48= MagicSkillUseif Povtor = 0then 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 > 0thenbeginif MobsID[povtor] = TargetID thenbegin
LastKilledMobObjID:=TargetID;
inc(MobsKilled); // подводим статистику
SpoilMode:=true;
TargetID:= 0;
buf:=hstr('2F 2A 00 00 00 00 00 00 00 00');
SendToServerEX(NickName);
// споил надо делать тута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)thenif Wait(time1,DrinkDelay)then DrinkBottle; // пьем бутылкиif MyHP > HPlevelProcent then time1:=1;
if MyHP = 0then// Проверка не убили ли нас...begin
SendMsg('Нас убили...');
log.Lines.Add('Нас убили...');
StopGame;
end;
end;
#$12: begin// DeleteObject:h(ObjectID)if LastKilledMobObjID = ReadD(2)then LastKilledMobObjID:= 0elsebegin
Povtor:= CheckItems(ReadD(2));
if Povtor <> 0then 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(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)thenbegin
Povtor:= TestPovtor(ReadD(2));
if Povtor = 0then 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(NpcTypeID_CurrentMob <> 0)then// Die:d(ChaID)if(NpcTypeID_List[NpcTypeID_CurrentMob] <> 0)thenbegin
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(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)
#$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.
Долго мучисля, но все таки научил его спойлить. Выкладываю правленый скрипт бота от Alexus.
Огромное спасибо QaK за оказаную помощь и проявленное терпение=)
Извини VismuT, но твой вариант спойла палевом попахивает. Процедура PhisicalAttack при атаке моба вызывается раз в 1 сек. А после твоих модификаций получается, что сразу за пакетом 04=Action, посылается пакет 2F=RequestMagicSkillUse, и так раз в секунду, пока моба не добьешь. Не думаю что это хорошо...