PDA

Просмотр полной версии : [Руководство] Исполнение скриптов от L2Walker из клиента игры


Hummel
19.03.2009, 13:25
Исполнение скриптов, написаных к L2Walker, из клиента игры

Довольно много готовых скриптов для валкера. Может стоит воспользоваться? Тем более, что для WP PPC есть подобное.
Замечание
Отпадают скрипты кача или с охотой в локации на мобов: команды типа SET. На вскидку, будут работать скрипты, где передвижение, общение с НПЦ, покупка/продажа в магазине.

Руководство пользователя:

Для примера, скрипт называется script.sec

NPCSEL(Monakan Fishermen's Guild Member[ID=31573])
NPCDLG(Monakan Fishermen's Guild Member[ID=31573])
DLGSEL("I want to purchase fishing equipment.")
BUYITEM(зелёные крючки[ID=7807],10;удочка нуба[ID=6529],1)
//BUYITEM(Тут всё равно что[ID=7807],100)
EXIT()


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

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


Становимся чаром рядом с фишермэном в Гиран-харборе.
Запускаем скрипт, установив галочку напротив его имени.
Скрипт пакетхака загружает команды из скрипта валкера (script.sec) и начинает исполнять команды. В конце по команде EXIT() скрипт пакетхака завершает интерпретацию валкеровского скрипта.
В результате выполнения скрипта имеем закупленные 10 шт зелёных крючков и одна удочка для нуба.


version 0.7 от 20.01.2009г.
[+] Понимает команды:

MSG,
SELLITEM,
BUYITEM,
PAUSE,
ITEMCOUNT,
CALL,
RETURN,
MOVETO,
USEITEM,
NPCDLG,
NPCSEL,
DELAY,
JMP,
LABEL,
EXIT,
DLGSEL


скрипт для пакетхака



//************************************************** ****************************
program WalkerScriptRunner;
//************************************************** ****************************
{
Walker Script Runner by NLObP for Gracia l2.ru
version 0.5 от 18.01.2009г.
что он может:
1.исполнение скриптов, написаных к L2Walker, из клиента игры

Эмулятор Walker'а
возможность запуска скриптов валкера в L2PacketHack 3.4.1+ by CoderX.ru

version 0.5 от 18.01.2009г.
[+] Понимает команды: PAUSE, ITEMCOUNT
version 0.4 от 18.01.2009г.
[+] Понимает команды: MOVETO, USEITEM, CALL, RETURN
version 0.3 от 17.01.2009г.
[+] Понимает команды: NPCDLG, NPCSEL
version 0.2 от 16.01.2009г.
[+] Понимает команды: DELAY, JMP, LABEL, EXIT, DLGSEL(только текст, кнопки не жмет)
[+] Ведём базу инвентаря
[+] Ведём базу NPCs
version 0.1 от 14.01.2009г.
[!] пока только заготовки: NPCDLG, NPCSEL, USEITEM, CALL
[!] Скрипт переводим в Ansi кодировку
}



//ВНИМАНИЕ:
//При написани скриптов соблюдайте некоторые правила:
//1. команды пишутся в столбик
//2. если нужно написать команду с {}, то делается так
//CharStatus(***,***,***)
//{
//КОМАНДЫ
//}
//А не так
//CharStatus(***,***,***)
//{КОМАНДЫ}
//3. Нельзя делать две проверки:
//CharStatus(***,***,***)
//{
//CharStatus(***,***,***)
//{
//КОМАНДЫ
//}
//}
//если хотите оформить двойную проверку используйте CALL и LABEL.

//************************************************** ****************************
const
Name='ttest'; //имя персонажа в игре
debug=true; //если не хотим видеть отладочной информации
PathWalkerScript='.\scripts\'; //путь к скрипту
NameWalkerScript='test.sec'; //имя скрипта
DefaultExecuteDelay=1000; //стандартная задержка между коммандами Валкера
DefaultDistanciya=200; //дистанция при которой считаем, что пришли в нужную точку

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

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

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

//требуется поддержка БД
//Chars OID=Name...
//NPCs
BaseNPCs: array[1..maxnpc, 1..2] of integer; //все NPC вокруг
NpcCount : integer; //количество Npc в базе
{
1 - OID
2 - ID
}
//ITEMs
BaseItems: array[1..maxitems, 1..12] of integer; //все предметы в инвентаре
{
0004 h ListSize: 21 (0x0015)
[Начало повторяющегося блока 1/21]
0006 h ItemType1: 4
0008 d ObjectID: 268482489
0012 d ItemID: Доказательство Ловли Рыбы ID:7609 (0x1DB9)
0016 d LocationSlot: 11
0020 d Count: 506
0024 h ItemType2: 5
0026 h CustomType1: 0
0028 h isEquipped: 0
0030 d BodyPart: 0
0034 h EnchantLevel: 0
0036 h CustType2: 0
0038 d AugmentationID: 0
...
[Конец повторяющегося блока 1/21]
[Начало повторяющегося блока 2/21]
0082 h ItemType1: 4
}
//************************************************** ****************************
procedure Init; //Вызывается при включении скрипта
begin
debugMsg('--------------------Запущен скрипт!-----------------------');
WalkerScript:=TStringList.Create;
WalkerLabel:=TStringList.Create;
ReturnStack:=TStringList.Create;
//загружаем скрипт валкера из файла
try
WalkerScript.LoadFromFile(PathWalkerScript+NameWal kerScript);
except
debugMsg(NameWalkerScript+' не найден!');
exit;
end;

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

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

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

ExecuteTimer:=TTimer.Create(nil);
ExecuteTimer.Enabled:=True;
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; Executetimer.OnTimer:=nil;
MoveTimer.Enabled:=False; //остановим на всякий случай
movetimer.Free; movetimer.OnTimer:=nil;
if WalkerScript<>nil then
try
WalkerScript.Free;
WalkerLabel.Free;
ReturnStack.Free;
except
debugMsg('Error free WallkerScript');
end;
end;
//.................................................. ............................
procedure OnConnect(WithClient: Boolean); //Вызывается при установке соединения
begin

end;
//.................................................. ............................
procedure OnDisonnect(WithClient: Boolean); //Вызывается при потере соединения
begin

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
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;
//.................................................. ............................
procedure InventoryUpdate; //пакет 27, Создает базу 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 : 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-kID; //ID
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-kID; //ID
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
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 начало смещения для поиска в строке
for j:=1 to Length(P) do
if P[j]<>S[i+j-1] then
Break
else if j=Length(P) then
begin
Result:=i;
Exit;
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;
//.................................................. ............................
{
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 rel="nofollow" action="bypass -h menu_select?ask=-303&amp;reply=518"> Exchange with the Dimension Diamond</a><br>
<a rel="nofollow" action="bypass -h menu_select?ask=-19&amp;reply=0"> [Noblesse Only] teleport</a><br>
<a rel="nofollow" action="bypass -h menu_select?ask=255&amp;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><br /><div style="z-index:3" class="smallfont" align="center">Search Engine Friendly URLs by vBSEO 3.1.0 &copy;2007, Crawlability, Inc.</div></body></html>
}
function GetBypass(sData, sText: string): string;
{находим в NpcHtmlMessage по заданной строке текста соответствующий ей bypass}
var
i: integer;
s, bypass, text: string;
eos: boolean; //конец NpcHtmlMessage
begin
debugMsg('GetBypass');
s:=sData;
//debugMsg('sData='+s);
// debugMsg('Stext='+sText);
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
// bypass:=AllTrim(ExtractName(s, '">'), ' ', ' '); //получили bypass
// debugMsg('ExtractName:'+bypass);
s:=ExtractValue(s,'">'); //получили остаток строки начиная с искомого символа
// debugMsg('ExtractValue: '+s);
text:=AllTrim(ExtractName(s, '</')); //получили текст
// text:=AllTrim(ExtractName(s, '</'), ' ', ' '); //получили текст
// debugMsg('ExtractName:'+text);
if sText=text then begin
// debugMsg('Нашли подходящий bypass: '+bypass);
result:=bypass; //нашли подходящий bypass
eos:=true; //сигналим, что закончили поиск
end;
end;
//поискать 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
// bypass:=AllTrim(ExtractName(s, '">'), ' ', ' '); //получили bypass
// debugMsg('ExtractName:'+bypass);
s:=ExtractValue(s,'">'); //получили остаток строки начиная с искомого символа
// debugMsg('ExtractValue: '+s);
text:=AllTrim(ExtractName(s, '</')); //получили текст
// text:=AllTrim(ExtractName(s, '</'), ' ', ' '); //получили текст
// debugMsg('ExtractName:'+text);
if sText=text then begin
// debugMsg('Нашли подходящий bypass: '+bypass);
result:=bypass; //нашли подходящий bypass
eos:=true; //сигналим, что закончили поиск
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;
//.................................................. ............................
function GetItemcount(sData: string): boolean;
//ITEMCOUNT(Red Bone Necklace[ID=7179],==,100)
//{
//}
//в sData = Red Bone Necklace[ID=7179],==,100
var
s, uslovie: string;
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:=GetItem(id,3,5); //возвращает количество из инвентаря
//обрабатываем >=,==,!=,>,<,<=
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: integer;
s: string;
begin
debugMsg('Пропускаем фигурные скобки...');
for i:=strIndex to WalkerScript.Count-1 do begin
s:=WalkerScript[i]; //считываем команду из листа
case s of
//пропускаем всё до первой фигурной скобки
'}': begin
debugmsg('Нашли скобку }...');
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 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);
//c19=UseItem:d(ObjectID)d(Unknown)
begin
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);
//c1F=Action:d(ObjectID)d(OriginX)d(OriginY)d(Origin Z)c(ActionID)
procedure Target(OID: Integer);
begin
buf:=#$1F;
WriteD(OID);
WriteD(MyX);
WriteD(MyY);
WriteD(MyZ);
WriteC(00);
SendToServerEx(Name);
end;
//.................................................. ............................
//атаковать цель, действует толко после Action(OID)
//use: AttackRequest(OID);
//c01=AttackRequest:d(ObjectID)d(OriginX)d(OriginY)d (OriginZ)c(AttackID)
procedure Attack(OID: Integer);
begin
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;
//************************************************** ****************************
{
Парсер/Исполнитель: главный цикл обработки команд Валкера
}
//************************************************** ****************************
function OnExecute(Sender: TObject): integer; //CommandList: TStringList
var
s, cmd, param : string;
begin
debugMsg('Парсер команд валкера...');
result:=-1;
//проверка на наличие команд в скрипте
if WalkerScript.Count=0 then begin
ExecuteTimer.Enabled:=False;
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('Exit');
end;
{изменяем паузу между командами}
'PAUSE','DELAY': begin
ExecuteTimer.Interval:=StrToInt(AlltrimEx(param,'( ',')')); //время задержки
end;
{находим bypass в HTML по заданной строке}
'DLGSEL': begin
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);
// UseItem(GetItemOID(strtoint(param)),0);
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(Название предмета[ID=#],<,1)
//{
//}
//Подсчитывает количество указанных предметов с условиями <, >, = и выполняет скрипт в фигурных скобках.
'ITEMCOUNT': begin
if not GetItemcount(param) //возвращает Истина, если проверку прошли, инача Ложь
then SkipFS; //пропускаем фигурные скобки
end;
{
BuyItem(Название предмета[ID=#],#)
//Покупает предмет
BuyItem(Название предмета[ID=#],#;Название предмета[ID=#],#)
//Покупает за раз более одного предмета (можно указать много предметов через точку с запятой) .
}
'BUYITEM': begin
end;
end;
inc(strIndex);
result:=1;
except
debugMsg('Error in OnExecute');
result:=-1;
end;
end;
//************************************************** ****************************
{
основная часть скрипта, вызывается при приходе каждого пакета, если скрипт включен
}
//************************************************** ****************************
begin
//************************************************** **************************
//не обрабатываем пустые пакеты
if pck='' then exit;

//************************************************** **************************
if (ConnectName=Name) and FromServer then begin
case pck[1] of
//************************************************** **********************
//08=DeleteObject:d(ObjectID)d(0)
#$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)
#$0C: begin
// debugmsg('S>C Пакет NpcInfo #$0C'+inttostr(ReadD(2)));
// OID ID
AppendNpc(ReadD(2), ReadD(6)); //добавляем в базу данных
end;
//************************************************** **********************
#$11: begin
// debugmsg('S>C Пакет ItemListPacket #$11');
ItemList;
end;
//************************************************** **********************
#$21: begin
// debugmsg('S>C Пакет InventoryUpdate #$21');
InventoryUpdate;
end;
//************************************************** **********************
//0x19 (NpcHtmlMessage)
#$19: begin
// debugmsg('S>C Пакет NpcHtmlMessage #$19');
sHTML:=ReadS(6);
// sendmsg(sHTML);
end;
//************************************************** **********************
end; //case
end;

//************************************************** **************************
if (ConnectName=Name) and FromClient then begin
case pck[1] of
//************************************************** **********************
//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.