Прокляті Землі

Багато людей грали в цю чудову гру. Цікавий сюжет, хороша музика, гарний геймплей. Тільки є кілька моментів, які мені не подобаються. Біг персонажів дуже обмежений буквально кілька секунд, а запас сил відновлюється довго. Система нарахування досвіду не стимулює брати напарників, тому що досвід розподіляється на всіх порівну, і краще бігати одному, щоб забирати весь досвід собі. Візьмемо наладчик і спробуємо це виправити. Нам знадобляться ArtMoney, IDA, Hiew.
У діях нічого складного немає, тут головний результат. Зміщення наведено для версії 1.07.
Запускаємо IDA, завантажуємо файл game.exe, чекаємо поки завершиться аналіз. Запускаємо стартер, прибираємо налаштування «Повноекранний режим». Запускаємо гру у відладчику, завантажуємо збереження де вже можна взяти партнера. Беремо партнера, виходимо на карту.

Дивимося скільки запасу сил у персонажа. Тут це 54. Запускаємо ArtMoney. Шукаємо це значення. Тип «З точкою 4 байти». Пробігаємо скільки-небудь і відсіваємо нове значення. Повторюємо скільки потрібно, у мене одразу залишилося одне значення.
Пробуємо заморозити, якщо запас сил під час бігу відновлюється, значить знайшли правильно. Тільки треба зняти згодом. Включаємо режим бігу. Ставимо гру на паузу (пробіл).

Судячи з значень, там зберігається:
[edi+14h] – поточне значення [edi+18h] – максимальне значення
Видно, що максимальний запас сил персонажа множиться на константу dbl_73F088 і результат віднімається з поточного значення. Тому всі персонажі бігають однаково.
Тобто персонаж може пробігти приблизно 150 кроків, але це не зовсім кроки, які видно на анімації, тому що відніманнявідбувається набагато частіше. Повний запас сил витрачається за 9-10 секунд, отже віднімання викликається 15 - 16.66 разів на секунду.
Швидше за все, це зелені точки, що позначають шлях.

У байтах ця константа записується так:

Для конвертації float/double в hex-виставу можна скористатися онлайн-конвертером, наприклад цим.
Виходить гарне число 0x3F623456789ABCDF
Замінюємо, зберігаємо, запускаємо. Ось так набагато краще.
Тут трохи складніше. Він не зберігається у явному вигляді. Потрібно шукати через пов'язані значення. Починаємо, втім, так само.
Дивимося скільки досвіду відображається у персонажа. Це можна зробити у режимі між картами. В мене це 116.

Шукаємо це значення. Тут потрібен тип «Ціле 4 байти».
Не вихідна змінна, а обчислюване значення, наведене до int. Сам досвід зберігається у float, але там інше значення, про це нижче.

Після кількох повторень у мене залишилося 6 значень, які змінюються синхронно.


Можна припустити, що це отриманий та витрачений досвід, а поточний розраховується як їхня різниця.
У мене гра падала кілька разів, тому я ставив брейкпойнт на код та завантажував із збереження. Тому тут 116, а не 120. Але це лише підтверджує припущення.
Поставимо новий брейк-пойнт на [ebx+4] .
Вибираємо всю групу та нападаємо на противника.

Брейкпойнт спрацьовує перед тим, як це буде видно на екрані.
В [esi+4] нове значення досвіду. [ebp+arg_4] число 2.0. За молодого кабана дається 4.0, отже розподіл перебуває до виклику функції.
Виходимо із функції через Ctrl+F7. Це обгортка, виходимо ще раз.
Дивимося трохи вище, тамзнаходиться такий код.
Поставимо брейкпойнт на 00591521 і візьмемо участь у битві ще раз.
fdivr ділить аргумент на st(0) і результат записує в st(0): st(0) = arg/st(0). У st(0) знаходиться значення [ebp+var_18] , в якому знаходиться 2 число персонажів. У [ebp+arg_4] знаходиться 4.0 – досвід за супротивника. За виконання місії нарахування теж відбувається тут.
Також розподіл на кількість учасників є вищим:
Але не знайшов, коли виконується цей код. Там чіпати не будемо.
Тепер через Hiew можна забрати код для поділу. Через особливості fdivr замінюємо на nop усі 3 команди (9 байт).
Тепер персонажі і бігають нормально, і запас сил не нескінченний, на заклинання витрачається як завжди, механіка гри збережена. А напарники набувають свого незалежного досвіду, який можна витрачати на їх розвиток.
Хардкорна конфа за С++. Ми запрошуємо лише профі.