IPB

Добро пожаловать, гость ( Вход | Регистрация )

> Патчим MageSlayer с помощью fasmg
Grom PE
Jul 19 2026, 10:36
Сообщение #1


Advanced Member
***

Группа: CTPAX-X
Сообщений: 87
Регистрация: 7-February 08
Из: i@grompe.org
Пользователь №: 3,120
Спасибо сказали: 98 раз(а)



Некто мне напомнил о существовании такой игры, как MageSlayer.
Пожаловался на управление, а я помнил только, что нравилась игра, а про управление негативных впечатлений не осталось.
Решил скачать и проверить. И что же я увидел?
Вид сверху, бег можно настроить, чтоб WASD слал на все четыре стороны, настройка "tank strafe".
А вот с мышью не заладилось. Игра умеет только воспринимать движение вверх-вниз, как бег вперёд-назад, а влево-вправо — как поворот.
Так дело не пойдёт, решил я, и пропатчил игру, чтоб курсор мыши был точкой, куда смотрит персонаж.
Теперь играется, словно современная игра.

Попрактиковался с fasmg, где макросы для патчинга стали ещё проще, чем это требовалось в fasm 1, попрактиковался с Ghidra и x87 FPU.

Игру берём отсюда: https://www.old-games.ru/game/496.html
Дисковую версию, после патча до 1.1.

Пока сильно не играл, на форуме old-games.ru говорят, что версия 1.1 портит прохождение, это ещё надо изучить.
А вот версия 1.0 крашится при перемещении на первую локацию, если разрешение игры не 640x480x8.

Что сделано:
- пропатчил вызовы ShowCursor, чтоб курсор никогда не скрывался
- пропатчил вызов SetCooperativeLevel, где был бит DISCL_EXCLUSIVE, чтоб курсор мыши не захватывался эксклюзивно, и опять же не скрывался из-за этого же
- пропатчил место, где движения мыши вызывали движение и поворот персонажа
- уникального значения "угол поворота персонажа" я не нашёл, поэтому пришлось обходным путём: нашёл место, где читается угол поворота разных объектов на уровне, а если вызов происходит из конкретной функции, то это персонаж, записываем угол.
- используя текущий угол персонажа и положение курсора на экране, вычисляем скорость поворота, которую надо отправить в сетевой пакет.
- чтоб поворот не случился больше нужного, заставляем функцию проверки ввода от мыши вызываться каждый кадр, а не только если координаты изменились

Проверял на Wine 10.5, виртуалке Windows 2000 SP2, Windows XP SP3.

Итак, вот мой патч:
CODE
; mouse targeting patch for MageSlayer v1.1
; use fasmg to assemble against mageslay.exe, sha256=1a970cd3d2d5065a93cdd1ee0b9fe370d0df107efbf3e4a2f1d4a9a47abfe8a7
format binary as 'exe'
include 'p6.inc'

calminstruction align? boundary,value:?
    compute boundary, (boundary-1)-((0 scaleof $)+boundary-1) mod boundary
    arrange value, =db boundary =dup value
    assemble value
end calminstruction

file 'mageslay.exe'

macro patch cmd
    match =at= vaddr= =to= paddr,cmd
            offs = paddr
        virtual at vaddr
end macro

macro end?.patch!
            load mover:$ - $$ from $$
            store mover:lengthof mover at :offs
        end virtual
    end match
end macro

use32
if $ <> 1121792
    err 'wrong mageslay.exe version, if 1.0, patch to 1.1 first!'
end if

new_ep_rva = new_ep - 0x400000
store dword new_ep_rva at :0xA8
store dword 0xD9800 at :0x180; more space for code in .text
store dword 0x01400 at :0x1F8; more space for data in .idata

patch at 0x428FF4 to 0x283F4
    jmp get_angle_of_object
end patch

patch at 0x42AC39 to 0x2A039
    jmp go_catch_the_flag
end patch

store byte 0xEB at :0x352F8; no-cd

;patch at 0x4375DB to 0x369DB; original printf is broken?..
;    patch05::
;    push 1.1
;end patch

store byte 4 at :0x3A7CE; remove exclusive mouse access

patch at 0x46CBBA to 0x6BFBA; make it always check for mouse input instead of only when moved, fixes spinning around
    jmp $+13
end patch

patch at 0x46CC2C to 0x6C02C
    jmp handle_mouse_input
end patch

store "Version: 1.1mf":14 at :0xE65A8

label ShowCursor dword at 0x5A45CC
label user32_dll dword at 0x4DCDB0
label LoadLibraryA dword at 0x5A4488
label GetProcAddress dword at 0x5A451C
label str_percent_d at 0x4E3A6F
label printf_to_console at 0x4132A0
label main_hwnd dword at 0x547F84
label GetClientRect dword at 0x5A4604

patch at 0x4DA6D8 to 0xD9AD8
disabled_ShowCursor:
    xor    eax,eax
    ret    4
    align 16, 0x90
new_ep:
    mov    eax,disabled_ShowCursor
    mov    [ShowCursor],eax
    push    GetCursorPos
    push    user32_dll
    call    [LoadLibraryA]
    push    eax
    call    [GetProcAddress]
    mov    [GetCursorPos],eax
    jmp    0x4A8060
;    align 16, 0x90
;debug_print_float32:
;    push    eax
;    fld    dword [esp]
;    push    10
;    fild    dword [esp]
;    fmulp    st(1),st(0)
;    fistp    dword [esp]
;    pop    eax
;    add    esp,4
;    align    16, 0x90
;debug_print_int32:
;    push    eax
;    push    str_percent_d
;    call    printf_to_console
;    add    esp,8
;    ret
    align 16, 0x90
go_catch_the_flag:
    xor    ecx,ecx
    inc    ecx
    mov    [catch_flag],ecx
    call    0x427300; original func
    jmp    0x42AC3E; original place
    align 16, 0x90
get_angle_of_object:
    mov    ecx,[catch_flag]
    test    ecx,ecx
    jz    no_catch
    mov    ecx,[edx+eax*4]
    mov    [current_angle],ecx
    xor    ecx,ecx
    mov    [catch_flag],ecx
  no_catch:
    jmp 0x42A0DC; original place
handle_mouse_input:
    call    0x416B20; original func
    xor    eax,eax
    mov    [esp+0x38],eax; zero out forward/backward speed
;    mov    [esp+0x34],eax; zero out turning speed
    push    CursorPos_point
    call    [GetCursorPos]
    mov    eax,[main_hwnd]
    push    GetClientRect_rect
    push    eax
    call    [GetClientRect]
    mov    eax,[CursorPos_point+4]
    mov    edx,[GetClientRect_rect+12]
    shr    edx,1
    sub    edx,eax
    push    edx
    fild    dword [esp]
    mov    eax,[CursorPos_point]
    mov    edx,[GetClientRect_rect+8]
    shr    edx,1
    sub    eax,edx
    push    eax
    fild    dword [esp]
    fpatan
    fld    [current_angle]
    fsubp    st(1),st(0)
    fldpi
    fadd    st(0),st(0)
    fxch    st(1)
    fprem1
    fstp    st(1)
    push    0x40000; turning speed multiplier
    fimul    dword [esp]
    add    esp, 12
    fistp    dword [esp+0x34]
    jmp    0x46CC31; original place
    if $ >= 0x4DA800
        err 'code too big, not enough space!'
    end if
end patch

patch at 0x5A5260 to 0xF3460
    catch_flag dd 0; set to 1 if current object is player
    current_angle dd 0
    label GetCursorPos dword
    db 'GetCursorPos',0
    align 4
CursorPos_point:
    dd 0,0
GetClientRect_rect:
    dd 0,0,0,0
    if $ >= 0x5A5400
        err 'data too big, not enough space!'
    end if
end patch



Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
 
Reply to this topicStart new topic
Ответов(1 - 3)
Grom PE
Jul 19 2026, 11:23
Сообщение #2


Advanced Member
***

Группа: CTPAX-X
Сообщений: 87
Регистрация: 7-February 08
Из: i@grompe.org
Пользователь №: 3,120
Спасибо сказали: 98 раз(а)



С помощью худо-бедно скомпилированного vpack:
https://web.archive.org/web/19980502215605/...files/vpack.cpp
выяснил, что версии 1.0 и 1.1 mage.vpk различаются следующими файлами внутри:

MAPS/DEATH3.VBM
MAPS/KEEP4.VBM
MAPS/SEWSCRT1.VBM
MAPS/TEMPLE4.VBM
MAPS/TEMPLEBS.VBM
MAPS/TMPSCRT1.VBM
MAPS/TMPSCRT2.VDT
MAPS/TOMB2.VBM

Пока неясно, что с этим делать. В архиве с исходниками утилит
https://web.archive.org/web/19980502215645/...es/rtsource.zip
ещё есть bspbin.c, который эти VBM только генерирует.


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jul 19 2026, 13:02
Сообщение #3


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,449
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 332 раз(а)



Welcome back, дружище!
С удовольствием прочитал твои изыскания, хотя игру видел всего один раз в жизни мельком в гостях.

QUOTE(Grom PE @ Jul 19 2026, 11:23) *
С помощью худо-бедно скомпилированного vpack:
...
выяснил, что версии 1.0 и 1.1 mage.vpk различаются следующими файлами внутри:
...
Пока неясно, что с этим делать.
Если есть исходные коды распаковщика/упаковщика файлов игры, то можно по одному файлу заменять, смотреть что поменялось, чтобы сузить круг подозреваемых.
В версии 1.00 и 1.1 только эти файлы меняются? Исполняемый файл тот же самый?
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
Grom PE
Jul 19 2026, 13:41
Сообщение #4


Advanced Member
***

Группа: CTPAX-X
Сообщений: 87
Регистрация: 7-February 08
Из: i@grompe.org
Пользователь №: 3,120
Спасибо сказали: 98 раз(а)



QUOTE(-=CHE@TER=- @ Jul 19 2026, 10:02) *
можно по одному файлу заменять, смотреть что поменялось
Так и думаю сделать, когда дойду в игре до глючного места.

QUOTE
В версии 1.00 и 1.1 только эти файлы меняются? Исполняемый файл тот же самый?
mageslay.exe тоже меняется, я изучал и патчил только 1.1. Не считая того, что no-cd подсмотрел из различий от 1.0 патченного и оригинала.


Спасибо сказали:
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0 -

 



Упрощённая версия Сейчас: 21st July 2026 - 11:42