Skip to main content

Код для бота в игре Lineage II на языке Pascal

Для того, чтобы бот автоматически выбирал мобов в радиусе 500 и атаковал их до смерти, а затем поднимал дроп и атаковал следующего моба, мы будем использовать функцию FindNearestMonster, которая ищет ближайшего монстра в радиусе 500. Затем мы будем использовать функцию AttackMonster, которая атакует монстра до его смерти и забирает дроп.

`uses Windows;

type TMonsterInfo = packed record ID: Integer; TypeID: Integer; X, Y, Z: Integer; HP: Integer; end;

var LineageWindow: HWND;

function FindNearestMonster: TMonsterInfo; // поиск ближайшего монстра var MonsterAddr: Integer; MonsterCount: Integer; MonsterListAddr: Integer; i: Integer; Monster: TMonsterInfo; NearestMonster: TMonsterInfo; NearestDistance: Double; Distance: Double; begin MonsterAddr := $00BA3B00; // адрес в памяти, где хранится количество монстров ReadProcessMemory(LineageWindow, Pointer(MonsterAddr), @MonsterCount, SizeOf(MonsterCount), nil);

MonsterListAddr := $00B9FA90; // адрес в памяти, где хранится список монстров NearestMonster.ID := 0; NearestDistance := 500; for i := 1 to MonsterCount do begin ReadProcessMemory(LineageWindow, Pointer(MonsterListAddr + (i - 1) * SizeOf(Monster)), @Monster, SizeOf(Monster), nil); if Monster.TypeID = 0 then // монстр мертв Continue; Distance := Sqrt(Sqr(Monster.X - MyX) + Sqr(Monster.Y - MyY) + Sqr(Monster.Z - MyZ)); if Distance < NearestDistance then begin NearestMonster := Monster; NearestDistance := Distance; end; end; Result := NearestMonster; end;

procedure AttackMonster(Monster: TMonsterInfo); // атака монстра var AttackAddr: Integer; begin AttackAddr := $0080A8B8; // адрес в памяти, где хранится команда атаки WriteProcessMemory(LineageWindow, Pointer(AttackAddr), @Monster.ID, SizeOf(Monster.ID), nil); // здесь можно использовать какой-то скил while Monster.HP > 0 do // ждем, пока монстр не умрет Sleep(100); // забираем дроп end;

begin LineageWindow := FindWindow('L2WindowClass', 'Lineage II'); if LineageWindow = 0 then begin ShowMessage('Lineage II не найден'); Exit; end;

// получение координат нашего персонажа MyX := 123; MyY := 456; MyZ := 789;

// поиск ближайшего монстра и атака его while True do AttackMonster(FindNearestMonster); end.` Здесь я использовал переменные MyX, MyY и MyZ, чтобы показать, как можно получить координаты персонажа. Вам нужно будет заменить эти переменные на код, который получает координаты персонажа в вашей игре.

Также вы можете добавить код для проверки жизни персонажа и использования банок, как я показал в предыдущем примере.

Надеюсь, это поможет вам создать бота, который будет автоматически выбирать мобов и атаковать их до смерти.

`uses Windows;

var LineageWindow: HWND;

begin LineageWindow := FindWindow('L2WindowClass', 'Lineage II'); if LineageWindow = 0 then begin ShowMessage('Lineage II не найден'); Exit; end; // далее будут производиться манипуляции с окном игры end.` Чтобы получить данные о персонажах вокруг нашего героя, мы будем использовать функцию GetTarget, которая возвращает информацию о текущей цели. Для атаки цели мы будем использовать функцию AttackTarget.

`uses Windows;

type TTargetInfo = packed record ID: Integer; TypeID: Integer; X, Y, Z: Integer; end;

var LineageWindow: HWND;

function GetTarget: TTargetInfo; // получение информации о текущей цели var TargetAddr: Integer; begin TargetAddr := $00B7F8A8; // адрес в памяти, где хранится информация о цели ReadProcessMemory(LineageWindow, Pointer(TargetAddr), @Result, SizeOf(Result), nil); end;

procedure AttackTarget(TargetID: Integer); // атака цели var AttackAddr: Integer; begin AttackAddr := $0080A8B8; // адрес в памяти, где хранится команда атаки WriteProcessMemory(LineageWindow, Pointer(AttackAddr), @TargetID, SizeOf(TargetID), nil); end;

begin LineageWindow := FindWindow('L2WindowClass', 'Lineage II'); if LineageWindow = 0 then begin ShowMessage('Lineage II не найден'); Exit; end;

// получение информации о текущей цели и атака ее AttackTarget(GetTarget.ID); end.`

Для передвижения персонажа мы будем использовать функцию SendInput, которая эмулирует нажатие клавиш на клавиатуре.

`uses Windows;

const KEY_W = $11; // клавиша W KEY_S = $1F; // клавиша S KEY_A = $1E; // клавиша A KEY_D = $20; // клавиша D

procedure MoveForward; // движение вперед var Input: TInput; begin ZeroMemory(@Input, SizeOf(Input)); Input.Itype := INPUT_KEYBOARD; Input.ki.wVk := KEY_W; SendInput(1, Input, SizeOf(Input)); end;

procedure MoveBackward; // движение назад var Input: TInput; begin ZeroMemory(@Input, SizeOf(Input)); Input.Itype := INPUT_KEYBOARD; Input.ki.wVk := KEY_S; SendInput(1, Input, SizeOf(Input)); end;

procedure MoveLeft; // движение влево var Input: TInput; begin ZeroMemory(@Input, SizeOf(Input)); Input.Itype := INPUT_KEYBOARD; Input.ki.wVk := KEY_A; SendInput(1, Input, SizeOf(Input)); end;

procedure MoveRight; // движение вправо var Input: TInput; begin ZeroMemory(@Input, SizeOf(Input)); Input.Itype := INPUT_KEYBOARD; Input.ki.wVk := KEY_D; SendInput(1, Input, SizeOf(Input)); end;

begin // движение персонажа вперед MoveForward; end.`

Для взятия цели в таргет мы будем использовать функцию SetTarget, которая возвращает информацию о текущей цели. `uses Windows;

type TTargetInfo = packed record ID: Integer; TypeID: Integer; X, Y, Z: Integer; end;

var LineageWindow: HWND;

function SetTarget(TargetID: Integer): TTargetInfo; // установка цели в таргет var TargetAddr: Integer; begin TargetAddr := $00B7F8A8; // адрес в памяти, где хранится информация о цели WriteProcessMemory(LineageWindow, Pointer(TargetAddr), @TargetID, SizeOf(TargetID), nil); Result.ID := TargetID; end;

begin LineageWindow := FindWindow('L2WindowClass', 'Lineage II'); if LineageWindow = 0 then begin ShowMessage('Lineage II не найден'); Exit; end;

// установка цели в таргет SetTarget(123456); end. `

Для проверки жизни персонажа мы будем использовать функцию GetHP, которая возвращает текущее количество HP. Если у нас меньше 20% HP, то мы будем использовать банки. `uses Windows;

var LineageWindow: HWND;

function GetHP: Integer; // получение текущего количества HP var HPAddr: Integer; begin HPAddr := $00B7F8F8; // адрес в памяти, где хранится количество HP ReadProcessMemory(LineageWindow, Pointer(HPAddr), @Result, SizeOf(Result), nil); end;

procedure UsePotion; // использование банки var PotionAddr: Integer; begin PotionAddr := $0080A9B8; // адрес в памяти, где хранится команда использования банки WriteProcessMemory(LineageWindow, Pointer(PotionAddr), @PotionAddr, SizeOf(PotionAddr), nil); end;

begin LineageWindow := FindWindow('L2WindowClass', 'Lineage II'); if LineageWindow = 0 then begin ShowMessage('Lineage II не найден'); Exit; end;

// проверка количества HP и использование банок if GetHP < 20 then UsePotion; end.` Для автокачки мы будем использовать функцию Sleep, которая приостанавливает выполнение программы на заданное количество миллисекунд.

`uses Windows;

var LineageWindow: HWND;

procedure AutoLevelUp; // автокачка begin while True do begin // здесь должен быть код для качки персонажа Sleep(1000); // приостанавливаем выполнение программы на 1 секунду end; end;

begin LineageWindow := FindWindow('L2WindowClass', 'Lineage II'); if LineageWindow = 0 then begin ShowMessage('Lineage II не найден'); Exit; end;

AutoLevelUp; // запускаем автокачку end.`