PDA

Просмотр полной версии : Исполнение скриптов, написаных к L2Walker, из клиента игры


NLObP
15.01.2009, 01:36
Довольно много готовых скриптов для валкера. Может стоит воспользоваться? Тем более, что для WP PPC есть подобное.
По крайней мере можно будет пользоваться в скриптах для пакетхака.

Руководство пользователя:
Открываем скрипт в Блокноте и сохраняем его в ANSI кодировке в папку scripts, которая расположена в папке с пакетхаком.
В ниже приведённом скрипте изменяем в таких строчках, указанные там значения на нужные нам:

Name='NLObP'; //имя персонажа в игре
PathWalkerScript='.\scripts\'; //путь к скрипту
NameWalkerScript='script.sec'; //имя скрипта


>>>

что он может:
1.исполнение скриптов, написаных к L2Walker, из клиента игры с помощью L2PacketHack

version 0.11 от 03.06.2009г.
[+] Понимает команды:
LoadItem(ITEMNAME[ID=#],#)
SaveItem(ITEMNAME[ID=#],#)
[+] Ведём базу хранилища
Подправил GetBypass, теперь можно писать в команде DLGSEL(), только начало строки.
Подправил команду DLGSEL() для того, чтобы она ждала пока чар не подбежит на достаточное расстояние к НПЦ

version 0.10 от 30.04.2009г.
[+] Команды управления из чата START|RUN, STOP, PAUSE, RESUME, загрузка скрипта SCRIPT|LOAD=TEST
[+] Добавил управление ботом - Алексус, который пришлось модифицировать для поодержки данного скрипта
[+] Добавил POSOUTRANGE, POSINRANGE
[+] CharStatus([CHP|CMP|HP|MP|WEIGHT|LV|SP|RACE|STAND],[>=|>|==|!=|<|<=],число)
[+] Добавил UserInfo, StatusUpdate
[+] Добавил SET(MON,ATTACK|NOATTACK|ATTACKONE,Name[ID=n];Name1[ID=n];|*), SET(MON,NOATTACK,*)
[+] Добавил SET(RangeType,DefPos,x,y,z,radii), SET(RangeType,StartPos,radii)
мелкие правки кода
вложенные условия
поменял логику применения RequestEnchantItem

version 0.9 от 02.02.2009г.
Поправил ITEMCOUNT

version 0.8 от 02.02.2009г.
[+] Понимает команды:
CrystallizeItem(Name1[Id=XXXX],Count;Name2[Id=XXXX],Count)

version 0.7 от 20.01.2009г.
[+] Понимает команды:
MSG(сообщение),
SELLITEM(Name1[Id=XXXX],Count) или SELLITEM(Name1[Id=XXXX],Count;Name2[Id=XXXX],Count),
DLGSEL(теперь и кнопки жмёт)

version 0.6 от 19.01.2009г.
[+] Понимает команды:
BUYITEM(Name1[Id=XXXX],Count) или BUYITEM(Name1[Id=XXXX],Count;Name2[Id=XXXX],Count)

version 0.5 от 18.01.2009г.
[+] Понимает команды:
PAUSE(время в мс),
ITEMCOUNT(Name[ID=XXXX],==|=>|<=|!=|<>,Count)

version 0.4 от 18.01.2009г.
[+] Понимает команды:
MOVETO(x,y,z),
USEITEM(Name[Id=XXX]),
CALL(метка),
RETURN

version 0.3 от 17.01.2009г.
[+] Понимает команды:
NPCDLG(Name[Id=XXX]),
NPCSEL(Name[Id=XXX])

version 0.2 от 16.01.2009г.
[+] Понимает команды:
DELAY(время в мс),
JMP(метка),
LABEL(имя метки),
EXIT,
DLGSEL(только текст, кнопки не жмёт)
[+] Ведём базу инвентаря
[+] Ведём базу NPCs
<<<

Подправленный бот Локомотив здесь (http://coderx.ru/showpost.php?p=28876&postcount=23).

marslem
15.01.2009, 01:46
Жутко важная тема и нужная

Grinch
15.01.2009, 11:11
NLObP, на пакетхаке скрипт понятней имхо.

boyan
15.01.2009, 18:58
NLObP, на пакетхаке скрипт понятней имхо.
некоторые вещи языком скриптов волкера сделать намного проще..

marslem
15.01.2009, 23:41
и некоторые вещи уже есть для валкера а для пнх еще не написаны

ratvier
16.01.2009, 10:29
Будет здорово, если будет совместимость со скриптами волкера хотябы на 50% :)

Murdoc
16.01.2009, 13:20
осталось добавить мувто и команды циклов и переходов. и по большому счету больше ничего не нужно :)

Fer123
16.01.2009, 17:52
Самое главное сделать базу OID нпц, итемов, игроков итд..

Govneco
17.01.2009, 13:22
давненько ждали все наверное)

NLObP
20.01.2009, 00:42
А эмулятор работает тока на Gracia или можно им C4 пользоваться?

ID пакетов поменять и сами внутренности пакетов, если вдруг отличаются, то будет работать.

NLObP
20.01.2009, 21:55
Я тока непонял тема развиваеться а где ссылка на эмулятор ?

Эмулятор (в первом сообщении) - это скрипт для пакетхака исполняющий скрипт для валкера.

Добавлено через 5 минут
Walker Script Runner by NLObP for Gracia l2.ru
version 0.7 от 20.01.2009г.
[+] Понимает команды: MSG, DLGSEL(теперь и кнопки жмет), SELLITEM, ENCHANTITEM*

*нет в валкере

ratvier
20.01.2009, 22:45
SELLITEM есть в валкере

NLObP
20.01.2009, 23:31
SELLITEM есть в валкере

Дайте ссылку на нормальный список команд валкера (можно английский), все что я видел, ущербные и sellitem там не было, а gohome начать скрипт заново.

ratvier
21.01.2009, 09:47
Вот это более-менеее похоже на правду:
_http://www.elitepvpers.de/forum/lin2-exploits-hacks-bots-tools-macros/48674-l2walker-script-commands.html

Fer123
21.01.2009, 12:55
_http://l2day.info/forum/showthread.php?t=152 тоже самое только на русском

NLObP
02.02.2009, 02:00
version 0.8 от 02.02.2009г.
[+] Понимает команды:
CrystallizeItem(Name1[Id=XXXX],Count;Name2[Id=XXXX],Count)

>>>label(start)
itemcount(Тут всё равно что[ID=151],=>,1)
{
MSG(пробуем кристаллизовать)
CRISTALLIZEITEM(Тут всё равно что[ID=151],1)
delay(500)
jmp(start)
}
MSG(кончилось всё)
EXIT()

<<<

>>>
label(start)
itemcount(Тут всё равно что[ID=80],>,1)
{
MSG(пробуем заточиться)
ENCHANTITEM(Тут скролл заточки[ID=729];Тут предмет[ID=80])
delay(500)
jmp(start)
}
MSG(кончилось всё)
EXIT()


<<<

Waider
07.03.2009, 00:15
Такая проблемка возникла скрипт на продажу в боте такой,продаёт отлично-
NPCDLG(Rouke[ID=31418])
LABEL(sell)
DLGSEL(Sell)
ITEMCOUNT(Tattoo of Absolute[ID=491],>,0)
{
SELLITEM(Tattoo of Absolute[ID=491],1)
JMP(sell)
}
MSG(кончилось всё)

прописал такой путь в хлапе
Name='kumus'; //имя персонажа в игре
PathWalkerScript='D:\eL2Walker2.09a\eL2Walker2.09a \script'; //путь к скрипту
NameWalkerScript='продажа в дионе.sec'; //имя скрипта
пишет ошибку имени тоесть выделяет нейм красным как быть, скрипт на точку от создателя переделанный под грацию пашет на 100%
Сервер у меня грация

NLObP
07.03.2009, 18:21
пишет ошибку имени

Может потому, что по русски? Попробуй короткое и на английском.
И еще, положи этот скрипт в папку \scripts пакетхака. Может тоже влияет?

Waider
07.03.2009, 20:16
спс попробую

NLObP
21.04.2009, 03:59
Дальнейшие работы со скриптом привели к определенным результатам. Работают команды
SET(MON,ATTACK,Name[ID=n];Name1[ID=n])
Set(FightStart|FightStop)
Set(RangeType,DefPos,x,y,z,radii)
Set(RangeType,StartPos,radii)


SET(MON,ATTACK,TEST1[ID=1020481];TEST2[ID=1020432];TEST3[ID=1020544])
//SET(RangeType,DefPos,5000,8000,-1200,1500)
SET(RangeType,StartPos,1500)
SET(FIGHTSTART)
DELAY(180000)
SET(FIGHTSTOP)


Удалось скрестить WalkerScriptRunner c ботом "локомотив от Alexus". Тестировал на Абиссе.

Grinch
21.04.2009, 07:33
добавь доп команду в скрипты валкекра, типа событие, флаг если моб умер, хотя могу быть не прав я поверхностно пробежал по валкеру

storoj
29.04.2009, 07:33
Удалось скрестить WalkerScriptRunner c ботом "локомотив от Alexus". Тестировал на Абиссе.
может быть выложишь на обозрение это творение ? ;)

NLObP
30.04.2009, 03:41
может быть выложишь на обозрение это творение ? ;)

Выкладываю новую версию скрипта, которая совместно с ботом - локомотивом эмулирует валкера (для сервера Абисс).

[+] Команды управления из чата START|RUN, STOP, PAUSE, RESUME, загрузка скрипта SCRIPT|LOAD=TEST
[+] Добавил управление ботом - Алексус, который пришлось модифицировать для поодержки данного скрипта
[+] Добавил POSOUTRANGE, POSINRANGE
[+] CharStatus([CHP|CMP|HP|MP|WEIGHT|LV|SP|RACE|STAND],[>=|>|==|!=|<|<=],число)
[+] Добавил UserInfo, StatusUpdate
[+] Добавил SET(MON,ATTACK|NOATTACK|ATTACKONE,Name[ID=n];Name1[ID=n];|*), SET(MON,NOATTACK,*)
[+] Добавил SET(RangeType,DefPos,x,y,z,radii), SET(RangeType,StartPos,radii)

мелкие правки кода

вложенные условия

поменял логику применения RequestEnchantItem

>>
//************************************************** ****************************
program WalkerScriptRunner;
//************************************************** ****************************
{version 0.10 от 30.04.2009г.
Walker Script Runner by NLObP for Russian Official Server Linage 2 (Gracia)
Эмулятор Walker'а: возможность запуска скриптов валкера в L2PacketHack 3.4.1+ by CoderX.ru

спасибо Trevor from allcheats.ru
_http://allcheats.ru/t37228/
что он может:
1.исполнение скриптов, написаных к L2Walker, из клиента игры

ВНИМАНИЕ:
Скрипт переводим в Ansi кодировку!
Настроим скрипт, найдя ниже по тексту такие строки и вставив тута нужные значения
Name='NLObP'; //имя персонажа в игре
NameWalkerScript='cristallize.sec'; //имя скрипта}
//При написани скриптов соблюдайте некоторые правила:
//1. команды пишутся в столбик
//2. если нужно написать команду с {}, то делается так
//CharStatus(***,***,***)
//{
//КОМАНДЫ
//}
//Или так
//CharStatus(***,***,***)
//{КОМАНДЫ}
//Или так
//CharStatus(***,***,***)
//{
//CharStatus(***,***,***)
//{
//КОМАНДЫ
//}
//}

//************************************************** ****************************
const
Name='RemoteAccess'; //имя персонажа в игре
//Name='NLObP'; //имя персонажа в игре

PathWalkerScript='.\scripts\walkerscript\'; //путь к скрипту
NameWalkerScript='default.sec'; //имя скрипта загружаемого по умолчанию

DefaultExecuteDelay=100; //стандартная задержка между коммандами Валкера
DefaultDistanciya=200; //дистанция при которой считаем, что пришли в нужную точку

debug=false; //если не хотим видеть отладочной информации - FALSE, иначе - TRUE

maxitems=250; //max количество предметов в базе
maxnpc=500; //max количество контролируемых NPC
kID=1000000;
//.................................................. ............................
var
WalkerScript, //сюда загружаем скрипт валкера
WalkerLabel, //здесь храним адреса меток в скрипте
ReturnStack: TStringList; //здесь храним адреса возврата по call()
sHTML, //здесь хранится текст сообщения из пакета NpcHtmlMessage
bypass: string; //для записи байпаса выбранной строчки в меню
TargetIDobject: integer;
ExecuteTimer: Ttimer; //основной таймер исполнения команд
ExecuteDelay: integer; //задержка между командами валкера

MoveTimer: Ttimer; //таймер движения
MoveDelay: integer; //задержка между командами движения
chkDelta: integer; //сохраняем дельту для проверки застревания
chkDelta2: integer; //сохраняем дельту для проверки застревания

strIndex: integer; //номер исполняемой строки в скрипте валкера

MyRace, MySex, //характеристики нашего чара
MyClass, MyLevel : integer;
MyOID, MyX, MyY, MyZ, MyMAX_HP, MyCUR_HP, MyMAX_MP,
MyCUR_MP, MyCur_CP, MyMax_CP, MySP, MyCUR_LOAD, MyMAX_LOAD : longint;
MyName:string;

X1, Y1, Z1, Delta1: integer;//координаты из команды MOVETO()
Running: boolean; //для вычисления скорости передвижения чара
runSpd, walkSpd : integer;
speed : extended;

//требуется поддержка БД
//BuyList
BaseBuyItems: array[1..maxitems, 1..2] of integer; //все предметы в инвентаре продавца
BuyListID: integer; //ID списка на продажу (всегда новый)

//Chars OID=Name...
//NPCs
BaseNPCs: array[1..maxnpc, 1..3] of integer; //все NPC вокруг
NpcCount : integer; //количество Npc в базе
{
1 - OID
2 - ID
3 - Attacable //можно атаковать - 1 или нет - 0
}
//ITEMs
BaseItems: array[1..maxitems, 1..12] of integer; //все предметы в инвентаре

//************************************************** ****************************
procedure Init; //Вызывается при включении скрипта
var
i, j :integer;
begin
debugMsg('WSR запущен!');
WalkerScript:=TStringList.Create;
WalkerLabel:=TStringList.Create;
ReturnStack:=TStringList.Create;
//загружаем скрипт валкера из файла
WalkerScript.LoadFromFile(PathWalkerScript+NameWal kerScript);

MakeLabel; //готовим адреса меток из скрипта Валкера

//чистим базы
for i:=1 to maxitems do
begin
for j:=1 to 12 do BaseItems[i,j]:=0; // забиваем нулями
end;
for i:=1 to maxnpc do
begin
for j:=1 to 3 do BaseNPCs[i,j]:=0; // забиваем нулями
end;


//14=RequestItemList вызываем инвентарь
buf:=hstr('14');
SendToServerEx(Name);
//delay(250);
//by Xelat
{я видел у тебя там проблемы с пакетом UserInfo - отправляешь на сервер пакет 6E
- RequestRecordInfo и тебе придёт и юзеринфо, и инфа о всех нпц и игроках,
которые тут есть}
buf:=#$6E;
SendToServerEx(Name);
//delay(250);

strIndex:=0; //начинаем с первой строки

ExecuteDelay:=DefaultExecuteDelay; //задержка между командами валкера

ExecuteTimer:=TTimer.Create(nil);
ExecuteTimer.Enabled:=false; //по умалчанию ExecuteTimer.Enabled:=false;
ExecuteTimer.Interval:=ExecuteDelay; //время задержки
ExecuteTimer.OnTimer:=@OnExecute;

MoveTimer:=TTimer.Create(nil);
MoveTimer.Enabled:=False;
MoveTimer.Interval:=1500; //время задержки
MoveTimer.OnTimer:=@OnMove;
end;
//.................................................. ............................
procedure Free; //Вызывается при выключении скрипта
begin
ExecuteTimer.Enabled:=False; //остановим на всякий случай
Executetimer.Free;
MoveTimer.Enabled:=False; //остановим на всякий случай
movetimer.Free;
WalkerScript.Free;
WalkerLabel.Free;
ReturnStack.Free;
end;
//************************************************** ****************************
{
Вспомогательные процедуры и функции
}
//************************************************** ****************************
//.................................................. ............................
function RequestEnchantItem(sData: string): boolean;
{
sData = Название предмета[ID=#];Название предмета[ID=#]

Tип: 0x19 (UseItem)
Pазмер: 9+2
Время прихода: 17:15:28:750
0002 d ObjectID: 268482417 (0x1000B771)
0006 d Unknown: 0 (0x00000000)

Tип: 0x5F (RequestEnchantItem)
Pазмер: 9+2
Время прихода: 17:15:34:015
0002 d ObjectID: 268482423 (0x1000B777)

отменили enchant
Tип: 0x5F (RequestEnchantItem)
Pазмер: 9+2
Время прихода: 17:37:27:421
0002 d ObjectID: -1 (0xFFFFFFFF)

результат: успешно
Tип: 0x87 (EnchantResult)
Pазмер: 13+2
Время прихода: 17:51:26:109
0002 d Result: 0 (0x00000000)
результат:разбили на кристаллы
Tип: 0x87 (EnchantResult)
Pазмер: 13+2
Время прихода: 17:53:29:703
0002 d Result: 1 (0x00000001)
результат:сбросило в 0 для блессед скроллов
Tип: 0x87 (EnchantResult)
Pазмер: 13+2
Время прихода: 17:53:29:703
0002 d Result: 2 (0x00000002)
}
var
i, ListSize, id, count: integer;
s: string;
begin
s:=sData+';'; //чтобы можно было взять число в конце
//Название предмета[ID=7807],10;Название предмета[ID=6529],1;
s:=ExtractValue(s,'='); //получили остаток строки начиная с искомого символа
if s<>'' then
begin
result:=false;
id:=strtoint(RTrimEx(ExtractName(s, ']'), ']')); //получили ID
sendmsg('ID='+inttostr(id));
for i:=1 to maxitems do
begin
if (BaseItems[i,3]=ID) then
begin //ищем по ItemID
debugMsg('UseItem');
buf:=#$19;
WriteD(BaseItems[i,2]); //пишем в пакет ObjectID
WriteD(0);
SendToServerEx(Name);
break;
end;
end;
delay(500);
//Название предмета[ID=7807],10;Название предмета[ID=6529],1;
s:=ExtractValue(s,'='); //получили остаток строки начиная с искомого символа
if s<>'' then
begin
id:=strtoint(RTrimEx(ExtractName(s, ']'), ']')); //получили ID
sendmsg('ID='+inttostr(id));
for i:=1 to maxitems do
begin
if (BaseItems[i,3]=ID) then
begin //ищем по ItemID
debugMsg('EnchantItem');
buf:=#$5F;
WriteD(BaseItems[i,2]); //пишем в пакет ObjectID
SendToServerEx(Name);
result:=true; //вещь, которую надо точить нашлась
break;
end;
end;
end else
begin //отменили энчант
debugMsg('отмена EnchantItem');
buf:=#$5F;
WriteD(-1); //пишем в пакет об отмене заточки
SendToServerEx(Name);
result:=false; //вещь, которую надо точить не нашлась
end;
end;
end;
//.................................................. ............................
procedure RequestCrystallizeItem(sData: string);
{CrystallizeItem(Name1[Id=XXX],Count;Name2[Id=XXX],Count)
sData = Название предмета[ID=#],Count;Название предмета[ID=#],Count
или
sData = Название предмета[ID=#],Count

Tип: 0x2F (RequestCrystallizeItem)
Pазмер: 9+2
Время прихода: 23:27:03:265
0002 d ObjectID: 268482418 (0x1000B772)
0006 d Count: 1 (0x00000001)
}
var
i, id, count: integer;
s: string;
eos: boolean;
begin
debugMsg('RequestCristallizeItem');
s:=sData+';'; //чтобы можно было взять число в конце
Count:=0;
eos:=false;
while not eos do
begin
//Название предмета[ID=7807],10;Название предмета[ID=6529],1;
s:=ExtractValue(s,'='); //получили остаток строки начиная с искомого символа
if s<>'' then
begin
id:=strtoint(RTrimEx(ExtractName(s, ']'), ']')); //получили ID
s:=ExtractValue(s,','); //получили остаток строки начиная с искомого символа
count:=strtoint(RTrimEx(ExtractName(s, ';'), ';')); //получили условие
for i:=1 to maxitems do
begin
if (BaseItems[i,3]=ID) then
begin //ищем по ItemID
buf:=#$2F; //начнем писать пакет
WriteD(BaseItems[i,2]); //пишем в пакет ObjectID
if count<=BaseItems[i,5] then WriteD(Count) else WriteD(BaseItems[i,5]);//пишем в пакет count
SendToServerEx(Name); //отсылаем пакет
//может сделать паузу вместо break и пройтись по всему инвентарю?
delay(500);
break;
end;
end;
end else eos:=true; //сигналим, что закончили поиск
end;
end;
//.................................................. ............................
procedure BuyList;
{Создаем базу BaseBuyItems

0002 d Money: 1140737 (0x00116801)
0006 d ListID: 3157300 (0x00302D34)
0010 h ListSize: 28 (0x001C)
[Начало повторяющегося блока 1/28]
0012 h ItemType1: 4
0014 d 0: 0
0018 d ItemID: Зеленая Наживка (для Новичков) ID:7807 (0x1E7F)
0022 d CurrentCount: 0
0026 h ItemType2: 5
0028 h 0: 0
0030 d BodyPart: 0
0034 h 0: 0
0036 h 0: 0
0038 h 0: 0
0040 d Price*TaxRate: 75
0044 d 0: 0
0048 d 0: 0
0052 d 0: 0
0056 d 0: 0
0060 d 0: 0
0064 d 0: 0
0068 d 0: 0
0072 d 0: 0
[Конец повторяющегося блока 1/28]
[Начало повторяющегося блока 2/28]
0076 h ItemType1: 4
}
var
i, j, k: integer;
ListCount: integer;
begin
j:=6; //смещение для ListID
BuyListID:=ReadD(j);
ListCount:=ReadH(j); //количество итемов не должно превышать max!
debugmsg('BuyListID='+inttostr(BuyListID)+' ListCount='+inttostr(ListCount));
for i:=1 to maxitems do
begin
if (i<=ListCount) then
begin
inc(j,6);
BaseBuyItems[i,1]:=ReadD(j); //ItemID
inc(j,18);
BaseBuyItems[i,2]:=ReadD(j); //Price*TaxRate
inc(j,32);
//debugmsg('ID='+inttostr(BaseBuyItems[i,1])+' price='+inttostr(BaseBuyItems[i,2]));

end else
for k:=1 to 2 do BaseBuyItems[i,k]:=0; // забиваем нулями
end;
end;
//.................................................. ............................
function RequestBuyItem(sData: string): boolean;
{
BuyItem(Название предмета[ID=#],#;Название предмета[ID=#],#)

sData = Название предмета[ID=#],#;Название предмета[ID=#],#
}
var
i, ListSize, id, count: integer;
s: string;
eos: boolean;
begin
debugMsg('RequestBuyItem');
s:=sData+';'; //чтобы можно было взять число в конце
ListSize:=0;
eos:=false;
{
0002 d ListID: 3157300 (0x00302D34)
0006 d ListSize: 2 (0x00000002)
[Начало повторяющегося блока 1/2]
0010 d ItemID: Зеленая Наживка (для Новичков) ID:7807 (0x1E7F)
0014 d Count: 10
[Конец повторяющегося блока 1/2]
[Начало повторяющегося блока 2/2]
0018 d ItemID: Удочка Утки ID:6529 (0x1981)
0022 d Count: 1
[Конец повторяющегося блока 2/2]
}
buf:=#$40;
WriteD(BuyListID);
WriteD(00); //ListCount - забили место
while not eos do
begin
//Название предмета[ID=7807],10;Название предмета[ID=6529],1;
s:=ExtractValue(s,'='); //получили остаток строки начиная с искомого символа
if s<>'' then
begin
id:=strtoint(RTrimEx(ExtractName(s, ']'), ']')); //получили ID
//sendmsg('ID='+inttostr(id));
s:=ExtractValue(s,','); //получили остаток строки начиная с искомого символа
count:=strtoint(RTrimEx(ExtractName(s, ';'), ';')); //получили условие
//sendmsg('Count='+inttostr(count));
for i:=1 to maxitems do
begin
if (BaseBuyItems[i,1]=ID) then
begin
WriteD(ID); //пишем в пакет ItemID
WriteD(Count);
inc(ListSize); //увеличиваем кол-во записей в пакете закупки
//sendmsg('ID='+inttostr(id)+' count='+inttostr(count)+' ListSize='+inttostr(listsize));
break;
end;
end;
end else eos:=true; //сигналим, что закончили поиск
end;
if ListSize>0 then
begin
//sendMsg('пишем ListSize');
WriteD(ListSize,6); //изменяем начиная с позиции 6
//sendMsg('шлём пакет RequestBuyItem='+strtohex(buf));
SendToServerEx(Name);
end;
end;
//.................................................. ............................
function RequestSellItem(sData: string): boolean;
{
SellItem(Название предмета[ID=#],#;Название предмета[ID=#],#)

sData = Название предмета[ID=#],#;Название предмета[ID=#],#
}
var
i, ListSize, id, count: integer;
s: string;
eos: boolean;
begin
debugMsg('RequestSellItem');
s:=sData+';'; //чтобы можно было взять число в конце
ListSize:=0;
eos:=false;
{
0x37 (RequestSellItem)
0002 d ListID: 0 (0x00000000)
0006 d ListSize: 2 (0x00000002)
[Начало повторяющегося блока 1/2]
0010 d ObjectID: 268482465
0014 d ItemID: Зеленая Наживка (для Новичков) ID:7807 (0x1E7F)
0018 d Count: 2
[Конец повторяющегося блока 1/2]
[Начало повторяющегося блока 2/2]
0022 d ObjectID: 268481851
0026 d ItemID: Зелье Исцеления ID:1061 (0x0425)
0030 d Count: 1
[Конец повторяющегося блока 2/2]
}
buf:=#$37;
WriteD(0); //SellListID = 0?
WriteD(0); //ListCount - забили место
while not eos do
begin
//Название предмета[ID=7807],10;Название предмета[ID=6529],1;
s:=ExtractValue(s,'='); //получили остаток строки начиная с искомого символа
if s<>'' then
begin
id:=strtoint(RTrimEx(ExtractName(s, ']'), ']')); //получили ID
//sendmsg('ID='+inttostr(id));
s:=ExtractValue(s,','); //получили остаток строки начиная с искомого символа
count:=strtoint(RTrimEx(ExtractName(s, ';'), ';')); //получили условие
//sendmsg('Count='+inttostr(count));
for i:=1 to maxitems do
begin
if (BaseItems[i,3]=ID) then
begin //ищем по ItemID
WriteD(BaseItems[i,2]); //пишем в пакет ObjectID
WriteD(BaseItems[i,3]); //пишем в пакет ItemID
if count<=BaseItems[i,5] then WriteD(Count) else WriteD(BaseItems[i,5]);//пишем в пакет count
inc(ListSize); //увеличиваем кол-во записей в пакете закупки
//sendmsg('ID='+inttostr(id)+' count='+inttostr(count)+' ListSize='+inttostr(listsize));
break;
end;
end;
end else eos:=true; //сигналим, что закончили поиск
end;
if ListSize>0 then
begin
//sendMsg('пишем ListSize');
WriteD(ListSize,6); //изменяем начиная с позиции 6
//sendMsg('шлём пакет RequestBuyItem='+strtohex(buf));
SendToServerEx(Name);
end;
end;
//.................................................. ............................
procedure ItemList;
{Создаем базу Items}
//11=ItemList:h(ShowWindow)h(ListSize:Loop.01.0021)h (ItemType1)d(ObjectID)
// d(ItemID:Get.Func01)d(LocationSlot)d(Count)h(ItemT ype2)h(CustomType1)
// h(isEquipped)d(BodyPart)h(EnchantLevel)h(CustType2 )d(AugmentationID)
// d(Mana)d(AttackAttrElement)d(AttackAttrElementVal) d(DefAttrFire)
// d(DefAttrWater)d(DefAttrWind)d(DefAttrEarth)d(DefA ttrHoly)d(DefAttrUnholy)
var
i, j, k: integer;
ListCount: integer;
begin
j:=4; //смещение для ListCount
ListCount:=ReadH(j); //количество итемов не должно превышать max!
for i:=1 to maxitems do
begin
if (i<=ListCount) then
begin
BaseItems[i,1]:=ReadH(j); //ItemType1
BaseItems[i,2]:=ReadD(j); //ObjectID
BaseItems[i,3]:=ReadD(j); //ItemID
BaseItems[i,4]:=ReadD(j); //LocationSlot
BaseItems[i,5]:=ReadD(j); //Count
BaseItems[i,6]:=ReadH(j); //ItemType2
BaseItems[i,7]:=ReadH(j); //CustomType1
BaseItems[i,8]:=ReadH(j); //isEquipped
BaseItems[i,9]:=ReadD(j); //BodyPart
BaseItems[i,10]:=ReadH(j); //EnchantLevel
BaseItems[i,11]:=ReadH(j); //CustType2
BaseItems[i,12]:=ReadD(j); //AugmentationID
//debugmsg('OID='+inttostr(BaseItems[i,2])+' ID='+inttostr(BaseItems[i,3]));
inc(j,40);
end else
for k:=1 to 12 do BaseItems[i,k]:=0; // забиваем нулями
end;
end;
//.................................................. ............................
procedure InventoryUpdate; //пакет 21, Создает базу ObjectID по ItemID
var
i, ii, j, k, ListCount, UpdType : integer;
ItemType1, ObjectID, ItemID, LocationSlot, Count, ItemType2, CustomType1,
isEquipped, BodyPart, EnchantLevel, CustType2, AugmentationID :integer;
additem : boolean;
begin
additem:=true;
ListCount:=ReadH(2); //количество итемов
//debugmsg('ListCount='+inttostr(ListCount));
j:=4; //смещение для действия с предметом 1-добавлен 2-изменен 3-удален
for i:=1 to ListCount do
begin
UpdType:=ReadH(j);
ItemType1:=ReadH(j);
ObjectID:=ReadD(j);
ItemID:=ReadD(j);
LocationSlot:=ReadD(j);
Count:=ReadD(j);
ItemType2:=ReadH(j);
CustomType1:=ReadH(j);
isEquipped:=ReadH(j);
BodyPart:=ReadD(j);
EnchantLevel:=ReadH(j);
CustType2:=ReadH(j);
AugmentationID:=ReadD(j);
case UpdType of
1: k:=0; //добавлен новый предмет
2: k:=ObjectID; //изменен предмет в инвентаре
3: begin //удален
for ii:=1 to maxitems do
if (BaseItems[ii,2]=ObjectID) then
begin
//debugmsg('удаляем OID='+inttostr(BaseItems[ii,2])+' ID='+inttostr(BaseItems[ii,3]));
for k:=1 to 12 do BaseItems[ii,k]:=0;
break;
end;
end;
end;
for ii:=1 to maxitems do
begin
if (BaseItems[ii,2]=k) then
begin
BaseItems[ii,1]:=ItemType1;
//BaseItems[ii,2]:=ObjectID;
BaseItems[ii,3]:=ItemID;
BaseItems[ii,4]:=LocationSlot;
BaseItems[ii,5]:=Count;
BaseItems[ii,6]:=ItemType2;
BaseItems[ii,7]:=CustomType1;
BaseItems[ii,8]:=isEquipped;
BaseItems[ii,9]:=BodyPart;
BaseItems[ii,10]:=EnchantLevel;
BaseItems[ii,11]:=CustType2;
BaseItems[ii,12]:=AugmentationID;
//debugmsg('доб/изм OID='+inttostr(BaseItems[ii,2])+' ID='+inttostr(BaseItems[ii,3]));
break;
end;
end;
inc(j,38);
end;
end;
//.................................................. ............................
function GetItem(ID, FieldIn, FieldOut : integer): integer;
{GetInv(по чему будем искать, номер того по чему будем искать, номер того что надо найти)
где:
ID - искомый код;
FieldIn - по какому полю ищем;
FieldOut - какое поле возвращаем;
1=ItemType1; 2=ObjectID;3=ItemID;4=LocationSlot;5=Count;6=ItemT ype2;7=CustomType1;
8=isEquipped;9=BodyPart;10=EnchantLevel;11=CustTyp e2;12=AugmentationID;
ex1: GetInv(6408,2,1) - вернет ObjectID свадебного платья, если онное лежит в
инвентаре, иначе вернет -1
ex2: GetInv(6408,2,8) - вернет уровень заточки первого попавшегося в инвентаре
свадебного платья, если свадебного платья нет, то вернет -1
}
var
i: integer;
begin
for i:=1 to maxitems do
if (BaseItems[i,FieldIn]=ID) then begin
Result:=BaseItems[i,FieldOut];
debugmsg('Нашли='+inttostr(result));
exit;
end;
Result:=-1;
end;
//.................................................. ............................
procedure AppendNpc(OID, ID, Att : integer);
{добавляем в базу данных NPC и мобов}
var
i: integer;
isExists:boolean;
begin
isExists:=false;
for i:=1 to maxnpc do begin
//если нашли в базе, то коректируем
if (BaseNPCs[i,1]=OID) and (MyOID<>OID) then begin
BaseNPCs[i,2]:=ID; //ID
BaseNPCs[i,3]:=Att; //Attacable
isExists:=true;
end;
end;
if not isExists then
begin //иначе, перебираем базу, ищем свободную ячейку в ней и добавляем нового
for i:=1 to maxnpc do begin
if (BaseNPCs[i,1]=0) and (MyOID<>OID) then begin
//запоминаем моба в свободную ячейку
BaseNPCs[i,1]:=OID; //OID
BaseNPCs[i,2]:=ID; //ID
BaseNPCs[i,3]:=Att; //Attacable
break;
end;
end;
end;
end;
//.................................................. ............................
procedure DeleteNpc(OID : integer);
{удаляем Npc}
var
i : integer;
begin
for i:=1 to maxnpc do
begin
//если нашли в базе, то удаляем его
if (BaseNPCs[i,1]=OID) then
begin
//debugmsg('Удаляем '+inttostr(BaseNPCs[i,1])+' '+inttostr(BaseNPCs[i,2]));
BaseNPCs[i,1]:=0; //OID
BaseNPCs[i,2]:=0; //ID
BaseNPCs[i,3]:=0; //ID
break;
end;
end;
end;
//.................................................. ............................
function GetNpcOID(ID:integer): integer;
{ищем в БД OID по ID}
var
i: integer;
begin
for i:=1 to maxnpc do
if (BaseNpcs[i,2]=ID) then
begin
Result:=BaseNpcs[i,1];
exit;
end;
Result:=-1;
end;
//.................................................. ............................
function RtrimEx(sData, sDelimiter: string): string;
{Удаление из строки S заданные символы справа}
var
m,i : integer;
s: string;
begin
s:=sData;
i:=0;
while i=0 do
begin
m:=length(s);
if m>0 then begin
if s[m]<>sDelimiter then i:=1;
if s[m]=sDelimiter then delete(s,m,1);
end;
if m <= 0 then i:=1;
end;
result:=s;
end;
//.................................................. ............................
function LtrimEx(sData, sDelimiter:String): string;
{Удаление из строки S заданные символы слева}
var
m,i : integer;
s: string;
begin
s:=sData;
i:=0;
while i=0 do
begin
m := length(s);
if m > 0 then
begin
if s[1]<>sDelimiter then i:=1;
if s[1]=sDelimiter then delete(s,1,1);
end;
if m <= 0 then i:=1;
end;
result:=s;
end;
//.................................................. ............................
function Ltrim(sData:String): string;
{Удаление из строки S заданные символы слева}
begin
result:=LtrimEx(sData,' ');
end;
//.................................................. ............................
function Rtrim(sData:String): string;
{Удаление из строки S заданные символы слева}
begin
result:=RtrimEx(sData,' ');
end;
//.................................................. ............................
function AllTrimEx(sData, sDelimiterLeft, sDelimiterRight: String): string;
{Удаление из строки S заданные символы слева и справа}
begin
result:=LtrimEx(RtrimEx(sData, sDelimiterRight), sDelimiterLeft);
end;
//.................................................. ............................
function AllTrim(sData: String): string;
{Удаление из строки S заданные символы слева и справа}
begin
result:=Ltrim(Rtrim(sData));
end;
//.................................................. ............................
{
В TStringList и Tstring -> Name=Value
123=ghjdthrf
i:=WalkerScript.IndexOfName(IntToHex(id,2));
i:=WalkerScript.Values[123]; //по value возвращает Name
i:=WalkerScript.Names[123]; //по Name возвращает Value
}
function GetValues(ValName: string): string;
begin
result:=WalkerScript.Values[ValName];
end;
//.................................................. ............................
function GetNames(Value: string): string;
begin
result:=WalkerScript.Names[strtoint(Value)];
end;
//.................................................. ............................
procedure SetValues(ValName: string; Value: string);
begin
WalkerScript.Values[ValName]:=Value;
end;
//.................................................. ............................
procedure SetNames(Value: string; Name: string);
begin
WalkerScript.Names[strtoint(Value)];
end;
//.................................................. ............................
function ExtractValue(sData, sFind: string;): string;
{возвращаем конец строки после найденного символа}
var
s: string;
i,j: integer;
begin
i:=0;
result:='';
i:=find(sData, sFind);
if i>0 then result:=copy(sData, i+length(sFind), length(sData));
end;
//.................................................. ............................
function ExtractName(sData, sFind: string): string;
{возвращаем строку до найденного символа}
var
i: integer;
begin
i:=0;
result:='';
i:=find(sData, sFind);
//if i>0 then result:=copy(sData,1,i-length(sFind));
if i>0 then result:=copy(sData, 1, i-length(sFind)+1);
end;
//.................................................. ............................
function Find(const S, P: string): Integer;
{Функция Find ищет подстроку P в строке S и возвращает индекс первого символа
подстроки или 0, если подстрока не найдена. Хотя в общем случае этот метод,
как и большинство методов грубой силы, малоэффективен, в некоторых ситуациях
он вполне приемлем.}
var
i, j: Integer;
begin
Result:=0;
if Length(P)>Length(S) then
begin
debugMSG('Несоответствие длин: p='+inttostr(Length(P))+' > S='+inttostr(Length(s)));
debugMSG('Строка: '+inttostr(strIndex));
Exit;
end;
for i:=1 to Length(S)-Length(P)+1 do //x0 начало смещения для поиска в строке
begin
for j:=1 to Length(P) do
begin
if P[j]<>S[i+j-1] then
Break
else if j=Length(P) then
begin
Result:=i;
Exit;
end;
end;
end;
end;
//.................................................. ............................
function GetID(sData: string): string;
{находим ID в строке sData
NPCSEL(Marcela[ID=32173])
NPCDLG(Marcela[ID=32173])
}
var
i: integer;
s, sID: string;
eos: boolean; //конец NpcHtmlMessage
begin
debugMsg('GetID');
s:=sData;
result:='';
s:=ExtractValue(s,'='); //получили остаток строки начиная с искомого символа
//debugMsg('ExtractValue:'+s);
if s='' then
begin
//debugMsg('BREAK');
exit;
end;
sID:=RTrimEx(ExtractName(s, ']'), ']'); //получили ID
//debugMsg('ExtractName:'+sID);
result:=sID;
end;
//.................................................. ............................
function GetBypass(sData, sText: string): string;
{находим в NpcHtmlMessage по заданной строке текста соответствующий ей bypass

Например:
Gatekeeper Clarissa:
<br> We Gatekeepers use the will of the Gods to open the doors to time and space and teleport others. Which door would you like to open?<br>
<a action="bypass -h teleport_request"> Teleport</a><br>
<a action="bypass -h menu_select?ask=-303&reply=518"> Exchange with the Dimension Diamond</a><br>
<a action="bypass -h menu_select?ask=-19&reply=0"> [Noblesse Only] teleport</a><br>
<a action="bypass -h menu_select?ask=255&reply=4" msg="811;Monster Derby Track"> Move to Monster Derby Track (Free of Charge)</a><br>
<a action="bypass -h talk_select">Quest </a></body></html>
}
var
i: integer;
s, bypass, text: string;
eos: boolean; //конец NpcHtmlMessage
begin
debugMsg('GetBypass');
s:=sData;
eos:=false;
result:='';
//поискать bypass в строке
while not eos do
begin //пока не конец NpcHtmlMessage считываем данные
s:=ExtractValue(s,'-h'); //получили остаток строки начиная с искомого символа
//debugMsg('ExtractValue:'+s);
if s='' then
begin
//debugMsg('BREAK');
break; //eos:=true; //сигналим, что закончили поиск
end;
bypass:=AllTrim(ExtractName(s, '">')); //получили bypass
//debugMsg('ExtractName:'+bypass);
s:=ExtractValue(s,'">'); //получили остаток строки начиная с искомого символа
//debugMsg('ExtractValue: '+s);
text:=AllTrim(ExtractName(s, '</')); //получили текст
//debugMsg('ExtractName:'+text);
if sText=text then
begin
//debugMsg('Нашли подходящий bypass: '+bypass);
result:=bypass; //нашли подходящий bypass
eos:=true; //сигналим, что закончили поиск
end;
end;
//debugMsg('не нашли в строке');
if result='' then
begin //поискать bypass в кнопке
//debugMsg('поищем в кнопке');
s:=sData;
eos:=false;
while not eos do
begin //пока не конец NpcHtmlMessage считываем данные
s:=ExtractValue(s,'button value="'); //получили остаток строки начиная с искомого символа
//debugMsg('ExtractValue:'+s);
if s='' then
begin
//debugMsg('BREAK');
break; //сигналим, что закончили поиск
end;
text:=AllTrim(ExtractName(s, '"')); //получили текст
text:=RTrimEx(text,'"'); //получили текст
s:=ExtractValue(s,'-h'); //получили остаток строки начиная с искомого символа
//debugMsg('ExtractValue: '+s);
bypass:=AllTrim(ExtractName(s, '"')); //получили bypass
bypass:=RTrimEx(bypass,'"'); //получили текст
//debugMsg('ExtractName:'+bypass);
//debugMsg('ExtractName:'+text);
if sText=text then
begin
//debugMsg('Нашли подходящий bypass: '+bypass);
result:=bypass; //нашли подходящий bypass
eos:=true; //сигналим, что закончили поиск
end;
end;
end;
end;
//.................................................. ............................
function CorrectCoord(Coord: integer): integer;
{коррекция значений координат}
begin
result:=Coord;
if result > 2147483648 then result:=result-4294967296;
end;
//.................................................. ............................
procedure GetXYZ(sData: string);
{
находим X, Y, Z в строке sData
MOVETO(-119839,44516,341)
}
var
s: string;
begin
debugMsg('GetXYZ');
s:=sData+','; //-119839,44516,341, чтобы можно было взять Z
x1:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили X
//x1:=CorrectCoord(x1);
s:=ExtractValue(s,','); //получили остаток строки начиная с искомого символа
y1:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили Y
//y1:=CorrectCoord(y1);
z1:=strtoint(RTrimEx(ExtractValue(s,','), ',')); //получили Z
//z1:=CorrectCoord(z1);
end;
//.................................................. ............................
procedure GetXYZD(sData: string);
{
находим X, Y, Z, Delta в строке sData
Posinrange(-119839,44516,341,100)
}
var
s: string;
begin
debugMsg('GetXYZD');
s:=sData+','; //-119839,44516,341,100, чтобы можно было взять Delta
x1:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили X
//x1:=CorrectCoord(x1);
s:=ExtractValue(s,','); //получили остаток строки начиная с искомого символа
y1:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили Y
//y1:=CorrectCoord(y1);
z1:=strtoint(RTrimEx(ExtractValue(s,','), ',')); //получили Z
//z1:=CorrectCoord(z1);
delta1:=strtoint(RTrimEx(ExtractValue(s,','), ',')); //получили Delta
end;
//.................................................. ............................
function GetItemcount(sData: string): boolean;
//ITEMCOUNT(Red Bone Necklace[ID=7179],==,100)
//{
//}
//в sData = Red Bone Necklace[ID=7179],==,100
var
s, uslovie: string;
i, id, count2, count: integer;
begin
debugMsg('GetItemcount');
s:=sData+','; //чтобы можно было взять число в конце
s:=ExtractValue(s,'='); //получили остаток строки начиная с искомого символа
id:=strtoint(RTrimEx(ExtractName(s, ']'), ']')); //получили ID
s:=ExtractValue(s,','); //получили остаток строки начиная с искомого символа
uslovie:=RTrimEx(ExtractName(s, ','), ','); //получили условие
count2:=strtoint(RTrimEx(ExtractValue(s,','), ',')); //получили число для проверки
count:=0; //GetItem(id,3,5); //возвращает количество из инвентаря
//считаем все подходящие предметы
for i:=1 to maxitems do
begin
if (BaseItems[i,3]=ID) then
begin
count:=count+BaseItems[i,5];
end;
end;
debugmsg('Нашли='+inttostr(count));
SendMessage('Нашли='+inttostr(count));

//обрабатываем условия, во всевозможных вариациях
case uslovie of
'==','=' : if count=count2 then result:=true;
'=>','>=': if count>=count2 then result:=true;
'>' : if count>count2 then result:=true;
'!=','<>','><' : if count<>count2 then result:=true;
'<' : if count<count2 then result:=true;
'<=','=<': if count<=count2 then result:=true;
end;
end;
//.................................................. ............................
function GetCharStatus(sData: string): boolean;
//CharStatus([CHP|CMP|HP|MP|WEIGHT|LV|SP|RACE|STAND],[>=|>|==|!=|<|<=],число)
//{
//}
//в sData = HP,<,70
var
s, conditiontype, uslovie: string;
i, id, count2, count: integer;
begin
debugMsg('GetCharStatus');
s:=sData+','; //чтобы можно было взять число в конце
conditiontype:=RTrimEx(ExtractName(s, ','), ','); //получили название статуса
debugMsg(conditiontype);

s:=ExtractValue(s,','); //получили остаток строки начиная с искомого символа
uslovie:=RTrimEx(ExtractName(s, ','), ','); //получили условие
debugMsg(uslovie);
count2:=strtoint(RTrimEx(ExtractValue(s,','), ',')); //получили число для проверки
debugMsg(inttostr(count2));
count:=0;
{CharStatus(CONDITIONTYPE,>=|>|==|!=|<|<=,#)
Замеряет состояние персонажа. Прочитайте все, что относится к <Операторам>,
чтобы знать как правильно это функционирует.:
CHP --> Здоровье
CharStatus(CHP,>=|>|==|!=|<|<=,#)
CMP: Мана
CharStatus(CMP,>=|>|==|!=|<|<=,#)
HP: ХП персонажа в процентах
CharStatus(HP,>=|>|==|!=|<|<=,#)
MP: МП персонажа в процентах
CharStatus(MP,>=|>|==|!=|<|<=,#)
SP: SP персонажа
CharStatus(SP,>=|>|==|!=|<|<=,#)
LV: Уровень персонажа
CharStatus(LV,>=|>|==|!=|<|<=,#)
Race: Раса персонажа
CharStatus(Race,>=|>|==|!=|<|<=,#)
(#=0: Human; #=1: Elf; #=2: Dark Elf; #=3: Orc; #=4: Dwarf)
}
case conditiontype of
'CHP' : count:=mycur_hp; //ХП персонажа
'CMP' : count:=mycur_mp; //МП персонажа
'HP' : count:=mycur_hp * 100 div mymax_hp; //ХП персонажа в процентах
'MP' : count:=mycur_mp * 100 div mymax_mp; //МП персонажа в процентах
'WEIGHT': count:=mycur_load * 100 div mymax_load;
'LV' : count:=mylevel;
'SP' : count:=mysp;
'RACE' : count:=myrace;
//'STAND' : count:=mystand;
end;
//обрабатываем условия, во всевозможных вариациях
case uslovie of
'==','=' : if count=count2 then result:=true;
'=>','>=': if count>=count2 then result:=true;
'>' : if count>count2 then result:=true;
'!=','<>','><' : if count<>count2 then result:=true;
'<' : if count<count2 then result:=true;
'<=','=<': if count<=count2 then result:=true;
end;
end;
//.................................................. ............................
//пропускаем фигурные скобки
procedure SkipFS;
var
i, j : integer;
s: string;
begin
debugMsg('Пропускаем фигурные скобки...');
j:=0;
for i:=strIndex to WalkerScript.Count-1 do
begin
s:=WalkerScript[i]; //считываем команду из листа
case s of
//пропускаем всё до соответствующей фигурной скобки
'{': begin
debugmsg('Нашли скобку {... strIndex='+inttostr(strIndex));
inc(j);
end;
'}': begin
debugmsg('Нашли скобку }... strIndex='+inttostr(strIndex));
dec(j);
if j=0 then exit;
end;
end;
inc(strIndex);
end;
end;
//.................................................. ............................
//Проверка находится ли заданная точка в пределах досягаемости.
function PosInRange(targetx,targety,targetz,distanciya:inte ger):boolean;
begin
if delta(targetx, targety, MyX, MyY)<=distanciya then result:=true else result:=false;
end;
//.................................................. ............................
//Проверка находится ли заданная точка за пределами досягаемости.
function PosOutRange(targetx,targety,targetz,distanciya:int eger):boolean;
begin
if delta(targetx, targety, MyX, MyY)>distanciya then result:=true else result:=false;
end;
//.................................................. ............................
function delta(xpos1, ypos1, xpos2, ypos2:extended):integer; //возвращает растоянием между 2 точками
var
dx, dy, summa: extended;
begin
try
dx:=xpos1-xpos2;
dy:=ypos1-ypos2;
summa:=dx*dx+dy*dy;
if summa=0 then result:=0 else result:=Round(sqrt(summa));
debugmsg('delta='+inttostr(result));
chkDelta:=result; //сохраним дельту для проверки застревания
except
debugmsg('error in delta');
end;
end;
//.................................................. ............................
procedure debugMsg(msg: string);
begin
if debug then
begin
sendMSG(msg);
SendMessage(msg);
end;
end;
//************************************************** ****************************
{
Посылаем пакеты
}
//************************************************** ****************************
//послать сообщение в чат
//use: SendMessage(msg);
procedure SendMessage(msg:string); //отправка системных сообщений клиенту
begin
buf:=#$4A;
WriteD(0);
WriteD(10);
WriteS('');
WriteS(msg);
SendToClientEx(Name);
end;
//.................................................. ............................
//использовать предмет
//use: UseItem(oid);
procedure UseItem(OID, shift: integer);
begin
//c19=UseItem:d(ObjectID)d(Unknown)
buf:=#$19;
WriteD(OID);
WriteD(shift);
SendToServerEx(Name);
end;
//.................................................. ............................
//снять цель
//use: TargetCancel;
procedure TargetCancel;
begin
buf:=Hstr('48 00 00');
SendToServerEx(Name);
end;
//.................................................. ............................
//взять в цель
//use: Action(OID);
procedure Target(OID: Integer);
begin
//c1F=Action:d(ObjectID)d(OriginX)d(OriginY)d(Origin Z)c(ActionID)
buf:=#$1F;
WriteD(OID);
WriteD(MyX);
WriteD(MyY);
WriteD(MyZ);
WriteC(00);
SendToServerEx(Name);
end;
//.................................................. ............................
//атаковать цель, действует толко после Action(OID)
//use: AttackRequest(OID);
procedure Attack(OID: Integer);
begin
//c01=AttackRequest:d(ObjectID)d(OriginX)d(OriginY)d (OriginZ)c(AttackID)
buf:=#$01;
WriteD(OID);
WriteD(MyX);
WriteD(MyY);
WriteD(MyZ);
WriteC(00);
SendToServerEx(Name);
end;
//.................................................. ............................
//Идти в точку с координатами x,y,z
//use: MoveBackwardToLocation(X,Y,Z);
procedure MoveBackwardToLocation(TargetX,TargetY,TargetZ: integer);
begin
//c0F=MoveBackwardToLocation:d(ToX)d(ToY)d(ToZ)d(Ori gX)d(OrigY)d(OrigZ)d(MoveMovement)
buf:=#$0F;
WriteD(TargetX); //куда
WriteD(TargetY);
WriteD(TargetZ);
WriteD(MyX); //откуда
WriteD(MyY);
WriteD(MyZ);
WriteD(1); //используем 1-мышь 0-клавиатура
SendToServerEx(Name);
end;
//.................................................. ............................
//выбор пункта меню
//use: RequestBypassToServer:s(Cmd)
procedure RequestByPassToServer(cmd: string);
begin
buf:=#$23;
WriteS(cmd);
SendToServerEx(Name);
end;
//.................................................. ............................
//************************************************** ****************************
// Поддержка меток используемых в скрипте Валкера
//************************************************** ****************************
procedure MakeLabel;
{перебираем строки скрипта и сохраняет в стринглист адреса меток}
var
i: integer;
s, cmd, param: string;
begin
//собираем метки
debugMsg('Готовим метки...');
WalkerLabel.Clear;
for i:=0 to WalkerScript.Count-1 do
begin
s:=WalkerScript[i]; //считываем команду из листа
cmd:=UpperCase(RtrimEx(ExtractName(s, '('), '(')); //выцепляем команду
param:=RtrimEx(ExtractValue(s, '('),')'); //выцепляем параметр
case cmd of
{безусловный переход на метку}
'LABEL': begin
WalkerLabel.Add(param+'='+inttostr(i));
debugmsg(param+'='+inttostr(i));
end;
{всё остальное игнорируем}
end;
end;
//WalkerLabel.SaveToFile(PathWalkerScript+'label.txt ');
end;
//************************************************** ****************************
// Поддержка организации движения
//************************************************** ****************************
function OnMove(Sender: TObject): integer; //CommandList: TStringList
begin
debugMsg('Процесс движения...');
if posinrange(x1,y1,z1,DefaultDistanciya) then
begin
MoveTimer.Enabled:=false;
ExecuteTimer.Enabled:=True;
debugMsg('Добежали...');
end else
begin
debugMsg('Ещё не добежали...');
if chkDelta2=chkDelta then
begin
MoveBackwardToLocation(x1,y1,z1);
debugMsg('Ещё раз бежим в точку...');
end else
chkDelta2:=chkDelta; //сохраняем дельту для проверки застревания
end;
end;
//************************************************** *************
{
32=UserInfo:d(X)d(Y)d(Z)d(Heading)d(ObjectID)s(Nam e)d(Race)d(Sex)d(ClassID:Get.ClassID)d(Level)q(Exp )d(STR)d(DEX)d(CON)d(INT)d(WIT)d(MEN)d(MaxHP)d(Cur rentHP)d(MaxMP)d(CurrentMP)d(SP)d(CurrentLoad)d(Ma xLoad)d(40)d(Unknown)d(RightEarring)d(LeftEarring) d(Necklace)d(RightRing)d(LeftRing)d(Head)d(RightHa nd)d(LeftHand)d(Gloves)d(Chest)d(Legs)d(Boots)d(Un known)d(Unknown)d(Hair)d(Face)d(Unknown)d(Unknown) d(0)d(0)d(0)d(0)d(0)d(0)d(Unknown)d(RightEarring)d (LeftEarring)d(Necklace)d(RightRing)d(LeftRing)d(H ead)d(RightHand)d(LeftHand)d(Gloves)d(Chest)d(Legs )d(Boots)d(Unknown)d(Unknown)d(Hair)d(Face)d(Unkno wn)d(Unknown)d(0)d(0)d(0)d(0)d(0)d(0)h(0)h(0)h(0)h (0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)d(Augme ntationID)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0) h(0)h(0)d(Unknown)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0) h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)h(0)d( PAtk)d(AtkSpd)d(PDef)d(Evasion)d(Accuracy)d(CritRa te)d(MAtk)d(CastSpd)d(AtkSpd)d(MDef)d(PvpFlag)d(Ka rma)d(RunSpd)d(WalkSpd)d(SwimRunSpd)d(SwimWalkSpd) d(FlRunSpd)d(FlWalkSpd)d(FlyRunSpd)d(FlyWalkSpd)f( MoveMultiplier)f(AtkSpdMultiplier)f(CollisionRadiu s)f(CollisionHeight)d(HairStyle)d(HairColor)d(Face )d(AccessLevel)s(Title)d(ClanID)d(ClanCrestID)d(Al lyID)d(AllyCrestID)d(Relation)c(MounType)c(Private StoreType)c(DwarvenCraft)d(PkKills)d(PvpKills)h(Cu bicsSize:Loop.01.0001)h(CubicID)c(0)d(AbnormalEffe ct)c(0)d(ClanPrivileges)h(RecomLeft)h(RecomHave)d( MountNpcID)h(InventoryLimit)d(ClassID:Get.ClassID) d(0)d(MaxCP)d(CurrentCP)c(isMount)c(Team)d(ClanCre stLargeID)c(isNoble)c(isHero)c(isFishing)d(FishX)d (FishY)d(FishZ)d(NameColor)c(isRunning)d(PledgeCla ss)d(0)d(TitleColor)d(CursedWeapon)d(Tranformation ID)d(AttackAttrElement)d(AttackAttrElementVal)d(De fAttrFire)d(DefAttrWater)d(DefAttrWind)d(DefAttrEa rth)d(DefAttrHoly)d(DefAttrUnholy)d(0)
}
procedure UserInfo;
{данные о себе}
var
i:integer;
begin
i:=2;
MyX:=ReadD(i);
MyY:=ReadD(i);
MyZ:=ReadD(i);
ReadD(i); //пропускаем heading
MyOID:=ReadD(i);
MyName:=ReadS(i);
MyRace:=ReadD(i);
MySex:=ReadD(i);
MyClass:=ReadD(i);
MyLevel:=ReadD(i);
inc(i,32);
MyMAX_HP:=ReadD(i);
MyCUR_HP:=ReadD(i);
MyMAX_MP:=ReadD(i);
MyCUR_MP:=ReadD(i);
MySP:=ReadD(i);
MyCUR_LOAD:=ReadD(i);
MyMAX_LOAD:=ReadD(i);
{
debugMsg('MyName='+MyName);
debugMsg('MyRace='+inttostr((MyRace)));
debugMsg('MySex='+inttostr((MySex)));
debugMsg('MyClass='+inttostr((MyClass)));
debugMsg('MyLevel='+inttostr((MyLevel)));
debugMsg('MyCurHP='+inttostr((MyCUR_HP)));
debugMsg('My=MaxHP'+inttostr((MyMAX_HP)));
debugMsg('MyCurMP='+inttostr((MyCUR_MP)));
debugMsg('MyMaxMP='+inttostr((MyMAX_MP)));
}
end;
//......................................
//************************************************** *************
{
18=StatusUpdate:d(ObjectID)d(AttribCount:Loop.01.0 002)d(AttrID:Get.FSup)d(AttrValue)
}
procedure StatusUpdate;
{обновление данных о себе}
var
i: integer;
begin
for i:=0 to ReadD(6)-1 do
case pck[i*8+10] of
#$01: MyLevel:=ReadD(i*8+14);
#$09: MyCur_HP:=ReadD(i*8+14);
#$0A: MyMax_HP:=ReadD(i*8+14);
#$0B: MyCur_MP:=ReadD(i*8+14);
#$0C: MyMax_MP:=ReadD(i*8+14);
#$0D: MySP:=ReadD(i*8+14);
#$0E: MyCur_Load:=ReadD(i*8+14);
#$0F: MyMax_Load:=ReadD(i*8+14);
#$21: MyCur_CP:=ReadD(i*8+14);
#$22: MyMax_CP:=ReadD(i*8+14);
end;
end;
//......................................
//************************************************** ****************************
// Парсер/Исполнитель: главный цикл обработки команд Валкера
//************************************************** ****************************
function OnExecute(Sender: TObject): integer; //CommandList: TStringList
var
s, cmd, param : string;
begin
debugMsg('Парсер команд валкера...');
ExecuteTimer.Enabled:=false; //остановим на время интерпретации и выполнения команды
result:=-1;
//проверка на наличие команд в скрипте
if WalkerScript.Count=0 then
begin
result:=0;
debugMsg('В скрипте нет данных для выполнения!');
exit;
end;
try
ExecuteTimer.Interval:=DefaultExecuteDelay; //восстанавливаем скорость исполнения скрипта Валкера
//на каждом шаге работаем с одной командой
s:=WalkerScript[strIndex]; //считываем команду из листа
debugMsg('Команда скрипта: '+s);
cmd:=UpperCase(RtrimEx(ExtractName(s, '('), '(')); //выцепляем команду
debugMsg('Команда: '+cmd);
param:=RtrimEx(ExtractValue(s, '('),')'); //выцепляем параметр
debugMsg('Параметр: '+param);
case cmd of
'GOHOME': begin
{Переход к началу скрипта после смерти}
//debugMSG('переходим к началу скрипта');
//strIndex:=0; //устанавливаем новую строку для исполнения
//debugMSG('strIndex='+inttostr(strIndex));
//RequestRestartPoint(5); //7D=RequestRestartPoint:d(PointType)
end;
'JMP': begin
{безусловный переход на метку}
//param:=RtrimEx(ExtractName(param,')'),')');
//debugMSG('результат='+param);
param:=WalkerLabel.Values[param]; //ищет по строке, номер строки (label=10)
//tmp:=WalkerLabel.Names[param]; //ищет по номеру
debugMSG('переходим на строку='+param);
strIndex:=strtoint(param); //устанавливаем новую строку для исполнения
debugMSG('strIndex='+inttostr(strIndex));
end;
'CALL': begin
{безусловный переход на метку}
//param:=RtrimEx(ExtractName(param,')'),')');
//debugMSG('результат='+param);
ReturnStack.Clear; //очищаем стек возврата из подпрограмм
ReturnStack.Add('return='+inttostr(strIndex)); //сохраним адрес возврата
ReturnStack.SaveToFile(PathWalkerScript+'return');
debugmsg('return='+inttostr(strIndex));
param:=WalkerLabel.Values[param]; //ищет по строке, номер строки (label=10)
debugMSG('переходим на строку='+param);
strIndex:=strtoint(param); //устанавливаем новую строку для исполнения
debugMSG('strIndex='+inttostr(strIndex));
end;
'RETURN': begin
{безусловный переход на метку}
param:=ReturnStack.Values['return']; //ищет по строке, номер строки (label=10)
debugMSG('переходим на строку='+param);
strIndex:=strtoint(param); //устанавливаем новую строку для исполнения
debugMSG('strIndex='+inttostr(strIndex));
end;
'EXIT': begin
{завершение работы скрипта}
ExecuteTimer.Enabled:=False;
debugMSG('Script stopped!');
exit;
end;
'PAUSE','DELAY': begin
{изменяем паузу между командами}
ExecuteTimer.Interval:=StrToInt(AlltrimEx(param,'( ',')')); //время задержки
end;
'DLGSEL': begin
{находим bypass в HTML по заданной строке}
param:=GetBypass(sHtml, param);
RequestByPassToServer(param); //выбрали пункт меню
debugMSG('результат Bypass='+param);
sHTML:=''; //обнуляем после использования
end;
'NPCDLG', 'NPCSEL': begin
{делаем таргет на NPC с ID в команде
NPCSEL(Marcela[ID=32173])
NPCDLG(Marcela[ID=32173])
}
param:=GetID(param);
debugMSG('результат ID='+param);
Target(GetNpcOID(strtoint(param)));
end;
'USEITEM': begin
{используем предмет с ID
USEITEM(Kamael Village Teleportation Scroll[ID=12753])
}
param:=GetID(param);
debugMSG('результат ID='+param);
// ищем по id,возвращаем OID
UseItem(GetItem(strtoint(param),3,2),0);
end;
'MOVETO': begin
{MOVETO(x,y,z)}
GetXYZ(param);
debugMSG('результат X='+inttostr(x1)+' Y='+inttostr(y1)+' Z='+inttostr(z1));
ExecuteTimer.Enabled:=False;
MoveTimer.Enabled:=True;
MoveBackwardToLocation(x1,y1,z1);
//runSpd:=115;
//MoveTimer.Interval:=1000; //delta(myx, myy, x1, y1)*runSpd div 5000; //время задержки
//debugMSG('результат T='+inttostr(ExecuteTimer.Interval)+' delta='+inttostr(delta(myx, myy, x1, y1)));
//скорость = расстояние / время
//время = расстояние * скорость * коэфф
{
by Xkor
я в боте скорость вычисляю так:
Код:
if Boolean(Running) then speed:=runSpd
else speed:=walkSpd;
r:=speed*d*MovementSpeedMultiplier;
d - время прошедшее после с последнего обновления координат
r - сосбно смещение за это время
формула работает вроде правильно, рассинхронизации координат с сервером практически непроисходит
}
end;
'ITEMCOUNT': begin
//ITEMCOUNT(Название предмета[ID=#],<,1)
//{
//}
//Подсчитывает количество указанных предметов с условиями <, >, = и выполняет скрипт в фигурных скобках.
if not GetItemcount(param) //возвращает Истина, если проверку прошли, инача Ложь
then SkipFS; //пропускаем фигурные скобки
//else inc(strIndex); //пропускаем {
end;
'BUYITEM': begin
{
BuyItem(Название предмета[ID=#],#)
//Покупает предмет
BuyItem(Название предмета[ID=#],#;Название предмета[ID=#],#)
//Покупает за раз более одного предмета (можно указать много предметов через точку с запятой) .
}
RequestBuyItem(param);
end;
'SELLITEM': begin
{
SellItem(Название предмета[ID=#],#)
//Продаёт предмет
SellItem(Название предмета[ID=#],#;Название предмета[ID=#],#)
//Продаёт за раз более одного предмета (можно указать много предметов через точку с запятой) .
}
RequestSellItem(param);
end;
'MSG', 'SAY' : begin
//MSG(Sdajom quest)
SendMessage(param); //шлем сообщение в чат
sendMSG(param); //шлем сообщение в пакетхак
end;
'CHARSTATUS': begin
//CharStatus([CHP|CMP|HP|MP|WEIGHT|LV|SP|RACE|STAND],[>=|>|==|!=|<|<=],число)
//{
//}
{
CHP = Здоровье персонажа
CMP = Мана персонажа
HP = Здоровье (%)
MP = Мана (%)
WEIGHT = Загрузка (%)
LV = Уровень (вожможно)
SP = Хрен знает что такое
RACE = Это еще менее понятно
STAND = Проверка сидишь или стоишь
...,==,0) Сидишь
...,==,1) Стоишь (может быть 0 и 1 надо поменять местами
}
if not GetCharStatus(param) //возвращает Истина, если проверку прошли, инача Ложь
then SkipFS; //пропускаем фигурные скобки
//else inc(strIndex); //пропускаем {
end;

//'{','}' : begin {ничего не делаем} end;

'POSINRANGE': begin
//PosInRange(-124658,79914,-3586,5000)
//{
//}
GetXYZD(param);
debugMSG('результат X='+inttostr(x1)+' Y='+inttostr(y1)+' Z='+inttostr(z1)+' D='+inttostr(delta1));
if not PosInRange(x1,y1,z1,delta1) //возвращает Истина, если проверку прошли, инача Ложь
then SkipFS; //пропускаем фигурные скобки
end;
'POSOUTRANGE': begin
//PosOutRange(-124658,79914,-3586,5000)
//{
//}
GetXYZD(param);
debugMSG('результат X='+inttostr(x1)+' Y='+inttostr(y1)+' Z='+inttostr(z1)+' D='+inttostr(delta1));
if not PosOutRange(x1,y1,z1,delta1) //возвращает Истина, если проверку прошли, инача Ложь
then SkipFS; //пропускаем фигурные скобки
end;
'ENCHANTITEM': begin
{Заточим предмет с ID
USEITEM(Enchant Scroll[ID=729];Enchant Item[ID=80])
}
{возвращает результат не заточки, а того, что вещь, которую надо точить, в рюкзаке была или нет!}
if not RequestEnchantItem(param) //возвращает Истина, если вещь для заточки нашлась, иначе если вещи не нашлось - Ложь
then SkipFS; //пропускаем фигурные скобки

end;
//************************************************** **********************
'CRISTALLIZEITEM': begin
{ разобъем предмет на кристаллы с ID
CrystallizeItem(Name1[Id=XXX],Count)
CrystallizeItem(Name1[Id=XXX],Count;Name2[Id=XXX],Count)
}
RequestCrystallizeItem(param);
end;
//************************************************** **********************
'SET': begin
{
SET (MON, ATTACK|NOATTACK|ATTACKONE, Name [ ID=n ]; Name1 [ ID=n ] |*)
Explained: The establishment attack monster or does not attack the monster
ATTACK// is the attack
NOATTACK// is does not attack
ATTACKONE// is the attack completes the order form

* - всех, кто шевелится =)
}
//SET(MON,ATTACK,Gremlin[ID=20001];Goblin[ID=20003])
{
Set(FightStart|FightStop)
Разрешает или запрещает Режим Боя.
Set(RangeType,DefPos,x,y,z,radii)
Выставляет режим боя по заданной центральной точке, и задает центральную точку
боя по координатам x, y и z, с радиусом указанным в radii.
Set(RangeType,StartPos,radii)
Начинает бой указывая текущую позицию центральной как если бы вы выбрали
"Combat Begin Point is Center Point" с радиусом заданным на месте <radii>.
}
SetupAlexus(param);
end;
end;
inc(strIndex);
result:=1;
ExecuteTimer.Enabled:=true; //включим интерпретацию скрипта валкера
except
debugMsg('Error in OnExecute! Script stopped!');
end;
end;

//управление Ботом - Алексус
procedure SetupAlexus(sData: string);
//SET(MON,ATTACK|NOATTACK|ATTACKONE,Name[ID=n];Name1[ID=n];|*)
//{
//}
//в sData = MON,ATTACK,Name[ID=n],Name1[ID=n]
var
i, j, k, id, x, y, z, radius: integer;
cmd1, cmd2, cmd3, s: string;
eos : boolean;
res:variant;
BaseIdNPCs: array[1..10] of integer; //ID для NPC вокруг

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

begin
debugMsg('SetupAlexus');
for i:=1 to 10 do BaseIdNPCs[i]:=0; //забиваем нулями

s:=sData+','; //чтобы можно было взять число в конце
eos:=false;
cmd1:=RTrimEx(ExtractName(s, ','), ','); //получили строку вплодь до найденного символа
cmd1:=UpperCase(alltrim(cmd1));
sendmsg(cmd1);
case cmd1 of
//RangeType,DefPos,x,y,z,radii,
//Выставляет режим боя по заданной центральной точке, и задает центральную точку
//боя по координатам x, y и z, с радиусом указанным в radii.
//Set(RangeType,StartPos,radii)
//Начинает бой указывая текущую позицию центральной как если бы вы выбрали
//"Combat Begin Point is Center Point" с радиусом заданным на месте <radii>.
'RANGETYPE': begin
s:=ExtractValue(s, ','); //получили остаток строки начиная с искомого символа
cmd2:=RTrimEx(ExtractName(s, ','), ','); //получили строку вплодь до найденного символа
cmd2:=UpperCase(alltrim(cmd2));
sendmsg(cmd2);
case cmd2 of
'STARTPOS': begin
s:=ExtractValue(s, ','); //получили остаток строки начиная с искомого символа
radius:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили строку вплодь до найденного символа
sendmsg(INTTOSTR(RADIUS));
res:=CallSF('Locomotiv-05_wsr', 'setStartPos', ['',radius]);
sendmsg(res);
end;
'DEFPOS': begin
s:=ExtractValue(s, ','); //получили остаток строки начиная с искомого символа
x:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили строку вплодь до найденного символа
sendmsg(INTTOSTR(X));
s:=ExtractValue(s, ','); //получили остаток строки начиная с искомого символа
y:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили строку вплодь до найденного символа
sendmsg(INTTOSTR(Y));
s:=ExtractValue(s, ','); //получили остаток строки начиная с искомого символа
z:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили строку вплодь до найденного символа
sendmsg(INTTOSTR(Z));
s:=ExtractValue(s, ','); //получили остаток строки начиная с искомого символа
radius:=strtoint(RTrimEx(ExtractName(s, ','), ',')); //получили строку вплодь до найденного символа
sendmsg(INTTOSTR(RADIUS));
res:=CallSF('Locomotiv-05_wsr', 'setDefPos', ['',x,y,z,radius]);
sendmsg(res);
end;
end;
end;
'FIGHTSTART': begin
res:=CallSF('Locomotiv-05_wsr', 'setPauseGame', ['']);
sendmsg(res);
end;
'FIGHTSTOP': begin
res:=CallSF('Locomotiv-05_wsr', 'setResumeGame', ['']);
sendmsg(res);
end;
'MON': begin
s:=ExtractValue(s, ','); //получили остаток строки начиная с искомого символа
cmd2:=RTrimEx(ExtractName(s, ','), ','); //получили строку вплодь до найденного символа
cmd2:=UpperCase(alltrim(cmd2));
sendmsg(cmd2);
case cmd2 of
//MON,ATTACK,Name[ID=n];Name1[ID=n],
'ATTACK': begin
j:=1; //кол-во монстров
cmd3:=RTrimEx(ExtractValue(s, ','), ','); //получили остаток строки начиная с искомого символа
cmd3:=UpperCase(alltrim(cmd3));
if cmd3<>'*' then
begin
sendmsg(cmd3);
while not eos do
begin
if s<>'' then
begin
s:=ExtractValue(s,'='); //получили остаток строки начиная с искомого символа
id:=strtoint(RTrimEx(ExtractName(s, ']'), ']')); //получили строку вплодь до найденного символа
//командуем скрипту Locomotiv-05_wsr установить переменную NpcTypeIDxx в величину id
res:=CallSF('Locomotiv-05_wsr', 'setVar', ['NpcTypeID'+inttostr(j), id]);
sendMSG(res);
inc(j);
s:=ExtractValue(s,';'); //получили остаток строки начиная с искомого символа
if i>10 then eos:=true; //не более 10 мобов
end else eos:=true; //сигналим, что закончили поиск
end;
end else
begin //иначе, обработка * - звездочки, отлавливая пакеты NpcInfo в количестве не более 10
sendmsg(cmd3);
j:=1;
for i:=1 to maxnpc do //maxnpc do
begin
sendmsg('i='+inttostr(i)+' id='+inttostr(BaseNPCs[i,2])+' attcbl='+inttostr(BaseNPCs[i,3]));
if (BaseNPCs[i,1]=0) then break; //проверяем, чтоб OID мобов не равнялось 0
//sendmsg('i='+inttostr(i)+' j='+inttostr(j)); //+'BaseNPCs[i,3]='+inttostr(BaseNPCs[i,3]));
if (BaseNPCs[i,3]=1) and (j<=10) then //проверяем, чтоб мобов было не более 10 и были атакуемы
begin
if testpovtor(BaseNPCs[i,2])=0 then
begin
BaseIdNPCs[j]:=BaseNPCs[i,2];
id:=BaseNPCs[i,2];
//командуем скрипту Locomotiv-05_wsr установить переменную NpcTypeIDxx в величину id
sendmsg('NpcTypeID'+inttostr(j)+' id='+inttostr(id));
res:=CallSF('Locomotiv-05_wsr', 'setVar', ['NpcTypeID'+inttostr(j), id]);
sendMSG(res);
//povtor:=true;
inc(j);
end;
end;
end;
end;
end;
//MON,NOATTACK,*,
'NOATTACK': begin
s:=RTrimEx(ExtractName(s, ','), ','); //получили строку вплодь до найденного символа
if s='*' then
begin
for i:=1 to 10 do
begin
//командуем скрипту Locomotiv-05_wsr установить переменную NpcTypeIDxx в величину id
res:=CallSF('Locomotiv-05_wsr', 'setVar', ['NpcTypeID'+inttostr(i), 0]);
sendMSG(res);
end;
end else sendMSG('команда не поддерживается!');
end;
end;
end;
end;
end;

function GetMobID(s : string): string;
var res: variant;
begin
res:=CallSF ('Locomotiv-05_wsr', 'getVar', [s]);
result:=res;
sendMSG('получили MobID='+res);
end;
procedure SetMobID(s: string; i: integer);
var res: variant;
begin
res:=CallSF ('Locomotiv-05_wsr', 'setVar', [s, i]);
sendMSG(res);
end;

procedure UserCommands; //комманды пользователя
var
i: integer;
s, cmd1: string;
begin //если комманда обработана удачно, то в чат сообщение не попадет, а будет выдано системное сообщение прямо в клиент
// if InitMode then
s:=ReadS(2);
s:=s+'='; //чтобы можно было взять число в конце
cmd1:=RTrimEx(ExtractName(s, '='), '='); //получили строку вплодь до найденного символа
cmd1:=UpperCase(alltrim(cmd1));
sendmsg(cmd1);
sendmessage(cmd1);
case cmd1 of
//команда загрузки скрипта script|load=walkerscript
'SCRIPT','LOAD': begin
s:=ExtractValue(s, '='); //получили остаток строки начиная с искомого символа
s:=RTrimEx(ExtractName(s, '='), '='); //получили строку вплодь до найденного символа
sendmsg(s);
sendmessage(s);
WalkerScript.clear;
WalkerScript.LoadFromFile(PathWalkerScript+s+'.sec '); //загружаем скрипт
MakeLabel; //готовим адреса меток из скрипта Валкера
pck:='';
end;
'START','RUN': begin
strIndex:=0; //начинаем с первой строки
ExecuteDelay:=DefaultExecuteDelay; //задержка между командами валкера
ExecuteTimer.Enabled:=true; //включим интерпретацию скрипта валкера
pck:='';
end;
'STOP': begin
CallSF('Locomotiv-05_wsr', 'setStopGame', ['']); //остановим бота
ExecuteTimer.Enabled:=false; //выключим интерпретацию скрипта валкера
pck:='';
end;
'PAUSE': begin
CallSF('Locomotiv-05_wsr', 'setPauseGame', ['']); //остановим бота
ExecuteTimer.Enabled:=false; //выключим интерпретацию скрипта валкера
pck:='';
end;
'RESUME': begin
CallSF('Locomotiv-05_wsr', 'setResumeGame', ['']); //остановим бота
ExecuteTimer.Enabled:=false; //выключим интерпретацию скрипта валкера
pck:='';
end;
end;
end;

//************************************************** ****************************
{
основная часть скрипта, вызывается при приходе каждого пакета, если скрипт включен
}
//************************************************** ****************************
begin
//************************************************** **************************
//не обрабатываем пустые пакеты
if pck='' then exit;

//************************************************** **************************
if (ConnectName=Name) and FromServer then
begin
case pck[1] of
//************************************************** **********************
//07=BuyList
#$11: begin //abyss
//#$07: begin
//debugmsg('S>C $07 BuyList');
BuyList;
end;
//************************************************** **********************
//08=DeleteObject:d(ObjectID)d(0)
#$12: begin //abyss
//#$08: begin
//debugmsg('S>C $08 DeleteObject '+inttostr(ReadD(2)));
DeleteNpc(ReadD(2));
end;
//************************************************** **********************
//0C=NpcInfo:d(ObjectID)d(NpcTypeId:Get.NpcId)d(IsAt tackable)d(X)d(Y)d(Z)
#$16: begin //abyss
//#$0C: begin
//debugmsg('S>C Пакет NpcInfo #$0C'+inttostr(ReadD(2)));
// OID ID
AppendNpc(ReadD(2), ReadD(6)-kID, ReadD(10)); //добавляем в базу данных
end;
//************************************************** **********************
#$1B: begin //abyss
//#$11: begin
//debugmsg('S>C Пакет ItemListPacket #$11');
ItemList;
end;
//************************************************** **********************
//18=StatusUpdate
//#$18: begin
#$0E: begin //abyss
//debugmsg('S>C Пакет StatusUpdate #$18');
StatusUpdate;
end;
//************************************************** **********************
//19 (NpcHtmlMessage)
#$0F: begin //abyss
//#$19: begin
//debugmsg('S>C Пакет NpcHtmlMessage #$19');
sHTML:=ReadS(6);
//sendmsg(sHTML);
end;
//************************************************** **********************
#$27: begin //abyss
//#$21: begin
//debugmsg('S>C Пакет InventoryUpdate #$21');
InventoryUpdate;
end;
//************************************************** **********************
//32=UserInfo
//#$32: begin
#$04: begin //abyss
//debugmsg('S>C Пакет UserInfo #$33');
UserInfo;
end;
end; //case
end;

//************************************************** **************************
if (ConnectName=Name) and FromClient then
begin
case pck[1] of
//************************************************** **********************
#$49: UserCommands; //Say2:s(Text)d(Type)s(Target)
//ValidatePosition пакет от клиента с моими кординатами
//59=ValidatePosition:d(X)d(Y)d(Z)d(Heading)d(Data)
#$59: begin
//debugmsg('C>S Пакет ValidatePosition #$59');
MyX:=ReadD(2); //получаю координату х моего чара
MyY:=ReadD(6); //получаю координату у моего чара
MyZ:=ReadD(10); //получаю координату z моего чара
end;
end; //case
end;
end.
//************************************************** ****************************
{ Changelog.txt }
{
version 0.10 от 30.04.2009г.
[+] Команды управления из чата START|RUN, STOP, PAUSE, RESUME, загрузка скрипта SCRIPT|LOAD=TEST
[+] Добавил управление ботом - Алексус, который пришлось модифицировать для поодержки данного скрипта
[+] Добавил POSOUTRANGE, POSINRANGE
[+] CharStatus([CHP|CMP|HP|MP|WEIGHT|LV|SP|RACE|STAND],[>=|>|==|!=|<|<=],число)
[+] Добавил UserInfo, StatusUpdate
[+] Добавил SET(MON,ATTACK|NOATTACK|ATTACKONE,Name[ID=n];Name1[ID=n];|*), SET(MON,NOATTACK,*)
[+] Добавил SET(RangeType,DefPos,x,y,z,radii), SET(RangeType,StartPos,radii)
мелкие правки кода
вложенные условия
поменял логику применения RequestEnchantItem

version 0.9 от 02.02.2009г.
Поправил ITEMCOUNT

version 0.8 от 02.02.2009г.
[+] Понимает команды:
CrystallizeItem(Name1[Id=XXXX],Count;Name2[Id=XXXX],Count)

version 0.7 от 20.01.2009г.
[+] Понимает команды:
MSG(сообщение),
SELLITEM(Name1[Id=XXXX],Count) или SELLITEM(Name1[Id=XXXX],Count;Name2[Id=XXXX],Count),
DLGSEL(теперь и кнопки жмёт)

version 0.6 от 19.01.2009г.
[+] Понимает команды:
BUYITEM(Name1[Id=XXXX],Count) или BUYITEM(Name1[Id=XXXX],Count;Name2[Id=XXXX],Count)

version 0.5 от 18.01.2009г.
[+] Понимает команды:
PAUSE(время в мс),
ITEMCOUNT(Name[ID=XXXX],==|=>|<=|!=|<>,Count)

version 0.4 от 18.01.2009г.
[+] Понимает команды:
MOVETO(x,y,z),
USEITEM(Name[Id=XXX]),
CALL(метка),
RETURN

version 0.3 от 17.01.2009г.
[+] Понимает команды:
NPCDLG(Name[Id=XXX]),
NPCSEL(Name[Id=XXX])

version 0.2 от 16.01.2009г.
[+] Понимает команды:
DELAY(время в мс),
JMP(метка),
LABEL(имя метки),
EXIT,
DLGSEL(только текст, кнопки не жмёт)
[+] Ведём базу инвентаря
[+] Ведём базу NPCs

version 0.1 от 14.01.2009г.
[!] пока только заготовки:
NPCDLG(Name[Id=XXX]),
NPCSEL(Name[Id=XXX]),
USEITEM(Name[Id=XXX]),
CALL(метка)
}

<<

>>
Const ProgramName =
'Бот - локомотив от Alexus '+
'версия : 0.5.2 (WSR) '+
'дата: 22.01.09';

//by NLObP
//Исправлено для работы совместно со скриптом WalkerScriptRunner
//30.04.2009
{################################################# ############################
Описание:
Бот для соло-кача в принципе любого война. По функциональности (в режиме кача) это еще не Волкер, но скрипт уже довольно умный :)
Охотиться только на заданных мобов.

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

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

История версий:
0.1 - самое начало :)
0.2 - куча глюков, первая рабочая версия!
0.3 - первая стабильная безглючная версия, с минимальной функциональностью (самая стабильная, но очень простая)
0.4 - изменения:
- радиус кача можно задать в секции настройки
- бот теперь сразу видит всю локацию с самого запуска скрипта
- автоопределение размера инвентаря
- ID мобов можно теперь задавать в секции настройки
- ускорен процесс добавление мобов через клиент (теперь их не надо гасить)
- отключена ф-ция автоопределения своего ID и инвентаря, по этому запускать теперь бот надо до запуска клиента
- обновлено окно вывода информации (теперь его нельзя случайно закрыть!)
- на форму добавлены кнопки управления
- добавлена кнопка "Init" в окно управления, теперь бота можно запускать в любом месте, затем нажать эту кнопку
- добавлен механизм глотания баф-банок
- оптимизирован алгоритм выбора ближайшего моба
- скрипт доработан для новых версий пакетхака (данная версия разработана под пакетхак версии 3.4.1.69)
- в режиме кача, при отсутствии мобов в радиусе, бот возвращается в центр кача
- устранена ошибка, связянная с неправильным распознованием пакета 01 - MoveToLocation
0.5 - модификация под РУ-ОФФ Gracia
- добавлен споил
- убрана ошибка, вылезающая после нажатия кнопки Init
- немного подправлен алгоритм работы с инвентарем

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

В процессе кача, в общий чат можно посылать следующие управляющие команды:
pause - пауза, можно приостановить бота, повторная комманда pause запустит бота
stop - срочная остановка бота, и сброс всех настроек, повторный запуск возможен командой start

Также можно управлять ботом одноименными кнопками с формы.
################################################## ###########################}

//################### Сеция настройки бота ############################################
NickName='RemoteAccess'; //имя персонажа в игре
//NickName='NLObP'; //имя персонажа в игре
CharNumber = 0; // если больше одного перса на аккаунте, то задаем его порядковый номер, нумерация начинается с нуля.
Radius_Kacha = 0; // Радиус кача, если 0 - то задавать вручную через клиента (изменять от 100 до 9999). Проверил на практике, что максимум не более 2000.
Spoil = false; // Споил false - откл, true - вкл. (только для гномов-спойлеров)
//-------------------------------------------------------------------------------------
HPLevel = 70; // Уровень жизни в %, при котором начинаем глотать банки
HPBottleID = 0; // ItemID 1060=Lesser Healing Potion; 1061=Healing Potion; 1539=Greater Healing Potion;
DrinkDelay = 14; // минимальное время задержки повторного питься HP-бутылки (10 - 20 сек).
//---------------------------------------------------------------------------------------
Bottle_1_ID = 0; // ID номера баф-банок, 6036=Greater Magic Haste Potion, 6035=Magic Haste Potion, 1374=Greater Haste Potion, 1062=Haste Potion, 734=Haste Potion
Bottle_2_ID = 0; // если 0 - то не использовать. 1375=Greater Swift Attack Potion, 735=Potion of Alacrity
Bottle_Interval = 19; // Время задержки повторного использования бутылей в минутах (изменять от 1 до 100)
//----------------------------------------------------------------------------------------

//############# Секция расширенной настройки для опытных ботоводеров :) ###################################
TimerCombat_Interval = 500; // частота срабатывания таймера атаки в милисекундах, чем меньше это число, тем быстрее бот будет думать.
TimerPickUp_Interval = 500; // частота срабатывания таймера сбора дропа, чем меньше это число, тем быстрее бот будет думать.
TimerForm_Interval = 2500; // частота срабатывания таймера обновления формы, чем меньше это число, тем быстрее будут обновляться данные в форме.
Attack_Time = 45; // Время на убивание моба в секундах.
PickUp_Time = 15; // Врямя на поднятие дропа в секундах.
Vertical = 1000; // Вертикальный радиус кача
//---------------------------------------------------------------------------------------
//################################################## ######################################
NpcTypeID_List_Razmer = 10; // Размер списка мобов (не трогать!)
OX = 1; OY = 2; OZ= 3; // Служебные константы
maximumItems = 500; // Размер базы мобов и дропа.
OblastVidimosti = 500000; // (не трогать!!!) Область видимости объектов (изменять от 1000 до 500000).
InvRazmer = 249; // Размер инвентаря (не трогать)

kID=1000000;

var
NpcTypeID1, // Если знаем, то задаем Type ID мобов, на которых будем охотиться
NpcTypeID2, // Если здесь одни нули, то задавать мобов будем через клиента
NpcTypeID3, // Для интерлюда задаем в формате 102xxxx , где xxxx - ID моба
NpcTypeID4, // Для С4 в формате 100хххх , где xxxx - ID моба
NpcTypeID5, // Для Gracia формат пока не смотрел...
NpcTypeID6,
NpcTypeID7,
NpcTypeID8,
NpcTypeID9,
NpcTypeID10:integer;

InitMode, RestartMode, PickUpMode : boolean;
//-------------------------------------- БД --------------------------------------------------
MobsObjID : array [1..maximumItems] of integer; // ID моба
MobsNpcTypeID : array [1..maximumItems] of integer; // Тип моба
MobsDist : array [1..maximumItems] of integer; // Расстояние от центра кача до моба
MobsXYZ : array [1..maximumItems, 1..3] of integer; // Координаты
MobsIsAttackable : array [1..maximumItems] of boolean; // Можно ли моба атаковать
MobsAgression : array [1..maximumItems] of boolean; // Моб атакует меня или стоит в сторонке...
MobsUpdated : 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)
CurrentInvRazmer : integer;
HPBottleObjID, HPBottleCount : integer; // ObjID и количество HP-бутылей
Bottle_1_ObjID, Bottle_1_Count : integer;
Bottle_2_ObjID, Bottle_2_Count : integer;

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

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

CenterX, CenterY, CenterZ : integer; // Центр кача
CenterFixed : boolean;
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;
btnInit, btnStart, btnStop, btnPause: TButton;
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, textMobsLastIndex, textMobsKilled: TEdit;
textHPBottleCount, textBottle_1_Count, textBottle_2_Count: TEdit;
cbFilterRadius : TCheckBox; l1: Tlabel;
//----------------------------------------------------------
TimerForm, TimerCombat, TimerPickUp, TimerBafBanka, TimerCheckDB : TTimer; // таймеры
time1: integer;
Calculated_AttackTime, Calculated_PickUpTime : integer;
AttackCycle: integer; // Цикл атаки
Spoiled: boolean;

//################################################## ############################################
//поддержка Walkerscriptrunner
function setStartGame(s:string) : variant;
begin
StartGame;
result:='StartGame';
end;
function setStopGame(s:string) : variant;
begin
StopGame;
result:='StopGame';
end;
function setPauseGame(s:string) : variant;
begin
PauseGame;
result:='PauseGame';
end;
function setResumeGame(s:string) : variant;
begin
ResumeGame;
result:='ResumeGame';
end;
function setCenter(x,y,z : integer) : variant;
begin
if (not CenterFixed) and InitMode then
begin
CenterX:= X;
CenterY:= Y;
CenterZ:= Z;
CenterFixed:=true;
SendMsg('Центр кача задан успешно! x='+inttostr(x)+' y='+inttostr(y)+' z='+inttostr(z));
result:='SetCenter';
end;
end;
function setRadius(radius : integer) : variant;
begin
if InitMode then
begin
Radius:= radius;
SendMsg('Радиус кача задан успешно, R = '+ inttostr(Radius));
result:='SetRadius';
end;
end;
function setDefPos(s : string; x,y,z,r : integer) : variant;
begin
if (not CenterFixed) and InitMode then
begin
CenterX:= X;
CenterY:= Y;
CenterZ:= Z;
CenterFixed:=true;
SendMsg('Центр кача задан успешно! x='+inttostr(x)+' y='+inttostr(y)+' z='+inttostr(z));
Radius:= r;
SendMsg('Радиус кача задан успешно, R = '+ inttostr(Radius));
result:='SetDefPos';
end else result:='SetDefPos error';
end;
function setStartPos(s : string; r : integer) : variant;
begin
if (not CenterFixed) and InitMode then
begin
CenterX:= myX;
CenterY:= myY;
CenterZ:= myZ;
CenterFixed:=true;
SendMsg('Центр кача задан успешно! x='+inttostr(myx)+' y='+inttostr(myy)+' z='+inttostr(myz));
Radius:= r;
SendMsg('Радиус кача задан успешно, R = '+ inttostr(Radius));
result:='SetStartPos';
end else result:='SetStartPos error';
end;
//считываем/записываем ID мобов
function getVar (s: string;): variant;
begin
case s of
'NpcTypeID1': Result:=NpcTypeID1; //Записываем ID МОБ'ов
'NpcTypeID2': Result:=NpcTypeID2; //Записываем ID МОБ'ов
'NpcTypeID3': Result:=NpcTypeID3; //Записываем ID МОБ'ов
'NpcTypeID4': Result:=NpcTypeID4; //Записываем ID МОБ'ов
'NpcTypeID5': Result:=NpcTypeID5; //Записываем ID МОБ'ов
'NpcTypeID6': Result:=NpcTypeID6; //Записываем ID МОБ'ов
'NpcTypeID7': Result:=NpcTypeID7; //Записываем ID МОБ'ов
'NpcTypeID8': Result:=NpcTypeID8; //Записываем ID МОБ'ов
'NpcTypeID9': Result:=NpcTypeID9; //Записываем ID МОБ'ов
'NpcTypeID10': Result:=NpcTypeID10; //Записываем ID МОБ'ов
end;
end;
function setVar (s: string; i: integer): variant;
begin
case s of
'NpcTypeID1': NpcTypeID1:=i; //Записываем ID МОБ'ов
'NpcTypeID2': NpcTypeID2:=i; //Записываем ID МОБ'ов
'NpcTypeID3': NpcTypeID3:=i; //Записываем ID МОБ'ов
'NpcTypeID4': NpcTypeID4:=i; //Записываем ID МОБ'ов
'NpcTypeID5': NpcTypeID5:=i; //Записываем ID МОБ'ов
'NpcTypeID6': NpcTypeID6:=i; //Записываем ID МОБ'ов
'NpcTypeID7': NpcTypeID7:=i; //Записываем ID МОБ'ов
'NpcTypeID8': NpcTypeID8:=i; //Записываем ID МОБ'ов
'NpcTypeID9': NpcTypeID9:=i; //Записываем ID МОБ'ов
'NpcTypeID10': NpcTypeID10:=i; //Записываем ID МОБ'ов
end;
ClearDB;
end;

//################################################## ############################################
procedure Init; //Вызывается при включении скрипта
var
i,n : integer;
begin
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;
Bottle_1_ObjID:= 0;
Bottle_1_Count:= 0;
Bottle_2_ObjID:= 0;
Bottle_2_Count:= 0;
InitMode:= true;
RestartMode:= false;
MobsLastIndex:= 0;
for i:=1 to maximumItems do // Очищаем базу
begin
MobsObjID[i]:= 0;
MobsNpcTypeID[i]:=0;
MobsDist[i]:= 0;
MobsXYZ[i, OX]:= 0;
MobsXYZ[i, OY]:= 0;
MobsXYZ[i, OZ]:= 0;
MobsIsAttackable[i]:= false;
MobsAgression[i]:= false;
MobsUpdated[i]:=false;
end;
for i:=0 to InvRazmer do for n:=0 to 9 do Inventory[i, n]:= 0;
CurrentInvRazmer:=0;
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;
TimerBafBanka:=TTimer.Create(nil);
TimerBafBanka.OnTimer:=@OnTimerBafBanka;
TimerBafBanka.enabled:=false;
TimerBafBanka.interval:= 15000;
TimerCheckDB:=TTimer.Create(nil);
TimerCheckDB.OnTimer:=@OnTimerCheckDB;
TimerCheckDB.enabled:=true;
TimerCheckDB.interval:= 20*60*1000; // раз в 20 минут
frmParamIndex:=0; // создаем контролы в форме
frm:= TForm.Create(nil);
frm.Caption:= ProgramName;
frm.BorderStyle := bsDialog;
frm.Position := poScreenCenter;
frm.Width:=650;
frm.Height:=700;
frm.OnClose := @FormClose;
MobsDBscreen:=TMemo.Create(frm);
MobsDBscreen.parent:=frm;
MobsDBscreen.ReadOnly:=true;
MobsDBscreen.ScrollBars:=0;
MobsDBscreen.Top:=157;
MobsDBscreen.Width:=457;
MobsDBscreen.Height:=385;
ItemsDBscreen:=TMemo.Create(frm);
ItemsDBscreen.parent:=frm;
ItemsDBscreen.ReadOnly:=true;
ItemsDBscreen.ScrollBars:=0;
ItemsDBscreen.Top:=1;
ItemsDBscreen.Width:=300;
ItemsDBscreen.Height:=155;
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('Лог...');
btnInit:= TButton.Create(frm);
btnInit.Name := 'btnInit';
btnInit.Parent := frm;
btnInit.SetBounds(370, 10, 75, 25);
btnInit.Caption := 'Init';
btnInit.OnClick := @BtnInit_Click;
btnStart:= TButton.Create(frm);
btnStart.Name := 'btnStart';
btnStart.Parent := frm;
btnStart.SetBounds(370, 40, 75, 25);
btnStart.Caption := 'Start';
btnStart.OnClick := @btnStart_Click;
btnStop:= TButton.Create(frm);
btnStop.Name := 'btnStop';
btnStop.Parent := frm;
btnStop.SetBounds(370, 70, 75, 25);
btnStop.Caption := 'Stop';
btnStop.OnClick := @btnStop_Click;
btnPause:= TButton.Create(frm);
btnPause.Name := 'btnPause';
btnPause.Parent := frm;
btnPause.SetBounds(370, 100, 75, 25);
btnPause.Caption := 'Pause';
btnPause.OnClick := @btnPause_Click;
l1:= TLabel.Create(frm);
l1.caption:='Фильтры:';
l1.parent:=frm;
l1.SetBounds(5, 547, 97, 17);
cbFilterRadius := TCheckBox.Create(frm);
cbFilterRadius.Name := 'cbFilterRadius';
cbFilterRadius.Parent := frm;
cbFilterRadius.SetBounds(60, 545, 97, 17);
cbFilterRadius.Caption := 'Радиус';
// cbFilterRadius.OnClick := @CheckBoxFilterClick;
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('Цикл атаки:');
textMobsLastIndex:= CreateTextBox('MobsLastIndex');
CreateLabel('Мобов в БД:');
textMobsKilled:= CreateTextBox('MobsKilled');
CreateLabel('Убито моб:');
inc(frmParamIndex);
textHPBottleCount:= CreateTextBox('HPBottleCount');
CreateLabel('HP бутылей:');
textBottle_1_Count:= CreateTextBox('Bottle_1_Count');
CreateLabel('Баф-Банки 1:');
textBottle_2_Count:= CreateTextBox('Bottle_2_Count');
CreateLabel('Баф-Банки 2:');
ClearDB;
frm.Show; // выводим форму на экран

buf:= #$14; // принудительно вызываем пакеты инвентаря и userinfo
SendToServerEx(NickName);
//RequestRecordInfo - прийдёт и юзеринфо, и инфа о всех нпц и игроках,
buf:=#$6E;
SendToServerEx(NickName);
end;

procedure btnPause_Click(Sender: TButton);
begin
PauseGame;
end;

procedure btnStop_Click(Sender: TButton);
begin
StopGame;
end;
procedure btnStart_Click(Sender: TButton);
begin
StartGame;
end;
procedure BtnInit_Click(Sender: TButton);
begin
RestartMode:= true;
//buf:= #$57; // авто релогин)
//buf:= #$0F; // принудительно вызываем пакеты инвентаря и userinfo
//RequestRecordInfo - прийдёт и юзеринфо, и инфа о всех нпц и игроках,
buf:=#$6E;
SendToServerEx(NickName);
end;

procedure AddtoNpcTypeID_List (NpcTypeID: integer);
begin
inc(NpcTypeID_List_Count);
NpcTypeID_List[NpcTypeID_List_Count]:= NpcTypeID;
end;

procedure ClearDB; // Очистка БД
var // Надо все занулять, иначе там хрень всякая вылезает или старые данные
i : integer;
begin
ItemsLastIndex:= 0; // Очищаем переменные
TargetID:= 0;
LastKilledMobObjID:= 0;
MobsKilled:= 0;
CenterX:= 0;
CenterY:= 0;
CenterZ:= 0;
CenterFixed:= false;
Radius:= Radius_Kacha;
TimerBafBanka.interval:= 15000;
AttackCycle:= 0;
Spoiled:= false;
NpcTypeID_List_Count:= 0;
if NpcTypeID1 <> 0 then AddtoNpcTypeID_List (NpcTypeID1);
if NpcTypeID2 <> 0 then AddtoNpcTypeID_List (NpcTypeID2);
if NpcTypeID3 <> 0 then AddtoNpcTypeID_List (NpcTypeID3);
if NpcTypeID4 <> 0 then AddtoNpcTypeID_List (NpcTypeID4);
if NpcTypeID5 <> 0 then AddtoNpcTypeID_List (NpcTypeID5);
if NpcTypeID6 <> 0 then AddtoNpcTypeID_List (NpcTypeID6);
if NpcTypeID7 <> 0 then AddtoNpcTypeID_List (NpcTypeID7);
if NpcTypeID8 <> 0 then AddtoNpcTypeID_List (NpcTypeID8);
if NpcTypeID9 <> 0 then AddtoNpcTypeID_List (NpcTypeID9);
if NpcTypeID10<> 0 then AddtoNpcTypeID_List (NpcTypeID10);
if NpcTypeID_List_Count = 0 then
for i:=1 to NpcTypeID_List_Razmer do NpcTypeID_List[i]:= 0;
NpcTypeID_CurrentMob:= 0;
for i:=1 to maximumItems do // Очищаем базу
begin
Items_ObjectID[i]:= 0;
Items_ItemID[i]:= 0;
Items_XYZ[i, OX]:= 0;
Items_XYZ[i, OY]:= 0;
Items_XYZ[i, OZ]:= 0;
end;
btnStop.enabled:=false;
btnPause.enabled:= false;
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
offset:= 76;
CurrentInvRazmer:=ReadH(4);
for i:=0 to InvRazmer do
if i < CurrentInvRazmer then begin
Inventory[i,0]:=ReadH(i*offset+6); // itemType1
Inventory[i,1]:=ReadD(i*offset+8); // ObjectId
Inventory[i,2]:=ReadD(i*offset+12); // ItemID
Inventory[i,3]:=ReadD(i*offset+20); // count
Inventory[i,4]:=ReadH(i*offset+24); // itemType2
Inventory[i,5]:=ReadH(i*offset+26); // CustType1
Inventory[i,6]:=ReadH(i*offset+28); // isEquipped
Inventory[i,7]:=ReadD(i*offset+30); // BodyPart
Inventory[i,8]:=ReadH(i*offset+34); // EnchantLevel
Inventory[i,9]:=ReadH(i*offset+36); // CustType2
end else
for k:=0 to 9 do Inventory[i,k]:=0; // забиваем нулями
end;

procedure InventoryUpdate;
var
i,j,k, offset: integer;
begin
offset:= 82;
for j:=0 to (ReadH(2)-1) do
begin
case pck[j*offset+4] of
#$01: k:=0; // add item, запишет на пустую ячейку
#$02: k:=ReadD(j*offset+8); // mod item
#$03: begin // remove item, обнулит ячейки удаленного предмета
k:=ReadD(j*offset+8);
for i:=0 to InvRazmer do if (Inventory[i,1]=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*offset+6); // itemType1
Inventory[i,1]:=ReadD(j*offset+8); // ObjectId
Inventory[i,2]:=ReadD(j*offset+12); // ItemID
Inventory[i,3]:=ReadD(j*offset+20); // count
Inventory[i,4]:=ReadH(j*offset+24); // itemType2
Inventory[i,5]:=ReadH(j*offset+26); // CustType1
Inventory[i,6]:=ReadH(j*offset+28); // isEquipped
Inventory[i,7]:=ReadD(j*offset+30); // BodyPart
Inventory[i,8]:=ReadH(j*offset+34); // EnchantLevel
Inventory[i,9]:=ReadH(j*offset+36); // CustType2
break;
end;
end;
//sendmsg('--доб/изм OID='+inttostr(Inventory[i,1])+' ID='+inttostr(Inventory[i,2]));
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 CurrentInvRazmer 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); //Использовать предмет с заданным ItemObjID
begin
buf:=#$19;
WriteD(ItemObjID);
WriteD(0);
SendToServerEx(NickName);;
end;
//################################################## ##########################################
function CorrectCoord(Coord: integer): integer;
{коррекция значений координат}
begin
result:=Coord;
if result > 2147483648 then result:=result-4294967296;
end;
//.................................................. ............................

//function rastoyanie(NpcX, NpcY, NpcZ : integer) : longint; // вычисление растояния между 2 точками
function rastoyanie(NpcX, NpcY, NpcZ : cardinal) : cardinal; // вычисление растояния между 2 точками
var
// dx,dy,dz : integer;
// summa : longint;
dx,dy,dz : cardinal;
summa : cardinal;
begin
try
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 + OblastVidimosti; // добавляем коррекцию по вертикали
except
sendmsg('Ошибка вычисления расстояния в rastoyanie');
sendmsg('npcx= '+ inttostr(npcx)+', npcy= '+ inttostr(npcy)+', npcz= '+ inttostr(npcz)+', dx= '+ inttostr(dx)+', dy= '+ inttostr(dy)+', dz= '+ inttostr(dz));
sendmsg('summa= '+ inttostr(summa));
result := OblastVidimosti;
end;
end;

function RastoyanieToMe(NpcX, NpcY : integer) : integer; // вычисление растояния между 2 точками
var
dx,dy, summa : integer;
begin
try
dx:= NpcX-MyX;
dy:= NpcY-MyY;
summa:= dx*dx+dy*dy; // мне кажется, что так будет быстрее считаться
if summa = 0 then result:= 0 else result:= Round(sqrt(summa)); // обход возможной ошибки, если моб стоит прямо в центре кача
except
sendmsg('Ошибка вычисления расстояния в RastoyanieToMe');
sendmsg('npcx= '+ inttostr(npcx)+', npcy= '+ inttostr(npcy)+', myx= '+ inttostr(myx)+', myy= '+ inttostr(myy));
sendmsg('summa= '+ inttostr(summa));
result := OblastVidimosti;
end;
end;

procedure AddDroppedItem (ObjID, ItemID, X, Y, Z: integer); // Процедура добавляет дропнутую вещь в БД
begin
if ItemsLastIndex = maximumItems then ItemsLastIndex:=0; // обход переполнения базы предметов
inc (ItemsLastIndex);
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, TypeID, x,y,z : integer; IsAttackable : boolean); // Процедура добавляет в БД нового моба
var
dist: integer;
begin
if (not initmode) then dist:= rastoyanie (x,y,z) else dist := OblastVidimosti; // вычиляем расстояние от центра кача до моба
if dist > (OblastVidimosti) then exit; // если моб слишко далеко то ничего не делаем
inc (MobsLastIndex); // увеличиваем размер БД
// log.Lines.Add('Моб добавлен, индекс в БД:'+ inttostr(MobsLastIndex));
// if agression then log.Lines.Add('На нас напала какая-то вражина.');
MobsObjID[MobsLastIndex]:= id; // Записываем моба
MobsNpcTypeID[MobsLastIndex]:= TypeID;
MobsDist[MobsLastIndex]:= dist;
MobsXYZ[MobsLastIndex, OX]:= x;
MobsXYZ[MobsLastIndex, OY]:= y;
MobsXYZ[MobsLastIndex, OZ]:= z;
MobsIsAttackable[MobsLastIndex]:= IsAttackable;
MobsAgression[MobsLastIndex]:= false;
MobsUpdated[MobsLastIndex]:= true;
end;

procedure UpdateDB (i, x,y,z : integer; agression : boolean); // Процедура обновляет данные в БД по мобу
var
dist: integer;
begin
if (not initmode) then dist:= rastoyanie (x,y,z) else dist := OblastVidimosti;
if dist > (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;
if (not MobsAgression[i]) then MobsAgression[i]:= agression;
MobsUpdated[i]:= true;
end;
end;

procedure DelDBItem (i: integer); // процедура удалаяет моба из БД
begin
// log.Lines.Add('Моб удален, индекс в БД: '+ inttostr(i));
MobsObjID[i]:= 0;
MobsNpcTypeID[i]:= 0;
MobsDist[i]:= 0;
MobsXYZ[i, OX]:= 0;
MobsXYZ[i, OY]:= 0;
MobsXYZ[i, OZ]:= 0;
MobsAgression[i]:= false;
MobsIsAttackable[i]:= false;
MobsUpdated[i]:= false;
if i < MobsLastIndex then // если надо, производим сдвиг данных в массивах
begin
MobsObjID[i]:= MobsObjID[MobsLastIndex];
MobsNpcTypeID[i]:= MobsNpcTypeID[MobsLastIndex];
MobsDist[i]:= MobsDist[MobsLastIndex];
MobsXYZ[i, OX]:= MobsXYZ[MobsLastIndex, OX];
MobsXYZ[i, OY]:= MobsXYZ[MobsLastIndex, OY];
MobsXYZ[i, OZ]:= MobsXYZ[MobsLastIndex, OZ];
MobsIsAttackable[i]:= MobsIsAttackable[MobsLastIndex];
MobsAgression[i]:= MobsAgression[MobsLastIndex];
MobsUpdated[i]:= MobsUpdated[MobsLastIndex];
end;
dec (MobsLastIndex); // уменьшаем размер БД
end;

procedure DelDroppedItem (i: 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
begin
Items_ObjectID[i]:= Items_ObjectID[ItemsLastIndex];
Items_ItemID[i] := Items_ItemID[ItemsLastIndex];
Items_XYZ[i, OX]:= Items_XYZ[ItemsLastIndex, OX];
Items_XYZ[i, OY]:= Items_XYZ[ItemsLastIndex, OY];
Items_XYZ[i, OZ]:= Items_XYZ[ItemsLastIndex, 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 MobsObjID[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_to_CL(msg:string); // отправка системных сообщений клиенту
begin
buf:=#$4A;
WriteD(0);
WriteD(10);
WriteS('');
WriteS(msg);
SendToClientEx(NickName);
end;

procedure OnTimerCheckDB (Sender: TObject);
var
i: integer;
begin
i:=0;
while i <= MobsLastIndex do
begin
inc(i);
if MobsUpdated[i] then MobsUpdated[i]:=false
else
begin
DelDBItem(i);
dec(i);
end;
end;
end;

procedure PrepareDB;
var
i: integer;
//dist : double;
begin
i:=0;
while i <= MobsLastIndex do
begin
inc(i);
if InMobsList(MobsNpcTypeID[i]) then MobsIsAttackable[i]:= true;
MobsDist[i] := rastoyanie (MobsXYZ[i, OX], MobsXYZ[i, OY], MobsXYZ[i, OZ]);
//if MobsDist[i] >= OblastVidimosti then
//begin
// DelDBItem(i);
// dec(i);
//end;
end;
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
PrepareDB;
SendMsg_to_CL('Все начальные параметры заданы и проверены!');
log.Lines.Add('Все начальные параметры заданы и проверены!');
result:= true;
end
else
begin
SendMsg_to_CL('Ошибка задания начальных параметров!');
log.Lines.Add('Ошибка задания начальных параметров!');
result:= false;
end;
end;

procedure UserCommands; // комманды пользователя
var
i: integer;
begin // если комманда обработана удачно, то в чат сообщение не попадет, а будет выдано системное сообщение прямо в клиент

exit; // нам не надо обрабатывать при работе совместно с WalkerScriptRunner

if InitMode then case (ReadS(2)) of
'pos' : if MyX <> 0 then // центр кача
begin
CenterX:= MyX;
CenterY:= MyY;
CenterZ:= MyZ;
CenterFixed:= true;
SendMsg_to_CL('Центр кача задан успешно!');
log.Lines.Add('Центр кача задан успешно!');
pck:='';
end;
'dist' : if (CenterX <> 0) and (MyX <> 0) then // радиус кача
begin
CenterFixed:= true;
Radius:= rastoyanie (MyX,MyY,MyZ);
SendMsg_to_CL('Радиус кача задан успешно');
SendMsg_to_CL('R= '+ inttostr(Radius));
log.Lines.Add('Радиус кача задан успешно, R = '+ inttostr(Radius));
pck:='';
end;
'reset': begin // сброс параметров
ClearDB;
SendMsg_to_CL('БД очищена, введите заново все параметры');
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_to_CL('Добавлять мобов можно тока по очереди 1, 2, 3...');
pck:='';
exit;
end;
NpcTypeID_CurrentMob:= strtoint(ReadS(2));
SendMsg_to_CL('Добавляем моба № '+ ReadS(2));
pck:='';
i:= TestPovtor (TargetID);
if i > 0 then
begin
NpcTypeID_List[NpcTypeID_CurrentMob]:= MobsNpcTypeID[i];
SendMsg_to_CL('Моб №' + inttostr(NpcTypeID_CurrentMob) + 'тип: '+inttostr(MobsNpcTypeID[i])+' добавлен в базу');
log.Lines.Add('Моб №' + inttostr(NpcTypeID_CurrentMob) + 'тип: '+inttostr(MobsNpcTypeID[i])+' добавлен в базу');
inc(NpcTypeID_List_Count);
NpcTypeID_CurrentMob:= 0;
TargetID:= 0;
end;
end;
'start': begin // собственно запуск бота
pck:='';
StartGame;
end;
end;
if (not InitMode) then case (ReadS(2)) of
'pause' : begin
pck:='';
PauseGame;
end;
'stop' : begin
pck:='';
StopGame;
end;
end;
end;
{
procedure PauseGame;
begin
TimerCombat.enabled:= not(TimerCombat.enabled);
TimerBafBanka.enabled:= not(TimerBafBanka.enabled);
if TimerCombat.enabled then
begin
btnPause.Caption:='Pause';
TimerBafBanka.interval:= 15000;
SendMsg('Искуственный интеллект запущен!');
SendMsg_to_CL('Искуственный интеллект запущен!');
log.Lines.Add('Искуственный интеллект запущен!');
end
else
begin
btnPause.Caption:='Repeat';
SendMsg('Искуственный интеллект приостановлен.');
SendMsg_to_CL('Искуственный интеллект приостановлен.');
log.Lines.Add('Искуственный интеллект приостановлен.');
MoveTo(centerX,centerY,centerZ);
end;
end;
}
procedure PauseGame;
begin
TimerCombat.enabled:= false;
TimerBafBanka.enabled:= false;
btnPause.Caption:='Repeat';
SendMsg('Искуственный интеллект приостановлен.');
SendMsg_to_CL('Искуственный интеллект приостановлен.');
log.Lines.Add('Искуственный интеллект приостановлен.');
//MoveTo(centerX,centerY,centerZ);
end;

procedure ResumeGame;
begin
TimerCombat.enabled:= true;
TimerBafBanka.enabled:= true;
btnPause.Caption:='Pause';
TimerBafBanka.interval:= 15000;
SendMsg('Искуственный интеллект запущен!');
SendMsg_to_CL('Искуственный интеллект запущен!');
log.Lines.Add('Искуственный интеллект запущен!');
end;

procedure StartGame;
begin
if ValidateData and InitMode then
begin
CenterFixed:= true;
SendMsg('ЗАПУСКАЕМ ИСКУСТВЕННЫЙ ИНТЕЛЛЕКТ!');
SendMsg_to_CL('ЗАПУСКАЕМ ИСКУСТВЕННЫЙ ИНТЕЛЛЕКТ!');
log.Lines.Add('ЗАПУСКАЕМ ИСКУСТВЕННЫЙ ИНТЕЛЛЕКТ!');
TargetID:=0;
InitMode:= false;
TimerCombat.enabled:=true; // запускаем таймер
TimerBafBanka.interval:= 15000;
TimerBafBanka.enabled:= true;
btnStart.enabled:= false;
btnStop.enabled:= true;
btnPause.enabled:= true;
end
else
begin
SendMsg('Еще не все параметры заданы. Проверьте параметры...');
SendMsg_to_CL('Еще не все параметры заданы. Проверьте параметры...');
log.Lines.Add('Еще не все параметры заданы. Проверьте параметры...');
end;
end;

procedure StopGame; // остановка кача
begin
TimerCombat.enabled:= false;
InitMode:= true;
TimerPickUp.enabled:=false;
TimerBafBanka.enabled:=false;
TargetID:= 0;
ClearDB;
SendMsg('Искуственный интелект остановлен.');
SendMsg_to_CL('Искуственный интелект остановлен.');
log.Lines.Add('Искуственный интелект остановлен.');
btnStart.enabled:= true;
btnStop.enabled:= false;
btnPause.Caption:= 'Pause';
btnPause.enabled:=false;
end;

function GetMinDistID : integer; // функция поиска ближайшего моба в БД
var
i, Dist, MinDist : integer;
begin
result:= 0;
if MobsLastIndex = 0 then exit;
MinDist:=RastoyanieToMe(MobsXYZ[1,OX], MobsXYZ[1,OY]);
for i:=1 to MobsLastIndex do if (MobsDist[i] <= Radius) and (MobsIsAttackable[i]) then
begin
Dist:= RastoyanieToMe(MobsXYZ[i,OX], MobsXYZ[i,OY]);
if Dist <= MinDist then
begin
// Dist:= MinDist;
MinDist:= Dist;
result:= i;
end; // если нашли хоть одного моба или несколько, товозращаем индекс ближайшего
end;
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:=#$1F; //action
WriteD(TargetID);
WriteD(MyX);
WriteD(MyY);
WriteD(MyZ);
WriteC(0);
SendToServerEx(NickName);
end;
procedure RequestMagicSkillUse (SkillID: integer); // маг атака
begin
buf:=#$39;
WriteD(SkillID);
WriteD(0);
WriteC(0);
SendToServerEx(NickName);
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 OnTimerBafBanka (Sender: TObject); // таймер питья баф-банок
begin
if (Bottle_1_Count > 0) and (Bottle_1_ObjID > 0) then
begin
UseItemObjID(Bottle_1_ObjID);
dec (Bottle_1_Count);
end;
if (Bottle_2_Count > 0) and (Bottle_2_ObjID > 0) then
begin
UseItemObjID(Bottle_2_ObjID);
dec (Bottle_2_Count);
end;
TimerBafBanka.interval:= Bottle_Interval*60*1000;
end;

procedure OnTimerPickUp (Sender: TObject); // таймер поднятия дропа
var
povtor: integer;
begin
if (AgroTest > 0) then
begin
TargetID:= 0;
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, i: integer;
begin
if TargetID > 0 then // если в прицеле есть моб, то
begin // валим вражину
if ((AttackCycle mod 5) = 0) then
begin
if Spoil and (not Spoiled) then RequestMagicSkillUse(254) // заспойлим моба если опция включена
else PhisicalAttack;
end;
inc(AttackCycle);
if AttackCycle > Calculated_AttackTime then // если валим моба больше минуты, значит это баг...
begin
i:= TestPovtor(TargetID);
if i > 0 then
begin
MobsIsAttackable[i]:= false; //DelDBItem(i);
MobsAgression[i]:= false;
end;
TargetID:= 0;
end;
exit;
end;
Agro:= AgroTest;
if Agro > 0 then // если нас кто-то атакует, то его и выбираем
begin
TargetID:= MobsObjID[Agro];
PhisicalAttack; // берем вражину в таргет
AttackCycle:= 0;
exit;
end;
if ItemsLastIndex > 0 then // если чего-то валяется на земле, то
begin
InitPickUpMode(true); // надо дроп подбирать
exit;
end;
MinDistID:= GetMinDistID; // запускаем алгоритм выбора цели
if MinDistID > 0 then // иначе ищем ближайшего
begin
TargetID:= MobsObjID[MinDistID];
PhisicalAttack; // берем вражину в таргет
AttackCycle:= 0;
exit;
end;
if (abs(MyX-CenterX) > 20) and (abs(MyY-CenterY) > 20) then MoveTo (CenterX, CenterY, CenterZ);
end;

procedure MoveTo(TargetX,TargetY,TargetZ:integer); //Идти в точку с координатами x,y,z
begin
buf:=#$0F; //01=MoveBackwardToLocation:d(targetX)d(targetY)d(ta rgetZ)d(originX)d(originY)d(originZ)d(moveByMouse)
WriteD(targetx); //куда
WriteD(targety);
WriteD(targetz);
WriteD(MyX); //откуда
WriteD(MyY);
WriteD(MyZ);
WriteD(1); //используем 1-мышь 0-клавиатура
SendToServerEx(NickName);
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);
textMobsLastIndex.text:= inttostr(MobsLastIndex);
textMobsKilled.text:= inttostr(MobsKilled);
textHPBottleCount.text:= inttostr(HPBottleCount);
textBottle_1_Count.text:= inttostr(Bottle_1_Count);
textBottle_2_Count.text:= inttostr(Bottle_2_Count);

MobsDBscreen.lines.Clear;
for i:=1 to MobsLastIndex do // выводим БД мобов
begin
if (TargetID = MobsObjID[i]) and MobsAgression[i] then
begin
MobsDBscreen.lines.add ('<> '+inttostr(i)+' МобID: '+inttostr(MobsObjID[i])+' ТипID: '+inttostr(MobsNpcTypeID[i])+' дистанция '+inttostr(MobsDist[i]));
continue;
end;
if TargetID = MobsObjID[i] then
begin
MobsDBscreen.lines.add ('-> '+inttostr(i)+' МобID: '+inttostr(MobsObjID[i])+' ТипID: '+inttostr(MobsNpcTypeID[i])+' дистанция '+inttostr(MobsDist[i]));
continue;
end;
if cbFilterRadius.checked then if MobsDist[i] <= Radius then
begin
MobsDBscreen.lines.add ('-- '+inttostr(i)+' МобID: '+inttostr(MobsObjID[i])+' ТипID: '+inttostr(MobsNpcTypeID[i])+' дистанция '+inttostr(MobsDist[i]));
continue;
end;
if MobsAgression[i] then
begin
MobsDBscreen.lines.add ('<- '+inttostr(i)+' МобID: '+inttostr(MobsObjID[i])+' ТипID: '+inttostr(MobsNpcTypeID[i])+' дистанция '+inttostr(MobsDist[i]));
continue;
end;
if (not cbFilterRadius.checked) then MobsDBscreen.lines.add ('-- '+inttostr(i)+' МобID: '+inttostr(MobsObjID[i])+' ТипID: '+inttostr(MobsNpcTypeID[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]));
if MobsLastIndex = 0 then MobsDBscreen.lines.add ('Мобы');
if ItemsLastIndex= 0 then ItemsDBscreen.lines.add('Дроп');
end;

procedure FormClose(Sender: TObject; var Action: TCloseAction);
begin
//Action:=caNone;
end;

procedure CreateLabel (text: string); // процедура автоматизирует создание текстовых меток в форме
var
l: TLabel;
begin
l:= TLabel.Create(panel);
l.caption:=text;
l.parent:=panel;
l.left:=10;
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:=80;
e.top:=10+20*frmParamIndex;
e.width:= 95;
e.ReadOnly:=true;
result:= e;
end;

procedure Free; //Вызывается при выключении скрипта
begin
ClearDB;
TimerForm.free;
TimerCombat.free;
TimerPickUp.free;
TimerBafBanka.free;
TimerCheckDB.free;
MobsDBscreen.free;
ItemsDBscreen.free;
log.free;
frm.free;
end;

procedure UserInfo; //обновление данных о себе
var
i:word;
begin
if InitMode then MyID:=ReadD(18);
MyX:=ReadD(2);
MyY:=ReadD(6);
MyZ:=ReadD(10);
i:=22;
ReadS(i);
i:=i+48;
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)*HPLevel);
end;

procedure DrinkBottle; //пъем бутылки и следим за их количеством
begin
if (HPBottleCount > 0) and (HPBottleObjID > 0)then
begin
UseItemObjID(HPBottleObjID);
dec (HPBottleCount);
end;
end;

procedure MoveToLocation01;
var
i: integer;
begin
i:= TestPovtor(ReadD(2));
if i > 0 then updateDB(i, ReadD(06), ReadD(10), ReadD(14), false);
end;

procedure NpcInfo16;
var
i: integer;
begin
i:= TestPovtor(ReadD(2));
if i = 0 then AddtoDB (ReadD(2), ReadD(6)-kID, ReadD(14), ReadD(18), ReadD(22), InMobsList(ReadD(6)-kID))
else UpdateDB(i, ReadD(14), ReadD(18), ReadD(22), false);
end;

procedure Attack05;
var
i: integer;
begin
i:= TestPovtor(ReadD(2));
if i = 0 then log.Lines.Add('Глюк, моб не найден, или нас утакует другой игрок!!!')
else UpdateDB(i, ReadD(15), ReadD(19), ReadD(23), true);
end;

procedure Die06;
var
i: integer;
begin
i:= TestPovtor(ReadD(2));
if i > 0 then begin
MobsIsAttackable[i]:= false;
MobsAgression[i]:= false;
if MobsObjID[i] = TargetID then
begin
TimerCombat.enabled:= false;
if Spoil and Spoiled then
if ReadD(22) = 1 then RequestMagicSkillUse(42);
LastKilledMobObjID:=TargetID;
inc (MobsKilled); // подводим статистику
Spoiled:= false;
TargetID:= 0;
TimerCombat.enabled:= true;
end;
end;
end;

procedure DeleteObject12;
var
i: integer;
begin
if LastKilledMobObjID = ReadD(2) then
begin
LastKilledMobObjID:= 0;
i:= TestPovtor(ReadD(2));
if i > 0 then DelDBItem(i);
exit;
end;
i:= CheckItems(ReadD(2));
if i > 0 then
begin
if Items_ObjectID[i] = TargetID then TargetID:= 0;
DelDroppedItem(i);
exit;
end;
i:= TestPovtor(ReadD(2));
if i > 0 then
begin
if TargetID = ReadD(2) then TargetID:= 0;
DelDBItem(i);
exit;
end;
end;

begin
if pck = '' then exit;
if (ConnectName = NickName) and FromServer then //разбор пакетов от сервера
case pck[1] of
#$01: MoveToLocation01; //MoveToLocation:h(ObjectID)d(CurX)d(CurY)d(CurZ)d(D estX)d(DestY)d(DestZ)
//#$2F: MoveToLocation01; //MoveToLocation:h(ObjectID)d(CurX)d(CurY)d(CurZ)d(D estX)d(DestY)d(DestZ)
// #$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()
// #$32: 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;
btnInit.enabled:= false;
if MyHP = 0 then //Проверка не убили ли нас...
begin
SendMsg_to_CL('Нас убили...');
log.Lines.Add('Нас убили...');
StopGame;
end;
end;
#$05: if (ReadD(6) = MyID) and (not InitMode) then Attack05; //05= Attack:d(AttackerID)d(TargetID)d(Damage)b(Flags)d( X)d(Y)d(Z)h(Hits)
//#$33: if (ReadD(6) = MyID) and (not InitMode) then Attack05; //05= Attack:d(AttackerID)d(TargetID)d(Damage)b(Flags)d( X)d(Y)d(Z)h(Hits)
#$48: begin; //48= MagicSkillUse:h(CharID)h(targetID)d(skillID)d(skil lLvl)d(hitTime)d(reuseDelay)d(X)d(Y)d(Z)w(count)d( d)d(d)d(d)
if (ReadD(2) = MyID) and (ReadD (6) = TargetID) and (ReadD(10) = 254) then Spoiled:= true;
end;
#$06: Die06; //Die:d(ChaID)
//#$00: Die06; //Die:d(ChaID)
#$0C: if LastKilledMobObjID = ReadD(2) then //DropItem:h(PlayerID)h(ObjectID)i(ItemID)d(X)d(Y)d( Z)d(Stackable)d(Count)
//#$16: 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)
//#$17: 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)
//#$18: 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_to_CL('Нас убили...');
log.Lines.Add('Нас убили...');
StopGame;
end;
end;
#$12: DeleteObject12; //DeleteObject:h(ObjectID)
//#$08: DeleteObject12; //DeleteObject:h(ObjectID)
//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)
#$16: if (ReadD(10)=1) and (pck[121]=#$00) then NpcInfo16;
//#$0C: if (ReadD(10)=1) and (pck[121]=#$00) then NpcInfo16;
#$1B: begin
//#$11: begin
InventoryCreate; //Инвентарь
if HPBottleID <> 0 then
begin
HPBottleObjID:= getinv(HPBottleID, 2,1);
HPBottleCount:= getinv(HPBottleID, 2,3);
end;
if Bottle_1_ID <> 0 then
begin
Bottle_1_ObjID:=getinv(Bottle_1_ID, 2,1);
Bottle_1_Count:=getinv(Bottle_1_ID, 2,3);
end;
if Bottle_2_ID <> 0 then
begin
Bottle_2_ObjID:=getinv(Bottle_2_ID, 2,1);
Bottle_2_Count:=getinv(Bottle_2_ID, 2,3);
end;
end;
#$27: begin
//#$21: begin
InventoryUpdate;
if HPBottleID <> 0 then
begin
HPBottleObjID:= getinv(HPBottleID, 2,1);
HPBottleCount:= getinv(HPBottleID, 2,3);
end;
if Bottle_1_ID <> 0 then
begin
Bottle_1_ObjID:=getinv(Bottle_1_ID, 2,1);
Bottle_1_Count:=getinv(Bottle_1_ID, 2,3);
end;
if Bottle_2_ID <> 0 then
begin
Bottle_2_ObjID:=getinv(Bottle_2_ID, 2,1);
Bottle_2_Count:=getinv(Bottle_2_ID, 2,3);
end;
end;
#$13: if RestartMode then //CharacterSelectionInfo
//#$09: if RestartMode then //CharacterSelectionInfo
begin
buf:=#$12; //CharacterSelected
WriteD(CharNumber);
buf:= buf + hstr('00 00 00 00 00 00 00 00 00 00 00 00 00 00');
SendToServerEx(NickName);
RestartMode:= false;
end;
end;

if (ConnectName = NickName) and FromClient then //разбор пакетов от клиента
case pck[1] of
#$1F: if InitMode then TargetID:= ReadD(2); //Action:h(ObjectID)d(OriginX)d(OriginY)d(OriginZ)b( ActionID)
#$49: UserCommands; //Say2:s(Text)d(Type)s(Target)
#$59: begin //ValidatePosition:d(X)d(Y)d(Z)d(Heading)d(Data)
MyX:= ReadD(2);
MyY:= ReadD(6);
MyZ:= ReadD(10);
if (not CenterFixed) and InitMode then
begin
CenterX:= MyX;
CenterY:= MyY;
CenterZ:= MyZ;
end;
end;
end;
end.
<<

В папке ./scripts/walkerscript/ должен лежать файл, загружаемый по умолчанию
MSG(Скрипт загружаемый по умолчанию, задает атаковать всех, в радиусе 2000)
DELAY(5000)
SET(MON,ATTACK,*)
SET(RangeType,StartPos,2000)
SET(FIGHTSTART)
EXIT()

также там должны лежать все остальные скрипты для валкера, которые грузим по LOAD=имя_скрипта_без_расширения

Настраиваем скрипты, как обычно (Name:='имя чара'; ).
Запускаем сначала локомотив (панель можно закрыть), затем эмулятор.
В чате пишем load=test - загружаем файл TEST.SEC, start - начнется исполнение загруженного файла, stop - остановим выполнение загруженного файла.

NLObP
04.06.2009, 13:23
Работа над скриптом ведется =)

version 0.11 от 03.06.2009г.
[+] Понимает команды:
LoadItem(ITEMNAME[ID=#],#)
SaveItem(ITEMNAME[ID=#],#)
[+] Ведём базу хранилища
Подправил GetBypass, теперь можно писать в команде DLGSEL(), только начало строки.
Подправил команду DLGSEL() для того, чтобы она ждала пока чар не подбежит на достаточное расстояние к НПЦ


NPCSEL(Taurin[ID=30086])
DELAY(1000)
NPCDLG(Taurin[ID=30086])
DELAY(1000)
DLGSEL(Private Warehouse.)
DELAY(1000)
DLGSEL(Deposit an item. (Private Warehouse))
DELAY(1000)
SAVEITEM(Adena[ID=57],40;Материя Карнавальной Маски [ID=6904],4;Божественный Клинок [ID=82],1)
DELAY(1000)
MSG(кончилось всё)
EXIT()


NPCSEL(Taurin[ID=30086])
DELAY(1000)
NPCDLG(Taurin[ID=30086])
DELAY(1000)
DLGSEL(Private Warehouse.)
DELAY(1000)
DLGSEL(Withdraw an item. (Private Warehouse))
DELAY(1000)
LOADITEM(Adena[ID=57],40;Материя Карнавальной Маски [ID=6904],4;Божественный Клинок [ID=82],1)
DELAY(1000)
MSG(кончилось всё)
EXIT()

DpblH
15.12.2009, 20:06
везде кричу о помощи:) никто непомогает:(
NLObP, работет ли твой скрипт под НБ и работает ли в нём RequestJoinParty?

NLObP
15.12.2009, 21:48
работет ли твой скрипт под НБ и работает ли в нём RequestJoinParty?

Скрипт для Грации.
Нет, такую команду пока ещё не понимает.

DpblH
16.12.2009, 05:01
NLObP, с помощью чего можно осуществить автономное пати на прокачку одного чара. еси неошибаюсь в валкере 10.9.1 нету RequestJoinParty. рас через валкер неполучаеться, пробую валкер+пнх. но т.к. в делпфи полный нуль, то и рыпаться в нужном направлении неполучаеться

NLObP
16.12.2009, 21:31
DpblH, время свободное будет - добавлю.

DpblH
17.12.2009, 03:59
ок. пасиб я всё равно буду пытаться разобраться. придёться серьёзна почитать делпфи т.к. хотелось бы подсесть на пнх

NLObP
17.12.2009, 23:11
DpblH, если сможешь кинь лог пакетов, чтобы там были пакеты RequestJoinParty.

DpblH
18.12.2009, 03:27
42 41 00 75 00 73 00 74 00 72 00 61 00 6C 00 6F 00 70 00 69 00 74 00 68 00 65 00 63 00 75 00 73 00 00 00 00 00 00 00

mikolasan
13.03.2010, 16:37
А что именно нужно изменять чтобы эмулятор работал на Intelude?
Причем нужны только использование скилов, передвижение и диалоги с нпц

QaK
13.03.2010, 20:21
mikolasan, идшники, и, возможно, разбор некоторых пакетов.

Liiion911
13.03.2010, 20:52
я не заметил, работает ли USESKILL ??
Если еще не сделал прошу в ближайшее время, без него туговато

ЗЫ. валкер неразу не использовал но понял что там писать скрипты сможет даже ребенок ))):D

QaK
13.03.2010, 21:59
Liiion911, нет, нету, в ближайшее время - только за убитых енотов ...

Liiion911
13.03.2010, 22:16
Я уже почти сам дописал, осталось както придумать чтобы проверка на NPC|SELF|PET и прочее влияла. атакующие скилы уже пашут у меня на мобов, а как быть с нпц и бафами разными особенно СЕЛФ и на ПЕТ скилы ;)
Жду процедуру )))

QaK
14.03.2010, 11:56
Liiion911, ну бык база НПЦ ведется, запоминаешь свой ОбджектИД, вот уже НПЦ/СЕЛФ проверка, а на петов, я не помню ... там по-моему по НПЦ ИД как-то можно вычислить, пет это или что ...

mikolasan
14.03.2010, 12:52
Я переправил все пакеты, но вот только одна проблема: не выделяет НПЦ, а следовательно не выполняет диалоги.

Я так понял "идшники" - это id NPC?

QaK
14.03.2010, 14:51
Я так понял "идшники" - это id NPC?в каком контексте?

mikolasan
15.03.2010, 12:27
В контексте id NPC в базе данных сервера. Вообще уже не важно, я разобрался - проблема была в том, что сервер Intelude а id NPC были взяты с Gracia. Жму автору спасибку! :)

mikolasan
18.03.2010, 03:58
Еще одна проблема: когда начинаешь выполнять скрипт квеста - первые 2 НПЦ не выделяются, приходиться помогать руками, но выбор пунктов меню происходит и персонаж передвигается по точкам. Такое чувство, что ему нужно показать как это делать, а потом он сам :unknw:. При зацикленном квесте второй и последующие циклы полностью выполняются без каких либо вмешательств пользователя.

balshoy
06.02.2011, 18:25
Еще одна проблема: когда начинаешь выполнять скрипт квеста - первые 2 НПЦ не выделяются, приходиться помогать руками, но выбор пунктов меню происходит и персонаж передвигается по точкам. Такое чувство, что ему нужно показать как это делать, а потом он сам :unknw:. При зацикленном квесте второй и последующие циклы полностью выполняются без каких либо вмешательств пользователя.

базе их просто еще нету. NocInfo не приходило, вот бот и не знает че за ObjId у этих нпц

kostaz
20.10.2011, 07:00
объясни как твоему скрипту дать команду запустить скрипт walker'a

NLObP
21.10.2011, 00:28
объясни как твоему скрипту дать команду запустить скрипт walker'a

Вот команды в чате для управления.

version 0.10 от 30.04.2009г.
[+] Команды управления из чата START|RUN, STOP, PAUSE, RESUME, загрузка скрипта SCRIPT|LOAD=TEST

START или RUN - запускает скрипт валкера;
STOP - останавливает;
LOAD=имя_скрипта_валкера - загружаем скрипт в память
SCRIPT=имя_скрипта_валкера - то-же самое, загружаем скрипт в память

NooBko
27.09.2012, 22:11
Привет у меня пару вопросов.
вопрос 1)если у меня на сервере все id предметов, скилов нпц переписаны и не совпадает с тем что в пакет хаке мне их нада самому добавлять?
2)ваш скрипт работает но есть одно но он не использует указанную вещь и не атакует указаного нпц, мобов не пробовал, мне нада атаковать нпц. нпц атакуется без контрла.
в item.ini добавлял нужные айди но так не чого и не добился так же делал и npc.ini
Хрониkи God
Сервер Bsfg.ru
вроде как посмотрел все пакеты совпадают.

помогите плз

Flash1234
24.02.2015, 17:36
Здраствуйте.
Не могли бы Вы скрипт "Locomotiv-05_wsr.script" сделать под С4. У меня неполучается.